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> 37 static 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);
141 leveldb::Options options;
142 options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
143 options.write_buffer_size = nCacheSize / 4;
144 options.filter_policy = leveldb::NewBloomFilterPolicy(10);
145 options.compression = leveldb::kNoCompression;
147 if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
150 options.paranoid_checks =
true;
163 m_impl_batch{std::make_unique<CDBBatch::WriteBatchImpl>()}
177 leveldb::Slice slKey(
CharCast(key.data()), key.size());
185 leveldb::Slice slKey(
CharCast(key.data()), key.size());
218 : m_db_context{std::make_unique<LevelDBContext>()}, m_name{
fs::PathToString(params.path.stem())}
220 DBContext().penv =
nullptr;
221 DBContext().readoptions.verify_checksums =
true;
222 DBContext().iteroptions.verify_checksums =
true;
223 DBContext().iteroptions.fill_cache =
false;
224 DBContext().syncoptions.sync =
true;
225 DBContext().options =
GetOptions(params.cache_bytes);
226 DBContext().options.create_if_missing =
true;
227 if (params.memory_only) {
228 DBContext().penv = leveldb::NewMemEnv(leveldb::Env::Default());
229 DBContext().options.env = DBContext().penv;
231 if (params.wipe_data) {
232 LogInfo(
"Wiping LevelDB in %s", fs::PathToString(params.path));
237 LogInfo(
"Opening LevelDB in %s", fs::PathToString(params.path));
243 leveldb::Status status = leveldb::DB::Open(DBContext().options, fs::PathToString(params.path), &DBContext().pdb);
245 LogInfo(
"Opened LevelDB successfully");
247 if (params.options.force_compact) {
248 LogInfo(
"Starting database compaction of %s", fs::PathToString(params.path));
249 DBContext().pdb->CompactRange(
nullptr,
nullptr);
250 LogInfo(
"Finished database compaction of %s", fs::PathToString(params.path));
253 if (!Read(OBFUSCATION_KEY, m_obfuscation) && params.obfuscate && IsEmpty()) {
257 Write(OBFUSCATION_KEY, obfuscation);
258 m_obfuscation = obfuscation;
259 LogInfo(
"Wrote new obfuscation key for %s: %s", fs::PathToString(params.path), m_obfuscation.HexKey());
261 LogInfo(
"Using obfuscation key for %s: %s", fs::PathToString(params.path), m_obfuscation.HexKey());
268 delete DBContext().options.filter_policy;
269 DBContext().options.filter_policy =
nullptr;
273 DBContext().options.block_cache =
nullptr;
281 double mem_before = 0;
290 m_name, mem_before, mem_after);
297 std::optional<size_t> parsed;
298 if (!
DBContext().pdb->GetProperty(
"leveldb.approximate-memory-usage", &memory) || !(parsed = ToIntegral<size_t>(memory))) {
302 return parsed.value();
307 leveldb::Slice slKey(
CharCast(key.data()), key.size());
308 std::string strValue;
309 leveldb::Status status =
DBContext().pdb->Get(
DBContext().readoptions, slKey, &strValue);
311 if (status.IsNotFound())
313 LogError(
"LevelDB read failure: %s", status.ToString());
321 leveldb::Slice slKey(
CharCast(key.data()), key.size());
323 std::string strValue;
324 leveldb::Status status =
DBContext().pdb->Get(
DBContext().readoptions, slKey, &strValue);
326 if (status.IsNotFound())
328 LogError(
"LevelDB read failure: %s", status.ToString());
336 leveldb::Slice slKey1(
CharCast(key1.data()), key1.size());
337 leveldb::Slice slKey2(
CharCast(key2.data()), key2.size());
339 leveldb::Range range(slKey1, slKey2);
340 DBContext().pdb->GetApproximateSizes(&range, 1, &size);
348 return !(it->Valid());
352 const std::unique_ptr<leveldb::Iterator>
iter;
358 m_impl_iter(
std::move(_piter)) {}
367 leveldb::Slice slKey(
CharCast(key.data()), key.size());
std::vector< B > randbytes(size_t len) noexcept
Generate random bytes.
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by create_directories if the requested directory exists.
void SeekImpl(std::span< const std::byte > key)
auto MakeByteSpan(const V &v) noexcept
These should be considered an implementation detail of the specific database.
void EraseImpl(std::span< const std::byte > key)
static const size_t DBWRAPPER_MAX_FILE_SIZE
void WriteImpl(std::span< const std::byte > key, DataStream &ssValue)
size_t ApproximateSize() const
Batch of changes queued to be written to a CDBWrapper.
const Obfuscation & GetObfuscation(const CDBWrapper &w)
Work around circular dependency, as well as for testing in dbwrapper_tests.
bool DestroyDB(const std::string &path_str)
auto & DBContext() const LIFETIMEBOUND
leveldb::ReadOptions readoptions
options used when reading from the database
size_t EstimateSizeImpl(std::span< const std::byte > key1, std::span< const std::byte > key2) const
std::string_view RemoveSuffixView(std::string_view str, std::string_view suffix)
const std::unique_ptr< IteratorImpl > m_impl_iter
CDBIterator(const CDBWrapper &_parent, std::unique_ptr< IteratorImpl > _piter)
static constexpr size_t KEY_SIZE
size_t DynamicMemoryUsage() const
std::span< const std::byte > GetKeyImpl() const
void Logv(const char *format, va_list ap) override
std::span< const std::byte > GetValueImpl() const
const CDBWrapper & parent
CDBWrapper(const DBParams ¶ms)
void WriteBatch(CDBBatch &batch, bool fSync=false)
Double ended buffer combining vector and stream-like interfaces.
const std::unique_ptr< leveldb::Iterator > iter
CDBIterator * NewIterator()
Obfuscation m_obfuscation
optional XOR-obfuscation of the database
leveldb::Options options
database options used
leveldb::WriteOptions writeoptions
options used when writing to the database
leveldb::DB * pdb
the database itself
bool IsEmpty()
Return true if the database managed by this class contains no entries.
#define LogDebug(category,...)
std::string m_name
the name of this database
bool ExistsImpl(std::span< const std::byte > key) const
static void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
std::optional< std::string > ReadImpl(std::span< const std::byte > key) const
static std::string PathToString(const path &path)
Convert path object to a byte string.
Application-specific storage settings.
CDBBatch(const CDBWrapper &_parent)
IteratorImpl(leveldb::Iterator *_iter)
static void SetMaxOpenFiles(leveldb::Options *options)
leveldb::ReadOptions iteroptions
options used when iterating over values of the database
static bool LogAcceptCategory(BCLog::LogFlags category, BCLog::Level level)
Return true if log accepts specified category, at the specified level.
static auto CharCast(const std::byte *data)
static leveldb::Options GetOptions(size_t nCacheSize)
const std::unique_ptr< WriteBatchImpl > m_impl_batch
leveldb::WriteBatch batch
leveldb::Env * penv
custom environment this database is using (may be nullptr in case of default environment) ...
leveldb::WriteOptions syncoptions
options used when sync writing to the database