Bitcoin Core  21.99.0
P2P Digital Currency
dbwrapper.h
Go to the documentation of this file.
1 // Copyright (c) 2012-2020 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 <span.h>
12 #include <streams.h>
13 #include <util/strencodings.h>
14 #include <util/system.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:
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  {
76  ssKey << key;
77  leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size());
78 
80  ssValue << value;
82  leveldb::Slice slValue((const char*)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  {
101  ssKey << key;
102  leveldb::Slice slKey((const char*)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) {
140  ssKey << key;
141  leveldb::Slice slKey((const char*)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 {
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(MakeUCharSpan(slValue), SER_DISK, CLIENT_VERSION);
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 
199  leveldb::DB* pdb;
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  {
235  ssKey << key;
236  leveldb::Slice slKey((const char*)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(MakeUCharSpan(strValue), 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  {
269  ssKey << key;
270  leveldb::Slice slKey((const char*)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 
297  {
298  return new CDBIterator(*this, pdb->NewIterator(iteroptions));
299  }
300 
304  bool IsEmpty();
305 
306  template<typename K>
307  size_t EstimateSize(const K& key_begin, const K& key_end) const
308  {
310  ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
312  ssKey1 << key_begin;
313  ssKey2 << key_end;
314  leveldb::Slice slKey1((const char*)ssKey1.data(), ssKey1.size());
315  leveldb::Slice slKey2((const char*)ssKey2.data(), ssKey2.size());
316  uint64_t size = 0;
317  leveldb::Range range(slKey1, slKey2);
318  pdb->GetApproximateSizes(&range, 1, &size);
319  return size;
320  }
321 
325  template<typename K>
326  void CompactRange(const K& key_begin, const K& key_end) const
327  {
329  ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
331  ssKey1 << key_begin;
332  ssKey2 << key_end;
333  leveldb::Slice slKey1((const char*)ssKey1.data(), ssKey1.size());
334  leveldb::Slice slKey2((const char*)ssKey2.data(), ssKey2.size());
335  pdb->CompactRange(&slKey1, &slKey2);
336  }
337 };
338 
339 #endif // BITCOIN_DBWRAPPER_H
CDBBatch::size_estimate
size_t size_estimate
Definition: dbwrapper.h:58
CDBBatch::ssValue
CDataStream ssValue
Definition: dbwrapper.h:56
CDBIterator::CDBIterator
CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter)
Definition: dbwrapper.h:129
CDBIterator::parent
const CDBWrapper & parent
Definition: dbwrapper.h:120
DBWRAPPER_PREALLOC_KEY_SIZE
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE
Definition: dbwrapper.h:19
SER_DISK
@ SER_DISK
Definition: serialize.h:167
fs.h
CDBBatch
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:47
streams.h
CDataStream::Xor
void Xor(const std::vector< unsigned char > &key)
XOR the contents of this stream with a certain key.
Definition: streams.h:437
MakeUCharSpan
constexpr auto MakeUCharSpan(V &&v) -> decltype(UCharSpanCast(MakeSpan(std::forward< V >(v))))
Like MakeSpan, but for (const) unsigned char member types only.
Definition: span.h:249
CDataStream::data
value_type * data()
Definition: streams.h:264
CDBBatch::parent
const CDBWrapper & parent
Definition: dbwrapper.h:52
clientversion.h
CDBWrapper::Read
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:231
CDBBatch::CDBBatch
CDBBatch(const CDBWrapper &_parent)
Definition: dbwrapper.h:64
CDBWrapper::readoptions
leveldb::ReadOptions readoptions
options used when reading from the database
Definition: dbwrapper.h:187
CDBWrapper::syncoptions
leveldb::WriteOptions syncoptions
options used when sync writing to the database
Definition: dbwrapper.h:196
CDBWrapper::CDBWrapper
CDBWrapper(const fs::path &path, size_t nCacheSize, bool fMemory=false, bool fWipe=false, bool obfuscate=false)
Definition: dbwrapper.cpp:117
CDBIterator::Next
void Next()
Definition: dbwrapper.cpp:239
CDBBatch::ssKey
CDataStream ssKey
Definition: dbwrapper.h:55
CDBBatch::Write
void Write(const K &key, const V &value)
Definition: dbwrapper.h:73
strencodings.h
dbwrapper_error::dbwrapper_error
dbwrapper_error(const std::string &msg)
Definition: dbwrapper.h:25
CDBWrapper::NewIterator
CDBIterator * NewIterator()
Definition: dbwrapper.h:296
CDBIterator::GetValue
bool GetValue(V &value)
Definition: dbwrapper.h:158
CDBWrapper::iteroptions
leveldb::ReadOptions iteroptions
options used when iterating over values of the database
Definition: dbwrapper.h:190
CDBBatch::Clear
void Clear()
Definition: dbwrapper.h:66
span.h
CDBWrapper::penv
leveldb::Env * penv
custom environment this database is using (may be nullptr in case of default environment)
Definition: dbwrapper.h:181
CDBWrapper::OBFUSCATE_KEY_KEY
static const std::string OBFUSCATE_KEY_KEY
the key under which the obfuscation key is stored
Definition: dbwrapper.h:208
CDBIterator::~CDBIterator
~CDBIterator()
Definition: dbwrapper.cpp:236
LogPrintf
#define LogPrintf(...)
Definition: logging.h:183
CDBBatch::batch
leveldb::WriteBatch batch
Definition: dbwrapper.h:53
CDBWrapper::pdb
leveldb::DB * pdb
the database itself
Definition: dbwrapper.h:199
dbwrapper_private
These should be considered an implementation detail of the specific database.
Definition: dbwrapper.cpp:241
CDBIterator::piter
leveldb::Iterator * piter
Definition: dbwrapper.h:121
CDBWrapper::Erase
bool Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:284
CDBWrapper::DynamicMemoryUsage
size_t DynamicMemoryUsage() const
Definition: dbwrapper.cpp:200
CDBWrapper::CreateObfuscateKey
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:221
CDataStream::reserve
void reserve(size_type n)
Definition: streams.h:258
CDBIterator::Seek
void Seek(const K &key)
Definition: dbwrapper.h:137
CDBWrapper::writeoptions
leveldb::WriteOptions writeoptions
options used when writing to the database
Definition: dbwrapper.h:193
CDataStream::size
size_type size() const
Definition: streams.h:255
CDBWrapper::m_name
std::string m_name
the name of this database
Definition: dbwrapper.h:202
dbwrapper_private::HandleError
void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
Definition: dbwrapper.cpp:243
CDBWrapper
Definition: dbwrapper.h:176
CDBIterator::Valid
bool Valid() const
Definition: dbwrapper.cpp:237
system.h
dbwrapper_error
Definition: dbwrapper.h:22
CDataStream::clear
void clear()
Definition: streams.h:261
CDBWrapper::options
leveldb::Options options
database options used
Definition: dbwrapper.h:184
CDBWrapper::~CDBWrapper
~CDBWrapper()
Definition: dbwrapper.cpp:169
CDBIterator::GetKey
bool GetKey(K &key)
Definition: dbwrapper.h:147
CDBIterator::GetValueSize
unsigned int GetValueSize()
Definition: dbwrapper.h:170
CDBBatch::Erase
void Erase(const K &key)
Definition: dbwrapper.h:98
DBWRAPPER_PREALLOC_VALUE_SIZE
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE
Definition: dbwrapper.h:20
CLIENT_VERSION
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:33
CDBWrapper::OBFUSCATE_KEY_NUM_BYTES
static const unsigned int OBFUSCATE_KEY_NUM_BYTES
the length of the obfuscate key in number of bytes
Definition: dbwrapper.h:211
CDBWrapper::obfuscate_key
std::vector< unsigned char > obfuscate_key
a key used for optional XOR-obfuscation of the database
Definition: dbwrapper.h:205
CDBWrapper::operator=
CDBWrapper & operator=(const CDBWrapper &)=delete
dbwrapper_private::GetObfuscateKey
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
CDBIterator::SeekToFirst
void SeekToFirst()
Definition: dbwrapper.cpp:238
serialize.h
CDataStream
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:204
CDBWrapper::IsEmpty
bool IsEmpty()
Return true if the database managed by this class contains no entries.
Definition: dbwrapper.cpp:229
CDBWrapper::EstimateSize
size_t EstimateSize(const K &key_begin, const K &key_end) const
Definition: dbwrapper.h:307
CDBWrapper::Write
bool Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:257
CDBWrapper::Exists
bool Exists(const K &key) const
Definition: dbwrapper.h:265
CDBWrapper::CompactRange
void CompactRange(const K &key_begin, const K &key_end) const
Compact a certain range of keys in the database.
Definition: dbwrapper.h:326
CDBWrapper::WriteBatch
bool WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:183
CDBBatch::SizeEstimate
size_t SizeEstimate() const
Definition: dbwrapper.h:114
CDBIterator
Definition: dbwrapper.h:117