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