erigontech / erigontech/erigon
execution/cache: avoid rebuilding cache views on direct reads
- Dominant language
- Go
- Stars
- 3.6k
- Forks
- 1.5k
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 455
Description
Follow-up to #23095. This is an optimization; it is not required for the correctness of that PR.
## Problem
#23095 binds each cache view to the database state and immutable-files view pinned by its transaction. Most hot callers already construct a `TemporalGetter` once and reuse its bound views, but some direct read paths still repeat view construction:
- `asOfStateReader` calls `SharedDomains.GetLatest` for every commitment-domain read.
- `SharedDomains.GetLatest` and `GetLatestContext` derive both cache generations even when the requested domain can use only one cache.
- View construction inspects the transaction even when no relevant cache is attached.
- The single-domain calls to variadic `TxNumsInFiles` allocate when made through `TemporalDebugTx`.
The work is small, but it is paid on reads whose cache-hit path is otherwise about 50 ns.
## Proposed change
- Bind one `TemporalGetter` when constructing an `asOfStateReader`. Reuse it when only `txNum` changes, and bind a new getter when a clone receives a different transaction.
- Return immediately when no relevant cache is attached.
- For direct reads, derive only the state-cache or branch-cache view needed by the requested domain. Code helpers need only the state-cache view.
- Consider a clearly named, non-variadic accessor for one pinned domain-files end, so generation construction does not allocate through the debug interface.
- Keep a benchmark that compares direct and bound cache hits.
## Correctness constraints
- A view must always be derived from the transaction that performs the read.
- A state-cache generation must still contain the Accounts, Storage, and Code file ends, even when the current read targets only one of those domains. The cache has one shared generation.
- A branch-cache generation uses the Commitment file end.
- Transactions without exact domain frontiers must remain ineligible for the relevant cache.
- Worker clones must preserve context-based metrics, and clones using another transaction must not reuse the source transaction's view.
- Publication and token-revocation semantics must remain unchanged.
## Prototype measurements
Indicative local results on darwin/arm64, Apple M2 Max:
| Path | Current #23095 | Prototype |
|---|---:|---:|
| Fresh getter construction | about 0.69 us, 96 B, 5 allocs | 0.34-0.42 us, 80 B, 1 alloc |
| Direct cache hit | about 111 ns, 0 allocs | 77-79 ns, 0 allocs |
| Bound-getter cache hit | about 49 ns, 0 allocs | about 49 ns, 0 allocs |
| No-cache unique miss | about 220 ns, 8 B, 4 allocs | about 116 ns, 0 allocs |
| Cache-backed unique miss | about 324 ns, 32 B, 5 allocs | about 295 ns, 24 B, 1 alloc |
The main expected benefit is that commitment reads through `asOfStateReader` use the bound-getter path. Before merging, repeat the microbenchmarks on amd64 and measure a representative commitment workload; the extra interface method is worthwhile only if the allocation reduction remains useful outside the microbenchmark.
Contributor guide
Assessment
This issue has not been assessed yet.