Bitcoin Core  0.18.99
P2P Digital Currency
db.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2019 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_DB_H
7 #define BITCOIN_WALLET_DB_H
8 
9 #include <clientversion.h>
10 #include <fs.h>
11 #include <serialize.h>
12 #include <streams.h>
13 #include <sync.h>
14 #include <util/system.h>
15 #include <version.h>
16 
17 #include <atomic>
18 #include <map>
19 #include <memory>
20 #include <string>
21 #include <unordered_map>
22 #include <vector>
23 
24 #include <db_cxx.h>
25 
26 static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
27 static const bool DEFAULT_WALLET_PRIVDB = true;
28 
30  u_int8_t value[DB_FILE_ID_LEN];
31  bool operator==(const WalletDatabaseFileId& rhs) const;
32 };
33 
34 class BerkeleyDatabase;
35 
37 {
38 private:
39  bool fDbEnvInit;
40  bool fMockDb;
41  // Don't change into fs::path, as that can result in
42  // shutdown problems/crashes caused by a static initialized internal pointer.
43  std::string strPath;
44 
45 public:
46  std::unique_ptr<DbEnv> dbenv;
47  std::map<std::string, int> mapFileUseCount;
48  std::map<std::string, std::reference_wrapper<BerkeleyDatabase>> m_databases;
49  std::unordered_map<std::string, WalletDatabaseFileId> m_fileids;
50  std::condition_variable_any m_db_in_use;
51 
52  BerkeleyEnvironment(const fs::path& env_directory);
55  void Reset();
56 
57  bool IsMock() const { return fMockDb; }
58  bool IsInitialized() const { return fDbEnvInit; }
59  bool IsDatabaseLoaded(const std::string& db_filename) const { return m_databases.find(db_filename) != m_databases.end(); }
60  fs::path Directory() const { return strPath; }
61 
68  enum class VerifyResult { VERIFY_OK,
69  RECOVER_OK,
70  RECOVER_FAIL };
71  typedef bool (*recoverFunc_type)(const fs::path& file_path, std::string& out_backup_filename);
72  VerifyResult Verify(const std::string& strFile, recoverFunc_type recoverFunc, std::string& out_backup_filename);
80  typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
81  bool Salvage(const std::string& strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
82 
83  bool Open(bool retry);
84  void Close();
85  void Flush(bool fShutdown);
86  void CheckpointLSN(const std::string& strFile);
87 
88  void CloseDb(const std::string& strFile);
89  void ReloadDbEnv();
90 
91  DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
92  {
93  DbTxn* ptxn = nullptr;
94  int ret = dbenv->txn_begin(nullptr, &ptxn, flags);
95  if (!ptxn || ret != 0)
96  return nullptr;
97  return ptxn;
98  }
99 };
100 
102 bool IsWalletLoaded(const fs::path& wallet_path);
103 
105 fs::path WalletDataFilePath(const fs::path& wallet_path);
106 
108 std::shared_ptr<BerkeleyEnvironment> GetWalletEnv(const fs::path& wallet_path, std::string& database_filename);
109 
114 {
115  friend class BerkeleyBatch;
116 public:
118  BerkeleyDatabase() : nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(nullptr)
119  {
120  }
121 
123  BerkeleyDatabase(std::shared_ptr<BerkeleyEnvironment> env, std::string filename) :
124  nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0), env(std::move(env)), strFile(std::move(filename))
125  {
126  auto inserted = this->env->m_databases.emplace(strFile, std::ref(*this));
127  assert(inserted.second);
128  }
129 
131  if (env) {
132  size_t erased = env->m_databases.erase(strFile);
133  assert(erased == 1);
134  }
135  }
136 
138  static std::unique_ptr<BerkeleyDatabase> Create(const fs::path& path)
139  {
140  std::string filename;
141  return MakeUnique<BerkeleyDatabase>(GetWalletEnv(path, filename), std::move(filename));
142  }
143 
145  static std::unique_ptr<BerkeleyDatabase> CreateDummy()
146  {
147  return MakeUnique<BerkeleyDatabase>();
148  }
149 
151  static std::unique_ptr<BerkeleyDatabase> CreateMock()
152  {
153  return MakeUnique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "");
154  }
155 
158  bool Rewrite(const char* pszSkip=nullptr);
159 
162  bool Backup(const std::string& strDest);
163 
166  void Flush(bool shutdown);
167 
168  void IncrementUpdateCounter();
169 
170  void ReloadDbEnv();
171 
172  std::atomic<unsigned int> nUpdateCounter;
173  unsigned int nLastSeen;
174  unsigned int nLastFlushed;
176 
186  std::shared_ptr<BerkeleyEnvironment> env;
187 
189  std::unique_ptr<Db> m_db;
190 
191 private:
192  std::string strFile;
193 
198  bool IsDummy() { return env == nullptr; }
199 };
200 
203 {
205  class SafeDbt final
206  {
207  Dbt m_dbt;
208 
209  public:
210  // construct Dbt with internally-managed data
211  SafeDbt();
212  // construct Dbt with provided data
213  SafeDbt(void* data, size_t size);
214  ~SafeDbt();
215 
216  // delegate to Dbt
217  const void* get_data() const;
218  u_int32_t get_size() const;
219 
220  // conversion operator to access the underlying Dbt
221  operator Dbt*();
222  };
223 
224 protected:
225  Db* pdb;
226  std::string strFile;
227  DbTxn* activeTxn;
228  bool fReadOnly;
231 
232 public:
233  explicit BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
234  ~BerkeleyBatch() { Close(); }
235 
236  BerkeleyBatch(const BerkeleyBatch&) = delete;
237  BerkeleyBatch& operator=(const BerkeleyBatch&) = delete;
238 
239  void Flush();
240  void Close();
241  static bool Recover(const fs::path& file_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
242 
243  /* flush the wallet passively (TRY_LOCK)
244  ideal to be called periodically */
245  static bool PeriodicFlush(BerkeleyDatabase& database);
246  /* verifies the database environment */
247  static bool VerifyEnvironment(const fs::path& file_path, std::string& errorStr);
248  /* verifies the database file */
249  static bool VerifyDatabaseFile(const fs::path& file_path, std::string& warningStr, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc);
250 
251  template <typename K, typename T>
252  bool Read(const K& key, T& value)
253  {
254  if (!pdb)
255  return false;
256 
257  // Key
259  ssKey.reserve(1000);
260  ssKey << key;
261  SafeDbt datKey(ssKey.data(), ssKey.size());
262 
263  // Read
264  SafeDbt datValue;
265  int ret = pdb->get(activeTxn, datKey, datValue, 0);
266  bool success = false;
267  if (datValue.get_data() != nullptr) {
268  // Unserialize value
269  try {
270  CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
271  ssValue >> value;
272  success = true;
273  } catch (const std::exception&) {
274  // In this case success remains 'false'
275  }
276  }
277  return ret == 0 && success;
278  }
279 
280  template <typename K, typename T>
281  bool Write(const K& key, const T& value, bool fOverwrite = true)
282  {
283  if (!pdb)
284  return true;
285  if (fReadOnly)
286  assert(!"Write called on database in read-only mode");
287 
288  // Key
290  ssKey.reserve(1000);
291  ssKey << key;
292  SafeDbt datKey(ssKey.data(), ssKey.size());
293 
294  // Value
296  ssValue.reserve(10000);
297  ssValue << value;
298  SafeDbt datValue(ssValue.data(), ssValue.size());
299 
300  // Write
301  int ret = pdb->put(activeTxn, datKey, datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
302  return (ret == 0);
303  }
304 
305  template <typename K>
306  bool Erase(const K& key)
307  {
308  if (!pdb)
309  return false;
310  if (fReadOnly)
311  assert(!"Erase called on database in read-only mode");
312 
313  // Key
315  ssKey.reserve(1000);
316  ssKey << key;
317  SafeDbt datKey(ssKey.data(), ssKey.size());
318 
319  // Erase
320  int ret = pdb->del(activeTxn, datKey, 0);
321  return (ret == 0 || ret == DB_NOTFOUND);
322  }
323 
324  template <typename K>
325  bool Exists(const K& key)
326  {
327  if (!pdb)
328  return false;
329 
330  // Key
332  ssKey.reserve(1000);
333  ssKey << key;
334  SafeDbt datKey(ssKey.data(), ssKey.size());
335 
336  // Exists
337  int ret = pdb->exists(activeTxn, datKey, 0);
338  return (ret == 0);
339  }
340 
341  Dbc* GetCursor()
342  {
343  if (!pdb)
344  return nullptr;
345  Dbc* pcursor = nullptr;
346  int ret = pdb->cursor(nullptr, &pcursor, 0);
347  if (ret != 0)
348  return nullptr;
349  return pcursor;
350  }
351 
352  int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue)
353  {
354  // Read at cursor
355  SafeDbt datKey;
356  SafeDbt datValue;
357  int ret = pcursor->get(datKey, datValue, DB_NEXT);
358  if (ret != 0)
359  return ret;
360  else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr)
361  return 99999;
362 
363  // Convert to streams
364  ssKey.SetType(SER_DISK);
365  ssKey.clear();
366  ssKey.write((char*)datKey.get_data(), datKey.get_size());
367  ssValue.SetType(SER_DISK);
368  ssValue.clear();
369  ssValue.write((char*)datValue.get_data(), datValue.get_size());
370  return 0;
371  }
372 
373  bool TxnBegin()
374  {
375  if (!pdb || activeTxn)
376  return false;
377  DbTxn* ptxn = env->TxnBegin();
378  if (!ptxn)
379  return false;
380  activeTxn = ptxn;
381  return true;
382  }
383 
384  bool TxnCommit()
385  {
386  if (!pdb || !activeTxn)
387  return false;
388  int ret = activeTxn->commit(0);
389  activeTxn = nullptr;
390  return (ret == 0);
391  }
392 
393  bool TxnAbort()
394  {
395  if (!pdb || !activeTxn)
396  return false;
397  int ret = activeTxn->abort();
398  activeTxn = nullptr;
399  return (ret == 0);
400  }
401 
402  bool ReadVersion(int& nVersion)
403  {
404  nVersion = 0;
405  return Read(std::string("version"), nVersion);
406  }
407 
408  bool WriteVersion(int nVersion)
409  {
410  return Write(std::string("version"), nVersion);
411  }
412 
413  bool static Rewrite(BerkeleyDatabase& database, const char* pszSkip = nullptr);
414 };
415 
416 #endif // BITCOIN_WALLET_DB_H
static std::unique_ptr< BerkeleyDatabase > CreateDummy()
Return object for accessing dummy database with no read/write capabilities.
Definition: db.h:145
bool fReadOnly
Definition: db.h:228
static std::unique_ptr< BerkeleyDatabase > CreateMock()
Return object for accessing temporary in-memory database.
Definition: db.h:151
bool IsInitialized() const
Definition: db.h:58
bool fDbEnvInit
Definition: db.h:39
bool TxnCommit()
Definition: db.h:384
VerifyResult
Verify that database file strFile is OK.
Definition: db.h:68
std::unordered_map< std::string, WalletDatabaseFileId > m_fileids
Definition: db.h:49
unsigned int nLastSeen
Definition: db.h:173
bool fFlushOnClose
Definition: db.h:229
bool TxnBegin()
Definition: db.h:373
bool Exists(const K &key)
Definition: db.h:325
bool Write(const K &key, const T &value, bool fOverwrite=true)
Definition: db.h:281
std::shared_ptr< BerkeleyEnvironment > GetWalletEnv(const fs::path &wallet_path, std::string &database_filename)
Get BerkeleyEnvironment and database filename given a wallet path.
Definition: db.cpp:98
value_type * data()
Definition: streams.h:303
An instance of this class represents one database.
Definition: db.h:113
bool IsDatabaseLoaded(const std::string &db_filename) const
Definition: db.h:59
Dbc * GetCursor()
Definition: db.h:341
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:203
void write(const char *pch, size_t nSize)
Definition: streams.h:436
fs::path Directory() const
Definition: db.h:60
u_int32_t get_size() const
Definition: db.cpp:318
int ReadAtCursor(Dbc *pcursor, CDataStream &ssKey, CDataStream &ssValue)
Definition: db.h:352
DbTxn * TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
Definition: db.h:91
std::shared_ptr< BerkeleyEnvironment > env
Pointer to shared database environment.
Definition: db.h:186
std::map< std::string, int > mapFileUseCount
Definition: db.h:47
std::map< std::string, std::reference_wrapper< BerkeleyDatabase > > m_databases
Definition: db.h:48
std::unique_ptr< DbEnv > dbenv
Definition: db.h:46
bool Erase(const K &key)
Definition: db.h:306
std::pair< std::vector< unsigned char >, std::vector< unsigned char > > KeyValPair
Salvage data from a file that Verify says is bad.
Definition: db.h:80
bool TxnAbort()
Definition: db.h:393
bool Read(const K &key, T &value)
Definition: db.h:252
BerkeleyDatabase(std::shared_ptr< BerkeleyEnvironment > env, std::string filename)
Create DB handle to real database.
Definition: db.h:123
size_type size() const
Definition: streams.h:294
std::string strFile
Definition: db.h:226
~BerkeleyBatch()
Definition: db.h:234
bool WriteVersion(int nVersion)
Definition: db.h:408
BerkeleyDatabase()
Create dummy DB handle.
Definition: db.h:118
DbTxn * activeTxn
Definition: db.h:227
RAII class that provides access to a Berkeley database.
Definition: db.h:202
void Flush()
Definition: db.cpp:596
std::string strFile
Definition: db.h:192
static const unsigned int DEFAULT_WALLET_DBLOGSIZE
Definition: db.h:26
bool operator==(const WalletDatabaseFileId &rhs) const
Definition: db.cpp:50
static std::unique_ptr< BerkeleyDatabase > Create(const fs::path &path)
Return object for accessing database at specified path.
Definition: db.h:138
int flags
Definition: bitcoin-tx.cpp:507
static bool Rewrite(BerkeleyDatabase &database, const char *pszSkip=nullptr)
Definition: db.cpp:676
int64_t nLastWalletUpdate
Definition: db.h:175
void reserve(size_type n)
Definition: streams.h:297
std::string strPath
Definition: db.h:43
fs::path WalletDataFilePath(const fs::path &wallet_path)
Given a wallet directory path or legacy file path, return path to main data file in the wallet databa...
Definition: db.cpp:83
unsigned int nLastFlushed
Definition: db.h:174
BerkeleyEnvironment * env
Definition: db.h:230
u_int8_t value[DB_FILE_ID_LEN]
Definition: db.h:30
Db * pdb
Definition: db.h:225
std::atomic< unsigned int > nUpdateCounter
Definition: db.h:172
bool(* recoverFunc_type)(const fs::path &file_path, std::string &out_backup_filename)
Definition: db.h:71
~BerkeleyDatabase()
Definition: db.h:130
static const bool DEFAULT_WALLET_PRIVDB
Definition: db.h:27
bool ReadVersion(int &nVersion)
Definition: db.h:402
void clear()
Definition: streams.h:300
bool IsMock() const
Definition: db.h:57
bool fMockDb
Definition: db.h:40
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:38
std::unique_ptr< Db > m_db
Database pointer.
Definition: db.h:189
const void * get_data() const
Definition: db.cpp:313
RAII class that automatically cleanses its data on destruction.
Definition: db.h:205
bool IsWalletLoaded(const fs::path &wallet_path)
Return whether a wallet database is currently loaded.
Definition: db.cpp:71
void SetType(int n)
Definition: streams.h:394
std::condition_variable_any m_db_in_use
Definition: db.h:50
bool IsDummy()
Return whether this database handle is a dummy for testing.
Definition: db.h:198