diff --git a/src/dbwrapper.cpp b/src/dbwrapper.cpp index b3faff10cea..1c35e11863b 100644 --- a/src/dbwrapper.cpp +++ b/src/dbwrapper.cpp @@ -158,14 +158,16 @@ struct CDBBatch::WriteBatchImpl { CDBBatch::CDBBatch(const CDBWrapper& _parent) : parent{_parent}, - m_impl_batch{std::make_unique()} {}; + m_impl_batch{std::make_unique()} +{ + Clear(); +}; CDBBatch::~CDBBatch() = default; void CDBBatch::Clear() { m_impl_batch->batch.Clear(); - size_estimate = 0; } void CDBBatch::WriteImpl(std::span key, DataStream& ssValue) @@ -174,26 +176,17 @@ void CDBBatch::WriteImpl(std::span key, DataStream& ssValue) ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent)); leveldb::Slice slValue(CharCast(ssValue.data()), ssValue.size()); m_impl_batch->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::EraseImpl(std::span key) { leveldb::Slice slKey(CharCast(key.data()), key.size()); m_impl_batch->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::ApproximateSize() const +{ + return m_impl_batch->batch.ApproximateSize(); } struct LevelDBContext { diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 98446361e4e..789b5be8fc7 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -83,8 +83,6 @@ private: DataStream ssKey{}; DataStream ssValue{}; - size_t size_estimate{0}; - void WriteImpl(std::span key, DataStream& ssValue); void EraseImpl(std::span key); @@ -117,7 +115,7 @@ public: ssKey.clear(); } - size_t SizeEstimate() const { return size_estimate; } + size_t ApproximateSize() const; }; class CDBIterator diff --git a/src/txdb.cpp b/src/txdb.cpp index 1622039d63b..bb6ee2eb524 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -119,16 +119,19 @@ bool CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashB for (auto it{cursor.Begin()}; it != cursor.End();) { if (it->second.IsDirty()) { CoinEntry entry(&it->first); - if (it->second.coin.IsSpent()) + if (it->second.coin.IsSpent()) { batch.Erase(entry); - else + } else { batch.Write(entry, it->second.coin); + } + changed++; } count++; it = cursor.NextAndMaybeErase(*it); - if (batch.SizeEstimate() > m_options.batch_write_bytes) { - LogDebug(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0)); + if (batch.ApproximateSize() > m_options.batch_write_bytes) { + LogDebug(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.ApproximateSize() * (1.0 / 1048576.0)); + m_db->WriteBatch(batch); batch.Clear(); if (m_options.simulate_crash_ratio) { @@ -145,7 +148,7 @@ bool CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashB batch.Erase(DB_HEAD_BLOCKS); batch.Write(DB_BEST_BLOCK, hashBlock); - LogDebug(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0)); + LogDebug(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.ApproximateSize() * (1.0 / 1048576.0)); bool ret = m_db->WriteBatch(batch); LogDebug(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count); return ret;