Bitcoin Core 32.99.0
P2P Digital Currency
dbwrapper.h
Go to the documentation of this file.
1// Copyright (c) 2012-present 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 <attributes.h>
9#include <serialize.h>
10#include <span.h>
11#include <streams.h>
12#include <util/byte_units.h>
13#include <util/check.h>
14#include <util/expected.h>
15#include <util/fs.h>
16#include <util/obfuscation.h>
17
18#include <cstddef>
19#include <cstdint>
20#include <exception>
21#include <memory>
22#include <optional>
23#include <span>
24#include <stdexcept>
25#include <string>
26
27namespace leveldb {
28class Env;
29} // namespace leveldb
30
31inline constexpr size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
32inline constexpr size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
33inline constexpr size_t DBWRAPPER_MAX_FILE_SIZE{32_MiB};
34
36struct DBOptions {
38 bool force_compact = false;
39};
40
42struct DBParams {
44 fs::path path;
46 uint64_t cache_bytes;
48 bool memory_only = false;
50 bool wipe_data = false;
53 bool obfuscate = false;
55 bool bloom_filter = true;
60 leveldb::Env* testing_env = nullptr;
64};
65
66class dbwrapper_error : public std::runtime_error
67{
68public:
69 explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
70};
71
72class CDBWrapper;
73
76namespace dbwrapper_private {
77
83}; // namespace dbwrapper_private
84
85bool DestroyDB(const std::string& path_str);
86
89{
90 friend class CDBWrapper;
91
92private:
94
95 struct WriteBatchImpl;
96 const std::unique_ptr<WriteBatchImpl> m_impl_batch;
97
100
101 void WriteImpl(std::span<const std::byte> key, DataStream& value);
102 void EraseImpl(std::span<const std::byte> key);
103
104public:
108 explicit CDBBatch(const CDBWrapper& _parent);
110 void Clear();
111
112 template <typename K, typename V>
113 void Write(const K& key, const V& value)
114 {
115 ScopedDataStreamUsage scoped_key{m_key_scratch}, scoped_value{m_value_scratch};
116 m_key_scratch << key;
117 m_value_scratch << value;
119 }
120
121 template <typename K>
122 void Erase(const K& key)
123 {
125 m_key_scratch << key;
127 }
128
129 size_t ApproximateSize() const;
130};
131
133{
134public:
135 struct IteratorImpl;
136
137private:
139 const std::unique_ptr<IteratorImpl> m_impl_iter;
141
142 void SeekImpl(std::span<const std::byte> key);
143 std::span<const std::byte> GetKeyImpl() const;
144 std::span<const std::byte> GetValueImpl() const;
145
146public:
147
152 CDBIterator(const CDBWrapper& _parent, std::unique_ptr<IteratorImpl> _piter);
154
155 bool Valid() const;
156
157 void SeekToFirst();
158
159 template<typename K> void Seek(const K& key) {
160 ScopedDataStreamUsage scoped_scratch{m_scratch};
161 m_scratch << key;
163 }
164
165 void Next();
166
167 template<typename K> bool GetKey(K& key) {
168 try {
169 SpanReader ssKey{GetKeyImpl()};
170 ssKey >> key;
171 } catch (const std::exception&) {
172 return false;
173 }
174 return true;
175 }
176
177 template<typename V> bool GetValue(V& value) {
178 try {
179 ScopedDataStreamUsage scoped_scratch{m_scratch};
182 m_scratch >> value;
183 } catch (const std::exception&) {
184 return false;
185 }
186 return true;
187 }
188};
189
190struct LevelDBContext;
191
193{
195private:
197 std::unique_ptr<LevelDBContext> m_db_context;
198
200 std::string m_name;
201
204
206 inline static const std::string OBFUSCATION_KEY{"\000obfuscate_key", 14}; // explicit size to avoid truncation at leading \0
207
208 std::optional<std::string> ReadImpl(std::span<const std::byte> key) const;
209 bool ExistsImpl(std::span<const std::byte> key) const;
210 size_t EstimateSizeImpl(std::span<const std::byte> key1, std::span<const std::byte> key2) const;
211 auto& DBContext() const LIFETIMEBOUND { return *Assert(m_db_context); }
212
213public:
214 CDBWrapper(const DBParams& params);
215 ~CDBWrapper();
216
217 CDBWrapper(const CDBWrapper&) = delete;
218 CDBWrapper& operator=(const CDBWrapper&) = delete;
219
220 struct ReadFailure {
221 enum class Code {
222 DeserializationError,
223 DatabaseError,
224 };
225
227 std::string err_msg;
228 };
229
231
248 template <typename K, typename V>
249 [[nodiscard]] ReadStatus TryRead(const K& key, V& value) const
250 {
251 DataStream ssKey{};
253 // Key serialization is the only operation that may throw.
254 // Callers are expected to provide well-formed keys.
255 ssKey << key;
256
257 std::optional<std::string> strValue;
258 try {
259 strValue = ReadImpl(ssKey);
260 if (!strValue) {
261 return false; // not found
262 }
263 } catch (const std::exception& e) {
265 }
266
267 try {
268 std::span ssValue{MakeWritableByteSpan(*strValue)};
269 m_obfuscation(ssValue);
270 SpanReader{ssValue} >> value;
271 } catch (const std::exception& e) {
273 }
274
275 return true;
276 }
277
286 template <typename K, typename V>
287 bool Read(const K& key, V& value) const
288 {
289 const ReadStatus res = TryRead(key,value);
290 if (res.has_value()) return res.value();
291 switch (const auto& [err_code, err_msg] = res.error(); err_code) {
294 } // no default case, so the compiler can warn about missing cases
295 std::abort(); // unreachable
296 }
297
298 template <typename K, typename V>
299 void Write(const K& key, const V& value, bool fSync = false)
300 {
301 CDBBatch batch(*this);
302 batch.Write(key, value);
303 WriteBatch(batch, fSync);
304 }
305
306 template <typename K>
307 bool Exists(const K& key) const
308 {
309 DataStream ssKey{};
311 ssKey << key;
312 return ExistsImpl(ssKey);
313 }
314
315 template <typename K>
316 void Erase(const K& key, bool fSync = false)
317 {
318 CDBBatch batch(*this);
319 batch.Erase(key);
320 WriteBatch(batch, fSync);
321 }
322
323 void WriteBatch(CDBBatch& batch, bool fSync = false);
324
326 void CompactFull();
327
329 std::optional<std::string> GetProperty(const std::string& property) const;
330
331 // Get an estimate of LevelDB memory usage (in bytes).
332 size_t DynamicMemoryUsage() const;
333
335
339 bool IsEmpty();
340
344 static bool HasKeyStartingWith(const fs::path& path, uint8_t prefix);
345
346 template<typename K>
347 size_t EstimateSize(const K& key_begin, const K& key_end) const
348 {
349 DataStream ssKey1{}, ssKey2{};
351 ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
352 ssKey1 << key_begin;
353 ssKey2 << key_end;
354 return EstimateSizeImpl(ssKey1, ssKey2);
355 }
356};
357
358#endif // BITCOIN_DBWRAPPER_H
#define LIFETIMEBOUND
Definition: attributes.h:16
#define Assert(val)
Identity function.
Definition: check.h:116
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:89
void Erase(const K &key)
Definition: dbwrapper.h:122
const std::unique_ptr< WriteBatchImpl > m_impl_batch
Definition: dbwrapper.h:96
void WriteImpl(std::span< const std::byte > key, DataStream &value)
Definition: dbwrapper.cpp:202
void Write(const K &key, const V &value)
Definition: dbwrapper.h:113
void EraseImpl(std::span< const std::byte > key)
Definition: dbwrapper.cpp:210
void Clear()
Definition: dbwrapper.cpp:195
CDBBatch(const CDBWrapper &_parent)
Definition: dbwrapper.cpp:184
DataStream m_key_scratch
Definition: dbwrapper.h:98
size_t ApproximateSize() const
Definition: dbwrapper.cpp:216
const CDBWrapper & parent
Definition: dbwrapper.h:93
DataStream m_value_scratch
Definition: dbwrapper.h:99
CDBIterator(const CDBWrapper &_parent, std::unique_ptr< IteratorImpl > _piter)
Definition: dbwrapper.cpp:398
bool GetValue(V &value)
Definition: dbwrapper.h:177
const std::unique_ptr< IteratorImpl > m_impl_iter
Definition: dbwrapper.h:139
void SeekImpl(std::span< const std::byte > key)
Definition: dbwrapper.cpp:409
std::span< const std::byte > GetKeyImpl() const
Definition: dbwrapper.cpp:415
bool GetKey(K &key)
Definition: dbwrapper.h:167
DataStream m_scratch
Definition: dbwrapper.h:140
void Seek(const K &key)
Definition: dbwrapper.h:159
const CDBWrapper & parent
Definition: dbwrapper.h:138
bool Valid() const
Definition: dbwrapper.cpp:428
void SeekToFirst()
Definition: dbwrapper.cpp:429
void Next()
Definition: dbwrapper.cpp:430
std::span< const std::byte > GetValueImpl() const
Definition: dbwrapper.cpp:422
CDBWrapper(const CDBWrapper &)=delete
std::optional< std::string > ReadImpl(std::span< const std::byte > key) const
Definition: dbwrapper.cpp:346
size_t EstimateSizeImpl(std::span< const std::byte > key1, std::span< const std::byte > key2) const
Definition: dbwrapper.cpp:375
void CompactFull()
Perform a blocking full compaction of the underlying LevelDB.
Definition: dbwrapper.cpp:334
size_t DynamicMemoryUsage() const
Definition: dbwrapper.cpp:336
bool Read(const K &key, V &value) const
Wrapper around TryRead() that preserves the original Read() semantics: returns true on success,...
Definition: dbwrapper.h:287
CDBIterator * NewIterator()
Definition: dbwrapper.cpp:404
std::string m_name
the name of this database
Definition: dbwrapper.h:200
bool Exists(const K &key) const
Definition: dbwrapper.h:307
CDBWrapper(const DBParams &params)
Definition: dbwrapper.cpp:244
void Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:316
void WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:312
bool ExistsImpl(std::span< const std::byte > key) const
Definition: dbwrapper.cpp:360
void Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:299
static bool HasKeyStartingWith(const fs::path &path, uint8_t prefix)
Probe an unopened database for a key prefix.
Definition: dbwrapper.cpp:156
Obfuscation m_obfuscation
optional XOR-obfuscation of the database
Definition: dbwrapper.h:203
std::unique_ptr< LevelDBContext > m_db_context
holds all leveldb-specific fields of this class
Definition: dbwrapper.h:197
CDBWrapper & operator=(const CDBWrapper &)=delete
static const std::string OBFUSCATION_KEY
obfuscation key storage key, null-prefixed to avoid collisions
Definition: dbwrapper.h:206
auto & DBContext() const LIFETIMEBOUND
Definition: dbwrapper.h:211
bool IsEmpty()
Return true if the database managed by this class contains no entries.
Definition: dbwrapper.cpp:385
ReadStatus TryRead(const K &key, V &value) const
Read and deserialize a value from the database, with explicit error discrimination.
Definition: dbwrapper.h:249
std::optional< std::string > GetProperty(const std::string &property) const
Return a LevelDB property value, if available.
Definition: dbwrapper.cpp:328
size_t EstimateSize(const K &key_begin, const K &key_end) const
Definition: dbwrapper.h:347
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:165
void write(std::span< const value_type > src)
Definition: streams.h:244
void reserve(size_type n)
Definition: streams.h:201
Minimal stream for reading from an existing byte array by std::span.
Definition: streams.h:83
dbwrapper_error(const std::string &msg)
Definition: dbwrapper.h:69
The util::Expected class provides a standard way for low-level functions to return either error value...
Definition: expected.h:44
constexpr bool has_value() const noexcept
Definition: expected.h:56
constexpr const T & value() const &LIFETIMEBOUND
Definition: expected.h:59
constexpr const E & error() const &noexcept LIFETIMEBOUND
Definition: expected.h:86
The util::Unexpected class represents an unexpected value stored in util::Expected.
Definition: expected.h:21
bool DestroyDB(const std::string &path_str)
Definition: dbwrapper.cpp:39
constexpr size_t DBWRAPPER_PREALLOC_KEY_SIZE
Definition: dbwrapper.h:31
constexpr size_t DBWRAPPER_MAX_FILE_SIZE
Definition: dbwrapper.h:33
constexpr size_t DBWRAPPER_PREALLOC_VALUE_SIZE
Definition: dbwrapper.h:32
These should be considered an implementation detail of the specific database.
Definition: dbwrapper.cpp:432
const Obfuscation & GetObfuscation(const CDBWrapper &w)
Work around circular dependency, as well as for testing in dbwrapper_tests.
Definition: dbwrapper.cpp:434
const char * prefix
Definition: rest.cpp:1195
auto MakeWritableByteSpan(V &&v) noexcept
Definition: span.h:89
@ DeserializationError
Key exists but value could not be deserialized.
@ DatabaseError
Unexpected internal DB error.
User-controlled performance and debug options.
Definition: dbwrapper.h:36
bool force_compact
Compact database on startup.
Definition: dbwrapper.h:38
Application-specific storage settings.
Definition: dbwrapper.h:42
DBOptions options
Passed-through options.
Definition: dbwrapper.h:57
bool obfuscate
If true, store data obfuscated via simple XOR.
Definition: dbwrapper.h:53
size_t max_file_size
Maximum LevelDB SST file size.
Definition: dbwrapper.h:63
bool wipe_data
If true, remove all existing data.
Definition: dbwrapper.h:50
uint64_t cache_bytes
Configures various leveldb cache settings.
Definition: dbwrapper.h:46
leveldb::Env * testing_env
If non-null, use this as the leveldb::Env instead of the default.
Definition: dbwrapper.h:60
fs::path path
Location in the filesystem where leveldb data will be stored.
Definition: dbwrapper.h:44
bool bloom_filter
If true, build a LevelDB bloom filter to accelerate point lookups.
Definition: dbwrapper.h:55
bool memory_only
If true, use leveldb's memory environment.
Definition: dbwrapper.h:48