Bitcoin Core 22.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
19static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
20static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
21
22class dbwrapper_error : public std::runtime_error
23{
24public:
25 explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
26};
27
28class CDBWrapper;
29
32namespace dbwrapper_private {
33
36void HandleError(const leveldb::Status& status);
37
42const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w);
43
44};
45
48{
49 friend class CDBWrapper;
50
51private:
53 leveldb::WriteBatch batch;
54
57
59
60public:
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{
119private:
121 leveldb::Iterator *piter;
122
123public:
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 {
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);
179private:
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
215public:
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 {
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
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:48
void Erase(const K &key)
Definition: dbwrapper.h:98
size_t SizeEstimate() const
Definition: dbwrapper.h:114
CDataStream ssKey
Definition: dbwrapper.h:55
CDataStream ssValue
Definition: dbwrapper.h:56
size_t size_estimate
Definition: dbwrapper.h:58
void Write(const K &key, const V &value)
Definition: dbwrapper.h:73
void Clear()
Definition: dbwrapper.h:66
CDBBatch(const CDBWrapper &_parent)
Definition: dbwrapper.h:64
leveldb::WriteBatch batch
Definition: dbwrapper.h:53
const CDBWrapper & parent
Definition: dbwrapper.h:52
bool GetValue(V &value)
Definition: dbwrapper.h:158
unsigned int GetValueSize()
Definition: dbwrapper.h:170
bool GetKey(K &key)
Definition: dbwrapper.h:147
leveldb::Iterator * piter
Definition: dbwrapper.h:121
void Seek(const K &key)
Definition: dbwrapper.h:137
const CDBWrapper & parent
Definition: dbwrapper.h:120
bool Valid() const
Definition: dbwrapper.cpp:238
void SeekToFirst()
Definition: dbwrapper.cpp:239
void Next()
Definition: dbwrapper.cpp:240
CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter)
Definition: dbwrapper.h:129
CDBWrapper(const CDBWrapper &)=delete
size_t DynamicMemoryUsage() const
Definition: dbwrapper.cpp:200
leveldb::Env * penv
custom environment this database is using (may be nullptr in case of default environment)
Definition: dbwrapper.h:181
bool WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:183
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:231
CDBIterator * NewIterator()
Definition: dbwrapper.h:296
std::string m_name
the name of this database
Definition: dbwrapper.h:202
bool Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:284
bool Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:257
bool Exists(const K &key) const
Definition: dbwrapper.h:265
std::vector< unsigned char > obfuscate_key
a key used for optional XOR-obfuscation of the database
Definition: dbwrapper.h:205
leveldb::Options options
database options used
Definition: dbwrapper.h:184
static const unsigned int OBFUSCATE_KEY_NUM_BYTES
the length of the obfuscate key in number of bytes
Definition: dbwrapper.h:211
static const std::string OBFUSCATE_KEY_KEY
the key under which the obfuscation key is stored
Definition: dbwrapper.h:208
leveldb::WriteOptions writeoptions
options used when writing to the database
Definition: dbwrapper.h:193
leveldb::WriteOptions syncoptions
options used when sync writing to the database
Definition: dbwrapper.h:196
CDBWrapper(const fs::path &path, size_t nCacheSize, bool fMemory=false, bool fWipe=false, bool obfuscate=false)
Definition: dbwrapper.cpp:117
CDBWrapper & operator=(const CDBWrapper &)=delete
leveldb::DB * pdb
the database itself
Definition: dbwrapper.h:199
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:223
leveldb::ReadOptions iteroptions
options used when iterating over values of the database
Definition: dbwrapper.h:190
void CompactRange(const K &key_begin, const K &key_end) const
Compact a certain range of keys in the database.
Definition: dbwrapper.h:326
bool IsEmpty()
Return true if the database managed by this class contains no entries.
Definition: dbwrapper.cpp:230
leveldb::ReadOptions readoptions
options used when reading from the database
Definition: dbwrapper.h:187
size_t EstimateSize(const K &key_begin, const K &key_end) const
Definition: dbwrapper.h:307
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:205
void reserve(size_type n)
Definition: streams.h:258
void Xor(const std::vector< unsigned char > &key)
XOR the contents of this stream with a certain key.
Definition: streams.h:437
value_type * data()
Definition: streams.h:264
size_type size() const
Definition: streams.h:255
void clear()
Definition: streams.h:261
dbwrapper_error(const std::string &msg)
Definition: dbwrapper.h:25
Path class wrapper to prepare application code for transition from boost::filesystem library to std::...
Definition: fs.h:34
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:33
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE
Definition: dbwrapper.h:19
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE
Definition: dbwrapper.h:20
#define LogPrintf(...)
Definition: logging.h:187
These should be considered an implementation detail of the specific database.
Definition: dbwrapper.cpp:242
void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
Definition: dbwrapper.cpp:244
const std::vector< unsigned char > & GetObfuscateKey(const CDBWrapper &w)
Work around circular dependency, as well as for testing in dbwrapper_tests.
Definition: dbwrapper.cpp:254
@ SER_DISK
Definition: serialize.h:139
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