Bitcoin ABC 0.30.7
P2P Digital Currency
bdb.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2020 The Bitcoin Core developers
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#include <wallet/bdb.h>
7#include <wallet/db.h>
8
9#include <common/args.h>
10#include <logging.h>
11#include <sync.h>
12#include <util/fs.h>
13#include <util/fs_helpers.h>
14#include <util/strencodings.h>
15#include <util/time.h>
16#include <util/translation.h>
17
18#include <cstdint>
19#ifndef WIN32
20#include <sys/stat.h>
21#endif
22
23namespace {
33void CheckUniqueFileid(const BerkeleyEnvironment &env,
34 const std::string &filename, Db &db,
35 WalletDatabaseFileId &fileid) {
36 if (env.IsMock()) {
37 return;
38 }
39
40 int ret = db.get_mpf()->get_fileid(fileid.value);
41 if (ret != 0) {
42 throw std::runtime_error(
43 strprintf("BerkeleyDatabase: Can't open database %s (get_fileid "
44 "failed with %d)",
45 filename, ret));
46 }
47
48 for (const auto &item : env.m_fileids) {
49 if (fileid == item.second && &fileid != &item.second) {
50 throw std::runtime_error(
51 strprintf("BerkeleyDatabase: Can't open database %s "
52 "(duplicates fileid %s "
53 "from %s)",
54 filename, HexStr(item.second.value), item.first));
55 }
56 }
57}
58
59RecursiveMutex cs_db;
60
62std::map<std::string, std::weak_ptr<BerkeleyEnvironment>>
63 g_dbenvs GUARDED_BY(cs_db);
64} // namespace
65
67 return memcmp(value, &rhs.value, sizeof(value)) == 0;
68}
69
82std::shared_ptr<BerkeleyEnvironment>
83GetWalletEnv(const fs::path &wallet_path, std::string &database_filename) {
84 fs::path env_directory;
85 SplitWalletPath(wallet_path, env_directory, database_filename);
86 LOCK(cs_db);
87 auto inserted = g_dbenvs.emplace(fs::PathToString(env_directory),
88 std::weak_ptr<BerkeleyEnvironment>());
89 if (inserted.second) {
90 auto env = std::make_shared<BerkeleyEnvironment>(env_directory);
91 inserted.first->second = env;
92 return env;
93 }
94 return inserted.first->second.lock();
95}
96
97//
98// BerkeleyBatch
99//
100
102 if (!fDbEnvInit) {
103 return;
104 }
105
106 fDbEnvInit = false;
107
108 for (auto &db : m_databases) {
109 BerkeleyDatabase &database = db.second.get();
110 assert(database.m_refcount <= 0);
111 if (database.m_db) {
112 database.m_db->close(0);
113 database.m_db.reset();
114 }
115 }
116
117 FILE *error_file = nullptr;
118 dbenv->get_errfile(&error_file);
119
120 int ret = dbenv->close(0);
121 if (ret != 0) {
122 LogPrintf("BerkeleyEnvironment::Close: Error %d closing database "
123 "environment: %s\n",
124 ret, DbEnv::strerror(ret));
125 }
126 if (!fMockDb) {
127 DbEnv(uint32_t(0)).remove(strPath.c_str(), 0);
128 }
129
130 if (error_file) {
131 fclose(error_file);
132 }
133
135}
136
138 dbenv.reset(new DbEnv(DB_CXX_NO_EXCEPTIONS));
139 fDbEnvInit = false;
140 fMockDb = false;
141}
142
144 : strPath(fs::PathToString(dir_path)) {
145 Reset();
146}
147
149 LOCK(cs_db);
150 g_dbenvs.erase(strPath);
151 Close();
152}
153
155 if (fDbEnvInit) {
156 return true;
157 }
158
160 TryCreateDirectories(pathIn);
161 if (!LockDirectory(pathIn, ".walletlock")) {
162 LogPrintf("Cannot obtain a lock on wallet directory %s. Another "
163 "instance of bitcoin may be using it.\n",
164 strPath);
165 err = strprintf(_("Error initializing wallet database environment %s!"),
167 return false;
168 }
169
170 fs::path pathLogDir = pathIn / "database";
171 TryCreateDirectories(pathLogDir);
172 fs::path pathErrorFile = pathIn / "db.log";
173 LogPrintf("BerkeleyEnvironment::Open: LogDir=%s ErrorFile=%s\n",
174 fs::PathToString(pathLogDir), fs::PathToString(pathErrorFile));
175
176 unsigned int nEnvFlags = 0;
177 if (gArgs.GetBoolArg("-privdb", DEFAULT_WALLET_PRIVDB)) {
178 nEnvFlags |= DB_PRIVATE;
179 }
180
181 dbenv->set_lg_dir(fs::PathToString(pathLogDir).c_str());
182 // 1 MiB should be enough for just the wallet
183 dbenv->set_cachesize(0, 0x100000, 1);
184 dbenv->set_lg_bsize(0x10000);
185 dbenv->set_lg_max(1048576);
186 dbenv->set_lk_max_locks(40000);
187 dbenv->set_lk_max_objects(40000);
189 dbenv->set_errfile(fsbridge::fopen(pathErrorFile, "a"));
190 dbenv->set_flags(DB_AUTO_COMMIT, 1);
191 dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1);
192 dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1);
193 int ret =
194 dbenv->open(strPath.c_str(),
195 DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL |
196 DB_INIT_TXN | DB_THREAD | DB_RECOVER | nEnvFlags,
197 S_IRUSR | S_IWUSR);
198 if (ret != 0) {
199 LogPrintf("BerkeleyEnvironment::Open: Error %d opening database "
200 "environment: %s\n",
201 ret, DbEnv::strerror(ret));
202 int ret2 = dbenv->close(0);
203 if (ret2 != 0) {
204 LogPrintf("BerkeleyEnvironment::Open: Error %d closing failed "
205 "database environment: %s\n",
206 ret2, DbEnv::strerror(ret2));
207 }
208 Reset();
209 err = strprintf(_("Error initializing wallet database environment %s!"),
211 if (ret == DB_RUNRECOVERY) {
212 err += Untranslated(" ") +
213 _("This error could occur if this wallet was not shutdown "
214 "cleanly and was last loaded using a build with a newer "
215 "version of Berkeley DB. If so, please use the software "
216 "that last loaded this wallet");
217 }
218 return false;
219 }
220
221 fDbEnvInit = true;
222 fMockDb = false;
223 return true;
224}
225
228 Reset();
229
230 LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::MakeMock\n");
231
232 dbenv->set_cachesize(1, 0, 1);
233 dbenv->set_lg_bsize(10485760 * 4);
234 dbenv->set_lg_max(10485760);
235 dbenv->set_lk_max_locks(10000);
236 dbenv->set_lk_max_objects(10000);
237 dbenv->set_flags(DB_AUTO_COMMIT, 1);
238 dbenv->log_set_config(DB_LOG_IN_MEMORY, 1);
239 int ret =
240 dbenv->open(nullptr,
241 DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL |
242 DB_INIT_TXN | DB_THREAD | DB_PRIVATE,
243 S_IRUSR | S_IWUSR);
244 if (ret > 0) {
245 throw std::runtime_error(
246 strprintf("BerkeleyEnvironment::MakeMock: Error %d opening "
247 "database environment.",
248 ret));
249 }
250
251 fDbEnvInit = true;
252 fMockDb = true;
253}
254
256 m_dbt.set_flags(DB_DBT_MALLOC);
257}
258
259BerkeleyBatch::SafeDbt::SafeDbt(void *data, size_t size) : m_dbt(data, size) {}
260
262 if (m_dbt.get_data() != nullptr) {
263 // Clear memory, e.g. in case it was a private key
264 memory_cleanse(m_dbt.get_data(), m_dbt.get_size());
265 // under DB_DBT_MALLOC, data is malloced by the Dbt, but must be
266 // freed by the caller.
267 // https://docs.oracle.com/cd/E17275_01/html/api_reference/C/dbt.html
268 if (m_dbt.get_flags() & DB_DBT_MALLOC) {
269 free(m_dbt.get_data());
270 }
271 }
272}
273
275 return m_dbt.get_data();
276}
277
279 return m_dbt.get_size();
280}
281
282BerkeleyBatch::SafeDbt::operator Dbt *() {
283 return &m_dbt;
284}
285
287 fs::path walletDir = env->Directory();
288 fs::path file_path = walletDir / strFile;
289
290 LogPrintf("Using BerkeleyDB version %s\n", BerkeleyDatabaseVersion());
291 LogPrintf("Using wallet %s\n", fs::PathToString(file_path));
292
293 if (!env->Open(errorStr)) {
294 return false;
295 }
296
297 if (fs::exists(file_path)) {
298 assert(m_refcount == 0);
299
300 Db db(env->dbenv.get(), 0);
301 int result = db.verify(strFile.c_str(), nullptr, nullptr, 0);
302 if (result != 0) {
303 errorStr =
304 strprintf(_("%s corrupt. Try using the wallet tool "
305 "bitcoin-wallet to salvage or restoring a backup."),
306 fs::quoted(fs::PathToString(file_path)));
307 return false;
308 }
309 }
310 // also return true if files does not exists
311 return true;
312}
313
315 dbenv->txn_checkpoint(0, 0, 0);
316 if (fMockDb) {
317 return;
318 }
319 dbenv->lsn_reset(strFile.c_str(), 0);
320}
321
323 if (env) {
324 LOCK(cs_db);
326 assert(!m_db);
327 size_t erased = env->m_databases.erase(strFile);
328 assert(erased == 1);
329 env->m_fileids.erase(strFile);
330 }
331}
332
333BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase &database, const bool read_only,
334 bool fFlushOnCloseIn)
335 : pdb(nullptr), activeTxn(nullptr), m_cursor(nullptr),
336 m_database(database) {
337 database.AddRef();
338 database.Open();
339 fReadOnly = read_only;
340 fFlushOnClose = fFlushOnCloseIn;
341 env = database.env.get();
342 pdb = database.m_db.get();
343 strFile = database.strFile;
344 if (!Exists(std::string("version"))) {
345 bool fTmp = fReadOnly;
346 fReadOnly = false;
347 Write(std::string("version"), CLIENT_VERSION);
348 fReadOnly = fTmp;
349 }
350}
351
353 unsigned int nFlags = DB_THREAD | DB_CREATE;
354
355 {
356 LOCK(cs_db);
357 bilingual_str open_err;
358 if (!env->Open(open_err)) {
359 throw std::runtime_error(
360 "BerkeleyDatabase: Failed to open database environment.");
361 }
362
363 if (m_db == nullptr) {
364 int ret;
365 std::unique_ptr<Db> pdb_temp =
366 std::make_unique<Db>(env->dbenv.get(), 0);
367
368 bool fMockDb = env->IsMock();
369 if (fMockDb) {
370 DbMpoolFile *mpf = pdb_temp->get_mpf();
371 ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
372 if (ret != 0) {
373 throw std::runtime_error(strprintf(
374 "BerkeleyDatabase: Failed to configure for no "
375 "temp file backing for database %s",
376 strFile));
377 }
378 }
379
380 ret = pdb_temp->open(
381 nullptr, // Txn pointer
382 fMockDb ? nullptr : strFile.c_str(), // Filename
383 fMockDb ? strFile.c_str() : "main", // Logical db name
384 DB_BTREE, // Database type
385 nFlags, // Flags
386 0);
387
388 if (ret != 0) {
389 throw std::runtime_error(strprintf(
390 "BerkeleyDatabase: Error %d, can't open database %s", ret,
391 strFile));
392 }
393
394 // Call CheckUniqueFileid on the containing BDB environment to
395 // avoid BDB data consistency bugs that happen when different data
396 // files in the same environment have the same fileid.
397 CheckUniqueFileid(*env, strFile, *pdb_temp,
398 this->env->m_fileids[strFile]);
399
400 m_db.reset(pdb_temp.release());
401 }
402 }
403}
404
406 if (activeTxn) {
407 return;
408 }
409
410 // Flush database activity from memory pool to disk log
411 unsigned int nMinutes = 0;
412 if (fReadOnly) {
413 nMinutes = 1;
414 }
415
416 // env is nullptr for dummy databases (i.e. in tests). Don't actually flush
417 // if env is nullptr so we don't segfault
418 if (env) {
419 env->dbenv->txn_checkpoint(
420 nMinutes
421 ? gArgs.GetIntArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024
422 : 0,
423 nMinutes, 0);
424 }
425}
426
429}
430
432 Close();
434}
435
437 if (!pdb) {
438 return;
439 }
440 if (activeTxn) {
441 activeTxn->abort();
442 }
443 activeTxn = nullptr;
444 pdb = nullptr;
445 CloseCursor();
446
447 if (fFlushOnClose) {
448 Flush();
449 }
450}
451
452void BerkeleyEnvironment::CloseDb(const std::string &strFile) {
453 LOCK(cs_db);
454 auto it = m_databases.find(strFile);
455 assert(it != m_databases.end());
456 BerkeleyDatabase &database = it->second.get();
457 if (database.m_db) {
458 // Close the database handle
459 database.m_db->close(0);
460 database.m_db.reset();
461 }
462}
463
465 // Make sure that no Db's are in use
466 AssertLockNotHeld(cs_db);
467 std::unique_lock<RecursiveMutex> lock(cs_db);
468 m_db_in_use.wait(lock, [this]() {
469 for (auto &db : m_databases) {
470 if (db.second.get().m_refcount > 0) {
471 return false;
472 }
473 }
474 return true;
475 });
476
477 std::vector<std::string> filenames;
478 for (auto it : m_databases) {
479 filenames.push_back(it.first);
480 }
481 // Close the individual Db's
482 for (const std::string &filename : filenames) {
483 CloseDb(filename);
484 }
485 // Reset the environment
486 // This will flush and close the environment
487 Flush(true);
488 Reset();
489 bilingual_str open_err;
490 Open(open_err);
491}
492
493bool BerkeleyDatabase::Rewrite(const char *pszSkip) {
494 while (true) {
495 {
496 LOCK(cs_db);
497 if (m_refcount <= 0) {
498 // Flush log data to the dat file
499 env->CloseDb(strFile);
500 env->CheckpointLSN(strFile);
501 m_refcount = -1;
502
503 bool fSuccess = true;
504 LogPrintf("BerkeleyBatch::Rewrite: Rewriting %s...\n", strFile);
505 std::string strFileRes = strFile + ".rewrite";
506 { // surround usage of db with extra {}
507 BerkeleyBatch db(*this, true);
508 std::unique_ptr<Db> pdbCopy =
509 std::make_unique<Db>(env->dbenv.get(), 0);
510
511 int ret = pdbCopy->open(nullptr, // Txn pointer
512 strFileRes.c_str(), // Filename
513 "main", // Logical db name
514 DB_BTREE, // Database type
515 DB_CREATE, // Flags
516 0);
517 if (ret > 0) {
518 LogPrintf("BerkeleyBatch::Rewrite: Can't create "
519 "database file %s\n",
520 strFileRes);
521 fSuccess = false;
522 }
523
524 if (db.StartCursor()) {
525 while (fSuccess) {
528 bool complete;
529 bool ret1 =
530 db.ReadAtCursor(ssKey, ssValue, complete);
531 if (complete) {
532 break;
533 }
534 if (!ret1) {
535 fSuccess = false;
536 break;
537 }
538 if (pszSkip &&
539 strncmp((const char *)ssKey.data(), pszSkip,
540 std::min(ssKey.size(),
541 strlen(pszSkip))) == 0) {
542 continue;
543 }
544 if (strncmp((const char *)ssKey.data(),
545 "\x07version", 8) == 0) {
546 // Update version:
547 ssValue.clear();
548 ssValue << CLIENT_VERSION;
549 }
550 Dbt datKey(ssKey.data(), ssKey.size());
551 Dbt datValue(ssValue.data(), ssValue.size());
552 int ret2 = pdbCopy->put(nullptr, &datKey, &datValue,
553 DB_NOOVERWRITE);
554 if (ret2 > 0) {
555 fSuccess = false;
556 }
557 }
558 db.CloseCursor();
559 }
560 if (fSuccess) {
561 db.Close();
562 env->CloseDb(strFile);
563 if (pdbCopy->close(0)) {
564 fSuccess = false;
565 }
566 } else {
567 pdbCopy->close(0);
568 }
569 }
570 if (fSuccess) {
571 Db dbA(env->dbenv.get(), 0);
572 if (dbA.remove(strFile.c_str(), nullptr, 0)) {
573 fSuccess = false;
574 }
575 Db dbB(env->dbenv.get(), 0);
576 if (dbB.rename(strFileRes.c_str(), nullptr, strFile.c_str(),
577 0)) {
578 fSuccess = false;
579 }
580 }
581 if (!fSuccess) {
582 LogPrintf("BerkeleyBatch::Rewrite: Failed to rewrite "
583 "database file %s\n",
584 strFileRes);
585 }
586 return fSuccess;
587 }
588 }
589 UninterruptibleSleep(std::chrono::milliseconds{100});
590 }
591}
592
593void BerkeleyEnvironment::Flush(bool fShutdown) {
594 int64_t nStart = GetTimeMillis();
595 // Flush log data to the actual data file on all files that are not in use
596 LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: [%s] Flush(%s)%s\n",
597 strPath, fShutdown ? "true" : "false",
598 fDbEnvInit ? "" : " database not started");
599 if (!fDbEnvInit) {
600 return;
601 }
602 {
603 LOCK(cs_db);
604 bool no_dbs_accessed = true;
605 for (auto &db_it : m_databases) {
606 std::string strFile = db_it.first;
607 int nRefCount = db_it.second.get().m_refcount;
608 if (nRefCount < 0) {
609 continue;
610 }
611 LogPrint(
613 "BerkeleyEnvironment::Flush: Flushing %s (refcount = %d)...\n",
614 strFile, nRefCount);
615 if (nRefCount == 0) {
616 // Move log data to the dat file
617 CloseDb(strFile);
619 "BerkeleyEnvironment::Flush: %s checkpoint\n",
620 strFile);
621 dbenv->txn_checkpoint(0, 0, 0);
623 "BerkeleyEnvironment::Flush: %s detach\n", strFile);
624 if (!fMockDb) {
625 dbenv->lsn_reset(strFile.c_str(), 0);
626 }
628 "BerkeleyEnvironment::Flush: %s closed\n", strFile);
629 nRefCount = -1;
630 } else {
631 no_dbs_accessed = false;
632 }
633 }
635 "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n",
636 fShutdown ? "true" : "false",
637 fDbEnvInit ? "" : " database not started",
638 GetTimeMillis() - nStart);
639 if (fShutdown) {
640 char **listp;
641 if (no_dbs_accessed) {
642 dbenv->log_archive(&listp, DB_ARCH_REMOVE);
643 Close();
644 if (!fMockDb) {
645 fs::remove_all(fs::PathFromString(strPath) / "database");
646 }
647 }
648 }
649 }
650}
651
653 // Don't flush if we can't acquire the lock.
654 TRY_LOCK(cs_db, lockDb);
655 if (!lockDb) {
656 return false;
657 }
658
659 // Don't flush if any databases are in use
660 for (auto &it : env->m_databases) {
661 if (it.second.get().m_refcount > 0) {
662 return false;
663 }
664 }
665
666 // Don't flush if there haven't been any batch writes for this database.
667 if (m_refcount < 0) {
668 return false;
669 }
670
671 LogPrint(BCLog::WALLETDB, "Flushing %s\n", strFile);
672 int64_t nStart = GetTimeMillis();
673
674 // Flush wallet file so it's self contained
675 env->CloseDb(strFile);
676 env->CheckpointLSN(strFile);
677 m_refcount = -1;
678
679 LogPrint(BCLog::WALLETDB, "Flushed %s %dms\n", strFile,
680 GetTimeMillis() - nStart);
681
682 return true;
683}
684
685bool BerkeleyDatabase::Backup(const std::string &strDest) const {
686 while (true) {
687 {
688 LOCK(cs_db);
689 if (m_refcount <= 0) {
690 // Flush log data to the dat file
691 env->CloseDb(strFile);
692 env->CheckpointLSN(strFile);
693
694 // Copy wallet file.
695 fs::path pathSrc = env->Directory() / strFile;
696 fs::path pathDest(fs::PathFromString(strDest));
697 if (fs::is_directory(pathDest)) {
698 pathDest /= fs::PathFromString(strFile);
699 }
700
701 try {
702 if (fs::exists(pathDest) &&
703 fs::equivalent(pathSrc, pathDest)) {
704 LogPrintf("cannot backup to wallet source file %s\n",
705 fs::PathToString(pathDest));
706 return false;
707 }
708
709 fs::copy_file(pathSrc, pathDest,
710 fs::copy_options::overwrite_existing);
711 LogPrintf("copied %s to %s\n", strFile,
712 fs::PathToString(pathDest));
713 return true;
714 } catch (const fs::filesystem_error &e) {
715 LogPrintf("error copying %s to %s - %s\n", strFile,
716 fs::PathToString(pathDest),
718 return false;
719 }
720 }
721 }
722 UninterruptibleSleep(std::chrono::milliseconds{100});
723 }
724}
725
727 env->Flush(false);
728}
729
731 env->Flush(true);
732}
733
735 env->ReloadDbEnv();
736}
737
740 if (!pdb) {
741 return false;
742 }
743 int ret = pdb->cursor(nullptr, &m_cursor, 0);
744 return ret == 0;
745}
746
748 bool &complete) {
749 complete = false;
750 if (m_cursor == nullptr) {
751 return false;
752 }
753 // Read at cursor
754 SafeDbt datKey;
755 SafeDbt datValue;
756 int ret = m_cursor->get(datKey, datValue, DB_NEXT);
757 if (ret == DB_NOTFOUND) {
758 complete = true;
759 }
760 if (ret != 0) {
761 return false;
762 } else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr) {
763 return false;
764 }
765
766 // Convert to streams
767 ssKey.SetType(SER_DISK);
768 ssKey.clear();
769 ssKey.write({BytePtr(datKey.get_data()), datKey.get_size()});
770 ssValue.SetType(SER_DISK);
771 ssValue.clear();
772 ssValue.write({BytePtr(datValue.get_data()), datValue.get_size()});
773 return true;
774}
775
777 if (!m_cursor) {
778 return;
779 }
780 m_cursor->close();
781 m_cursor = nullptr;
782}
783
785 if (!pdb || activeTxn) {
786 return false;
787 }
788 DbTxn *ptxn = env->TxnBegin();
789 if (!ptxn) {
790 return false;
791 }
792 activeTxn = ptxn;
793 return true;
794}
795
797 if (!pdb || !activeTxn) {
798 return false;
799 }
800 int ret = activeTxn->commit(0);
801 activeTxn = nullptr;
802 return (ret == 0);
803}
804
806 if (!pdb || !activeTxn) {
807 return false;
808 }
809 int ret = activeTxn->abort();
810 activeTxn = nullptr;
811 return (ret == 0);
812}
813
815 return DbEnv::version(nullptr, nullptr, nullptr);
816}
817
819 if (!pdb) {
820 return false;
821 }
822
823 SafeDbt datKey(key.data(), key.size());
824
825 SafeDbt datValue;
826 int ret = pdb->get(activeTxn, datKey, datValue, 0);
827 if (ret == 0 && datValue.get_data() != nullptr) {
828 value.write({BytePtr(datValue.get_data()), datValue.get_size()});
829 return true;
830 }
831 return false;
832}
833
835 bool overwrite) {
836 if (!pdb) {
837 return false;
838 }
839
840 if (fReadOnly) {
841 assert(!"Write called on database in read-only mode");
842 }
843
844 SafeDbt datKey(key.data(), key.size());
845
846 SafeDbt datValue(value.data(), value.size());
847
848 int ret =
849 pdb->put(activeTxn, datKey, datValue, (overwrite ? 0 : DB_NOOVERWRITE));
850 return (ret == 0);
851}
852
854 if (!pdb) {
855 return false;
856 }
857 if (fReadOnly) {
858 assert(!"Erase called on database in read-only mode");
859 }
860
861 SafeDbt datKey(key.data(), key.size());
862
863 int ret = pdb->del(activeTxn, datKey, 0);
864 return (ret == 0 || ret == DB_NOTFOUND);
865}
866
868 if (!pdb) {
869 return false;
870 }
871
872 SafeDbt datKey(key.data(), key.size());
873
874 int ret = pdb->exists(activeTxn, datKey, 0);
875 return ret == 0;
876}
877
879 LOCK(cs_db);
880 if (m_refcount < 0) {
881 m_refcount = 1;
882 } else {
883 m_refcount++;
884 }
885}
886
888 LOCK(cs_db);
889 m_refcount--;
890 if (env) {
891 env->m_db_in_use.notify_all();
892 }
893}
894
895std::unique_ptr<DatabaseBatch>
896BerkeleyDatabase::MakeBatch(bool flush_on_close) {
897 return std::make_unique<BerkeleyBatch>(*this, false, flush_on_close);
898}
899
901 fs::path env_directory;
902 std::string data_filename;
903 SplitWalletPath(path, env_directory, data_filename);
904 return IsBerkeleyBtree(env_directory / data_filename);
905}
906
907std::unique_ptr<BerkeleyDatabase>
910 std::unique_ptr<BerkeleyDatabase> db;
911 {
912 // Lock env.m_databases until insert in BerkeleyDatabase constructor
913 LOCK(cs_db);
914 std::string data_filename;
915 std::shared_ptr<BerkeleyEnvironment> env =
916 GetWalletEnv(path, data_filename);
917 if (env->m_databases.count(data_filename)) {
919 "Refusing to load database. Data file '%s' is already loaded.",
920 fs::PathToString(env->Directory() / data_filename)));
922 return nullptr;
923 }
924 db = std::make_unique<BerkeleyDatabase>(std::move(env),
925 std::move(data_filename));
926 }
927
928 if (options.verify && !db->Verify(error)) {
930 return nullptr;
931 }
932
934 return db;
935}
ArgsManager gArgs
Definition: args.cpp:38
bool ExistsBerkeleyDatabase(const fs::path &path)
Check if Berkeley database exists at specified path.
Definition: bdb.cpp:900
std::unique_ptr< BerkeleyDatabase > MakeBerkeleyDatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
Return object giving access to Berkeley database at specified path.
Definition: bdb.cpp:908
std::string BerkeleyDatabaseVersion()
Definition: bdb.cpp:814
std::shared_ptr< BerkeleyEnvironment > GetWalletEnv(const fs::path &wallet_path, std::string &database_filename)
Get BerkeleyEnvironment and database filename given a wallet path.
Definition: bdb.cpp:83
static const unsigned int DEFAULT_WALLET_DBLOGSIZE
Definition: bdb.h:28
static const bool DEFAULT_WALLET_PRIVDB
Definition: bdb.h:29
bool IsBerkeleyBtree(const fs::path &path)
Check format of database file.
Definition: walletutil.cpp:35
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: args.cpp:526
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:556
RAII class that automatically cleanses its data on destruction.
Definition: bdb.h:189
uint32_t get_size() const
Definition: bdb.cpp:278
const void * get_data() const
Definition: bdb.cpp:274
RAII class that provides access to a Berkeley database.
Definition: bdb.h:187
void Close() override
Definition: bdb.cpp:436
std::string strFile
Definition: bdb.h:216
bool TxnCommit() override
Definition: bdb.cpp:796
bool WriteKey(CDataStream &&key, CDataStream &&value, bool overwrite=true) override
Definition: bdb.cpp:834
void Flush() override
Definition: bdb.cpp:405
bool ReadKey(CDataStream &&key, CDataStream &value) override
Definition: bdb.cpp:818
bool StartCursor() override
Definition: bdb.cpp:738
void CloseCursor() override
Definition: bdb.cpp:776
BerkeleyBatch(BerkeleyDatabase &database, const bool fReadOnly, bool fFlushOnCloseIn=true)
Definition: bdb.cpp:333
BerkeleyEnvironment * env
Definition: bdb.h:221
bool TxnAbort() override
Definition: bdb.cpp:805
Db * pdb
Definition: bdb.h:215
bool EraseKey(CDataStream &&key) override
Definition: bdb.cpp:853
~BerkeleyBatch() override
Definition: bdb.cpp:431
DbTxn * activeTxn
Definition: bdb.h:217
bool fFlushOnClose
Definition: bdb.h:220
BerkeleyDatabase & m_database
Definition: bdb.h:222
bool HasKey(CDataStream &&key) override
Definition: bdb.cpp:867
bool fReadOnly
Definition: bdb.h:219
Dbc * m_cursor
Definition: bdb.h:218
bool ReadAtCursor(CDataStream &ssKey, CDataStream &ssValue, bool &complete) override
Definition: bdb.cpp:747
bool TxnBegin() override
Definition: bdb.cpp:784
An instance of this class represents one database.
Definition: bdb.h:94
std::shared_ptr< BerkeleyEnvironment > env
Pointer to shared database environment.
Definition: bdb.h:171
void IncrementUpdateCounter() override
Definition: bdb.cpp:427
void ReloadDbEnv() override
Definition: bdb.cpp:734
std::unique_ptr< DatabaseBatch > MakeBatch(bool flush_on_close=true) override
Make a BerkeleyBatch connected to this database.
Definition: bdb.cpp:896
~BerkeleyDatabase() override
Definition: bdb.cpp:322
bool Rewrite(const char *pszSkip=nullptr) override
Rewrite the entire database on disk, with the exception of key pszSkip if non-zero.
Definition: bdb.cpp:493
std::string strFile
Definition: bdb.h:179
void AddRef() override
Indicate the a new database user has began using the database.
Definition: bdb.cpp:878
void Flush() override
Make sure all changes are flushed to database file.
Definition: bdb.cpp:726
void Open() override
Open the database if it is not already opened.
Definition: bdb.cpp:352
bool PeriodicFlush() override
flush the wallet passively (TRY_LOCK) ideal to be called periodically
Definition: bdb.cpp:652
void RemoveRef() override
Indicate that database user has stopped using the database and that it could be flushed or closed.
Definition: bdb.cpp:887
void Close() override
Flush to the database file and close the database.
Definition: bdb.cpp:730
std::unique_ptr< Db > m_db
Database pointer.
Definition: bdb.h:177
bool Verify(bilingual_str &error)
Verifies the environment and database file.
Definition: bdb.cpp:286
bool Backup(const std::string &strDest) const override
Back up the entire database to a file.
Definition: bdb.cpp:685
std::unordered_map< std::string, WalletDatabaseFileId > m_fileids
Definition: bdb.h:50
DbTxn * TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
Definition: bdb.h:71
fs::path Directory() const
Definition: bdb.h:61
bool IsMock() const
Definition: bdb.h:59
void ReloadDbEnv()
Definition: bdb.cpp:464
std::map< std::string, std::reference_wrapper< BerkeleyDatabase > > m_databases
Definition: bdb.h:49
bool fDbEnvInit
Definition: bdb.h:40
bool Open(bilingual_str &error)
Definition: bdb.cpp:154
std::string strPath
Definition: bdb.h:45
std::unique_ptr< DbEnv > dbenv
Definition: bdb.h:48
std::condition_variable_any m_db_in_use
Definition: bdb.h:51
void CheckpointLSN(const std::string &strFile)
Definition: bdb.cpp:314
void Flush(bool fShutdown)
Definition: bdb.cpp:593
bool fMockDb
Definition: bdb.h:41
BerkeleyEnvironment()
Construct an in-memory mock Berkeley environment for testing.
Definition: bdb.cpp:227
void CloseDb(const std::string &strFile)
Definition: bdb.cpp:452
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
void write(Span< const value_type > src)
Definition: streams.h:379
void SetType(int n)
Definition: streams.h:336
value_type * data()
Definition: streams.h:243
size_type size() const
Definition: streams.h:223
void clear()
Definition: streams.h:233
bool Write(const K &key, const T &value, bool fOverwrite=true)
Definition: db.h:60
bool Exists(const K &key)
Definition: db.h:80
std::atomic< unsigned int > nUpdateCounter
Definition: db.h:156
std::atomic< int > m_refcount
Counts the number of active database users to be sure that the database is not closed while someone i...
Definition: db.h:113
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
Definition: cleanse.cpp:14
static constexpr int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:38
bool LockDirectory(const fs::path &directory, const std::string lockfile_name, bool probe_only)
Definition: fs_helpers.cpp:58
void UnlockDirectory(const fs::path &directory, const std::string &lockfile_name)
Definition: fs_helpers.cpp:86
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by create_directories if the requested directory exists.
Definition: fs_helpers.cpp:287
bool error(const char *fmt, const Args &...args)
Definition: logging.h:263
#define LogPrint(category,...)
Definition: logging.h:238
#define LogPrintf(...)
Definition: logging.h:227
@ WALLETDB
Definition: logging.h:46
Filesystem operations and types.
Definition: fs.h:20
static auto quoted(const std::string &s)
Definition: fs.h:107
static bool exists(const path &p)
Definition: fs.h:102
static bool copy_file(const path &from, const path &to, copy_options options)
Definition: fs.h:119
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:142
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:165
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:30
std::string get_filesystem_error_message(const fs::filesystem_error &e)
Definition: fs.cpp:142
CAddrDb db
Definition: main.cpp:35
@ SER_DISK
Definition: serialize.h:153
const std::byte * BytePtr(const void *data)
Convert a data pointer to a std::byte data pointer.
Definition: span.h:286
bool verify
Definition: db.h:226
bool operator==(const WalletDatabaseFileId &rhs) const
Definition: bdb.cpp:66
uint8_t value[DB_FILE_ID_LEN]
Definition: bdb.h:32
Bilingual messages:
Definition: translation.h:17
#define AssertLockNotHeld(cs)
Definition: sync.h:163
#define LOCK(cs)
Definition: sync.h:306
#define TRY_LOCK(cs, name)
Definition: sync.h:314
#define GUARDED_BY(x)
Definition: threadsafety.h:45
int64_t GetTimeMillis()
Returns the system time (not mockable)
Definition: time.cpp:101
void UninterruptibleSleep(const std::chrono::microseconds &n)
Definition: time.cpp:23
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:68
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:36
static const char * filenames[]
Definition: unitester.cpp:68
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
assert(!tx.IsCoinBase())
void SplitWalletPath(const fs::path &wallet_path, fs::path &env_directory, std::string &database_filename)
Definition: db.cpp:11
DatabaseStatus
Definition: db.h:229