execution: abort cache transitions after interrupted read-ahead drain - #22469
execution: abort cache transitions after interrupted read-ahead drain#22469yperbasis wants to merge 4 commits into
Conversation
…pulating warmups against epoch bumps and clears Split from #22159 (StateCache review findings #22120). - WarmupStarted/WarmupDone bracket every fire-and-forget warmup and StateCache.Unwind panics under ASSERT_STATE_CACHE if one is still in flight — the drain-before-epoch-bump convention becomes a loud invariant. The warmup binds its gauge and its puts to one launch-time cache snapshot so a racing SetStateCache cannot split the pair. - WaitForWarmup and drainReadAhead report whether the warmup fully drained (false only when the module context is cancelled), and every epoch-bump or Clear call site treats an interrupted drain as a failed precondition instead of proceeding; the DB-close caller keeps its bounded wait. - ExecModule.Start drains and clears the state cache under the module semaphore before ProcessFrozenBlocks, so pre-start payload validation cannot leave pre-catchup entries live across frozen-block processing. - The read-ahead getter carries a snapshot-progress oracle: negatives are stamped with the domain's progress at observation time (a getter without an oracle fills nothing), and a side-effect-free CodeCache.ContainsLive probe lets it skip the keccak+copy for already-live address bindings.
There was a problem hiding this comment.
Pull request overview
This PR hardens the lifecycle of asynchronous cache-populating warmups so they cannot race cache epoch bumps (unwind/clear) and contaminate canonical state, and it reduces unnecessary work in read-ahead warm paths.
Changes:
- Make read-ahead warmup draining report “fully drained vs interrupted”, and gate unwind/clear/FCU paths on a successful drain.
- Track in-flight warmups in
StateCacheand (underASSERT_STATE_CACHE) assert thatUnwindnever runs while a cache-populating warmup is still running. - Add side-effect-free “live binding” probes (
CodeCache.ContainsLive/StateCache.HasLiveCode) so read-ahead can skip keccak+copy when a conditional put would no-op; add tests for the new behaviors.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| execution/execmodule/set_head.go | Bail out of SetHead unwind if read-ahead warmup drain is interrupted. |
| execution/execmodule/forkchoice.go | Treat interrupted warmup drain as shutdown and abort FCU handling early. |
| execution/execmodule/exec_module.go | Make drainReadAhead return a drained/undrained boolean; drain+clear on Start; enforce drain before unwind. |
| execution/exec/blocks_read_ahead.go | Add warmup Started/Done bracketing + cache snapshot binding; make WaitForWarmup return bool; implement negative stamping and “skip for live code” logic. |
| execution/exec/blocks_read_ahead_test.go | Add coverage for drained reporting, live-binding skip, and negative invalidation behavior. |
| execution/cache/state_cache.go | Add warmup gauge + assert in Unwind; expose HasLiveCode. |
| execution/cache/grow_lru.go | Add Peek passthrough for side-effect-free LRU probes. |
| execution/cache/code_cache.go | Add ContainsLive probe for “live binding” detection without recency/counter side effects. |
| execution/cache/cache_test.go | Add tests for CodeCache.ContainsLive and the unwind-vs-warmup invariant assertion. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Heads-up: #21414's latest commit reworks the same read-ahead prefetch this PR hardens, taking a different approach — flagging so we can coordinate direction before either merges. What #21414 does: Direct conflict: both PRs edit Complementary vs obviated, if the SD-routed prefetch is the agreed direction:
My read: the SD-routed prefetch (remove the anomaly) with this PR's drain/gauge/finding-10 hardening layered on top is the clean combination — but it's your call on direction. Related: #22520 (SD-owned run-task API + dropping the parallel-exec start queue). |
…h-fences # Conflicts: # execution/cache/cache_test.go # execution/exec/blocks_read_ahead.go # execution/exec/blocks_read_ahead_test.go
|
@mh0lt Agreed. On current The getter-specific optimization and behavior are no longer part of the PR. #21414 should preserve the successful-drain requirement when it routes read-ahead through published The broader cache-coherence cases remain separate: startup processing is #22925, forward stale read-view fills are #22444, and pre-unwind stale read-view fills are #22463. |
Problem
Block read-ahead runs asynchronously and can populate
StateCachefrom a committed read-only snapshot. The execution paths already wait for read-ahead before an unwind epoch bump or FCU cache apply, butWaitForWarmupdid not report whether the warmup completed or the module context cancelled the wait. A caller could therefore continue without satisfying the drain precondition.Solution
WaitForWarmupanddrainReadAheadreport whether the warmup fully drained.unwindToCommonCanonical,updateForkChoice, andSetHeadstop when shutdown interrupts the drain.ASSERT_STATE_CACHE,StateCache.Unwindrejects an unwind while a directly cache-populating read-ahead warmup is counted as in flight.StateCacheinstance for both its diagnostic gauge and cache writes.The database-close path intentionally ignores the result because it only needs a bounded wait before shutdown.
Scope
This PR covers only the direct
BlockReadAheaderlifecycle. It does not address:ProcessFrozenBlocks, tracked by execution: fence StateCache across frozen-block startup processing #22925#21414 proposes routing read-ahead through the published
SharedDomains. That implementation must preserve the requirement that read-ahead fully drains before an unwind or cache apply.Testing
TestStateCache_UnwindAssertsWarmupInFlightTestWaitForWarmupReportsDrainedgo test ./execution/cache ./execution/exec ./execution/execmodulego test -race -count=1 ./execution/cache ./execution/exec ./execution/execmodulemake erigon integrationmake lint