33 int ret = db.get_mpf()->get_fileid(fileid.
value);
35 throw std::runtime_error(
strprintf(
"BerkeleyDatabase: Can't open database %s (get_fileid failed with %d)", filename, ret));
39 if (fileid == item.second && &fileid != &item.second) {
40 throw std::runtime_error(
strprintf(
"BerkeleyDatabase: Can't open database %s (duplicates fileid %s from %s)", filename,
41 HexStr(item.second.value), item.first));
47std::map<std::string, std::weak_ptr<BerkeleyEnvironment>> g_dbenvs
GUARDED_BY(cs_db);
64 auto inserted = g_dbenvs.emplace(
fs::PathToString(env_directory), std::weak_ptr<BerkeleyEnvironment>());
65 if (inserted.second) {
66 auto env = std::make_shared<BerkeleyEnvironment>(env_directory);
67 inserted.first->second = env;
70 return inserted.first->second.lock();
88 database.
m_db->close(0);
89 database.
m_db.reset();
93 FILE* error_file =
nullptr;
94 dbenv->get_errfile(&error_file);
96 int ret =
dbenv->close(0);
98 LogPrintf(
"BerkeleyEnvironment::Close: Error %d closing database environment: %s\n", ret, DbEnv::strerror(ret));
100 DbEnv((u_int32_t)0).remove(
strPath.c_str(), 0);
102 if (error_file) fclose(error_file);
109 dbenv.reset(
new DbEnv(DB_CXX_NO_EXCEPTIONS));
135 LogPrintf(
"Cannot obtain a lock on wallet directory %s. Another instance may be using it.\n",
strPath);
140 fs::path pathLogDir = pathIn /
"database";
142 fs::path pathErrorFile = pathIn /
"db.log";
145 unsigned int nEnvFlags = 0;
147 nEnvFlags |= DB_PRIVATE;
150 dbenv->set_cachesize(0, 0x100000, 1);
151 dbenv->set_lg_bsize(0x10000);
152 dbenv->set_lg_max(1048576);
153 dbenv->set_lk_max_locks(40000);
154 dbenv->set_lk_max_objects(40000);
156 dbenv->set_flags(DB_AUTO_COMMIT, 1);
157 dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1);
158 dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1);
170 LogPrintf(
"BerkeleyEnvironment::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
171 int ret2 =
dbenv->close(0);
173 LogPrintf(
"BerkeleyEnvironment::Open: Error %d closing failed database environment: %s\n", ret2, DbEnv::strerror(ret2));
177 if (ret == DB_RUNRECOVERY) {
178 err +=
Untranslated(
" ") +
_(
"This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet");
195 dbenv->set_cachesize(1, 0, 1);
196 dbenv->set_lg_bsize(10485760 * 4);
197 dbenv->set_lg_max(10485760);
198 dbenv->set_lk_max_locks(10000);
199 dbenv->set_lk_max_objects(10000);
200 dbenv->set_flags(DB_AUTO_COMMIT, 1);
201 dbenv->log_set_config(DB_LOG_IN_MEMORY, 1);
202 int ret =
dbenv->open(
nullptr,
212 throw std::runtime_error(
strprintf(
"BerkeleyEnvironment::MakeMock: Error %d opening database environment.", ret));
221 m_dbt.set_flags(DB_DBT_MALLOC);
231 if (m_dbt.get_data() !=
nullptr) {
237 if (m_dbt.get_flags() & DB_DBT_MALLOC) {
238 free(m_dbt.get_data());
245 return m_dbt.get_data();
250 return m_dbt.get_size();
253BerkeleyBatch::SafeDbt::operator Dbt*()
275 int result = db.verify(
strFile.c_str(),
nullptr,
nullptr, 0);
287 dbenv->txn_checkpoint(0, 0, 0);
290 dbenv->lsn_reset(
strFile.c_str(), 0);
314 if (!
Exists(std::string(
"version"))) {
324 unsigned int nFlags = DB_THREAD | DB_CREATE;
329 if (!
env->Open(open_err))
330 throw std::runtime_error(
"BerkeleyDatabase: Failed to open database environment.");
332 if (
m_db ==
nullptr) {
334 std::unique_ptr<Db> pdb_temp = std::make_unique<Db>(
env->dbenv.get(), 0);
336 bool fMockDb =
env->IsMock();
338 DbMpoolFile* mpf = pdb_temp->get_mpf();
339 ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
341 throw std::runtime_error(
strprintf(
"BerkeleyDatabase: Failed to configure for no temp file backing for database %s",
strFile));
345 ret = pdb_temp->open(
nullptr,
346 fMockDb ?
nullptr :
strFile.c_str(),
347 fMockDb ?
strFile.c_str() :
"main",
353 throw std::runtime_error(
strprintf(
"BerkeleyDatabase: Error %d, can't open database %s", ret,
strFile));
361 m_db.reset(pdb_temp.release());
373 unsigned int nMinutes = 0;
416 database.
m_db->close(0);
417 database.
m_db.reset();
426 std::unique_lock<RecursiveMutex> lock(cs_db);
429 if (db.second.get().m_refcount > 0)
return false;
439 for (
const std::string& filename :
filenames) {
460 bool fSuccess =
true;
462 std::string strFileRes =
strFile +
".rewrite";
465 std::unique_ptr<Db> pdbCopy = std::make_unique<Db>(
env->dbenv.get(), 0);
467 int ret = pdbCopy->open(
nullptr,
474 LogPrintf(
"BerkeleyBatch::Rewrite: Can't create database file %s\n", strFileRes);
491 strncmp((
const char*)ssKey.
data(), pszSkip, std::min(ssKey.
size(), strlen(pszSkip))) == 0)
493 if (strncmp((
const char*)ssKey.
data(),
"\x07version", 8) == 0) {
498 Dbt datKey(ssKey.
data(), ssKey.
size());
499 Dbt datValue(ssValue.
data(), ssValue.
size());
500 int ret2 = pdbCopy->put(
nullptr, &datKey, &datValue, DB_NOOVERWRITE);
509 if (pdbCopy->close(0))
516 Db dbA(
env->dbenv.get(), 0);
517 if (dbA.remove(
strFile.c_str(),
nullptr, 0))
519 Db dbB(
env->dbenv.get(), 0);
520 if (dbB.rename(strFileRes.c_str(),
nullptr,
strFile.c_str(), 0))
524 LogPrintf(
"BerkeleyBatch::Rewrite: Failed to rewrite database file %s\n", strFileRes);
542 bool no_dbs_accessed =
true;
544 std::string strFile = db_it.first;
545 int nRefCount = db_it.second.get().m_refcount;
546 if (nRefCount < 0)
continue;
548 if (nRefCount == 0) {
552 dbenv->txn_checkpoint(0, 0, 0);
555 dbenv->lsn_reset(strFile.c_str(), 0);
559 no_dbs_accessed =
false;
565 if (no_dbs_accessed) {
566 dbenv->log_archive(&listp, DB_ARCH_REMOVE);
580 if (!lockDb)
return false;
583 for (
auto& it :
env->m_databases) {
584 if (it.second.get().m_refcount > 0)
return false;
618 if (fs::is_directory(pathDest))
622 if (fs::equivalent(pathSrc, pathDest)) {
627 fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists);
630 }
catch (
const fs::filesystem_error& e) {
667 if (
m_cursor ==
nullptr)
return false;
671 int ret =
m_cursor->get(datKey, datValue, DB_NEXT);
672 if (ret == DB_NOTFOUND) {
729 DbEnv::version(&major, &minor,
nullptr);
734 if (major != DB_VERSION_MAJOR || minor < DB_VERSION_MINOR) {
735 LogPrintf(
"BerkeleyDB database version conflict: header version is %d.%d, library version is %d.%d\n",
736 DB_VERSION_MAJOR, DB_VERSION_MINOR, major, minor);
745 return DbEnv::version(
nullptr,
nullptr,
nullptr);
753 SafeDbt datKey(key.data(), key.size());
757 if (ret == 0 && datValue.
get_data() !=
nullptr) {
769 assert(!
"Write called on database in read-only mode");
771 SafeDbt datKey(key.data(), key.size());
773 SafeDbt datValue(value.data(), value.size());
775 int ret =
pdb->put(
activeTxn, datKey, datValue, (overwrite ? 0 : DB_NOOVERWRITE));
784 assert(!
"Erase called on database in read-only mode");
786 SafeDbt datKey(key.data(), key.size());
789 return (ret == 0 || ret == DB_NOTFOUND);
797 SafeDbt datKey(key.data(), key.size());
817 if (
env)
env->m_db_in_use.notify_all();
822 return std::make_unique<BerkeleyBatch>(*
this,
false, flush_on_close);
828 std::unique_ptr<BerkeleyDatabase> db;
832 std::shared_ptr<BerkeleyEnvironment> env =
GetBerkeleyEnv(data_file.parent_path());
833 if (env->m_databases.count(data_filename)) {
838 db = std::make_unique<BerkeleyDatabase>(std::move(env), std::move(data_filename));
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.
std::string BerkeleyDatabaseVersion()
bool BerkeleyDatabaseSanityCheck()
Perform sanity check of runtime BDB version versus linked BDB version.
std::shared_ptr< BerkeleyEnvironment > GetBerkeleyEnv(const fs::path &env_directory)
Get BerkeleyEnvironment given a directory path.
static const unsigned int DEFAULT_WALLET_DBLOGSIZE
static const bool DEFAULT_WALLET_PRIVDB
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
RAII class that automatically cleanses its data on destruction.
u_int32_t get_size() const
const void * get_data() const
RAII class that provides access to a Berkeley database.
bool TxnCommit() override
bool WriteKey(CDataStream &&key, CDataStream &&value, bool overwrite=true) override
bool ReadKey(CDataStream &&key, CDataStream &value) override
bool StartCursor() override
void CloseCursor() override
BerkeleyBatch(BerkeleyDatabase &database, const bool fReadOnly, bool fFlushOnCloseIn=true)
BerkeleyEnvironment * env
bool EraseKey(CDataStream &&key) override
~BerkeleyBatch() override
BerkeleyDatabase & m_database
bool HasKey(CDataStream &&key) override
bool ReadAtCursor(CDataStream &ssKey, CDataStream &ssValue, bool &complete) override
An instance of this class represents one database.
std::shared_ptr< BerkeleyEnvironment > env
Pointer to shared database environment.
void IncrementUpdateCounter() override
void ReloadDbEnv() override
std::unique_ptr< DatabaseBatch > MakeBatch(bool flush_on_close=true) override
Make a BerkeleyBatch connected to this database.
~BerkeleyDatabase() override
bool Rewrite(const char *pszSkip=nullptr) override
Rewrite the entire database on disk, with the exception of key pszSkip if non-zero.
void AddRef() override
Indicate the a new database user has began using the database.
void Flush() override
Make sure all changes are flushed to database file.
void Open() override
Open the database if it is not already opened.
bool PeriodicFlush() override
void RemoveRef() override
Indicate that database user has stopped using the database and that it could be flushed or closed.
void Close() override
Flush to the database file and close the database.
std::unique_ptr< Db > m_db
Database pointer.
bool Verify(bilingual_str &error)
Verifies the environment and database file.
bool Backup(const std::string &strDest) const override
Back up the entire database to a file.
std::unordered_map< std::string, WalletDatabaseFileId > m_fileids
DbTxn * TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
fs::path Directory() const
std::map< std::string, std::reference_wrapper< BerkeleyDatabase > > m_databases
bool Open(bilingual_str &error)
std::unique_ptr< DbEnv > dbenv
std::condition_variable_any m_db_in_use
void CheckpointLSN(const std::string &strFile)
void Flush(bool fShutdown)
BerkeleyEnvironment()
Construct an in-memory mock Berkeley environment for testing.
void CloseDb(const std::string &strFile)
Double ended buffer combining vector and stream-like interfaces.
void write(const char *pch, size_t nSize)
bool Write(const K &key, const T &value, bool fOverwrite=true)
bool Exists(const K &key)
std::atomic< unsigned int > nUpdateCounter
std::atomic< int > m_refcount
Counts the number of active database users to be sure that the database is not closed while someone i...
Path class wrapper to prepare application code for transition from boost::filesystem library to std::...
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
fs::path BDBDataFile(const fs::path &wallet_path)
#define LogPrint(category,...)
Filesystem operations and types.
static auto quoted(const std::string &s)
static bool exists(const path &p)
static std::string PathToString(const path &path)
Convert path object to byte string.
static path PathFromString(const std::string &string)
Convert byte string to path object.
FILE * fopen(const fs::path &p, const char *mode)
std::string get_filesystem_error_message(const fs::filesystem_error &e)
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
u_int8_t value[DB_FILE_ID_LEN]
bool operator==(const WalletDatabaseFileId &rhs) const
#define AssertLockNotHeld(cs)
#define TRY_LOCK(cs, name)
bool error(const char *fmt, const Args &... args)
int64_t GetTimeMillis()
Returns the system time (not mockable)
void UninterruptibleSleep(const std::chrono::microseconds &n)
bilingual_str _(const char *psz)
Translation function.
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
static const char * filenames[]
bool LockDirectory(const fs::path &directory, const std::string lockfile_name, bool probe_only)
void UnlockDirectory(const fs::path &directory, const std::string &lockfile_name)
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by Boost's create_directories if the requested directory exists.