walletdb: track database file use as m_refcount within BerkeleyDatabase

Instead of having BerkeleyEnvironment track the file use count, make
BerkeleyDatabase do it itself.
This commit is contained in:
Andrew Chow 2020-05-13 14:09:26 -04:00
parent 65fb8807ac
commit 4fe4b3bf1b
2 changed files with 28 additions and 29 deletions

View File

@ -97,9 +97,8 @@ void BerkeleyEnvironment::Close()
fDbEnvInit = false; fDbEnvInit = false;
for (auto& db : m_databases) { for (auto& db : m_databases) {
auto count = mapFileUseCount.find(db.first);
assert(count == mapFileUseCount.end() || count->second == 0);
BerkeleyDatabase& database = db.second.get(); BerkeleyDatabase& database = db.second.get();
assert(database.m_refcount <= 0);
if (database.m_db) { if (database.m_db) {
database.m_db->close(0); database.m_db->close(0);
database.m_db.reset(); database.m_db.reset();
@ -285,8 +284,7 @@ bool BerkeleyDatabase::Verify(bilingual_str& errorStr)
if (fs::exists(file_path)) if (fs::exists(file_path))
{ {
LOCK(cs_db); assert(m_refcount == 0);
assert(env->mapFileUseCount.count(strFile) == 0);
Db db(env->dbenv.get(), 0); Db db(env->dbenv.get(), 0);
int result = db.verify(strFile.c_str(), nullptr, nullptr, 0); int result = db.verify(strFile.c_str(), nullptr, nullptr, 0);
@ -459,8 +457,8 @@ void BerkeleyEnvironment::ReloadDbEnv()
AssertLockNotHeld(cs_db); AssertLockNotHeld(cs_db);
std::unique_lock<RecursiveMutex> lock(cs_db); std::unique_lock<RecursiveMutex> lock(cs_db);
m_db_in_use.wait(lock, [this](){ m_db_in_use.wait(lock, [this](){
for (auto& count : mapFileUseCount) { for (auto& db : m_databases) {
if (count.second > 0) return false; if (db.second.get().m_refcount > 0) return false;
} }
return true; return true;
}); });
@ -488,11 +486,11 @@ bool BerkeleyDatabase::Rewrite(const char* pszSkip)
while (true) { while (true) {
{ {
LOCK(cs_db); LOCK(cs_db);
if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0) { if (m_refcount <= 0) {
// Flush log data to the dat file // Flush log data to the dat file
env->CloseDb(strFile); env->CloseDb(strFile);
env->CheckpointLSN(strFile); env->CheckpointLSN(strFile);
env->mapFileUseCount.erase(strFile); m_refcount = -1;
bool fSuccess = true; bool fSuccess = true;
LogPrintf("BerkeleyBatch::Rewrite: Rewriting %s...\n", strFile); LogPrintf("BerkeleyBatch::Rewrite: Rewriting %s...\n", strFile);
@ -576,10 +574,11 @@ void BerkeleyEnvironment::Flush(bool fShutdown)
return; return;
{ {
LOCK(cs_db); LOCK(cs_db);
std::map<std::string, int>::iterator mi = mapFileUseCount.begin(); bool no_dbs_accessed = true;
while (mi != mapFileUseCount.end()) { for (auto& db_it : m_databases) {
std::string strFile = (*mi).first; std::string strFile = db_it.first;
int nRefCount = (*mi).second; int nRefCount = db_it.second.get().m_refcount;
if (nRefCount < 0) continue;
LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount); LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount);
if (nRefCount == 0) { if (nRefCount == 0) {
// Move log data to the dat file // Move log data to the dat file
@ -590,14 +589,15 @@ void BerkeleyEnvironment::Flush(bool fShutdown)
if (!fMockDb) if (!fMockDb)
dbenv->lsn_reset(strFile.c_str(), 0); dbenv->lsn_reset(strFile.c_str(), 0);
LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s closed\n", strFile); LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s closed\n", strFile);
mapFileUseCount.erase(mi++); nRefCount = -1;
} else } else {
mi++; no_dbs_accessed = false;
}
} }
LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart); LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart);
if (fShutdown) { if (fShutdown) {
char** listp; char** listp;
if (mapFileUseCount.empty()) { if (no_dbs_accessed) {
dbenv->log_archive(&listp, DB_ARCH_REMOVE); dbenv->log_archive(&listp, DB_ARCH_REMOVE);
Close(); Close();
if (!fMockDb) { if (!fMockDb) {
@ -618,13 +618,12 @@ bool BerkeleyDatabase::PeriodicFlush()
if (!lockDb) return false; if (!lockDb) return false;
// Don't flush if any databases are in use // Don't flush if any databases are in use
for (const auto& use_count : env->mapFileUseCount) { for (auto& it : env->m_databases) {
if (use_count.second > 0) return false; if (it.second.get().m_refcount > 0) return false;
} }
// Don't flush if there haven't been any batch writes for this database. // Don't flush if there haven't been any batch writes for this database.
auto it = env->mapFileUseCount.find(strFile); if (m_refcount < 0) return false;
if (it == env->mapFileUseCount.end()) return false;
LogPrint(BCLog::WALLETDB, "Flushing %s\n", strFile); LogPrint(BCLog::WALLETDB, "Flushing %s\n", strFile);
int64_t nStart = GetTimeMillis(); int64_t nStart = GetTimeMillis();
@ -632,7 +631,7 @@ bool BerkeleyDatabase::PeriodicFlush()
// Flush wallet file so it's self contained // Flush wallet file so it's self contained
env->CloseDb(strFile); env->CloseDb(strFile);
env->CheckpointLSN(strFile); env->CheckpointLSN(strFile);
env->mapFileUseCount.erase(it); m_refcount = -1;
LogPrint(BCLog::WALLETDB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart); LogPrint(BCLog::WALLETDB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
@ -648,12 +647,11 @@ bool BerkeleyDatabase::Backup(const std::string& strDest) const
{ {
{ {
LOCK(cs_db); LOCK(cs_db);
if (!env->mapFileUseCount.count(strFile) || env->mapFileUseCount[strFile] == 0) if (m_refcount <= 0)
{ {
// Flush log data to the dat file // Flush log data to the dat file
env->CloseDb(strFile); env->CloseDb(strFile);
env->CheckpointLSN(strFile); env->CheckpointLSN(strFile);
env->mapFileUseCount.erase(strFile);
// Copy wallet file // Copy wallet file
fs::path pathSrc = env->Directory() / strFile; fs::path pathSrc = env->Directory() / strFile;
@ -835,15 +833,17 @@ bool BerkeleyBatch::HasKey(CDataStream&& key)
void BerkeleyDatabase::AddRef() void BerkeleyDatabase::AddRef()
{ {
LOCK(cs_db); LOCK(cs_db);
++env->mapFileUseCount[strFile]; if (m_refcount < 0) {
m_refcount = 1;
} else {
m_refcount++;
}
} }
void BerkeleyDatabase::RemoveRef() void BerkeleyDatabase::RemoveRef()
{ {
{ LOCK(cs_db);
LOCK(cs_db); m_refcount--;
--env->mapFileUseCount[strFile];
}
env->m_db_in_use.notify_all(); env->m_db_in_use.notify_all();
} }

View File

@ -52,7 +52,6 @@ private:
public: public:
std::unique_ptr<DbEnv> dbenv; std::unique_ptr<DbEnv> dbenv;
std::map<std::string, int> mapFileUseCount;
std::map<std::string, std::reference_wrapper<BerkeleyDatabase>> m_databases; std::map<std::string, std::reference_wrapper<BerkeleyDatabase>> m_databases;
std::unordered_map<std::string, WalletDatabaseFileId> m_fileids; std::unordered_map<std::string, WalletDatabaseFileId> m_fileids;
std::condition_variable_any m_db_in_use; std::condition_variable_any m_db_in_use;