BSHA3  0.17.99
P2P Blockchain, based on Bitcoin
db.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2018 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.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 
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<std::string, int> mapFileUseCount;
46  std::map<std::string, Db*> mapDb;
47  std::unordered_map<std::string, WalletDatabaseFileId> m_fileids;
48  std::condition_variable_any m_db_in_use;
49 
50  BerkeleyEnvironment(const fs::path& env_directory);
52  void Reset();
53 
54  void MakeMock();
55  bool IsMock() const { return fMockDb; }
56  bool IsInitialized() const { return fDbEnvInit; }
57  fs::path Directory() const { return strPath; }
58 
65  enum class VerifyResult { VERIFY_OK,
66  RECOVER_OK,
67  RECOVER_FAIL };
68  typedef bool (*recoverFunc_type)(const fs::path& file_path, std::string& out_backup_filename);
69  VerifyResult Verify(const std::string& strFile, recoverFunc_type recoverFunc, std::string& out_backup_filename);
77  typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
78  bool Salvage(const std::string& strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
79 
80  bool Open(bool retry);
81  void Close();
82  void Flush(bool fShutdown);
83  void CheckpointLSN(const std::string& strFile);
84 
85  void CloseDb(const std::string& strFile);
86  void ReloadDbEnv();
87 
88  DbTxn* TxnBegin(int flags = DB_TXN_WRITE_NOSYNC)
89  {
90  DbTxn* ptxn = nullptr;
91  int ret = dbenv->txn_begin(nullptr, &ptxn, flags);
92  if (!ptxn || ret != 0)
93  return nullptr;
94  return ptxn;
95  }
96 };
97 
99 BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename);
100 
105 {
106  friend class BerkeleyBatch;
107 public:
110  {
111  }
112 
114  BerkeleyDatabase(const fs::path& wallet_path, bool mock = false) :
116  {
117  env = GetWalletEnv(wallet_path, strFile);
118  if (mock) {
119  env->Close();
120  env->Reset();
121  env->MakeMock();
122  }
123  }
124 
126  static std::unique_ptr<BerkeleyDatabase> Create(const fs::path& path)
127  {
128  return MakeUnique<BerkeleyDatabase>(path);
129  }
130 
132  static std::unique_ptr<BerkeleyDatabase> CreateDummy()
133  {
134  return MakeUnique<BerkeleyDatabase>();
135  }
136 
138  static std::unique_ptr<BerkeleyDatabase> CreateMock()
139  {
140  return MakeUnique<BerkeleyDatabase>("", true /* mock */);
141  }
142 
145  bool Rewrite(const char* pszSkip=nullptr);
146 
149  bool Backup(const std::string& strDest);
150 
153  void Flush(bool shutdown);
154 
155  void IncrementUpdateCounter();
156 
157  void ReloadDbEnv();
158 
159  std::atomic<unsigned int> nUpdateCounter;
160  unsigned int nLastSeen;
161  unsigned int nLastFlushed;
163 
164 private:
167  std::string strFile;
168 
173  bool IsDummy() { return env == nullptr; }
174 };
175 
176 
179 {
180 protected:
181  Db* pdb;
182  std::string strFile;
183  DbTxn* activeTxn;
184  bool fReadOnly;
187 
188 public:
189  explicit BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
191 
192  BerkeleyBatch(const BerkeleyBatch&) = delete;
193  BerkeleyBatch& operator=(const BerkeleyBatch&) = delete;
194 
195  void Flush();
196  void Close();
197  static bool Recover(const fs::path& file_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
198 
199  /* flush the wallet passively (TRY_LOCK)
200  ideal to be called periodically */
201  static bool PeriodicFlush(BerkeleyDatabase& database);
202  /* verifies the database environment */
203  static bool VerifyEnvironment(const fs::path& file_path, std::string& errorStr);
204  /* verifies the database file */
205  static bool VerifyDatabaseFile(const fs::path& file_path, std::string& warningStr, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc);
206 
207 public:
208  template <typename K, typename T>
209  bool Read(const K& key, T& value)
210  {
211  if (!pdb)
212  return false;
213 
214  // Key
215  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
216  ssKey.reserve(1000);
217  ssKey << key;
218  Dbt datKey(ssKey.data(), ssKey.size());
219 
220  // Read
221  Dbt datValue;
222  datValue.set_flags(DB_DBT_MALLOC);
223  int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
224  memory_cleanse(datKey.get_data(), datKey.get_size());
225  bool success = false;
226  if (datValue.get_data() != nullptr) {
227  // Unserialize value
228  try {
229  CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
230  ssValue >> value;
231  success = true;
232  } catch (const std::exception&) {
233  // In this case success remains 'false'
234  }
235 
236  // Clear and free memory
237  memory_cleanse(datValue.get_data(), datValue.get_size());
238  free(datValue.get_data());
239  }
240  return ret == 0 && success;
241  }
242 
243  template <typename K, typename T>
244  bool Write(const K& key, const T& value, bool fOverwrite = true)
245  {
246  if (!pdb)
247  return true;
248  if (fReadOnly)
249  assert(!"Write called on database in read-only mode");
250 
251  // Key
252  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
253  ssKey.reserve(1000);
254  ssKey << key;
255  Dbt datKey(ssKey.data(), ssKey.size());
256 
257  // Value
258  CDataStream ssValue(SER_DISK, CLIENT_VERSION);
259  ssValue.reserve(10000);
260  ssValue << value;
261  Dbt datValue(ssValue.data(), ssValue.size());
262 
263  // Write
264  int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
265 
266  // Clear memory in case it was a private key
267  memory_cleanse(datKey.get_data(), datKey.get_size());
268  memory_cleanse(datValue.get_data(), datValue.get_size());
269  return (ret == 0);
270  }
271 
272  template <typename K>
273  bool Erase(const K& key)
274  {
275  if (!pdb)
276  return false;
277  if (fReadOnly)
278  assert(!"Erase called on database in read-only mode");
279 
280  // Key
281  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
282  ssKey.reserve(1000);
283  ssKey << key;
284  Dbt datKey(ssKey.data(), ssKey.size());
285 
286  // Erase
287  int ret = pdb->del(activeTxn, &datKey, 0);
288 
289  // Clear memory
290  memory_cleanse(datKey.get_data(), datKey.get_size());
291  return (ret == 0 || ret == DB_NOTFOUND);
292  }
293 
294  template <typename K>
295  bool Exists(const K& key)
296  {
297  if (!pdb)
298  return false;
299 
300  // Key
301  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
302  ssKey.reserve(1000);
303  ssKey << key;
304  Dbt datKey(ssKey.data(), ssKey.size());
305 
306  // Exists
307  int ret = pdb->exists(activeTxn, &datKey, 0);
308 
309  // Clear memory
310  memory_cleanse(datKey.get_data(), datKey.get_size());
311  return (ret == 0);
312  }
313 
314  Dbc* GetCursor()
315  {
316  if (!pdb)
317  return nullptr;
318  Dbc* pcursor = nullptr;
319  int ret = pdb->cursor(nullptr, &pcursor, 0);
320  if (ret != 0)
321  return nullptr;
322  return pcursor;
323  }
324 
325  int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false)
326  {
327  // Read at cursor
328  Dbt datKey;
329  unsigned int fFlags = DB_NEXT;
330  if (setRange) {
331  datKey.set_data(ssKey.data());
332  datKey.set_size(ssKey.size());
333  fFlags = DB_SET_RANGE;
334  }
335  Dbt datValue;
336  datKey.set_flags(DB_DBT_MALLOC);
337  datValue.set_flags(DB_DBT_MALLOC);
338  int ret = pcursor->get(&datKey, &datValue, fFlags);
339  if (ret != 0)
340  return ret;
341  else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr)
342  return 99999;
343 
344  // Convert to streams
345  ssKey.SetType(SER_DISK);
346  ssKey.clear();
347  ssKey.write((char*)datKey.get_data(), datKey.get_size());
348  ssValue.SetType(SER_DISK);
349  ssValue.clear();
350  ssValue.write((char*)datValue.get_data(), datValue.get_size());
351 
352  // Clear and free memory
353  memory_cleanse(datKey.get_data(), datKey.get_size());
354  memory_cleanse(datValue.get_data(), datValue.get_size());
355  free(datKey.get_data());
356  free(datValue.get_data());
357  return 0;
358  }
359 
360 public:
361  bool TxnBegin()
362  {
363  if (!pdb || activeTxn)
364  return false;
365  DbTxn* ptxn = env->TxnBegin();
366  if (!ptxn)
367  return false;
368  activeTxn = ptxn;
369  return true;
370  }
371 
372  bool TxnCommit()
373  {
374  if (!pdb || !activeTxn)
375  return false;
376  int ret = activeTxn->commit(0);
377  activeTxn = nullptr;
378  return (ret == 0);
379  }
380 
381  bool TxnAbort()
382  {
383  if (!pdb || !activeTxn)
384  return false;
385  int ret = activeTxn->abort();
386  activeTxn = nullptr;
387  return (ret == 0);
388  }
389 
390  bool ReadVersion(int& nVersion)
391  {
392  nVersion = 0;
393  return Read(std::string("version"), nVersion);
394  }
395 
396  bool WriteVersion(int nVersion)
397  {
398  return Write(std::string("version"), nVersion);
399  }
400 
401  bool static Rewrite(BerkeleyDatabase& database, const char* pszSkip = nullptr);
402 };
403 
404 #endif // BITCOIN_WALLET_DB_H
void Flush(bool shutdown)
Make sure all changes are flushed to disk.
Definition: db.cpp:821
static std::unique_ptr< BerkeleyDatabase > CreateDummy()
Return object for accessing dummy database with no read/write capabilities.
Definition: db.h:132
bool fReadOnly
Definition: db.h:184
static std::unique_ptr< BerkeleyDatabase > CreateMock()
Return object for accessing temporary in-memory database.
Definition: db.h:138
bool IsInitialized() const
Definition: db.h:56
bool fDbEnvInit
Definition: db.h:37
void Close()
Definition: db.cpp:86
BerkeleyDatabase(const fs::path &wallet_path, bool mock=false)
Create DB handle to real database.
Definition: db.h:114
bool TxnCommit()
Definition: db.h:372
VerifyResult
Verify that database file strFile is OK.
Definition: db.h:65
std::unordered_map< std::string, WalletDatabaseFileId > m_fileids
Definition: db.h:47
void Close()
Definition: db.cpp:543
unsigned int nLastSeen
Definition: db.h:160
bool fFlushOnClose
Definition: db.h:185
bool TxnBegin()
Definition: db.h:361
UniValue ret(UniValue::VARR)
Definition: rpcwallet.cpp:1140
bool Exists(const K &key)
Definition: db.h:295
bool Write(const K &key, const T &value, bool fOverwrite=true)
Definition: db.h:244
value_type * data()
Definition: streams.h:321
An instance of this class represents one database.
Definition: db.h:104
Dbc * GetCursor()
Definition: db.h:314
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:221
void write(const char *pch, size_t nSize)
Definition: streams.h:454
void ReloadDbEnv()
Definition: db.cpp:840
bool Backup(const std::string &strDest)
Back up the entire database to a file.
Definition: db.cpp:780
fs::path Directory() const
Definition: db.h:57
bool Open(bool retry)
Definition: db.cpp:127
static bool PeriodicFlush(BerkeleyDatabase &database)
Definition: db.cpp:732
std::map< std::string, Db * > mapDb
Definition: db.h:46
DbTxn * TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
Definition: db.h:88
std::map< std::string, int > mapFileUseCount
Definition: db.h:45
std::unique_ptr< DbEnv > dbenv
Definition: db.h:44
void CheckpointLSN(const std::string &strFile)
Definition: db.cpp:437
bool Erase(const K &key)
Definition: db.h:273
std::pair< std::vector< unsigned char >, std::vector< unsigned char > > KeyValPair
Salvage data from a file that Verify says is bad.
Definition: db.h:77
bool TxnAbort()
Definition: db.h:381
bool Read(const K &key, T &value)
Definition: db.h:209
void memory_cleanse(void *ptr, size_t len)
Definition: cleanse.cpp:31
size_type size() const
Definition: streams.h:312
std::string strFile
Definition: db.h:182
BerkeleyEnvironment * GetWalletEnv(const fs::path &wallet_path, std::string &database_filename)
Get BerkeleyEnvironment and database filename given a wallet path.
Definition: db.cpp:59
bool Rewrite(const char *pszSkip=nullptr)
Rewrite the entire database on disk, with the exception of key pszSkip if non-zero.
Definition: db.cpp:775
~BerkeleyBatch()
Definition: db.h:190
bool WriteVersion(int nVersion)
Definition: db.h:396
BerkeleyDatabase()
Create dummy DB handle.
Definition: db.h:109
DbTxn * activeTxn
Definition: db.h:183
void MakeMock()
Definition: db.cpp:201
RAII class that provides access to a Berkeley database.
Definition: db.h:178
void Flush()
Definition: db.cpp:525
std::string strFile
Definition: db.h:167
bool operator==(const WalletDatabaseFileId &rhs) const
Definition: db.cpp:54
static bool VerifyEnvironment(const fs::path &file_path, std::string &errorStr)
Definition: db.cpp:319
BerkeleyEnvironment(const fs::path &env_directory)
Definition: db.cpp:117
static bool Recover(const fs::path &file_path, void *callbackDataIn, bool(*recoverKVcallback)(void *callbackData, CDataStream ssKey, CDataStream ssValue), std::string &out_backup_filename)
Definition: db.cpp:250
static std::unique_ptr< BerkeleyDatabase > Create(const fs::path &path)
Return object for accessing database at specified path.
Definition: db.h:126
bool Salvage(const std::string &strFile, bool fAggressive, std::vector< KeyValPair > &vResult)
Definition: db.cpp:376
void ReloadDbEnv()
Definition: db.cpp:576
static bool Rewrite(BerkeleyDatabase &database, const char *pszSkip=nullptr)
Definition: db.cpp:602
int64_t nLastWalletUpdate
Definition: db.h:162
void IncrementUpdateCounter()
Definition: db.cpp:538
void reserve(size_type n)
Definition: streams.h:315
std::string strPath
Definition: db.h:41
BerkeleyBatch(BerkeleyDatabase &database, const char *pszMode="r+", bool fFlushOnCloseIn=true)
Definition: db.cpp:446
unsigned int nLastFlushed
Definition: db.h:161
int ReadAtCursor(Dbc *pcursor, CDataStream &ssKey, CDataStream &ssValue, bool setRange=false)
Definition: db.h:325
BerkeleyEnvironment * env
Definition: db.h:186
u_int8_t value[DB_FILE_ID_LEN]
Definition: db.h:30
void Flush(bool fShutdown)
Definition: db.cpp:691
Db * pdb
Definition: db.h:181
std::atomic< unsigned int > nUpdateCounter
Definition: db.h:159
bool(* recoverFunc_type)(const fs::path &file_path, std::string &out_backup_filename)
Definition: db.h:68
VerifyResult Verify(const std::string &strFile, recoverFunc_type recoverFunc, std::string &out_backup_filename)
Definition: db.cpp:233
bool ReadVersion(int &nVersion)
Definition: db.h:390
void clear()
Definition: streams.h:318
static bool VerifyDatabaseFile(const fs::path &file_path, std::string &warningStr, std::string &errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc)
Definition: db.cpp:343
void Reset()
Definition: db.cpp:110
int flags
Definition: bsha3-tx.cpp:509
void CloseDb(const std::string &strFile)
Definition: db.cpp:562
bool IsMock() const
Definition: db.h:55
~BerkeleyEnvironment()
Definition: db.cpp:122
BerkeleyEnvironment * env
BerkeleyDB specific.
Definition: db.h:166
bool fMockDb
Definition: db.h:38
BerkeleyBatch & operator=(const BerkeleyBatch &)=delete
void SetType(int n)
Definition: streams.h:412
std::condition_variable_any m_db_in_use
Definition: db.h:48
bool IsDummy()
Return whether this database handle is a dummy for testing.
Definition: db.h:173