Bitcoin ABC  0.24.7
P2P Digital Currency
dbwrapper.h
Go to the documentation of this file.
1 // Copyright (c) 2012-2016 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/strencodings.h>
13 #include <util/system.h>
14 
15 #include <leveldb/db.h>
16 #include <leveldb/write_batch.h>
17 
18 static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
19 static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
20 
21 class dbwrapper_error : public std::runtime_error {
22 public:
23  explicit dbwrapper_error(const std::string &msg)
24  : std::runtime_error(msg) {}
25 };
26 
27 class CDBWrapper;
28 
32 namespace dbwrapper_private {
33 
37 void HandleError(const leveldb::Status &status);
38 
44 const std::vector<uint8_t> &GetObfuscateKey(const CDBWrapper &w);
45 }; // namespace dbwrapper_private
46 
48 class CDBBatch {
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)
65  : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION),
67 
68  void Clear() {
69  batch.Clear();
70  size_estimate = 0;
71  }
72 
73  template <typename K, typename V> void Write(const K &key, const V &value) {
75  ssKey << key;
76  leveldb::Slice slKey(ssKey.data(), ssKey.size());
77 
79  ssValue << value;
81  leveldb::Slice slValue(ssValue.data(), ssValue.size());
82 
83  batch.Put(slKey, slValue);
84  // LevelDB serializes writes as:
85  // - byte: header
86  // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...)
87  // - byte[]: key
88  // - varint: value length
89  // - byte[]: value
90  // The formula below assumes the key and value are both less than 16k.
91  size_estimate += 3 + (slKey.size() > 127) + slKey.size() +
92  (slValue.size() > 127) + slValue.size();
93  ssKey.clear();
94  ssValue.clear();
95  }
96 
97  template <typename K> void Erase(const K &key) {
99  ssKey << key;
100  leveldb::Slice slKey(ssKey.data(), ssKey.size());
101 
102  batch.Delete(slKey);
103  // LevelDB serializes erases as:
104  // - byte: header
105  // - varint: key length
106  // - byte[]: key
107  // The formula below assumes the key is less than 16kB.
108  size_estimate += 2 + (slKey.size() > 127) + slKey.size();
109  ssKey.clear();
110  }
111 
112  size_t SizeEstimate() const { return size_estimate; }
113 };
114 
115 class CDBIterator {
116 private:
118  leveldb::Iterator *piter;
119 
120 public:
125  CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter)
126  : parent(_parent), piter(_piter){};
127  ~CDBIterator();
128 
129  bool Valid() const;
130 
131  void SeekToFirst();
132 
133  template <typename K> void Seek(const K &key) {
136  ssKey << key;
137  leveldb::Slice slKey(ssKey.data(), ssKey.size());
138  piter->Seek(slKey);
139  }
140 
141  void Next();
142 
143  template <typename K> bool GetKey(K &key) {
144  leveldb::Slice slKey = piter->key();
145  try {
146  CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(),
148  ssKey >> key;
149  } catch (const std::exception &) {
150  return false;
151  }
152  return true;
153  }
154 
155  template <typename V> bool GetValue(V &value) {
156  leveldb::Slice slValue = piter->value();
157  try {
158  CDataStream ssValue(slValue.data(), slValue.data() + slValue.size(),
161  ssValue >> value;
162  } catch (const std::exception &) {
163  return false;
164  }
165  return true;
166  }
167 
168  unsigned int GetValueSize() { return piter->value().size(); }
169 };
170 
171 class CDBWrapper {
172  friend const std::vector<uint8_t> &
174 
175 private:
178  leveldb::Env *penv;
179 
181  leveldb::Options options;
182 
184  leveldb::ReadOptions readoptions;
185 
187  leveldb::ReadOptions iteroptions;
188 
190  leveldb::WriteOptions writeoptions;
191 
193  leveldb::WriteOptions syncoptions;
194 
196  leveldb::DB *pdb;
197 
199  std::string m_name;
200 
202  std::vector<uint8_t> 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<uint8_t> CreateObfuscateKey() const;
211 
212 public:
223  CDBWrapper(const fs::path &path, size_t nCacheSize, bool fMemory = false,
224  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> bool Read(const K &key, V &value) const {
233  ssKey << key;
234  leveldb::Slice slKey(ssKey.data(), ssKey.size());
235 
236  std::string strValue;
237  leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
238  if (!status.ok()) {
239  if (status.IsNotFound()) return false;
240  LogPrintf("LevelDB read failure: %s\n", status.ToString());
242  }
243  try {
244  CDataStream ssValue(strValue.data(),
245  strValue.data() + strValue.size(), SER_DISK,
247  ssValue.Xor(obfuscate_key);
248  ssValue >> value;
249  } catch (const std::exception &) {
250  return false;
251  }
252  return true;
253  }
254 
255  template <typename K, typename V>
256  bool Write(const K &key, const V &value, bool fSync = false) {
257  CDBBatch batch(*this);
258  batch.Write(key, value);
259  return WriteBatch(batch, fSync);
260  }
261 
262  template <typename K> bool Exists(const K &key) const {
265  ssKey << key;
266  leveldb::Slice slKey(ssKey.data(), ssKey.size());
267 
268  std::string strValue;
269  leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
270  if (!status.ok()) {
271  if (status.IsNotFound()) return false;
272  LogPrintf("LevelDB read failure: %s\n", status.ToString());
274  }
275  return true;
276  }
277 
278  template <typename K> bool Erase(const K &key, bool fSync = false) {
279  CDBBatch batch(*this);
280  batch.Erase(key);
281  return WriteBatch(batch, fSync);
282  }
283 
284  bool WriteBatch(CDBBatch &batch, bool fSync = false);
285 
286  // Get an estimate of LevelDB memory usage (in bytes).
287  size_t DynamicMemoryUsage() const;
288 
290  return new CDBIterator(*this, pdb->NewIterator(iteroptions));
291  }
292 
296  bool IsEmpty();
297 
298  template <typename K>
299  size_t EstimateSize(const K &key_begin, const K &key_end) const {
301  ssKey2(SER_DISK, CLIENT_VERSION);
302  ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
304  ssKey1 << key_begin;
305  ssKey2 << key_end;
306  leveldb::Slice slKey1(ssKey1.data(), ssKey1.size());
307  leveldb::Slice slKey2(ssKey2.data(), ssKey2.size());
308  uint64_t size = 0;
309  leveldb::Range range(slKey1, slKey2);
310  pdb->GetApproximateSizes(&range, 1, &size);
311  return size;
312  }
313 
317  template <typename K>
318  void CompactRange(const K &key_begin, const K &key_end) const {
320  ssKey2(SER_DISK, CLIENT_VERSION);
321  ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
323  ssKey1 << key_begin;
324  ssKey2 << key_end;
325  leveldb::Slice slKey1(ssKey1.data(), ssKey1.size());
326  leveldb::Slice slKey2(ssKey2.data(), ssKey2.size());
327  pdb->CompactRange(&slKey1, &slKey2);
328  }
329 };
330 
331 #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:125
CDBIterator::parent
const CDBWrapper & parent
Definition: dbwrapper.h:117
DBWRAPPER_PREALLOC_KEY_SIZE
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE
Definition: dbwrapper.h:18
fs.h
CDBBatch
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:48
streams.h
CDataStream::data
value_type * data()
Definition: streams.h:298
CDBWrapper::obfuscate_key
std::vector< uint8_t > obfuscate_key
a key used for optional XOR-obfuscation of the database
Definition: dbwrapper.h:202
CDBWrapper::CreateObfuscateKey
std::vector< uint8_t > CreateObfuscateKey() const
Returns a string (consisting of 8 random bytes) suitable for use as an obfuscating XOR key.
Definition: dbwrapper.cpp:227
CDBBatch::parent
const CDBWrapper & parent
Definition: dbwrapper.h:52
clientversion.h
CDBWrapper::Read
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:230
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:184
CDBWrapper::syncoptions
leveldb::WriteOptions syncoptions
options used when sync writing to the database
Definition: dbwrapper.h:193
CDBWrapper::CDBWrapper
CDBWrapper(const fs::path &path, size_t nCacheSize, bool fMemory=false, bool fWipe=false, bool obfuscate=false)
Definition: dbwrapper.cpp:119
CDBIterator::Next
void Next()
Definition: dbwrapper.cpp:248
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:23
CDBWrapper::NewIterator
CDBIterator * NewIterator()
Definition: dbwrapper.h:289
CDBIterator::GetValue
bool GetValue(V &value)
Definition: dbwrapper.h:155
CDBWrapper::iteroptions
leveldb::ReadOptions iteroptions
options used when iterating over values of the database
Definition: dbwrapper.h:187
CDBBatch::Clear
void Clear()
Definition: dbwrapper.h:68
CDBWrapper::penv
leveldb::Env * penv
custom environment this database is using (may be nullptr in case of default environment)
Definition: dbwrapper.h:178
CDBWrapper::OBFUSCATE_KEY_KEY
static const std::string OBFUSCATE_KEY_KEY
the key under which the obfuscation key is stored
Definition: dbwrapper.h:205
CDBIterator::~CDBIterator
~CDBIterator()
Definition: dbwrapper.cpp:239
dbwrapper_private::GetObfuscateKey
const std::vector< uint8_t > & GetObfuscateKey(const CDBWrapper &w)
Work around circular dependency, as well as for testing in dbwrapper_tests.
Definition: dbwrapper.cpp:265
CDBBatch::batch
leveldb::WriteBatch batch
Definition: dbwrapper.h:53
CDBWrapper::pdb
leveldb::DB * pdb
the database itself
Definition: dbwrapper.h:196
CDataStream::Xor
void Xor(const std::vector< uint8_t > &key)
XOR the contents of this stream with a certain key.
Definition: streams.h:461
dbwrapper_private
These should be considered an implementation detail of the specific database.
Definition: dbwrapper.cpp:252
CDBIterator::piter
leveldb::Iterator * piter
Definition: dbwrapper.h:118
CDBWrapper::Erase
bool Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:278
CDBWrapper::DynamicMemoryUsage
size_t DynamicMemoryUsage() const
Definition: dbwrapper.cpp:205
CDataStream::reserve
void reserve(size_type n)
Definition: streams.h:283
CDBIterator::Seek
void Seek(const K &key)
Definition: dbwrapper.h:133
CDBWrapper::writeoptions
leveldb::WriteOptions writeoptions
options used when writing to the database
Definition: dbwrapper.h:190
CDataStream::size
size_type size() const
Definition: streams.h:280
CDBWrapper::m_name
std::string m_name
the name of this database
Definition: dbwrapper.h:199
dbwrapper_private::HandleError
void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
Definition: dbwrapper.cpp:254
CDBWrapper
Definition: dbwrapper.h:171
CDBIterator::Valid
bool Valid() const
Definition: dbwrapper.cpp:242
system.h
CLIENT_VERSION
static constexpr int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:44
dbwrapper_error
Definition: dbwrapper.h:21
CDataStream::clear
void clear()
Definition: streams.h:288
CDBWrapper::options
leveldb::Options options
database options used
Definition: dbwrapper.h:181
CDBWrapper::~CDBWrapper
~CDBWrapper()
Definition: dbwrapper.cpp:173
CDBIterator::GetKey
bool GetKey(K &key)
Definition: dbwrapper.h:143
CDBIterator::GetValueSize
unsigned int GetValueSize()
Definition: dbwrapper.h:168
CDBBatch::Erase
void Erase(const K &key)
Definition: dbwrapper.h:97
DBWRAPPER_PREALLOC_VALUE_SIZE
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE
Definition: dbwrapper.h:19
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:208
CDBWrapper::operator=
CDBWrapper & operator=(const CDBWrapper &)=delete
SER_DISK
@ SER_DISK
Definition: serialize.h:166
CDBIterator::SeekToFirst
void SeekToFirst()
Definition: dbwrapper.cpp:245
serialize.h
CDataStream
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:197
CDBWrapper::IsEmpty
bool IsEmpty()
Return true if the database managed by this class contains no entries.
Definition: dbwrapper.cpp:233
CDBWrapper::EstimateSize
size_t EstimateSize(const K &key_begin, const K &key_end) const
Definition: dbwrapper.h:299
CDBWrapper::Write
bool Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:256
CDBWrapper::Exists
bool Exists(const K &key) const
Definition: dbwrapper.h:262
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:318
CDBWrapper::WriteBatch
bool WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:186
LogPrintf
static void LogPrintf(const char *fmt, const Args &... args)
Definition: logging.h:175
CDBBatch::SizeEstimate
size_t SizeEstimate() const
Definition: dbwrapper.h:112
CDBIterator
Definition: dbwrapper.h:115