LCOV - code coverage report
Current view: top level - src/wallet - bdb.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 554 620 89.4 %
Date: 2021-06-29 14:35:33 Functions: 50 50 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 180 246 73.2 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2009-2010 Satoshi Nakamoto
#       2                 :            : // Copyright (c) 2009-2020 The Bitcoin Core developers
#       3                 :            : // Distributed under the MIT software license, see the accompanying
#       4                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       5                 :            : 
#       6                 :            : #include <wallet/bdb.h>
#       7                 :            : #include <wallet/db.h>
#       8                 :            : 
#       9                 :            : #include <util/strencodings.h>
#      10                 :            : #include <util/translation.h>
#      11                 :            : 
#      12                 :            : #include <stdint.h>
#      13                 :            : 
#      14                 :            : #ifndef WIN32
#      15                 :            : #include <sys/stat.h>
#      16                 :            : #endif
#      17                 :            : 
#      18                 :            : namespace {
#      19                 :            : 
#      20                 :            : //! Make sure database has a unique fileid within the environment. If it
#      21                 :            : //! doesn't, throw an error. BDB caches do not work properly when more than one
#      22                 :            : //! open database has the same fileid (values written to one database may show
#      23                 :            : //! up in reads to other databases).
#      24                 :            : //!
#      25                 :            : //! BerkeleyDB generates unique fileids by default
#      26                 :            : //! (https://docs.oracle.com/cd/E17275_01/html/programmer_reference/program_copy.html),
#      27                 :            : //! so bitcoin should never create different databases with the same fileid, but
#      28                 :            : //! this error can be triggered if users manually copy database files.
#      29                 :            : void CheckUniqueFileid(const BerkeleyEnvironment& env, const std::string& filename, Db& db, WalletDatabaseFileId& fileid)
#      30                 :       1152 : {
#      31         [ +  + ]:       1152 :     if (env.IsMock()) return;
#      32                 :            : 
#      33                 :       1141 :     int ret = db.get_mpf()->get_fileid(fileid.value);
#      34         [ -  + ]:       1141 :     if (ret != 0) {
#      35                 :          0 :         throw std::runtime_error(strprintf("BerkeleyDatabase: Can't open database %s (get_fileid failed with %d)", filename, ret));
#      36                 :          0 :     }
#      37                 :            : 
#      38         [ +  + ]:       1177 :     for (const auto& item : env.m_fileids) {
#      39 [ +  + ][ +  + ]:       1177 :         if (fileid == item.second && &fileid != &item.second) {
#      40                 :          6 :             throw std::runtime_error(strprintf("BerkeleyDatabase: Can't open database %s (duplicates fileid %s from %s)", filename,
#      41                 :          6 :                 HexStr(item.second.value), item.first));
#      42                 :          6 :         }
#      43                 :       1177 :     }
#      44                 :       1141 : }
#      45                 :            : 
#      46                 :            : RecursiveMutex cs_db;
#      47                 :            : std::map<std::string, std::weak_ptr<BerkeleyEnvironment>> g_dbenvs GUARDED_BY(cs_db); //!< Map from directory name to db environment.
#      48                 :            : } // namespace
#      49                 :            : 
#      50                 :            : bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const
#      51                 :       1177 : {
#      52                 :       1177 :     return memcmp(value, &rhs.value, sizeof(value)) == 0;
#      53                 :       1177 : }
#      54                 :            : 
#      55                 :            : /**
#      56                 :            :  * @param[in] env_directory Path to environment directory
#      57                 :            :  * @return A shared pointer to the BerkeleyEnvironment object for the wallet directory, never empty because ~BerkeleyEnvironment
#      58                 :            :  * erases the weak pointer from the g_dbenvs map.
#      59                 :            :  * @post A new BerkeleyEnvironment weak pointer is inserted into g_dbenvs if the directory path key was not already in the map.
#      60                 :            :  */
#      61                 :            : std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory)
#      62                 :        625 : {
#      63                 :        625 :     LOCK(cs_db);
#      64                 :        625 :     auto inserted = g_dbenvs.emplace(env_directory.string(), std::weak_ptr<BerkeleyEnvironment>());
#      65         [ +  + ]:        625 :     if (inserted.second) {
#      66                 :        597 :         auto env = std::make_shared<BerkeleyEnvironment>(env_directory.string());
#      67                 :        597 :         inserted.first->second = env;
#      68                 :        597 :         return env;
#      69                 :        597 :     }
#      70                 :         28 :     return inserted.first->second.lock();
#      71                 :         28 : }
#      72                 :            : 
#      73                 :            : //
#      74                 :            : // BerkeleyBatch
#      75                 :            : //
#      76                 :            : 
#      77                 :            : void BerkeleyEnvironment::Close()
#      78                 :       1012 : {
#      79         [ +  + ]:       1012 :     if (!fDbEnvInit)
#      80                 :        404 :         return;
#      81                 :            : 
#      82                 :        608 :     fDbEnvInit = false;
#      83                 :            : 
#      84         [ +  + ]:        608 :     for (auto& db : m_databases) {
#      85                 :        410 :         BerkeleyDatabase& database = db.second.get();
#      86                 :        410 :         assert(database.m_refcount <= 0);
#      87         [ -  + ]:        410 :         if (database.m_db) {
#      88                 :          0 :             database.m_db->close(0);
#      89                 :          0 :             database.m_db.reset();
#      90                 :          0 :         }
#      91                 :        410 :     }
#      92                 :            : 
#      93                 :        608 :     FILE* error_file = nullptr;
#      94                 :        608 :     dbenv->get_errfile(&error_file);
#      95                 :            : 
#      96                 :        608 :     int ret = dbenv->close(0);
#      97         [ -  + ]:        608 :     if (ret != 0)
#      98                 :        608 :         LogPrintf("BerkeleyEnvironment::Close: Error %d closing database environment: %s\n", ret, DbEnv::strerror(ret));
#      99         [ +  + ]:        608 :     if (!fMockDb)
#     100                 :        597 :         DbEnv((u_int32_t)0).remove(strPath.c_str(), 0);
#     101                 :            : 
#     102         [ +  + ]:        608 :     if (error_file) fclose(error_file);
#     103                 :            : 
#     104                 :        608 :     UnlockDirectory(strPath, ".walletlock");
#     105                 :        608 : }
#     106                 :            : 
#     107                 :            : void BerkeleyEnvironment::Reset()
#     108                 :        624 : {
#     109                 :        624 :     dbenv.reset(new DbEnv(DB_CXX_NO_EXCEPTIONS));
#     110                 :        624 :     fDbEnvInit = false;
#     111                 :        624 :     fMockDb = false;
#     112                 :        624 : }
#     113                 :            : 
#     114                 :            : BerkeleyEnvironment::BerkeleyEnvironment(const fs::path& dir_path) : strPath(dir_path.string())
#     115                 :        597 : {
#     116                 :        597 :     Reset();
#     117                 :        597 : }
#     118                 :            : 
#     119                 :            : BerkeleyEnvironment::~BerkeleyEnvironment()
#     120                 :        608 : {
#     121                 :        608 :     LOCK(cs_db);
#     122                 :        608 :     g_dbenvs.erase(strPath);
#     123                 :        608 :     Close();
#     124                 :        608 : }
#     125                 :            : 
#     126                 :            : bool BerkeleyEnvironment::Open(bilingual_str& err)
#     127                 :     119171 : {
#     128         [ +  + ]:     119171 :     if (fDbEnvInit) {
#     129                 :     118566 :         return true;
#     130                 :     118566 :     }
#     131                 :            : 
#     132                 :        605 :     fs::path pathIn = strPath;
#     133                 :        605 :     TryCreateDirectories(pathIn);
#     134         [ +  + ]:        605 :     if (!LockDirectory(pathIn, ".walletlock")) {
#     135                 :          6 :         LogPrintf("Cannot obtain a lock on wallet directory %s. Another instance of bitcoin may be using it.\n", strPath);
#     136                 :          6 :         err = strprintf(_("Error initializing wallet database environment %s!"), Directory());
#     137                 :          6 :         return false;
#     138                 :          6 :     }
#     139                 :            : 
#     140                 :        599 :     fs::path pathLogDir = pathIn / "database";
#     141                 :        599 :     TryCreateDirectories(pathLogDir);
#     142                 :        599 :     fs::path pathErrorFile = pathIn / "db.log";
#     143                 :        599 :     LogPrintf("BerkeleyEnvironment::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string());
#     144                 :            : 
#     145                 :        599 :     unsigned int nEnvFlags = 0;
#     146         [ +  + ]:        599 :     if (gArgs.GetBoolArg("-privdb", DEFAULT_WALLET_PRIVDB))
#     147                 :        597 :         nEnvFlags |= DB_PRIVATE;
#     148                 :            : 
#     149                 :        599 :     dbenv->set_lg_dir(pathLogDir.string().c_str());
#     150                 :        599 :     dbenv->set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet
#     151                 :        599 :     dbenv->set_lg_bsize(0x10000);
#     152                 :        599 :     dbenv->set_lg_max(1048576);
#     153                 :        599 :     dbenv->set_lk_max_locks(40000);
#     154                 :        599 :     dbenv->set_lk_max_objects(40000);
#     155                 :        599 :     dbenv->set_errfile(fsbridge::fopen(pathErrorFile, "a")); /// debug
#     156                 :        599 :     dbenv->set_flags(DB_AUTO_COMMIT, 1);
#     157                 :        599 :     dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1);
#     158                 :        599 :     dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1);
#     159                 :        599 :     int ret = dbenv->open(strPath.c_str(),
#     160                 :        599 :                          DB_CREATE |
#     161                 :        599 :                              DB_INIT_LOCK |
#     162                 :        599 :                              DB_INIT_LOG |
#     163                 :        599 :                              DB_INIT_MPOOL |
#     164                 :        599 :                              DB_INIT_TXN |
#     165                 :        599 :                              DB_THREAD |
#     166                 :        599 :                              DB_RECOVER |
#     167                 :        599 :                              nEnvFlags,
#     168                 :        599 :                          S_IRUSR | S_IWUSR);
#     169         [ -  + ]:        599 :     if (ret != 0) {
#     170                 :          0 :         LogPrintf("BerkeleyEnvironment::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
#     171                 :          0 :         int ret2 = dbenv->close(0);
#     172         [ #  # ]:          0 :         if (ret2 != 0) {
#     173                 :          0 :             LogPrintf("BerkeleyEnvironment::Open: Error %d closing failed database environment: %s\n", ret2, DbEnv::strerror(ret2));
#     174                 :          0 :         }
#     175                 :          0 :         Reset();
#     176                 :          0 :         err = strprintf(_("Error initializing wallet database environment %s!"), Directory());
#     177         [ #  # ]:          0 :         if (ret == DB_RUNRECOVERY) {
#     178                 :          0 :             err += Untranslated(" ") + _("This error could occur if this wallet was not shutdown cleanly and was last loaded using a build with a newer version of Berkeley DB. If so, please use the software that last loaded this wallet");
#     179                 :          0 :         }
#     180                 :          0 :         return false;
#     181                 :          0 :     }
#     182                 :            : 
#     183                 :        599 :     fDbEnvInit = true;
#     184                 :        599 :     fMockDb = false;
#     185                 :        599 :     return true;
#     186                 :        599 : }
#     187                 :            : 
#     188                 :            : //! Construct an in-memory mock Berkeley environment for testing
#     189                 :            : BerkeleyEnvironment::BerkeleyEnvironment()
#     190                 :         11 : {
#     191                 :         11 :     Reset();
#     192                 :            : 
#     193         [ +  - ]:         11 :     LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::MakeMock\n");
#     194                 :            : 
#     195                 :         11 :     dbenv->set_cachesize(1, 0, 1);
#     196                 :         11 :     dbenv->set_lg_bsize(10485760 * 4);
#     197                 :         11 :     dbenv->set_lg_max(10485760);
#     198                 :         11 :     dbenv->set_lk_max_locks(10000);
#     199                 :         11 :     dbenv->set_lk_max_objects(10000);
#     200                 :         11 :     dbenv->set_flags(DB_AUTO_COMMIT, 1);
#     201                 :         11 :     dbenv->log_set_config(DB_LOG_IN_MEMORY, 1);
#     202                 :         11 :     int ret = dbenv->open(nullptr,
#     203                 :         11 :                          DB_CREATE |
#     204                 :         11 :                              DB_INIT_LOCK |
#     205                 :         11 :                              DB_INIT_LOG |
#     206                 :         11 :                              DB_INIT_MPOOL |
#     207                 :         11 :                              DB_INIT_TXN |
#     208                 :         11 :                              DB_THREAD |
#     209                 :         11 :                              DB_PRIVATE,
#     210                 :         11 :                          S_IRUSR | S_IWUSR);
#     211         [ -  + ]:         11 :     if (ret > 0) {
#     212                 :          0 :         throw std::runtime_error(strprintf("BerkeleyEnvironment::MakeMock: Error %d opening database environment.", ret));
#     213                 :          0 :     }
#     214                 :            : 
#     215                 :         11 :     fDbEnvInit = true;
#     216                 :         11 :     fMockDb = true;
#     217                 :         11 : }
#     218                 :            : 
#     219                 :            : BerkeleyBatch::SafeDbt::SafeDbt()
#     220                 :     123905 : {
#     221                 :     123905 :     m_dbt.set_flags(DB_DBT_MALLOC);
#     222                 :     123905 : }
#     223                 :            : 
#     224                 :            : BerkeleyBatch::SafeDbt::SafeDbt(void* data, size_t size)
#     225                 :            :     : m_dbt(data, size)
#     226                 :     565539 : {
#     227                 :     565539 : }
#     228                 :            : 
#     229                 :            : BerkeleyBatch::SafeDbt::~SafeDbt()
#     230                 :     689444 : {
#     231         [ +  + ]:     689444 :     if (m_dbt.get_data() != nullptr) {
#     232                 :            :         // Clear memory, e.g. in case it was a private key
#     233                 :     687810 :         memory_cleanse(m_dbt.get_data(), m_dbt.get_size());
#     234                 :            :         // under DB_DBT_MALLOC, data is malloced by the Dbt, but must be
#     235                 :            :         // freed by the caller.
#     236                 :            :         // https://docs.oracle.com/cd/E17275_01/html/api_reference/C/dbt.html
#     237         [ +  + ]:     687810 :         if (m_dbt.get_flags() & DB_DBT_MALLOC) {
#     238                 :     122271 :             free(m_dbt.get_data());
#     239                 :     122271 :         }
#     240                 :     687810 :     }
#     241                 :     689444 : }
#     242                 :            : 
#     243                 :            : const void* BerkeleyBatch::SafeDbt::get_data() const
#     244                 :     244542 : {
#     245                 :     244542 :     return m_dbt.get_data();
#     246                 :     244542 : }
#     247                 :            : 
#     248                 :            : u_int32_t BerkeleyBatch::SafeDbt::get_size() const
#     249                 :     122271 : {
#     250                 :     122271 :     return m_dbt.get_size();
#     251                 :     122271 : }
#     252                 :            : 
#     253                 :            : BerkeleyBatch::SafeDbt::operator Dbt*()
#     254                 :     689444 : {
#     255                 :     689444 :     return &m_dbt;
#     256                 :     689444 : }
#     257                 :            : 
#     258                 :            : bool BerkeleyDatabase::Verify(bilingual_str& errorStr)
#     259                 :        517 : {
#     260                 :        517 :     fs::path walletDir = env->Directory();
#     261                 :        517 :     fs::path file_path = walletDir / strFile;
#     262                 :            : 
#     263                 :        517 :     LogPrintf("Using BerkeleyDB version %s\n", BerkeleyDatabaseVersion());
#     264                 :        517 :     LogPrintf("Using wallet %s\n", file_path.string());
#     265                 :            : 
#     266         [ +  + ]:        517 :     if (!env->Open(errorStr)) {
#     267                 :          6 :         return false;
#     268                 :          6 :     }
#     269                 :            : 
#     270         [ +  + ]:        511 :     if (fs::exists(file_path))
#     271                 :        235 :     {
#     272                 :        235 :         assert(m_refcount == 0);
#     273                 :            : 
#     274                 :        235 :         Db db(env->dbenv.get(), 0);
#     275                 :        235 :         int result = db.verify(strFile.c_str(), nullptr, nullptr, 0);
#     276         [ -  + ]:        235 :         if (result != 0) {
#     277                 :          0 :             errorStr = strprintf(_("%s corrupt. Try using the wallet tool bitcoin-wallet to salvage or restoring a backup."), file_path);
#     278                 :          0 :             return false;
#     279                 :          0 :         }
#     280                 :        511 :     }
#     281                 :            :     // also return true if files does not exists
#     282                 :        511 :     return true;
#     283                 :        511 : }
#     284                 :            : 
#     285                 :            : void BerkeleyEnvironment::CheckpointLSN(const std::string& strFile)
#     286                 :        327 : {
#     287                 :        327 :     dbenv->txn_checkpoint(0, 0, 0);
#     288         [ -  + ]:        327 :     if (fMockDb)
#     289                 :          0 :         return;
#     290                 :        327 :     dbenv->lsn_reset(strFile.c_str(), 0);
#     291                 :        327 : }
#     292                 :            : 
#     293                 :            : BerkeleyDatabase::~BerkeleyDatabase()
#     294                 :        623 : {
#     295         [ +  - ]:        623 :     if (env) {
#     296                 :        623 :         LOCK(cs_db);
#     297                 :        623 :         env->CloseDb(strFile);
#     298                 :        623 :         assert(!m_db);
#     299                 :        623 :         size_t erased = env->m_databases.erase(strFile);
#     300                 :        623 :         assert(erased == 1);
#     301                 :        623 :         env->m_fileids.erase(strFile);
#     302                 :        623 :     }
#     303                 :        623 : }
#     304                 :            : 
#     305                 :            : BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const bool read_only, bool fFlushOnCloseIn) : pdb(nullptr), activeTxn(nullptr), m_cursor(nullptr), m_database(database)
#     306                 :     118637 : {
#     307                 :     118637 :     database.AddRef();
#     308                 :     118637 :     database.Open();
#     309                 :     118637 :     fReadOnly = read_only;
#     310                 :     118637 :     fFlushOnClose = fFlushOnCloseIn;
#     311                 :     118637 :     env = database.env.get();
#     312                 :     118637 :     pdb = database.m_db.get();
#     313                 :     118637 :     strFile = database.strFile;
#     314         [ +  + ]:     118637 :     if (!Exists(std::string("version"))) {
#     315                 :        283 :         bool fTmp = fReadOnly;
#     316                 :        283 :         fReadOnly = false;
#     317                 :        283 :         Write(std::string("version"), CLIENT_VERSION);
#     318                 :        283 :         fReadOnly = fTmp;
#     319                 :        283 :     }
#     320                 :     118637 : }
#     321                 :            : 
#     322                 :            : void BerkeleyDatabase::Open()
#     323                 :     118637 : {
#     324                 :     118637 :     unsigned int nFlags = DB_THREAD | DB_CREATE;
#     325                 :            : 
#     326                 :     118637 :     {
#     327                 :     118637 :         LOCK(cs_db);
#     328                 :     118637 :         bilingual_str open_err;
#     329         [ -  + ]:     118637 :         if (!env->Open(open_err))
#     330                 :          0 :             throw std::runtime_error("BerkeleyDatabase: Failed to open database environment.");
#     331                 :            : 
#     332         [ +  + ]:     118637 :         if (m_db == nullptr) {
#     333                 :       1152 :             int ret;
#     334                 :       1152 :             std::unique_ptr<Db> pdb_temp = std::make_unique<Db>(env->dbenv.get(), 0);
#     335                 :            : 
#     336                 :       1152 :             bool fMockDb = env->IsMock();
#     337         [ +  + ]:       1152 :             if (fMockDb) {
#     338                 :         11 :                 DbMpoolFile* mpf = pdb_temp->get_mpf();
#     339                 :         11 :                 ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
#     340         [ -  + ]:         11 :                 if (ret != 0) {
#     341                 :          0 :                     throw std::runtime_error(strprintf("BerkeleyDatabase: Failed to configure for no temp file backing for database %s", strFile));
#     342                 :          0 :                 }
#     343                 :       1152 :             }
#     344                 :            : 
#     345                 :       1152 :             ret = pdb_temp->open(nullptr,                             // Txn pointer
#     346         [ +  + ]:       1152 :                             fMockDb ? nullptr : strFile.c_str(),      // Filename
#     347         [ +  + ]:       1152 :                             fMockDb ? strFile.c_str() : "main",       // Logical db name
#     348                 :       1152 :                             DB_BTREE,                                 // Database type
#     349                 :       1152 :                             nFlags,                                   // Flags
#     350                 :       1152 :                             0);
#     351                 :            : 
#     352         [ -  + ]:       1152 :             if (ret != 0) {
#     353                 :          0 :                 throw std::runtime_error(strprintf("BerkeleyDatabase: Error %d, can't open database %s", ret, strFile));
#     354                 :          0 :             }
#     355                 :            : 
#     356                 :            :             // Call CheckUniqueFileid on the containing BDB environment to
#     357                 :            :             // avoid BDB data consistency bugs that happen when different data
#     358                 :            :             // files in the same environment have the same fileid.
#     359                 :       1152 :             CheckUniqueFileid(*env, strFile, *pdb_temp, this->env->m_fileids[strFile]);
#     360                 :            : 
#     361                 :       1152 :             m_db.reset(pdb_temp.release());
#     362                 :            : 
#     363                 :       1152 :         }
#     364                 :     118637 :     }
#     365                 :     118637 : }
#     366                 :            : 
#     367                 :            : void BerkeleyBatch::Flush()
#     368                 :      76942 : {
#     369         [ +  + ]:      76942 :     if (activeTxn)
#     370                 :          1 :         return;
#     371                 :            : 
#     372                 :            :     // Flush database activity from memory pool to disk log
#     373                 :      76941 :     unsigned int nMinutes = 0;
#     374         [ +  + ]:      76941 :     if (fReadOnly)
#     375                 :         16 :         nMinutes = 1;
#     376                 :            : 
#     377         [ +  - ]:      76941 :     if (env) { // env is nullptr for dummy databases (i.e. in tests). Don't actually flush if env is nullptr so we don't segfault
#     378         [ +  + ]:      76941 :         env->dbenv->txn_checkpoint(nMinutes ? gArgs.GetArg("-dblogsize", DEFAULT_WALLET_DBLOGSIZE) * 1024 : 0, nMinutes, 0);
#     379                 :      76941 :     }
#     380                 :      76941 : }
#     381                 :            : 
#     382                 :            : void BerkeleyDatabase::IncrementUpdateCounter()
#     383                 :     213002 : {
#     384                 :     213002 :     ++nUpdateCounter;
#     385                 :     213002 : }
#     386                 :            : 
#     387                 :            : BerkeleyBatch::~BerkeleyBatch()
#     388                 :     118631 : {
#     389                 :     118631 :     Close();
#     390                 :     118631 :     m_database.RemoveRef();
#     391                 :     118631 : }
#     392                 :            : 
#     393                 :            : void BerkeleyBatch::Close()
#     394                 :     118647 : {
#     395         [ +  + ]:     118647 :     if (!pdb)
#     396                 :         16 :         return;
#     397         [ -  + ]:     118631 :     if (activeTxn)
#     398                 :          0 :         activeTxn->abort();
#     399                 :     118631 :     activeTxn = nullptr;
#     400                 :     118631 :     pdb = nullptr;
#     401                 :     118631 :     CloseCursor();
#     402                 :            : 
#     403         [ +  + ]:     118631 :     if (fFlushOnClose)
#     404                 :      76789 :         Flush();
#     405                 :     118631 : }
#     406                 :            : 
#     407                 :            : void BerkeleyEnvironment::CloseDb(const std::string& strFile)
#     408                 :       1844 : {
#     409                 :       1844 :     {
#     410                 :       1844 :         LOCK(cs_db);
#     411                 :       1844 :         auto it = m_databases.find(strFile);
#     412                 :       1844 :         assert(it != m_databases.end());
#     413                 :       1844 :         BerkeleyDatabase& database = it->second.get();
#     414         [ +  + ]:       1844 :         if (database.m_db) {
#     415                 :            :             // Close the database handle
#     416                 :       1146 :             database.m_db->close(0);
#     417                 :       1146 :             database.m_db.reset();
#     418                 :       1146 :         }
#     419                 :       1844 :     }
#     420                 :       1844 : }
#     421                 :            : 
#     422                 :            : void BerkeleyEnvironment::ReloadDbEnv()
#     423                 :         16 : {
#     424                 :            :     // Make sure that no Db's are in use
#     425                 :         16 :     AssertLockNotHeld(cs_db);
#     426                 :         16 :     std::unique_lock<RecursiveMutex> lock(cs_db);
#     427                 :         16 :     m_db_in_use.wait(lock, [this](){
#     428         [ +  + ]:         16 :         for (auto& db : m_databases) {
#     429         [ -  + ]:         16 :             if (db.second.get().m_refcount > 0) return false;
#     430                 :         16 :         }
#     431                 :         16 :         return true;
#     432                 :         16 :     });
#     433                 :            : 
#     434                 :         16 :     std::vector<std::string> filenames;
#     435         [ +  + ]:         16 :     for (auto it : m_databases) {
#     436                 :         16 :         filenames.push_back(it.first);
#     437                 :         16 :     }
#     438                 :            :     // Close the individual Db's
#     439         [ +  + ]:         16 :     for (const std::string& filename : filenames) {
#     440                 :         16 :         CloseDb(filename);
#     441                 :         16 :     }
#     442                 :            :     // Reset the environment
#     443                 :         16 :     Flush(true); // This will flush and close the environment
#     444                 :         16 :     Reset();
#     445                 :         16 :     bilingual_str open_err;
#     446                 :         16 :     Open(open_err);
#     447                 :         16 : }
#     448                 :            : 
#     449                 :            : bool BerkeleyDatabase::Rewrite(const char* pszSkip)
#     450                 :         16 : {
#     451                 :         16 :     while (true) {
#     452                 :         16 :         {
#     453                 :         16 :             LOCK(cs_db);
#     454         [ +  - ]:         16 :             if (m_refcount <= 0) {
#     455                 :            :                 // Flush log data to the dat file
#     456                 :         16 :                 env->CloseDb(strFile);
#     457                 :         16 :                 env->CheckpointLSN(strFile);
#     458                 :         16 :                 m_refcount = -1;
#     459                 :            : 
#     460                 :         16 :                 bool fSuccess = true;
#     461                 :         16 :                 LogPrintf("BerkeleyBatch::Rewrite: Rewriting %s...\n", strFile);
#     462                 :         16 :                 std::string strFileRes = strFile + ".rewrite";
#     463                 :         16 :                 { // surround usage of db with extra {}
#     464                 :         16 :                     BerkeleyBatch db(*this, true);
#     465                 :         16 :                     std::unique_ptr<Db> pdbCopy = std::make_unique<Db>(env->dbenv.get(), 0);
#     466                 :            : 
#     467                 :         16 :                     int ret = pdbCopy->open(nullptr,               // Txn pointer
#     468                 :         16 :                                             strFileRes.c_str(), // Filename
#     469                 :         16 :                                             "main",             // Logical db name
#     470                 :         16 :                                             DB_BTREE,           // Database type
#     471                 :         16 :                                             DB_CREATE,          // Flags
#     472                 :         16 :                                             0);
#     473         [ -  + ]:         16 :                     if (ret > 0) {
#     474                 :          0 :                         LogPrintf("BerkeleyBatch::Rewrite: Can't create database file %s\n", strFileRes);
#     475                 :          0 :                         fSuccess = false;
#     476                 :          0 :                     }
#     477                 :            : 
#     478         [ +  - ]:         16 :                     if (db.StartCursor()) {
#     479         [ +  - ]:       1727 :                         while (fSuccess) {
#     480                 :       1727 :                             CDataStream ssKey(SER_DISK, CLIENT_VERSION);
#     481                 :       1727 :                             CDataStream ssValue(SER_DISK, CLIENT_VERSION);
#     482                 :       1727 :                             bool complete;
#     483                 :       1727 :                             bool ret1 = db.ReadAtCursor(ssKey, ssValue, complete);
#     484         [ +  + ]:       1727 :                             if (complete) {
#     485                 :         16 :                                 break;
#     486         [ -  + ]:       1711 :                             } else if (!ret1) {
#     487                 :          0 :                                 fSuccess = false;
#     488                 :          0 :                                 break;
#     489                 :          0 :                             }
#     490 [ -  + ][ -  + ]:       1711 :                             if (pszSkip &&
#     491         [ #  # ]:       1711 :                                 strncmp((const char*)ssKey.data(), pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)
#     492                 :          0 :                                 continue;
#     493         [ +  + ]:       1711 :                             if (strncmp((const char*)ssKey.data(), "\x07version", 8) == 0) {
#     494                 :            :                                 // Update version:
#     495                 :         16 :                                 ssValue.clear();
#     496                 :         16 :                                 ssValue << CLIENT_VERSION;
#     497                 :         16 :                             }
#     498                 :       1711 :                             Dbt datKey(ssKey.data(), ssKey.size());
#     499                 :       1711 :                             Dbt datValue(ssValue.data(), ssValue.size());
#     500                 :       1711 :                             int ret2 = pdbCopy->put(nullptr, &datKey, &datValue, DB_NOOVERWRITE);
#     501         [ -  + ]:       1711 :                             if (ret2 > 0)
#     502                 :          0 :                                 fSuccess = false;
#     503                 :       1711 :                         }
#     504                 :         16 :                         db.CloseCursor();
#     505                 :         16 :                     }
#     506         [ +  - ]:         16 :                     if (fSuccess) {
#     507                 :         16 :                         db.Close();
#     508                 :         16 :                         env->CloseDb(strFile);
#     509         [ -  + ]:         16 :                         if (pdbCopy->close(0))
#     510                 :          0 :                             fSuccess = false;
#     511                 :         16 :                     } else {
#     512                 :          0 :                         pdbCopy->close(0);
#     513                 :          0 :                     }
#     514                 :         16 :                 }
#     515         [ +  - ]:         16 :                 if (fSuccess) {
#     516                 :         16 :                     Db dbA(env->dbenv.get(), 0);
#     517         [ -  + ]:         16 :                     if (dbA.remove(strFile.c_str(), nullptr, 0))
#     518                 :          0 :                         fSuccess = false;
#     519                 :         16 :                     Db dbB(env->dbenv.get(), 0);
#     520         [ -  + ]:         16 :                     if (dbB.rename(strFileRes.c_str(), nullptr, strFile.c_str(), 0))
#     521                 :          0 :                         fSuccess = false;
#     522                 :         16 :                 }
#     523         [ -  + ]:         16 :                 if (!fSuccess)
#     524                 :         16 :                     LogPrintf("BerkeleyBatch::Rewrite: Failed to rewrite database file %s\n", strFileRes);
#     525                 :         16 :                 return fSuccess;
#     526                 :         16 :             }
#     527                 :          0 :         }
#     528                 :          0 :         UninterruptibleSleep(std::chrono::milliseconds{100});
#     529                 :          0 :     }
#     530                 :         16 : }
#     531                 :            : 
#     532                 :            : 
#     533                 :            : void BerkeleyEnvironment::Flush(bool fShutdown)
#     534                 :       1285 : {
#     535                 :       1285 :     int64_t nStart = GetTimeMillis();
#     536                 :            :     // Flush log data to the actual data file on all files that are not in use
#     537 [ +  + ][ +  + ]:       1285 :     LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: [%s] Flush(%s)%s\n", strPath, fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started");
#                 [ +  + ]
#     538         [ +  + ]:       1285 :     if (!fDbEnvInit)
#     539                 :        392 :         return;
#     540                 :        893 :     {
#     541                 :        893 :         LOCK(cs_db);
#     542                 :        893 :         bool no_dbs_accessed = true;
#     543         [ +  + ]:        931 :         for (auto& db_it : m_databases) {
#     544                 :        931 :             std::string strFile = db_it.first;
#     545                 :        931 :             int nRefCount = db_it.second.get().m_refcount;
#     546         [ +  + ]:        931 :             if (nRefCount < 0) continue;
#     547         [ +  + ]:        870 :             LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flushing %s (refcount = %d)...\n", strFile, nRefCount);
#     548         [ +  + ]:        870 :             if (nRefCount == 0) {
#     549                 :            :                 // Move log data to the dat file
#     550                 :        862 :                 CloseDb(strFile);
#     551         [ +  + ]:        862 :                 LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s checkpoint\n", strFile);
#     552                 :        862 :                 dbenv->txn_checkpoint(0, 0, 0);
#     553         [ +  + ]:        862 :                 LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s detach\n", strFile);
#     554         [ +  - ]:        862 :                 if (!fMockDb)
#     555                 :        862 :                     dbenv->lsn_reset(strFile.c_str(), 0);
#     556         [ +  + ]:        862 :                 LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: %s closed\n", strFile);
#     557                 :        862 :                 nRefCount = -1;
#     558                 :        862 :             } else {
#     559                 :          8 :                 no_dbs_accessed = false;
#     560                 :          8 :             }
#     561                 :        870 :         }
#     562 [ +  + ][ +  - ]:        893 :         LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart);
#                 [ +  + ]
#     563         [ +  + ]:        893 :         if (fShutdown) {
#     564                 :        404 :             char** listp;
#     565         [ +  - ]:        404 :             if (no_dbs_accessed) {
#     566                 :        404 :                 dbenv->log_archive(&listp, DB_ARCH_REMOVE);
#     567                 :        404 :                 Close();
#     568         [ +  - ]:        404 :                 if (!fMockDb) {
#     569                 :        404 :                     fs::remove_all(fs::path(strPath) / "database");
#     570                 :        404 :                 }
#     571                 :        404 :             }
#     572                 :        404 :         }
#     573                 :        893 :     }
#     574                 :        893 : }
#     575                 :            : 
#     576                 :            : bool BerkeleyDatabase::PeriodicFlush()
#     577                 :        291 : {
#     578                 :            :     // Don't flush if we can't acquire the lock.
#     579                 :        291 :     TRY_LOCK(cs_db, lockDb);
#     580         [ +  + ]:        291 :     if (!lockDb) return false;
#     581                 :            : 
#     582                 :            :     // Don't flush if any databases are in use
#     583         [ +  + ]:        284 :     for (auto& it : env->m_databases) {
#     584         [ -  + ]:        284 :         if (it.second.get().m_refcount > 0) return false;
#     585                 :        284 :     }
#     586                 :            : 
#     587                 :            :     // Don't flush if there haven't been any batch writes for this database.
#     588         [ -  + ]:        284 :     if (m_refcount < 0) return false;
#     589                 :            : 
#     590         [ +  - ]:        284 :     LogPrint(BCLog::WALLETDB, "Flushing %s\n", strFile);
#     591                 :        284 :     int64_t nStart = GetTimeMillis();
#     592                 :            : 
#     593                 :            :     // Flush wallet file so it's self contained
#     594                 :        284 :     env->CloseDb(strFile);
#     595                 :        284 :     env->CheckpointLSN(strFile);
#     596                 :        284 :     m_refcount = -1;
#     597                 :            : 
#     598         [ +  - ]:        284 :     LogPrint(BCLog::WALLETDB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
#     599                 :            : 
#     600                 :        284 :     return true;
#     601                 :        284 : }
#     602                 :            : 
#     603                 :            : bool BerkeleyDatabase::Backup(const std::string& strDest) const
#     604                 :         27 : {
#     605                 :         27 :     while (true)
#     606                 :         27 :     {
#     607                 :         27 :         {
#     608                 :         27 :             LOCK(cs_db);
#     609         [ +  - ]:         27 :             if (m_refcount <= 0)
#     610                 :         27 :             {
#     611                 :            :                 // Flush log data to the dat file
#     612                 :         27 :                 env->CloseDb(strFile);
#     613                 :         27 :                 env->CheckpointLSN(strFile);
#     614                 :            : 
#     615                 :            :                 // Copy wallet file
#     616                 :         27 :                 fs::path pathSrc = env->Directory() / strFile;
#     617                 :         27 :                 fs::path pathDest(strDest);
#     618         [ +  + ]:         27 :                 if (fs::is_directory(pathDest))
#     619                 :          2 :                     pathDest /= strFile;
#     620                 :            : 
#     621                 :         27 :                 try {
#     622         [ +  + ]:         27 :                     if (fs::equivalent(pathSrc, pathDest)) {
#     623                 :          4 :                         LogPrintf("cannot backup to wallet source file %s\n", pathDest.string());
#     624                 :          4 :                         return false;
#     625                 :          4 :                     }
#     626                 :            : 
#     627                 :         23 :                     fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists);
#     628                 :         23 :                     LogPrintf("copied %s to %s\n", strFile, pathDest.string());
#     629                 :         23 :                     return true;
#     630                 :         23 :                 } catch (const fs::filesystem_error& e) {
#     631                 :          0 :                     LogPrintf("error copying %s to %s - %s\n", strFile, pathDest.string(), fsbridge::get_filesystem_error_message(e));
#     632                 :          0 :                     return false;
#     633                 :          0 :                 }
#     634                 :          0 :             }
#     635                 :          0 :         }
#     636                 :          0 :         UninterruptibleSleep(std::chrono::milliseconds{100});
#     637                 :          0 :     }
#     638                 :         27 : }
#     639                 :            : 
#     640                 :            : void BerkeleyDatabase::Flush()
#     641                 :        868 : {
#     642                 :        868 :     env->Flush(false);
#     643                 :        868 : }
#     644                 :            : 
#     645                 :            : void BerkeleyDatabase::Close()
#     646                 :        401 : {
#     647                 :        401 :     env->Flush(true);
#     648                 :        401 : }
#     649                 :            : 
#     650                 :            : void BerkeleyDatabase::ReloadDbEnv()
#     651                 :         16 : {
#     652                 :         16 :     env->ReloadDbEnv();
#     653                 :         16 : }
#     654                 :            : 
#     655                 :            : bool BerkeleyBatch::StartCursor()
#     656                 :        533 : {
#     657                 :        533 :     assert(!m_cursor);
#     658         [ -  + ]:        533 :     if (!pdb)
#     659                 :          0 :         return false;
#     660                 :        533 :     int ret = pdb->cursor(nullptr, &m_cursor, 0);
#     661                 :        533 :     return ret == 0;
#     662                 :        533 : }
#     663                 :            : 
#     664                 :            : bool BerkeleyBatch::ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete)
#     665                 :      54089 : {
#     666                 :      54089 :     complete = false;
#     667         [ -  + ]:      54089 :     if (m_cursor == nullptr) return false;
#     668                 :            :     // Read at cursor
#     669                 :      54089 :     SafeDbt datKey;
#     670                 :      54089 :     SafeDbt datValue;
#     671                 :      54089 :     int ret = m_cursor->get(datKey, datValue, DB_NEXT);
#     672         [ +  + ]:      54089 :     if (ret == DB_NOTFOUND) {
#     673                 :        533 :         complete = true;
#     674                 :        533 :     }
#     675         [ +  + ]:      54089 :     if (ret != 0)
#     676                 :        533 :         return false;
#     677 [ -  + ][ -  + ]:      53556 :     else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr)
#     678                 :          0 :         return false;
#     679                 :            : 
#     680                 :            :     // Convert to streams
#     681                 :      53556 :     ssKey.SetType(SER_DISK);
#     682                 :      53556 :     ssKey.clear();
#     683                 :      53556 :     ssKey.write((char*)datKey.get_data(), datKey.get_size());
#     684                 :      53556 :     ssValue.SetType(SER_DISK);
#     685                 :      53556 :     ssValue.clear();
#     686                 :      53556 :     ssValue.write((char*)datValue.get_data(), datValue.get_size());
#     687                 :      53556 :     return true;
#     688                 :      53556 : }
#     689                 :            : 
#     690                 :            : void BerkeleyBatch::CloseCursor()
#     691                 :     119164 : {
#     692         [ +  + ]:     119164 :     if (!m_cursor) return;
#     693                 :        533 :     m_cursor->close();
#     694                 :        533 :     m_cursor = nullptr;
#     695                 :        533 : }
#     696                 :            : 
#     697                 :            : bool BerkeleyBatch::TxnBegin()
#     698                 :         22 : {
#     699 [ -  + ][ -  + ]:         22 :     if (!pdb || activeTxn)
#     700                 :          0 :         return false;
#     701                 :         22 :     DbTxn* ptxn = env->TxnBegin();
#     702         [ -  + ]:         22 :     if (!ptxn)
#     703                 :          0 :         return false;
#     704                 :         22 :     activeTxn = ptxn;
#     705                 :         22 :     return true;
#     706                 :         22 : }
#     707                 :            : 
#     708                 :            : bool BerkeleyBatch::TxnCommit()
#     709                 :         19 : {
#     710 [ -  + ][ -  + ]:         19 :     if (!pdb || !activeTxn)
#     711                 :          0 :         return false;
#     712                 :         19 :     int ret = activeTxn->commit(0);
#     713                 :         19 :     activeTxn = nullptr;
#     714                 :         19 :     return (ret == 0);
#     715                 :         19 : }
#     716                 :            : 
#     717                 :            : bool BerkeleyBatch::TxnAbort()
#     718                 :          3 : {
#     719 [ -  + ][ -  + ]:          3 :     if (!pdb || !activeTxn)
#     720                 :          0 :         return false;
#     721                 :          3 :     int ret = activeTxn->abort();
#     722                 :          3 :     activeTxn = nullptr;
#     723                 :          3 :     return (ret == 0);
#     724                 :          3 : }
#     725                 :            : 
#     726                 :            : bool BerkeleyDatabaseSanityCheck()
#     727                 :       1513 : {
#     728                 :       1513 :     int major, minor;
#     729                 :       1513 :     DbEnv::version(&major, &minor, nullptr);
#     730                 :            : 
#     731                 :            :     /* If the major version differs, or the minor version of library is *older*
#     732                 :            :      * than the header that was compiled against, flag an error.
#     733                 :            :      */
#     734 [ -  + ][ -  + ]:       1513 :     if (major != DB_VERSION_MAJOR || minor < DB_VERSION_MINOR) {
#     735                 :          0 :         LogPrintf("BerkeleyDB database version conflict: header version is %d.%d, library version is %d.%d\n",
#     736                 :          0 :             DB_VERSION_MAJOR, DB_VERSION_MINOR, major, minor);
#     737                 :          0 :         return false;
#     738                 :          0 :     }
#     739                 :            : 
#     740                 :       1513 :     return true;
#     741                 :       1513 : }
#     742                 :            : 
#     743                 :            : std::string BerkeleyDatabaseVersion()
#     744                 :        517 : {
#     745                 :        517 :     return DbEnv::version(nullptr, nullptr, nullptr);
#     746                 :        517 : }
#     747                 :            : 
#     748                 :            : bool BerkeleyBatch::ReadKey(CDataStream&& key, CDataStream& value)
#     749                 :      15727 : {
#     750         [ -  + ]:      15727 :     if (!pdb)
#     751                 :          0 :         return false;
#     752                 :            : 
#     753                 :      15727 :     SafeDbt datKey(key.data(), key.size());
#     754                 :            : 
#     755                 :      15727 :     SafeDbt datValue;
#     756                 :      15727 :     int ret = pdb->get(activeTxn, datKey, datValue, 0);
#     757 [ +  + ][ +  - ]:      15727 :     if (ret == 0 && datValue.get_data() != nullptr) {
#     758                 :      15159 :         value.write((char*)datValue.get_data(), datValue.get_size());
#     759                 :      15159 :         return true;
#     760                 :      15159 :     }
#     761                 :        568 :     return false;
#     762                 :        568 : }
#     763                 :            : 
#     764                 :            : bool BerkeleyBatch::WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite)
#     765                 :     208950 : {
#     766         [ -  + ]:     208950 :     if (!pdb)
#     767                 :          0 :         return false;
#     768         [ -  + ]:     208950 :     if (fReadOnly)
#     769                 :     208950 :         assert(!"Write called on database in read-only mode");
#     770                 :            : 
#     771                 :     208950 :     SafeDbt datKey(key.data(), key.size());
#     772                 :            : 
#     773                 :     208950 :     SafeDbt datValue(value.data(), value.size());
#     774                 :            : 
#     775         [ +  + ]:     208950 :     int ret = pdb->put(activeTxn, datKey, datValue, (overwrite ? 0 : DB_NOOVERWRITE));
#     776                 :     208950 :     return (ret == 0);
#     777                 :     208950 : }
#     778                 :            : 
#     779                 :            : bool BerkeleyBatch::EraseKey(CDataStream&& key)
#     780                 :      13281 : {
#     781         [ -  + ]:      13281 :     if (!pdb)
#     782                 :          0 :         return false;
#     783         [ -  + ]:      13281 :     if (fReadOnly)
#     784                 :      13281 :         assert(!"Erase called on database in read-only mode");
#     785                 :            : 
#     786                 :      13281 :     SafeDbt datKey(key.data(), key.size());
#     787                 :            : 
#     788                 :      13281 :     int ret = pdb->del(activeTxn, datKey, 0);
#     789 [ +  + ][ +  - ]:      13281 :     return (ret == 0 || ret == DB_NOTFOUND);
#     790                 :      13281 : }
#     791                 :            : 
#     792                 :            : bool BerkeleyBatch::HasKey(CDataStream&& key)
#     793                 :     118631 : {
#     794         [ -  + ]:     118631 :     if (!pdb)
#     795                 :          0 :         return false;
#     796                 :            : 
#     797                 :     118631 :     SafeDbt datKey(key.data(), key.size());
#     798                 :            : 
#     799                 :     118631 :     int ret = pdb->exists(activeTxn, datKey, 0);
#     800                 :     118631 :     return ret == 0;
#     801                 :     118631 : }
#     802                 :            : 
#     803                 :            : void BerkeleyDatabase::AddRef()
#     804                 :     118637 : {
#     805                 :     118637 :     LOCK(cs_db);
#     806         [ +  + ]:     118637 :     if (m_refcount < 0) {
#     807                 :        296 :         m_refcount = 1;
#     808                 :     118341 :     } else {
#     809                 :     118341 :         m_refcount++;
#     810                 :     118341 :     }
#     811                 :     118637 : }
#     812                 :            : 
#     813                 :            : void BerkeleyDatabase::RemoveRef()
#     814                 :     118631 : {
#     815                 :     118631 :     LOCK(cs_db);
#     816                 :     118631 :     m_refcount--;
#     817         [ +  - ]:     118631 :     if (env) env->m_db_in_use.notify_all();
#     818                 :     118631 : }
#     819                 :            : 
#     820                 :            : std::unique_ptr<DatabaseBatch> BerkeleyDatabase::MakeBatch(bool flush_on_close)
#     821                 :     118621 : {
#     822                 :     118621 :     return std::make_unique<BerkeleyBatch>(*this, false, flush_on_close);
#     823                 :     118621 : }
#     824                 :            : 
#     825                 :            : std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
#     826                 :        616 : {
#     827                 :        616 :     fs::path data_file = BDBDataFile(path);
#     828                 :        616 :     std::unique_ptr<BerkeleyDatabase> db;
#     829                 :        616 :     {
#     830                 :        616 :         LOCK(cs_db); // Lock env.m_databases until insert in BerkeleyDatabase constructor
#     831                 :        616 :         std::string data_filename = data_file.filename().string();
#     832                 :        616 :         std::shared_ptr<BerkeleyEnvironment> env = GetBerkeleyEnv(data_file.parent_path());
#     833         [ +  + ]:        616 :         if (env->m_databases.count(data_filename)) {
#     834                 :          4 :             error = Untranslated(strprintf("Refusing to load database. Data file '%s' is already loaded.", (env->Directory() / data_filename).string()));
#     835                 :          4 :             status = DatabaseStatus::FAILED_ALREADY_LOADED;
#     836                 :          4 :             return nullptr;
#     837                 :          4 :         }
#     838                 :        612 :         db = std::make_unique<BerkeleyDatabase>(std::move(env), std::move(data_filename));
#     839                 :        612 :     }
#     840                 :            : 
#     841 [ +  + ][ +  + ]:        612 :     if (options.verify && !db->Verify(error)) {
#     842                 :          6 :         status = DatabaseStatus::FAILED_VERIFY;
#     843                 :          6 :         return nullptr;
#     844                 :          6 :     }
#     845                 :            : 
#     846                 :        606 :     status = DatabaseStatus::SUCCESS;
#     847                 :        606 :     return db;
#     848                 :        606 : }

Generated by: LCOV version 1.14