Bitcoin ABC 0.32.5
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 <common/system.h>
9#include <logging.h>
10#include <serialize.h>
11#include <span.h>
12#include <streams.h>
13#include <util/fs.h>
14#include <util/strencodings.h>
15
16#include <leveldb/db.h>
17#include <leveldb/write_batch.h>
18
19#include <optional>
20
21static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
22static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
23
25struct DBOptions {
27 bool force_compact = false;
28};
29
31struct DBParams {
37 bool memory_only = false;
39 bool wipe_data = false;
42 bool obfuscate = false;
45};
46
47class dbwrapper_error : public std::runtime_error {
48public:
49 explicit dbwrapper_error(const std::string &msg)
50 : std::runtime_error(msg) {}
51};
52
53class CDBWrapper;
54
55namespace dbwrapper {
56using leveldb::DestroyDB;
57}
61namespace dbwrapper_private {
62
66void HandleError(const leveldb::Status &status);
67
73const std::vector<uint8_t> &GetObfuscateKey(const CDBWrapper &w);
74}; // namespace dbwrapper_private
75
77class CDBBatch {
78 friend class CDBWrapper;
79
80private:
82 leveldb::WriteBatch batch;
83
86
87 size_t size_estimate{0};
88
89public:
93 explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent){};
94
95 void Clear() {
96 batch.Clear();
97 size_estimate = 0;
98 }
99
100 template <typename K, typename V> void Write(const K &key, const V &value) {
102 ssKey << key;
103 leveldb::Slice slKey((const char *)ssKey.data(), ssKey.size());
104
106 ssValue << value;
108 leveldb::Slice slValue((const char *)ssValue.data(), ssValue.size());
109
110 batch.Put(slKey, slValue);
111 // LevelDB serializes writes as:
112 // - byte: header
113 // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...)
114 // - byte[]: key
115 // - varint: value length
116 // - byte[]: value
117 // The formula below assumes the key and value are both less than 16k.
118 size_estimate += 3 + (slKey.size() > 127) + slKey.size() +
119 (slValue.size() > 127) + slValue.size();
120 ssKey.clear();
121 ssValue.clear();
122 }
123
124 template <typename K> void Erase(const K &key) {
126 ssKey << key;
127 leveldb::Slice slKey((const char *)ssKey.data(), ssKey.size());
128
129 batch.Delete(slKey);
130 // LevelDB serializes erases as:
131 // - byte: header
132 // - varint: key length
133 // - byte[]: key
134 // The formula below assumes the key is less than 16kB.
135 size_estimate += 2 + (slKey.size() > 127) + slKey.size();
136 ssKey.clear();
137 }
138
139 size_t SizeEstimate() const { return size_estimate; }
140};
141
143private:
145 leveldb::Iterator *piter;
146
147public:
152 CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter)
153 : parent(_parent), piter(_piter){};
154 ~CDBIterator();
155
156 bool Valid() const;
157
158 void SeekToFirst();
159
160 template <typename K> void Seek(const K &key) {
161 DataStream ssKey{};
163 ssKey << key;
164 leveldb::Slice slKey((const char *)ssKey.data(), ssKey.size());
165 piter->Seek(slKey);
166 }
167
168 void Next();
169
170 template <typename K> bool GetKey(K &key) {
171 leveldb::Slice slKey = piter->key();
172 try {
173 DataStream ssKey{MakeByteSpan(slKey)};
174 ssKey >> key;
175 } catch (const std::exception &) {
176 return false;
177 }
178 return true;
179 }
180
181 template <typename V> bool GetValue(V &value) {
182 leveldb::Slice slValue = piter->value();
183 try {
184 DataStream ssValue{MakeByteSpan(slValue)};
186 ssValue >> value;
187 } catch (const std::exception &) {
188 return false;
189 }
190 return true;
191 }
192
193 unsigned int GetValueSize() { return piter->value().size(); }
194};
195
197 friend const std::vector<uint8_t> &
199
200private:
203 leveldb::Env *penv;
204
206 leveldb::Options options;
207
209 leveldb::ReadOptions readoptions;
210
212 leveldb::ReadOptions iteroptions;
213
215 leveldb::WriteOptions writeoptions;
216
218 leveldb::WriteOptions syncoptions;
219
221 leveldb::DB *pdb;
222
224 std::string m_name;
225
227 std::vector<uint8_t> obfuscate_key;
228
230 static const std::string OBFUSCATE_KEY_KEY;
231
233 static const unsigned int OBFUSCATE_KEY_NUM_BYTES;
234
235 std::vector<uint8_t> CreateObfuscateKey() const;
236
239
242
243public:
244 CDBWrapper(const DBParams &params);
245 ~CDBWrapper();
246
247 CDBWrapper(const CDBWrapper &) = delete;
248 CDBWrapper &operator=(const CDBWrapper &) = delete;
249
250 template <typename K, typename V> bool Read(const K &key, V &value) const {
251 DataStream ssKey{};
253 ssKey << key;
254 leveldb::Slice slKey((const char *)ssKey.data(), ssKey.size());
255
256 std::string strValue;
257 leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
258 if (!status.ok()) {
259 if (status.IsNotFound()) return false;
260 LogPrintf("LevelDB read failure: %s\n", status.ToString());
262 }
263 try {
264 DataStream ssValue{MakeByteSpan(strValue)};
265 ssValue.Xor(obfuscate_key);
266 ssValue >> value;
267 } catch (const std::exception &) {
268 return false;
269 }
270 return true;
271 }
272
273 template <typename K, typename V>
274 bool Write(const K &key, const V &value, bool fSync = false) {
275 CDBBatch batch(*this);
276 batch.Write(key, value);
277 return WriteBatch(batch, fSync);
278 }
279
281 std::optional<fs::path> StoragePath() {
282 if (m_is_memory) {
283 return {};
284 }
285 return m_path;
286 }
287
288 template <typename K> bool Exists(const K &key) const {
289 DataStream ssKey{};
291 ssKey << key;
292 leveldb::Slice slKey((const char *)ssKey.data(), ssKey.size());
293
294 std::string strValue;
295 leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
296 if (!status.ok()) {
297 if (status.IsNotFound()) return false;
298 LogPrintf("LevelDB read failure: %s\n", status.ToString());
300 }
301 return true;
302 }
303
304 template <typename K> bool Erase(const K &key, bool fSync = false) {
305 CDBBatch batch(*this);
306 batch.Erase(key);
307 return WriteBatch(batch, fSync);
308 }
309
310 bool WriteBatch(CDBBatch &batch, bool fSync = false);
311
312 // Get an estimate of LevelDB memory usage (in bytes).
313 size_t DynamicMemoryUsage() const;
314
316 return new CDBIterator(*this, pdb->NewIterator(iteroptions));
317 }
318
322 bool IsEmpty();
323
324 template <typename K>
325 size_t EstimateSize(const K &key_begin, const K &key_end) const {
326 DataStream ssKey1{}, ssKey2{};
328 ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
329 ssKey1 << key_begin;
330 ssKey2 << key_end;
331 leveldb::Slice slKey1((const char *)ssKey1.data(), ssKey1.size());
332 leveldb::Slice slKey2((const char *)ssKey2.data(), ssKey2.size());
333 uint64_t size = 0;
334 leveldb::Range range(slKey1, slKey2);
335 pdb->GetApproximateSizes(&range, 1, &size);
336 return size;
337 }
338
342 template <typename K>
343 void CompactRange(const K &key_begin, const K &key_end) const {
344 DataStream ssKey1{}, ssKey2{};
346 ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
347 ssKey1 << key_begin;
348 ssKey2 << key_end;
349 leveldb::Slice slKey1((const char *)ssKey1.data(), ssKey1.size());
350 leveldb::Slice slKey2((const char *)ssKey2.data(), ssKey2.size());
351 pdb->CompactRange(&slKey1, &slKey2);
352 }
353};
354
355#endif // BITCOIN_DBWRAPPER_H
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:77
void Erase(const K &key)
Definition: dbwrapper.h:124
size_t SizeEstimate() const
Definition: dbwrapper.h:139
DataStream ssKey
Definition: dbwrapper.h:84
size_t size_estimate
Definition: dbwrapper.h:87
void Write(const K &key, const V &value)
Definition: dbwrapper.h:100
DataStream ssValue
Definition: dbwrapper.h:85
void Clear()
Definition: dbwrapper.h:95
CDBBatch(const CDBWrapper &_parent)
Definition: dbwrapper.h:93
leveldb::WriteBatch batch
Definition: dbwrapper.h:82
const CDBWrapper & parent
Definition: dbwrapper.h:81
bool GetValue(V &value)
Definition: dbwrapper.h:181
unsigned int GetValueSize()
Definition: dbwrapper.h:193
bool GetKey(K &key)
Definition: dbwrapper.h:170
leveldb::Iterator * piter
Definition: dbwrapper.h:145
void Seek(const K &key)
Definition: dbwrapper.h:160
const CDBWrapper & parent
Definition: dbwrapper.h:144
bool Valid() const
Definition: dbwrapper.cpp:253
void SeekToFirst()
Definition: dbwrapper.cpp:256
void Next()
Definition: dbwrapper.cpp:259
CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter)
Definition: dbwrapper.h:152
CDBWrapper(const CDBWrapper &)=delete
size_t DynamicMemoryUsage() const
Definition: dbwrapper.cpp:216
leveldb::Env * penv
custom environment this database is using (may be nullptr in case of default environment)
Definition: dbwrapper.h:203
bool WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:196
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:250
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:238
CDBIterator * NewIterator()
Definition: dbwrapper.h:315
std::string m_name
the name of this database
Definition: dbwrapper.h:224
bool Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:304
bool Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:274
bool Exists(const K &key) const
Definition: dbwrapper.h:288
std::vector< uint8_t > obfuscate_key
a key used for optional XOR-obfuscation of the database
Definition: dbwrapper.h:227
CDBWrapper(const DBParams &params)
Definition: dbwrapper.cpp:121
leveldb::Options options
database options used
Definition: dbwrapper.h:206
static const unsigned int OBFUSCATE_KEY_NUM_BYTES
the length of the obfuscate key in number of bytes
Definition: dbwrapper.h:233
static const std::string OBFUSCATE_KEY_KEY
the key under which the obfuscation key is stored
Definition: dbwrapper.h:230
leveldb::WriteOptions writeoptions
options used when writing to the database
Definition: dbwrapper.h:215
const fs::path m_path
path to filesystem storage
Definition: dbwrapper.h:238
leveldb::WriteOptions syncoptions
options used when sync writing to the database
Definition: dbwrapper.h:218
CDBWrapper & operator=(const CDBWrapper &)=delete
bool m_is_memory
whether or not the database resides in memory
Definition: dbwrapper.h:241
leveldb::DB * pdb
the database itself
Definition: dbwrapper.h:221
leveldb::ReadOptions iteroptions
options used when iterating over values of the database
Definition: dbwrapper.h:212
void CompactRange(const K &key_begin, const K &key_end) const
Compact a certain range of keys in the database.
Definition: dbwrapper.h:343
bool IsEmpty()
Return true if the database managed by this class contains no entries.
Definition: dbwrapper.cpp:244
std::optional< fs::path > StoragePath()
Definition: dbwrapper.h:281
leveldb::ReadOptions readoptions
options used when reading from the database
Definition: dbwrapper.h:209
size_t EstimateSize(const K &key_begin, const K &key_end) const
Definition: dbwrapper.h:325
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:174
size_type size() const
Definition: streams.h:207
void Xor(const std::vector< uint8_t > &key)
XOR the contents of this stream with a certain key.
Definition: streams.h:366
value_type * data()
Definition: streams.h:221
void reserve(size_type n)
Definition: streams.h:212
void clear()
Definition: streams.h:217
dbwrapper_error(const std::string &msg)
Definition: dbwrapper.h:49
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
static const size_t DBWRAPPER_PREALLOC_KEY_SIZE
Definition: dbwrapper.h:21
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE
Definition: dbwrapper.h:22
#define LogPrintf(...)
Definition: logging.h:424
These should be considered an implementation detail of the specific database.
Definition: dbwrapper.cpp:263
void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
Definition: dbwrapper.cpp:265
const std::vector< uint8_t > & GetObfuscateKey(const CDBWrapper &w)
Work around circular dependency, as well as for testing in dbwrapper_tests.
Definition: dbwrapper.cpp:276
Implement std::hash so RCUPtr can be used as a key for maps or sets.
Definition: rcu.h:259
Span< const std::byte > MakeByteSpan(V &&v) noexcept
Definition: span.h:302
User-controlled performance and debug options.
Definition: dbwrapper.h:25
bool force_compact
Compact database on startup.
Definition: dbwrapper.h:27
Application-specific storage settings.
Definition: dbwrapper.h:31
DBOptions options
Passed-through options.
Definition: dbwrapper.h:44
bool obfuscate
If true, store data obfuscated via simple XOR.
Definition: dbwrapper.h:42
bool wipe_data
If true, remove all existing data.
Definition: dbwrapper.h:39
size_t cache_bytes
Configures various leveldb cache settings.
Definition: dbwrapper.h:35
fs::path path
Location in the filesystem where leveldb data will be stored.
Definition: dbwrapper.h:33
bool memory_only
If true, use leveldb's memory environment.
Definition: dbwrapper.h:37