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); }
41 return leveldb::DestroyDB(path_str, {}).ok();
50 const std::string errmsg =
"Fatal LevelDB error: " + status.ToString();
52 LogInfo(
"You can use -debug=leveldb to get more complete diagnostic messages");
60 void Logv(
const char * format, va_list ap)
override {
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;
167 HandleError(leveldb::DB::Open(options, fs::PathToString(path), &raw_db));
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());
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());
264 LogInfo(
"Wiping LevelDB in %s", fs::PathToString(params.
path));
265 leveldb::Status result = leveldb::DestroyDB(fs::PathToString(params.
path),
DBContext().options);
271 LogInfo(
"Opening LevelDB in %s", fs::PathToString(params.
path));
277 leveldb::Status status = leveldb::DB::Open(
DBContext().options, fs::PathToString(params.
path), &
DBContext().pdb);
279 LogInfo(
"Opened LevelDB successfully");
282 LogInfo(
"Starting database compaction of %s", fs::PathToString(params.
path));
284 LogInfo(
"Finished database compaction of %s", fs::PathToString(params.
path));
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;
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;
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
const CDBWrapper & parent
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
Wrapper around TryRead() that preserves the original Read() semantics: returns true on success,...
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)
Obfuscation m_obfuscation
optional XOR-obfuscation of the database
std::unique_ptr< LevelDBContext > m_db_context
holds all leveldb-specific fields of this class
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.
dbwrapper_error(const std::string &msg)
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
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.
Filesystem operations and types.
bool ShouldDebugLog(Category category)
Return whether messages with specified category should be debug logged.
std::string_view RemoveSuffixView(std::string_view str LIFETIMEBOUND, std::string_view suffix)
auto MakeByteSpan(const V &v) noexcept
std::optional< T > ToIntegral(std::string_view str, size_t base=10)
Convert string to integral type T.
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 wipe_data
If true, remove all existing data.
uint64_t cache_bytes
Configures various leveldb cache settings.
leveldb::Env * testing_env
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