Skip to content

perf(rowids): stream dataset version runs with a cursor - #8716

Merged
Xuanwo merged 4 commits into
lance-format:mainfrom
jiaoew1991:perf/row-version-cursor
Sep 3, 2026
Merged

perf(rowids): stream dataset version runs with a cursor#8716
Xuanwo merged 4 commits into
lance-format:mainfrom
jiaoew1991:perf/row-version-cursor

Conversation

@jiaoew1991

@jiaoew1991 jiaoew1991 commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Stream dataset-version RLE metadata with a persistent cursor instead of rebuilding and searching run offsets for every batch.

The change:

  • adds RowDatasetVersionCursor for adjacent, monotonic batch traversal;
  • caches the active run length and bulk-expands range values;
  • lazily builds a run-offset index on the first backward seek, then uses it for every later non-adjacent seek in either direction;
  • precomputes created-at and last-updated-at arrays while polling the ordered task stream;
  • preserves the direct-call fallback and the single-run fast path.

#8713 and #8715 are merged. This branch is rebased on 774e32d67, and its diff now contains only the dataset-version work.

Performance

Linux Criterion A/B, 100,000 rows, batch size 1,024, release-with-debug, pinned to the same CPU. Baseline is 774e32d67; this PR is 6f22e566c.

Ordered stream

Version runs main This PR Result
1 98.325 us 98.855 us +0.54% (neutral)
98 930.69 us 112.30 us 8.29x faster
3,125 3.2053 ms 128.27 us 24.99x faster
100,000 56.033 ms 517.17 us 108.34x faster

Direct-call fallback

Version runs main This PR Result
1 631.81 ns 634.07 ns +0.36% (neutral)
98 8.983 us 762.10 ns 11.79x faster
3,125 32.532 us 5.108 us 6.37x faster
100,000 552.08 us 142.84 us 3.87x faster

This PR makes no single-run speedup claim. It improves robustness for updated and multi-run fragments.

For attribution, Linux perf sampled the 3,125-run ordered-stream case for five seconds at 997 Hz. On main, 49.72% of samples were in version_values_for_selection, 39.39% in U64Segment::len, and 4.96% in run-offset Vec construction (94.07% combined). With this PR, U64Segment::len and offset construction were each below the 0.5% report threshold; the remaining profile was distributed across cursor expansion, allocation, Arrow column assembly, and stream scheduling.

Correctness

The tests cover adjacent ranges, gaps, rewinds, empty runs, non-range spans, out-of-bounds selections, descending seeks, alternating far-forward/backward seeks, direct calls, deletions, both version columns, concurrent batches, and unsorted indices split across multiple batches.

Validation

  • cargo test -p lance-table --lib (372 passed)
  • cargo clippy --all --tests --benches -- -D warnings
  • cargo fmt --all -- --check
  • git diff --check
  • Linux release-with-debug Criterion A/B and perf profiles described above

lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Aug 24, 2026
@jiaoew1991
jiaoew1991 force-pushed the perf/row-version-cursor branch from 16a33d9 to 450d631 Compare August 24, 2026 12:08
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Aug 24, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@jiaoew1991
jiaoew1991 changed the base branch from jiaoew/stack-rowid-cursor-base to jiaoew/stack-rowid-cursor-base-v2 August 24, 2026 12:14
@lance-gatekeeper lance-gatekeeper Bot added K-approved Latest Gatekeeper recommendation permits acceptance. and removed K-approved Latest Gatekeeper recommendation permits acceptance. labels Aug 24, 2026
@jiaoew1991
jiaoew1991 force-pushed the perf/row-version-cursor branch from 450d631 to 453f949 Compare August 24, 2026 13:53
@github-actions github-actions Bot added A-python Python bindings A-deps Dependency updates A-encoding Encoding, IO, file reader/writer labels Aug 24, 2026
@jiaoew1991
jiaoew1991 changed the base branch from jiaoew/stack-rowid-cursor-base-v2 to jiaoew/stack-rowid-cursor-base-v3 August 24, 2026 13:54
@lance-gatekeeper lance-gatekeeper Bot removed the K-approved Latest Gatekeeper recommendation permits acceptance. label Aug 24, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-approved Latest Gatekeeper recommendation permits acceptance. label Aug 24, 2026
@jiaoew1991
jiaoew1991 force-pushed the perf/row-version-cursor branch from 453f949 to 720380c Compare August 24, 2026 14:33
@github-actions github-actions Bot added the A-java Java bindings + JNI label Aug 24, 2026
@jiaoew1991
jiaoew1991 changed the base branch from jiaoew/stack-rowid-cursor-base-v3 to jiaoew/stack-rowid-cursor-base-v4 August 24, 2026 14:33
@lance-gatekeeper lance-gatekeeper Bot removed the K-approved Latest Gatekeeper recommendation permits acceptance. label Aug 24, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-approved Latest Gatekeeper recommendation permits acceptance. label Aug 24, 2026
@jiaoew1991
jiaoew1991 force-pushed the perf/row-version-cursor branch from 720380c to 9c5653f Compare August 25, 2026 01:09
@github-actions github-actions Bot added A-index Vector index, linalg, tokenizer A-ci CI / build workflows labels Aug 25, 2026
@jiaoew1991
jiaoew1991 changed the base branch from jiaoew/stack-rowid-cursor-base-v4 to jiaoew/stack-rowid-cursor-base-v5 August 25, 2026 01:09
@lance-gatekeeper lance-gatekeeper Bot removed the K-approved Latest Gatekeeper recommendation permits acceptance. label Aug 25, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added K-approved Latest Gatekeeper recommendation permits acceptance. and removed K-approved Latest Gatekeeper recommendation permits acceptance. labels Aug 25, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Aug 25, 2026
jiaoew1991 added a commit that referenced this pull request Aug 25, 2026
## Summary

Reduce fixed per-batch work in the system-column scan pipeline after the
row-ID and version cursors have removed decoder prefix scans.

This change:

- reads at most 64K stable row IDs ahead and serves adjacent batches as
zero-copy Arrow slices;
- assembles all requested system columns into one `RecordBatch` instead
of repeatedly extending schema/batch objects;
- caches structurally equivalent schemas, not only pointer-identical
`Arc<Schema>` values;
- reuses a full-size zero-column batch template;
- skips no-op projections for system-only reads only when schemas are
strictly equal;
- bounds read-ahead by the actual range selection, including empty and
tail reads.

The 64K read-ahead bound is about 512 KiB of `u64` values per active
fragment. Zero-copy slices can keep that chunk alive until adjacent
batches are released.

## Performance

100K-row synthetic scan on top of #8713, #8715, and #8716:

- batch size 64: row-ID-only cases improve 29-45%; all-system-column
cases improve 53-57%;
- batch size 1024, stable isolated all-system cases:

| Shape | Payload | Before | After | Reduction |
|---|---:|---:|---:|---:|
| 50% bitmap | u64 | 544.23 us | 377.30 us | 30.7% |
| ~94% bitmap | none | 449.06 us | 291.73 us | 35.0% |
| ~94% bitmap | u64 | 481.21 us | 296.43 us | 38.4% |

Full-suite batch-size-1024 runs showed pod outliers, so the table
reports paired one-case reruns that were stable. The batch-size-64
matrix was stable as a full run.

CPU profiling before this change identified
`RecordBatch::try_with_column`, `SchemaExt::try_with_column`, schema
`Arc` drops, and allocator consolidation as material hotspots. Those
repeated per-column/schema-extension hotspots disappear afterward;
remaining time is one system-column assembly, row-ID decode, array
ownership, and allocator work.

## Validation

- `cargo test -p lance-table --lib` (344 passed)
- `cargo test -p lance dataset::fragment::tests` (82 passed)
- `cargo check -p lance-table --tests --benches`
- `cargo clippy -p lance-table --all-targets --no-deps -- -D warnings`
- `cargo clippy -p lance --all-targets --no-deps -- -D warnings`
- `cargo fmt --all -- --check`
- `git diff --check`
- 32/32 read-only correctness matrix spanning stable-row-ID encodings,
boundary offsets, batch sizes 1 through 65536, and row-ID / row-address
/ combined projections; every array matched an independent oracle

Targeted regressions cover mixed payload + all-system projection
schema/order, structurally equal schemas with different `Arc`s,
stable-row-ID unsorted indices, read-ahead tail/chunk boundaries, empty
tasks, and system-only `read_all` / `read_ranges`.

Stack dependencies: #8713, #8715, #8716. The PR base is a temporary
upstream integration ref containing those three dependencies and will be
retargeted to `main` after they merge.
@jiaoew1991
jiaoew1991 force-pushed the perf/row-version-cursor branch from 9c5653f to abd74b6 Compare August 25, 2026 12:22
@jiaoew1991
jiaoew1991 changed the base branch from jiaoew/stack-rowid-cursor-base-v5 to jiaoew/stack-rowid-cursor-base-v6 August 25, 2026 12:24
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Aug 25, 2026
@jiaoew1991
jiaoew1991 changed the base branch from jiaoew/stack-rowid-cursor-base-v6 to main August 25, 2026 12:28
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Aug 25, 2026
BubbleCal pushed a commit that referenced this pull request Aug 26, 2026
## Summary

Reuse a stable row-ID cursor across ordered record-batch tasks and
bulk-decode range-backed segments.

Stable row IDs represented as `RangeWithBitmap` / `RangeWithHoles`
previously rebuilt selection state for every batch. Sequential scans
therefore rescanned an ever-growing prefix, approaching quadratic work
as batch count increased.

This change:

- persists `RowIdSequenceCursor` across ordered tasks and caches segment
lengths;
- adds an exact-capacity contiguous-range path;
- adds `SegmentCursorState::extend_range` for bulk expansion of range
and bitmap segments;
- preserves the direct/random selection fallback and rejects unsorted
indices explicitly;
- reports truncated stable row-ID metadata as `CorruptFile` instead of
panicking or returning a short batch.

## Performance

100K-row synthetic sequential scan, identical Criterion harness:

| Batch size | `main` | This PR | Speedup |
|---:|---:|---:|---:|
| 64 | 17.177 ms | 1.174 ms | 14.6x |
| 1024 | 1.868 ms | 236.16 us | 7.9x |

CPU profiling on `main` attributed 51.73% to `RowIdSequence::select` and
33.45% to `U64Segment::len`, matching repeated prefix traversal. After
this change those hotspots are replaced by
`SegmentCursorState::extend_range`; remaining time is fixed
allocation/schema work.

## Validation

- `cargo test -p lance-table --lib` (336 passed)
- `cargo check -p lance-table --tests --benches`
- `cargo clippy -p lance-table --all-targets --no-deps -- -D warnings`
- `cargo fmt --all -- --check`
- `git diff --check`

This is the root of the row-ID optimization stack and has no dependency
on the bitmap or version-cursor follow-ups.

Follow-up PRs:

- #8715: dense / near-dense bitmap decode paths
- #8716: dataset-version RLE cursor
- #8747: system-column scan pipeline fixed-cost reduction
@jiaoew1991
jiaoew1991 force-pushed the perf/row-version-cursor branch from abd74b6 to 6f22e56 Compare September 3, 2026 00:51
@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Sep 3, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added K-approved Latest Gatekeeper recommendation permits acceptance. and removed K-approved Latest Gatekeeper recommendation permits acceptance. labels Sep 3, 2026
@lance-gatekeeper lance-gatekeeper Bot removed the K-approved Latest Gatekeeper recommendation permits acceptance. label Sep 3, 2026

@lance-gatekeeper lance-gatekeeper Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gate recommendation: approve.

With #8713 in the base, this patch-equivalent merge preserves the version-column-only change: one-pass adjacent traversal, indexed non-adjacent seeks, and arbitrary selection order across batches.

@lance-gatekeeper lance-gatekeeper Bot added the K-approved Latest Gatekeeper recommendation permits acceptance. label Sep 3, 2026
@Xuanwo
Xuanwo merged commit a8bec27 into lance-format:main Sep 3, 2026
38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ci CI / build workflows A-deps Dependency updates A-encoding Encoding, IO, file reader/writer A-index Vector index, linalg, tokenizer A-java Java bindings + JNI A-python Python bindings K-approved Latest Gatekeeper recommendation permits acceptance. performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants