Branch data Line data Source code
1 : : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : : // Copyright (c) 2009-2022 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 <common/system.h>
11 : : #include <serialize.h>
12 : : #include <streams.h>
13 : : #include <util/fs.h>
14 : : #include <wallet/db.h>
15 : :
16 : : #include <atomic>
17 : : #include <condition_variable>
18 : : #include <map>
19 : : #include <memory>
20 : : #include <string>
21 : : #include <unordered_map>
22 : : #include <vector>
23 : :
24 : : struct bilingual_str;
25 : :
26 : : class DbEnv;
27 : : class DbTxn;
28 : : class Db;
29 : : class Dbc;
30 : :
31 : : // This constant was introduced in BDB 4.0.14 and has never changed, but there
32 : : // is a belt-and-suspenders check in the cpp file just in case.
33 : : #define BDB_DB_FILE_ID_LEN 20 /* Unique file ID length. */
34 : :
35 : : namespace wallet {
36 : :
37 : : struct WalletDatabaseFileId {
38 : : uint8_t value[BDB_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<fs::path, 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 : : bool m_use_shared_memory;
59 : :
60 : : explicit BerkeleyEnvironment(const fs::path& env_directory, bool use_shared_memory);
61 : : BerkeleyEnvironment();
62 : : ~BerkeleyEnvironment();
63 : : void Reset();
64 : :
65 [ - + + - ]: 2204 : bool IsMock() const { return fMockDb; }
66 : : bool IsInitialized() const { return fDbEnvInit; }
67 [ + - + - : 1174 : fs::path Directory() const { return fs::PathFromString(strPath); }
+ - - - ]
[ + - + - ]
68 : :
69 : : bool Open(bilingual_str& error);
70 : : void Close();
71 : : void Flush(bool fShutdown);
72 : : void CheckpointLSN(const std::string& strFile);
73 : :
74 : : void CloseDb(const fs::path& filename);
75 : : void ReloadDbEnv();
76 : :
77 : : DbTxn* TxnBegin(int flags);
78 : : };
79 : :
80 : : /** Get BerkeleyEnvironment given a directory path. */
81 : : std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory, bool use_shared_memory);
82 : :
83 : : class BerkeleyBatch;
84 : :
85 : : /** An instance of this class represents one database.
86 : : * For BerkeleyDB this is just a (env, strFile) tuple.
87 : : **/
88 : : class BerkeleyDatabase : public WalletDatabase
89 : : {
90 : : public:
91 : : BerkeleyDatabase() = delete;
92 : :
93 : : /** Create DB handle to real database */
94 : : BerkeleyDatabase(std::shared_ptr<BerkeleyEnvironment> env, fs::path filename, const DatabaseOptions& options);
95 : :
96 : : ~BerkeleyDatabase() override;
97 : :
98 : : /** Open the database if it is not already opened. */
99 : : void Open() override;
100 : :
101 : : /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero
102 : : */
103 : : bool Rewrite(const char* pszSkip=nullptr) override;
104 : :
105 : : /** Indicate that a new database user has begun using the database. */
106 : : void AddRef() override;
107 : : /** Indicate that database user has stopped using the database and that it could be flushed or closed. */
108 : : void RemoveRef() override;
109 : :
110 : : /** Back up the entire database to a file.
111 : : */
112 : : bool Backup(const std::string& strDest) const override;
113 : :
114 : : /** Make sure all changes are flushed to database file.
115 : : */
116 : : void Flush() override;
117 : : /** Flush to the database file and close the database.
118 : : * Also close the environment if no other databases are open in it.
119 : : */
120 : : void Close() override;
121 : : /* flush the wallet passively (TRY_LOCK)
122 : : ideal to be called periodically */
123 : : bool PeriodicFlush() override;
124 : :
125 : : void IncrementUpdateCounter() override;
126 : :
127 : : void ReloadDbEnv() override;
128 : :
129 : : /** Verifies the environment and database file */
130 : : bool Verify(bilingual_str& error);
131 : :
132 : : /** Return path to main database filename */
133 [ + - + - ]: 2695 : std::string Filename() override { return fs::PathToString(env->Directory() / m_filename); }
134 : :
135 : 1261 : std::string Format() override { return "bdb"; }
136 : : /**
137 : : * Pointer to shared database environment.
138 : : *
139 : : * Normally there is only one BerkeleyDatabase object per
140 : : * BerkeleyEnvivonment, but in the special, backwards compatible case where
141 : : * multiple wallet BDB data files are loaded from the same directory, this
142 : : * will point to a shared instance that gets freed when the last data file
143 : : * is closed.
144 : : */
145 : : std::shared_ptr<BerkeleyEnvironment> env;
146 : :
147 : : /** Database pointer. This is initialized lazily and reset during flushes, so it can be null. */
148 : : std::unique_ptr<Db> m_db;
149 : :
150 : : // Whether to byteswap
151 : : bool m_byteswap;
152 : :
153 : : fs::path m_filename;
154 : : int64_t m_max_log_mb;
155 : :
156 : : /** Make a BerkeleyBatch connected to this database */
157 : : std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override;
158 : : };
159 : :
160 : : class BerkeleyCursor : public DatabaseCursor
161 : : {
162 : : private:
163 : : Dbc* m_cursor;
164 : : std::vector<std::byte> m_key_prefix;
165 : : bool m_first{true};
166 : :
167 : : public:
168 : : // Constructor for cursor for records matching the prefix
169 : : // To match all records, an empty prefix may be provided.
170 : : explicit BerkeleyCursor(BerkeleyDatabase& database, const BerkeleyBatch& batch, Span<const std::byte> prefix = {});
171 : : ~BerkeleyCursor() override;
172 : :
173 : : Status Next(DataStream& key, DataStream& value) override;
174 [ + - + - : 60 : Dbc* dbc() const { return m_cursor; }
+ - ]
175 : : };
176 : :
177 : : /** RAII class that provides access to a Berkeley database */
178 : : class BerkeleyBatch : public DatabaseBatch
179 : : {
180 : : private:
181 : : bool ReadKey(DataStream&& key, DataStream& value) override;
182 : : bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override;
183 : : bool EraseKey(DataStream&& key) override;
184 : : bool HasKey(DataStream&& key) override;
185 : : bool ErasePrefix(Span<const std::byte> prefix) override;
186 : :
187 : : protected:
188 : : Db* pdb{nullptr};
189 : : std::string strFile;
190 : : DbTxn* activeTxn{nullptr};
191 : : bool fReadOnly;
192 : : bool fFlushOnClose;
193 : : BerkeleyEnvironment *env;
194 : : BerkeleyDatabase& m_database;
195 : :
196 : : public:
197 : : explicit BerkeleyBatch(BerkeleyDatabase& database, const bool fReadOnly, bool fFlushOnCloseIn=true);
198 : : ~BerkeleyBatch() override;
199 : :
200 : : BerkeleyBatch(const BerkeleyBatch&) = delete;
201 : : BerkeleyBatch& operator=(const BerkeleyBatch&) = delete;
202 : :
203 : : void Flush() override;
204 : : void Close() override;
205 : :
206 : : std::unique_ptr<DatabaseCursor> GetNewCursor() override;
207 : : std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(Span<const std::byte> prefix) override;
208 : : bool TxnBegin() override;
209 : : bool TxnCommit() override;
210 : : bool TxnAbort() override;
211 [ + - ]: 11582 : DbTxn* txn() const { return activeTxn; }
212 : : };
213 : :
214 : : std::string BerkeleyDatabaseVersion();
215 : :
216 : : /** Perform sanity check of runtime BDB version versus linked BDB version.
217 : : */
218 : : bool BerkeleyDatabaseSanityCheck();
219 : :
220 : : //! Return object giving access to Berkeley database at specified path.
221 : : std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
222 : : } // namespace wallet
223 : :
224 : : #endif // BITCOIN_WALLET_BDB_H
|