perf: binary-search index leaf position instead of full-page decode - #651
Merged
Conversation
…648) insert_into_index_leaf and delete_from_leaf each fully decoded every cell on an index leaf page (collect_index_leaf_cells) just to linear- scan for one position, and decode_value_cell re-copied the whole page into a fresh Rc<[u8]> per cell decoded rather than once per page. search_index_leaf replaces both call sites with a binary search that decodes only the O(log n) cells actually compared; the full decode now only runs on the already-rare split/fragmented-page fallback paths that genuinely need every cell's contents. value_cell_len adds a cheap, key-decode-free byte-length check for the insert space calculation. update_filtered_range (tests/performance/crud.rs, the reported 85x- slower-than-oracle outlier): 666ms -> 123ms. Other write scenarios: no regression, most modestly faster. spend: matched estimate (medium)
iheitlager
force-pushed
the
perf/648-index-leaf-binary-search
branch
from
August 29, 2026 20:41
a093f63 to
472958e
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.
Summary
insert_into_index_leafanddelete_from_leafeach fully decoded every cellon an index leaf page (
collect_index_leaf_cells) just to linear-scan forone insert/delete position, and
decode_value_cellre-copied the entirepage into a fresh
Rc<[u8]>once per cell decoded rather than once per page.tests/performance/crud.rs(triggered bybenchmark results showing all write ops 5-11x slower than the SQLite
oracle, with
update_filtered_rangeat 85x) traced the shared bottleneckto this exact code path.
Changes
Changed
src/btree/index.rs:decode_value_cellnow takes a sharedRc<[u8]>built once per page by its callers instead of building its own per cell.
Added
search_index_leaf— a binary search over an index leaf's sortedcells, decoding only the O(log n) cells actually compared — and
value_cell_len, a cheap byte-length-only check (no key decode) forspace bookkeeping.
src/btree/index/insert.rs:insert_into_index_leafusessearch_index_leaffor position/duplicate-check and a cheap length-onlyloop for the page-space check. Full
collect_index_leaf_cellsnow onlyruns on the already-rare split/fragmented-fallback paths, which genuinely
need every cell's contents.
src/btree/index/delete.rs:delete_from_leafuses the samesearch_index_leafswap —splice_delete_cellalready recomputes thecell span from raw bytes by index, so only the matched cell's bytes (for
overflow_page_of) are needed.Not touched (intentionally out of scope, see #648 discussion)
IndexCursor::seek's read-path linear scan — a documented Tier 0 designtradeoff (
index.rs:20-22), a separate concern.collect_index_interior_entries, used insplit-promotion/predecessor-swap) — gets the
Rc-hoist fix but not abinary-search rewrite, since those call sites already need full page
contents.
Testing
cargo test --lib— 959 passed, 0 failedmake test(unit, public-API, proptest, doctests) — all greenmake lint(clippy + fmt) — cleanmake -C tests/performance crud(criterion, sqlite-rs vs pinned oracle):update_filtered_range(the reported 85x outlier): 666ms → 123ms (5.4x faster)delete_pk: 8.7% faster;delete_filtered_range: 2.7% fasterinsert_single,update_indexed_column,delete_equality_bucket: nochange (within run-to-run noise) — expected, since single-row writes
are dominated by fixed per-statement fsync/journal cost, not index
decoding
spend: matched estimate (medium)
Related Issues
Closes #648
🤖 Generated with Claude Code