20
20
#include < boost/thread.hpp>
21
21
22
22
namespace {
23
+
23
24
// ! Make sure database has a unique fileid within the environment. If it
24
25
// ! doesn't, throw an error. BDB caches do not work properly when more than one
25
26
// ! open database has the same fileid (values written to one database may show
@@ -29,25 +30,19 @@ namespace {
29
30
// ! (https://docs.oracle.com/cd/E17275_01/html/programmer_reference/program_copy.html),
30
31
// ! so bitcoin should never create different databases with the same fileid, but
31
32
// ! this error can be triggered if users manually copy database files.
32
- void CheckUniqueFileid (const BerkeleyEnvironment& env, const std::string& filename, Db& db)
33
+ void CheckUniqueFileid (const BerkeleyEnvironment& env, const std::string& filename, Db& db, WalletDatabaseFileId& fileid )
33
34
{
34
35
if (env.IsMock ()) return ;
35
36
36
- u_int8_t fileid[DB_FILE_ID_LEN];
37
- int ret = db.get_mpf ()->get_fileid (fileid);
37
+ int ret = db.get_mpf ()->get_fileid (fileid.value );
38
38
if (ret != 0 ) {
39
39
throw std::runtime_error (strprintf (" BerkeleyBatch: Can't open database %s (get_fileid failed with %d)" , filename, ret));
40
40
}
41
41
42
- for (const auto & item : env.mapDb ) {
43
- u_int8_t item_fileid[DB_FILE_ID_LEN];
44
- if (item.second && item.second ->get_mpf ()->get_fileid (item_fileid) == 0 &&
45
- memcmp (fileid, item_fileid, sizeof (fileid)) == 0 ) {
46
- const char * item_filename = nullptr ;
47
- item.second ->get_dbname (&item_filename, nullptr );
42
+ for (const auto & item : env.m_fileids ) {
43
+ if (fileid == item.second && &fileid != &item.second ) {
48
44
throw std::runtime_error (strprintf (" BerkeleyBatch: Can't open database %s (duplicates fileid %s from %s)" , filename,
49
- HexStr (std::begin (item_fileid), std::end (item_fileid)),
50
- item_filename ? item_filename : " (unknown database)" ));
45
+ HexStr (std::begin (item.second .value ), std::end (item.second .value )), item.first ));
51
46
}
52
47
}
53
48
}
@@ -56,6 +51,11 @@ CCriticalSection cs_db;
56
51
std::map<std::string, BerkeleyEnvironment> g_dbenvs GUARDED_BY (cs_db); // !< Map from directory name to open db environment.
57
52
} // namespace
58
53
54
+ bool WalletDatabaseFileId::operator ==(const WalletDatabaseFileId& rhs) const
55
+ {
56
+ return memcmp (value, &rhs.value , sizeof (value)) == 0 ;
57
+ }
58
+
59
59
BerkeleyEnvironment* GetWalletEnv (const fs::path& wallet_path, std::string& database_filename)
60
60
{
61
61
fs::path env_directory;
@@ -504,7 +504,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo
504
504
// versions of BDB have an set_lk_exclusive method for this
505
505
// purpose, but the older version we use does not.)
506
506
for (const auto & env : g_dbenvs) {
507
- CheckUniqueFileid (env.second , strFilename, *pdb_temp);
507
+ CheckUniqueFileid (env.second , strFilename, *pdb_temp, this -> env -> m_fileids [strFilename] );
508
508
}
509
509
510
510
pdb = pdb_temp.release ();
@@ -826,6 +826,13 @@ void BerkeleyDatabase::Flush(bool shutdown)
826
826
LOCK (cs_db);
827
827
g_dbenvs.erase (env->Directory ().string ());
828
828
env = nullptr ;
829
+ } else {
830
+ // TODO: To avoid g_dbenvs.erase erasing the environment prematurely after the
831
+ // first database shutdown when multiple databases are open in the same
832
+ // environment, should replace raw database `env` pointers with shared or weak
833
+ // pointers, or else separate the database and environment shutdowns so
834
+ // environments can be shut down after databases.
835
+ env->m_fileids .erase (strFile);
829
836
}
830
837
}
831
838
}
0 commit comments