21 #include <leveldb/cache.h> 22 #include <leveldb/db.h> 23 #include <leveldb/env.h> 24 #include <leveldb/filter_policy.h> 25 #include <leveldb/helpers/memenv/memenv.h> 26 #include <leveldb/iterator.h> 27 #include <leveldb/options.h> 28 #include <leveldb/slice.h> 29 #include <leveldb/status.h> 30 #include <leveldb/write_batch.h> 35 static auto CharCast(
const std::byte* data) {
return reinterpret_cast<const char*
>(data); }
48 const std::string errmsg =
"Fatal LevelDB error: " + status.ToString();
50 LogPrintf(
"You can use -debug=leveldb to get more complete diagnostic messages\n");
63 for (
int iter = 0; iter < 2; iter++) {
67 bufsize =
sizeof(buffer);
72 base =
new char[bufsize];
75 char* limit = base + bufsize;
80 va_copy(backup_ap, ap);
82 p += vsnprintf(p, limit - p,
format, backup_ap);
97 if (p == base || p[-1] !=
'\n') {
102 base[std::min(bufsize - 1, (
int)(p - base))] =
'\0';
104 if (base != buffer) {
127 int default_open_files = options->max_open_files;
129 if (
sizeof(
void*) < 8) {
130 options->max_open_files = 64;
134 options->max_open_files, default_open_files);
139 leveldb::Options options;
140 options.block_cache = leveldb::NewLRUCache(nCacheSize / 2);
141 options.write_buffer_size = nCacheSize / 4;
142 options.filter_policy = leveldb::NewBloomFilterPolicy(10);
143 options.compression = leveldb::kNoCompression;
145 if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) {
148 options.paranoid_checks =
true;
160 m_impl_batch{std::make_unique<CDBBatch::WriteBatchImpl>()} {};
183 size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size();
222 : m_db_context{std::make_unique<LevelDBContext>()}, m_name{
fs::PathToString(params.path.stem())}, m_path{params.path}, m_is_memory{params.memory_only}
224 DBContext().penv =
nullptr;
225 DBContext().readoptions.verify_checksums =
true;
226 DBContext().iteroptions.verify_checksums =
true;
227 DBContext().iteroptions.fill_cache =
false;
228 DBContext().syncoptions.sync =
true;
229 DBContext().options =
GetOptions(params.cache_bytes);
230 DBContext().options.create_if_missing =
true;
231 if (params.memory_only) {
232 DBContext().penv = leveldb::NewMemEnv(leveldb::Env::Default());
233 DBContext().options.env = DBContext().penv;
235 if (params.wipe_data) {
247 leveldb::Status status = leveldb::DB::Open(DBContext().options,
fs::PathToString(params.path), &DBContext().pdb);
249 LogPrintf(
"Opened LevelDB successfully\n");
251 if (params.options.force_compact) {
253 DBContext().pdb->CompactRange(
nullptr,
nullptr);
258 obfuscate_key = std::vector<unsigned char>(OBFUSCATE_KEY_NUM_BYTES,
'\000');
260 bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key);
262 if (!key_exists && params.obfuscate && IsEmpty()) {
265 std::vector<unsigned char> new_key = CreateObfuscateKey();
268 Write(OBFUSCATE_KEY_KEY, new_key);
269 obfuscate_key = new_key;
281 delete DBContext().options.filter_policy;
282 DBContext().options.filter_policy =
nullptr;
286 DBContext().options.block_cache =
nullptr;
294 double mem_before = 0;
303 m_name, mem_before, mem_after);
311 std::optional<size_t> parsed;
312 if (!
DBContext().pdb->GetProperty(
"leveldb.approximate-memory-usage", &memory) || !(parsed = ToIntegral<size_t>(memory))) {
316 return parsed.value();
341 std::string strValue;
342 leveldb::Status status =
DBContext().pdb->Get(
DBContext().readoptions, slKey, &strValue);
344 if (status.IsNotFound())
346 LogPrintf(
"LevelDB read failure: %s\n", status.ToString());
356 std::string strValue;
357 leveldb::Status status =
DBContext().pdb->Get(
DBContext().readoptions, slKey, &strValue);
359 if (status.IsNotFound())
361 LogPrintf(
"LevelDB read failure: %s\n", status.ToString());
372 leveldb::Range range(slKey1, slKey2);
373 DBContext().pdb->GetApproximateSizes(&range, 1, &size);
381 return !(it->Valid());
385 const std::unique_ptr<leveldb::Iterator>
iter;
391 m_impl_iter(
std::move(_piter)) {}
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by create_directories if the requested directory exists.
These should be considered an implementation detail of the specific database.
#define LogPrint(category,...)
Batch of changes queued to be written to a CDBWrapper.
bool DestroyDB(const std::string &path_str)
auto & DBContext() const LIFETIMEBOUND
leveldb::ReadOptions readoptions
options used when reading from the database
Span< const std::byte > GetValueImpl() const
Span< const std::byte > GetKeyImpl() const
constexpr std::size_t size() const noexcept
const std::unique_ptr< IteratorImpl > m_impl_iter
CDBIterator(const CDBWrapper &_parent, std::unique_ptr< IteratorImpl > _piter)
std::vector< unsigned char > CreateObfuscateKey() const
Returns a string (consisting of 8 random bytes) suitable for use as an obfuscating XOR key...
size_t EstimateSizeImpl(Span< const std::byte > key1, Span< const std::byte > key2) const
size_t DynamicMemoryUsage() const
void Logv(const char *format, va_list ap) override
const CDBWrapper & parent
static std::string PathToString(const path &path)
Convert path object to a byte string.
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
CDBWrapper(const DBParams ¶ms)
Double ended buffer combining vector and stream-like interfaces.
const std::unique_ptr< leveldb::Iterator > iter
CDBIterator * NewIterator()
#define LogPrintLevel(category, level,...)
leveldb::Options options
database options used
leveldb::WriteOptions writeoptions
options used when writing to the database
void EraseImpl(Span< const std::byte > key)
leveldb::DB * pdb
the database itself
bool IsEmpty()
Return true if the database managed by this class contains no entries.
const std::vector< unsigned char > & GetObfuscateKey(const CDBWrapper &w)
Work around circular dependency, as well as for testing in dbwrapper_tests.
static const unsigned int OBFUSCATE_KEY_NUM_BYTES
the length of the obfuscate key in number of bytes
void SeekImpl(Span< const std::byte > key)
std::string m_name
the name of this database
static void HandleError(const leveldb::Status &status)
Handle database error by throwing dbwrapper_error exception.
constexpr C * data() const noexcept
static const std::string OBFUSCATE_KEY_KEY
the key under which the obfuscation key is stored
void Xor(const std::vector< unsigned char > &key)
XOR the contents of this stream with a certain key.
Span< const std::byte > MakeByteSpan(V &&v) noexcept
void WriteImpl(Span< const std::byte > key, DataStream &ssValue)
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
void GetRandBytes(Span< unsigned char > bytes) noexcept
Overall design of the RNG and entropy sources.
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)
bool WriteBatch(CDBBatch &batch, bool fSync=false)
bool ExistsImpl(Span< const std::byte > key) const
static leveldb::Options GetOptions(size_t nCacheSize)
const std::unique_ptr< WriteBatchImpl > m_impl_batch
std::vector< unsigned char > obfuscate_key
a key used for optional XOR-obfuscation of the database
std::optional< std::string > ReadImpl(Span< const std::byte > key) const
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