Bitcoin Core 31.99.0
P2P Digital Currency
dbwrapper.cpp
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#include <dbwrapper.h>
6
7#include <leveldb/cache.h>
8#include <leveldb/db.h>
9#include <leveldb/env.h>
10#include <leveldb/filter_policy.h>
11#include <leveldb/helpers/memenv/memenv.h>
12#include <leveldb/iterator.h>
13#include <leveldb/options.h>
14#include <leveldb/slice.h>
15#include <leveldb/status.h>
16#include <leveldb/write_batch.h>
17#include <random.h>
18#include <serialize.h>
19#include <span.h>
20#include <streams.h>
21#include <util/byte_units.h>
22#include <util/fs.h>
23#include <util/fs_helpers.h>
24#include <util/log.h>
25#include <util/obfuscation.h>
26#include <util/strencodings.h>
27
28#include <algorithm>
29#include <cassert>
30#include <cstdarg>
31#include <cstdint>
32#include <cstdio>
33#include <memory>
34#include <optional>
35#include <utility>
36
37static auto CharCast(const std::byte* data) { return reinterpret_cast<const char*>(data); }
38
39bool DestroyDB(const std::string& path_str)
40{
41 return leveldb::DestroyDB(path_str, {}).ok();
42}
43
46static void HandleError(const leveldb::Status& status)
47{
48 if (status.ok())
49 return;
50 const std::string errmsg = "Fatal LevelDB error: " + status.ToString();
51 LogError("%s", errmsg);
52 LogInfo("You can use -debug=leveldb to get more complete diagnostic messages");
53 throw dbwrapper_error(errmsg);
54}
55
56class CBitcoinLevelDBLogger : public leveldb::Logger {
57public:
58 // This code is adapted from posix_logger.h, which is why it is using vsprintf.
59 // Please do not do this in normal code
60 void Logv(const char * format, va_list ap) override {
62 return;
63 }
64 char buffer[500];
65 for (int iter = 0; iter < 2; iter++) {
66 char* base;
67 int bufsize;
68 if (iter == 0) {
69 bufsize = sizeof(buffer);
70 base = buffer;
71 }
72 else {
73 bufsize = 30000;
74 base = new char[bufsize];
75 }
76 char* p = base;
77 char* limit = base + bufsize;
78
79 // Print the message
80 if (p < limit) {
81 va_list backup_ap;
82 va_copy(backup_ap, ap);
83 // Do not use vsnprintf elsewhere in bitcoin source code, see above.
84 p += vsnprintf(p, limit - p, format, backup_ap);
85 va_end(backup_ap);
86 }
87
88 // Truncate to available space if necessary
89 if (p >= limit) {
90 if (iter == 0) {
91 continue; // Try again with larger buffer
92 }
93 else {
94 p = limit - 1;
95 }
96 }
97
98 // Add newline if necessary
99 if (p == base || p[-1] != '\n') {
100 *p++ = '\n';
101 }
102
103 assert(p <= limit);
104 base[std::min(bufsize - 1, (int)(p - base))] = '\0';
105 LogDebug(BCLog::LEVELDB, "%s\n", util::RemoveSuffixView(base, "\n"));
106 if (base != buffer) {
107 delete[] base;
108 }
109 break;
110 }
111 }
112};
113
114static void SetMaxOpenFiles(leveldb::Options *options) {
115 // On most platforms the default setting of max_open_files (which is 1000)
116 // is optimal. On Windows using a large file count is OK because the handles
117 // do not interfere with select() loops. On 64-bit Unix hosts this value is
118 // also OK, because up to that amount LevelDB will use an mmap
119 // implementation that does not use extra file descriptors (the fds are
120 // closed after being mmap'ed).
121 //
122 // Increasing the value beyond the default is dangerous because LevelDB will
123 // fall back to a non-mmap implementation when the file count is too large.
124 // On 32-bit Unix host we should decrease the value because the handles use
125 // up real fds, and we want to avoid fd exhaustion issues.
126 //
127 // See PR #12495 for further discussion.
128
129 int default_open_files = options->max_open_files;
130#ifndef WIN32
131 if (sizeof(void*) < 8) {
132 options->max_open_files = 64;
133 }
134#endif
135 LogDebug(BCLog::LEVELDB, "LevelDB using max_open_files=%d (default=%d)\n",
136 options->max_open_files, default_open_files);
137}
138
139static leveldb::Options GetOptions(size_t nCacheSize, bool bloom_filter)
140{
141 leveldb::Options options;
142 options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
143 options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously
144 options.filter_policy = bloom_filter ? leveldb::NewBloomFilterPolicy(10) : nullptr;
145 options.compression = leveldb::kNoCompression;
146 options.info_log = new CBitcoinLevelDBLogger();
147 if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
148 // LevelDB versions before 1.16 consider short writes to be corruption. Only trigger error
149 // on corruption in later versions.
150 options.paranoid_checks = true;
151 }
152 SetMaxOpenFiles(&options);
153 return options;
154}
155
156bool CDBWrapper::HasKeyStartingWith(const fs::path& path, uint8_t prefix)
157{
158 if (!fs::exists(path / "CURRENT")) return false;
159
161 leveldb::Options options;
162 options.paranoid_checks = true;
163 // Avoid creating or rotating LevelDB's LOG files during this probe.
164 options.info_log = &logger;
165
166 leveldb::DB* raw_db;
167 HandleError(leveldb::DB::Open(options, fs::PathToString(path), &raw_db));
168 const std::unique_ptr<leveldb::DB> db{raw_db};
169
170 leveldb::ReadOptions iteroptions;
171 iteroptions.verify_checksums = true;
172 iteroptions.fill_cache = false;
173 const std::unique_ptr<leveldb::Iterator> it{db->NewIterator(iteroptions)};
174 const leveldb::Slice prefix_slice{reinterpret_cast<const char*>(&prefix), sizeof(prefix)};
175 it->Seek(prefix_slice);
176 HandleError(it->status());
177 return it->Valid() && it->key().starts_with(prefix_slice);
178}
179
181 leveldb::WriteBatch batch;
182};
183
185 : parent{_parent},
186 m_impl_batch{std::make_unique<CDBBatch::WriteBatchImpl>()}
187{
190 Clear();
191};
192
193CDBBatch::~CDBBatch() = default;
194
196{
197 m_impl_batch->batch.Clear();
200}
201
202void CDBBatch::WriteImpl(std::span<const std::byte> key, DataStream& value)
203{
204 leveldb::Slice slKey(CharCast(key.data()), key.size());
206 leveldb::Slice slValue(CharCast(value.data()), value.size());
207 m_impl_batch->batch.Put(slKey, slValue);
208}
209
210void CDBBatch::EraseImpl(std::span<const std::byte> key)
211{
212 leveldb::Slice slKey(CharCast(key.data()), key.size());
213 m_impl_batch->batch.Delete(slKey);
214}
215
217{
218 return m_impl_batch->batch.ApproximateSize();
219}
220
223 leveldb::Env* penv;
224
226 leveldb::Options options;
227
229 leveldb::ReadOptions readoptions;
230
232 leveldb::ReadOptions iteroptions;
233
235 leveldb::WriteOptions writeoptions;
236
238 leveldb::WriteOptions syncoptions;
239
241 leveldb::DB* pdb;
242};
243
245 : m_db_context{std::make_unique<LevelDBContext>()}, m_name{fs::PathToString(params.path.stem())}
246{
247 DBContext().penv = nullptr;
248 DBContext().readoptions.verify_checksums = true;
249 DBContext().iteroptions.verify_checksums = true;
250 DBContext().iteroptions.fill_cache = false;
251 DBContext().syncoptions.sync = true;
252 DBContext().options = GetOptions(params.cache_bytes, params.bloom_filter);
253 DBContext().options.create_if_missing = true;
254 DBContext().options.max_file_size = params.max_file_size;
255 assert(!(params.testing_env && params.memory_only));
256 if (params.testing_env) {
257 DBContext().options.env = params.testing_env;
258 } else if (params.memory_only) {
259 DBContext().penv = leveldb::NewMemEnv(leveldb::Env::Default());
260 DBContext().options.env = DBContext().penv;
261 }
262 if (!params.memory_only) {
263 if (params.wipe_data) {
264 LogInfo("Wiping LevelDB in %s", fs::PathToString(params.path));
265 leveldb::Status result = leveldb::DestroyDB(fs::PathToString(params.path), DBContext().options);
266 HandleError(result);
267 }
268 if (!params.testing_env) {
270 }
271 LogInfo("Opening LevelDB in %s", fs::PathToString(params.path));
272 }
273 // PathToString() return value is safe to pass to leveldb open function,
274 // because on POSIX leveldb passes the byte string directly to ::open(), and
275 // on Windows it converts from UTF-8 to UTF-16 before calling ::CreateFileW
276 // (see env_posix.cc and env_windows.cc).
277 leveldb::Status status = leveldb::DB::Open(DBContext().options, fs::PathToString(params.path), &DBContext().pdb);
278 HandleError(status);
279 LogInfo("Opened LevelDB successfully");
280
281 if (params.options.force_compact) {
282 LogInfo("Starting database compaction of %s", fs::PathToString(params.path));
283 CompactFull();
284 LogInfo("Finished database compaction of %s", fs::PathToString(params.path));
285 }
286
287 if (!Read(OBFUSCATION_KEY, m_obfuscation) && params.obfuscate && IsEmpty()) {
288 // Generate and write the new obfuscation key.
290 assert(!m_obfuscation); // Make sure the key is written without obfuscation.
291 Write(OBFUSCATION_KEY, obfuscation);
292 m_obfuscation = obfuscation;
293 LogInfo("Wrote new obfuscation key for %s: %s", fs::PathToString(params.path), m_obfuscation.HexKey());
294 }
295 LogInfo("Using obfuscation key for %s: %s", fs::PathToString(params.path), m_obfuscation.HexKey());
296}
297
299{
300 delete DBContext().pdb;
301 DBContext().pdb = nullptr;
302 delete DBContext().options.filter_policy;
303 DBContext().options.filter_policy = nullptr;
304 delete DBContext().options.info_log;
305 DBContext().options.info_log = nullptr;
306 delete DBContext().options.block_cache;
307 DBContext().options.block_cache = nullptr;
308 delete DBContext().penv;
309 DBContext().options.env = nullptr;
310}
311
312void CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync)
313{
314 const bool log_memory = util::log::ShouldDebugLog(BCLog::LEVELDB);
315 double mem_before = 0;
316 if (log_memory) {
317 mem_before = DynamicMemoryUsage() / double(1_MiB);
318 }
319 leveldb::Status status = DBContext().pdb->Write(fSync ? DBContext().syncoptions : DBContext().writeoptions, &batch.m_impl_batch->batch);
320 HandleError(status);
321 if (log_memory) {
322 double mem_after{DynamicMemoryUsage() / double(1_MiB)};
323 LogDebug(BCLog::LEVELDB, "WriteBatch memory usage: db=%s, before=%.1fMiB, after=%.1fMiB\n",
324 m_name, mem_before, mem_after);
325 }
326}
327
328std::optional<std::string> CDBWrapper::GetProperty(const std::string& property) const
329{
330 if (std::string value; DBContext().pdb->GetProperty(property, &value)) return value;
331 return std::nullopt;
332}
333
334void CDBWrapper::CompactFull() { DBContext().pdb->CompactRange(nullptr, nullptr); }
335
337{
338 std::optional<size_t> parsed;
339 if (auto memory{GetProperty("leveldb.approximate-memory-usage")}; !memory || !(parsed = ToIntegral<size_t>(*memory))) {
340 LogDebug(BCLog::LEVELDB, "Failed to get approximate-memory-usage property\n");
341 return 0;
342 }
343 return parsed.value();
344}
345
346std::optional<std::string> CDBWrapper::ReadImpl(std::span<const std::byte> key) const
347{
348 leveldb::Slice slKey(CharCast(key.data()), key.size());
349 std::string strValue;
350 leveldb::Status status = DBContext().pdb->Get(DBContext().readoptions, slKey, &strValue);
351 if (!status.ok()) {
352 if (status.IsNotFound())
353 return std::nullopt;
354 LogError("LevelDB read failure: %s", status.ToString());
355 HandleError(status);
356 }
357 return strValue;
358}
359
360bool CDBWrapper::ExistsImpl(std::span<const std::byte> key) const
361{
362 leveldb::Slice slKey(CharCast(key.data()), key.size());
363
364 std::string strValue;
365 leveldb::Status status = DBContext().pdb->Get(DBContext().readoptions, slKey, &strValue);
366 if (!status.ok()) {
367 if (status.IsNotFound())
368 return false;
369 LogError("LevelDB read failure: %s", status.ToString());
370 HandleError(status);
371 }
372 return true;
373}
374
375size_t CDBWrapper::EstimateSizeImpl(std::span<const std::byte> key1, std::span<const std::byte> key2) const
376{
377 leveldb::Slice slKey1(CharCast(key1.data()), key1.size());
378 leveldb::Slice slKey2(CharCast(key2.data()), key2.size());
379 uint64_t size = 0;
380 leveldb::Range range(slKey1, slKey2);
381 DBContext().pdb->GetApproximateSizes(&range, 1, &size);
382 return size;
383}
384
386{
387 std::unique_ptr<CDBIterator> it(NewIterator());
388 it->SeekToFirst();
389 return !(it->Valid());
390}
391
393 const std::unique_ptr<leveldb::Iterator> iter;
394
395 explicit IteratorImpl(leveldb::Iterator* _iter) : iter{_iter} {}
396};
397
398CDBIterator::CDBIterator(const CDBWrapper& _parent, std::unique_ptr<IteratorImpl> _piter) : parent(_parent),
399 m_impl_iter(std::move(_piter))
400{
402}
403
405{
406 return new CDBIterator{*this, std::make_unique<CDBIterator::IteratorImpl>(DBContext().pdb->NewIterator(DBContext().iteroptions))};
407}
408
409void CDBIterator::SeekImpl(std::span<const std::byte> key)
410{
411 leveldb::Slice slKey(CharCast(key.data()), key.size());
412 m_impl_iter->iter->Seek(slKey);
413}
414
415std::span<const std::byte> CDBIterator::GetKeyImpl() const
416{
417 // The returned span borrows from the current iterator entry and is only
418 // valid until the iterator is advanced.
419 return MakeByteSpan(m_impl_iter->iter->key());
420}
421
422std::span<const std::byte> CDBIterator::GetValueImpl() const
423{
424 return MakeByteSpan(m_impl_iter->iter->value());
425}
426
427CDBIterator::~CDBIterator() = default;
428bool CDBIterator::Valid() const { return m_impl_iter->iter->Valid(); }
429void CDBIterator::SeekToFirst() { m_impl_iter->iter->SeekToFirst(); }
430void CDBIterator::Next() { m_impl_iter->iter->Next(); }
431
433
435{
436 return w.m_obfuscation;
437}
438
439} // namespace dbwrapper_private
void Logv(const char *format, va_list ap) override
Definition: dbwrapper.cpp:60
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:88
const std::unique_ptr< WriteBatchImpl > m_impl_batch
Definition: dbwrapper.h:95
void WriteImpl(std::span< const std::byte > key, DataStream &value)
Definition: dbwrapper.cpp:202
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:97
size_t ApproximateSize() const
Definition: dbwrapper.cpp:216
const CDBWrapper & parent
Definition: dbwrapper.h:92
DataStream m_value_scratch
Definition: dbwrapper.h:98
CDBIterator(const CDBWrapper &_parent, std::unique_ptr< IteratorImpl > _piter)
Definition: dbwrapper.cpp:398
const std::unique_ptr< IteratorImpl > m_impl_iter
Definition: dbwrapper.h:138
void SeekImpl(std::span< const std::byte > key)
Definition: dbwrapper.cpp:409
std::span< const std::byte > GetKeyImpl() const
Definition: dbwrapper.cpp:415
DataStream m_scratch
Definition: dbwrapper.h:139
void Seek(const K &key)
Definition: dbwrapper.h:158
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
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
Definition: dbwrapper.h:220
CDBIterator * NewIterator()
Definition: dbwrapper.cpp:404
std::string m_name
the name of this database
Definition: dbwrapper.h:199
CDBWrapper(const DBParams &params)
Definition: dbwrapper.cpp:244
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:240
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:202
static const std::string OBFUSCATION_KEY
obfuscation key storage key, null-prefixed to avoid collisions
Definition: dbwrapper.h:205
auto & DBContext() const LIFETIMEBOUND
Definition: dbwrapper.h:210
bool IsEmpty()
Return true if the database managed by this class contains no entries.
Definition: dbwrapper.cpp:385
std::optional< std::string > GetProperty(const std::string &property) const
Return a LevelDB property value, if available.
Definition: dbwrapper.cpp:328
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:165
bool empty() const
Definition: streams.h:199
size_type size() const
Definition: streams.h:198
value_type * data()
Definition: streams.h:205
void reserve(size_type n)
Definition: streams.h:201
Fast randomness source.
Definition: random.h:386
std::string HexKey() const
Definition: obfuscation.h:80
static constexpr size_t KEY_SIZE
Definition: obfuscation.h:24
std::vector< B > randbytes(size_t len) noexcept
Generate random bytes.
Definition: random.h:297
static const PrecomputedData data
Precomputed COutPoint and CCoins values.
static auto CharCast(const std::byte *data)
Definition: dbwrapper.cpp:37
bool DestroyDB(const std::string &path_str)
Definition: dbwrapper.cpp:39
static void SetMaxOpenFiles(leveldb::Options *options)
Definition: dbwrapper.cpp:114
static void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
Definition: dbwrapper.cpp:46
static leveldb::Options GetOptions(size_t nCacheSize, bool bloom_filter)
Definition: dbwrapper.cpp:139
constexpr size_t DBWRAPPER_PREALLOC_KEY_SIZE
Definition: dbwrapper.h:30
constexpr size_t DBWRAPPER_PREALLOC_VALUE_SIZE
Definition: dbwrapper.h:31
static bool exists(const path &p)
Definition: fs.h:96
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:162
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by create_directories if the requested directory exists.
Definition: fs_helpers.cpp:274
#define LogInfo(...)
Definition: log.h:125
#define LogError(...)
Definition: log.h:127
#define LogDebug(category,...)
Definition: log.h:143
@ LEVELDB
Definition: categories.h:35
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
void format(std::ostream &out, FormatStringCheck< sizeof...(Args)> fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1079
bool ShouldDebugLog(Category category)
Return whether messages with specified category should be debug logged.
Definition: logging.cpp:619
std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix)
Definition: string.h:178
const char * prefix
Definition: rest.cpp:1179
auto MakeByteSpan(const V &v) noexcept
Definition: span.h:84
leveldb::WriteBatch batch
Definition: dbwrapper.cpp:181
IteratorImpl(leveldb::Iterator *_iter)
Definition: dbwrapper.cpp:395
const std::unique_ptr< leveldb::Iterator > iter
Definition: dbwrapper.cpp:393
bool force_compact
Compact database on startup.
Definition: dbwrapper.h:37
Application-specific storage settings.
Definition: dbwrapper.h:41
DBOptions options
Passed-through options.
Definition: dbwrapper.h:56
bool obfuscate
If true, store data obfuscated via simple XOR.
Definition: dbwrapper.h:52
size_t max_file_size
Maximum LevelDB SST file size.
Definition: dbwrapper.h:62
bool wipe_data
If true, remove all existing data.
Definition: dbwrapper.h:49
uint64_t cache_bytes
Configures various leveldb cache settings.
Definition: dbwrapper.h:45
leveldb::Env * testing_env
If non-null, use this as the leveldb::Env instead of the default.
Definition: dbwrapper.h:59
fs::path path
Location in the filesystem where leveldb data will be stored.
Definition: dbwrapper.h:43
bool bloom_filter
If true, build a LevelDB bloom filter to accelerate point lookups.
Definition: dbwrapper.h:54
bool memory_only
If true, use leveldb's memory environment.
Definition: dbwrapper.h:47
leveldb::Env * penv
custom environment this database is using (may be nullptr in case of default environment)
Definition: dbwrapper.cpp:223
leveldb::ReadOptions iteroptions
options used when iterating over values of the database
Definition: dbwrapper.cpp:232
leveldb::ReadOptions readoptions
options used when reading from the database
Definition: dbwrapper.cpp:229
leveldb::Options options
database options used
Definition: dbwrapper.cpp:226
leveldb::DB * pdb
the database itself
Definition: dbwrapper.cpp:241
leveldb::WriteOptions syncoptions
options used when sync writing to the database
Definition: dbwrapper.cpp:238
leveldb::WriteOptions writeoptions
options used when writing to the database
Definition: dbwrapper.cpp:235
CDBWrapper db
Definition: dbwrapper.cpp:371
assert(!tx.IsCoinBase())