@@ -32,12 +32,12 @@ void CheckUniqueFileid(const BerkeleyEnvironment& env, const std::string& filena
32
32
33
33
int ret = db.get_mpf ()->get_fileid (fileid.value );
34
34
if (ret != 0 ) {
35
- throw std::runtime_error (strprintf (" BerkeleyBatch : Can't open database %s (get_fileid failed with %d)" , filename, ret));
35
+ throw std::runtime_error (strprintf (" BerkeleyDatabase : Can't open database %s (get_fileid failed with %d)" , filename, ret));
36
36
}
37
37
38
38
for (const auto & item : env.m_fileids ) {
39
39
if (fileid == item.second && &fileid != &item.second ) {
40
- throw std::runtime_error (strprintf (" BerkeleyBatch : Can't open database %s (duplicates fileid %s from %s)" , filename,
40
+ throw std::runtime_error (strprintf (" BerkeleyDatabase : Can't open database %s (duplicates fileid %s from %s)" , filename,
41
41
HexStr (std::begin (item.second .value ), std::end (item.second .value )), item.first ));
42
42
}
43
43
}
@@ -97,9 +97,8 @@ void BerkeleyEnvironment::Close()
97
97
fDbEnvInit = false ;
98
98
99
99
for (auto & db : m_databases) {
100
- auto count = mapFileUseCount.find (db.first );
101
- assert (count == mapFileUseCount.end () || count->second == 0 );
102
100
BerkeleyDatabase& database = db.second .get ();
101
+ assert (database.m_refcount <= 0 );
103
102
if (database.m_db ) {
104
103
database.m_db ->close (0 );
105
104
database.m_db .reset ();
@@ -232,16 +231,6 @@ BerkeleyEnvironment::BerkeleyEnvironment()
232
231
fMockDb = true ;
233
232
}
234
233
235
- bool BerkeleyEnvironment::Verify (const std::string& strFile)
236
- {
237
- LOCK (cs_db);
238
- assert (mapFileUseCount.count (strFile) == 0 );
239
-
240
- Db db (dbenv.get (), 0 );
241
- int result = db.verify (strFile.c_str (), nullptr , nullptr , 0 );
242
- return result == 0 ;
243
- }
244
-
245
234
BerkeleyBatch::SafeDbt::SafeDbt ()
246
235
{
247
236
m_dbt.set_flags (DB_DBT_MALLOC);
@@ -295,7 +284,11 @@ bool BerkeleyDatabase::Verify(bilingual_str& errorStr)
295
284
296
285
if (fs::exists (file_path))
297
286
{
298
- if (!env->Verify (strFile)) {
287
+ assert (m_refcount == 0 );
288
+
289
+ Db db (env->dbenv .get (), 0 );
290
+ int result = db.verify (strFile.c_str (), nullptr , nullptr , 0 );
291
+ if (result != 0 ) {
299
292
errorStr = strprintf (_ (" %s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup." ), file_path);
300
293
return false ;
301
294
}
@@ -316,6 +309,8 @@ BerkeleyDatabase::~BerkeleyDatabase()
316
309
{
317
310
if (env) {
318
311
LOCK (cs_db);
312
+ env->CloseDb (strFile);
313
+ assert (!m_db);
319
314
size_t erased = env->m_databases .erase (strFile);
320
315
assert (erased == 1 );
321
316
env->m_fileids .erase (strFile);
@@ -324,13 +319,27 @@ BerkeleyDatabase::~BerkeleyDatabase()
324
319
325
320
BerkeleyBatch::BerkeleyBatch (BerkeleyDatabase& database, const char * pszMode, bool fFlushOnCloseIn ) : pdb(nullptr ), activeTxn(nullptr ), m_cursor(nullptr ), m_database(database)
326
321
{
322
+ database.AddRef ();
323
+ database.Open (pszMode);
327
324
fReadOnly = (!strchr (pszMode, ' +' ) && !strchr (pszMode, ' w' ));
328
325
fFlushOnClose = fFlushOnCloseIn ;
329
326
env = database.env .get ();
330
- if (database.IsDummy ()) {
327
+ pdb = database.m_db .get ();
328
+ strFile = database.strFile ;
329
+ bool fCreate = strchr (pszMode, ' c' ) != nullptr ;
330
+ if (fCreate && !Exists (std::string (" version" ))) {
331
+ bool fTmp = fReadOnly ;
332
+ fReadOnly = false ;
333
+ Write (std::string (" version" ), CLIENT_VERSION);
334
+ fReadOnly = fTmp ;
335
+ }
336
+ }
337
+
338
+ void BerkeleyDatabase::Open (const char * pszMode)
339
+ {
340
+ if (IsDummy ()){
331
341
return ;
332
342
}
333
- const std::string &strFilename = database.strFile ;
334
343
335
344
bool fCreate = strchr (pszMode, ' c' ) != nullptr ;
336
345
unsigned int nFlags = DB_THREAD;
@@ -341,10 +350,9 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo
341
350
LOCK (cs_db);
342
351
bilingual_str open_err;
343
352
if (!env->Open (open_err))
344
- throw std::runtime_error (" BerkeleyBatch : Failed to open database environment." );
353
+ throw std::runtime_error (" BerkeleyDatabase : Failed to open database environment." );
345
354
346
- pdb = database.m_db .get ();
347
- if (pdb == nullptr ) {
355
+ if (m_db == nullptr ) {
348
356
int ret;
349
357
std::unique_ptr<Db> pdb_temp = MakeUnique<Db>(env->dbenv .get (), 0 );
350
358
@@ -353,60 +361,33 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo
353
361
DbMpoolFile* mpf = pdb_temp->get_mpf ();
354
362
ret = mpf->set_flags (DB_MPOOL_NOFILE, 1 );
355
363
if (ret != 0 ) {
356
- throw std::runtime_error (strprintf (" BerkeleyBatch : Failed to configure for no temp file backing for database %s" , strFilename ));
364
+ throw std::runtime_error (strprintf (" BerkeleyDatabase : Failed to configure for no temp file backing for database %s" , strFile ));
357
365
}
358
366
}
359
367
360
368
ret = pdb_temp->open (nullptr , // Txn pointer
361
- fMockDb ? nullptr : strFilename .c_str (), // Filename
362
- fMockDb ? strFilename .c_str () : " main" , // Logical db name
369
+ fMockDb ? nullptr : strFile .c_str (), // Filename
370
+ fMockDb ? strFile .c_str () : " main" , // Logical db name
363
371
DB_BTREE, // Database type
364
372
nFlags, // Flags
365
373
0 );
366
374
367
375
if (ret != 0 ) {
368
- throw std::runtime_error (strprintf (" BerkeleyBatch : Error %d, can't open database %s" , ret, strFilename ));
376
+ throw std::runtime_error (strprintf (" BerkeleyDatabase : Error %d, can't open database %s" , ret, strFile ));
369
377
}
378
+ m_file_path = (env->Directory () / strFile).string ();
370
379
371
380
// Call CheckUniqueFileid on the containing BDB environment to
372
381
// avoid BDB data consistency bugs that happen when different data
373
382
// files in the same environment have the same fileid.
374
- //
375
- // Also call CheckUniqueFileid on all the other g_dbenvs to prevent
376
- // bitcoin from opening the same data file through another
377
- // environment when the file is referenced through equivalent but
378
- // not obviously identical symlinked or hard linked or bind mounted
379
- // paths. In the future a more relaxed check for equal inode and
380
- // device ids could be done instead, which would allow opening
381
- // different backup copies of a wallet at the same time. Maybe even
382
- // more ideally, an exclusive lock for accessing the database could
383
- // be implemented, so no equality checks are needed at all. (Newer
384
- // versions of BDB have an set_lk_exclusive method for this
385
- // purpose, but the older version we use does not.)
386
- for (const auto & env : g_dbenvs) {
387
- CheckUniqueFileid (*env.second .lock ().get (), strFilename, *pdb_temp, this ->env ->m_fileids [strFilename]);
388
- }
383
+ CheckUniqueFileid (*env, strFile, *pdb_temp, this ->env ->m_fileids [strFile]);
389
384
390
- pdb = pdb_temp.release ();
391
- database.m_db .reset (pdb);
385
+ m_db.reset (pdb_temp.release ());
392
386
393
- if (fCreate && !Exists (std::string (" version" ))) {
394
- bool fTmp = fReadOnly ;
395
- fReadOnly = false ;
396
- Write (std::string (" version" ), CLIENT_VERSION);
397
- fReadOnly = fTmp ;
398
- }
399
387
}
400
- database.AddRef ();
401
- strFile = strFilename;
402
388
}
403
389
}
404
390
405
- void BerkeleyDatabase::Open (const char * mode)
406
- {
407
- throw std::logic_error (" BerkeleyDatabase does not implement Open. This function should not be called." );
408
- }
409
-
410
391
void BerkeleyBatch::Flush ()
411
392
{
412
393
if (activeTxn)
@@ -427,6 +408,12 @@ void BerkeleyDatabase::IncrementUpdateCounter()
427
408
++nUpdateCounter;
428
409
}
429
410
411
+ BerkeleyBatch::~BerkeleyBatch ()
412
+ {
413
+ Close ();
414
+ m_database.RemoveRef ();
415
+ }
416
+
430
417
void BerkeleyBatch::Close ()
431
418
{
432
419
if (!pdb)
@@ -439,8 +426,6 @@ void BerkeleyBatch::Close()
439
426
440
427
if (fFlushOnClose )
441
428
Flush ();
442
-
443
- m_database.RemoveRef ();
444
429
}
445
430
446
431
void BerkeleyEnvironment::CloseDb (const std::string& strFile)
@@ -464,8 +449,8 @@ void BerkeleyEnvironment::ReloadDbEnv()
464
449
AssertLockNotHeld (cs_db);
465
450
std::unique_lock<RecursiveMutex> lock (cs_db);
466
451
m_db_in_use.wait (lock, [this ](){
467
- for (auto & count : mapFileUseCount ) {
468
- if (count .second > 0 ) return false ;
452
+ for (auto & db : m_databases ) {
453
+ if (db .second . get (). m_refcount > 0 ) return false ;
469
454
}
470
455
return true ;
471
456
});
@@ -493,11 +478,11 @@ bool BerkeleyDatabase::Rewrite(const char* pszSkip)
493
478
while (true ) {
494
479
{
495
480
LOCK (cs_db);
496
- if (!env-> mapFileUseCount . count (strFile) || env-> mapFileUseCount [strFile] = = 0 ) {
481
+ if (m_refcount < = 0 ) {
497
482
// Flush log data to the dat file
498
483
env->CloseDb (strFile);
499
484
env->CheckpointLSN (strFile);
500
- env-> mapFileUseCount . erase (strFile) ;
485
+ m_refcount = - 1 ;
501
486
502
487
bool fSuccess = true ;
503
488
LogPrintf (" BerkeleyBatch::Rewrite: Rewriting %s...\n " , strFile);
@@ -581,10 +566,11 @@ void BerkeleyEnvironment::Flush(bool fShutdown)
581
566
return ;
582
567
{
583
568
LOCK (cs_db);
584
- std::map<std::string, int >::iterator mi = mapFileUseCount.begin ();
585
- while (mi != mapFileUseCount.end ()) {
586
- std::string strFile = (*mi).first ;
587
- int nRefCount = (*mi).second ;
569
+ bool no_dbs_accessed = true ;
570
+ for (auto & db_it : m_databases) {
571
+ std::string strFile = db_it.first ;
572
+ int nRefCount = db_it.second .get ().m_refcount ;
573
+ if (nRefCount < 0 ) continue ;
588
574
LogPrint (BCLog::WALLETDB, " BerkeleyEnvironment::Flush: Flushing %s (refcount = %d)...\n " , strFile, nRefCount);
589
575
if (nRefCount == 0 ) {
590
576
// Move log data to the dat file
@@ -595,14 +581,15 @@ void BerkeleyEnvironment::Flush(bool fShutdown)
595
581
if (!fMockDb )
596
582
dbenv->lsn_reset (strFile.c_str (), 0 );
597
583
LogPrint (BCLog::WALLETDB, " BerkeleyEnvironment::Flush: %s closed\n " , strFile);
598
- mapFileUseCount.erase (mi++);
599
- } else
600
- mi++;
584
+ nRefCount = -1 ;
585
+ } else {
586
+ no_dbs_accessed = false ;
587
+ }
601
588
}
602
589
LogPrint (BCLog::WALLETDB, " BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n " , fShutdown ? " true" : " false" , fDbEnvInit ? " " : " database not started" , GetTimeMillis () - nStart);
603
590
if (fShutdown ) {
604
591
char ** listp;
605
- if (mapFileUseCount. empty () ) {
592
+ if (no_dbs_accessed ) {
606
593
dbenv->log_archive (&listp, DB_ARCH_REMOVE);
607
594
Close ();
608
595
if (!fMockDb ) {
@@ -623,21 +610,20 @@ bool BerkeleyDatabase::PeriodicFlush()
623
610
if (!lockDb) return false ;
624
611
625
612
// Don't flush if any databases are in use
626
- for (const auto & use_count : env->mapFileUseCount ) {
627
- if (use_count .second > 0 ) return false ;
613
+ for (auto & it : env->m_databases ) {
614
+ if (it .second . get (). m_refcount > 0 ) return false ;
628
615
}
629
616
630
617
// Don't flush if there haven't been any batch writes for this database.
631
- auto it = env->mapFileUseCount .find (strFile);
632
- if (it == env->mapFileUseCount .end ()) return false ;
618
+ if (m_refcount < 0 ) return false ;
633
619
634
620
LogPrint (BCLog::WALLETDB, " Flushing %s\n " , strFile);
635
621
int64_t nStart = GetTimeMillis ();
636
622
637
623
// Flush wallet file so it's self contained
638
624
env->CloseDb (strFile);
639
625
env->CheckpointLSN (strFile);
640
- env-> mapFileUseCount . erase (it) ;
626
+ m_refcount = - 1 ;
641
627
642
628
LogPrint (BCLog::WALLETDB, " Flushed %s %dms\n " , strFile, GetTimeMillis () - nStart);
643
629
@@ -653,12 +639,11 @@ bool BerkeleyDatabase::Backup(const std::string& strDest) const
653
639
{
654
640
{
655
641
LOCK (cs_db);
656
- if (!env-> mapFileUseCount . count (strFile) || env-> mapFileUseCount [strFile] = = 0 )
642
+ if (m_refcount < = 0 )
657
643
{
658
644
// Flush log data to the dat file
659
645
env->CloseDb (strFile);
660
646
env->CheckpointLSN (strFile);
661
- env->mapFileUseCount .erase (strFile);
662
647
663
648
// Copy wallet file
664
649
fs::path pathSrc = env->Directory () / strFile;
@@ -840,16 +825,18 @@ bool BerkeleyBatch::HasKey(CDataStream&& key)
840
825
void BerkeleyDatabase::AddRef ()
841
826
{
842
827
LOCK (cs_db);
843
- ++env->mapFileUseCount [strFile];
828
+ if (m_refcount < 0 ) {
829
+ m_refcount = 1 ;
830
+ } else {
831
+ m_refcount++;
832
+ }
844
833
}
845
834
846
835
void BerkeleyDatabase::RemoveRef ()
847
836
{
848
- {
849
- LOCK (cs_db);
850
- --env->mapFileUseCount [strFile];
851
- }
852
- env->m_db_in_use .notify_all ();
837
+ LOCK (cs_db);
838
+ m_refcount--;
839
+ if (env) env->m_db_in_use .notify_all ();
853
840
}
854
841
855
842
std::unique_ptr<DatabaseBatch> BerkeleyDatabase::MakeBatch (const char * mode, bool flush_on_close)
0 commit comments