7#include <leveldb/cache.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>
37static auto CharCast(
const std::byte*
data) {
return reinterpret_cast<const char*
>(
data); }
50 const std::string errmsg =
"Fatal LevelDB error: " + status.ToString();
52 LogInfo(
"You can use -debug=leveldb to get more complete diagnostic messages");
65 for (
int iter = 0; iter < 2; iter++) {
69 bufsize =
sizeof(buffer);
74 base =
new char[bufsize];
77 char* limit = base + bufsize;
82 va_copy(backup_ap, ap);
84 p += vsnprintf(p, limit - p,
format, backup_ap);
99 if (p == base || p[-1] !=
'\n') {
104 base[std::min(bufsize - 1, (
int)(p - base))] =
'\0';
106 if (base != buffer) {
129 int default_open_files = options->max_open_files;
131 if (
sizeof(
void*) < 8) {
132 options->max_open_files = 64;
136 options->max_open_files, default_open_files);
139static leveldb::Options
GetOptions(
size_t nCacheSize,
bool bloom_filter)
141 leveldb::Options options;
142 options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
143 options.write_buffer_size = nCacheSize / 4;
144 options.filter_policy = bloom_filter ? leveldb::NewBloomFilterPolicy(10) :
nullptr;
145 options.compression = leveldb::kNoCompression;
147 if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
150 options.paranoid_checks =
true;
158 if (!
fs::exists(path /
"CURRENT"))
return false;
161 leveldb::Options options;
162 options.paranoid_checks =
true;
164 options.info_log = &logger;
168 const std::unique_ptr<leveldb::DB>
db{raw_db};
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);
177 return it->Valid() && it->key().starts_with(prefix_slice);
204 leveldb::Slice slKey(
CharCast(key.data()), key.size());
212 leveldb::Slice slKey(
CharCast(key.data()), key.size());
245 : m_db_context{
std::make_unique<
LevelDBContext>()}, m_name{fs::PathToString(params.path.stem())}
248 DBContext().readoptions.verify_checksums =
true;
249 DBContext().iteroptions.verify_checksums =
true;
250 DBContext().iteroptions.fill_cache =
false;
253 DBContext().options.create_if_missing =
true;
259 DBContext().penv = leveldb::NewMemEnv(leveldb::Env::Default());
279 LogInfo(
"Opened LevelDB successfully");
302 delete DBContext().options.filter_policy;
303 DBContext().options.filter_policy =
nullptr;
307 DBContext().options.block_cache =
nullptr;
315 double mem_before = 0;
324 m_name, mem_before, mem_after);
330 if (std::string value;
DBContext().pdb->GetProperty(property, &value))
return value;
338 std::optional<size_t> parsed;
339 if (
auto memory{
GetProperty(
"leveldb.approximate-memory-usage")}; !memory || !(parsed = ToIntegral<size_t>(*memory))) {
343 return parsed.value();
348 leveldb::Slice slKey(
CharCast(key.data()), key.size());
349 std::string strValue;
350 leveldb::Status status =
DBContext().pdb->Get(
DBContext().readoptions, slKey, &strValue);
352 if (status.IsNotFound())
354 LogError(
"LevelDB read failure: %s", status.ToString());
362 leveldb::Slice slKey(
CharCast(key.data()), key.size());
364 std::string strValue;
365 leveldb::Status status =
DBContext().pdb->Get(
DBContext().readoptions, slKey, &strValue);
367 if (status.IsNotFound())
369 LogError(
"LevelDB read failure: %s", status.ToString());
377 leveldb::Slice slKey1(
CharCast(key1.data()), key1.size());
378 leveldb::Slice slKey2(
CharCast(key2.data()), key2.size());
380 leveldb::Range range(slKey1, slKey2);
381 DBContext().pdb->GetApproximateSizes(&range, 1, &size);
389 return !(it->Valid());
393 const std::unique_ptr<leveldb::Iterator>
iter;
399 m_impl_iter(
std::move(_piter))
411 leveldb::Slice slKey(
CharCast(key.data()), key.size());
void Logv(const char *format, va_list ap) override
Batch of changes queued to be written to a CDBWrapper.
const std::unique_ptr< WriteBatchImpl > m_impl_batch
void WriteImpl(std::span< const std::byte > key, DataStream &value)
void EraseImpl(std::span< const std::byte > key)
CDBBatch(const CDBWrapper &_parent)
size_t ApproximateSize() const
const CDBWrapper & parent
DataStream m_value_scratch
CDBIterator(const CDBWrapper &_parent, std::unique_ptr< IteratorImpl > _piter)
const std::unique_ptr< IteratorImpl > m_impl_iter
void SeekImpl(std::span< const std::byte > key)
std::span< const std::byte > GetKeyImpl() const
std::span< const std::byte > GetValueImpl() const
std::optional< std::string > ReadImpl(std::span< const std::byte > key) const
size_t EstimateSizeImpl(std::span< const std::byte > key1, std::span< const std::byte > key2) const
void CompactFull()
Perform a blocking full compaction of the underlying LevelDB.
size_t DynamicMemoryUsage() const
bool Read(const K &key, V &value) const
CDBIterator * NewIterator()
std::string m_name
the name of this database
CDBWrapper(const DBParams ¶ms)
void WriteBatch(CDBBatch &batch, bool fSync=false)
bool ExistsImpl(std::span< const std::byte > key) const
void Write(const K &key, const V &value, bool fSync=false)
static bool HasKeyStartingWith(const fs::path &path, uint8_t prefix)
Probe an unopened database for a key prefix.
Obfuscation m_obfuscation
optional XOR-obfuscation of the database
static const std::string OBFUSCATION_KEY
obfuscation key storage key, null-prefixed to avoid collisions
auto & DBContext() const LIFETIMEBOUND
bool IsEmpty()
Return true if the database managed by this class contains no entries.
std::optional< std::string > GetProperty(const std::string &property) const
Return a LevelDB property value, if available.
Double ended buffer combining vector and stream-like interfaces.
void reserve(size_type n)
std::string HexKey() const
static constexpr size_t KEY_SIZE
std::vector< B > randbytes(size_t len) noexcept
Generate random bytes.
static const PrecomputedData data
Precomputed COutPoint and CCoins values.
static auto CharCast(const std::byte *data)
bool DestroyDB(const std::string &path_str)
static void SetMaxOpenFiles(leveldb::Options *options)
static void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
static leveldb::Options GetOptions(size_t nCacheSize, bool bloom_filter)
constexpr size_t DBWRAPPER_PREALLOC_KEY_SIZE
constexpr size_t DBWRAPPER_PREALLOC_VALUE_SIZE
static bool exists(const path &p)
static std::string PathToString(const path &path)
Convert path object to a byte string.
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by create_directories if the requested directory exists.
#define LogDebug(category,...)
These should be considered an implementation detail of the specific database.
const Obfuscation & GetObfuscation(const CDBWrapper &w)
Work around circular dependency, as well as for testing in dbwrapper_tests.
bool ShouldDebugLog(Category category)
Return whether messages with specified category should be debug logged.
std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix)
auto MakeByteSpan(const V &v) noexcept
leveldb::WriteBatch batch
IteratorImpl(leveldb::Iterator *_iter)
const std::unique_ptr< leveldb::Iterator > iter
bool force_compact
Compact database on startup.
Application-specific storage settings.
DBOptions options
Passed-through options.
bool obfuscate
If true, store data obfuscated via simple XOR.
size_t max_file_size
Maximum LevelDB SST file size.
bool wipe_data
If true, remove all existing data.
uint64_t cache_bytes
Configures various leveldb cache settings.
leveldb::Env * testing_env
If non-null, use this as the leveldb::Env instead of the default.
fs::path path
Location in the filesystem where leveldb data will be stored.
bool bloom_filter
If true, build a LevelDB bloom filter to accelerate point lookups.
bool memory_only
If true, use leveldb's memory environment.
leveldb::Env * penv
custom environment this database is using (may be nullptr in case of default environment)
leveldb::ReadOptions iteroptions
options used when iterating over values of the database
leveldb::ReadOptions readoptions
options used when reading from the database
leveldb::Options options
database options used
leveldb::DB * pdb
the database itself
leveldb::WriteOptions syncoptions
options used when sync writing to the database
leveldb::WriteOptions writeoptions
options used when writing to the database