Problem
The temporal kv read path has accreted several near-duplicate ways to do the same GetLatest, because each incremental need is added as an optional duck-typed interface + type-switch rather than by changing the kv interface itself. Changing the interface ripples to a large number of call sites, so it's repeatedly deferred as "too big for this PR" — and the variants accumulate.
Current state (db/state/execctx/domain_shared.go, getLatestMetered):
- plain
tx.GetLatest(domain, k) — no metering, no txN
MeteredGetter.MeteredGetLatest(…, metrics, start) → (v, step, ok, err) — adds read metering + maxStep
MeteredGetterWithTxN.MeteredGetLatestWithTxN(…) → (v, step, txN, ok, err) — adds the read's txN (needed to tag BranchCache entries with their unwind watermark)
The SD getter type-switches over tx.AggTx() to pick the richest available variant. MeteredGetterWithTxN differs from MeteredGetter only by the extra txN return value.
Proposal
Make the temporal GetLatest API consistent: a single GetLatest that returns the txN and is metered, with metrics threaded via ctx (so the signature doesn't grow a metrics parameter). Remove the MeteredGetter / MeteredGetterWithTxN duck-typed interfaces and the type-switches that select between them.
Related — another take on the same problem
The lock-free, channel-fed KV-read metrics collector (#21663) threads metrics through via ctx rather than an interface parameter. That is effectively another take on this same underlying issue (adding read-path capabilities without an interface-param explosion). The unified GetLatest should adopt that ctx-carried pattern instead of passing metrics *changeset.DomainMetrics explicitly.
Scope / why it keeps getting deferred
Changing the kv temporal interface touches many call sites, so it gets punted from feature PRs. This needs its own dedicated PR.
Surfaced in review of #21380.
Problem
The temporal
kvread path has accreted several near-duplicate ways to do the sameGetLatest, because each incremental need is added as an optional duck-typed interface + type-switch rather than by changing thekvinterface itself. Changing the interface ripples to a large number of call sites, so it's repeatedly deferred as "too big for this PR" — and the variants accumulate.Current state (
db/state/execctx/domain_shared.go,getLatestMetered):tx.GetLatest(domain, k)— no metering, no txNMeteredGetter.MeteredGetLatest(…, metrics, start) → (v, step, ok, err)— adds read metering +maxStepMeteredGetterWithTxN.MeteredGetLatestWithTxN(…) → (v, step, txN, ok, err)— adds the read'stxN(needed to tag BranchCache entries with their unwind watermark)The SD getter type-switches over
tx.AggTx()to pick the richest available variant.MeteredGetterWithTxNdiffers fromMeteredGetteronly by the extratxNreturn value.Proposal
Make the temporal
GetLatestAPI consistent: a singleGetLatestthat returns thetxNand is metered, with metrics threaded viactx(so the signature doesn't grow ametricsparameter). Remove theMeteredGetter/MeteredGetterWithTxNduck-typed interfaces and the type-switches that select between them.Related — another take on the same problem
The lock-free, channel-fed KV-read metrics collector (#21663) threads metrics through via
ctxrather than an interface parameter. That is effectively another take on this same underlying issue (adding read-path capabilities without an interface-param explosion). The unifiedGetLatestshould adopt that ctx-carried pattern instead of passingmetrics *changeset.DomainMetricsexplicitly.Scope / why it keeps getting deferred
Changing the
kvtemporal interface touches many call sites, so it gets punted from feature PRs. This needs its own dedicated PR.Surfaced in review of #21380.