Repository navigation
perf(rust): walk every path-table a statement names at the same time - #1239
Merged
Merged
Conversation
Each path-table's scan ran inside its first xFilter, and SQLite opens one cursor at a time, so a statement over two tables walked the second tree after the first. The authorizer at the final prepare now names the tables the statement reads, and the statement scope starts each one's scan on a thread of its own before SQLite asks for any; the first read joins it.
5 tasks done
Collaborator
Author
|
Hold for #1241. Profiling on this branch (notes in |
8 tasks done
This was referenced Oct 5, 2026
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.
Fixes #1238
Status
Green step pushed, both receipts committed, migrations fragment added (the changelog gate asks for one on any
packages/rust/srcchange),just preflightclean (Rust mutation: 12 tested, 0 survived). The two-table walks now overlap:packages/rust/tests/path_table_parallel_scan.rsfailed on the serial code (CI red on 8c8f56c, ubuntu and Windows, with the test's own assertion) and passes with the fix. The join e2e's strict xfail is removed. Honest caveat: on this box (shared, load average 20 to 200) the join test went from 2.6x over the bar to sitting at it -- 5 passes in 14 runs after the fix, every failure within 2 to 30 percent of the bar, with native itself swinging between 0.78s and 2.74s between runs. The Python receipt took 11 attempts of the full suite; the failures on the way were join (5), dossier (4, untouched by this change) and notebook (1, untouched). The walk no longer costs twice; what remains between dirsql and thefind | awk | joinpipeline is readingcontentfor 34k files plus the join and the sort, which this issue does not cover.What changed
A statement that names several path-tables walked their trees one after the other. The serialization was not in the resolver loop in
Db::run_statement(that loop only registers the virtual tables); it was in SQLite driving the cursors: each path-table's walk runs inside its firstxFilter, and SQLite opens one cursor at a time.Option chosen: the pre-pass, not the shared walk. At the final successful prepare, the authorizer already installed by
prepare_guardedrecords everySQLITE_READtable name.run_statementthen callsStatementScope::warmwith those names, and every adopted path-table cache whose name is in the set starts its scan on a thread of its own (RowCachegains aPendingslot the firstxFilterjoins). The SQLite error loop remains the only thing that registers a table: the authorizer names are read from the statement SQLite accepted, after everyno such tablewas resolved, and a name no adopted table answers to is skipped, so a declared table is never shadowed and nothing is registered for a name SQLite did not fail on. The shared-walk option was not measured: it needs a common root and a merged glob, a bigger change, and the pre-pass alone brings the join to the bar.Measurements
Five speed-of-light tests,
packages/python/tests/e2e, run on a shared 32-core box with load average 50 to 200 throughout; every number is best-of-3 and noisy.measuredis dirsql minus startup; the bar is startup plus 1.1 x native.Before (main's build):
After (this branch):
Release CLI profile against the join fixture (40,000 papers, 3 runs each):
count(*)over the abstract glob 0.44-0.53s, over the title glob 0.43s, over both joined 0.42-0.47s, so two walks now cost one walk. The remaining gap to native on a loaded box is readingcontentand the join itself, not the walk.Manual exercise
cargo build --release --features cli, then the join query fromuse_case_join_test.pyagainst a 40,000-paper fixture, load average about 180: native (find+join) 0.74s / 0.58s / 0.86s, 31,168 rows;dirsql query1.39s / 1.09s / 1.37s, same 31,168 rows, one JSON array line, rows such as{"dir":"papers/2609.000001","title":"Paper 1: on the 1th method","abstract_bytes":248}.E2E Verification
packages/python/e2e-attestations/<branch>.jsonreceipt written ifpackages/pythonchanged (just e2e-attest-python)packages/ts/e2e-attestations/<branch>.jsonreceipt written ifpackages/tschanged (just e2e-attest-ts)cargo test --workspace --features cli,just e2e-attest-python,just e2e-attest-ts,just preflightcargo test --workspace --features cliall green (1042 lib tests plus every integration and CLI e2e test);just e2e-attest-tspassed first run (4 scripts, 112s) and wrotepackages/ts/e2e-attestations/claude-1238-parallel-walk.json;just e2e-attest-pythonpassed on the 11th attempt (40 passed, transcripts strict-xfailed as on main) and wrotepackages/python/e2e-attestations/claude-1238-parallel-walk.json;just preflight0 failing pairs.Changelog / Migrations
packages/rust/changelog.d/2026-10-02-path-table-parallel-walk.mdpackages/rust/migrations.d/2026-10-02-path-table-parallel-walk.md-- no API change; records the one runtime difference (every path table a statement reads is walked at prepare, on its own thread, even if SQLite never opens its cursor) and a verification query