Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/db.cpp
Show First 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | |||||
//!< Map from directory name to open db environment. | //!< Map from directory name to open db environment. | ||||
std::map<std::string, BerkeleyEnvironment> g_dbenvs; | std::map<std::string, BerkeleyEnvironment> g_dbenvs; | ||||
} // namespace | } // namespace | ||||
bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId &rhs) const { | bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId &rhs) const { | ||||
return memcmp(value, &rhs.value, sizeof(value)) == 0; | return memcmp(value, &rhs.value, sizeof(value)) == 0; | ||||
} | } | ||||
BerkeleyEnvironment *GetWalletEnv(const fs::path &wallet_path, | static void SplitWalletPath(const fs::path &wallet_path, | ||||
fs::path &env_directory, | |||||
std::string &database_filename) { | std::string &database_filename) { | ||||
fs::path env_directory; | |||||
if (fs::is_regular_file(wallet_path)) { | if (fs::is_regular_file(wallet_path)) { | ||||
// Special case for backwards compatibility: if wallet path points to an | // Special case for backwards compatibility: if wallet path points to an | ||||
// existing file, treat it as the path to a BDB data file in a parent | // existing file, treat it as the path to a BDB data file in a parent | ||||
// directory that also contains BDB log files. | // directory that also contains BDB log files. | ||||
env_directory = wallet_path.parent_path(); | env_directory = wallet_path.parent_path(); | ||||
database_filename = wallet_path.filename().string(); | database_filename = wallet_path.filename().string(); | ||||
} else { | } else { | ||||
// Normal case: Interpret wallet path as a directory path containing | // Normal case: Interpret wallet path as a directory path containing | ||||
// data and log files. | // data and log files. | ||||
env_directory = wallet_path; | env_directory = wallet_path; | ||||
database_filename = "wallet.dat"; | database_filename = "wallet.dat"; | ||||
} | } | ||||
} | |||||
bool IsWalletLoaded(const fs::path &wallet_path) { | |||||
fs::path env_directory; | |||||
std::string database_filename; | |||||
SplitWalletPath(wallet_path, env_directory, database_filename); | |||||
LOCK(cs_db); | |||||
auto env = g_dbenvs.find(env_directory.string()); | |||||
if (env == g_dbenvs.end()) { | |||||
return false; | |||||
} | |||||
return env->second.IsDatabaseLoaded(database_filename); | |||||
} | |||||
BerkeleyEnvironment *GetWalletEnv(const fs::path &wallet_path, | |||||
std::string &database_filename) { | |||||
fs::path env_directory; | |||||
SplitWalletPath(wallet_path, env_directory, database_filename); | |||||
LOCK(cs_db); | LOCK(cs_db); | ||||
// Note: An ununsed temporary BerkeleyEnvironment object may be created | // Note: An ununsed temporary BerkeleyEnvironment object may be created | ||||
// inside the emplace function if the key already exists. This is a little | // inside the emplace function if the key already exists. This is a little | ||||
// inefficient, but not a big concern since the map will be changed in the | // inefficient, but not a big concern since the map will be changed in the | ||||
// future to hold pointers instead of objects, anyway. | // future to hold pointers instead of objects, anyway. | ||||
return &g_dbenvs | return &g_dbenvs | ||||
.emplace(std::piecewise_construct, | .emplace(std::piecewise_construct, | ||||
std::forward_as_tuple(env_directory.string()), | std::forward_as_tuple(env_directory.string()), | ||||
std::forward_as_tuple(env_directory)) | std::forward_as_tuple(env_directory)) | ||||
.first->second; | .first->second; | ||||
} | } | ||||
// | // | ||||
// BerkeleyBatch | // BerkeleyBatch | ||||
// | // | ||||
void BerkeleyEnvironment::Close() { | void BerkeleyEnvironment::Close() { | ||||
if (!fDbEnvInit) { | if (!fDbEnvInit) { | ||||
return; | return; | ||||
} | } | ||||
fDbEnvInit = false; | fDbEnvInit = false; | ||||
for (auto &db : mapDb) { | for (auto &db : m_databases) { | ||||
auto count = mapFileUseCount.find(db.first); | auto count = mapFileUseCount.find(db.first); | ||||
assert(count == mapFileUseCount.end() || count->second == 0); | assert(count == mapFileUseCount.end() || count->second == 0); | ||||
if (db.second) { | BerkeleyDatabase &database = db.second.get(); | ||||
db.second->close(0); | if (database.m_db) { | ||||
delete db.second; | database.m_db->close(0); | ||||
db.second = nullptr; | database.m_db.reset(); | ||||
} | } | ||||
} | } | ||||
int ret = dbenv->close(0); | int ret = dbenv->close(0); | ||||
if (ret != 0) { | if (ret != 0) { | ||||
LogPrintf("BerkeleyEnvironment::Close: Error %d closing database " | LogPrintf("BerkeleyEnvironment::Close: Error %d closing database " | ||||
"environment: %s\n", | "environment: %s\n", | ||||
ret, DbEnv::strerror(ret)); | ret, DbEnv::strerror(ret)); | ||||
▲ Show 20 Lines • Show All 379 Lines • ▼ Show 20 Lines | BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase &database, const char *pszMode, | ||||
{ | { | ||||
LOCK(cs_db); | LOCK(cs_db); | ||||
if (!env->Open(false /* retry */)) { | if (!env->Open(false /* retry */)) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"BerkeleyBatch: Failed to open database environment."); | "BerkeleyBatch: Failed to open database environment."); | ||||
} | } | ||||
pdb = env->mapDb[strFilename]; | pdb = database.m_db.get(); | ||||
if (pdb == nullptr) { | if (pdb == nullptr) { | ||||
int ret; | int ret; | ||||
std::unique_ptr<Db> pdb_temp = | std::unique_ptr<Db> pdb_temp = | ||||
std::make_unique<Db>(env->dbenv.get(), 0); | std::make_unique<Db>(env->dbenv.get(), 0); | ||||
bool fMockDb = env->IsMock(); | bool fMockDb = env->IsMock(); | ||||
if (fMockDb) { | if (fMockDb) { | ||||
DbMpoolFile *mpf = pdb_temp->get_mpf(); | DbMpoolFile *mpf = pdb_temp->get_mpf(); | ||||
Show All 36 Lines | if (fCreate) { | ||||
// versions of BDB have an set_lk_exclusive method for this | // versions of BDB have an set_lk_exclusive method for this | ||||
// purpose, but the older version we use does not.) | // purpose, but the older version we use does not.) | ||||
for (const auto &dbenv : g_dbenvs) { | for (const auto &dbenv : g_dbenvs) { | ||||
CheckUniqueFileid(dbenv.second, strFilename, *pdb_temp, | CheckUniqueFileid(dbenv.second, strFilename, *pdb_temp, | ||||
this->env->m_fileids[strFilename]); | this->env->m_fileids[strFilename]); | ||||
} | } | ||||
pdb = pdb_temp.release(); | pdb = pdb_temp.release(); | ||||
env->mapDb[strFilename] = pdb; | database.m_db.reset(pdb); | ||||
if (fCreate && !Exists(std::string("version"))) { | if (fCreate && !Exists(std::string("version"))) { | ||||
bool fTmp = fReadOnly; | bool fTmp = fReadOnly; | ||||
fReadOnly = false; | fReadOnly = false; | ||||
WriteVersion(CLIENT_VERSION); | WriteVersion(CLIENT_VERSION); | ||||
fReadOnly = fTmp; | fReadOnly = fTmp; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | if (fFlushOnClose) { | ||||
LOCK(cs_db); | LOCK(cs_db); | ||||
--env->mapFileUseCount[strFile]; | --env->mapFileUseCount[strFile]; | ||||
} | } | ||||
env->m_db_in_use.notify_all(); | env->m_db_in_use.notify_all(); | ||||
} | } | ||||
void BerkeleyEnvironment::CloseDb(const std::string &strFile) { | void BerkeleyEnvironment::CloseDb(const std::string &strFile) { | ||||
LOCK(cs_db); | LOCK(cs_db); | ||||
if (mapDb[strFile] != nullptr) { | auto it = m_databases.find(strFile); | ||||
assert(it != m_databases.end()); | |||||
BerkeleyDatabase &database = it->second.get(); | |||||
if (database.m_db) { | |||||
// Close the database handle | // Close the database handle | ||||
Db *pdb = mapDb[strFile]; | database.m_db->close(0); | ||||
pdb->close(0); | database.m_db.reset(); | ||||
delete pdb; | |||||
mapDb[strFile] = nullptr; | |||||
} | } | ||||
} | } | ||||
void BerkeleyEnvironment::ReloadDbEnv() { | void BerkeleyEnvironment::ReloadDbEnv() { | ||||
// Make sure that no Db's are in use | // Make sure that no Db's are in use | ||||
AssertLockNotHeld(cs_db); | AssertLockNotHeld(cs_db); | ||||
std::unique_lock<CCriticalSection> lock(cs_db); | std::unique_lock<CCriticalSection> lock(cs_db); | ||||
m_db_in_use.wait(lock, [this]() { | m_db_in_use.wait(lock, [this]() { | ||||
for (auto &count : mapFileUseCount) { | for (auto &count : mapFileUseCount) { | ||||
if (count.second > 0) { | if (count.second > 0) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
}); | }); | ||||
std::vector<std::string> filenames; | std::vector<std::string> filenames; | ||||
for (auto it : mapDb) { | for (auto it : m_databases) { | ||||
filenames.push_back(it.first); | filenames.push_back(it.first); | ||||
} | } | ||||
// Close the individual Db's | // Close the individual Db's | ||||
for (const std::string &filename : filenames) { | for (const std::string &filename : filenames) { | ||||
CloseDb(filename); | CloseDb(filename); | ||||
} | } | ||||
// Reset the environment | // Reset the environment | ||||
// This will flush and close the environment | // This will flush and close the environment | ||||
▲ Show 20 Lines • Show All 277 Lines • Show Last 20 Lines |