Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/db.h
Show All 18 Lines | |||||
#include <atomic> | #include <atomic> | ||||
#include <map> | #include <map> | ||||
#include <string> | #include <string> | ||||
#include <vector> | #include <vector> | ||||
static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100; | static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100; | ||||
static const bool DEFAULT_WALLET_PRIVDB = true; | static const bool DEFAULT_WALLET_PRIVDB = true; | ||||
class CDBEnv { | class BerkeleyEnvironment { | ||||
private: | private: | ||||
bool fDbEnvInit; | bool fDbEnvInit; | ||||
bool fMockDb; | bool fMockDb; | ||||
// Don't change into fs::path, as that can result in | // Don't change into fs::path, as that can result in | ||||
// shutdown problems/crashes caused by a static initialized internal | // shutdown problems/crashes caused by a static initialized internal | ||||
// pointer. | // pointer. | ||||
std::string strPath; | std::string strPath; | ||||
public: | public: | ||||
std::unique_ptr<DbEnv> dbenv; | std::unique_ptr<DbEnv> dbenv; | ||||
std::map<std::string, int> mapFileUseCount; | std::map<std::string, int> mapFileUseCount; | ||||
std::map<std::string, Db *> mapDb; | std::map<std::string, Db *> mapDb; | ||||
CDBEnv(const fs::path &env_directory); | BerkeleyEnvironment(const fs::path &env_directory); | ||||
~CDBEnv(); | ~BerkeleyEnvironment(); | ||||
void Reset(); | void Reset(); | ||||
void MakeMock(); | void MakeMock(); | ||||
bool IsMock() const { return fMockDb; } | bool IsMock() const { return fMockDb; } | ||||
bool IsInitialized() const { return fDbEnvInit; } | bool IsInitialized() const { return fDbEnvInit; } | ||||
fs::path Directory() const { return strPath; } | fs::path Directory() const { return strPath; } | ||||
/** | /** | ||||
Show All 31 Lines | public: | ||||
DbTxn *TxnBegin(int flags = DB_TXN_WRITE_NOSYNC) { | DbTxn *TxnBegin(int flags = DB_TXN_WRITE_NOSYNC) { | ||||
DbTxn *ptxn = nullptr; | DbTxn *ptxn = nullptr; | ||||
int ret = dbenv->txn_begin(nullptr, &ptxn, flags); | int ret = dbenv->txn_begin(nullptr, &ptxn, flags); | ||||
if (!ptxn || ret != 0) return nullptr; | if (!ptxn || ret != 0) return nullptr; | ||||
return ptxn; | return ptxn; | ||||
} | } | ||||
}; | }; | ||||
/** Get CDBEnv and database filename given a wallet path. */ | /** Get BerkeleyEnvironment and database filename given a wallet path. */ | ||||
CDBEnv *GetWalletEnv(const fs::path &wallet_path, | BerkeleyEnvironment *GetWalletEnv(const fs::path &wallet_path, | ||||
std::string &database_filename); | std::string &database_filename); | ||||
/** | /** | ||||
* An instance of this class represents one database. | * An instance of this class represents one database. | ||||
* For BerkeleyDB this is just a (env, strFile) tuple. | * For BerkeleyDB this is just a (env, strFile) tuple. | ||||
*/ | */ | ||||
class CWalletDBWrapper { | class BerkeleyDatabase { | ||||
friend class CDB; | friend class BerkeleyBatch; | ||||
public: | public: | ||||
/** Create dummy DB handle */ | /** Create dummy DB handle */ | ||||
CWalletDBWrapper() | BerkeleyDatabase() | ||||
: nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), | : nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), | ||||
nLastWalletUpdate(0), env(nullptr) {} | nLastWalletUpdate(0), env(nullptr) {} | ||||
/** Create DB handle to real database */ | /** Create DB handle to real database */ | ||||
CWalletDBWrapper(const fs::path &wallet_path, bool mock = false) | BerkeleyDatabase(const fs::path &wallet_path, bool mock = false) | ||||
: nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), | : nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), | ||||
nLastWalletUpdate(0) { | nLastWalletUpdate(0) { | ||||
env = GetWalletEnv(wallet_path, strFile); | env = GetWalletEnv(wallet_path, strFile); | ||||
if (mock) { | if (mock) { | ||||
env->Close(); | env->Close(); | ||||
env->Reset(); | env->Reset(); | ||||
env->MakeMock(); | env->MakeMock(); | ||||
} | } | ||||
} | } | ||||
/** Return object for accessing database at specified path. */ | /** Return object for accessing database at specified path. */ | ||||
static std::unique_ptr<CWalletDBWrapper> Create(const fs::path &path) { | static std::unique_ptr<BerkeleyDatabase> Create(const fs::path &path) { | ||||
return std::make_unique<CWalletDBWrapper>(path); | return std::make_unique<BerkeleyDatabase>(path); | ||||
} | } | ||||
/** | /** | ||||
* Return object for accessing dummy database with no read/write | * Return object for accessing dummy database with no read/write | ||||
* capabilities. | * capabilities. | ||||
*/ | */ | ||||
static std::unique_ptr<CWalletDBWrapper> CreateDummy() { | static std::unique_ptr<BerkeleyDatabase> CreateDummy() { | ||||
return std::make_unique<CWalletDBWrapper>(); | return std::make_unique<BerkeleyDatabase>(); | ||||
} | } | ||||
/** | /** | ||||
* Return object for accessing temporary in-memory database. | * Return object for accessing temporary in-memory database. | ||||
*/ | */ | ||||
static std::unique_ptr<CWalletDBWrapper> CreateMock() { | static std::unique_ptr<BerkeleyDatabase> CreateMock() { | ||||
return std::make_unique<CWalletDBWrapper>("", true /* mock */); | return std::make_unique<BerkeleyDatabase>("", true /* mock */); | ||||
} | } | ||||
/** | /** | ||||
* Rewrite the entire database on disk, with the exception of key pszSkip if | * Rewrite the entire database on disk, with the exception of key pszSkip if | ||||
* non-zero | * non-zero | ||||
*/ | */ | ||||
bool Rewrite(const char *pszSkip = nullptr); | bool Rewrite(const char *pszSkip = nullptr); | ||||
Show All 11 Lines | public: | ||||
std::atomic<unsigned int> nUpdateCounter; | std::atomic<unsigned int> nUpdateCounter; | ||||
unsigned int nLastSeen; | unsigned int nLastSeen; | ||||
unsigned int nLastFlushed; | unsigned int nLastFlushed; | ||||
int64_t nLastWalletUpdate; | int64_t nLastWalletUpdate; | ||||
private: | private: | ||||
/** BerkeleyDB specific */ | /** BerkeleyDB specific */ | ||||
CDBEnv *env; | BerkeleyEnvironment *env; | ||||
std::string strFile; | std::string strFile; | ||||
/** | /** | ||||
* Return whether this database handle is a dummy for testing. | * Return whether this database handle is a dummy for testing. | ||||
* Only to be used at a low level, application should ideally not care | * Only to be used at a low level, application should ideally not care | ||||
* about this. | * about this. | ||||
*/ | */ | ||||
bool IsDummy() { return env == nullptr; } | bool IsDummy() { return env == nullptr; } | ||||
}; | }; | ||||
/** RAII class that provides access to a Berkeley database */ | /** RAII class that provides access to a Berkeley database */ | ||||
class CDB { | class BerkeleyBatch { | ||||
protected: | protected: | ||||
Db *pdb; | Db *pdb; | ||||
std::string strFile; | std::string strFile; | ||||
DbTxn *activeTxn; | DbTxn *activeTxn; | ||||
bool fReadOnly; | bool fReadOnly; | ||||
bool fFlushOnClose; | bool fFlushOnClose; | ||||
CDBEnv *env; | BerkeleyEnvironment *env; | ||||
public: | public: | ||||
explicit CDB(CWalletDBWrapper &dbw, const char *pszMode = "r+", | explicit BerkeleyBatch(BerkeleyDatabase &database, | ||||
const char *pszMode = "r+", | |||||
bool fFlushOnCloseIn = true); | bool fFlushOnCloseIn = true); | ||||
~CDB() { Close(); } | ~BerkeleyBatch() { Close(); } | ||||
CDB(const CDB &) = delete; | BerkeleyBatch(const BerkeleyBatch &) = delete; | ||||
CDB &operator=(const CDB &) = delete; | BerkeleyBatch &operator=(const BerkeleyBatch &) = delete; | ||||
void Flush(); | void Flush(); | ||||
void Close(); | void Close(); | ||||
static bool Recover(const fs::path &file_path, void *callbackDataIn, | static bool Recover(const fs::path &file_path, void *callbackDataIn, | ||||
bool (*recoverKVcallback)(void *callbackData, | bool (*recoverKVcallback)(void *callbackData, | ||||
CDataStream ssKey, | CDataStream ssKey, | ||||
CDataStream ssValue), | CDataStream ssValue), | ||||
std::string &out_backup_filename); | std::string &out_backup_filename); | ||||
/* flush the wallet passively (TRY_LOCK) | /* flush the wallet passively (TRY_LOCK) | ||||
ideal to be called periodically */ | ideal to be called periodically */ | ||||
static bool PeriodicFlush(CWalletDBWrapper &dbw); | static bool PeriodicFlush(BerkeleyDatabase &database); | ||||
/* verifies the database environment */ | /* verifies the database environment */ | ||||
static bool VerifyEnvironment(const fs::path &file_path, | static bool VerifyEnvironment(const fs::path &file_path, | ||||
std::string &errorStr); | std::string &errorStr); | ||||
/* verifies the database file */ | /* verifies the database file */ | ||||
static bool VerifyDatabaseFile(const fs::path &file_path, | static bool | ||||
std::string &warningStr, | VerifyDatabaseFile(const fs::path &file_path, std::string &warningStr, | ||||
std::string &errorStr, | std::string &errorStr, | ||||
CDBEnv::recoverFunc_type recoverFunc); | BerkeleyEnvironment::recoverFunc_type recoverFunc); | ||||
public: | public: | ||||
template <typename K, typename T> bool Read(const K &key, T &value) { | template <typename K, typename T> bool Read(const K &key, T &value) { | ||||
if (!pdb) { | if (!pdb) { | ||||
return false; | return false; | ||||
} | } | ||||
// Key | // Key | ||||
▲ Show 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | bool ReadVersion(int &nVersion) { | ||||
nVersion = 0; | nVersion = 0; | ||||
return Read(std::string("version"), nVersion); | return Read(std::string("version"), nVersion); | ||||
} | } | ||||
bool WriteVersion(int nVersion) { | bool WriteVersion(int nVersion) { | ||||
return Write(std::string("version"), nVersion); | return Write(std::string("version"), nVersion); | ||||
} | } | ||||
static bool Rewrite(CWalletDBWrapper &dbw, const char *pszSkip = nullptr); | static bool Rewrite(BerkeleyDatabase &database, | ||||
const char *pszSkip = nullptr); | |||||
}; | }; | ||||
#endif // BITCOIN_WALLET_DB_H | #endif // BITCOIN_WALLET_DB_H |