Bitcoin Core  0.19.99
P2P Digital Currency
dbwrapper.h
Go to the documentation of this file.
1 // Copyright (c) 2012-2019 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #ifndef BITCOIN_DBWRAPPER_H
6 #define BITCOIN_DBWRAPPER_H
7 
8 #include <clientversion.h>
9 #include <fs.h>
10 #include <serialize.h>
11 #include <streams.h>
12 #include <util/system.h>
13 #include <util/strencodings.h>
14 
15 #include <leveldb/db.h>
16 #include <leveldb/write_batch.h>
17 
18 static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
19 static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
20 
21 class dbwrapper_error : public std::runtime_error
22 {
23 public:
24  explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
25 };
26 
27 class CDBWrapper;
28 
31 namespace dbwrapper_private {
32 
35 void HandleError(const leveldb::Status& status);
36 
41 const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w);
42 
43 };
44 
46 class CDBBatch
47 {
48  friend class CDBWrapper;
49 
50 private:
52  leveldb::WriteBatch batch;
53 
56 
57  size_t size_estimate;
58 
59 public:
63  explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0) { };
64 
65  void Clear()
66  {
67  batch.Clear();
68  size_estimate = 0;
69  }
70 
71  template <typename K, typename V>
72  void Write(const K& key, const V& value)
73  {
75  ssKey << key;
76  leveldb::Slice slKey(ssKey.data(), ssKey.size());
77 
79  ssValue << value;
80  ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
81  leveldb::Slice slValue(ssValue.data(), ssValue.size());
82 
83  batch.Put(slKey, slValue);
84  // LevelDB serializes writes as:
85  // - byte: header
86  // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...)
87  // - byte[]: key
88  // - varint: value length
89  // - byte[]: value
90  // The formula below assumes the key and value are both less than 16k.
91  size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size();
92  ssKey.clear();
93  ssValue.clear();
94  }
95 
96  template <typename K>
97  void Erase(const K& key)
98  {
100  ssKey << key;
101  leveldb::Slice slKey(ssKey.data(), ssKey.size());
102 
103  batch.Delete(slKey);
104  // LevelDB serializes erases as:
105  // - byte: header
106  // - varint: key length
107  // - byte[]: key
108  // The formula below assumes the key is less than 16kB.
109  size_estimate += 2 + (slKey.size() > 127) + slKey.size();
110  ssKey.clear();
111  }
112 
113  size_t SizeEstimate() const { return size_estimate; }
114 };
115 
117 {
118 private:
120  leveldb::Iterator *piter;
121 
122 public:
123 
128  CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) :
129  parent(_parent), piter(_piter) { };
130  ~CDBIterator();
131 
132  bool Valid() const;
133 
134  void SeekToFirst();
135 
136  template<typename K> void Seek(const K& key) {
139  ssKey << key;
140  leveldb::Slice slKey(ssKey.data(), ssKey.size());
141  piter->Seek(slKey);
142  }
143 
144  void Next();
145 
146  template<typename K> bool GetKey(K& key) {
147  leveldb::Slice slKey = piter->key();
148  try {
149  CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
150  ssKey >> key;
151  } catch (const std::exception&) {
152  return false;
153  }
154  return true;
155  }
156 
157  template<typename V> bool GetValue(V& value) {
158  leveldb::Slice slValue = piter->value();
159  try {
160  CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(), SER_DISK, CLIENT_VERSION);
161  ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
162  ssValue >> value;
163  } catch (const std::exception&) {
164  return false;
165  }
166  return true;
167  }
168 
169  unsigned int GetValueSize() {
170  return piter->value().size();
171  }
172 
173 };
174 
176 {
177  friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w);
178 private:
180  leveldb::Env* penv;
181 
183  leveldb::Options options;
184 
186  leveldb::ReadOptions readoptions;
187 
189  leveldb::ReadOptions iteroptions;
190 
192  leveldb::WriteOptions writeoptions;
193 
195  leveldb::WriteOptions syncoptions;
196 
198  leveldb::DB* pdb;
199 
201  std::string m_name;
202 
204  std::vector<unsigned char> obfuscate_key;
205 
207  static const std::string OBFUSCATE_KEY_KEY;
208 
210  static const unsigned int OBFUSCATE_KEY_NUM_BYTES;
211 
212  std::vector<unsigned char> CreateObfuscateKey() const;
213 
214 public:
223  CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
224  ~CDBWrapper();
225 
226  CDBWrapper(const CDBWrapper&) = delete;
227  CDBWrapper& operator=(const CDBWrapper&) = delete;
228 
229  template <typename K, typename V>
230  bool Read(const K& key, V& value) const
231  {
234  ssKey << key;
235  leveldb::Slice slKey(ssKey.data(), ssKey.size());
236 
237  std::string strValue;
238  leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
239  if (!status.ok()) {
240  if (status.IsNotFound())
241  return false;
242  LogPrintf("LevelDB read failure: %s\n", status.ToString());
244  }
245  try {
246  CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
247  ssValue.Xor(obfuscate_key);
248  ssValue >> value;
249  } catch (const std::exception&) {
250  return false;
251  }
252  return true;
253  }
254 
255  template <typename K, typename V>
256  bool Write(const K& key, const V& value, bool fSync = false)
257  {
258  CDBBatch batch(*this);
259  batch.Write(key, value);
260  return WriteBatch(batch, fSync);
261  }
262 
263  template <typename K>
264  bool Exists(const K& key) const
265  {
268  ssKey << key;
269  leveldb::Slice slKey(ssKey.data(), ssKey.size());
270 
271  std::string strValue;
272  leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
273  if (!status.ok()) {
274  if (status.IsNotFound())
275  return false;
276  LogPrintf("LevelDB read failure: %s\n", status.ToString());
278  }
279  return true;
280  }
281 
282  template <typename K>
283  bool Erase(const K& key, bool fSync = false)
284  {
285  CDBBatch batch(*this);
286  batch.Erase(key);
287  return WriteBatch(batch, fSync);
288  }
289 
290  bool WriteBatch(CDBBatch& batch, bool fSync = false);
291 
292  // Get an estimate of LevelDB memory usage (in bytes).
293  size_t DynamicMemoryUsage() const;
294 
295  // not available for LevelDB; provide for compatibility with BDB
296  bool Flush()
297  {
298  return true;
299  }
300 
301  bool Sync()
302  {
303  CDBBatch batch(*this);
304  return WriteBatch(batch, true);
305  }
306 
308  {
309  return new CDBIterator(*this, pdb->NewIterator(iteroptions));
310  }
311 
315  bool IsEmpty();
316 
317  template<typename K>
318  size_t EstimateSize(const K& key_begin, const K& key_end) const
319  {
321  ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
323  ssKey1 << key_begin;
324  ssKey2 << key_end;
325  leveldb::Slice slKey1(ssKey1.data(), ssKey1.size());
326  leveldb::Slice slKey2(ssKey2.data(), ssKey2.size());
327  uint64_t size = 0;
328  leveldb::Range range(slKey1, slKey2);
329  pdb->GetApproximateSizes(&range, 1, &size);
330  return size;
331  }
332 
336  template<typename K>
337  void CompactRange(const K& key_begin, const K& key_end) const
338  {
340  ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
342  ssKey1 << key_begin;
343  ssKey2 << key_end;
344  leveldb::Slice slKey1(ssKey1.data(), ssKey1.size());
345  leveldb::Slice slKey2(ssKey2.data(), ssKey2.size());
346  pdb->CompactRange(&slKey1, &slKey2);
347  }
348 
349 };
350 
351 #endif // BITCOIN_DBWRAPPER_H
bool Exists(const K &key) const
Definition: dbwrapper.h:264
bool GetKey(K &key)
Definition: dbwrapper.h:146
dbwrapper_error(const std::string &msg)
Definition: dbwrapper.h:24
bool Flush()
Definition: dbwrapper.h:296
These should be considered an implementation detail of the specific database.
Definition: dbwrapper.cpp:241
void Clear()
Definition: dbwrapper.h:65
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:46
size_t size_estimate
Definition: dbwrapper.h:57
void Erase(const K &key)
Definition: dbwrapper.h:97
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE
Definition: dbwrapper.h:18
void Xor(const std::vector< unsigned char > &key)
XOR the contents of this stream with a certain key.
Definition: streams.h:474
value_type * data()
Definition: streams.h:301
static void LogPrintf(const char *fmt, const Args &... args)
Definition: logging.h:163
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:201
void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
Definition: dbwrapper.cpp:243
leveldb::WriteBatch batch
Definition: dbwrapper.h:52
CDBIterator * NewIterator()
Definition: dbwrapper.h:307
leveldb::ReadOptions readoptions
options used when reading from the database
Definition: dbwrapper.h:186
const CDBWrapper & parent
Definition: dbwrapper.h:119
bool GetValue(V &value)
Definition: dbwrapper.h:157
leveldb::WriteOptions syncoptions
options used when sync writing to the database
Definition: dbwrapper.h:195
const CDBWrapper & parent
Definition: dbwrapper.h:51
size_type size() const
Definition: streams.h:292
bool Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:283
leveldb::DB * pdb
the database itself
Definition: dbwrapper.h:198
leveldb::ReadOptions iteroptions
options used when iterating over values of the database
Definition: dbwrapper.h:189
void Write(const K &key, const V &value)
Definition: dbwrapper.h:72
size_t SizeEstimate() const
Definition: dbwrapper.h:113
leveldb::WriteOptions writeoptions
options used when writing to the database
Definition: dbwrapper.h:192
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:230
unsigned int GetValueSize()
Definition: dbwrapper.h:169
const std::vector< unsigned char > & GetObfuscateKey(const CDBWrapper &w)
Work around circular dependency, as well as for testing in dbwrapper_tests.
Definition: dbwrapper.cpp:253
leveldb::Iterator * piter
Definition: dbwrapper.h:120
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE
Definition: dbwrapper.h:19
static const unsigned int OBFUSCATE_KEY_NUM_BYTES
the length of the obfuscate key in number of bytes
Definition: dbwrapper.h:210
bool Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:256
void CompactRange(const K &key_begin, const K &key_end) const
Compact a certain range of keys in the database.
Definition: dbwrapper.h:337
std::string m_name
the name of this database
Definition: dbwrapper.h:201
leveldb::Env * penv
custom environment this database is using (may be nullptr in case of default environment) ...
Definition: dbwrapper.h:180
CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter)
Definition: dbwrapper.h:128
void reserve(size_type n)
Definition: streams.h:295
static const std::string OBFUSCATE_KEY_KEY
the key under which the obfuscation key is stored
Definition: dbwrapper.h:207
CDataStream ssKey
Definition: dbwrapper.h:54
bool Sync()
Definition: dbwrapper.h:301
void Seek(const K &key)
Definition: dbwrapper.h:136
CDBBatch(const CDBWrapper &_parent)
Definition: dbwrapper.h:63
CDataStream ssValue
Definition: dbwrapper.h:55
void clear()
Definition: streams.h:298
leveldb::Options options
database options used
Definition: dbwrapper.h:183
std::vector< unsigned char > obfuscate_key
a key used for optional XOR-obfuscation of the database
Definition: dbwrapper.h:204
size_t EstimateSize(const K &key_begin, const K &key_end) const
Definition: dbwrapper.h:318
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:38