Fabcoin Core  0.16.2
P2P Digital Currency
dbwrapper.h
Go to the documentation of this file.
1 // Copyright (c) 2012-2017 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 FABCOIN_DBWRAPPER_H
6 #define FABCOIN_DBWRAPPER_H
7 
8 #include <clientversion.h>
9 #include <fs.h>
10 #include <serialize.h>
11 #include <streams.h>
12 #include <util.h>
13 #include <utilstrencodings.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  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  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();
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::vector<unsigned char> obfuscate_key;
203 
205  static const std::string OBFUSCATE_KEY_KEY;
206 
208  static const unsigned int OBFUSCATE_KEY_NUM_BYTES;
209 
210  std::vector<unsigned char> CreateObfuscateKey() const;
211 
212 public:
221  CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
222  ~CDBWrapper();
223 
224  template <typename K, typename V>
225  bool Read(const K& key, V& value) const
226  {
227  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
228  ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
229  ssKey << key;
230  leveldb::Slice slKey(ssKey.data(), ssKey.size());
231 
232  std::string strValue;
233  leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
234  if (!status.ok()) {
235  if (status.IsNotFound())
236  return false;
237  LogPrintf("LevelDB read failure: %s\n", status.ToString());
239  }
240  try {
241  CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION);
242  ssValue.Xor(obfuscate_key);
243  ssValue >> value;
244  } catch (const std::exception&) {
245  return false;
246  }
247  return true;
248  }
249 
250  template <typename K, typename V>
251  bool Write(const K& key, const V& value, bool fSync = false)
252  {
253  CDBBatch batch(*this);
254  batch.Write(key, value);
255  return WriteBatch(batch, fSync);
256  }
257 
258  template <typename K>
259  bool Exists(const K& key) const
260  {
261  CDataStream ssKey(SER_DISK, CLIENT_VERSION);
262  ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
263  ssKey << key;
264  leveldb::Slice slKey(ssKey.data(), ssKey.size());
265 
266  std::string strValue;
267  leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
268  if (!status.ok()) {
269  if (status.IsNotFound())
270  return false;
271  LogPrintf("LevelDB read failure: %s\n", status.ToString());
273  }
274  return true;
275  }
276 
277  template <typename K>
278  bool Erase(const K& key, bool fSync = false)
279  {
280  CDBBatch batch(*this);
281  batch.Erase(key);
282  return WriteBatch(batch, fSync);
283  }
284 
285  bool WriteBatch(CDBBatch& batch, bool fSync = false);
286 
287  // not available for LevelDB; provide for compatibility with BDB
288  bool Flush()
289  {
290  return true;
291  }
292 
293  bool Sync()
294  {
295  CDBBatch batch(*this);
296  return WriteBatch(batch, true);
297  }
298 
300  {
301  return new CDBIterator(*this, pdb->NewIterator(iteroptions));
302  }
303 
307  bool IsEmpty();
308 
309  template<typename K>
310  size_t EstimateSize(const K& key_begin, const K& key_end) const
311  {
312  CDataStream ssKey1(SER_DISK, CLIENT_VERSION), ssKey2(SER_DISK, CLIENT_VERSION);
313  ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
314  ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
315  ssKey1 << key_begin;
316  ssKey2 << key_end;
317  leveldb::Slice slKey1(ssKey1.data(), ssKey1.size());
318  leveldb::Slice slKey2(ssKey2.data(), ssKey2.size());
319  uint64_t size = 0;
320  leveldb::Range range(slKey1, slKey2);
321  pdb->GetApproximateSizes(&range, 1, &size);
322  return size;
323  }
324 
328  template<typename K>
329  void CompactRange(const K& key_begin, const K& key_end) const
330  {
331  CDataStream ssKey1(SER_DISK, CLIENT_VERSION), ssKey2(SER_DISK, CLIENT_VERSION);
332  ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
333  ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
334  ssKey1 << key_begin;
335  ssKey2 << key_end;
336  leveldb::Slice slKey1(ssKey1.data(), ssKey1.size());
337  leveldb::Slice slKey2(ssKey2.data(), ssKey2.size());
338  pdb->CompactRange(&slKey1, &slKey2);
339  }
340 
341 };
342 
343 #endif // FABCOIN_DBWRAPPER_H
bool GetKey(K &key)
Definition: dbwrapper.h:147
dbwrapper_error(const std::string &msg)
Definition: dbwrapper.h:25
bool Flush()
Definition: dbwrapper.h:288
These should be considered an implementation detail of the specific database.
Definition: dbwrapper.cpp:197
void Clear()
Definition: dbwrapper.h:66
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:47
Definition: util.h:95
size_t size_estimate
Definition: dbwrapper.h:58
void Erase(const K &key)
Definition: dbwrapper.h:98
size_t SizeEstimate() const
Definition: dbwrapper.h:114
void Xor(const std::vector< unsigned char > &key)
XOR the contents of this stream with a certain key.
Definition: streams.h:421
value_type * data()
Definition: streams.h:246
std::hash for asio::adress
Definition: Common.h:323
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:146
void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
Definition: dbwrapper.cpp:199
leveldb::WriteBatch batch
Definition: dbwrapper.h:53
CDBIterator * NewIterator()
Definition: dbwrapper.h:299
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
#define LogPrintf(...)
Definition: util.h:153
const CDBWrapper & parent
Definition: dbwrapper.h:52
bool Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:278
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
size_type size() const
Definition: streams.h:237
size_t EstimateSize(const K &key_begin, const K &key_end) const
Definition: dbwrapper.h:310
void Write(const K &key, const V &value)
Definition: dbwrapper.h:73
leveldb::WriteOptions writeoptions
options used when writing to the database
Definition: dbwrapper.h:193
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:213
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:208
bool Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:251
leveldb::Env * penv
custom environment this database is using (may be nullptr in case of default environment) ...
Definition: dbwrapper.h:181
void CompactRange(const K &key_begin, const K &key_end) const
Compact a certain range of keys in the database.
Definition: dbwrapper.h:329
CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter)
Definition: dbwrapper.h:129
void reserve(size_type n)
Definition: streams.h:240
uint8_t const size_t const size
Definition: sha3.h:20
static const std::string OBFUSCATE_KEY_KEY
the key under which the obfuscation key is stored
Definition: dbwrapper.h:205
CDataStream ssKey
Definition: dbwrapper.h:55
bool Sync()
Definition: dbwrapper.h:293
void Seek(const K &key)
Definition: dbwrapper.h:137
CDBBatch(const CDBWrapper &_parent)
Definition: dbwrapper.h:64
CDataStream ssValue
Definition: dbwrapper.h:56
bool Exists(const K &key) const
Definition: dbwrapper.h:259
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:225
void clear()
Definition: streams.h:243
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:202