Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/bdb.cpp
Show All 27 Lines | void CheckUniqueFileid(const BerkeleyEnvironment &env, | ||||
const std::string &filename, Db &db, | const std::string &filename, Db &db, | ||||
WalletDatabaseFileId &fileid) { | WalletDatabaseFileId &fileid) { | ||||
if (env.IsMock()) { | if (env.IsMock()) { | ||||
return; | return; | ||||
} | } | ||||
int ret = db.get_mpf()->get_fileid(fileid.value); | int ret = db.get_mpf()->get_fileid(fileid.value); | ||||
if (ret != 0) { | if (ret != 0) { | ||||
throw std::runtime_error(strprintf( | throw std::runtime_error( | ||||
"BerkeleyBatch: Can't open database %s (get_fileid failed with %d)", | strprintf("BerkeleyDatabase: Can't open database %s (get_fileid " | ||||
"failed with %d)", | |||||
filename, ret)); | filename, ret)); | ||||
} | } | ||||
for (const auto &item : env.m_fileids) { | for (const auto &item : env.m_fileids) { | ||||
if (fileid == item.second && &fileid != &item.second) { | if (fileid == item.second && &fileid != &item.second) { | ||||
throw std::runtime_error(strprintf( | throw std::runtime_error( | ||||
"BerkeleyBatch: Can't open database %s (duplicates fileid %s " | strprintf("BerkeleyDatabase: Can't open database %s " | ||||
"(duplicates fileid %s " | |||||
"from %s)", | "from %s)", | ||||
filename, HexStr(item.second.value), item.first)); | filename, HexStr(item.second.value), item.first)); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
RecursiveMutex cs_db; | RecursiveMutex cs_db; | ||||
//! Map from directory name to db environment. | //! Map from directory name to db environment. | ||||
std::map<std::string, std::weak_ptr<BerkeleyEnvironment>> | std::map<std::string, std::weak_ptr<BerkeleyEnvironment>> | ||||
▲ Show 20 Lines • Show All 271 Lines • ▼ Show 20 Lines | if (fMockDb) { | ||||
return; | return; | ||||
} | } | ||||
dbenv->lsn_reset(strFile.c_str(), 0); | dbenv->lsn_reset(strFile.c_str(), 0); | ||||
} | } | ||||
BerkeleyDatabase::~BerkeleyDatabase() { | BerkeleyDatabase::~BerkeleyDatabase() { | ||||
if (env) { | if (env) { | ||||
LOCK(cs_db); | LOCK(cs_db); | ||||
env->CloseDb(strFile); | |||||
assert(!m_db); | |||||
size_t erased = env->m_databases.erase(strFile); | size_t erased = env->m_databases.erase(strFile); | ||||
assert(erased == 1); | assert(erased == 1); | ||||
env->m_fileids.erase(strFile); | env->m_fileids.erase(strFile); | ||||
} | } | ||||
} | } | ||||
BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase &database, const char *pszMode, | BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase &database, const char *pszMode, | ||||
bool fFlushOnCloseIn) | bool fFlushOnCloseIn) | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | if (fCreate) { | ||||
nFlags, // Flags | nFlags, // Flags | ||||
0); | 0); | ||||
if (ret != 0) { | if (ret != 0) { | ||||
throw std::runtime_error(strprintf( | throw std::runtime_error(strprintf( | ||||
"BerkeleyDatabase: Error %d, can't open database %s", ret, | "BerkeleyDatabase: Error %d, can't open database %s", ret, | ||||
strFile)); | strFile)); | ||||
} | } | ||||
m_file_path = (env->Directory() / strFile).string(); | |||||
// Call CheckUniqueFileid on the containing BDB environment to | // Call CheckUniqueFileid on the containing BDB environment to | ||||
// avoid BDB data consistency bugs that happen when different data | // avoid BDB data consistency bugs that happen when different data | ||||
// files in the same environment have the same fileid. | // files in the same environment have the same fileid. | ||||
// | CheckUniqueFileid(*env, strFile, *pdb_temp, | ||||
// Also call CheckUniqueFileid on all the other g_dbenvs to prevent | this->env->m_fileids[strFile]); | ||||
// bitcoin from opening the same data file through another | |||||
// environment when the file is referenced through equivalent but | |||||
// not obviously identical symlinked or hard linked or bind mounted | |||||
// paths. In the future a more relaxed check for equal inode and | |||||
// device ids could be done instead, which would allow opening | |||||
// different backup copies of a wallet at the same time. Maybe even | |||||
// more ideally, an exclusive lock for accessing the database could | |||||
// be implemented, so no equality checks are needed at all. (Newer | |||||
// versions of BDB have an set_lk_exclusive method for this | |||||
// purpose, but the older version we use does not.) | |||||
for (const auto &dbenv : g_dbenvs) { | |||||
CheckUniqueFileid(*dbenv.second.lock().get(), strFile, | |||||
*pdb_temp, this->env->m_fileids[strFile]); | |||||
} | |||||
m_db.reset(pdb_temp.release()); | m_db.reset(pdb_temp.release()); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
void BerkeleyBatch::Flush() { | void BerkeleyBatch::Flush() { | ||||
if (activeTxn) { | if (activeTxn) { | ||||
▲ Show 20 Lines • Show All 502 Lines • Show Last 20 Lines |