Skip to content

perf: make Rewrite transaction fragment handling O(n) instead of O(groups × fragments) - #22

Merged
tanish-exa merged 2 commits into
mainfrom
devin/1787684548-fast-rewrite-commit
Aug 26, 2026
Merged

perf: make Rewrite transaction fragment handling O(n) instead of O(groups × fragments)#22
tanish-exa merged 2 commits into
mainfrom
devin/1787684548-fast-rewrite-commit

Conversation

@tanish-exa

@tanish-exa tanish-exa commented Aug 25, 2026

Copy link
Copy Markdown

Summary

Makes Transaction::handle_rewrite_fragments O(n + groups) instead of O(groups × fragments), fixing the multi-minute compaction commits seen at Silk Node scale (~4.5M fragments × 384 rewrite groups; debug benchmark ~775s → ~4.6s).

Algorithm: build a one-time HashMap<fragment_id, position> over final_fragments, then for each RewriteGroup:

  • contiguous group → mark positions removed, record replacements[start] = new_fragments (inserted in place)
  • non-contiguous group → mark old positions removed, append new_fragments at the end

Final list is assembled in a single pass. Semantics match the previous implementation (in-place replacement for contiguous groups, append for non-contiguous, CommitConflict on missing first fragment), verified by existing dataset::transaction and dataset::optimize tests.

Hardening found during review: the old code silently tolerated two rewrite groups replacing the same fragment (the O(n) version would have silently overwritten a replacements entry, losing new fragments). Now any group replacing an already-removed position returns CommitConflict ("attempts to replace fragment id=N more than once"), with a regression test. A single compaction plan can't produce overlapping groups (bins come from one linear scan) and concurrent rewrites touching the same fragments are already rejected by the conflict resolver, so this only guards against bugs/replayed transactions.

Known CI failures inherited from main (not caused by this PR, intentionally left out of scope): clippy 1.91 lints in unchanged cleanup.rs, notebook CI missing pandas/tqdm, and cargo-deny RustSec advisories (crossbeam-epoch, h2, aws-lc-sys, …).

Link to Devin session: https://app.devin.ai/sessions/1bf2b920440f4a1db74a8e2809a6d8e8
Requested by: @tanish-exa

…oups * fragments)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration

Copy link
Copy Markdown

Tested this end-to-end by building pylance wheels from this branch and from the parent commit (851925c) and A/B-comparing every rewrite-commit path.

Correctness — byte-identical behavior vs parent commit

  • python/python/tests/test_optimize.py: 10/10 passed on the PR wheel
  • Custom parity harness (contiguous mid-range group, non-contiguous group via materialized deletions, 4 groups in one commit, stable row ids with _rowid preservation, stale-plan conflict): fragment orders, row hashes, and the missing-fragment conflict error (Commit conflict ... id=0) are identical between PR and parent wheels, and identical to prod's pylance 9.0.1+exa.5
  • Rust: dataset::transaction::tests 28 passed (incl. new missing-fragment test), dataset::optimize 46 passed

Silk Node committer (the motivating consumer): installed the PR wheel into the silk_node venv and ran core/nodes/tests/test_compaction_graph/ (62/62, incl. test_committer_real_lance.py) and graphs/tests/test_compaction.py (18/18) — all green.

Perf (debug builds, manifest with 1,000,000 fragments, 2,000 rewrite groups × 100):

build commit time resulting manifest
🔴 parent 851925c 58.75 s 802,000 frags, order sha 4537e1b0…
🟢 this PR 28.25 s 802,000 frags, order sha 4537e1b0… (identical)

The ~30s algorithmic term is eliminated; the remainder is manifest serialization common to both. Not covered: concurrent-append rebase mid-compaction (stale plans surface as conflicts before that path in the Python API).

Tested by Devin — session: https://app.devin.ai/sessions/53d00624d93f48cebd023412401b9ea2

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant