Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/db.cpp
Show All 15 Lines | |||||
#include <boost/version.hpp> | #include <boost/version.hpp> | ||||
#include <cstdint> | #include <cstdint> | ||||
#ifndef WIN32 | #ifndef WIN32 | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#endif | #endif | ||||
namespace { | |||||
//! Make sure database has a unique fileid within the environment. If it | |||||
//! doesn't, throw an error. BDB caches do not work properly when more than one | |||||
//! open database has the same fileid (values written to one database may show | |||||
//! up in reads to other databases). | |||||
//! | |||||
//! BerkeleyDB generates unique fileids by default | |||||
//! (https://docs.oracle.com/cd/E17275_01/html/programmer_reference/program_copy.html), | |||||
//! so bitcoin should never create different databases with the same fileid, but | |||||
//! this error can be triggered if users manually copy database files. | |||||
void CheckUniqueFileid(const CDBEnv &env, const std::string &filename, Db &db) { | |||||
if (env.IsMock()) { | |||||
return; | |||||
} | |||||
u_int8_t fileid[DB_FILE_ID_LEN]; | |||||
int ret = db.get_mpf()->get_fileid(fileid); | |||||
if (ret != 0) { | |||||
throw std::runtime_error( | |||||
strprintf("CDB: Can't open database %s (get_fileid failed with %d)", | |||||
filename, ret)); | |||||
} | |||||
for (const auto &item : env.mapDb) { | |||||
u_int8_t item_fileid[DB_FILE_ID_LEN]; | |||||
if (item.second && | |||||
item.second->get_mpf()->get_fileid(item_fileid) == 0 && | |||||
memcmp(fileid, item_fileid, sizeof(fileid)) == 0) { | |||||
const char *item_filename = nullptr; | |||||
item.second->get_dbname(&item_filename, nullptr); | |||||
throw std::runtime_error(strprintf( | |||||
"CDB: Can't open database %s (duplicates fileid %s from %s)", | |||||
filename, | |||||
HexStr(std::begin(item_fileid), std::end(item_fileid)), | |||||
item_filename ? item_filename : "(unknown database)")); | |||||
} | |||||
} | |||||
} | |||||
} // namespace | |||||
// | // | ||||
// CDB | // CDB | ||||
// | // | ||||
CDBEnv bitdb; | CDBEnv bitdb; | ||||
void CDBEnv::EnvShutdown() { | void CDBEnv::EnvShutdown() { | ||||
if (!fDbEnvInit) { | if (!fDbEnvInit) { | ||||
▲ Show 20 Lines • Show All 386 Lines • ▼ Show 20 Lines | if (fCreate) { | ||||
DB_BTREE, // Database type | DB_BTREE, // Database type | ||||
nFlags, // Flags | nFlags, // Flags | ||||
0); | 0); | ||||
if (ret != 0) { | if (ret != 0) { | ||||
throw std::runtime_error(strprintf( | throw std::runtime_error(strprintf( | ||||
"CDB: Error %d, can't open database %s", ret, strFilename)); | "CDB: Error %d, can't open database %s", ret, strFilename)); | ||||
} | } | ||||
CheckUniqueFileid(*env, strFilename, *pdb_temp); | |||||
pdb = pdb_temp.release(); | pdb = pdb_temp.release(); | ||||
env->mapDb[strFilename] = pdb; | env->mapDb[strFilename] = 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); | ||||
▲ Show 20 Lines • Show All 305 Lines • Show Last 20 Lines |