diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index 58fd47ce1ca..b8ee852bb52 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -196,23 +196,46 @@ void CDBBatch::EraseImpl(Span ssKey) size_estimate += 2 + (slKey.size() > 127) + slKey.size(); } +struct LevelDBContext { + //! custom environment this database is using (may be nullptr in case of default environment) + leveldb::Env* penv; + + //! database options used + leveldb::Options options; + + //! options used when reading from the database + leveldb::ReadOptions readoptions; + + //! options used when iterating over values of the database + leveldb::ReadOptions iteroptions; + + //! options used when writing to the database + leveldb::WriteOptions writeoptions; + + //! options used when sync writing to the database + leveldb::WriteOptions syncoptions; + + //! the database itself + leveldb::DB* pdb; +}; + CDBWrapper::CDBWrapper(const DBParams& params) - : m_name{fs::PathToString(params.path.stem())}, m_path{params.path}, m_is_memory{params.memory_only} + : m_db_context{std::make_unique()}, m_name{fs::PathToString(params.path.stem())}, m_path{params.path}, m_is_memory{params.memory_only} { - penv = nullptr; - readoptions.verify_checksums = true; - iteroptions.verify_checksums = true; - iteroptions.fill_cache = false; - syncoptions.sync = true; - options = GetOptions(params.cache_bytes); - options.create_if_missing = true; + DBContext().penv = nullptr; + DBContext().readoptions.verify_checksums = true; + DBContext().iteroptions.verify_checksums = true; + DBContext().iteroptions.fill_cache = false; + DBContext().syncoptions.sync = true; + DBContext().options = GetOptions(params.cache_bytes); + DBContext().options.create_if_missing = true; if (params.memory_only) { - penv = leveldb::NewMemEnv(leveldb::Env::Default()); - options.env = penv; + DBContext().penv = leveldb::NewMemEnv(leveldb::Env::Default()); + DBContext().options.env = DBContext().penv; } else { if (params.wipe_data) { LogPrintf("Wiping LevelDB in %s\n", fs::PathToString(params.path)); - leveldb::Status result = leveldb::DestroyDB(fs::PathToString(params.path), options); + leveldb::Status result = leveldb::DestroyDB(fs::PathToString(params.path), DBContext().options); HandleError(result); } TryCreateDirectories(params.path); @@ -222,13 +245,13 @@ CDBWrapper::CDBWrapper(const DBParams& params) // because on POSIX leveldb passes the byte string directly to ::open(), and // on Windows it converts from UTF-8 to UTF-16 before calling ::CreateFileW // (see env_posix.cc and env_windows.cc). - leveldb::Status status = leveldb::DB::Open(options, fs::PathToString(params.path), &pdb); + leveldb::Status status = leveldb::DB::Open(DBContext().options, fs::PathToString(params.path), &DBContext().pdb); HandleError(status); LogPrintf("Opened LevelDB successfully\n"); if (params.options.force_compact) { LogPrintf("Starting database compaction of %s\n", fs::PathToString(params.path)); - pdb->CompactRange(nullptr, nullptr); + DBContext().pdb->CompactRange(nullptr, nullptr); LogPrintf("Finished database compaction of %s\n", fs::PathToString(params.path)); } @@ -254,16 +277,16 @@ CDBWrapper::CDBWrapper(const DBParams& params) CDBWrapper::~CDBWrapper() { - delete pdb; - pdb = nullptr; - delete options.filter_policy; - options.filter_policy = nullptr; - delete options.info_log; - options.info_log = nullptr; - delete options.block_cache; - options.block_cache = nullptr; - delete penv; - options.env = nullptr; + delete DBContext().pdb; + DBContext().pdb = nullptr; + delete DBContext().options.filter_policy; + DBContext().options.filter_policy = nullptr; + delete DBContext().options.info_log; + DBContext().options.info_log = nullptr; + delete DBContext().options.block_cache; + DBContext().options.block_cache = nullptr; + delete DBContext().penv; + DBContext().options.env = nullptr; } bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) @@ -273,7 +296,7 @@ bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) if (log_memory) { mem_before = DynamicMemoryUsage() / 1024.0 / 1024; } - leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.m_impl_batch->batch); + leveldb::Status status = DBContext().pdb->Write(fSync ? DBContext().syncoptions : DBContext().writeoptions, &batch.m_impl_batch->batch); HandleError(status); if (log_memory) { double mem_after = DynamicMemoryUsage() / 1024.0 / 1024; @@ -287,7 +310,7 @@ size_t CDBWrapper::DynamicMemoryUsage() const { std::string memory; std::optional parsed; - if (!pdb->GetProperty("leveldb.approximate-memory-usage", &memory) || !(parsed = ToIntegral(memory))) { + if (!DBContext().pdb->GetProperty("leveldb.approximate-memory-usage", &memory) || !(parsed = ToIntegral(memory))) { LogPrint(BCLog::LEVELDB, "Failed to get approximate-memory-usage property\n"); return 0; } @@ -317,7 +340,7 @@ std::optional CDBWrapper::ReadImpl(Span ssKey) con { leveldb::Slice slKey(CharCast(ssKey.data()), ssKey.size()); std::string strValue; - leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); + leveldb::Status status = DBContext().pdb->Get(DBContext().readoptions, slKey, &strValue); if (!status.ok()) { if (status.IsNotFound()) return std::nullopt; @@ -332,7 +355,7 @@ bool CDBWrapper::ExistsImpl(Span ssKey) const leveldb::Slice slKey(CharCast(ssKey.data()), ssKey.size()); std::string strValue; - leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); + leveldb::Status status = DBContext().pdb->Get(DBContext().readoptions, slKey, &strValue); if (!status.ok()) { if (status.IsNotFound()) return false; @@ -348,7 +371,7 @@ size_t CDBWrapper::EstimateSizeImpl(Span ssKey1, SpanGetApproximateSizes(&range, 1, &size); + DBContext().pdb->GetApproximateSizes(&range, 1, &size); return size; } @@ -365,11 +388,12 @@ struct CDBIterator::IteratorImpl { explicit IteratorImpl(leveldb::Iterator* _iter) : iter{_iter} {} }; -CDBIterator::CDBIterator(const CDBWrapper& _parent, std::unique_ptr _piter) : parent(_parent), m_impl_iter(std::move(_piter)) {} +CDBIterator::CDBIterator(const CDBWrapper& _parent, std::unique_ptr _piter) : parent(_parent), + m_impl_iter(std::move(_piter)) {} CDBIterator* CDBWrapper::NewIterator() { - return new CDBIterator{*this, std::make_unique(pdb->NewIterator(iteroptions))}; + return new CDBIterator{*this, std::make_unique(DBContext().pdb->NewIterator(DBContext().iteroptions))}; } void CDBIterator::SeekImpl(Span ssKey) diff --git a/src/dbwrapper.h b/src/dbwrapper.h index fa7b6397cba..66170b5efa2 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -5,24 +5,21 @@ #ifndef BITCOIN_DBWRAPPER_H #define BITCOIN_DBWRAPPER_H +#include #include #include #include #include +#include #include #include #include -#include #include #include #include #include #include -namespace leveldb { -class DB; -class Env; -} static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64; static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024; @@ -180,30 +177,14 @@ public: } }; +struct LevelDBContext; + class CDBWrapper { friend const std::vector& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w); private: - //! custom environment this database is using (may be nullptr in case of default environment) - leveldb::Env* penv; - - //! database options used - leveldb::Options options; - - //! options used when reading from the database - leveldb::ReadOptions readoptions; - - //! options used when iterating over values of the database - leveldb::ReadOptions iteroptions; - - //! options used when writing to the database - leveldb::WriteOptions writeoptions; - - //! options used when sync writing to the database - leveldb::WriteOptions syncoptions; - - //! the database itself - leveldb::DB* pdb; + //! holds all leveldb-specific fields of this class + std::unique_ptr m_db_context; //! the name of this database std::string m_name; @@ -228,6 +209,7 @@ private: std::optional ReadImpl(Span ssKey) const; bool ExistsImpl(Span ssKey) const; size_t EstimateSizeImpl(Span ssKey1, Span ssKey2) const; + auto& DBContext() const LIFETIMEBOUND { return *Assert(m_db_context); } public: CDBWrapper(const DBParams& params);