Repository navigation
perf(core): own batched rows by rowid range and shape them once in DDL order - #1248
Merged
Merged
Conversation
… a mapping row each
…them once in DDL order A batched on-file hook paid a `_dirsql_internal_rows` insert plus an index insert per row, and rebuilt each row through two HashMaps before binding it by name. The batch is now owned as one `(table, first_rowid, last_rowid)` range in `_dirsql_internal_ranges`, and its rows are laid out in DDL column order once (`Db::shape_rows` -> `ShapedRows`) and bound positionally. Per-file hooks keep the per-row mapping; `delete_rows_by_file`, `get_rows_by_file` and `files_under` resolve both forms, so refresh and watch keep their delete-before-reingest semantics and old persisted caches gain the table on open. Transcripts fixture, release build, min of 6: ingest only 0.99 s -> 0.58 s; full run 2.65 s -> 2.17 s; identical rows.
…nused ShapedRows accessors Unit tests build their JsonRows from json! literals rather than calling the parser, and the persist sweep tests declare the two internal tables inline on their raw connection. ShapedRows::len and is_empty had no production caller. The migration fragment's verification snippet passes -c so it runs as written.
5 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 #1243
Status
Implementation complete;
just preflightgreen locally (0 failing pairs, 41 mutants all caught); both e2e receipts committed. Awaiting CI.What changed
Db::insert_rowsrecords a single(table, owner, first_rowid, last_rowid)in the new_dirsql_internal_rangestable instead of one_dirsql_internal_rowsrow per ingested row.get_rows_by_file,files_underanddelete_rows_by_file_stmtsread both tables, so refresh and the watcher's delete-before-reingest keep their semantics (DELETE ... WHERE rowid BETWEEN first AND last). Tables with a user-suppliedINTEGER PRIMARY KEYare covered by taking min/max of the returned rowids.Db::shape_rowsturns a hook'sVec<JsonRow>intoShapedRows { columns, cells: Vec<Vec<Value>> }(strict validation, extra/missing-column messages unchanged);insert_rowsbinds positionally. The two per-rowHashMaprebuilds (json_row_into_row+normalize_against) are gone.refresh_tablediffs viaShapedRows::to_maps()sodiffer::diff_unorderedis untouched.persist::drop_user_tablesalso clears_dirsql_internal_ranges; the cache keeps both internal tables.ARCHITECTURE.md/PARITY.mdname the new internal table.query()rejects it like the other_dirsql_*tables (new auth test).Item 3 (parser stdout copies in
command.rs): measured, not changed.from_utf8_lossyis zero-copy on valid UTF-8 and the remainingto_stringis one ~36 MB memcpy, under 10 ms on this fixture. Removing it produced no measurable difference across 6 runs, so the change was reverted rather than shipped. No follow-up issue is warranted.Timings
Release build, transcripts fixture (4096 files, 3 parser spawns, ~37 MB of rows), min of 6, load ~1. Output md5 identical before and after (
5ca3f08c04ba5648317060d7b81206c9).efee3e9/tmp/dirsql-tp-feed, pre-generated rows)/tmp/dirsql-tp-fixture/transcripts)The issue's bar was 0.55 s for ingest; this lands at 0.58 s. What remains is reading the parser pipe and
serde_jsondeserialising intoVec<JsonRow>(oneStringper key per row ininfer::parse_rows), which is outside items 1-3.Speed-of-light tests (
packages/python/tests/e2e/,uv run pytest -k speed_of_light):plugins/dirsql-plugin-embeddings/tests/e2e/speed_of_light_test.py)Exercised by hand
Rows match main byte-for-byte; the migrations fragment's verification snippet runs as written.
E2E Verification
just e2e-attest-python->40 passed, 2 xfailed(the two strict xfails are the join and transcripts speed-of-light bars, unchanged); receiptpackages/python/e2e-attestations/claude-1243-ingest-perf.jsonjust e2e-attest-ts->6 files, 18 tests passed; receiptpackages/ts/e2e-attestations/claude-1243-ingest-perf.jsoncargo test --workspace --features cli-> 62 suites, 0 failures (one pre-existing port-race flake incli_e2e::no_config_serves_path_tables_not_a_files_tableseen once in six runs; passes alone and in four consecutive suite runs; untouched by this PR)Changelog / Migrations
packages/rust/changelog.d/2026-10-02-batch-rows-owned-by-range.md(Changed)packages/rust/migrations.d/2026-10-02-batch-rows-owned-by-range.mdPARITY
No public SDK surface changed.
Dbis doc-hidden;_dirsql_internal_rangesis listed inPARITY.mdnext to_dirsql_internal_rows.