validation: don't reallocate cache for short-lived CCoinsViewCache

A few temporary `CCoinsViewCache`'s are destructed right after the `Flush()`, therefore it is not necessary to call `ReallocateCache` to recreate them right before they're killed anyway.

* `Flush()` - retains existing functionality;
* `Flush(/*will_reuse_cache=*/false)` - skips destruction and reallocation of the parent cache since it will soon go out of scope anyway;

For the `will_reuse_cache` parameter we want to see exactly which ones will reallocate memory and which won't - since both can be valid usages.

This change was based on a subset of https://github.com/bitcoin/bitcoin/pull/28945.

Co-authored-by: Martin Ankerl <martin.ankerl@gmail.com>
This commit is contained in:
LőrincandMartin Ankerl committed 2025-11-02 21:40:16 +01:00
1 parent c8f5e446dc
commit 0ac969cddf
5 files changed
+12 -16

No files matched your search

+4 -2
View File
@@ -249,12 +249,14 @@ bool CCoinsViewCache::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &ha
return true; return true;
} }
bool CCoinsViewCache::Flush() { bool CCoinsViewCache::Flush(bool will_reuse_cache) {
auto cursor{CoinsViewCacheCursor(m_sentinel, cacheCoins, /*will_erase=*/true)}; auto cursor{CoinsViewCacheCursor(m_sentinel, cacheCoins, /*will_erase=*/true)};
bool fOk = base->BatchWrite(cursor, hashBlock); bool fOk = base->BatchWrite(cursor, hashBlock);
if (fOk) { if (fOk) {
cacheCoins.clear(); cacheCoins.clear();
ReallocateCache(); if (will_reuse_cache) {
ReallocateCache();
}
cachedCoinsUsage = 0; cachedCoinsUsage = 0;
} }
return fOk; return fOk;
+3 -1
View File
@@ -439,9 +439,11 @@ public:
* Push the modifications applied to this cache to its base and wipe local state. * Push the modifications applied to this cache to its base and wipe local state.
* Failure to call this method or Sync() before destruction will cause the changes * Failure to call this method or Sync() before destruction will cause the changes
* to be forgotten. * to be forgotten.
* If will_reuse_cache is false, the cache will retain the same memory footprint
* after flushing and should be destroyed to deallocate.
* If false is returned, the state of this cache (and its backing view) will be undefined. * If false is returned, the state of this cache (and its backing view) will be undefined.
*/ */
bool Flush(); bool Flush(bool will_reuse_cache = true);
/** /**
* Push the modifications applied to this cache to its base while retaining * Push the modifications applied to this cache to its base while retaining
+1 -1
View File
@@ -74,7 +74,7 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend
} }
}, },
[&] { [&] {
(void)coins_view_cache.Flush(); (void)coins_view_cache.Flush(/*will_reuse_cache=*/fuzzed_data_provider.ConsumeBool());
}, },
[&] { [&] {
(void)coins_view_cache.Sync(); (void)coins_view_cache.Sync();
+1 -9
View File
@@ -392,7 +392,7 @@ FUZZ_TARGET(coinscache_sim)
// Apply to simulation data. // Apply to simulation data.
flush(); flush();
// Apply to real caches. // Apply to real caches.
caches.back()->Flush(); caches.back()->Flush(/*will_reuse_cache=*/provider.ConsumeBool());
}, },
[&]() { // Sync. [&]() { // Sync.
@@ -402,14 +402,6 @@ FUZZ_TARGET(coinscache_sim)
caches.back()->Sync(); caches.back()->Sync();
}, },
[&]() { // Flush + ReallocateCache.
// Apply to simulation data.
flush();
// Apply to real caches.
caches.back()->Flush();
caches.back()->ReallocateCache();
},
[&]() { // GetCacheSize [&]() { // GetCacheSize
(void)caches.back()->GetCacheSize(); (void)caches.back()->GetCacheSize();
}, },
+3 -3
View File
@@ -3036,7 +3036,7 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
LogError("DisconnectTip(): DisconnectBlock %s failed\n", pindexDelete->GetBlockHash().ToString()); LogError("DisconnectTip(): DisconnectBlock %s failed\n", pindexDelete->GetBlockHash().ToString());
return false; return false;
} }
bool flushed = view.Flush(); bool flushed = view.Flush(/*will_reuse_cache=*/false); // local CCoinsViewCache goes out of scope
assert(flushed); assert(flushed);
} }
LogDebug(BCLog::BENCH, "- Disconnect block: %.2fms\n", LogDebug(BCLog::BENCH, "- Disconnect block: %.2fms\n",
@@ -3171,7 +3171,7 @@ bool Chainstate::ConnectTip(
Ticks<MillisecondsDouble>(time_3 - time_2), Ticks<MillisecondsDouble>(time_3 - time_2),
Ticks<SecondsDouble>(m_chainman.time_connect_total), Ticks<SecondsDouble>(m_chainman.time_connect_total),
Ticks<MillisecondsDouble>(m_chainman.time_connect_total) / m_chainman.num_blocks_total); Ticks<MillisecondsDouble>(m_chainman.time_connect_total) / m_chainman.num_blocks_total);
bool flushed = view.Flush(); bool flushed = view.Flush(/*will_reuse_cache=*/false); // local CCoinsViewCache goes out of scope
assert(flushed); assert(flushed);
} }
const auto time_4{SteadyClock::now()}; const auto time_4{SteadyClock::now()};
@@ -4950,7 +4950,7 @@ bool Chainstate::ReplayBlocks()
} }
cache.SetBestBlock(pindexNew->GetBlockHash()); cache.SetBestBlock(pindexNew->GetBlockHash());
cache.Flush(); cache.Flush(/*will_reuse_cache=*/false); // local CCoinsViewCache goes out of scope
m_chainman.GetNotifications().progress(bilingual_str{}, 100, false); m_chainman.GetNotifications().progress(bilingual_str{}, 100, false);
return true; return true;
} }