20 #include <boost/filesystem.hpp> 21 #include <boost/thread.hpp> 22 #include <boost/version.hpp> 42 int ret = dbenv->close(0);
44 LogPrintf(
"CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
46 DbEnv(0).remove(strPath.c_str(), 0);
52 dbenv =
new DbEnv(DB_CXX_NO_EXCEPTIONS);
79 boost::this_thread::interruption_point();
82 boost::filesystem::path pathLogDir = pathIn /
"database";
84 boost::filesystem::path pathErrorFile = pathIn /
"db.log";
85 LogPrintf(
"CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string());
87 unsigned int nEnvFlags = 0;
89 nEnvFlags |= DB_PRIVATE;
91 dbenv->set_lg_dir(pathLogDir.string().c_str());
92 dbenv->set_cachesize(0, 0x100000, 1);
93 dbenv->set_lg_bsize(0x10000);
94 dbenv->set_lg_max(1048576);
95 dbenv->set_lk_max_locks(40000);
96 dbenv->set_lk_max_objects(40000);
97 dbenv->set_errfile(fopen(pathErrorFile.string().c_str(),
"a"));
98 dbenv->set_flags(DB_AUTO_COMMIT, 1);
99 dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1);
100 dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1);
112 return error(
"CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
122 throw runtime_error(
"CDBEnv::MakeMock: Already initialized");
124 boost::this_thread::interruption_point();
126 LogPrint(
"db",
"CDBEnv::MakeMock\n");
128 dbenv->set_cachesize(1, 0, 1);
129 dbenv->set_lg_bsize(10485760 * 4);
130 dbenv->set_lg_max(10485760);
131 dbenv->set_lk_max_locks(10000);
132 dbenv->set_lk_max_objects(10000);
133 dbenv->set_flags(DB_AUTO_COMMIT, 1);
134 dbenv->log_set_config(DB_LOG_IN_MEMORY, 1);
135 int ret =
dbenv->open(NULL,
145 throw runtime_error(
strprintf(
"CDBEnv::MakeMock: Error %d opening database environment.", ret));
157 int result = db.verify(strFile.c_str(), NULL, NULL, 0);
160 else if (recoverFunc == NULL)
164 bool fRecovered = (*recoverFunc)(*
this, strFile);
168 bool CDBEnv::Salvage(
const std::string& strFile,
bool fAggressive, std::vector<CDBEnv::KeyValPair>& vResult)
173 u_int32_t
flags = DB_SALVAGE;
175 flags |= DB_AGGRESSIVE;
177 stringstream strDump;
180 int result = db.verify(strFile.c_str(), NULL, &strDump,
flags);
181 if (
result == DB_VERIFY_BAD) {
182 LogPrintf(
"CDBEnv::Salvage: Database salvage found errors, all data may not be recoverable.\n");
184 LogPrintf(
"CDBEnv::Salvage: Rerun with aggressive mode to ignore errors and continue.\n");
189 LogPrintf(
"CDBEnv::Salvage: Database salvage failed with result %d.\n",
result);
202 while (!strDump.eof() && strLine !=
"HEADER=END")
203 getline(strDump, strLine);
205 std::string keyHex, valueHex;
206 while (!strDump.eof() && keyHex !=
"DATA=END") {
207 getline(strDump, keyHex);
208 if (keyHex !=
"DATA=END") {
209 getline(strDump, valueHex);
220 dbenv->txn_checkpoint(0, 0, 0);
223 dbenv->lsn_reset(strFile.c_str(), 0);
227 CDB::CDB(
const std::string& strFilename,
const char* pszMode,
bool fFlushOnCloseIn) : pdb(NULL), activeTxn(NULL)
230 fReadOnly = (!strchr(pszMode,
'+') && !strchr(pszMode,
'w'));
232 if (strFilename.empty())
235 bool fCreate = strchr(pszMode,
'c') != NULL;
236 unsigned int nFlags = DB_THREAD;
243 throw runtime_error(
"CDB: Failed to open database environment.");
253 DbMpoolFile* mpf =
pdb->get_mpf();
254 ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
256 throw runtime_error(
strprintf(
"CDB: Failed to configure for no temp file backing for database %s",
strFile));
259 ret =
pdb->open(NULL,
260 fMockDb ? NULL :
strFile.c_str(),
261 fMockDb ?
strFile.c_str() :
"main",
271 throw runtime_error(
strprintf(
"CDB: Error %d, can't open database %s", ret, strFilename));
274 if (fCreate && !
Exists(
string(
"version"))) {
292 unsigned int nMinutes = 0;
321 if (
mapDb[strFile] != NULL) {
323 Db* pdb =
mapDb[strFile];
326 mapDb[strFile] = NULL;
336 int rc =
dbenv->dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT);
351 bool fSuccess =
true;
353 string strFileRes =
strFile +
".rewrite";
358 int ret = pdbCopy->open(NULL,
365 LogPrintf(
"CDB::Rewrite: Can't create database file %s\n", strFileRes);
369 Dbc* pcursor = db.GetCursor();
374 int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
375 if (ret == DB_NOTFOUND) {
378 }
else if (ret != 0) {
384 strncmp(&ssKey[0], pszSkip, std::min(ssKey.
size(), strlen(pszSkip))) == 0)
386 if (strncmp(&ssKey[0],
"\x07version", 8) == 0) {
391 Dbt datKey(&ssKey[0], ssKey.
size());
392 Dbt datValue(&ssValue[0], ssValue.
size());
393 int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
400 if (pdbCopy->close(0))
407 if (dbA.remove(
strFile.c_str(), NULL, 0))
410 if (dbB.rename(strFileRes.c_str(), NULL,
strFile.c_str(), 0))
414 LogPrintf(
"CDB::Rewrite: Failed to rewrite database file %s\n", strFileRes);
428 LogPrint(
"db",
"CDBEnv::Flush: Flush(%s)%s\n", fShutdown ?
"true" :
"false",
fDbEnvInit ?
"" :
" database not started");
435 string strFile = (*mi).first;
436 int nRefCount = (*mi).second;
437 LogPrint(
"db",
"CDBEnv::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount);
438 if (nRefCount == 0) {
441 LogPrint(
"db",
"CDBEnv::Flush: %s checkpoint\n", strFile);
442 dbenv->txn_checkpoint(0, 0, 0);
443 LogPrint(
"db",
"CDBEnv::Flush: %s detach\n", strFile);
445 dbenv->lsn_reset(strFile.c_str(), 0);
446 LogPrint(
"db",
"CDBEnv::Flush: %s closed\n", strFile);
451 LogPrint(
"db",
"CDBEnv::Flush: Flush(%s)%s took %15dms\n", fShutdown ?
"true" :
"false",
fDbEnvInit ?
"" :
" database not started",
GetTimeMillis() - nStart);
455 dbenv->log_archive(&listp, DB_ARCH_REMOVE);
458 boost::filesystem::remove_all(boost::filesystem::path(
strPath) /
"database");
VerifyResult Verify(const std::string &strFile, bool(*recoverFunc)(CDBEnv &dbenv, const std::string &strFile))
const boost::filesystem::path & GetDataDir(bool fNetSpecific)
unsigned int nWalletDBUpdated
bool RemoveDb(const std::string &strFile)
std::map< std::string, Db * > mapDb
CDB(const std::string &strFilename, const char *pszMode="r+", bool fFlushOnCloseIn=true)
void MilliSleep(int64_t n)
bool Exists(const K &key)
static bool Rewrite(const std::string &strFile, const char *pszSkip=NULL)
std::map< std::string, int > mapFileUseCount
bool GetBoolArg(const std::string &strArg, bool fDefault)
static int LogPrint(const char *category, const char *format)
bool Open(const boost::filesystem::path &path)
static bool error(const char *format)
bool TryCreateDirectory(const boost::filesystem::path &p)
vector< unsigned char > ParseHex(const char *psz)
static const unsigned int DEFAULT_WALLET_DBLOGSIZE
void Flush(bool fShutdown)
void CheckpointLSN(const std::string &strFile)
bool Salvage(const std::string &strFile, bool fAggressive, std::vector< KeyValPair > &vResult)
bool WriteVersion(int nVersion)
static const bool DEFAULT_WALLET_PRIVDB
void CloseDb(const std::string &strFile)
std::string GetArg(const std::string &strArg, const std::string &strDefault)
static const int CLIENT_VERSION