PIVX Core  5.6.99
P2P Digital Currency
db.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2021 The Bitcoin developers
3 // Copyright (c) 2019-2021 The PIVX Core developers
4 // Distributed under the MIT software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 
7 #ifndef PIVX_WALLET_DB_H
8 #define PIVX_WALLET_DB_H
9 
10 #include "clientversion.h"
11 #include "fs.h"
12 #include "serialize.h"
13 #include "streams.h"
14 #include "sync.h"
15 #include "version.h"
16 
17 #include <atomic>
18 #include <map>
19 #include <string>
20 #include <unordered_map>
21 #include <vector>
22 
23 #include <db_cxx.h>
24 
25 static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
26 static const bool DEFAULT_WALLET_PRIVDB = true;
27 
29  u_int8_t value[DB_FILE_ID_LEN];
30  bool operator==(const WalletDatabaseFileId& rhs) const;
31 };
32 
34 {
35 private:
36  bool fDbEnvInit;
37  bool fMockDb;
38  // Don't change into fs::path, as that can result in
39  // shutdown problems/crashes caused by a static initialized internal pointer.
40  std::string strPath;
41 
42 public:
43  std::unique_ptr<DbEnv> dbenv;
44  std::map<std::string, int> mapFileUseCount;
45  std::map<std::string, Db*> mapDb;
46  std::unordered_map<std::string, WalletDatabaseFileId> m_fileids;
47  std::condition_variable_any m_db_in_use;
48 
49  explicit BerkeleyEnvironment(const fs::path& env_directory);
51  void Reset();
52 
53  void MakeMock();
54  bool IsMock() const { return fMockDb; }
55  bool IsInitialized() const { return fDbEnvInit; }
56  fs::path Directory() const { return strPath; }
57 
67  typedef bool (*recoverFunc_type)(const fs::path& file_path, std::string& out_backup_filename);
68  VerifyResult Verify(const std::string& strFile, recoverFunc_type recoverFunc, std::string& out_backup_filename);
69 
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  explicit 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 std::make_unique<BerkeleyDatabase>(path);
129  }
130 
132  static std::unique_ptr<BerkeleyDatabase> CreateDummy()
133  {
134  return std::make_unique<BerkeleyDatabase>();
135  }
136 
138  static std::unique_ptr<BerkeleyDatabase> CreateMock()
139  {
140  return std::make_unique<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  fs::path GetPathToFile() { return env->Directory() / strFile; }
164 
165 private:
168  std::string strFile;
169 
174  bool IsDummy() { return env == nullptr; }
175 };
176 
177 
180 {
181 protected:
182  Db* pdb;
183  std::string strFile;
184  DbTxn* activeTxn;
185  bool fReadOnly;
188 
189 public:
190  explicit BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode = "r+", bool fFlushOnCloseIn=true);
192 
193  BerkeleyBatch(const BerkeleyBatch&) = delete;
195 
196  void Flush();
197  void Close();
198  static bool Recover(const fs::path& file_path, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename);
199 
200  /* flush the wallet passively (TRY_LOCK)
201  ideal to be called periodically */
202  static bool PeriodicFlush(BerkeleyDatabase& database);
203  /* verifies the database environment */
204  static bool VerifyEnvironment(const fs::path& file_path, std::string& errorStr);
205  /* verifies the database file */
206  static bool VerifyDatabaseFile(const fs::path& file_path, std::string& warningStr, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc);
207 
208 public:
209  template <typename K, typename T>
210  bool Read(const K& key, T& value)
211  {
212  if (!pdb)
213  return false;
214 
215  // Key
216  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
217  ssKey.reserve(1000);
218  ssKey << key;
219  Dbt datKey(ssKey.data(), ssKey.size());
220 
221  // Read
222  Dbt datValue;
223  datValue.set_flags(DB_DBT_MALLOC);
224  int ret = pdb->get(activeTxn, &datKey, &datValue, 0);
225  memory_cleanse(datKey.get_data(), datKey.get_size());
226  bool success = false;
227  if (datValue.get_data() != nullptr) {
228  // Unserialize value
229  try {
230  CDataStream ssValue((char*)datValue.get_data(), (char*)datValue.get_data() + datValue.get_size(), SER_DISK, CLIENT_VERSION);
231  ssValue >> value;
232  success = true;
233  } catch (const std::exception&) {
234  // In this case success remains 'false'
235  }
236 
237  // Clear and free memory
238  memory_cleanse(datValue.get_data(), datValue.get_size());
239  free(datValue.get_data());
240  }
241  return ret == 0 && success;
242  }
243 
244  template <typename K, typename T>
245  bool Write(const K& key, const T& value, bool fOverwrite = true)
246  {
247  if (!pdb)
248  return true;
249  if (fReadOnly)
250  assert(!"Write called on database in read-only mode");
251 
252  // Key
253  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
254  ssKey.reserve(1000);
255  ssKey << key;
256  Dbt datKey(ssKey.data(), ssKey.size());
257 
258  // Value
259  CDataStream ssValue(SER_DISK, CLIENT_VERSION);
260  ssValue.reserve(10000);
261  ssValue << value;
262  Dbt datValue(ssValue.data(), ssValue.size());
263 
264  // Write
265  int ret = pdb->put(activeTxn, &datKey, &datValue, (fOverwrite ? 0 : DB_NOOVERWRITE));
266 
267  // Clear memory in case it was a private key
268  memory_cleanse(datKey.get_data(), datKey.get_size());
269  memory_cleanse(datValue.get_data(), datValue.get_size());
270  return (ret == 0);
271  }
272 
273  template <typename K>
274  bool Erase(const K& key)
275  {
276  if (!pdb)
277  return false;
278  if (fReadOnly)
279  assert(!"Erase called on database in read-only mode");
280 
281  // Key
282  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
283  ssKey.reserve(1000);
284  ssKey << key;
285  Dbt datKey(ssKey.data(), ssKey.size());
286 
287  // Erase
288  int ret = pdb->del(activeTxn, &datKey, 0);
289 
290  // Clear memory
291  memory_cleanse(datKey.get_data(), datKey.get_size());
292  return (ret == 0 || ret == DB_NOTFOUND);
293  }
294 
295  template <typename K>
296  bool Exists(const K& key)
297  {
298  if (!pdb)
299  return false;
300 
301  // Key
302  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
303  ssKey.reserve(1000);
304  ssKey << key;
305  Dbt datKey(ssKey.data(), ssKey.size());
306 
307  // Exists
308  int ret = pdb->exists(activeTxn, &datKey, 0);
309 
310  // Clear memory
311  memory_cleanse(datKey.get_data(), datKey.get_size());
312  return (ret == 0);
313  }
314 
315  Dbc* GetCursor()
316  {
317  if (!pdb)
318  return nullptr;
319  Dbc* pcursor = nullptr;
320  int ret = pdb->cursor(nullptr, &pcursor, 0);
321  if (ret != 0)
322  return nullptr;
323  return pcursor;
324  }
325 
326  int ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue, bool setRange = false)
327  {
328  // Read at cursor
329  Dbt datKey;
330  unsigned int fFlags = DB_NEXT;
331  if (setRange) {
332  datKey.set_data(ssKey.data());
333  datKey.set_size(ssKey.size());
334  fFlags = DB_SET_RANGE;
335  }
336  Dbt datValue;
337  datKey.set_flags(DB_DBT_MALLOC);
338  datValue.set_flags(DB_DBT_MALLOC);
339  int ret = pcursor->get(&datKey, &datValue, fFlags);
340  if (ret != 0)
341  return ret;
342  else if (datKey.get_data() == nullptr || datValue.get_data() == nullptr)
343  return 99999;
344 
345  // Convert to streams
346  ssKey.SetType(SER_DISK);
347  ssKey.clear();
348  ssKey.write((char*)datKey.get_data(), datKey.get_size());
349  ssValue.SetType(SER_DISK);
350  ssValue.clear();
351  ssValue.write((char*)datValue.get_data(), datValue.get_size());
352 
353  // Clear and free memory
354  memory_cleanse(datKey.get_data(), datKey.get_size());
355  memory_cleanse(datValue.get_data(), datValue.get_size());
356  free(datKey.get_data());
357  free(datValue.get_data());
358  return 0;
359  }
360 
361 public:
362  bool TxnBegin()
363  {
364  if (!pdb || activeTxn)
365  return false;
366  DbTxn* ptxn = env->TxnBegin();
367  if (!ptxn)
368  return false;
369  activeTxn = ptxn;
370  return true;
371  }
372 
373  bool TxnCommit()
374  {
375  if (!pdb || !activeTxn)
376  return false;
377  int ret = activeTxn->commit(0);
378  activeTxn = nullptr;
379  return (ret == 0);
380  }
381 
382  bool TxnAbort()
383  {
384  if (!pdb || !activeTxn)
385  return false;
386  int ret = activeTxn->abort();
387  activeTxn = nullptr;
388  return (ret == 0);
389  }
390 
391  bool ReadVersion(int& nVersion)
392  {
393  nVersion = 0;
394  return Read(std::string("version"), nVersion);
395  }
396 
397  bool WriteVersion(int nVersion)
398  {
399  return Write(std::string("version"), nVersion);
400  }
401 
402  bool static Rewrite(BerkeleyDatabase& database, const char* pszSkip = nullptr);
403 };
404 
405 #endif // PIVX_WALLET_DB_H
RAII class that provides access to a Berkeley database.
Definition: db.h:180
bool WriteVersion(int nVersion)
Definition: db.h:397
std::string strFile
Definition: db.h:183
Dbc * GetCursor()
Definition: db.h:315
bool TxnCommit()
Definition: db.h:373
BerkeleyBatch(const BerkeleyBatch &)=delete
bool ReadVersion(int &nVersion)
Definition: db.h:391
static bool VerifyEnvironment(const fs::path &file_path, std::string &errorStr)
Definition: db.cpp:322
BerkeleyBatch & operator=(const BerkeleyBatch &)=delete
bool Exists(const K &key)
Definition: db.h:296
static bool PeriodicFlush(BerkeleyDatabase &database)
Definition: db.cpp:732
bool TxnBegin()
Definition: db.h:362
static bool VerifyDatabaseFile(const fs::path &file_path, std::string &warningStr, std::string &errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc)
Definition: db.cpp:344
int ReadAtCursor(Dbc *pcursor, CDataStream &ssKey, CDataStream &ssValue, bool setRange=false)
Definition: db.h:326
~BerkeleyBatch()
Definition: db.h:191
bool TxnAbort()
Definition: db.h:382
BerkeleyEnvironment * env
Definition: db.h:187
void Close()
Definition: db.cpp:543
Db * pdb
Definition: db.h:182
DbTxn * activeTxn
Definition: db.h:184
bool fFlushOnClose
Definition: db.h:186
bool Write(const K &key, const T &value, bool fOverwrite=true)
Definition: db.h:245
bool fReadOnly
Definition: db.h:185
void Flush()
Definition: db.cpp:525
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:254
BerkeleyBatch(BerkeleyDatabase &database, const char *pszMode="r+", bool fFlushOnCloseIn=true)
Definition: db.cpp:446
static bool Rewrite(BerkeleyDatabase &database, const char *pszSkip=nullptr)
Definition: db.cpp:602
bool Erase(const K &key)
Definition: db.h:274
bool Read(const K &key, T &value)
Definition: db.h:210
An instance of this class represents one database.
Definition: db.h:105
bool Rewrite(const char *pszSkip=nullptr)
Rewrite the entire database on disk, with the exception of key pszSkip if non-zero.
Definition: db.cpp:772
void Flush(bool shutdown)
Make sure all changes are flushed to disk.
Definition: db.cpp:822
BerkeleyEnvironment * env
BerkeleyDB specific.
Definition: db.h:167
bool Backup(const std::string &strDest)
Back up the entire database to a file.
Definition: db.cpp:777
BerkeleyDatabase(const fs::path &wallet_path, bool mock=false)
Create DB handle to real database.
Definition: db.h:114
void IncrementUpdateCounter()
Definition: db.cpp:538
fs::path GetPathToFile()
Definition: db.h:163
bool IsDummy()
Return whether this database handle is a dummy for testing.
Definition: db.h:174
static std::unique_ptr< BerkeleyDatabase > CreateDummy()
Return object for accessing dummy database with no read/write capabilities.
Definition: db.h:132
std::string strFile
Definition: db.h:168
int64_t nLastWalletUpdate
Definition: db.h:162
unsigned int nLastFlushed
Definition: db.h:161
static std::unique_ptr< BerkeleyDatabase > Create(const fs::path &path)
Return object for accessing database at specified path.
Definition: db.h:126
void ReloadDbEnv()
Definition: db.cpp:841
BerkeleyDatabase()
Create dummy DB handle.
Definition: db.h:109
static std::unique_ptr< BerkeleyDatabase > CreateMock()
Return object for accessing temporary in-memory database.
Definition: db.h:138
std::atomic< unsigned int > nUpdateCounter
Definition: db.h:159
unsigned int nLastSeen
Definition: db.h:160
std::unordered_map< std::string, WalletDatabaseFileId > m_fileids
Definition: db.h:46
bool IsInitialized() const
Definition: db.h:55
std::map< std::string, Db * > mapDb
Definition: db.h:45
void MakeMock()
Definition: db.cpp:205
fs::path Directory() const
Definition: db.h:56
std::map< std::string, int > mapFileUseCount
Definition: db.h:44
bool IsMock() const
Definition: db.h:54
void ReloadDbEnv()
Definition: db.cpp:576
bool Open(bool retry)
Definition: db.cpp:131
bool(* recoverFunc_type)(const fs::path &file_path, std::string &out_backup_filename)
Definition: db.h:67
BerkeleyEnvironment(const fs::path &env_directory)
Definition: db.cpp:121
bool fDbEnvInit
Definition: db.h:36
void Close()
Definition: db.cpp:90
VerifyResult Verify(const std::string &strFile, recoverFunc_type recoverFunc, std::string &out_backup_filename)
Definition: db.cpp:237
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
void Reset()
Definition: db.cpp:114
VerifyResult
Verify that database file strFile is OK.
Definition: db.h:64
std::string strPath
Definition: db.h:40
DbTxn * TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
Definition: db.h:88
std::unique_ptr< DbEnv > dbenv
Definition: db.h:43
std::condition_variable_any m_db_in_use
Definition: db.h:47
void CheckpointLSN(const std::string &strFile)
Definition: db.cpp:437
void Flush(bool fShutdown)
Definition: db.cpp:691
bool Salvage(const std::string &strFile, bool fAggressive, std::vector< KeyValPair > &vResult)
Definition: db.cpp:376
~BerkeleyEnvironment()
Definition: db.cpp:126
bool fMockDb
Definition: db.h:37
void CloseDb(const std::string &strFile)
Definition: db.cpp:562
void SetType(int n)
Definition: streams.h:257
value_type * data()
Definition: streams.h:178
void write(const char *pch, size_t nSize)
Definition: streams.h:302
size_type size() const
Definition: streams.h:165
void reserve(size_type n)
Definition: streams.h:168
void clear()
Definition: streams.h:171
void memory_cleanse(void *ptr, size_t len)
Definition: cleanse.cpp:27
BerkeleyEnvironment * GetWalletEnv(const fs::path &wallet_path, std::string &database_filename)
Get BerkeleyEnvironment and database filename given a wallet path.
Definition: db.cpp:63
#define T(expected, seed, data)
int flags
Definition: pivx-tx.cpp:400
@ SER_DISK
Definition: serialize.h:175
u_int8_t value[DB_FILE_ID_LEN]
Definition: db.h:29
bool operator==(const WalletDatabaseFileId &rhs) const
Definition: db.cpp:58