1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_xmlhelp.hxx" 30 31 #include "db.hxx" 32 33 #include <rtl/alloc.h> 34 #include <cstring> 35 36 #include "com/sun/star/io/XSeekable.hpp" 37 38 #include "osl/file.hxx" 39 #include "osl/thread.hxx" 40 #ifdef TEST_DBHELP 41 #include <osl/time.h> 42 #endif 43 44 using namespace com::sun::star; 45 using namespace com::sun::star::uno; 46 using namespace com::sun::star::io; 47 48 namespace berkeleydbproxy { 49 50 //---------------------------------------------------------------------------- 51 namespace db_internal 52 { 53 // static void raise_error(int dberr, const char * where); 54 55 static inline int check_error(int dberr, const char * where) 56 { 57 (void)where; 58 59 // if (dberr) raise_error(dberr,where); 60 return dberr; 61 } 62 } 63 64 void DBData::copyToBuffer( const char* pSrcData, int nSize ) 65 { 66 m_nSize = nSize; 67 delete [] m_pBuffer; 68 m_pBuffer = new char[m_nSize+1]; 69 memcpy( m_pBuffer, pSrcData, m_nSize ); 70 m_pBuffer[m_nSize] = 0; 71 } 72 73 74 // DBHelp 75 76 bool DBHelp::implReadLenAndData( const char* pData, int& riPos, DBData& rValue ) 77 { 78 bool bSuccess = false; 79 80 // Read key len 81 const char* pStartPtr = pData + riPos; 82 char* pEndPtr; 83 sal_Int32 nKeyLen = strtol( pStartPtr, &pEndPtr, 16 ); 84 if( pEndPtr == pStartPtr ) 85 return bSuccess; 86 riPos += (pEndPtr - pStartPtr) + 1; 87 88 const char* pKeySrc = pData + riPos; 89 rValue.copyToBuffer( pKeySrc, nKeyLen ); 90 riPos += nKeyLen + 1; 91 92 bSuccess = true; 93 return bSuccess; 94 } 95 96 #ifdef TEST_DBHELP 97 98 typedef std::pair< rtl::OString, rtl::OString > KeyValPair; 99 typedef std::vector< KeyValPair > KeyValPairVector; 100 101 void testWriteKeyValue( FILE* pFile, const KeyValPair& rKeyValPair ) 102 { 103 if( pFile == NULL ) 104 return; 105 char cLF = 10; 106 107 const rtl::OString& aKeyStr = rKeyValPair.first; 108 const rtl::OString& aValueStr = rKeyValPair.second; 109 int nKeyLen = aKeyStr.getLength(); 110 int nValueLen = aValueStr.getLength(); 111 fprintf( pFile, "%x ", nKeyLen ); 112 if( nKeyLen > 0 ) 113 fwrite( aKeyStr.getStr(), 1, nKeyLen, pFile ); 114 fprintf( pFile, " %x ", nValueLen ); 115 if( nValueLen > 0 ) 116 fwrite( aValueStr.getStr(), 1, nValueLen, pFile ); 117 fprintf( pFile, "%c", cLF ); 118 } 119 120 bool DBHelp::testAgainstDb( const rtl::OUString& fileURL, bool bOldDbAccess ) 121 { 122 bool bSuccess = true; 123 124 KeyValPairVector avKeyValPair; 125 126 rtl::OUString aOutFileName = fileURL; 127 aOutFileName += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("_TestOut")); 128 if( bOldDbAccess ) 129 aOutFileName += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("_Old")); 130 #ifdef WNT 131 FILE* pFile = _wfopen( aOutFileName.getStr(), L"wb" ); 132 #else 133 rtl::OString sFile = rtl::OUStringToOString(aOutFileName, osl_getThreadTextEncoding()); 134 FILE* pFile = fopen( sFile.getStr(), "wb" ); 135 #endif 136 // Get all values 137 Db table; 138 if( 0 == table.open( 0,fileURL,DB_BTREE,DB_RDONLY,0644 ) ) 139 { 140 bool first = true; 141 142 Dbc* cursor = 0; 143 table.cursor( 0,&cursor,0 ); 144 Dbt key_,data; 145 key_.set_flags( DB_DBT_MALLOC ); // Initially the cursor must allocate the necessary memory 146 data.set_flags( DB_DBT_MALLOC ); 147 148 while( cursor && DB_NOTFOUND != cursor->get( &key_,&data,DB_NEXT ) ) 149 { 150 rtl::OString keyword( static_cast<sal_Char*>(key_.get_data()), 151 key_.get_size() ); 152 rtl::OString value( static_cast<sal_Char*>(data.get_data()), 153 data.get_size() ); 154 155 KeyValPair aPair( keyword, value ); 156 avKeyValPair.push_back( aPair ); 157 if( pFile != NULL ) 158 testWriteKeyValue( pFile, aPair ); 159 160 if( first ) 161 { 162 key_.set_flags( DB_DBT_REALLOC ); 163 data.set_flags( DB_DBT_REALLOC ); 164 first = false; 165 } 166 } 167 168 if( cursor ) cursor->close(); 169 } 170 table.close( 0 ); 171 172 // TEST 173 DBData aDBData; 174 Db tableTest; 175 Dbt data; 176 177 int nOkCount = 0; 178 int nErrCount = 0; 179 180 bool bTestSuccess; 181 const char* pTestReadData = NULL; 182 int nTestReadDataSize = 0; 183 184 sal_uInt32 starttime = osl_getGlobalTimer(); 185 sal_uInt32 afterfirsttime = starttime; 186 187 if( pFile != NULL ) 188 { 189 if( bOldDbAccess ) 190 fprintf( pFile, "\nTesting old access:\n" ); 191 else 192 fprintf( pFile, "\nTesting new access:\n" ); 193 } 194 195 KeyValPairVector::const_iterator it; 196 bool bFirst = true; 197 for( it = avKeyValPair.begin() ; it != avKeyValPair.end() ; ++it ) 198 { 199 const KeyValPair& rKeyValPair = *it; 200 201 const rtl::OString& aKeyStr = rKeyValPair.first; 202 const rtl::OString& aValueStr = rKeyValPair.second; 203 int nKeyLen = aKeyStr.getLength(); 204 int nValueLen = aValueStr.getLength(); 205 206 const sal_Char* ptr = aValueStr.getStr(); 207 208 bTestSuccess = false; 209 pTestReadData = NULL; 210 nTestReadDataSize = 0; 211 if( bOldDbAccess ) 212 { 213 if( bFirst ) 214 { 215 if( tableTest.open( 0,fileURL, DB_BTREE,DB_RDONLY,0644 ) ) 216 { 217 if( pFile != NULL ) 218 fprintf( pFile, "Cannot open database\n" ); 219 220 break; 221 } 222 } 223 224 Dbt key( static_cast< void* >( const_cast< sal_Char* >( aKeyStr.getStr() ) ), aKeyStr.getLength() ); 225 int err = tableTest.get( 0, &key, &data, 0 ); 226 if( err == 0 ) 227 { 228 bTestSuccess = true; 229 pTestReadData = static_cast< sal_Char* >( data.get_data() ); 230 nTestReadDataSize = data.get_size(); 231 } 232 } 233 else 234 { 235 bTestSuccess = getValueForKey( aKeyStr, aDBData ); 236 if( bTestSuccess ) 237 { 238 pTestReadData = aDBData.getData(); 239 nTestReadDataSize = aDBData.getSize(); 240 } 241 } 242 if( bFirst ) 243 { 244 afterfirsttime = osl_getGlobalTimer(); 245 bFirst = false; 246 } 247 int nError = 0; 248 if( bTestSuccess && pTestReadData != NULL ) 249 { 250 int nCmp = memcmp( ptr, pTestReadData, nValueLen ); 251 if( nCmp == 0 ) 252 ++nOkCount; 253 else 254 nError = 1; 255 256 if( nValueLen != nTestReadDataSize ) 257 nError = 2; 258 } 259 else 260 nError = 3; 261 262 if( nError != 0 ) 263 { 264 bSuccess = false; 265 ++nErrCount; 266 267 if( pFile != NULL ) 268 { 269 fprintf( pFile, "ERROR, not found:\n" ); 270 testWriteKeyValue( pFile, rKeyValPair ); 271 fprintf( pFile, "\nError Code: %d\n", nError ); 272 } 273 } 274 } 275 tableTest.close( 0 ); 276 277 sal_uInt32 endtime = osl_getGlobalTimer(); 278 double dDiffTime = (endtime-starttime) / 1000.0; 279 double dDiffFirstTime = (afterfirsttime-starttime) / 1000.0; 280 if( pFile != NULL ) 281 { 282 int nCount = avKeyValPair.size(); 283 fprintf( pFile, "%d key/values in total, read %d correctly, %d errors\n", 284 nCount, nOkCount, nErrCount ); 285 fprintf( pFile, "Time taken: %g s (First access %g s)\n", dDiffTime, dDiffFirstTime ); 286 fprintf( pFile, "Average time per access: %g s\n", dDiffTime / nCount ); 287 } 288 289 if( pFile != NULL ) 290 fclose( pFile ); 291 292 return bSuccess; 293 } 294 295 #endif 296 297 298 void DBHelp::createHashMap( bool bOptimizeForPerformance ) 299 { 300 releaseHashMap(); 301 if( bOptimizeForPerformance ) 302 { 303 if( m_pStringToDataMap != NULL ) 304 return; 305 m_pStringToDataMap = new StringToDataMap(); 306 } 307 else 308 { 309 if( m_pStringToValPosMap != NULL ) 310 return; 311 m_pStringToValPosMap = new StringToValPosMap(); 312 } 313 314 Reference< XInputStream > xIn = m_xSFA->openFileRead( m_aFileURL ); 315 if( xIn.is() ) 316 { 317 Sequence< sal_Int8 > aData; 318 sal_Int32 nSize = m_xSFA->getSize( m_aFileURL ); 319 sal_Int32 nRead = xIn->readBytes( aData, nSize ); 320 321 const char* pData = (const char*)aData.getConstArray(); 322 int iPos = 0; 323 while( iPos < nRead ) 324 { 325 DBData aDBKey; 326 if( !implReadLenAndData( pData, iPos, aDBKey ) ) 327 break; 328 329 rtl::OString aOKeyStr = aDBKey.getData(); 330 331 // Read val len 332 const char* pStartPtr = pData + iPos; 333 char* pEndPtr; 334 sal_Int32 nValLen = strtol( pStartPtr, &pEndPtr, 16 ); 335 if( pEndPtr == pStartPtr ) 336 break; 337 338 iPos += (pEndPtr - pStartPtr) + 1; 339 340 if( bOptimizeForPerformance ) 341 { 342 const char* pValSrc = pData + iPos; 343 rtl::OString aValStr( pValSrc, nValLen ); 344 (*m_pStringToDataMap)[aOKeyStr] = aValStr; 345 } 346 else 347 { 348 // store value start position 349 (*m_pStringToValPosMap)[aOKeyStr] = std::pair<int,int>( iPos, nValLen ); 350 } 351 iPos += nValLen + 1; 352 } 353 354 xIn->closeInput(); 355 } 356 } 357 358 void DBHelp::releaseHashMap( void ) 359 { 360 if( m_pStringToDataMap != NULL ) 361 { 362 delete m_pStringToDataMap; 363 m_pStringToDataMap = NULL; 364 } 365 if( m_pStringToValPosMap != NULL ) 366 { 367 delete m_pStringToValPosMap; 368 m_pStringToValPosMap = NULL; 369 } 370 } 371 372 373 bool DBHelp::getValueForKey( const rtl::OString& rKey, DBData& rValue ) 374 { 375 bool bSuccess = false; 376 if( !m_xSFA.is() ) 377 return bSuccess; 378 379 try 380 { 381 382 if( m_pStringToDataMap == NULL && m_pStringToValPosMap == NULL ) 383 { 384 bool bOptimizeForPerformance = false; 385 createHashMap( bOptimizeForPerformance ); 386 } 387 388 if( m_pStringToValPosMap != NULL ) 389 { 390 StringToValPosMap::const_iterator it = m_pStringToValPosMap->find( rKey ); 391 if( it != m_pStringToValPosMap->end() ) 392 { 393 const std::pair<int,int>& rValPair = it->second; 394 int iValuePos = rValPair.first; 395 int nValueLen = rValPair.second; 396 397 Reference< XInputStream > xIn = m_xSFA->openFileRead( m_aFileURL ); 398 if( xIn.is() ) 399 { 400 Reference< XSeekable > xXSeekable( xIn, UNO_QUERY ); 401 if( xXSeekable.is() ) 402 { 403 xXSeekable->seek( iValuePos ); 404 405 Sequence< sal_Int8 > aData; 406 sal_Int32 nRead = xIn->readBytes( aData, nValueLen ); 407 if( nRead == nValueLen ) 408 { 409 const char* pData = (const sal_Char*)aData.getConstArray(); 410 rValue.copyToBuffer( pData, nValueLen ); 411 bSuccess = true; 412 } 413 } 414 xIn->closeInput(); 415 } 416 } 417 } 418 419 else if( m_pStringToDataMap != NULL ) 420 { 421 StringToDataMap::const_iterator it = m_pStringToDataMap->find( rKey ); 422 if( it != m_pStringToDataMap->end() ) 423 { 424 const rtl::OString& rValueStr = it->second; 425 int nValueLen = rValueStr.getLength(); 426 const char* pData = rValueStr.getStr(); 427 rValue.copyToBuffer( pData, nValueLen ); 428 bSuccess = true; 429 } 430 } 431 432 } 433 catch( Exception & ) 434 { 435 bSuccess = false; 436 } 437 438 return bSuccess; 439 } 440 441 bool DBHelp::startIteration( void ) 442 { 443 bool bSuccess = false; 444 445 sal_Int32 nSize = m_xSFA->getSize( m_aFileURL ); 446 447 Reference< XInputStream > xIn = m_xSFA->openFileRead( m_aFileURL ); 448 if( xIn.is() ) 449 { 450 m_nItRead = xIn->readBytes( m_aItData, nSize ); 451 if( m_nItRead == nSize ) 452 { 453 bSuccess = true; 454 m_pItData = (const char*)m_aItData.getConstArray(); 455 m_iItPos = 0; 456 } 457 else 458 { 459 stopIteration(); 460 } 461 } 462 463 return bSuccess; 464 } 465 466 bool DBHelp::getNextKeyAndValue( DBData& rKey, DBData& rValue ) 467 { 468 bool bSuccess = false; 469 470 if( m_iItPos < m_nItRead ) 471 { 472 if( implReadLenAndData( m_pItData, m_iItPos, rKey ) ) 473 { 474 if( implReadLenAndData( m_pItData, m_iItPos, rValue ) ) 475 bSuccess = true; 476 } 477 } 478 479 return bSuccess; 480 } 481 482 void DBHelp::stopIteration( void ) 483 { 484 m_aItData = Sequence<sal_Int8>(); 485 m_pItData = NULL; 486 m_nItRead = -1; 487 m_iItPos = -1; 488 } 489 490 491 Db::Db() 492 { 493 db_internal::check_error( db_create(&m_pDBP,0,0),"Db::Db" ); 494 m_pDBHelp = NULL; 495 } 496 497 498 Db::~Db() 499 { 500 if (m_pDBP) 501 { 502 // should not happen 503 // TODO: add assert 504 } 505 506 delete m_pDBHelp; 507 } 508 509 510 int Db::close(u_int32_t flags) 511 { 512 int error = m_pDBP->close(m_pDBP,flags); 513 m_pDBP = 0; 514 return db_internal::check_error(error,"Db::close"); 515 } 516 517 int Db::open(DB_TXN *txnid, 518 const char *file, 519 const char *database, 520 DBTYPE type, 521 u_int32_t flags, 522 int mode) 523 { 524 int err = m_pDBP->open(m_pDBP,txnid,file,database,type,flags,mode); 525 return db_internal::check_error( err,"Db::open" ); 526 } 527 528 int Db::open(DB_TXN *txnid, 529 ::rtl::OUString const & fileURL, 530 DBTYPE type, 531 u_int32_t flags, 532 int mode) 533 { 534 ::rtl::OUString ouPath; 535 ::osl::FileBase::getSystemPathFromFileURL(fileURL, ouPath); 536 const ::rtl::OString sPath = ::rtl::OUStringToOString(ouPath, osl_getThreadTextEncoding()); 537 return open(txnid, sPath.getStr(), 0, type, flags, mode); 538 } 539 540 541 542 int Db::get(DB_TXN *txnid, Dbt *key, Dbt *data, u_int32_t flags) 543 { 544 int err = m_pDBP->get(m_pDBP,txnid,key,data,flags); 545 546 // these are non-exceptional outcomes 547 if (err != DB_NOTFOUND && err != DB_KEYEMPTY) 548 db_internal::check_error( err,"Db::get" ); 549 550 return err; 551 } 552 553 int Db::cursor(DB_TXN *txnid, Dbc **cursorp, u_int32_t flags) 554 { 555 DBC * dbc = 0; 556 int error = m_pDBP->cursor(m_pDBP,txnid,&dbc,flags); 557 558 if (!db_internal::check_error(error,"Db::cursor")) 559 *cursorp = new Dbc(dbc); 560 561 return error; 562 } 563 564 //---------------------------------------------------------------------------- 565 566 Dbc::Dbc(DBC * dbc) 567 : m_pDBC(dbc) 568 { 569 } 570 571 Dbc::~Dbc() 572 { 573 } 574 575 int Dbc::close() 576 { 577 int err = m_pDBC->c_close(m_pDBC); 578 delete this; 579 return db_internal::check_error( err,"Dbcursor::close" ); 580 } 581 582 int Dbc::get(Dbt *key, Dbt *data, u_int32_t flags) 583 { 584 int err = m_pDBC->c_get(m_pDBC,key,data,flags); 585 586 // these are non-exceptional outcomes 587 if (err != DB_NOTFOUND && err != DB_KEYEMPTY) 588 db_internal::check_error( err, "Dbcursor::get" ); 589 590 return err; 591 } 592 593 //---------------------------------------------------------------------------- 594 595 596 Dbt::Dbt() 597 { 598 using namespace std; 599 DBT * thispod = this; 600 memset(thispod, 0, sizeof *thispod); 601 } 602 603 604 Dbt::Dbt(void *data_arg, u_int32_t size_arg) 605 { 606 using namespace std; 607 DBT * thispod = this; 608 memset(thispod, 0, sizeof *thispod); 609 this->set_data(data_arg); 610 this->set_size(size_arg); 611 } 612 613 /* 614 Dbt::Dbt(const Dbt & other) 615 { 616 using namespace std; 617 const DBT *otherpod = &other; 618 DBT *thispod = this; 619 memcpy(thispod, otherpod, sizeof *thispod); 620 } 621 622 Dbt& Dbt::operator = (const Dbt & other) 623 { 624 if (this != &other) 625 { 626 using namespace std; 627 const DBT *otherpod = &other; 628 DBT *thispod = this; 629 memcpy(thispod, otherpod, sizeof *thispod); 630 } 631 return *this; 632 } 633 */ 634 635 Dbt::~Dbt() 636 { 637 } 638 639 void * Dbt::get_data() const 640 { 641 return this->data; 642 } 643 644 void Dbt::set_data(void *value) 645 { 646 this->data = value; 647 } 648 649 u_int32_t Dbt::get_size() const 650 { 651 return this->size; 652 } 653 654 void Dbt::set_size(u_int32_t value) 655 { 656 this->size = value; 657 } 658 659 void Dbt::set_flags(u_int32_t value) 660 { 661 this->flags = value; 662 } 663 664 //---------------------------------------------------------------------------- 665 /* 666 void db_internal::raise_error(int dberr, const char * where) 667 { 668 if (!where) where = "<unknown>"; 669 670 const char * dberrmsg = db_strerror(dberr); 671 if (!dberrmsg || !*dberrmsg) dberrmsg = "<unknown DB error>"; 672 673 rtl::OString msg = where; 674 msg += ": "; 675 msg += dberrmsg; 676 677 throw DbException(msg); 678 } 679 */ 680 681 //---------------------------------------------------------------------------- 682 } // namespace ecomp 683 684