|
|
@ -364,6 +364,7 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb |
|
|
|
int ret; |
|
|
|
int ret; |
|
|
|
fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); |
|
|
|
fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w')); |
|
|
|
fFlushOnClose = fFlushOnCloseIn; |
|
|
|
fFlushOnClose = fFlushOnCloseIn; |
|
|
|
|
|
|
|
env = dbw.env; |
|
|
|
if (dbw.IsDummy()) { |
|
|
|
if (dbw.IsDummy()) { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
@ -375,17 +376,17 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb |
|
|
|
nFlags |= DB_CREATE; |
|
|
|
nFlags |= DB_CREATE; |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
LOCK(bitdb.cs_db); |
|
|
|
LOCK(env->cs_db); |
|
|
|
if (!bitdb.Open(GetDataDir())) |
|
|
|
if (!env->Open(GetDataDir())) |
|
|
|
throw std::runtime_error("CDB: Failed to open database environment."); |
|
|
|
throw std::runtime_error("CDB: Failed to open database environment."); |
|
|
|
|
|
|
|
|
|
|
|
strFile = strFilename; |
|
|
|
strFile = strFilename; |
|
|
|
++bitdb.mapFileUseCount[strFile]; |
|
|
|
++env->mapFileUseCount[strFile]; |
|
|
|
pdb = bitdb.mapDb[strFile]; |
|
|
|
pdb = env->mapDb[strFile]; |
|
|
|
if (pdb == NULL) { |
|
|
|
if (pdb == NULL) { |
|
|
|
pdb = new Db(bitdb.dbenv, 0); |
|
|
|
pdb = new Db(env->dbenv, 0); |
|
|
|
|
|
|
|
|
|
|
|
bool fMockDb = bitdb.IsMock(); |
|
|
|
bool fMockDb = env->IsMock(); |
|
|
|
if (fMockDb) { |
|
|
|
if (fMockDb) { |
|
|
|
DbMpoolFile* mpf = pdb->get_mpf(); |
|
|
|
DbMpoolFile* mpf = pdb->get_mpf(); |
|
|
|
ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); |
|
|
|
ret = mpf->set_flags(DB_MPOOL_NOFILE, 1); |
|
|
@ -403,7 +404,7 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb |
|
|
|
if (ret != 0) { |
|
|
|
if (ret != 0) { |
|
|
|
delete pdb; |
|
|
|
delete pdb; |
|
|
|
pdb = NULL; |
|
|
|
pdb = NULL; |
|
|
|
--bitdb.mapFileUseCount[strFile]; |
|
|
|
--env->mapFileUseCount[strFile]; |
|
|
|
strFile = ""; |
|
|
|
strFile = ""; |
|
|
|
throw std::runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename)); |
|
|
|
throw std::runtime_error(strprintf("CDB: Error %d, can't open database %s", ret, strFilename)); |
|
|
|
} |
|
|
|
} |
|
|
@ -415,7 +416,7 @@ CDB::CDB(CWalletDBWrapper& dbw, const char* pszMode, bool fFlushOnCloseIn) : pdb |
|
|
|
fReadOnly = fTmp; |
|
|
|
fReadOnly = fTmp; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bitdb.mapDb[strFile] = pdb; |
|
|
|
env->mapDb[strFile] = pdb; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -430,7 +431,7 @@ void CDB::Flush() |
|
|
|
if (fReadOnly) |
|
|
|
if (fReadOnly) |
|
|
|
nMinutes = 1; |
|
|
|
nMinutes = 1; |
|
|
|
|
|
|
|
|
|
|
|
bitdb.dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0); |
|
|
|
env->dbenv->txn_checkpoint(nMinutes ? GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CDB::Close() |
|
|
|
void CDB::Close() |
|
|
@ -446,8 +447,8 @@ void CDB::Close() |
|
|
|
Flush(); |
|
|
|
Flush(); |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
LOCK(bitdb.cs_db); |
|
|
|
LOCK(env->cs_db); |
|
|
|
--bitdb.mapFileUseCount[strFile]; |
|
|
|
--env->mapFileUseCount[strFile]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -479,22 +480,23 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip) |
|
|
|
if (dbw.IsDummy()) { |
|
|
|
if (dbw.IsDummy()) { |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
CDBEnv *env = dbw.env; |
|
|
|
const std::string& strFile = dbw.strFile; |
|
|
|
const std::string& strFile = dbw.strFile; |
|
|
|
while (true) { |
|
|
|
while (true) { |
|
|
|
{ |
|
|
|
{ |
|
|
|
LOCK(bitdb.cs_db); |
|
|
|
LOCK(env->cs_db); |
|
|
|
if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) { |
|
|
|
if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0) { |
|
|
|
// Flush log data to the dat file
|
|
|
|
// Flush log data to the dat file
|
|
|
|
bitdb.CloseDb(strFile); |
|
|
|
env->CloseDb(strFile); |
|
|
|
bitdb.CheckpointLSN(strFile); |
|
|
|
env->CheckpointLSN(strFile); |
|
|
|
bitdb.mapFileUseCount.erase(strFile); |
|
|
|
env->mapFileUseCount.erase(strFile); |
|
|
|
|
|
|
|
|
|
|
|
bool fSuccess = true; |
|
|
|
bool fSuccess = true; |
|
|
|
LogPrintf("CDB::Rewrite: Rewriting %s...\n", strFile); |
|
|
|
LogPrintf("CDB::Rewrite: Rewriting %s...\n", strFile); |
|
|
|
std::string strFileRes = strFile + ".rewrite"; |
|
|
|
std::string strFileRes = strFile + ".rewrite"; |
|
|
|
{ // surround usage of db with extra {}
|
|
|
|
{ // surround usage of db with extra {}
|
|
|
|
CDB db(dbw, "r"); |
|
|
|
CDB db(dbw, "r"); |
|
|
|
Db* pdbCopy = new Db(bitdb.dbenv, 0); |
|
|
|
Db* pdbCopy = new Db(env->dbenv, 0); |
|
|
|
|
|
|
|
|
|
|
|
int ret = pdbCopy->open(NULL, // Txn pointer
|
|
|
|
int ret = pdbCopy->open(NULL, // Txn pointer
|
|
|
|
strFileRes.c_str(), // Filename
|
|
|
|
strFileRes.c_str(), // Filename
|
|
|
@ -537,17 +539,17 @@ bool CDB::Rewrite(CWalletDBWrapper& dbw, const char* pszSkip) |
|
|
|
} |
|
|
|
} |
|
|
|
if (fSuccess) { |
|
|
|
if (fSuccess) { |
|
|
|
db.Close(); |
|
|
|
db.Close(); |
|
|
|
bitdb.CloseDb(strFile); |
|
|
|
env->CloseDb(strFile); |
|
|
|
if (pdbCopy->close(0)) |
|
|
|
if (pdbCopy->close(0)) |
|
|
|
fSuccess = false; |
|
|
|
fSuccess = false; |
|
|
|
delete pdbCopy; |
|
|
|
delete pdbCopy; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (fSuccess) { |
|
|
|
if (fSuccess) { |
|
|
|
Db dbA(bitdb.dbenv, 0); |
|
|
|
Db dbA(env->dbenv, 0); |
|
|
|
if (dbA.remove(strFile.c_str(), NULL, 0)) |
|
|
|
if (dbA.remove(strFile.c_str(), NULL, 0)) |
|
|
|
fSuccess = false; |
|
|
|
fSuccess = false; |
|
|
|
Db dbB(bitdb.dbenv, 0); |
|
|
|
Db dbB(env->dbenv, 0); |
|
|
|
if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) |
|
|
|
if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) |
|
|
|
fSuccess = false; |
|
|
|
fSuccess = false; |
|
|
|
} |
|
|
|
} |
|
|
@ -608,14 +610,15 @@ bool CDB::PeriodicFlush(CWalletDBWrapper& dbw) |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
bool ret = false; |
|
|
|
bool ret = false; |
|
|
|
|
|
|
|
CDBEnv *env = dbw.env; |
|
|
|
const std::string& strFile = dbw.strFile; |
|
|
|
const std::string& strFile = dbw.strFile; |
|
|
|
TRY_LOCK(bitdb.cs_db,lockDb); |
|
|
|
TRY_LOCK(bitdb.cs_db,lockDb); |
|
|
|
if (lockDb) |
|
|
|
if (lockDb) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// Don't do this if any databases are in use
|
|
|
|
// Don't do this if any databases are in use
|
|
|
|
int nRefCount = 0; |
|
|
|
int nRefCount = 0; |
|
|
|
std::map<std::string, int>::iterator mit = bitdb.mapFileUseCount.begin(); |
|
|
|
std::map<std::string, int>::iterator mit = env->mapFileUseCount.begin(); |
|
|
|
while (mit != bitdb.mapFileUseCount.end()) |
|
|
|
while (mit != env->mapFileUseCount.end()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
nRefCount += (*mit).second; |
|
|
|
nRefCount += (*mit).second; |
|
|
|
mit++; |
|
|
|
mit++; |
|
|
@ -624,17 +627,17 @@ bool CDB::PeriodicFlush(CWalletDBWrapper& dbw) |
|
|
|
if (nRefCount == 0) |
|
|
|
if (nRefCount == 0) |
|
|
|
{ |
|
|
|
{ |
|
|
|
boost::this_thread::interruption_point(); |
|
|
|
boost::this_thread::interruption_point(); |
|
|
|
std::map<std::string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile); |
|
|
|
std::map<std::string, int>::iterator mi = env->mapFileUseCount.find(strFile); |
|
|
|
if (mi != bitdb.mapFileUseCount.end()) |
|
|
|
if (mi != env->mapFileUseCount.end()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
LogPrint(BCLog::DB, "Flushing %s\n", strFile); |
|
|
|
LogPrint(BCLog::DB, "Flushing %s\n", strFile); |
|
|
|
int64_t nStart = GetTimeMillis(); |
|
|
|
int64_t nStart = GetTimeMillis(); |
|
|
|
|
|
|
|
|
|
|
|
// Flush wallet file so it's self contained
|
|
|
|
// Flush wallet file so it's self contained
|
|
|
|
bitdb.CloseDb(strFile); |
|
|
|
env->CloseDb(strFile); |
|
|
|
bitdb.CheckpointLSN(strFile); |
|
|
|
env->CheckpointLSN(strFile); |
|
|
|
|
|
|
|
|
|
|
|
bitdb.mapFileUseCount.erase(mi++); |
|
|
|
env->mapFileUseCount.erase(mi++); |
|
|
|
LogPrint(BCLog::DB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart); |
|
|
|
LogPrint(BCLog::DB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart); |
|
|
|
ret = true; |
|
|
|
ret = true; |
|
|
|
} |
|
|
|
} |
|
|
@ -657,13 +660,13 @@ bool CWalletDBWrapper::Backup(const std::string& strDest) |
|
|
|
while (true) |
|
|
|
while (true) |
|
|
|
{ |
|
|
|
{ |
|
|
|
{ |
|
|
|
{ |
|
|
|
LOCK(bitdb.cs_db); |
|
|
|
LOCK(env->cs_db); |
|
|
|
if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0) |
|
|
|
if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// Flush log data to the dat file
|
|
|
|
// Flush log data to the dat file
|
|
|
|
bitdb.CloseDb(strFile); |
|
|
|
env->CloseDb(strFile); |
|
|
|
bitdb.CheckpointLSN(strFile); |
|
|
|
env->CheckpointLSN(strFile); |
|
|
|
bitdb.mapFileUseCount.erase(strFile); |
|
|
|
env->mapFileUseCount.erase(strFile); |
|
|
|
|
|
|
|
|
|
|
|
// Copy wallet file
|
|
|
|
// Copy wallet file
|
|
|
|
fs::path pathSrc = GetDataDir() / strFile; |
|
|
|
fs::path pathSrc = GetDataDir() / strFile; |
|
|
@ -685,3 +688,10 @@ bool CWalletDBWrapper::Backup(const std::string& strDest) |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CWalletDBWrapper::Flush(bool shutdown) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!IsDummy()) { |
|
|
|
|
|
|
|
env->Flush(shutdown); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|