Skip to content

Commit ab23325

Browse files
committed
Merge bitcoin#33866: refactor: Let CCoinsViewCache::BatchWrite return void
6da6f50 refactor: Let CCoinsViewCache::BatchWrite return void (TheCharlatan) Pull request description: CCoinsViewCache::BatchWrite always returns true if called from a backed cache, so just return void instead. Also return void from ::Sync and ::Flush. This allows for dropping a FatalError condition and simplifying some dead error handling code a bit. Since we now no longer exercise the "error path" when returning from `CCoinsView::BatchWrite`, make the method clear the cache instead. This should only be exercised by tests and not change production behaviour. This might slightly improve the coins_view fuzz test's ability to generate better coverage. ACKs for top commit: l0rinc: ACK 6da6f50 andrewtoth: re-ACK 6da6f50 achow101: ACK 6da6f50 w0xlt: ACK bitcoin@6da6f50 Tree-SHA512: dfaa325b0cf8108910aebf1b27434aaddb639d10d860e96797c77ea42eca9035a54a7dc1d6a5d4eae2b75fcc9356206d3d5672243d2c906e80d19024c8b95408
2 parents 2628de7 + 6da6f50 commit ab23325

File tree

9 files changed

+41
-50
lines changed

9 files changed

+41
-50
lines changed

src/coins.cpp

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ TRACEPOINT_SEMAPHORE(utxocache, uncache);
1616
std::optional<Coin> CCoinsView::GetCoin(const COutPoint& outpoint) const { return std::nullopt; }
1717
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
1818
std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); }
19-
bool CCoinsView::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) { return false; }
19+
void CCoinsView::BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock)
20+
{
21+
for (auto it{cursor.Begin()}; it != cursor.End(); it = cursor.NextAndMaybeErase(*it)) { }
22+
}
23+
2024
std::unique_ptr<CCoinsViewCursor> CCoinsView::Cursor() const { return nullptr; }
2125

2226
bool CCoinsView::HaveCoin(const COutPoint &outpoint) const
@@ -30,7 +34,7 @@ bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->
3034
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
3135
std::vector<uint256> CCoinsViewBacked::GetHeadBlocks() const { return base->GetHeadBlocks(); }
3236
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
33-
bool CCoinsViewBacked::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) { return base->BatchWrite(cursor, hashBlock); }
37+
void CCoinsViewBacked::BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock) { base->BatchWrite(cursor, hashBlock); }
3438
std::unique_ptr<CCoinsViewCursor> CCoinsViewBacked::Cursor() const { return base->Cursor(); }
3539
size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }
3640

@@ -183,7 +187,8 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
183187
hashBlock = hashBlockIn;
184188
}
185189

186-
bool CCoinsViewCache::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlockIn) {
190+
void CCoinsViewCache::BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlockIn)
191+
{
187192
for (auto it{cursor.Begin()}; it != cursor.End(); it = cursor.NextAndMaybeErase(*it)) {
188193
if (!it->second.IsDirty()) { // TODO a cursor can only contain dirty entries
189194
continue;
@@ -246,33 +251,27 @@ bool CCoinsViewCache::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &ha
246251
}
247252
}
248253
hashBlock = hashBlockIn;
249-
return true;
250254
}
251255

252-
bool CCoinsViewCache::Flush(bool will_reuse_cache) {
256+
void CCoinsViewCache::Flush(bool will_reuse_cache)
257+
{
253258
auto cursor{CoinsViewCacheCursor(m_sentinel, cacheCoins, /*will_erase=*/true)};
254-
bool fOk = base->BatchWrite(cursor, hashBlock);
255-
if (fOk) {
256-
cacheCoins.clear();
257-
if (will_reuse_cache) {
258-
ReallocateCache();
259-
}
260-
cachedCoinsUsage = 0;
259+
base->BatchWrite(cursor, hashBlock);
260+
cacheCoins.clear();
261+
if (will_reuse_cache) {
262+
ReallocateCache();
261263
}
262-
return fOk;
264+
cachedCoinsUsage = 0;
263265
}
264266

265-
bool CCoinsViewCache::Sync()
267+
void CCoinsViewCache::Sync()
266268
{
267269
auto cursor{CoinsViewCacheCursor(m_sentinel, cacheCoins, /*will_erase=*/false)};
268-
bool fOk = base->BatchWrite(cursor, hashBlock);
269-
if (fOk) {
270-
if (m_sentinel.second.Next() != &m_sentinel) {
271-
/* BatchWrite must clear flags of all entries */
272-
throw std::logic_error("Not all unspent flagged entries were cleared");
273-
}
270+
base->BatchWrite(cursor, hashBlock);
271+
if (m_sentinel.second.Next() != &m_sentinel) {
272+
/* BatchWrite must clear flags of all entries */
273+
throw std::logic_error("Not all unspent flagged entries were cleared");
274274
}
275-
return fOk;
276275
}
277276

278277
void CCoinsViewCache::Uncache(const COutPoint& hash)

src/coins.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ class CCoinsView
324324

325325
//! Do a bulk modification (multiple Coin changes + BestBlock change).
326326
//! The passed cursor is used to iterate through the coins.
327-
virtual bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock);
327+
virtual void BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock);
328328

329329
//! Get a cursor to iterate over the whole state
330330
virtual std::unique_ptr<CCoinsViewCursor> Cursor() const;
@@ -350,7 +350,7 @@ class CCoinsViewBacked : public CCoinsView
350350
uint256 GetBestBlock() const override;
351351
std::vector<uint256> GetHeadBlocks() const override;
352352
void SetBackend(CCoinsView &viewIn);
353-
bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) override;
353+
void BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock) override;
354354
std::unique_ptr<CCoinsViewCursor> Cursor() const override;
355355
size_t EstimateSize() const override;
356356
};
@@ -389,7 +389,7 @@ class CCoinsViewCache : public CCoinsViewBacked
389389
bool HaveCoin(const COutPoint &outpoint) const override;
390390
uint256 GetBestBlock() const override;
391391
void SetBestBlock(const uint256 &hashBlock);
392-
bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) override;
392+
void BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock) override;
393393
std::unique_ptr<CCoinsViewCursor> Cursor() const override {
394394
throw std::logic_error("CCoinsViewCache cursor iteration not supported.");
395395
}
@@ -441,18 +441,16 @@ class CCoinsViewCache : public CCoinsViewBacked
441441
* to be forgotten.
442442
* If will_reuse_cache is false, the cache will retain the same memory footprint
443443
* after flushing and should be destroyed to deallocate.
444-
* If false is returned, the state of this cache (and its backing view) will be undefined.
445444
*/
446-
bool Flush(bool will_reuse_cache = true);
445+
void Flush(bool will_reuse_cache = true);
447446

448447
/**
449448
* Push the modifications applied to this cache to its base while retaining
450449
* the contents of this cache (except for spent coins, which we erase).
451450
* Failure to call this method or Flush() before destruction will cause the changes
452451
* to be forgotten.
453-
* If false is returned, the state of this cache (and its backing view) will be undefined.
454452
*/
455-
bool Sync();
453+
void Sync();
456454

457455
/**
458456
* Removes the UTXO with the given outpoint from the cache, if it is

src/test/coins_tests.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class CCoinsViewTest : public CCoinsView
5858

5959
uint256 GetBestBlock() const override { return hashBestBlock_; }
6060

61-
bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock) override
61+
void BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock) override
6262
{
6363
for (auto it{cursor.Begin()}; it != cursor.End(); it = cursor.NextAndMaybeErase(*it)){
6464
if (it->second.IsDirty()) {
@@ -72,7 +72,6 @@ class CCoinsViewTest : public CCoinsView
7272
}
7373
if (!hashBlock.IsNull())
7474
hashBestBlock_ = hashBlock;
75-
return true;
7675
}
7776
};
7877

@@ -237,7 +236,7 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
237236
unsigned int flushIndex = m_rng.randrange(stack.size() - 1);
238237
if (fake_best_block) stack[flushIndex]->SetBestBlock(m_rng.rand256());
239238
bool should_erase = m_rng.randrange(4) < 3;
240-
BOOST_CHECK(should_erase ? stack[flushIndex]->Flush() : stack[flushIndex]->Sync());
239+
should_erase ? stack[flushIndex]->Flush() : stack[flushIndex]->Sync();
241240
flushed_without_erase |= !should_erase;
242241
}
243242
}
@@ -247,7 +246,7 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
247246
//Remove the top cache
248247
if (fake_best_block) stack.back()->SetBestBlock(m_rng.rand256());
249248
bool should_erase = m_rng.randrange(4) < 3;
250-
BOOST_CHECK(should_erase ? stack.back()->Flush() : stack.back()->Sync());
249+
should_erase ? stack.back()->Flush() : stack.back()->Sync();
251250
flushed_without_erase |= !should_erase;
252251
stack.pop_back();
253252
}
@@ -496,13 +495,13 @@ BOOST_FIXTURE_TEST_CASE(updatecoins_simulation_test, UpdateTest)
496495
// Every 100 iterations, flush an intermediate cache
497496
if (stack.size() > 1 && m_rng.randbool() == 0) {
498497
unsigned int flushIndex = m_rng.randrange(stack.size() - 1);
499-
BOOST_CHECK(stack[flushIndex]->Flush());
498+
stack[flushIndex]->Flush();
500499
}
501500
}
502501
if (m_rng.randrange(100) == 0) {
503502
// Every 100 iterations, change the cache stack.
504503
if (stack.size() > 0 && m_rng.randbool() == 0) {
505-
BOOST_CHECK(stack.back()->Flush());
504+
stack.back()->Flush();
506505
stack.pop_back();
507506
}
508507
if (stack.size() == 0 || (stack.size() < 4 && m_rng.randbool())) {
@@ -664,7 +663,7 @@ static void WriteCoinsViewEntry(CCoinsView& view, const MaybeCoin& cache_coin)
664663
CCoinsMap map{0, CCoinsMap::hasher{}, CCoinsMap::key_equal{}, &resource};
665664
if (cache_coin) InsertCoinsMapEntry(map, sentinel, *cache_coin);
666665
auto cursor{CoinsViewCacheCursor(sentinel, map, /*will_erase=*/true)};
667-
BOOST_CHECK(view.BatchWrite(cursor, {}));
666+
view.BatchWrite(cursor, {});
668667
}
669668

670669
class SingleEntryCacheTest

src/test/fuzz/coins_view.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,10 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend
7474
}
7575
},
7676
[&] {
77-
(void)coins_view_cache.Flush(/*will_reuse_cache=*/fuzzed_data_provider.ConsumeBool());
77+
coins_view_cache.Flush(/*will_reuse_cache=*/fuzzed_data_provider.ConsumeBool());
7878
},
7979
[&] {
80-
(void)coins_view_cache.Sync();
80+
coins_view_cache.Sync();
8181
},
8282
[&] {
8383
uint256 best_block{ConsumeUInt256(fuzzed_data_provider)};

src/test/fuzz/coinscache_sim.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ class CoinsViewBottom final : public CCoinsView
163163
std::unique_ptr<CCoinsViewCursor> Cursor() const final { return {}; }
164164
size_t EstimateSize() const final { return m_data.size(); }
165165

166-
bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256&) final
166+
void BatchWrite(CoinsViewCacheCursor& cursor, const uint256&) final
167167
{
168168
for (auto it{cursor.Begin()}; it != cursor.End(); it = cursor.NextAndMaybeErase(*it)) {
169169
if (it->second.IsDirty()) {
@@ -187,7 +187,6 @@ class CoinsViewBottom final : public CCoinsView
187187
}
188188
}
189189
}
190-
return true;
191190
}
192191
};
193192

src/test/validation_flush_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
6060
// CRITICAL → OK via Flush
6161
BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState(MAX_COINS_BYTES, /*max_mempool_size_bytes=*/0), CoinsCacheSizeState::CRITICAL);
6262
view.SetBestBlock(m_rng.rand256());
63-
BOOST_REQUIRE(view.Flush());
63+
view.Flush();
6464
BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState(MAX_COINS_BYTES, /*max_mempool_size_bytes=*/0), CoinsCacheSizeState::OK);
6565
}
6666

src/txdb.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
9090
return vhashHeadBlocks;
9191
}
9292

93-
bool CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) {
93+
void CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock)
94+
{
9495
CDBBatch batch(*m_db);
9596
size_t count = 0;
9697
size_t changed = 0;
@@ -151,7 +152,6 @@ bool CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashB
151152
LogDebug(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.ApproximateSize() * (1.0 / 1048576.0));
152153
m_db->WriteBatch(batch);
153154
LogDebug(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
154-
return true;
155155
}
156156

157157
size_t CCoinsViewDB::EstimateSize() const

src/txdb.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class CCoinsViewDB final : public CCoinsView
4444
bool HaveCoin(const COutPoint &outpoint) const override;
4545
uint256 GetBestBlock() const override;
4646
std::vector<uint256> GetHeadBlocks() const override;
47-
bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) override;
47+
void BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock) override;
4848
std::unique_ptr<CCoinsViewCursor> Cursor() const override;
4949

5050
//! Whether an unsupported database format is used.

src/validation.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2845,9 +2845,7 @@ bool Chainstate::FlushStateToDisk(
28452845
}
28462846
// Flush the chainstate (which may refer to block index entries).
28472847
const auto empty_cache{(mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical};
2848-
if (empty_cache ? !CoinsTip().Flush() : !CoinsTip().Sync()) {
2849-
return FatalError(m_chainman.GetNotifications(), state, _("Failed to write to coin database."));
2850-
}
2848+
empty_cache ? CoinsTip().Flush() : CoinsTip().Sync();
28512849
full_flush_completed = true;
28522850
TRACEPOINT(utxocache, flush,
28532851
int64_t{Ticks<std::chrono::microseconds>(NodeClock::now() - nNow)},
@@ -2984,8 +2982,7 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
29842982
LogError("DisconnectTip(): DisconnectBlock %s failed\n", pindexDelete->GetBlockHash().ToString());
29852983
return false;
29862984
}
2987-
bool flushed = view.Flush(/*will_reuse_cache=*/false); // local CCoinsViewCache goes out of scope
2988-
assert(flushed);
2985+
view.Flush(/*will_reuse_cache=*/false); // local CCoinsViewCache goes out of scope
29892986
}
29902987
LogDebug(BCLog::BENCH, "- Disconnect block: %.2fms\n",
29912988
Ticks<MillisecondsDouble>(SteadyClock::now() - time_start));
@@ -3119,8 +3116,7 @@ bool Chainstate::ConnectTip(
31193116
Ticks<MillisecondsDouble>(time_3 - time_2),
31203117
Ticks<SecondsDouble>(m_chainman.time_connect_total),
31213118
Ticks<MillisecondsDouble>(m_chainman.time_connect_total) / m_chainman.num_blocks_total);
3122-
bool flushed = view.Flush(/*will_reuse_cache=*/false); // local CCoinsViewCache goes out of scope
3123-
assert(flushed);
3119+
view.Flush(/*will_reuse_cache=*/false); // local CCoinsViewCache goes out of scope
31243120
}
31253121
const auto time_4{SteadyClock::now()};
31263122
m_chainman.time_flush += time_4 - time_3;

0 commit comments

Comments
 (0)