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