Bitcoin Core  24.1.0
P2P Digital Currency
dbwrapper.h
Go to the documentation of this file.
1 // Copyright (c) 2012-2021 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 <logging.h>
11 #include <serialize.h>
12 #include <span.h>
13 #include <streams.h>
14 
15 #include <cstddef>
16 #include <cstdint>
17 #include <exception>
18 #include <leveldb/db.h>
19 #include <leveldb/iterator.h>
20 #include <leveldb/options.h>
21 #include <leveldb/slice.h>
22 #include <leveldb/status.h>
23 #include <leveldb/write_batch.h>
24 #include <stdexcept>
25 #include <string>
26 #include <vector>
27 namespace leveldb {
28 class Env;
29 }
30 
31 static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
32 static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
33 
34 class dbwrapper_error : public std::runtime_error
35 {
36 public:
37  explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
38 };
39 
40 class CDBWrapper;
41 
44 namespace dbwrapper_private {
45 
48 void HandleError(const leveldb::Status& status);
49 
54 const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w);
55 
56 };
57 
59 class CDBBatch
60 {
61  friend class CDBWrapper;
62 
63 private:
65  leveldb::WriteBatch batch;
66 
69 
70  size_t size_estimate;
71 
72 public:
77 
78  void Clear()
79  {
80  batch.Clear();
81  size_estimate = 0;
82  }
83 
84  template <typename K, typename V>
85  void Write(const K& key, const V& value)
86  {
88  ssKey << key;
89  leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
90 
92  ssValue << value;
94  leveldb::Slice slValue((const char*)ssValue.data(), ssValue.size());
95 
96  batch.Put(slKey, slValue);
97  // LevelDB serializes writes as:
98  // - byte: header
99  // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...)
100  // - byte[]: key
101  // - varint: value length
102  // - byte[]: value
103  // The formula below assumes the key and value are both less than 16k.
104  size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size();
105  ssKey.clear();
106  ssValue.clear();
107  }
108 
109  template <typename K>
110  void Erase(const K& key)
111  {
113  ssKey << key;
114  leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
115 
116  batch.Delete(slKey);
117  // LevelDB serializes erases as:
118  // - byte: header
119  // - varint: key length
120  // - byte[]: key
121  // The formula below assumes the key is less than 16kB.
122  size_estimate += 2 + (slKey.size() > 127) + slKey.size();
123  ssKey.clear();
124  }
125 
126  size_t SizeEstimate() const { return size_estimate; }
127 };
128 
130 {
131 private:
133  leveldb::Iterator *piter;
134 
135 public:
136 
141  CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) :
142  parent(_parent), piter(_piter) { };
143  ~CDBIterator();
144 
145  bool Valid() const;
146 
147  void SeekToFirst();
148 
149  template<typename K> void Seek(const K& key) {
152  ssKey << key;
153  leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
154  piter->Seek(slKey);
155  }
156 
157  void Next();
158 
159  template<typename K> bool GetKey(K& key) {
160  leveldb::Slice slKey = piter->key();
161  try {
163  ssKey >> key;
164  } catch (const std::exception&) {
165  return false;
166  }
167  return true;
168  }
169 
170  template<typename V> bool GetValue(V& value) {
171  leveldb::Slice slValue = piter->value();
172  try {
173  CDataStream ssValue{MakeByteSpan(slValue), SER_DISK, CLIENT_VERSION};
175  ssValue >> value;
176  } catch (const std::exception&) {
177  return false;
178  }
179  return true;
180  }
181 };
182 
184 {
185  friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w);
186 private:
188  leveldb::Env* penv;
189 
191  leveldb::Options options;
192 
194  leveldb::ReadOptions readoptions;
195 
197  leveldb::ReadOptions iteroptions;
198 
200  leveldb::WriteOptions writeoptions;
201 
203  leveldb::WriteOptions syncoptions;
204 
206  leveldb::DB* pdb;
207 
209  std::string m_name;
210 
212  std::vector<unsigned char> obfuscate_key;
213 
215  static const std::string OBFUSCATE_KEY_KEY;
216 
218  static const unsigned int OBFUSCATE_KEY_NUM_BYTES;
219 
220  std::vector<unsigned char> CreateObfuscateKey() const;
221 
222 public:
231  CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false, bool obfuscate = false);
232  ~CDBWrapper();
233 
234  CDBWrapper(const CDBWrapper&) = delete;
235  CDBWrapper& operator=(const CDBWrapper&) = delete;
236 
237  template <typename K, typename V>
238  bool Read(const K& key, V& value) const
239  {
242  ssKey << key;
243  leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
244 
245  std::string strValue;
246  leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
247  if (!status.ok()) {
248  if (status.IsNotFound())
249  return false;
250  LogPrintf("LevelDB read failure: %s\n", status.ToString());
252  }
253  try {
254  CDataStream ssValue{MakeByteSpan(strValue), SER_DISK, CLIENT_VERSION};
255  ssValue.Xor(obfuscate_key);
256  ssValue >> value;
257  } catch (const std::exception&) {
258  return false;
259  }
260  return true;
261  }
262 
263  template <typename K, typename V>
264  bool Write(const K& key, const V& value, bool fSync = false)
265  {
266  CDBBatch batch(*this);
267  batch.Write(key, value);
268  return WriteBatch(batch, fSync);
269  }
270 
271  template <typename K>
272  bool Exists(const K& key) const
273  {
276  ssKey << key;
277  leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
278 
279  std::string strValue;
280  leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
281  if (!status.ok()) {
282  if (status.IsNotFound())
283  return false;
284  LogPrintf("LevelDB read failure: %s\n", status.ToString());
286  }
287  return true;
288  }
289 
290  template <typename K>
291  bool Erase(const K& key, bool fSync = false)
292  {
293  CDBBatch batch(*this);
294  batch.Erase(key);
295  return WriteBatch(batch, fSync);
296  }
297 
298  bool WriteBatch(CDBBatch& batch, bool fSync = false);
299 
300  // Get an estimate of LevelDB memory usage (in bytes).
301  size_t DynamicMemoryUsage() const;
302 
304  {
305  return new CDBIterator(*this, pdb->NewIterator(iteroptions));
306  }
307 
311  bool IsEmpty();
312 
313  template<typename K>
314  size_t EstimateSize(const K& key_begin, const K& key_end) const
315  {
317  ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
319  ssKey1 << key_begin;
320  ssKey2 << key_end;
321  leveldb::Slice slKey1((const char*)ssKey1.data(), ssKey1.size());
322  leveldb::Slice slKey2((const char*)ssKey2.data(), ssKey2.size());
323  uint64_t size = 0;
324  leveldb::Range range(slKey1, slKey2);
325  pdb->GetApproximateSizes(&range, 1, &size);
326  return size;
327  }
328 };
329 
330 #endif // BITCOIN_DBWRAPPER_H
bool Exists(const K &key) const
Definition: dbwrapper.h:272
bool GetKey(K &key)
Definition: dbwrapper.h:159
dbwrapper_error(const std::string &msg)
Definition: dbwrapper.h:37
These should be considered an implementation detail of the specific database.
Definition: dbwrapper.cpp:259
void Clear()
Definition: dbwrapper.h:78
void SeekToFirst()
Definition: dbwrapper.cpp:256
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:59
CDBWrapper(const fs::path &path, size_t nCacheSize, bool fMemory=false, bool fWipe=false, bool obfuscate=false)
Definition: dbwrapper.cpp:130
size_t size_estimate
Definition: dbwrapper.h:70
void Erase(const K &key)
Definition: dbwrapper.h:110
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE
Definition: dbwrapper.h:31
void Xor(const std::vector< unsigned char > &key)
XOR the contents of this stream with a certain key.
Definition: streams.h:348
value_type * data()
Definition: streams.h:244
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:185
void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
Definition: dbwrapper.cpp:261
leveldb::WriteBatch batch
Definition: dbwrapper.h:65
std::vector< unsigned char > CreateObfuscateKey() const
Returns a string (consisting of 8 random bytes) suitable for use as an obfuscating XOR key...
Definition: dbwrapper.cpp:240
CDBIterator * NewIterator()
Definition: dbwrapper.h:303
leveldb::ReadOptions readoptions
options used when reading from the database
Definition: dbwrapper.h:194
size_t DynamicMemoryUsage() const
Definition: dbwrapper.cpp:217
const CDBWrapper & parent
Definition: dbwrapper.h:132
bool GetValue(V &value)
Definition: dbwrapper.h:170
leveldb::WriteOptions syncoptions
options used when sync writing to the database
Definition: dbwrapper.h:203
const CDBWrapper & parent
Definition: dbwrapper.h:64
CDBWrapper & operator=(const CDBWrapper &)=delete
size_type size() const
Definition: streams.h:237
bool Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:291
leveldb::DB * pdb
the database itself
Definition: dbwrapper.h:206
leveldb::ReadOptions iteroptions
options used when iterating over values of the database
Definition: dbwrapper.h:197
void Write(const K &key, const V &value)
Definition: dbwrapper.h:85
size_t SizeEstimate() const
Definition: dbwrapper.h:126
leveldb::WriteOptions writeoptions
options used when writing to the database
Definition: dbwrapper.h:200
bool IsEmpty()
Return true if the database managed by this class contains no entries.
Definition: dbwrapper.cpp:247
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:238
const std::vector< unsigned char > & GetObfuscateKey(const CDBWrapper &w)
Work around circular dependency, as well as for testing in dbwrapper_tests.
Definition: dbwrapper.cpp:271
leveldb::Iterator * piter
Definition: dbwrapper.h:133
void Next()
Definition: dbwrapper.cpp:257
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE
Definition: dbwrapper.h:32
static const unsigned int OBFUSCATE_KEY_NUM_BYTES
the length of the obfuscate key in number of bytes
Definition: dbwrapper.h:218
bool Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:264
std::string m_name
the name of this database
Definition: dbwrapper.h:209
leveldb::Env * penv
custom environment this database is using (may be nullptr in case of default environment) ...
Definition: dbwrapper.h:188
CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter)
Definition: dbwrapper.h:141
void reserve(size_type n)
Definition: streams.h:240
static const std::string OBFUSCATE_KEY_KEY
the key under which the obfuscation key is stored
Definition: dbwrapper.h:215
Span< const std::byte > MakeByteSpan(V &&v) noexcept
Definition: span.h:264
CDataStream ssKey
Definition: dbwrapper.h:67
void Seek(const K &key)
Definition: dbwrapper.h:149
CDBBatch(const CDBWrapper &_parent)
Definition: dbwrapper.h:76
bool Valid() const
Definition: dbwrapper.cpp:255
CDataStream ssValue
Definition: dbwrapper.h:68
void clear()
Definition: streams.h:243
bool WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:200
leveldb::Options options
database options used
Definition: dbwrapper.h:191
std::vector< unsigned char > obfuscate_key
a key used for optional XOR-obfuscation of the database
Definition: dbwrapper.h:212
#define LogPrintf(...)
Definition: logging.h:234
size_t EstimateSize(const K &key_begin, const K &key_end) const
Definition: dbwrapper.h:314
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:33