# HG changeset patch # User Jeff Garzik # Date 1336959459 14400 # Node ID 04775a4029eb3ace1f407840eb26e6168d8ae3f6 # Parent b9f40dce7763f13d25ed7c1d2e21faf528685071 Encapsulate BDB environment inside new CDBEnv class Cleans up and organizes several scattered functions and variables related to the BDB env. Class CDBInit() existed to provide a guaranteed-via-C++-destructor cleanup of the db environment. A formal CDBEnv class provides all of this inside a single wrapper. diff --git a/src/db.cpp b/src/db.cpp --- a/src/db.cpp +++ b/src/db.cpp @@ -26,14 +26,11 @@ // CDB // -CCriticalSection cs_db; -static bool fDbEnvInit = false; -bool fDetachDB = false; -DbEnv dbenv(0); +CDBEnv bitdb; map mapFileUseCount; static map mapDb; -static void EnvShutdown() +void CDBEnv::EnvShutdown() { if (!fDbEnvInit) return; @@ -50,18 +47,67 @@ DbEnv(0).remove(GetDataDir().string().c_str(), 0); } -class CDBInit +CDBEnv::CDBEnv() : dbenv(0) +{ +} + +CDBEnv::~CDBEnv() +{ + EnvShutdown(); +} + +void CDBEnv::Close() +{ + EnvShutdown(); +} + +bool CDBEnv::Open(boost::filesystem::path pathEnv_) { -public: - CDBInit() - { - } - ~CDBInit() - { - EnvShutdown(); - } + if (fDbEnvInit) + return true; + + if (fShutdown) + return false; + + pathEnv = pathEnv_; + filesystem::path pathDataDir = pathEnv; + filesystem::path pathLogDir = pathDataDir / "database"; + filesystem::create_directory(pathLogDir); + filesystem::path pathErrorFile = pathDataDir / "db.log"; + printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str()); + + int nDbCache = GetArg("-dbcache", 25); + dbenv.set_lg_dir(pathLogDir.string().c_str()); + dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1); + dbenv.set_lg_bsize(1048576); + dbenv.set_lg_max(10485760); + dbenv.set_lk_max_locks(10000); + dbenv.set_lk_max_objects(10000); + dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug + dbenv.set_flags(DB_AUTO_COMMIT, 1); + dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); + dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); + int ret = dbenv.open(pathDataDir.string().c_str(), + DB_CREATE | + DB_INIT_LOCK | + DB_INIT_LOG | + DB_INIT_MPOOL | + DB_INIT_TXN | + DB_THREAD | + DB_RECOVER, + S_IRUSR | S_IWUSR); + if (ret > 0) + return error("CDB() : error %d opening database environment", ret); + + fDbEnvInit = true; + return true; } -instance_of_cdbinit; + +void CDBEnv::CheckpointLSN(std::string strFile) +{ + dbenv.txn_checkpoint(0, 0, 0); + dbenv.lsn_reset(strFile.c_str(), 0); +} CDB::CDB(const char *pszFile, const char* pszMode) : pdb(NULL) @@ -77,48 +123,16 @@ nFlags |= DB_CREATE; { - LOCK(cs_db); - if (!fDbEnvInit) - { - if (fShutdown) - return; - filesystem::path pathDataDir = GetDataDir(); - filesystem::path pathLogDir = pathDataDir / "database"; - filesystem::create_directory(pathLogDir); - filesystem::path pathErrorFile = pathDataDir / "db.log"; - printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str()); - - int nDbCache = GetArg("-dbcache", 25); - dbenv.set_lg_dir(pathLogDir.string().c_str()); - dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1); - dbenv.set_lg_bsize(1048576); - dbenv.set_lg_max(10485760); - dbenv.set_lk_max_locks(10000); - dbenv.set_lk_max_objects(10000); - dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug - dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1); - dbenv.set_flags(DB_AUTO_COMMIT, 1); - dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1); - ret = dbenv.open(pathDataDir.string().c_str(), - DB_CREATE | - DB_INIT_LOCK | - DB_INIT_LOG | - DB_INIT_MPOOL | - DB_INIT_TXN | - DB_THREAD | - DB_RECOVER, - S_IRUSR | S_IWUSR); - if (ret > 0) - throw runtime_error(strprintf("CDB() : error %d opening database environment", ret)); - fDbEnvInit = true; - } + LOCK(bitdb.cs_db); + if (!bitdb.Open(GetDataDir())) + throw runtime_error("env open failed"); strFile = pszFile; ++mapFileUseCount[strFile]; pdb = mapDb[strFile]; if (pdb == NULL) { - pdb = new Db(&dbenv, 0); + pdb = new Db(&bitdb.dbenv, 0); ret = pdb->open(NULL, // Txn pointer pszFile, // Filename @@ -132,7 +146,7 @@ delete pdb; pdb = NULL; { - LOCK(cs_db); + LOCK(bitdb.cs_db); --mapFileUseCount[strFile]; } strFile = ""; @@ -170,10 +184,10 @@ if (strFile == "blkindex.dat" && IsInitialBlockDownload()) nMinutes = 5; - dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0); + bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0); { - LOCK(cs_db); + LOCK(bitdb.cs_db); --mapFileUseCount[strFile]; } } @@ -181,7 +195,7 @@ void CloseDb(const string& strFile) { { - LOCK(cs_db); + LOCK(bitdb.cs_db); if (mapDb[strFile] != NULL) { // Close the database handle @@ -198,13 +212,12 @@ while (!fShutdown) { { - LOCK(cs_db); + LOCK(bitdb.cs_db); if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0) { // Flush log data to the dat file CloseDb(strFile); - dbenv.txn_checkpoint(0, 0, 0); - dbenv.lsn_reset(strFile.c_str(), 0); + bitdb.CheckpointLSN(strFile); mapFileUseCount.erase(strFile); bool fSuccess = true; @@ -212,7 +225,7 @@ string strFileRes = strFile + ".rewrite"; { // surround usage of db with extra {} CDB db(strFile.c_str(), "r"); - Db* pdbCopy = new Db(&dbenv, 0); + Db* pdbCopy = new Db(&bitdb.dbenv, 0); int ret = pdbCopy->open(NULL, // Txn pointer strFileRes.c_str(), // Filename @@ -270,10 +283,10 @@ } if (fSuccess) { - Db dbA(&dbenv, 0); + Db dbA(&bitdb.dbenv, 0); if (dbA.remove(strFile.c_str(), NULL, 0)) fSuccess = false; - Db dbB(&dbenv, 0); + Db dbB(&bitdb.dbenv, 0); if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) fSuccess = false; } @@ -288,12 +301,12 @@ } -void DBFlush(bool fShutdown) +void CDBEnv::Flush(bool fShutdown) { int64 nStart = GetTimeMillis(); // Flush log data to the actual data file // on all files that are not in use - printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started"); + printf("Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started"); if (!fDbEnvInit) return; { @@ -327,7 +340,7 @@ if (mapFileUseCount.empty()) { dbenv.log_archive(&listp, DB_ARCH_REMOVE); - EnvShutdown(); + Close(); } } } diff --git a/src/db.h b/src/db.h --- a/src/db.h +++ b/src/db.h @@ -25,14 +25,36 @@ class CWalletTx; extern unsigned int nWalletDBUpdated; -extern bool fDetachDB; -extern DbEnv dbenv; -extern void DBFlush(bool fShutdown); void ThreadFlushWalletDB(void* parg); bool BackupWallet(const CWallet& wallet, const std::string& strDest); +class CDBEnv +{ +private: + bool fDetachDB; + bool fDbEnvInit; + boost::filesystem::path pathEnv; + + void EnvShutdown(); + +public: + mutable CCriticalSection cs_db; + DbEnv dbenv; + + CDBEnv(); + ~CDBEnv(); + bool Open(boost::filesystem::path pathEnv_); + void Close(); + void Flush(bool fShutdown); + void CheckpointLSN(std::string strFile); + void SetDetach(bool fDetachDB_) { fDetachDB = fDetachDB_; } +}; + +extern CDBEnv bitdb; + + /** RAII class that provides access to a Berkeley database */ class CDB { @@ -216,7 +238,7 @@ if (!pdb) return false; DbTxn* ptxn = NULL; - int ret = dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_WRITE_NOSYNC); + int ret = bitdb.dbenv.txn_begin(GetTxn(), &ptxn, DB_TXN_WRITE_NOSYNC); if (!ptxn || ret != 0) return false; vTxn.push_back(ptxn); diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -54,9 +54,9 @@ { fShutdown = true; nTransactionsUpdated++; - DBFlush(false); + bitdb.Flush(false); StopNode(); - DBFlush(true); + bitdb.Flush(true); boost::filesystem::remove(GetPidFile()); UnregisterWallet(pwalletMain); delete pwalletMain; @@ -294,7 +294,7 @@ } fDebug = GetBoolArg("-debug"); - fDetachDB = GetBoolArg("-detachdb", false); + bitdb.SetDetach(GetBoolArg("-detachdb", false)); #if !defined(WIN32) && !defined(QT_GUI) fDaemon = GetBoolArg("-daemon"); diff --git a/src/walletdb.cpp b/src/walletdb.cpp --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -13,7 +13,6 @@ static uint64 nAccountingEntryNumber = 0; -extern CCriticalSection cs_db; extern map mapFileUseCount; extern void CloseDb(const string& strFile); @@ -350,7 +349,7 @@ if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2) { - TRY_LOCK(cs_db,lockDb); + TRY_LOCK(bitdb.cs_db,lockDb); if (lockDb) { // Don't do this if any databases are in use @@ -373,8 +372,7 @@ // Flush wallet.dat so it's self contained CloseDb(strFile); - dbenv.txn_checkpoint(0, 0, 0); - dbenv.lsn_reset(strFile.c_str(), 0); + bitdb.CheckpointLSN(strFile); mapFileUseCount.erase(mi++); printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart); @@ -392,13 +390,12 @@ while (!fShutdown) { { - LOCK(cs_db); + LOCK(bitdb.cs_db); if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0) { // Flush log data to the dat file CloseDb(wallet.strWalletFile); - dbenv.txn_checkpoint(0, 0, 0); - dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0); + bitdb.CheckpointLSN(wallet.strWalletFile); mapFileUseCount.erase(wallet.strWalletFile); // Copy wallet.dat