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