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.
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
TemporalGetteronce and reuse its bound views, but some direct read paths still repeat view construction:asOfStateReadercallsSharedDomains.GetLatestfor every commitment-domain read.SharedDomains.GetLatestandGetLatestContextderive both cache generations even when the requested domain can use only one cache.TxNumsInFilesallocate when made throughTemporalDebugTx.The work is small, but it is paid on reads whose cache-hit path is otherwise about 50 ns.
Proposed change
TemporalGetterwhen constructing anasOfStateReader. Reuse it when onlytxNumchanges, and bind a new getter when a clone receives a different transaction.Correctness constraints
Prototype measurements
Indicative local results on darwin/arm64, Apple M2 Max:
The main expected benefit is that commitment reads through
asOfStateReaderuse 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.