diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index b0ea80ea1aca1..b4ddf55fa12f7 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -4,17 +4,206 @@ #include -#include #include +#include #include +#include #include #include +#include #include -#include + #include +#include +#include + +/** These should be considered an implementation detail of the specific database. + */ +namespace dbwrapper_private { + +/** Handle database error by throwing dbwrapper_error exception. + */ +void HandleError(const leveldb::Status& status); +}; + +class DBBatchImpl +{ +private: + const CDBWrapper& parent; + + leveldb::WriteBatch batch; + + size_t size_estimate{0}; +public: + DBBatchImpl(const CDBWrapper& _parent); + + void Clear(); + + void doWrite(CDataStream& key, CDataStream& value); + void doErase(CDataStream& key); + + size_t SizeEstimate() const; + + leveldb::WriteBatch& GetWriteBatch(); +}; + +CDBBatch::CDBBatch(const CDBWrapper& _parent) + : m_impl(std::make_unique(_parent)) {} + +DBBatchImpl::DBBatchImpl(const CDBWrapper& _parent) + : parent(_parent) {} + +CDBBatch::~CDBBatch() = default; + +void CDBBatch::Clear() +{ + return m_impl->Clear(); +} + +void DBBatchImpl::Clear() +{ + batch.Clear(); + size_estimate = 0; +} + +void CDBBatch::doWrite(CDataStream& key, CDataStream& value) +{ + m_impl->doWrite(key, value); +} + +void DBBatchImpl::doWrite(CDataStream& key, CDataStream& value) +{ + leveldb::Slice slKey((const char*)key.data(), key.size()); + + value.Xor(dbwrapper_private::GetObfuscateKey(parent)); + leveldb::Slice slValue((const char*)value.data(), value.size()); + + batch.Put(slKey, slValue); + + // LevelDB serializes writes as: + // - byte: header + // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...) + // - byte[]: key + // - varint: value length + // - byte[]: value + // The formula below assumes the key and value are both less than 16k. + size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size(); +} + +void CDBBatch::doErase(CDataStream& key) +{ + m_impl->doErase(key); +} + +void DBBatchImpl::doErase(CDataStream& key) +{ + leveldb::Slice slKey((const char*)key.data(), key.size()); + batch.Delete(slKey); + + // LevelDB serializes erases as: + // - byte: header + // - varint: key length + // - byte[]: key + // The formula below assumes the key is less than 16kB. + size_estimate += 2 + (slKey.size() > 127) + slKey.size(); +} + +size_t CDBBatch::SizeEstimate() const { + return m_impl->SizeEstimate(); +} + +size_t DBBatchImpl::SizeEstimate() const { return size_estimate; } + +class DBIteratorImpl +{ +private: + const CDBWrapper& parent; + std::unique_ptr piter; -class CBitcoinLevelDBLogger : public leveldb::Logger { +public: + explicit DBIteratorImpl(const CDBWrapper& _parent, leveldb::Iterator* _piter); + + void doSeek(const CDataStream& key); + CDataStream doGetKey(); + CDataStream doGetValue(); + + unsigned int GetValueSize(); + + bool Valid() const; + void SeekToFirst(); + void Next(); +}; + +leveldb::WriteBatch& DBBatchImpl::GetWriteBatch() +{ + return batch; +} + +CDBIterator::CDBIterator(std::unique_ptr impl) + : m_impl(std::move(impl)) {}; + +DBIteratorImpl::DBIteratorImpl(const CDBWrapper& _parent, leveldb::Iterator* _piter) + : parent(_parent), piter(_piter){}; + +CDBIterator::~CDBIterator() = default; + +void CDBIterator::doSeek(const CDataStream& key) +{ + return m_impl->doSeek(key); +} + +void DBIteratorImpl::doSeek(const CDataStream& key) +{ + leveldb::Slice slKey((const char*)key.data(), key.size()); + piter->Seek(slKey); +} + +CDataStream CDBIterator::doGetKey() +{ + return m_impl->doGetKey(); +} + +CDataStream DBIteratorImpl::doGetKey() +{ + leveldb::Slice slKey = piter->key(); + return CDataStream{MakeByteSpan(slKey), SER_DISK, CLIENT_VERSION}; +} + +CDataStream CDBIterator::doGetValue() +{ + return m_impl->doGetValue(); +} + +CDataStream DBIteratorImpl::doGetValue() +{ + leveldb::Slice slValue = piter->value(); + CDataStream ssValue{MakeByteSpan(slValue), SER_DISK, CLIENT_VERSION}; + ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent)); + return ssValue; +} + +unsigned int CDBIterator::GetValueSize() +{ + return m_impl->GetValueSize(); +} + +unsigned int DBIteratorImpl::GetValueSize() +{ + return piter->value().size(); +} + +bool CDBIterator::Valid() const { return m_impl->Valid(); } +bool DBIteratorImpl::Valid() const { return piter->Valid(); } + +void CDBIterator::SeekToFirst() { m_impl->SeekToFirst(); } +void DBIteratorImpl::SeekToFirst() { piter->SeekToFirst(); } + +void CDBIterator::Next() { m_impl->Next(); } +void DBIteratorImpl::Next() { piter->Next(); } + +class CBitcoinLevelDBLogger : public leveldb::Logger +{ public: // This code is adapted from posix_logger.h, which is why it is using vsprintf. // Please do not do this in normal code @@ -114,8 +303,78 @@ static leveldb::Options GetOptions(size_t nCacheSize) return options; } -CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) - : m_name{fs::PathToString(path.stem())} +class DBWrapperImpl +{ + friend const std::vector& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w); +private: + CDBWrapper& m_parent; + + //! 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; + + //! the name of this database + std::string m_name; + + //! a key used for optional XOR-obfuscation of the database + std::vector obfuscate_key; + + //! the key under which the obfuscation key is stored + static const std::string OBFUSCATE_KEY_KEY; + + //! the length of the obfuscate key in number of bytes + static const unsigned int OBFUSCATE_KEY_NUM_BYTES; + +public: + DBWrapperImpl(CDBWrapper& parent, const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate); + ~DBWrapperImpl(); + + bool WriteBatch(CDBBatch& batch, bool fSync); + + size_t DynamicMemoryUsage() const; + + std::unique_ptr NewIterator(); + + bool IsEmpty(); + + /** + * Returns a string (consisting of 8 random bytes) suitable for use as an + * obfuscating XOR key. + */ + std::vector CreateObfuscateKey() const; + + // Removed from interface later when pimpl'd + bool doRawGet(const CDataStream& ssKey, std::string& strValue) const; + + std::optional doGet(const CDataStream& ssKey) const; + + bool doExists(const CDataStream& ssKey) const; + + size_t doEstimateSizes(const CDataStream& begin_key, const CDataStream& end_key) const; + + void doCompactRange(const CDataStream& begin_key, const CDataStream& end_key) const; +}; + +DBWrapperImpl::DBWrapperImpl(CDBWrapper& parent, const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) + : m_parent(parent), + m_name{fs::PathToString(path.stem())} { penv = nullptr; readoptions.verify_checksums = true; @@ -153,7 +412,7 @@ CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bo // The base-case obfuscation key, which is a noop. obfuscate_key = std::vector(OBFUSCATE_KEY_NUM_BYTES, '\000'); - bool key_exists = Read(OBFUSCATE_KEY_KEY, obfuscate_key); + bool key_exists = m_parent.Read(OBFUSCATE_KEY_KEY, obfuscate_key); if (!key_exists && obfuscate && IsEmpty()) { // Initialize non-degenerate obfuscation if it won't upset @@ -161,7 +420,7 @@ CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bo std::vector new_key = CreateObfuscateKey(); // Write `new_key` so we don't obfuscate the key with itself - Write(OBFUSCATE_KEY_KEY, new_key); + m_parent.Write(OBFUSCATE_KEY_KEY, new_key); obfuscate_key = new_key; LogPrintf("Wrote new obfuscate key for %s: %s\n", fs::PathToString(path), HexStr(obfuscate_key)); @@ -170,7 +429,11 @@ CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bo LogPrintf("Using obfuscation key for %s: %s\n", fs::PathToString(path), HexStr(obfuscate_key)); } -CDBWrapper::~CDBWrapper() +CDBWrapper::CDBWrapper(const fs::path& path, size_t nCacheSize, bool fMemory, bool fWipe, bool obfuscate) + : m_impl(std::make_unique(*this, path, nCacheSize, fMemory, fWipe, obfuscate)) +{} + +DBWrapperImpl::~DBWrapperImpl() { delete pdb; pdb = nullptr; @@ -184,14 +447,97 @@ CDBWrapper::~CDBWrapper() options.env = nullptr; } +CDBWrapper::~CDBWrapper() = default; + +bool DBWrapperImpl::doRawGet(const CDataStream& ssKey, std::string& strValue) const +{ + leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size()); + + leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); + if (!status.ok()) { + if (status.IsNotFound()) + return false; + LogPrintf("LevelDB read failure: %s\n", status.ToString()); + dbwrapper_private::HandleError(status); + } + + return true; +} + +std::optional CDBWrapper::doGet(const CDataStream& ssKey) const +{ + return m_impl->doGet(ssKey); +} + +std::optional DBWrapperImpl::doGet(const CDataStream& ssKey) const +{ + std::string strValue; + if (!doRawGet(ssKey, strValue)) { + return std::nullopt; + } + + try { + CDataStream ssValue{MakeByteSpan(strValue), SER_DISK, CLIENT_VERSION}; + ssValue.Xor(obfuscate_key); + return std::move(ssValue); + } catch (const std::exception&) { + return std::nullopt; + } +} + +bool CDBWrapper::doExists(const CDataStream& ssKey) const +{ + return m_impl->doExists(ssKey); +} + +bool DBWrapperImpl::doExists(const CDataStream& ssKey) const +{ + std::string strValue; + return doRawGet(ssKey, strValue); +} + +size_t CDBWrapper::doEstimateSizes(const CDataStream& begin_key, const CDataStream& end_key) const +{ + return m_impl->doEstimateSizes(begin_key, end_key); +} + +size_t DBWrapperImpl::doEstimateSizes(const CDataStream& begin_key, const CDataStream& end_key) const +{ + leveldb::Slice slKey1((const char*)begin_key.data(), begin_key.size()); + leveldb::Slice slKey2((const char*)end_key.data(), end_key.size()); + + uint64_t size = 0; + leveldb::Range range(slKey1, slKey2); + pdb->GetApproximateSizes(&range, 1, &size); + return size; +} + +void CDBWrapper::doCompactRange(const CDataStream& begin_key, const CDataStream& end_key) const +{ + return m_impl->doCompactRange(begin_key, end_key); +} + +void DBWrapperImpl::doCompactRange(const CDataStream& begin_key, const CDataStream& end_key) const +{ + leveldb::Slice slKey1((const char*)begin_key.data(), begin_key.size()); + leveldb::Slice slKey2((const char*)end_key.data(), end_key.size()); + + pdb->CompactRange(&slKey1, &slKey2); +} + bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) +{ + return m_impl->WriteBatch(batch, fSync); +} + +bool DBWrapperImpl::WriteBatch(CDBBatch& batch, bool fSync) { const bool log_memory = LogAcceptCategory(BCLog::LEVELDB); double mem_before = 0; if (log_memory) { mem_before = DynamicMemoryUsage() / 1024.0 / 1024; } - leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.batch); + leveldb::Status status = pdb->Write(fSync ? syncoptions : writeoptions, &batch.m_impl->GetWriteBatch()); dbwrapper_private::HandleError(status); if (log_memory) { double mem_after = DynamicMemoryUsage() / 1024.0 / 1024; @@ -202,6 +548,11 @@ bool CDBWrapper::WriteBatch(CDBBatch& batch, bool fSync) } size_t CDBWrapper::DynamicMemoryUsage() const +{ + return m_impl->DynamicMemoryUsage(); +} + +size_t DBWrapperImpl::DynamicMemoryUsage() const { std::string memory; std::optional parsed; @@ -212,19 +563,25 @@ size_t CDBWrapper::DynamicMemoryUsage() const return parsed.value(); } +std::unique_ptr CDBWrapper::NewIterator() +{ + return std::make_unique(m_impl->NewIterator()); +} + +std::unique_ptr DBWrapperImpl::NewIterator() +{ + return std::make_unique(m_parent, pdb->NewIterator(iteroptions)); +} + // Prefixed with null character to avoid collisions with other keys // // We must use a string constructor which specifies length so that we copy // past the null-terminator. -const std::string CDBWrapper::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14); +const std::string DBWrapperImpl::OBFUSCATE_KEY_KEY("\000obfuscate_key", 14); -const unsigned int CDBWrapper::OBFUSCATE_KEY_NUM_BYTES = 8; +const unsigned int DBWrapperImpl::OBFUSCATE_KEY_NUM_BYTES = 8; -/** - * Returns a string (consisting of 8 random bytes) suitable for use as an - * obfuscating XOR key. - */ -std::vector CDBWrapper::CreateObfuscateKey() const +std::vector DBWrapperImpl::CreateObfuscateKey() const { std::vector ret(OBFUSCATE_KEY_NUM_BYTES); GetRandBytes(ret.data(), OBFUSCATE_KEY_NUM_BYTES); @@ -233,16 +590,16 @@ std::vector CDBWrapper::CreateObfuscateKey() const bool CDBWrapper::IsEmpty() { - std::unique_ptr it(NewIterator()); + return m_impl->IsEmpty(); +} + +bool DBWrapperImpl::IsEmpty() +{ + std::unique_ptr it(NewIterator()); it->SeekToFirst(); return !(it->Valid()); } -CDBIterator::~CDBIterator() { delete piter; } -bool CDBIterator::Valid() const { return piter->Valid(); } -void CDBIterator::SeekToFirst() { piter->SeekToFirst(); } -void CDBIterator::Next() { piter->Next(); } - namespace dbwrapper_private { void HandleError(const leveldb::Status& status) @@ -257,7 +614,7 @@ void HandleError(const leveldb::Status& status) const std::vector& GetObfuscateKey(const CDBWrapper &w) { - return w.obfuscate_key; + return w.m_impl->obfuscate_key; } } // namespace dbwrapper_private diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 1109cb5888bba..61737020464a4 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -13,9 +13,6 @@ #include #include -#include -#include - static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64; static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024; @@ -26,15 +23,12 @@ class dbwrapper_error : public std::runtime_error }; class CDBWrapper; +class DBWrapperImpl; /** These should be considered an implementation detail of the specific database. */ namespace dbwrapper_private { -/** Handle database error by throwing dbwrapper_error exception. - */ -void HandleError(const leveldb::Status& status); - /** Work around circular dependency, as well as for testing in dbwrapper_tests. * Database obfuscation should be considered an implementation detail of the * specific database. @@ -43,91 +37,71 @@ const std::vector& GetObfuscateKey(const CDBWrapper &w); }; +class DBBatchImpl; + /** Batch of changes queued to be written to a CDBWrapper */ class CDBBatch { - friend class CDBWrapper; + friend class DBWrapperImpl; +protected: + const std::unique_ptr m_impl; private: - const CDBWrapper &parent; - leveldb::WriteBatch batch; - - CDataStream ssKey; - CDataStream ssValue; - - size_t size_estimate; + void doWrite(CDataStream& key, CDataStream& value); + void doErase(CDataStream& key); public: /** * @param[in] _parent CDBWrapper that this batch is to be submitted to */ - explicit CDBBatch(const CDBWrapper &_parent) : parent(_parent), ssKey(SER_DISK, CLIENT_VERSION), ssValue(SER_DISK, CLIENT_VERSION), size_estimate(0) { }; + explicit CDBBatch(const CDBWrapper &_parent); + ~CDBBatch(); - void Clear() - { - batch.Clear(); - size_estimate = 0; - } + void Clear(); template void Write(const K& key, const V& value) { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; - leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size()); + CDataStream ssValue(SER_DISK, CLIENT_VERSION); ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE); ssValue << value; - ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent)); - leveldb::Slice slValue((const char*)ssValue.data(), ssValue.size()); - - batch.Put(slKey, slValue); - // LevelDB serializes writes as: - // - byte: header - // - varint: key length (1 byte up to 127B, 2 bytes up to 16383B, ...) - // - byte[]: key - // - varint: value length - // - byte[]: value - // The formula below assumes the key and value are both less than 16k. - size_estimate += 3 + (slKey.size() > 127) + slKey.size() + (slValue.size() > 127) + slValue.size(); - ssKey.clear(); - ssValue.clear(); + + doWrite(ssKey, ssValue); } template void Erase(const K& key) { + CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; - leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size()); - - batch.Delete(slKey); - // LevelDB serializes erases as: - // - byte: header - // - varint: key length - // - byte[]: key - // The formula below assumes the key is less than 16kB. - size_estimate += 2 + (slKey.size() > 127) + slKey.size(); - ssKey.clear(); + + doErase(ssKey); } - size_t SizeEstimate() const { return size_estimate; } + size_t SizeEstimate() const; }; +class DBIteratorImpl; + class CDBIterator { +protected: + const std::unique_ptr m_impl; private: - const CDBWrapper &parent; - leveldb::Iterator *piter; + void doSeek(const CDataStream& key); + CDataStream doGetKey(); + CDataStream doGetValue(); public: - /** - * @param[in] _parent Parent CDBWrapper instance. - * @param[in] _piter The original leveldb iterator. + * @param[in] impl DBIteratorImpl instance. */ - CDBIterator(const CDBWrapper &_parent, leveldb::Iterator *_piter) : - parent(_parent), piter(_piter) { }; + CDBIterator(std::unique_ptr impl); ~CDBIterator(); bool Valid() const; @@ -138,17 +112,15 @@ class CDBIterator CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; - leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size()); - piter->Seek(slKey); + + doSeek(ssKey); } void Next(); template bool GetKey(K& key) { - leveldb::Slice slKey = piter->key(); try { - CDataStream ssKey{MakeByteSpan(slKey), SER_DISK, CLIENT_VERSION}; - ssKey >> key; + doGetKey() >> key; } catch (const std::exception&) { return false; } @@ -156,62 +128,30 @@ class CDBIterator } template bool GetValue(V& value) { - leveldb::Slice slValue = piter->value(); try { - CDataStream ssValue{MakeByteSpan(slValue), SER_DISK, CLIENT_VERSION}; - ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent)); - ssValue >> value; + doGetValue() >> value; } catch (const std::exception&) { return false; } return true; } - unsigned int GetValueSize() { - return piter->value().size(); - } - + unsigned int GetValueSize(); }; 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; + std::optional doGet(const CDataStream& ssKey) const; - //! options used when iterating over values of the database - leveldb::ReadOptions iteroptions; + bool doExists(const CDataStream& ssKey) const; - //! 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; - - //! the name of this database - std::string m_name; - - //! a key used for optional XOR-obfuscation of the database - std::vector obfuscate_key; - - //! the key under which the obfuscation key is stored - static const std::string OBFUSCATE_KEY_KEY; - - //! the length of the obfuscate key in number of bytes - static const unsigned int OBFUSCATE_KEY_NUM_BYTES; - - std::vector CreateObfuscateKey() const; + size_t doEstimateSizes(const CDataStream& begin_key, const CDataStream& end_key) const; + void doCompactRange(const CDataStream& begin_key, const CDataStream& end_key) const; +protected: + const std::unique_ptr m_impl; public: /** * @param[in] path Location in the filesystem where leveldb data will be stored. @@ -233,20 +173,16 @@ class CDBWrapper CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; - leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size()); std::string strValue; - leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); - if (!status.ok()) { - if (status.IsNotFound()) - return false; - LogPrintf("LevelDB read failure: %s\n", status.ToString()); - dbwrapper_private::HandleError(status); + + auto maybe_data = doGet(ssKey); + if (!maybe_data) { + return false; } + try { - CDataStream ssValue{MakeByteSpan(strValue), SER_DISK, CLIENT_VERSION}; - ssValue.Xor(obfuscate_key); - ssValue >> value; + *maybe_data >> value; } catch (const std::exception&) { return false; } @@ -267,17 +203,8 @@ class CDBWrapper CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; - leveldb::Slice slKey((const char*)ssKey.data(), ssKey.size()); - std::string strValue; - leveldb::Status status = pdb->Get(readoptions, slKey, &strValue); - if (!status.ok()) { - if (status.IsNotFound()) - return false; - LogPrintf("LevelDB read failure: %s\n", status.ToString()); - dbwrapper_private::HandleError(status); - } - return true; + return doExists(ssKey); } template @@ -293,10 +220,7 @@ class CDBWrapper // Get an estimate of LevelDB memory usage (in bytes). size_t DynamicMemoryUsage() const; - CDBIterator *NewIterator() - { - return new CDBIterator(*this, pdb->NewIterator(iteroptions)); - } + std::unique_ptr NewIterator(); /** * Return true if the database managed by this class contains no entries. @@ -311,13 +235,9 @@ class CDBWrapper ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey1 << key_begin; ssKey2 << key_end; - leveldb::Slice slKey1((const char*)ssKey1.data(), ssKey1.size()); - leveldb::Slice slKey2((const char*)ssKey2.data(), ssKey2.size()); - uint64_t size = 0; - leveldb::Range range(slKey1, slKey2); - pdb->GetApproximateSizes(&range, 1, &size); - return size; - } + + return doEstimateSizes(ssKey1, ssKey2); + } /** * Compact a certain range of keys in the database. @@ -330,9 +250,8 @@ class CDBWrapper ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey1 << key_begin; ssKey2 << key_end; - leveldb::Slice slKey1((const char*)ssKey1.data(), ssKey1.size()); - leveldb::Slice slKey2((const char*)ssKey2.data(), ssKey2.size()); - pdb->CompactRange(&slKey1, &slKey2); + + return doCompactRange(ssKey1, ssKey2); } }; diff --git a/src/txdb.cpp b/src/txdb.cpp index 9a39e90ccd16a..6c0369931c914 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -197,8 +197,8 @@ class CCoinsViewDBCursor: public CCoinsViewCursor public: // Prefer using CCoinsViewDB::Cursor() since we want to perform some // cache warmup on instantiation. - CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256&hashBlockIn): - CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {} + CCoinsViewDBCursor(std::unique_ptr pcursorIn, const uint256&hashBlockIn): + CCoinsViewCursor(hashBlockIn), pcursor(std::move(pcursorIn)) {} ~CCoinsViewDBCursor() {} bool GetKey(COutPoint &key) const override;