20 #include <boost/filesystem.hpp>
21 #include <boost/version.hpp>
22 #include <openssl/rand.h>
25 using namespace boost;
44 int ret = dbenv.close(0);
46 LogPrintf(
"CDBEnv::EnvShutdown : Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
48 DbEnv(0).remove(path.string().c_str(), 0);
72 boost::this_thread::interruption_point();
75 filesystem::path pathLogDir =
path /
"database";
77 filesystem::path pathErrorFile =
path /
"db.log";
78 LogPrintf(
"CDBEnv::Open : LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string());
80 unsigned int nEnvFlags = 0;
82 nEnvFlags |= DB_PRIVATE;
84 dbenv.set_lg_dir(pathLogDir.string().c_str());
85 dbenv.set_cachesize(0, 0x100000, 1);
86 dbenv.set_lg_bsize(0x10000);
87 dbenv.set_lg_max(1048576);
88 dbenv.set_lk_max_locks(40000);
89 dbenv.set_lk_max_objects(40000);
90 dbenv.set_errfile(fopen(pathErrorFile.string().c_str(),
"a"));
91 dbenv.set_flags(DB_AUTO_COMMIT, 1);
92 dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
93 dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
94 int ret =
dbenv.open(
path.string().c_str(),
105 return error(
"CDBEnv::Open : Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
115 throw runtime_error(
"CDBEnv::MakeMock : Already initialized");
117 boost::this_thread::interruption_point();
119 LogPrint(
"db",
"CDBEnv::MakeMock\n");
121 dbenv.set_cachesize(1, 0, 1);
122 dbenv.set_lg_bsize(10485760*4);
123 dbenv.set_lg_max(10485760);
124 dbenv.set_lk_max_locks(10000);
125 dbenv.set_lk_max_objects(10000);
126 dbenv.set_flags(DB_AUTO_COMMIT, 1);
127 dbenv.log_set_config(DB_LOG_IN_MEMORY, 1);
128 int ret =
dbenv.open(NULL,
138 throw runtime_error(
strprintf(
"CDBEnv::MakeMock : Error %d opening database environment.", ret));
150 int result = db.verify(strFile.c_str(), NULL, NULL, 0);
153 else if (recoverFunc == NULL)
157 bool fRecovered = (*recoverFunc)(*
this, strFile);
162 std::vector<CDBEnv::KeyValPair >& vResult)
167 u_int32_t flags = DB_SALVAGE;
168 if (fAggressive) flags |= DB_AGGRESSIVE;
170 stringstream strDump;
173 int result = db.verify(strFile.c_str(), NULL, &strDump, flags);
174 if (result == DB_VERIFY_BAD)
176 LogPrintf(
"CDBEnv::Salvage : Database salvage found errors, all data may not be recoverable.\n");
179 LogPrintf(
"CDBEnv::Salvage : Rerun with aggressive mode to ignore errors and continue.\n");
183 if (result != 0 && result != DB_VERIFY_BAD)
185 LogPrintf(
"CDBEnv::Salvage : Database salvage failed with result %d.\n", result);
198 while (!strDump.eof() && strLine !=
"HEADER=END")
199 getline(strDump, strLine);
201 std::string keyHex, valueHex;
202 while (!strDump.eof() && keyHex !=
"DATA=END")
204 getline(strDump, keyHex);
205 if (keyHex !=
"DATA_END")
207 getline(strDump, valueHex);
212 return (result == 0);
218 dbenv.txn_checkpoint(0, 0, 0);
221 dbenv.lsn_reset(strFile.c_str(), 0);
225 CDB::CDB(
const char *pszFile,
const char* pszMode) :
226 pdb(NULL), activeTxn(NULL)
232 fReadOnly = (!strchr(pszMode,
'+') && !strchr(pszMode,
'w'));
233 bool fCreate = strchr(pszMode,
'c');
234 unsigned int nFlags = DB_THREAD;
241 throw runtime_error(
"CDB : Failed to open database environment.");
250 bool fMockDb = bitdb.
IsMock();
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", pszFile));
259 ret =
pdb->open(NULL,
260 fMockDb ? NULL : pszFile,
261 fMockDb ? pszFile :
"main",
272 throw runtime_error(
strprintf(
"CDB : Error %d, can't open database %s", ret, pszFile));
275 if (fCreate && !
Exists(
string(
"version")))
294 unsigned int nMinutes = 0;
298 bitdb.
dbenv.txn_checkpoint(nMinutes ?
GetArg(
"-dblogsize", 100)*1024 : 0, nMinutes, 0);
322 if (
mapDb[strFile] != NULL)
325 Db* pdb =
mapDb[strFile];
328 mapDb[strFile] = NULL;
338 int rc =
dbenv.dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT);
355 bool fSuccess =
true;
356 LogPrintf(
"CDB::Rewrite : Rewriting %s...\n", strFile);
357 string strFileRes = strFile +
".rewrite";
359 CDB db(strFile.c_str(),
"r");
360 Db* pdbCopy =
new Db(&bitdb.
dbenv, 0);
362 int ret = pdbCopy->open(NULL,
370 LogPrintf(
"CDB::Rewrite : Can't create database file %s\n", strFileRes);
374 Dbc* pcursor = db.GetCursor();
380 int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
381 if (ret == DB_NOTFOUND)
393 strncmp(&ssKey[0], pszSkip, std::min(ssKey.
size(), strlen(pszSkip))) == 0)
395 if (strncmp(&ssKey[0],
"\x07version", 8) == 0)
399 ssValue << CLIENT_VERSION;
401 Dbt datKey(&ssKey[0], ssKey.
size());
402 Dbt datValue(&ssValue[0], ssValue.
size());
403 int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
411 if (pdbCopy->close(0))
418 Db dbA(&bitdb.
dbenv, 0);
419 if (dbA.remove(strFile.c_str(), NULL, 0))
421 Db dbB(&bitdb.
dbenv, 0);
422 if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
426 LogPrintf(
"CDB::Rewrite : Failed to rewrite database file %s\n", strFileRes);
440 LogPrint(
"db",
"CDBEnv::Flush : Flush(%s)%s\n", fShutdown ?
"true" :
"false",
fDbEnvInit ?
"" :
" database not started");
448 string strFile = (*mi).first;
449 int nRefCount = (*mi).second;
450 LogPrint(
"db",
"CDBEnv::Flush : Flushing %s (refcount = %d)...\n", strFile, nRefCount);
455 LogPrint(
"db",
"CDBEnv::Flush : %s checkpoint\n", strFile);
456 dbenv.txn_checkpoint(0, 0, 0);
457 LogPrint(
"db",
"CDBEnv::Flush : %s detach\n", strFile);
459 dbenv.lsn_reset(strFile.c_str(), 0);
460 LogPrint(
"db",
"CDBEnv::Flush : %s closed\n", strFile);
466 LogPrint(
"db",
"CDBEnv::Flush : Flush(%s)%s took %15dms\n", fShutdown ?
"true" :
"false",
fDbEnvInit ?
"" :
" database not started",
GetTimeMillis() - nStart);
472 dbenv.log_archive(&listp, DB_ARCH_REMOVE);
475 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)
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
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)