1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_xmlhelp.hxx"
36 #include <rtl/alloc.h>
39 #include "com/sun/star/io/XSeekable.hpp"
45 using namespace com::sun::star
;
46 using namespace com::sun::star::uno
;
47 using namespace com::sun::star::io
;
49 namespace berkeleydbproxy
{
51 //----------------------------------------------------------------------------
54 // static void raise_error(int dberr, const char * where);
56 static inline int check_error(int dberr
, const char * where
)
60 // if (dberr) raise_error(dberr,where);
65 void DBData::copyToBuffer( const char* pSrcData
, int nSize
)
69 m_pBuffer
= new char[m_nSize
+1];
70 memcpy( m_pBuffer
, pSrcData
, m_nSize
);
71 m_pBuffer
[m_nSize
] = 0;
77 bool DBHelp::implReadLenAndData( const char* pData
, int& riPos
, DBData
& rValue
)
79 bool bSuccess
= false;
82 const char* pStartPtr
= pData
+ riPos
;
84 sal_Int32 nKeyLen
= strtol( pStartPtr
, &pEndPtr
, 16 );
85 if( pEndPtr
== pStartPtr
)
87 riPos
+= (pEndPtr
- pStartPtr
) + 1;
89 const char* pKeySrc
= pData
+ riPos
;
90 rValue
.copyToBuffer( pKeySrc
, nKeyLen
);
99 typedef std::pair
< rtl::OString
, rtl::OString
> KeyValPair
;
100 typedef std::vector
< KeyValPair
> KeyValPairVector
;
102 void testWriteKeyValue( FILE* pFile
, const KeyValPair
& rKeyValPair
)
108 const rtl::OString
& aKeyStr
= rKeyValPair
.first
;
109 const rtl::OString
& aValueStr
= rKeyValPair
.second
;
110 int nKeyLen
= aKeyStr
.getLength();
111 int nValueLen
= aValueStr
.getLength();
112 fprintf( pFile
, "%x ", nKeyLen
);
114 fwrite( aKeyStr
.getStr(), 1, nKeyLen
, pFile
);
115 fprintf( pFile
, " %x ", nValueLen
);
117 fwrite( aValueStr
.getStr(), 1, nValueLen
, pFile
);
118 fprintf( pFile
, "%c", cLF
);
121 bool DBHelp::testAgainstDb( const rtl::OString
& fileName
, bool bOldDbAccess
)
123 bool bSuccess
= true;
125 KeyValPairVector avKeyValPair
;
127 rtl::OString aOutFileName
= fileName
;
128 aOutFileName
+= "_TestOut";
130 aOutFileName
+= "_Old";
131 FILE* pFile
= fopen( aOutFileName
.getStr(), "wb" );
135 if( 0 == table
.open( 0,fileName
.getStr(),0,DB_BTREE
,DB_RDONLY
,0644 ) )
140 table
.cursor( 0,&cursor
,0 );
142 key_
.set_flags( DB_DBT_MALLOC
); // Initially the cursor must allocate the necessary memory
143 data
.set_flags( DB_DBT_MALLOC
);
145 while( cursor
&& DB_NOTFOUND
!= cursor
->get( &key_
,&data
,DB_NEXT
) )
147 rtl::OString
keyword( static_cast<sal_Char
*>(key_
.get_data()),
149 rtl::OString
value( static_cast<sal_Char
*>(data
.get_data()),
152 KeyValPair
aPair( keyword
, value
);
153 avKeyValPair
.push_back( aPair
);
155 testWriteKeyValue( pFile
, aPair
);
159 key_
.set_flags( DB_DBT_REALLOC
);
160 data
.set_flags( DB_DBT_REALLOC
);
165 if( cursor
) cursor
->close();
178 const char* pTestReadData
= NULL
;
179 int nTestReadDataSize
= 0;
181 sal_uInt32 starttime
= osl_getGlobalTimer();
182 sal_uInt32 afterfirsttime
= starttime
;
187 fprintf( pFile
, "\nTesting old access:\n" );
189 fprintf( pFile
, "\nTesting new access:\n" );
192 KeyValPairVector::const_iterator it
;
194 for( it
= avKeyValPair
.begin() ; it
!= avKeyValPair
.end() ; ++it
)
196 const KeyValPair
& rKeyValPair
= *it
;
198 const rtl::OString
& aKeyStr
= rKeyValPair
.first
;
199 const rtl::OString
& aValueStr
= rKeyValPair
.second
;
200 int nKeyLen
= aKeyStr
.getLength();
201 int nValueLen
= aValueStr
.getLength();
203 const sal_Char
* ptr
= aValueStr
.getStr();
205 bTestSuccess
= false;
206 pTestReadData
= NULL
;
207 nTestReadDataSize
= 0;
212 if( tableTest
.open( 0,fileName
.getStr(),0,DB_BTREE
,DB_RDONLY
,0644 ) )
215 fprintf( pFile
, "Cannot open database\n" );
221 Dbt
key( static_cast< void* >( const_cast< sal_Char
* >( aKeyStr
.getStr() ) ), aKeyStr
.getLength() );
222 int err
= tableTest
.get( 0, &key
, &data
, 0 );
226 pTestReadData
= static_cast< sal_Char
* >( data
.get_data() );
227 nTestReadDataSize
= data
.get_size();
232 bTestSuccess
= getValueForKey( aKeyStr
, aDBData
);
235 pTestReadData
= aDBData
.getData();
236 nTestReadDataSize
= aDBData
.getSize();
241 afterfirsttime
= osl_getGlobalTimer();
245 if( bTestSuccess
&& pTestReadData
!= NULL
)
247 int nCmp
= memcmp( ptr
, pTestReadData
, nValueLen
);
253 if( nValueLen
!= nTestReadDataSize
)
266 fprintf( pFile
, "ERROR, not found:\n" );
267 testWriteKeyValue( pFile
, rKeyValPair
);
268 fprintf( pFile
, "\nError Code: %d\n", nError
);
272 tableTest
.close( 0 );
274 sal_uInt32 endtime
= osl_getGlobalTimer();
275 double dDiffTime
= (endtime
-starttime
) / 1000.0;
276 double dDiffFirstTime
= (afterfirsttime
-starttime
) / 1000.0;
279 int nCount
= avKeyValPair
.size();
280 fprintf( pFile
, "%d key/values in total, read %d correctly, %d errors\n",
281 nCount
, nOkCount
, nErrCount
);
282 fprintf( pFile
, "Time taken: %g s (First access %g s)\n", dDiffTime
, dDiffFirstTime
);
283 fprintf( pFile
, "Average time per access: %g s\n", dDiffTime
/ nCount
);
295 void DBHelp::createHashMap( bool bOptimizeForPerformance
)
298 if( bOptimizeForPerformance
)
300 if( m_pStringToDataMap
!= NULL
)
302 m_pStringToDataMap
= new StringToDataMap();
306 if( m_pStringToValPosMap
!= NULL
)
308 m_pStringToValPosMap
= new StringToValPosMap();
311 Reference
< XInputStream
> xIn
= m_xSFA
->openFileRead( m_aFileName
);
314 Sequence
< sal_Int8
> aData
;
315 sal_Int32 nSize
= m_xSFA
->getSize( m_aFileName
);
316 sal_Int32 nRead
= xIn
->readBytes( aData
, nSize
);
318 const char* pData
= (const char*)aData
.getConstArray();
320 while( iPos
< nRead
)
323 if( !implReadLenAndData( pData
, iPos
, aDBKey
) )
326 rtl::OString aOKeyStr
= aDBKey
.getData();
329 const char* pStartPtr
= pData
+ iPos
;
331 sal_Int32 nValLen
= strtol( pStartPtr
, &pEndPtr
, 16 );
332 if( pEndPtr
== pStartPtr
)
335 iPos
+= (pEndPtr
- pStartPtr
) + 1;
337 if( bOptimizeForPerformance
)
339 const char* pValSrc
= pData
+ iPos
;
340 rtl::OString
aValStr( pValSrc
, nValLen
);
341 (*m_pStringToDataMap
)[aOKeyStr
] = aValStr
;
345 // store value start position
346 (*m_pStringToValPosMap
)[aOKeyStr
] = std::pair
<int,int>( iPos
, nValLen
);
355 void DBHelp::releaseHashMap( void )
357 if( m_pStringToDataMap
!= NULL
)
359 delete m_pStringToDataMap
;
360 m_pStringToDataMap
= NULL
;
362 if( m_pStringToValPosMap
!= NULL
)
364 delete m_pStringToValPosMap
;
365 m_pStringToValPosMap
= NULL
;
370 bool DBHelp::getValueForKey( const rtl::OString
& rKey
, DBData
& rValue
)
372 bool bSuccess
= false;
379 if( m_pStringToDataMap
== NULL
&& m_pStringToValPosMap
== NULL
)
381 bool bOptimizeForPerformance
= false;
382 createHashMap( bOptimizeForPerformance
);
385 if( m_pStringToValPosMap
!= NULL
)
387 StringToValPosMap::const_iterator it
= m_pStringToValPosMap
->find( rKey
);
388 if( it
!= m_pStringToValPosMap
->end() )
390 const std::pair
<int,int>& rValPair
= it
->second
;
391 int iValuePos
= rValPair
.first
;
392 int nValueLen
= rValPair
.second
;
394 Reference
< XInputStream
> xIn
= m_xSFA
->openFileRead( m_aFileName
);
397 Reference
< XSeekable
> xXSeekable( xIn
, UNO_QUERY
);
398 if( xXSeekable
.is() )
400 xXSeekable
->seek( iValuePos
);
402 Sequence
< sal_Int8
> aData
;
403 sal_Int32 nRead
= xIn
->readBytes( aData
, nValueLen
);
404 if( nRead
== nValueLen
)
406 const char* pData
= (const sal_Char
*)aData
.getConstArray();
407 rValue
.copyToBuffer( pData
, nValueLen
);
416 else if( m_pStringToDataMap
!= NULL
)
418 StringToDataMap::const_iterator it
= m_pStringToDataMap
->find( rKey
);
419 if( it
!= m_pStringToDataMap
->end() )
421 const rtl::OString
& rValueStr
= it
->second
;
422 int nValueLen
= rValueStr
.getLength();
423 const char* pData
= rValueStr
.getStr();
424 rValue
.copyToBuffer( pData
, nValueLen
);
438 bool DBHelp::startIteration( void )
440 bool bSuccess
= false;
442 sal_Int32 nSize
= m_xSFA
->getSize( m_aFileName
);
444 Reference
< XInputStream
> xIn
= m_xSFA
->openFileRead( m_aFileName
);
447 m_nItRead
= xIn
->readBytes( m_aItData
, nSize
);
448 if( m_nItRead
== nSize
)
451 m_pItData
= (const char*)m_aItData
.getConstArray();
463 bool DBHelp::getNextKeyAndValue( DBData
& rKey
, DBData
& rValue
)
465 bool bSuccess
= false;
467 if( m_iItPos
< m_nItRead
)
469 if( implReadLenAndData( m_pItData
, m_iItPos
, rKey
) )
471 if( implReadLenAndData( m_pItData
, m_iItPos
, rValue
) )
479 void DBHelp::stopIteration( void )
481 m_aItData
= Sequence
<sal_Int8
>();
490 db_internal::check_error( db_create(&m_pDBP
,0,0),"Db::Db" );
507 int Db::close(u_int32_t flags
)
509 int error
= m_pDBP
->close(m_pDBP
,flags
);
511 return db_internal::check_error(error
,"Db::close");
514 int Db::open(DB_TXN
*txnid
,
516 const char *database
,
521 int err
= m_pDBP
->open(m_pDBP
,txnid
,file
,database
,type
,flags
,mode
);
522 return db_internal::check_error( err
,"Db::open" );
526 int Db::get(DB_TXN
*txnid
, Dbt
*key
, Dbt
*data
, u_int32_t flags
)
528 int err
= m_pDBP
->get(m_pDBP
,txnid
,key
,data
,flags
);
530 // these are non-exceptional outcomes
531 if (err
!= DB_NOTFOUND
&& err
!= DB_KEYEMPTY
)
532 db_internal::check_error( err
,"Db::get" );
537 int Db::cursor(DB_TXN
*txnid
, Dbc
**cursorp
, u_int32_t flags
)
540 int error
= m_pDBP
->cursor(m_pDBP
,txnid
,&dbc
,flags
);
542 if (!db_internal::check_error(error
,"Db::cursor"))
543 *cursorp
= new Dbc(dbc
);
548 //----------------------------------------------------------------------------
561 int err
= m_pDBC
->c_close(m_pDBC
);
563 return db_internal::check_error( err
,"Dbcursor::close" );
566 int Dbc::get(Dbt
*key
, Dbt
*data
, u_int32_t flags
)
568 int err
= m_pDBC
->c_get(m_pDBC
,key
,data
,flags
);
570 // these are non-exceptional outcomes
571 if (err
!= DB_NOTFOUND
&& err
!= DB_KEYEMPTY
)
572 db_internal::check_error( err
, "Dbcursor::get" );
577 //----------------------------------------------------------------------------
583 DBT
* thispod
= this;
584 memset(thispod
, 0, sizeof *thispod
);
588 Dbt::Dbt(void *data_arg
, u_int32_t size_arg
)
591 DBT
* thispod
= this;
592 memset(thispod
, 0, sizeof *thispod
);
593 this->set_data(data_arg
);
594 this->set_size(size_arg
);
598 Dbt::Dbt(const Dbt & other)
601 const DBT *otherpod = &other;
603 memcpy(thispod, otherpod, sizeof *thispod);
606 Dbt& Dbt::operator = (const Dbt & other)
611 const DBT *otherpod = &other;
613 memcpy(thispod, otherpod, sizeof *thispod);
623 void * Dbt::get_data() const
628 void Dbt::set_data(void *value
)
633 u_int32_t
Dbt::get_size() const
638 void Dbt::set_size(u_int32_t value
)
643 void Dbt::set_flags(u_int32_t value
)
648 //----------------------------------------------------------------------------
650 void db_internal::raise_error(int dberr, const char * where)
652 if (!where) where = "<unknown>";
654 const char * dberrmsg = db_strerror(dberr);
655 if (!dberrmsg || !*dberrmsg) dberrmsg = "<unknown DB error>";
657 rtl::OString msg = where;
661 throw DbException(msg);
665 //----------------------------------------------------------------------------