#35195 coins: cache UTXO outpoint hash codes

ReviewabilityReviewsAgreementSize
#35195 l0rinc coins: cache UTXO outpoint hash codesAuthor silent 183d0Strong4 + 17 tests
  • Speed up initial sync and AssumeUTXO loading by avoiding redundant hash calculations on UTXO lookups
  • Trades a small memory increase per cached entry for faster table operations
  • Needs rebase
  • Author silent for 138 days
  • Concept support because benchmarks justify the memory trade-off for faster execution (optout21)
  • 4 lines added or modified outside tests
  • 17 lines added or modified in tests
  • 7 lines removed in total
  • 2 files, 2 commits
Validation#32 of 53
P3 · speedup
  • P3 because IBD and reindex speedups are modest at 2% to 3%, though AssumeUTXO loading gains reach 11%
  • The speedup trades off increased cache memory usage and relies on compiler-specific standard library traits
  • Ranking pass: Moved up: measured IBD and assumeutxo-loading gains make it the most tangible P3 item after the bug fixes
Reviewability: ReadyStalePaused
Agreement: StrongPositivePositive w/ caveatsNeutralMildDisputedBlockedCrickets
Reviews: current code-review ACKs, then (+stale ACKs) and -NACKs; greener = more ACKs.
Size: lines added or modified outside tests, then in tests; greener = smaller.

Goal

Removes the `noexcept` specification from `SaltedOutpointHasher::operator()` to induce `libstdc++`'s `std::unordered_map` to cache hash codes within node structures. This effectively reverts PR #16957, trading a node-size memory increase of one `size_t` for reduced SipHash recomputations during UTXO map operations. A unit test is also added to check invocability and the `libstdc++` fast-hash trait.

Problem: In `libstdc++`, `std::unordered_map` omits cached hash codes in bucket nodes when the hash functor is marked `noexcept`, forcing table lookups and rehashing in `CCoinsMap` to repeatedly recompute outpoint hashes with SipHash. While PR #16957 introduced `noexcept` to reduce memory usage per node by about 9%, it introduced a runtime penalty.

Evidence of importance:

  • Author's benchmarks show reindex-chainstate and IBD completing approximately 2% to 3% faster with cached hash codes across different `-dbcache` settings.
  • Author reports up to ~11% speedup during AssumeUTXO loading (`loadtxoutset`), which isolates the coins cache performance from block validation overhead.
  • Author's Massif profiling showed memory usage was roughly neutral at moderate `-dbcache` values, but increased at very high cache sizes (24.11 GB to 25.49 GB peak RSS).

Scope: Relies on implementation-defined behavior in libstdc++ where non-noexcept fast hash functions cause unordered containers to store cached hash values in nodes. The unit test uses the internal libstdc++ header `<bits/functional_hash.h>` and `std::__is_fast_hash` under `__GLIBCXX__`.

Reviewability

Stale · Author silent 183d

No author activity for 183 days; a review may wait a long time for a response.

Agreement

Strong

substantive support, no open objection (optout21)

Thread notes: optout21 provided a substantive Concept ACK based on benchmark results. Their inline question regarding __is_fast_hash was not recorded as an objection because optout21 explicitly noted having no issues or dangers with reverting noexcept and categorized the inline remarks as nits.

Objections, suggestions, and questions: none recorded.

Support:

  • optout21 (contributor) (Concept ACK, 2026-05-28): In general, the tradeoff between extra memory and extra CPU is not clear, but in this case benchmarks indicate that caching (more memory, less CPU) results in faster execution, therefore it should be applied.

Participants:

  • optout21 (contributor, support, 5 statements 2026-05-28 to 2026-05-28): Concept ACK citing benchmark performance gains; asked an inline question about __is_fast_hash and left nits

Files

17 lines under test/bench/ci.

  • src/test/hash_tests.cpp +17/-0
  • src/util/hasher.h +4/-7

Card

The short text the ranking pass compares across PRs.

This PR marks SaltedOutpointHasher as noexcept(false) to prompt libstdc++ unordered containers to cache hash codes in their nodes. This intentionally reverses the tradeoff made in PR #16957, prioritizing CPU speed over per-node memory savings in the UTXO cache. The author's benchmarks demonstrate a 2% to 3% runtime improvement during IBD and reindex-chainstate, and up to an 11% speedup during AssumeUTXO loading, at the cost of higher peak memory on very large dbcache configurations.

Data

dossier JSON · extract JSON · model ledger, generated 2026-09-18T03:29, confidence high, input hash beac7d10d236235e
thread read through 2026-05-28 (5 statements), head 16e77fdf13
Discussion read under schema 1 rules: suggestions and questions may be missing, and an objection may combine several harms (schema history).
labels: UTXO Db and Indexes, Needs rebase · draft

Categories

Validation

P3 · speedup (ranking pass: Moved up: measured IBD and assumeutxo-loading gains make it the most tangible P3 item after the bug fixes)

Provides a modest 2% to 3% speedup to IBD/reindex and ~11% during AssumeUTXO loading, traded against higher memory usage per cache node. Benchmarks demonstrate reduced SipHash recomputation in `CCoinsMap`, but the optimization relies on implementation-defined `libstdc++` behavior and is reasonably deferrable.

Membership: Carries the 'UTXO Db and Indexes' label and modifies hashing behavior specifically to optimize the in-memory UTXO cache (`CCoinsMap`) during IBD and AssumeUTXO loading.

Factors: security/stability 0, bug 0, performance 1, user value 0, leverage 0