coins: pass linked list of flagged entries to BatchWrite

BatchWrite now iterates through the linked
list of flagged entries instead of the entire
coinsCache map.

Co-Authored-By: l0rinc <pap.lorinc@gmail.com>
This commit is contained in:
Andrew Toth
2024-07-17 23:11:48 -04:00
parent a14edada8a
commit 7825b8b9ae
7 changed files with 59 additions and 36 deletions

View File

@@ -55,9 +55,9 @@ public:
uint256 GetBestBlock() const override { return hashBestBlock_; }
bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock, bool erase = true) override
bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock) override
{
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = erase ? mapCoins.erase(it) : std::next(it)) {
for (auto it{cursor.Begin()}; it != cursor.End(); it = cursor.NextAndMaybeErase(*it)){
if (it->second.IsDirty()) {
// Same optimization used in CCoinsViewDB is to only write dirty entries.
map_[it->first] = it->second.coin;
@@ -618,8 +618,9 @@ void WriteCoinsViewEntry(CCoinsView& view, CAmount value, char flags)
sentinel.second.SelfRef(sentinel);
CCoinsMapMemoryResource resource;
CCoinsMap map{0, CCoinsMap::hasher{}, CCoinsMap::key_equal{}, &resource};
InsertCoinsMapEntry(map, sentinel, value, flags);
BOOST_CHECK(view.BatchWrite(map, {}));
auto usage{InsertCoinsMapEntry(map, sentinel, value, flags)};
auto cursor{CoinsViewCacheCursor(usage, sentinel, map, /*will_erase=*/true)};
BOOST_CHECK(view.BatchWrite(cursor, {}));
}
class SingleEntryCacheTest

View File

@@ -122,6 +122,7 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
[&] {
CoinsCachePair sentinel{};
sentinel.second.SelfRef(sentinel);
size_t usage{0};
CCoinsMapMemoryResource resource;
CCoinsMap coins_map{0, SaltedOutpointHasher{/*deterministic=*/true}, CCoinsMap::key_equal{}, &resource};
LIMITED_WHILE(good_data && fuzzed_data_provider.ConsumeBool(), 10'000)
@@ -140,10 +141,12 @@ FUZZ_TARGET(coins_view, .init = initialize_coins_view)
}
auto it{coins_map.emplace(random_out_point, std::move(coins_cache_entry)).first};
it->second.AddFlags(flags, *it, sentinel);
usage += it->second.coin.DynamicMemoryUsage();
}
bool expected_code_path = false;
try {
coins_view_cache.BatchWrite(coins_map, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock());
auto cursor{CoinsViewCacheCursor(usage, sentinel, coins_map, /*will_erase=*/true)};
coins_view_cache.BatchWrite(cursor, fuzzed_data_provider.ConsumeBool() ? ConsumeUInt256(fuzzed_data_provider) : coins_view_cache.GetBestBlock());
expected_code_path = true;
} catch (const std::logic_error& e) {
if (e.what() == std::string{"FRESH flag misapplied to coin that exists in parent cache"}) {

View File

@@ -172,13 +172,13 @@ public:
std::unique_ptr<CCoinsViewCursor> Cursor() const final { return {}; }
size_t EstimateSize() const final { return m_data.size(); }
bool BatchWrite(CCoinsMap& data, const uint256&, bool erase) final
bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256&) final
{
for (auto it = data.begin(); it != data.end(); it = erase ? data.erase(it) : std::next(it)) {
for (auto it{cursor.Begin()}; it != cursor.End(); it = cursor.NextAndMaybeErase(*it)) {
if (it->second.IsDirty()) {
if (it->second.coin.IsSpent() && (it->first.n % 5) != 4) {
m_data.erase(it->first);
} else if (erase) {
} else if (cursor.WillErase(*it)) {
m_data[it->first] = std::move(it->second.coin);
} else {
m_data[it->first] = it->second.coin;