20 #include <boost/thread.hpp>
21 #include <boost/version.hpp>
37 int ret =
dbenv->close(0);
39 LogPrintf(
"CDBEnv::EnvShutdown : Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
41 DbEnv((u_int32_t)0).remove(
strPath.c_str(), 0);
47 dbenv =
new DbEnv(DB_CXX_NO_EXCEPTIONS);
74 boost::this_thread::interruption_point();
77 fs::path pathLogDir = pathIn /
"database";
79 fs::path pathErrorFile = pathIn /
"db.log";
80 LogPrintf(
"CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string());
82 unsigned int nEnvFlags = 0;
84 nEnvFlags |= DB_PRIVATE;
86 dbenv->set_lg_dir(pathLogDir.string().c_str());
87 dbenv->set_cachesize(1, 0x100000, 1);
88 dbenv->set_lg_bsize(0x10000);
89 dbenv->set_lg_max(1048576);
90 dbenv->set_lk_max_locks(40000);
91 dbenv->set_lk_max_objects(40000);
93 dbenv->set_flags(DB_AUTO_COMMIT, 1);
94 dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1);
95 dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1);
108 return error(
"CDBEnv::Open : Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
119 throw std::runtime_error(
"CDBEnv::MakeMock : Already initialized");
121 boost::this_thread::interruption_point();
125 dbenv->set_cachesize(1, 0, 1);
126 dbenv->set_lg_bsize(10485760 * 4);
127 dbenv->set_lg_max(10485760);
128 dbenv->set_lk_max_locks(10000);
129 dbenv->set_lk_max_objects(10000);
130 dbenv->set_flags(DB_AUTO_COMMIT, 1);
131 dbenv->log_set_config(DB_LOG_IN_MEMORY, 1);
132 int ret =
dbenv->open(NULL,
142 throw std::runtime_error(
strprintf(
"CDBEnv::MakeMock : Error %d opening database environment.", ret));
154 int result = db.verify(strFile.c_str(), NULL, NULL, 0);
157 else if (recoverFunc == NULL)
161 bool fRecovered = (*recoverFunc)(*
this, strFile);
169 DB_COMPACT dbcompact;
170 dbcompact.compact_fillpercent = 80;
171 dbcompact.compact_pages = DB_MAX_PAGES;
172 dbcompact.compact_timeout = 0;
174 DB_COMPACT *pdbcompact;
175 pdbcompact = &dbcompact;
178 if (
mapDb[strFile] != NULL) {
179 Db* pdb =
mapDb[strFile];
180 result = pdb->compact(NULL, NULL, NULL, pdbcompact, DB_FREE_SPACE, NULL);
182 mapDb[strFile] = NULL;
186 case DB_LOCK_DEADLOCK:
189 case DB_LOCK_NOTGRANTED:
192 case DB_REP_HANDLE_DEAD:
211 return (result == 0);
214 bool CDBEnv::Salvage(std::string strFile,
bool fAggressive, std::vector<CDBEnv::KeyValPair>& vResult)
219 u_int32_t
flags = DB_SALVAGE;
221 flags |= DB_AGGRESSIVE;
223 std::stringstream strDump;
226 int result = db.verify(strFile.c_str(), NULL, &strDump,
flags);
227 if (result == DB_VERIFY_BAD) {
228 LogPrintf(
"CDBEnv::Salvage : Database salvage found errors, all data may not be recoverable.\n");
230 LogPrintf(
"CDBEnv::Salvage : Rerun with aggressive mode to ignore errors and continue.\n");
234 if (result != 0 && result != DB_VERIFY_BAD) {
235 LogPrintf(
"CDBEnv::Salvage : Database salvage failed with result %d.\n", result);
248 while (!strDump.eof() && strLine !=
"HEADER=END")
249 getline(strDump, strLine);
251 std::string keyHex, valueHex;
252 while (!strDump.eof() && keyHex !=
"DATA=END") {
253 getline(strDump, keyHex);
254 if (keyHex !=
"DATA=END") {
255 getline(strDump, valueHex);
260 return (result == 0);
266 dbenv->txn_checkpoint(0, 0, 0);
269 dbenv->lsn_reset(strFile.c_str(), 0);
273 CDB::CDB(
const std::string& strFilename,
const char* pszMode,
bool fFlushOnCloseIn) : pdb(NULL), activeTxn(NULL)
276 fReadOnly = (!strchr(pszMode,
'+') && !strchr(pszMode,
'w'));
278 if (strFilename.empty())
281 bool fCreate = strchr(pszMode,
'c') != NULL;
282 unsigned int nFlags = DB_THREAD;
289 throw std::runtime_error(
"CDB : Failed to open database environment.");
299 DbMpoolFile* mpf =
pdb->get_mpf();
300 ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
302 throw std::runtime_error(
strprintf(
"CDB : Failed to configure for no temp file backing for database %s",
strFile));
305 ret =
pdb->open(NULL,
306 fMockDb ? NULL :
strFile.c_str(),
307 fMockDb ?
strFile.c_str() :
"main",
318 throw std::runtime_error(
strprintf(
"CDB : Error %d, can't open database %s", ret, tempCopy));
321 if (fCreate && !
Exists(std::string(
"version"))) {
339 unsigned int nMinutes = 0;
343 bitdb.
dbenv->txn_checkpoint(nMinutes ?
GetArg(
"-dblogsize", 100) * 1024 : 0, nMinutes, 0);
368 if (
mapDb[strFile] != NULL) {
370 Db* pdb =
mapDb[strFile];
373 mapDb[strFile] = NULL;
383 int rc =
dbenv->dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT);
398 bool fSuccess =
true;
400 std::string strFileRes =
strFile +
".rewrite";
405 int ret = pdbCopy->open(NULL,
412 LogPrintf(
"CDB::Rewrite : Can't create database file %s\n", strFileRes);
421 int ret = db.
ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
422 if (ret == DB_NOTFOUND) {
425 }
else if (ret != 0) {
431 strncmp(&ssKey[0], pszSkip, std::min(ssKey.
size(), strlen(pszSkip))) == 0)
433 if (strncmp(&ssKey[0],
"\x07version", 8) == 0) {
436 ssValue << CLIENT_VERSION;
438 Dbt datKey(&ssKey[0], ssKey.
size());
439 Dbt datValue(&ssValue[0], ssValue.
size());
440 int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
447 if (pdbCopy->close(0))
456 if (dbA.remove(
strFile.c_str(), NULL, 0))
459 if (dbB.rename(strFileRes.c_str(), NULL,
strFile.c_str(), 0))
463 LogPrintf(
"CDB::Rewrite : Failed to rewrite database file %s\n", strFileRes);
484 std::string strFile = (*mi).first;
485 int nRefCount = (*mi).second;
486 LogPrint(
BCLog::DB,
"CDBEnv::Flush : Flushing %s (refcount = %d)...\n", strFile, nRefCount);
487 if (nRefCount == 0) {
491 dbenv->txn_checkpoint(0, 0, 0);
494 dbenv->lsn_reset(strFile.c_str(), 0);
504 dbenv->log_archive(&listp, DB_ARCH_REMOVE);
507 fs::remove_all(fs::path(
strPath) /
"database");