From bbc98fd7469c53ca8a80038ee385e40cc31bef10 Mon Sep 17 00:00:00 2001 From: Valentin Balaschenko <13349202+vlntb@users.noreply.github.com> Date: Fri, 20 Mar 2026 13:41:57 +0000 Subject: [PATCH] adding callback into TaggedCache --- include/xrpl/basics/TaggedCache.h | 15 +++++ include/xrpl/basics/TaggedCache.ipp | 25 ++++++++ src/xrpld/app/ledger/LedgerHistory.cpp | 88 +++++++++++++------------- 3 files changed, 83 insertions(+), 45 deletions(-) diff --git a/include/xrpl/basics/TaggedCache.h b/include/xrpl/basics/TaggedCache.h index 95f4451c86..7c5458b8fb 100644 --- a/include/xrpl/basics/TaggedCache.h +++ b/include/xrpl/basics/TaggedCache.h @@ -161,6 +161,21 @@ public: fetch(key_type const& digest, Handler const& h); // End CachedSLEs functions. + /** Fetch or create an entry and execute a callback while holding the lock. + + The entry for the given key is fetched from the cache or created if it + doesn't exist. The callback is then invoked with a reference to the + entry while the cache mutex is still held, allowing safe modification + of the cached object. + + @param key The key to fetch or create + @param callback Function to call with the entry under lock. + Signature: void(T&) + */ + template + void + fetch_and_modify(key_type const& key, Callback&& callback); + private: SharedPointerType initialFetch(key_type const& key, std::lock_guard const& l); diff --git a/include/xrpl/basics/TaggedCache.ipp b/include/xrpl/basics/TaggedCache.ipp index 978cbcfb6b..cfa49c443e 100644 --- a/include/xrpl/basics/TaggedCache.ipp +++ b/include/xrpl/basics/TaggedCache.ipp @@ -586,6 +586,31 @@ TaggedCache +template +inline void +TaggedCache:: + fetch_and_modify(key_type const& key, Callback&& callback) +{ + static_assert( + !IsKeyCache, "fetch_and_modify is only supported for value caches, not key-only caches"); + + std::lock_guard lock(m_mutex); + + auto entry = std::make_shared(); + canonicalize(key, entry, []() { return false; }); + + callback(*entry); +} + template < class Key, class T, diff --git a/src/xrpld/app/ledger/LedgerHistory.cpp b/src/xrpld/app/ledger/LedgerHistory.cpp index c6c2c05f3a..126bc86654 100644 --- a/src/xrpld/app/ledger/LedgerHistory.cpp +++ b/src/xrpld/app/ledger/LedgerHistory.cpp @@ -412,32 +412,31 @@ LedgerHistory::builtLedger( LedgerHash hash = ledger->header().hash; XRPL_ASSERT(!hash.isZero(), "xrpl::LedgerHistory::builtLedger : nonzero hash"); - auto entry = std::make_shared(); - m_consensus_validated.canonicalize_replace_client(index, entry); - - if (entry->validated && !entry->built) - { - if (entry->validated.value() != hash) + m_consensus_validated.fetch_and_modify(index, [&](cv_entry& entry) { + if (entry.validated && !entry.built) { - JLOG(j_.error()) << "MISMATCH: seq=" << index - << " validated:" << entry->validated.value() << " then:" << hash; - handleMismatch( - hash, - entry->validated.value(), - consensusHash, - entry->validatedConsensusHash, - consensus); + if (entry.validated.value() != hash) + { + JLOG(j_.error()) << "MISMATCH: seq=" << index + << " validated:" << entry.validated.value() << " then:" << hash; + handleMismatch( + hash, + entry.validated.value(), + consensusHash, + entry.validatedConsensusHash, + consensus); + } + else + { + // We validated a ledger and then built it locally + JLOG(j_.debug()) << "MATCH: seq=" << index << " late"; + } } - else - { - // We validated a ledger and then built it locally - JLOG(j_.debug()) << "MATCH: seq=" << index << " late"; - } - } - entry->built.emplace(hash); - entry->builtConsensusHash.emplace(consensusHash); - entry->consensus.emplace(std::move(consensus)); + entry.built.emplace(hash); + entry.builtConsensusHash.emplace(consensusHash); + entry.consensus.emplace(std::move(consensus)); + }); } void @@ -449,31 +448,30 @@ LedgerHistory::validatedLedger( LedgerHash hash = ledger->header().hash; XRPL_ASSERT(!hash.isZero(), "xrpl::LedgerHistory::validatedLedger : nonzero hash"); - auto entry = std::make_shared(); - m_consensus_validated.canonicalize_replace_client(index, entry); - - if (entry->built && !entry->validated) - { - if (entry->built.value() != hash) + m_consensus_validated.fetch_and_modify(index, [&](cv_entry& entry) { + if (entry.built && !entry.validated) { - JLOG(j_.error()) << "MISMATCH: seq=" << index << " built:" << entry->built.value() - << " then:" << hash; - handleMismatch( - entry->built.value(), - hash, - entry->builtConsensusHash, - consensusHash, - entry->consensus.value()); + if (entry.built.value() != hash) + { + JLOG(j_.error()) << "MISMATCH: seq=" << index << " built:" << entry.built.value() + << " then:" << hash; + handleMismatch( + entry.built.value(), + hash, + entry.builtConsensusHash, + consensusHash, + entry.consensus.value()); + } + else + { + // We built a ledger locally and then validated it + JLOG(j_.debug()) << "MATCH: seq=" << index; + } } - else - { - // We built a ledger locally and then validated it - JLOG(j_.debug()) << "MATCH: seq=" << index; - } - } - entry->validated.emplace(hash); - entry->validatedConsensusHash = consensusHash; + entry.validated.emplace(hash); + entry.validatedConsensusHash = consensusHash; + }); } /** Ensure m_ledgers_by_hash doesn't have the wrong hash for a particular index