Skip to content

Commit 8b5e19d

Browse files
committed
refactor: Delegate to LevelDB for CDBBatch size estimation
Serialized batch size can be queried via the underlying LevelDB implementation calling the native `leveldb::WriteBatch::ApproximateSize()`. The previous manual calculation was added in bitcoin/bitcoin@e66dbde as part of bitcoin/bitcoin#10195. At that time (April 2017), the version of LevelDB used by Bitcoin Core (and even the latest source) lacked a native function for this. LevelDB added this capability in google/leveldb@69e2bd2, merged later that year. The old manual estimation method (`SizeEstimate()`) is kept temporarily in this commit, and assertions are added in `txdb.cpp` to verify its results against `ApproximateSize()` during batch writes. This ensures the native function behaves as expected before removing the manual calculation in the subsequent commit.
1 parent 751077c commit 8b5e19d

File tree

3 files changed

+28
-3
lines changed

3 files changed

+28
-3
lines changed

src/dbwrapper.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ void CDBBatch::EraseImpl(std::span<const std::byte> key)
200200
size_estimate += 2 + (slKey.size() > 127) + slKey.size();
201201
}
202202

203+
size_t CDBBatch::ApproximateSize() const
204+
{
205+
return m_impl_batch->batch.ApproximateSize();
206+
}
207+
203208
struct LevelDBContext {
204209
//! custom environment this database is using (may be nullptr in case of default environment)
205210
leveldb::Env* penv;

src/dbwrapper.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ class CDBBatch
119119
ssKey.clear();
120120
}
121121

122-
size_t SizeEstimate() const { return size_estimate; }
122+
size_t ApproximateSize() const;
123+
size_t SizeEstimate() const { return size_estimate; } // TODO replace with ApproximateSize
123124
};
124125

125126
class CDBIterator

src/txdb.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,24 +113,39 @@ bool CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashB
113113
// transition from old_tip to hashBlock.
114114
// A vector is used for future extensibility, as we may want to support
115115
// interrupting after partial writes from multiple independent reorgs.
116+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
116117
batch.Erase(DB_BEST_BLOCK);
118+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
117119
batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
120+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
118121

119122
for (auto it{cursor.Begin()}; it != cursor.End();) {
120123
if (it->second.IsDirty()) {
121124
CoinEntry entry(&it->first);
122-
if (it->second.coin.IsSpent())
125+
if (it->second.coin.IsSpent()) {
126+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
123127
batch.Erase(entry);
124-
else
128+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
129+
} else {
130+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
125131
batch.Write(entry, it->second.coin);
132+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
133+
}
134+
126135
changed++;
127136
}
128137
count++;
129138
it = cursor.NextAndMaybeErase(*it);
139+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
130140
if (batch.SizeEstimate() > m_options.batch_write_bytes) {
131141
LogDebug(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
142+
143+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
132144
m_db->WriteBatch(batch);
145+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
133146
batch.Clear();
147+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
148+
134149
if (m_options.simulate_crash_ratio) {
135150
static FastRandomContext rng;
136151
if (rng.randrange(m_options.simulate_crash_ratio) == 0) {
@@ -142,11 +157,15 @@ bool CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashB
142157
}
143158

144159
// In the last batch, mark the database as consistent with hashBlock again.
160+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
145161
batch.Erase(DB_HEAD_BLOCKS);
162+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
146163
batch.Write(DB_BEST_BLOCK, hashBlock);
164+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
147165

148166
LogDebug(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
149167
bool ret = m_db->WriteBatch(batch);
168+
assert(batch.ApproximateSize() == batch.SizeEstimate()); // TODO remove
150169
LogDebug(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
151170
return ret;
152171
}

0 commit comments

Comments
 (0)