19 #include <boost/filesystem.hpp>
20 #include <boost/version.hpp>
21 #include <openssl/rand.h>
24 using namespace boost;
43 int ret = dbenv.close(0);
45 LogPrintf(
"CDBEnv::EnvShutdown : Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
47 DbEnv(0).remove(path.string().c_str(), 0);
71 boost::this_thread::interruption_point();
74 filesystem::path pathLogDir =
path /
"database";
76 filesystem::path pathErrorFile =
path /
"db.log";
77 LogPrintf(
"CDBEnv::Open : LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string());
79 unsigned int nEnvFlags = 0;
81 nEnvFlags |= DB_PRIVATE;
83 dbenv.set_lg_dir(pathLogDir.string().c_str());
84 dbenv.set_cachesize(0, 0x100000, 1);
85 dbenv.set_lg_bsize(0x10000);
86 dbenv.set_lg_max(1048576);
87 dbenv.set_lk_max_locks(40000);
88 dbenv.set_lk_max_objects(40000);
89 dbenv.set_errfile(fopen(pathErrorFile.string().c_str(),
"a"));
90 dbenv.set_flags(DB_AUTO_COMMIT, 1);
91 dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
92 dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
93 int ret =
dbenv.open(
path.string().c_str(),
104 return error(
"CDBEnv::Open : Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
114 throw runtime_error(
"CDBEnv::MakeMock : Already initialized");
116 boost::this_thread::interruption_point();
118 LogPrint(
"db",
"CDBEnv::MakeMock\n");
120 dbenv.set_cachesize(1, 0, 1);
121 dbenv.set_lg_bsize(10485760*4);
122 dbenv.set_lg_max(10485760);
123 dbenv.set_lk_max_locks(10000);
124 dbenv.set_lk_max_objects(10000);
125 dbenv.set_flags(DB_AUTO_COMMIT, 1);
126 dbenv.log_set_config(DB_LOG_IN_MEMORY, 1);
127 int ret =
dbenv.open(NULL,
137 throw runtime_error(
strprintf(
"CDBEnv::MakeMock : Error %d opening database environment.", ret));
149 int result = db.verify(strFile.c_str(), NULL, NULL, 0);
152 else if (recoverFunc == NULL)
156 bool fRecovered = (*recoverFunc)(*
this, strFile);
161 std::vector<CDBEnv::KeyValPair >& vResult)
166 u_int32_t flags = DB_SALVAGE;
167 if (fAggressive) flags |= DB_AGGRESSIVE;
169 stringstream strDump;
172 int result = db.verify(strFile.c_str(), NULL, &strDump, flags);
173 if (result == DB_VERIFY_BAD)
175 LogPrintf(
"CDBEnv::Salvage : Database salvage found errors, all data may not be recoverable.\n");
178 LogPrintf(
"CDBEnv::Salvage : Rerun with aggressive mode to ignore errors and continue.\n");
182 if (result != 0 && result != DB_VERIFY_BAD)
184 LogPrintf(
"CDBEnv::Salvage : Database salvage failed with result %d.\n", result);
197 while (!strDump.eof() && strLine !=
"HEADER=END")
198 getline(strDump, strLine);
200 std::string keyHex, valueHex;
201 while (!strDump.eof() && keyHex !=
"DATA=END")
203 getline(strDump, keyHex);
204 if (keyHex !=
"DATA_END")
206 getline(strDump, valueHex);
211 return (result == 0);
217 dbenv.txn_checkpoint(0, 0, 0);
220 dbenv.lsn_reset(strFile.c_str(), 0);
224 CDB::CDB(
const char *pszFile,
const char* pszMode) :
225 pdb(NULL), activeTxn(NULL)
231 fReadOnly = (!strchr(pszMode,
'+') && !strchr(pszMode,
'w'));
232 bool fCreate = strchr(pszMode,
'c');
233 unsigned int nFlags = DB_THREAD;
240 throw runtime_error(
"CDB : Failed to open database environment.");
249 bool fMockDb = bitdb.
IsMock();
252 DbMpoolFile*mpf =
pdb->get_mpf();
253 ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
255 throw runtime_error(
strprintf(
"CDB : Failed to configure for no temp file backing for database %s", pszFile));
258 ret =
pdb->open(NULL,
259 fMockDb ? NULL : pszFile,
260 fMockDb ? pszFile :
"main",
271 throw runtime_error(
strprintf(
"CDB : Error %d, can't open database %s", ret, pszFile));
274 if (fCreate && !
Exists(
string(
"version")))
293 unsigned int nMinutes = 0;
297 bitdb.
dbenv.txn_checkpoint(nMinutes ?
GetArg(
"-dblogsize", 100)*1024 : 0, nMinutes, 0);
321 if (
mapDb[strFile] != NULL)
324 Db* pdb =
mapDb[strFile];
327 mapDb[strFile] = NULL;
337 int rc =
dbenv.dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT);
354 bool fSuccess =
true;
355 LogPrintf(
"CDB::Rewrite : Rewriting %s...\n", strFile);
356 string strFileRes = strFile +
".rewrite";
358 CDB db(strFile.c_str(),
"r");
359 Db* pdbCopy =
new Db(&bitdb.
dbenv, 0);
361 int ret = pdbCopy->open(NULL,
369 LogPrintf(
"CDB::Rewrite : Can't create database file %s\n", strFileRes);
373 Dbc* pcursor = db.GetCursor();
379 int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
380 if (ret == DB_NOTFOUND)
392 strncmp(&ssKey[0], pszSkip, std::min(ssKey.
size(), strlen(pszSkip))) == 0)
394 if (strncmp(&ssKey[0],
"\x07version", 8) == 0)
400 Dbt datKey(&ssKey[0], ssKey.
size());
401 Dbt datValue(&ssValue[0], ssValue.
size());
402 int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
410 if (pdbCopy->close(0))
417 Db dbA(&bitdb.
dbenv, 0);
418 if (dbA.remove(strFile.c_str(), NULL, 0))
420 Db dbB(&bitdb.
dbenv, 0);
421 if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
425 LogPrintf(
"CDB::Rewrite : Failed to rewrite database file %s\n", strFileRes);
439 LogPrint(
"db",
"CDBEnv::Flush : Flush(%s)%s\n", fShutdown ?
"true" :
"false",
fDbEnvInit ?
"" :
" database not started");
447 string strFile = (*mi).first;
448 int nRefCount = (*mi).second;
449 LogPrint(
"db",
"CDBEnv::Flush : Flushing %s (refcount = %d)...\n", strFile, nRefCount);
454 LogPrint(
"db",
"CDBEnv::Flush : %s checkpoint\n", strFile);
455 dbenv.txn_checkpoint(0, 0, 0);
456 LogPrint(
"db",
"CDBEnv::Flush : %s detach\n", strFile);
458 dbenv.lsn_reset(strFile.c_str(), 0);
459 LogPrint(
"db",
"CDBEnv::Flush : %s closed\n", strFile);
465 LogPrint(
"db",
"CDBEnv::Flush : Flush(%s)%s took %15dms\n", fShutdown ?
"true" :
"false",
fDbEnvInit ?
"" :
" database not started",
GetTimeMillis() - nStart);
471 dbenv.log_archive(&listp, DB_ARCH_REMOVE);
474 boost::filesystem::remove_all(
path /
"database");
const boost::filesystem::path & GetDataDir(bool fNetSpecific)
unsigned int nWalletDBUpdated
std::map< std::string, int > mapFileUseCount
void CheckpointLSN(std::string strFile)
void MilliSleep(int64_t n)
static bool Rewrite(const std::string &strFile, const char *pszSkip=NULL)
static const int CLIENT_VERSION
void Flush(bool fShutdown)
bool Exists(const K &key)
Double ended buffer combining vector and stream-like interfaces.
boost::filesystem::path path
bool GetBoolArg(const std::string &strArg, bool fDefault)
Return boolean argument or default value.
std::map< std::string, Db * > mapDb
static int LogPrint(const char *category, const char *format)
static bool error(const char *format)
bool TryCreateDirectory(const boost::filesystem::path &p)
RAII class that provides access to a Berkeley database.
bool RemoveDb(const std::string &strFile)
bool Salvage(std::string strFile, bool fAggressive, std::vector< KeyValPair > &vResult)
void CloseDb(const std::string &strFile)
bool WriteVersion(int nVersion)
CDB(const char *pszFile, const char *pszMode="r+")
VerifyResult Verify(std::string strFile, bool(*recoverFunc)(CDBEnv &dbenv, std::string strFile))
std::string GetArg(const std::string &strArg, const std::string &strDefault)
Return string argument or default value.
bool Open(const boost::filesystem::path &path)
vector< unsigned char > ParseHex(const char *psz)