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 : #ifndef BITCOIN_WALLET_BDB_H 7 : #define BITCOIN_WALLET_BDB_H 8 : 9 : #include <clientversion.h> 10 : #include <fs.h> 11 : #include <serialize.h> 12 : #include <streams.h> 13 : #include <util/system.h> 14 : #include <wallet/db.h> 15 : 16 : #include <map> 17 : #include <memory> 18 : #include <string> 19 : #include <unordered_map> 20 : #include <vector> 21 : 22 : struct bilingual_str; 23 : 24 : #include <db_cxx.h> 25 : 26 : namespace wallet { 27 : struct WalletDatabaseFileId { 28 : uint8_t value[DB_FILE_ID_LEN]; 29 : bool operator==(const WalletDatabaseFileId& rhs) const; 30 : }; 31 : 32 : class BerkeleyDatabase; 33 : 34 : class BerkeleyEnvironment 35 : { 36 : private: 37 : bool fDbEnvInit; 38 : bool fMockDb; 39 : // Don't change into fs::path, as that can result in 40 : // shutdown problems/crashes caused by a static initialized internal pointer. 41 : std::string strPath; 42 : 43 : public: 44 : std::unique_ptr<DbEnv> dbenv; 45 : std::map<fs::path, std::reference_wrapper<BerkeleyDatabase>> m_databases; 46 : std::unordered_map<std::string, WalletDatabaseFileId> m_fileids; 47 : std::condition_variable_any m_db_in_use; 48 : bool m_use_shared_memory; 49 : 50 : explicit BerkeleyEnvironment(const fs::path& env_directory, bool use_shared_memory); 51 : BerkeleyEnvironment(); 52 : ~BerkeleyEnvironment(); 53 : void Reset(); 54 : 55 8252 : bool IsMock() const { return fMockDb; } 56 : bool IsInitialized() const { return fDbEnvInit; } 57 3194 : fs::path Directory() const { return fs::PathFromString(strPath); } 58 : 59 : bool Open(bilingual_str& error); 60 : void Close(); 61 : void Flush(bool fShutdown); 62 : void CheckpointLSN(const std::string& strFile); 63 : 64 : void CloseDb(const fs::path& filename); 65 : void ReloadDbEnv(); 66 : 67 66 : DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC) 68 : { 69 66 : DbTxn* ptxn = nullptr; 70 66 : int ret = dbenv->txn_begin(nullptr, &ptxn, flags); 71 66 : if (!ptxn || ret != 0) 72 0 : return nullptr; 73 66 : return ptxn; 74 66 : } 75 : }; 76 : 77 : /** Get BerkeleyEnvironment given a directory path. */ 78 : std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory, bool use_shared_memory); 79 : 80 : class BerkeleyBatch; 81 : 82 : /** An instance of this class represents one database. 83 : * For BerkeleyDB this is just a (env, strFile) tuple. 84 : **/ 85 : class BerkeleyDatabase : public WalletDatabase 86 : { 87 : public: 88 : BerkeleyDatabase() = delete; 89 : 90 : /** Create DB handle to real database */ 91 5775 : BerkeleyDatabase(std::shared_ptr<BerkeleyEnvironment> env, fs::path filename, const DatabaseOptions& options) : 92 5775 : WalletDatabase(), env(std::move(env)), m_filename(std::move(filename)), m_max_log_mb(options.max_log_mb) 93 3850 : { 94 1925 : auto inserted = this->env->m_databases.emplace(m_filename, std::ref(*this)); 95 1925 : assert(inserted.second); 96 3850 : } 97 : 98 : ~BerkeleyDatabase() override; 99 : 100 : /** Open the database if it is not already opened. */ 101 : void Open() override; 102 : 103 : /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero 104 : */ 105 : bool Rewrite(const char* pszSkip=nullptr) override; 106 : 107 : /** Indicate that a new database user has begun using the database. */ 108 : void AddRef() override; 109 : /** Indicate that database user has stopped using the database and that it could be flushed or closed. */ 110 : void RemoveRef() override; 111 : 112 : /** Back up the entire database to a file. 113 : */ 114 : bool Backup(const std::string& strDest) const override; 115 : 116 : /** Make sure all changes are flushed to database file. 117 : */ 118 : void Flush() override; 119 : /** Flush to the database file and close the database. 120 : * Also close the environment if no other databases are open in it. 121 : */ 122 : void Close() override; 123 : /* flush the wallet passively (TRY_LOCK) 124 : ideal to be called periodically */ 125 : bool PeriodicFlush() override; 126 : 127 : void IncrementUpdateCounter() override; 128 : 129 : void ReloadDbEnv() override; 130 : 131 : /** Verifies the environment and database file */ 132 : bool Verify(bilingual_str& error); 133 : 134 : /** Return path to main database filename */ 135 1535 : std::string Filename() override { return fs::PathToString(env->Directory() / m_filename); } 136 : 137 1328 : std::string Format() override { return "bdb"; } 138 : /** 139 : * Pointer to shared database environment. 140 : * 141 : * Normally there is only one BerkeleyDatabase object per 142 : * BerkeleyEnvivonment, but in the special, backwards compatible case where 143 : * multiple wallet BDB data files are loaded from the same directory, this 144 : * will point to a shared instance that gets freed when the last data file 145 : * is closed. 146 : */ 147 : std::shared_ptr<BerkeleyEnvironment> env; 148 : 149 : /** Database pointer. This is initialized lazily and reset during flushes, so it can be null. */ 150 : std::unique_ptr<Db> m_db; 151 : 152 : fs::path m_filename; 153 : int64_t m_max_log_mb; 154 : 155 : /** Make a BerkeleyBatch connected to this database */ 156 : std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override; 157 : 158 2234 : virtual bool SupportsAutoBackup() override { return true; } 159 : }; 160 : 161 : /** RAII class that provides access to a Berkeley database */ 162 : class BerkeleyBatch : public DatabaseBatch 163 : { 164 : public: 165 : /** RAII class that automatically cleanses its data on destruction */ 166 : class SafeDbt final 167 : { 168 : Dbt m_dbt; 169 : 170 : public: 171 : // construct Dbt with internally-managed data 172 : SafeDbt(); 173 : // construct Dbt with provided data 174 : SafeDbt(void* data, size_t size); 175 : ~SafeDbt(); 176 : 177 : // delegate to Dbt 178 : const void* get_data() const; 179 : uint32_t get_size() const; 180 : 181 : // conversion operator to access the underlying Dbt 182 : operator Dbt*(); 183 : }; 184 : 185 : private: 186 : bool ReadKey(CDataStream&& key, CDataStream& value) override; 187 : bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite = true) override; 188 : bool EraseKey(CDataStream&& key) override; 189 : bool HasKey(CDataStream&& key) override; 190 : bool ErasePrefix(Span<const std::byte> prefix) override; 191 : 192 : protected: 193 : Db* pdb{nullptr}; 194 : std::string strFile; 195 : DbTxn* activeTxn{nullptr}; 196 : Dbc* m_cursor{nullptr}; 197 : bool fReadOnly; 198 : bool fFlushOnClose; 199 : BerkeleyEnvironment *env; 200 : BerkeleyDatabase& m_database; 201 : 202 : public: 203 : explicit BerkeleyBatch(BerkeleyDatabase& database, const bool fReadOnly, bool fFlushOnCloseIn=true); 204 : ~BerkeleyBatch() override; 205 : 206 : BerkeleyBatch(const BerkeleyBatch&) = delete; 207 : BerkeleyBatch& operator=(const BerkeleyBatch&) = delete; 208 : 209 : void Flush() override; 210 : void Close() override; 211 : 212 : bool StartCursor() override; 213 : bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) override; 214 : void CloseCursor() override; 215 : bool TxnBegin() override; 216 : bool TxnCommit() override; 217 : bool TxnAbort() override; 218 : DbTxn* txn() const { return activeTxn; } 219 : }; 220 : 221 : std::string BerkeleyDatabaseVersion(); 222 : 223 : /** Perform sanity check of runtime BDB version versus linked BDB version. 224 : */ 225 : bool BerkeleyDatabaseSanityCheck(); 226 : 227 : //! Return object giving access to Berkeley database at specified path. 228 : std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); 229 : } // namespace wallet 230 : 231 : #endif // BITCOIN_WALLET_BDB_H