fix(archiver): speed up log-by-tag queries - #25254
Open
spalladino wants to merge 1 commit into
Open
Conversation
Collaborator
Flakey Tests🤖 says: This CI run detected 1 tests that failed, but were tolerated due to a .test_patterns.yml entry. |
spalladino
force-pushed
the
spl/faster-get-private-logs-by-tags
branch
from
August 25, 2026 19:34
7832313 to
55bc733
Compare
spalladino
changed the base branch from
merge-train/spartan-v5
to
spl/batched-kv-gets
August 25, 2026 19:34
spalladino
force-pushed
the
spl/faster-get-private-logs-by-tags
branch
from
August 25, 2026 19:44
55bc733 to
654e2b4
Compare
spalladino
force-pushed
the
spl/faster-get-private-logs-by-tags
branch
from
August 25, 2026 21:13
654e2b4 to
337936d
Compare
Tag log queries fan the per-tag scans out 8 wide instead of walking tags one at a time, and bounded scans now read a single cursor page instead of paging in tens of entries at a time. `SINGLE_PAGE_LIMIT` caps how large a bounded scan may be before it goes back to paging. Supporting changes on the read path: an empty write batch short circuits to a plain read, `Fr.fromHexString` rejects over-long input on byte length rather than after parsing, and `hexSchemaFor` runs a single transform instead of chaining two. The queries stay inside `db.transactionAsync`, so they serialize with queued writes by design and cannot return a torn result. `node_rpc_perf` gains the production query shape (100 tags per call, real tags, a reference block anchor, `includeEffects` on) plus a probe that measures how much a query queues behind five concurrent siblings.
spalladino
force-pushed
the
spl/faster-get-private-logs-by-tags
branch
from
August 25, 2026 21:19
337936d to
226b1fc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack
Part of A-1817. Bottom to top, each PR targets the branch below it:
spl/faster-block-ingestion->merge-train/spartan-v5— cheaper checkpoint ingestion, so writes hold the store for less timespl/kv-store-read-only-tx->spl/faster-block-ingestion— addsreadOnlyTransactionplustxIdon the nativeGET/START_CURSORspl/batched-kv-gets->spl/kv-store-read-only-tx— addsgetMany/getManyAsync; depends on feat(kv-store): expose read-only lmdb transactions #25280 fortxIdonGetRequestspl/faster-get-private-logs-by-tags->spl/batched-kv-gets— faster tag scans; depends on fix(archiver): batch multi-key point reads into one LMDB round trip #25282 forgetManyAsyncon the log store's per-block reads <- this PRspl/log-store-read-only-snapshots->spl/faster-get-private-logs-by-tags— moves the log store's reads onto snapshots; depends on feat(kv-store): expose read-only lmdb transactions #25280 forreadOnlyTransactionContext
getPrivateLogsByTagswas reported at 100-200ms per call in production, ~10x slower than other node RPC calls. The existingnode_rpc_perfbench couldn't see it (~0.2ms) because it measured a single random tag; measured PXE traffic at the node boundary is very different: ~100 tags per call (median 84, p95 100),includeEffectson, nofromBlock, and a near-total miss rate (0.45% of tags match; 86% of calls return nothing). Profiling with representative benches attributed the cost to: per-tag scans running sequentially, each paying 2-4 native msgpack cursor round trips (10-entry pages vs a 20-log limit); queries queueing behind writes on lmdb-v2's single writer queue; and, for log-heavy responses, re-hydrating thousands ofFrfields through layered Zod schemas and a Buffer-to-hex-to-BigInt round trip.Approach
Queries stay transactional: they still run in
db.transactionAsyncwith exactly the same snapshot-consistency semantics as before, and therefore still serialize with writes. Taking them off the writer queue without losing that guarantee needs the read-only snapshots from #25280 and is done in #25315, on top of this PR.Within that unchanged envelope:
asyncPoolover the transaction's snapshot instead of one at a time, preserving per-tag result order.limit <= 128are fetched as a single one-page cursor request (one native round trip, no cursor slot held). A narrow fast path inWriteTransaction.iteratedelegates to that one-page read when the pending batch is empty — safe because nothing pending can shadow or suppress a committed entry — so it also applies to reads inside a transaction.hexSchemaForcollapses its refine/refine/transform chain into a single transform, andfromHexStringbuilds field elements viaBigInt('0x…')directly instead of round-tripping through a Buffer (~5x faster per field, benefits all hex deserialization).Measured impact (uncontended, vs base):
includeEffects), in-process: 5.3ms → 3.2ms (~40%).Benches and tests added:
node_rpc_perfbench now mints to private so blocks contain real private logs, and addsgetPrivateLogsByTags_100tagsshaped after the measured recipient-sync traffic (100 tags, 1 hit + 99 misses,includeEffects,referenceBlock; ~3.4ms avg) plusgetPrivateLogsByTags_100tags_allhitsandgetPublicLogsByTags_100tagsstress variants, alongside the existing single-tag series.node_rpc_perfalso gainsgetPrivateLogsByTags_100tags_queued, which measures how much a 100-tag query queues behind five concurrent siblings.log_store_write_contentiontest: asserts a tag query racing queued write transactions returns results identical to an uncontended query.