LCOV - code coverage report
Current view: top level - src/wallet - bdb.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 521 621 83.9 %
Date: 2022-04-21 14:51:19 Functions: 49 50 98.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: 172 248 69.4 %

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

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a