Bitcoin ABC 0.33.12
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;
23static const size_t DBWRAPPER_MAX_FILE_SIZE = 32 << 20; // 32 MiB
24
26struct DBOptions {
28 bool force_compact = false;
29};
30
32struct DBParams {
38 bool memory_only = false;
40 bool wipe_data = false;
43 bool obfuscate = false;
46};
47
48class dbwrapper_error : public std::runtime_error {
49public:
50 explicit dbwrapper_error(const std::string &msg)
51 : std::runtime_error(msg) {}
52};
53
54class CDBWrapper;
55
56namespace dbwrapper {
57using leveldb::DestroyDB;
58}
62namespace dbwrapper_private {
63
67void HandleError(const leveldb::Status &status);
68
74const std::vector<uint8_t> &GetObfuscateKey(const CDBWrapper &w);
75}; // namespace dbwrapper_private
76
78class CDBBatch {
79 friend class CDBWrapper;
80
81private:
83 leveldb::WriteBatch batch;
84
87
88 size_t size_estimate{0};
89
90public:
94 explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent) {};
95
96 void Clear() {
97 batch.Clear();
98 size_estimate = 0;
99 }
100
101 template <typename K, typename V> void Write(const K &key, const V &value) {
103 ssKey << key;
104 leveldb::Slice slKey((const char *)ssKey.data(), ssKey.size());
105
107 ssValue << value;
109 leveldb::Slice slValue((const char *)ssValue.data(), ssValue.size());
110
111 batch.Put(slKey, slValue);
112 // LevelDB serializes writes as:
113 // - byte: header
114 // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...)
115 // - byte[]: key
116 // - varint: value length
117 // - byte[]: value
118 // The formula below assumes the key and value are both less than 16k.
119 size_estimate += 3 + (slKey.size() > 127) + slKey.size() +
120 (slValue.size() > 127) + slValue.size();
121 ssKey.clear();
122 ssValue.clear();
123 }
124
125 template <typename K> void Erase(const K &key) {
127 ssKey << key;
128 leveldb::Slice slKey((const char *)ssKey.data(), ssKey.size());
129
130 batch.Delete(slKey);
131 // LevelDB serializes erases as:
132 // - byte: header
133 // - varint: key length
134 // - byte[]: key
135 // The formula below assumes the key is less than 16kB.
136 size_estimate += 2 + (slKey.size() > 127) + slKey.size();
137 ssKey.clear();
138 }
139
140 size_t SizeEstimate() const { return size_estimate; }
141};
142
144private:
146 leveldb::Iterator *piter;
147
148public:
153 CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter)
154 : parent(_parent), piter(_piter) {};
155 ~CDBIterator();
156
157 bool Valid() const;
158
159 void SeekToFirst();
160
161 template <typename K> void Seek(const K &key) {
162 DataStream ssKey{};
164 ssKey << key;
165 leveldb::Slice slKey((const char *)ssKey.data(), ssKey.size());
166 piter->Seek(slKey);
167 }
168
169 void Next();
170
171 template <typename K> bool GetKey(K &key) {
172 leveldb::Slice slKey = piter->key();
173 try {
174 DataStream ssKey{MakeByteSpan(slKey)};
175 ssKey >> key;
176 } catch (const std::exception &) {
177 return false;
178 }
179 return true;
180 }
181
182 template <typename V> bool GetValue(V &value) {
183 leveldb::Slice slValue = piter->value();
184 try {
185 DataStream ssValue{MakeByteSpan(slValue)};
187 ssValue >> value;
188 } catch (const std::exception &) {
189 return false;
190 }
191 return true;
192 }
193
194 unsigned int GetValueSize() { return piter->value().size(); }
195};
196
198 friend const std::vector<uint8_t> &
200
201private:
204 leveldb::Env *penv;
205
207 leveldb::Options options;
208
210 leveldb::ReadOptions readoptions;
211
213 leveldb::ReadOptions iteroptions;
214
216 leveldb::WriteOptions writeoptions;
217
219 leveldb::WriteOptions syncoptions;
220
222 leveldb::DB *pdb;
223
225 std::string m_name;
226
228 std::vector<uint8_t> obfuscate_key;
229
231 static const std::string OBFUSCATE_KEY_KEY;
232
234 static const unsigned int OBFUSCATE_KEY_NUM_BYTES;
235
236 std::vector<uint8_t> CreateObfuscateKey() const;
237
240
243
244public:
245 CDBWrapper(const DBParams &params);
246 ~CDBWrapper();
247
248 CDBWrapper(const CDBWrapper &) = delete;
249 CDBWrapper &operator=(const CDBWrapper &) = delete;
250
251 template <typename K, typename V> bool Read(const K &key, V &value) const {
252 DataStream ssKey{};
254 ssKey << key;
255 leveldb::Slice slKey((const char *)ssKey.data(), ssKey.size());
256
257 std::string strValue;
258 leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
259 if (!status.ok()) {
260 if (status.IsNotFound()) {
261 return false;
262 }
263 LogPrintf("LevelDB read failure: %s\n", status.ToString());
265 }
266 try {
267 DataStream ssValue{MakeByteSpan(strValue)};
268 ssValue.Xor(obfuscate_key);
269 ssValue >> value;
270 } catch (const std::exception &) {
271 return false;
272 }
273 return true;
274 }
275
276 template <typename K, typename V>
277 void Write(const K &key, const V &value, bool fSync = false) {
278 CDBBatch batch(*this);
279 batch.Write(key, value);
280 WriteBatch(batch, fSync);
281 }
282
284 std::optional<fs::path> StoragePath() {
285 if (m_is_memory) {
286 return {};
287 }
288 return m_path;
289 }
290
291 template <typename K> bool Exists(const K &key) const {
292 DataStream ssKey{};
294 ssKey << key;
295 leveldb::Slice slKey((const char *)ssKey.data(), ssKey.size());
296
297 std::string strValue;
298 leveldb::Status status = pdb->Get(readoptions, slKey, &strValue);
299 if (!status.ok()) {
300 if (status.IsNotFound()) {
301 return false;
302 }
303 LogPrintf("LevelDB read failure: %s\n", status.ToString());
305 }
306 return true;
307 }
308
309 template <typename K> void Erase(const K &key, bool fSync = false) {
310 CDBBatch batch(*this);
311 batch.Erase(key);
312 WriteBatch(batch, fSync);
313 }
314
315 void WriteBatch(CDBBatch &batch, bool fSync = false);
316
317 // Get an estimate of LevelDB memory usage (in bytes).
318 size_t DynamicMemoryUsage() const;
319
321 return new CDBIterator(*this, pdb->NewIterator(iteroptions));
322 }
323
327 bool IsEmpty();
328
329 template <typename K>
330 size_t EstimateSize(const K &key_begin, const K &key_end) const {
331 DataStream ssKey1{}, ssKey2{};
333 ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
334 ssKey1 << key_begin;
335 ssKey2 << key_end;
336 leveldb::Slice slKey1((const char *)ssKey1.data(), ssKey1.size());
337 leveldb::Slice slKey2((const char *)ssKey2.data(), ssKey2.size());
338 uint64_t size = 0;
339 leveldb::Range range(slKey1, slKey2);
340 pdb->GetApproximateSizes(&range, 1, &size);
341 return size;
342 }
343
347 template <typename K>
348 void CompactRange(const K &key_begin, const K &key_end) const {
349 DataStream ssKey1{}, ssKey2{};
351 ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
352 ssKey1 << key_begin;
353 ssKey2 << key_end;
354 leveldb::Slice slKey1((const char *)ssKey1.data(), ssKey1.size());
355 leveldb::Slice slKey2((const char *)ssKey2.data(), ssKey2.size());
356 pdb->CompactRange(&slKey1, &slKey2);
357 }
358};
359
360#endif // BITCOIN_DBWRAPPER_H
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:78
void Erase(const K &key)
Definition: dbwrapper.h:125
size_t SizeEstimate() const
Definition: dbwrapper.h:140
DataStream ssKey
Definition: dbwrapper.h:85
size_t size_estimate
Definition: dbwrapper.h:88
void Write(const K &key, const V &value)
Definition: dbwrapper.h:101
DataStream ssValue
Definition: dbwrapper.h:86
void Clear()
Definition: dbwrapper.h:96
CDBBatch(const CDBWrapper &_parent)
Definition: dbwrapper.h:94
leveldb::WriteBatch batch
Definition: dbwrapper.h:83
const CDBWrapper & parent
Definition: dbwrapper.h:82
bool GetValue(V &value)
Definition: dbwrapper.h:182
unsigned int GetValueSize()
Definition: dbwrapper.h:194
bool GetKey(K &key)
Definition: dbwrapper.h:171
leveldb::Iterator * piter
Definition: dbwrapper.h:146
void Seek(const K &key)
Definition: dbwrapper.h:161
const CDBWrapper & parent
Definition: dbwrapper.h:145
bool Valid() const
Definition: dbwrapper.cpp:254
void SeekToFirst()
Definition: dbwrapper.cpp:257
void Next()
Definition: dbwrapper.cpp:260
CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter)
Definition: dbwrapper.h:153
CDBWrapper(const CDBWrapper &)=delete
size_t DynamicMemoryUsage() const
Definition: dbwrapper.cpp:217
leveldb::Env * penv
custom environment this database is using (may be nullptr in case of default environment)
Definition: dbwrapper.h:204
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:251
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:239
CDBIterator * NewIterator()
Definition: dbwrapper.h:320
std::string m_name
the name of this database
Definition: dbwrapper.h:225
bool Exists(const K &key) const
Definition: dbwrapper.h:291
std::vector< uint8_t > obfuscate_key
a key used for optional XOR-obfuscation of the database
Definition: dbwrapper.h:228
CDBWrapper(const DBParams &params)
Definition: dbwrapper.cpp:123
void Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:309
leveldb::Options options
database options used
Definition: dbwrapper.h:207
static const unsigned int OBFUSCATE_KEY_NUM_BYTES
the length of the obfuscate key in number of bytes
Definition: dbwrapper.h:234
static const std::string OBFUSCATE_KEY_KEY
the key under which the obfuscation key is stored
Definition: dbwrapper.h:231
void WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:198
leveldb::WriteOptions writeoptions
options used when writing to the database
Definition: dbwrapper.h:216
const fs::path m_path
path to filesystem storage
Definition: dbwrapper.h:239
leveldb::WriteOptions syncoptions
options used when sync writing to the database
Definition: dbwrapper.h:219
void Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:277
CDBWrapper & operator=(const CDBWrapper &)=delete
bool m_is_memory
whether or not the database resides in memory
Definition: dbwrapper.h:242
leveldb::DB * pdb
the database itself
Definition: dbwrapper.h:222
leveldb::ReadOptions iteroptions
options used when iterating over values of the database
Definition: dbwrapper.h:213
void CompactRange(const K &key_begin, const K &key_end) const
Compact a certain range of keys in the database.
Definition: dbwrapper.h:348
bool IsEmpty()
Return true if the database managed by this class contains no entries.
Definition: dbwrapper.cpp:245
std::optional< fs::path > StoragePath()
Definition: dbwrapper.h:284
leveldb::ReadOptions readoptions
options used when reading from the database
Definition: dbwrapper.h:210
size_t EstimateSize(const K &key_begin, const K &key_end) const
Definition: dbwrapper.h:330
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:118
size_type size() const
Definition: streams.h:151
void Xor(const std::vector< uint8_t > &key)
XOR the contents of this stream with a certain key.
Definition: streams.h:311
value_type * data()
Definition: streams.h:165
void reserve(size_type n)
Definition: streams.h:156
void clear()
Definition: streams.h:161
dbwrapper_error(const std::string &msg)
Definition: dbwrapper.h:50
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
static const size_t DBWRAPPER_MAX_FILE_SIZE
Definition: dbwrapper.h:23
#define LogPrintf(...)
Definition: logging.h:424
These should be considered an implementation detail of the specific database.
Definition: dbwrapper.cpp:264
void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
Definition: dbwrapper.cpp:266
const std::vector< uint8_t > & GetObfuscateKey(const CDBWrapper &w)
Work around circular dependency, as well as for testing in dbwrapper_tests.
Definition: dbwrapper.cpp:277
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:26
bool force_compact
Compact database on startup.
Definition: dbwrapper.h:28
Application-specific storage settings.
Definition: dbwrapper.h:32
DBOptions options
Passed-through options.
Definition: dbwrapper.h:45
bool obfuscate
If true, store data obfuscated via simple XOR.
Definition: dbwrapper.h:43
bool wipe_data
If true, remove all existing data.
Definition: dbwrapper.h:40
size_t cache_bytes
Configures various leveldb cache settings.
Definition: dbwrapper.h:36
fs::path path
Location in the filesystem where leveldb data will be stored.
Definition: dbwrapper.h:34
bool memory_only
If true, use leveldb's memory environment.
Definition: dbwrapper.h:38