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/not_null.h>
17#include <util/obfuscation.h>
18
19#include <cstddef>
20#include <cstdint>
21#include <exception>
22#include <memory>
23#include <optional>
24#include <span>
25#include <stdexcept>
26#include <string>
27
28namespace leveldb {
29class Env;
30} // namespace leveldb
31
32inline constexpr size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
33inline constexpr size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
34inline constexpr size_t DBWRAPPER_MAX_FILE_SIZE{32_MiB};
35
37struct DBOptions {
39 bool force_compact = false;
40};
41
43struct DBParams {
45 fs::path path;
47 uint64_t cache_bytes;
49 bool memory_only = false;
51 bool wipe_data = false;
54 bool obfuscate = false;
56 bool bloom_filter = true;
61 leveldb::Env* testing_env = nullptr;
65};
66
67class dbwrapper_error : public std::runtime_error
68{
69public:
70 explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
71};
72
73class CDBWrapper;
74
77namespace dbwrapper_private {
78
84}; // namespace dbwrapper_private
85
86bool DestroyDB(const std::string& path_str);
87
90{
91 friend class CDBWrapper;
92
93private:
95
96 struct WriteBatchImpl;
97 const std::unique_ptr<WriteBatchImpl> m_impl_batch;
98
101
102 void WriteImpl(std::span<const std::byte> key, DataStream& value);
103 void EraseImpl(std::span<const std::byte> key);
104
105public:
109 explicit CDBBatch(const CDBWrapper& _parent);
111 void Clear();
112
113 template <typename K, typename V>
114 void Write(const K& key, const V& value)
115 {
116 ScopedDataStreamUsage scoped_key{m_key_scratch}, scoped_value{m_value_scratch};
117 m_key_scratch << key;
118 m_value_scratch << value;
120 }
121
122 template <typename K>
123 void Erase(const K& key)
124 {
126 m_key_scratch << key;
128 }
129
130 size_t ApproximateSize() const;
131};
132
134{
135public:
136 struct IteratorImpl;
137
138private:
140 const std::unique_ptr<IteratorImpl> m_impl_iter;
142
143 void SeekImpl(std::span<const std::byte> key);
144 std::span<const std::byte> GetKeyImpl() const;
145 std::span<const std::byte> GetValueImpl() const;
146
147public:
148
153 CDBIterator(const CDBWrapper& _parent, std::unique_ptr<IteratorImpl> _piter);
155
156 bool Valid() const;
157
158 void SeekToFirst();
159
160 template<typename K> void Seek(const K& key) {
161 ScopedDataStreamUsage scoped_scratch{m_scratch};
162 m_scratch << key;
164 }
165
166 void Next();
167
168 template<typename K> bool GetKey(K& key) {
169 try {
170 SpanReader ssKey{GetKeyImpl()};
171 ssKey >> key;
172 } catch (const std::exception&) {
173 return false;
174 }
175 return true;
176 }
177
178 template<typename V> bool GetValue(V& value) {
179 try {
180 ScopedDataStreamUsage scoped_scratch{m_scratch};
183 m_scratch >> value;
184 } catch (const std::exception&) {
185 return false;
186 }
187 return true;
188 }
189};
190
191struct LevelDBContext;
192
194{
196private:
199
201 std::string m_name;
202
205
207 inline static const std::string OBFUSCATION_KEY{"\000obfuscate_key", 14}; // explicit size to avoid truncation at leading \0
208
209 std::optional<std::string> ReadImpl(std::span<const std::byte> key) const;
210 bool ExistsImpl(std::span<const std::byte> key) const;
211 size_t EstimateSizeImpl(std::span<const std::byte> key1, std::span<const std::byte> key2) const;
212 auto& DBContext() const LIFETIMEBOUND { return *m_db_context; }
213
214public:
215 CDBWrapper(const DBParams& params);
216 ~CDBWrapper();
217
218 CDBWrapper(const CDBWrapper&) = delete;
219 CDBWrapper& operator=(const CDBWrapper&) = delete;
220
221 struct ReadFailure {
222 enum class Code {
223 DeserializationError,
224 DatabaseError,
225 };
226
228 std::string err_msg;
229 };
230
232
249 template <typename K, typename V>
250 [[nodiscard]] ReadStatus TryRead(const K& key, V& value) const
251 {
252 DataStream ssKey{};
254 // Key serialization is the only operation that may throw.
255 // Callers are expected to provide well-formed keys.
256 ssKey << key;
257
258 std::optional<std::string> strValue;
259 try {
260 strValue = ReadImpl(ssKey);
261 if (!strValue) {
262 return false; // not found
263 }
264 } catch (const std::exception& e) {
266 }
267
268 try {
269 std::span ssValue{MakeWritableByteSpan(*strValue)};
270 m_obfuscation(ssValue);
271 SpanReader{ssValue} >> value;
272 } catch (const std::exception& e) {
274 }
275
276 return true;
277 }
278
287 template <typename K, typename V>
288 bool Read(const K& key, V& value) const
289 {
290 const ReadStatus res = TryRead(key,value);
291 if (res.has_value()) return res.value();
292 switch (const auto& [err_code, err_msg] = res.error(); err_code) {
295 } // no default case, so the compiler can warn about missing cases
296 std::abort(); // unreachable
297 }
298
299 template <typename K, typename V>
300 void Write(const K& key, const V& value, bool fSync = false)
301 {
302 CDBBatch batch(*this);
303 batch.Write(key, value);
304 WriteBatch(batch, fSync);
305 }
306
307 template <typename K>
308 bool Exists(const K& key) const
309 {
310 DataStream ssKey{};
312 ssKey << key;
313 return ExistsImpl(ssKey);
314 }
315
316 template <typename K>
317 void Erase(const K& key, bool fSync = false)
318 {
319 CDBBatch batch(*this);
320 batch.Erase(key);
321 WriteBatch(batch, fSync);
322 }
323
324 void WriteBatch(CDBBatch& batch, bool fSync = false);
325
327 void CompactFull();
328
330 std::optional<std::string> GetProperty(const std::string& property) const;
331
332 // Get an estimate of LevelDB memory usage (in bytes).
333 size_t DynamicMemoryUsage() const;
334
336
340 bool IsEmpty();
341
345 static bool HasKeyStartingWith(const fs::path& path, uint8_t prefix);
346
347 template<typename K>
348 size_t EstimateSize(const K& key_begin, const K& key_end) const
349 {
350 DataStream ssKey1{}, ssKey2{};
352 ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
353 ssKey1 << key_begin;
354 ssKey2 << key_end;
355 return EstimateSizeImpl(ssKey1, ssKey2);
356 }
357};
358
359#endif // BITCOIN_DBWRAPPER_H
#define LIFETIMEBOUND
Definition: attributes.h:16
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:90
void Erase(const K &key)
Definition: dbwrapper.h:123
const std::unique_ptr< WriteBatchImpl > m_impl_batch
Definition: dbwrapper.h:97
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:114
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:99
size_t ApproximateSize() const
Definition: dbwrapper.cpp:216
const CDBWrapper & parent
Definition: dbwrapper.h:94
DataStream m_value_scratch
Definition: dbwrapper.h:100
CDBIterator(const CDBWrapper &_parent, std::unique_ptr< IteratorImpl > _piter)
Definition: dbwrapper.cpp:398
bool GetValue(V &value)
Definition: dbwrapper.h:178
const std::unique_ptr< IteratorImpl > m_impl_iter
Definition: dbwrapper.h:140
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:168
DataStream m_scratch
Definition: dbwrapper.h:141
void Seek(const K &key)
Definition: dbwrapper.h:160
const CDBWrapper & parent
Definition: dbwrapper.h:139
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
util::NotNullUniquePtr< LevelDBContext > m_db_context
holds all leveldb-specific fields of this class
Definition: dbwrapper.h:198
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:288
CDBIterator * NewIterator()
Definition: dbwrapper.cpp:404
std::string m_name
the name of this database
Definition: dbwrapper.h:201
bool Exists(const K &key) const
Definition: dbwrapper.h:308
CDBWrapper(const DBParams &params)
Definition: dbwrapper.cpp:244
void Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:317
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:300
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:204
CDBWrapper & operator=(const CDBWrapper &)=delete
static const std::string OBFUSCATION_KEY
obfuscation key storage key, null-prefixed to avoid collisions
Definition: dbwrapper.h:207
auto & DBContext() const LIFETIMEBOUND
Definition: dbwrapper.h:212
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:250
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:348
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:70
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
NotNull is intended to be used to denote that a smart pointer type can not hold a nullptr value.
Definition: not_null.h:45
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:32
constexpr size_t DBWRAPPER_MAX_FILE_SIZE
Definition: dbwrapper.h:34
constexpr size_t DBWRAPPER_PREALLOC_VALUE_SIZE
Definition: dbwrapper.h:33
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:1197
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:37
bool force_compact
Compact database on startup.
Definition: dbwrapper.h:39
Application-specific storage settings.
Definition: dbwrapper.h:43
DBOptions options
Passed-through options.
Definition: dbwrapper.h:58
bool obfuscate
If true, store data obfuscated via simple XOR.
Definition: dbwrapper.h:54
size_t max_file_size
Maximum LevelDB SST file size.
Definition: dbwrapper.h:64
bool wipe_data
If true, remove all existing data.
Definition: dbwrapper.h:51
uint64_t cache_bytes
Configures various leveldb cache settings.
Definition: dbwrapper.h:47
leveldb::Env * testing_env
If non-null, use this as the leveldb::Env instead of the default.
Definition: dbwrapper.h:61
fs::path path
Location in the filesystem where leveldb data will be stored.
Definition: dbwrapper.h:45
bool bloom_filter
If true, build a LevelDB bloom filter to accelerate point lookups.
Definition: dbwrapper.h:56
bool memory_only
If true, use leveldb's memory environment.
Definition: dbwrapper.h:49