diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index 658500e4563..9ea43ca67c5 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -18,6 +18,7 @@ #include +#include #include // Windows may not define S_IRUSR or S_IWUSR. We define both @@ -29,12 +30,10 @@ #endif #endif +static_assert(BDB_DB_FILE_ID_LEN == DB_FILE_ID_LEN, "DB_FILE_ID_LEN should be 20."); + namespace wallet { namespace { -Span SpanFromDbt(const SafeDbt& dbt) -{ - return {reinterpret_cast(dbt.get_data()), dbt.get_size()}; -} //! Make sure database has a unique fileid within the environment. If it //! doesn't, throw an error. BDB caches do not work properly when more than one @@ -236,6 +235,26 @@ BerkeleyEnvironment::BerkeleyEnvironment() : m_use_shared_memory(false) fMockDb = true; } +/** RAII class that automatically cleanses its data on destruction */ +class SafeDbt final +{ + Dbt m_dbt; + +public: + // construct Dbt with internally-managed data + SafeDbt(); + // construct Dbt with provided data + SafeDbt(void* data, size_t size); + ~SafeDbt(); + + // delegate to Dbt + const void* get_data() const; + uint32_t get_size() const; + + // conversion operator to access the underlying Dbt + operator Dbt*(); +}; + SafeDbt::SafeDbt() { m_dbt.set_flags(DB_DBT_MALLOC); @@ -275,6 +294,18 @@ SafeDbt::operator Dbt*() return &m_dbt; } +static Span SpanFromDbt(const SafeDbt& dbt) +{ + return {reinterpret_cast(dbt.get_data()), dbt.get_size()}; +} + +BerkeleyDatabase::BerkeleyDatabase(std::shared_ptr env, fs::path filename, const DatabaseOptions& options) : + WalletDatabase(), env(std::move(env)), m_filename(std::move(filename)), m_max_log_mb(options.max_log_mb) +{ + auto inserted = this->env->m_databases.emplace(m_filename, std::ref(*this)); + assert(inserted.second); +} + bool BerkeleyDatabase::Verify(bilingual_str& errorStr) { fs::path walletDir = env->Directory(); @@ -462,6 +493,15 @@ void BerkeleyEnvironment::ReloadDbEnv() Open(open_err); } +DbTxn* BerkeleyEnvironment::TxnBegin(int flags) +{ + DbTxn* ptxn = nullptr; + int ret = dbenv->txn_begin(nullptr, &ptxn, flags); + if (!ptxn || ret != 0) + return nullptr; + return ptxn; +} + bool BerkeleyDatabase::Rewrite(const char* pszSkip) { while (true) { @@ -742,7 +782,7 @@ bool BerkeleyBatch::TxnBegin() { if (!pdb || activeTxn) return false; - DbTxn* ptxn = env->TxnBegin(); + DbTxn* ptxn = env->TxnBegin(DB_TXN_WRITE_NOSYNC); if (!ptxn) return false; activeTxn = ptxn; diff --git a/src/wallet/bdb.h b/src/wallet/bdb.h index 1073d32e0f2..630630ebe01 100644 --- a/src/wallet/bdb.h +++ b/src/wallet/bdb.h @@ -21,14 +21,21 @@ #include #include -#include - struct bilingual_str; +class DbEnv; +class DbTxn; +class Db; +class Dbc; + +// This constant was introduced in BDB 4.0.14 and has never changed, but there +// is a belt-and-suspenders check in the cpp file just in case. +#define BDB_DB_FILE_ID_LEN 20 /* Unique file ID length. */ + namespace wallet { struct WalletDatabaseFileId { - uint8_t value[DB_FILE_ID_LEN]; + uint8_t value[BDB_DB_FILE_ID_LEN]; bool operator==(const WalletDatabaseFileId& rhs) const; }; @@ -67,14 +74,7 @@ public: void CloseDb(const fs::path& filename); void ReloadDbEnv(); - DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC) - { - DbTxn* ptxn = nullptr; - int ret = dbenv->txn_begin(nullptr, &ptxn, flags); - if (!ptxn || ret != 0) - return nullptr; - return ptxn; - } + DbTxn* TxnBegin(int flags); }; /** Get BerkeleyEnvironment given a directory path. */ @@ -91,12 +91,7 @@ public: BerkeleyDatabase() = delete; /** Create DB handle to real database */ - BerkeleyDatabase(std::shared_ptr env, fs::path filename, const DatabaseOptions& options) : - WalletDatabase(), env(std::move(env)), m_filename(std::move(filename)), m_max_log_mb(options.max_log_mb) - { - auto inserted = this->env->m_databases.emplace(m_filename, std::ref(*this)); - assert(inserted.second); - } + BerkeleyDatabase(std::shared_ptr env, fs::path filename, const DatabaseOptions& options); ~BerkeleyDatabase() override; @@ -159,26 +154,6 @@ public: std::unique_ptr MakeBatch(bool flush_on_close = true) override; }; -/** RAII class that automatically cleanses its data on destruction */ -class SafeDbt final -{ - Dbt m_dbt; - -public: - // construct Dbt with internally-managed data - SafeDbt(); - // construct Dbt with provided data - SafeDbt(void* data, size_t size); - ~SafeDbt(); - - // delegate to Dbt - const void* get_data() const; - uint32_t get_size() const; - - // conversion operator to access the underlying Dbt - operator Dbt*(); -}; - class BerkeleyCursor : public DatabaseCursor { private: diff --git a/src/wallet/salvage.cpp b/src/wallet/salvage.cpp index da16435f041..0a0745b1c50 100644 --- a/src/wallet/salvage.cpp +++ b/src/wallet/salvage.cpp @@ -11,6 +11,8 @@ #include #include +#include + namespace wallet { /* End of headers, beginning of key/value data */ static const char *HEADER_END = "HEADER=END"; @@ -175,7 +177,7 @@ bool RecoverDatabaseFile(const ArgsManager& args, const fs::path& file_path, bil return false; } - DbTxn* ptxn = env->TxnBegin(); + DbTxn* ptxn = env->TxnBegin(DB_TXN_WRITE_NOSYNC); CWallet dummyWallet(nullptr, "", std::make_unique()); for (KeyValPair& row : salvagedData) {