Repository navigation
Description
What
Adjacent to the query-path optimizations in epic #732, several endpoints redo per-request work whose answer only changes once per ledger close. getLatestLedger was the slowest no-parameter endpoint by over 2x (see @tamirms's measurements here, or any release eval run), and getNetwork / getVersionInfo decoded the whole ~2 MB latest LedgerCloseMeta to read one 4-byte protocol version. Under load these cheap-looking endpoints were the first to buckle.
This issue tracks caching/memoization of that per-ledger work in the endpoint handlers. Anything that only changes when the ledger sequence changes can be memoized keyed by sequence: a new ledger invalidates the entry by moving the key, so no ingestion hook is needed, and one bounded single-entry memo amortizes the work down to once per close across all polls.
Implemented in #1003 as a generic latestMemo[T] (atomic pointer to a {seq, value} entry plus a miss mutex, so a burst at a ledger boundary computes once, an older read view cannot evict a newer ledger's value, and errors are never memoized), used by:
getLatestLedger: the fully rendered JSON response, keyed by sequence.getNetworkandgetVersionInfo: the protocol version, via a sharedprotocolVersionCache. Use views in getProtocolVersion #1035 (merged) first made the miss path cheap by reading the version off the header view instead of decoding the ledger.
Acceptance criteria
-
getLatestLedgercaches its rendered response, invalidated by ledger sequence ([DRAFT] Optimize query-path caching/memoization #1003) -
getNetworkandgetVersionInfomemoize the latest ledger's protocol version by sequence ([DRAFT] Optimize query-path caching/memoization #1003, on top of Use views in getProtocolVersion #1035) -
simulateTransaction'sgetLatestLedgerPreflightInfostops full-decoding the latest ledger for three header fields (protocol version, bucket list size, close time): read them off the view and memoize by sequence like the above - release eval harness run over the change, speedup noted (perf-eval runs Remove contract-committers from CODEOWNERS #7–soroban-rpc: add an endpoint on soroban RPC to self report versions for downstream clients #10 on the sticky comment; compare against the pre-optimization baseline in [Benchmarking] revert query-path backends to pre-XDR-views to measure speedup #1018)
- [optional] decide whether the three per-handler memos should become one shared latest-ledger cache wired through
specs.go; per-field laziness would be needed so agetNetworkmiss does not trigger the 2 MB render
Measurements
Handler-level, perf-eval go-bench leg, pubnet-sized ledger:
| time | B/op | allocs/op | |
|---|---|---|---|
getLatestLedger, uncached |
8.8 ms | 11.2 MiB | 40 |
getLatestLedger, cached |
1.06 µs | 164 B | 5 |
getNetwork over the pubnet sqlite fixture (v1 sqlite / v2 hot); getVersionInfo tracks it within noise:
| time | B/op | allocs/op | |
|---|---|---|---|
| before | 4.2 ms / 4.4 ms | 10.5 MB / 9.2 MB | 103,000 |
| header view read (#1035) | 175 µs / 264 µs | 1.5 MB / 8.7 KB | ~200 |
| view + memo (#1003) | 10 µs / 13 µs | 5 KB / 6 KB | ~120 |
Out of scope
- Committing ingestion transactions outside the ledger-range cache lock (Commit ingestion transactions outside the ledger-range cache lock #1036): tracked in a separate issue.
- Bypassing jrpc2's marshal round trip for raw response passthrough (jsonrpc: replace jhttp.Bridge with an in-tree bridge #1037; supersedes jsonrpc: own the response envelope — one marshal, one write; the jhttp bridge retires #969): response path, not caching.
- The XDR views migration itself: epic Query-path Sub-Epic: Adopt zero-copy XDR views and GetLedgerRaw for performance #732.
Metadata
Metadata
Assignees
Type
Projects
- StatusShow more project fieldsDone
Activity
[-]Cache getLatestLedger response for performance[/-][+]Cache/memoize per-ledger work in the endpoint handlers (getLatestLedger, getNetwork, getVersionInfo, simulateTransaction) for performance[/+][-]Cache/memoize per-ledger work in the endpoint handlers (getLatestLedger, getNetwork, getVersionInfo, simulateTransaction) for performance[/-][+]Cache/memoize per-ledger work in the endpoint handlers for performance[/+]