Repository navigation
feat: switch vortex compress to use v2 scan api - #10540
Conversation
Describe how to land the vortex-scan planning driver running develop's pipeline::Scan decode path, with IO through the planning protocol, as a small PR stack extracted from 42b29cc. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P1oQtzTgSzkvrGDKisoNko Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk> Signed-off-by: Claude <noreply@anthropic.com>
…e fork Port the planning driver (`Run`/`Driver`) into vortex-scan and a projection-only V2 executor into vortex-layout that runs develop's pipeline `Scan` through the planning protocol, with every segment read issued as an `IoRequest` served from the file's `SegmentSource`. `ScanBuilder`'s lazy prepare step is the single place a streaming scan picks its executor: `v2::select` returns V1 unless `VORTEX_SCAN_V2=1`, the builder carries a `ScanFile`, and the scan has no filter, no limit and no list layout. `VortexFile::scan()` attaches the `ScanFile`; no caller changes. Signed-off-by: Claude <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cUKVPYqfN7SLcXetK59i6
…ndoff doc Signed-off-by: Claude <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cUKVPYqfN7SLcXetK59i6
Develop's lower keeps Zoned and LegacyStats nodes in the plan, so the boundary walk stopped at them and every default-written file ran as a single split. Follow their data child. Signed-off-by: Claude <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cUKVPYqfN7SLcXetK59i6
Each split had its own ValueCache, so a dictionary shared by many chunks was decoded once per split (HashTags 2.2x, CMSprovider 1.7x slower than V1). Share one cache per scan, as V1's reader does. Signed-off-by: Claude <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cUKVPYqfN7SLcXetK59i6
Reuse V1 split policies, avoid redundant identity-projection planning, and release decoded dictionary values after their consuming splits finish. Reduce pipeline allocation, plan retention, and ready-I/O scheduling overhead. Validated with repeated V1/V2/Parquet decompression comparisons, output parity across 14 datasets, and 175 focused pipeline and scan tests. Some workloads still retain modest RSS and parallel duplicate-read overhead versus V1. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Measure preparation, compilation and in-memory segment delivery for narrow and wide pipeline scans in the existing CodSpeed layout shard. Document the stable identity of scoped dictionary-cache keys and use an explicit Arc clone in the V2 test so the scan code passes the CI Clippy configurations. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Keep private implementation names as code and remove the redundant v2 link target so the planner documentation builds with warnings denied. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Adds ScanBuilder::with_scan_v2 to choose the planner-driven executor for one scan, overriding VORTEX_SCAN_V2, and has compress-bench's Vortex decompression call it, so CI measures V2 decompression against develop's V1 baseline without relying on an environment variable. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VtNyxw9KerLDyt5eXnpnRE Signed-off-by: Claude <noreply@anthropic.com>
Polar Signals Profiling ResultsLatest Run
Previous Runs (4)
Powered by Polar Signals Cloud |
Merging this PR will improve performance by 19.43%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | WallTime | threshold_neon[8] |
2.4 µs | 1.3 µs | +80.41% |
| ⚡ | WallTime | threshold_neon[80] |
4.9 µs | 3.3 µs | +47.36% |
| ⚡ | WallTime | filter_neon[8] |
1,339 ns | 918 ns | +45.86% |
| ⚡ | WallTime | threshold_neon[64] |
3.5 µs | 2.5 µs | +40.64% |
| ⚡ | WallTime | filter_neon[64] |
2.3 µs | 1.8 µs | +30% |
| ⚡ | Simulation | isolated_runs[u64, (161, 944)] |
168.2 µs | 137.7 µs | +22.12% |
| ⚡ | Simulation | embedding_code_runs_expanded_baseline[4096] |
1.9 ms | 1.6 ms | +20.65% |
| ⚡ | Simulation | embedding_code_runs_expanded_baseline[2048] |
1,016.3 µs | 850.6 µs | +19.48% |
| ⚡ | Simulation | embedding_code_runs_expanded_baseline[1024] |
548.4 µs | 465.1 µs | +17.89% |
| ⚡ | Simulation | isolated_runs[u64, (256, 896)] |
219.7 µs | 189.2 µs | +16.11% |
| ⚡ | Simulation | embedding_runs_expanded_baseline[1024] |
609 µs | 525.7 µs | +15.84% |
| ⚡ | Simulation | embedding_runs_expanded_baseline[1536] |
913.6 µs | 789.1 µs | +15.77% |
| ⚡ | Simulation | fragmented_runs_expanded_baseline[1024] |
623.2 µs | 540.2 µs | +15.37% |
| ⚡ | Simulation | embedding_code_runs_expanded_baseline[512] |
319.9 µs | 278.9 µs | +14.72% |
| ⚡ | Simulation | isolated_runs[u64, (161, 0)] |
180.4 µs | 157.2 µs | +14.72% |
| ⚡ | Simulation | isolated_runs[u64, (256, 0)] |
192.8 µs | 169.3 µs | +13.86% |
| ⚡ | Simulation | embedding_runs_expanded_baseline[768] |
516.1 µs | 454.6 µs | +13.51% |
| ⚡ | Simulation | isolated_runs[u64, (256, 1020)] |
196.6 µs | 173.5 µs | +13.34% |
| ⚡ | Simulation | isolated_runs[u32, (128, 0)] |
111.6 µs | 98.6 µs | +13.17% |
| ⚡ | Simulation | isolated_runs[u32, (160, 0)] |
113.8 µs | 101 µs | +12.67% |
| ... | ... | ... | ... | ... | ... |
ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.
Tip
Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.
Comparing ji/upbeat-volta-adp0xd (a9e2601) with develop (6289e58)2
Footnotes
-
12 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
-
No successful run was found on
develop(bc9e0e6) during the generation of this report, so 6289e58 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩
Benchmarks: Compression 📖Commits: PR vortex / vortex-file-compressed / ns (0.908x ➖, 7↑ 0↓)
vortex / vortex-file-compressed / bytes (1.000x ➖, 0↑ 0↓)
vortex / vortex-file-compressed / ratio (0.935x ➖, 10↑ 0↓)
vortex / parquet / ns (1.004x ➖, 0↑ 0↓)
vortex / parquet / bytes (1.000x ➖, 0↑ 0↓)
vortex / arrow-ipc / ns (0.992x ➖, 0↑ 0↓)
vortex / arrow-ipc / bytes (1.000x ➖, 0↑ 0↓)
|
Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VtNyxw9KerLDyt5eXnpnRE Signed-off-by: Claude <noreply@anthropic.com>
Use an explicit V2 ScanBuilder import for benchmark decompression and restore the V1 builder. Remove runtime executor selection and fallback, restrict planning and graph helper visibility, and cover the direct stream and Arrow paths. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
26c83e0 to
4632a21
Compare
Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
d445ce4 to
740e1ef
Compare
Start from 740e1ef and retain its explicit V2 ScanBuilder, fixed row chunks sized by serialized bytes, ScanAdaptor, and one output per work chunk. SelectionPlanner hands its selected rows to the existing ProjectionPlanner. Add ListPack compilation that reads selected boundaries/validity before scanning element ranges. This replaces the follow-up at ad83fcb; that history is preserved by ji/scan-v2-before-pr10540 locally and by the existing ji/scan-v2-regression-ci remote branch. The shared ancestor is 7b15cfc. Reconstructing the compatible additions avoids resurrecting files removed or replaced by the new base. Deviations resolved in favor of PR #10540 before benchmarking: - Keep its explicit API; drop the V1-builder environment gate. - Keep its 8,192-row multiples, at most 65,536 rows, and 8 MiB serialized target; drop the stored-chunk/list-element sparse splitter and separate 32 MiB list-work admission cap. - Keep its ScanAdaptor and aggregate output; drop the alternate ScanGraph, direct point morsel, and per-split streaming channels. - Keep its I/O implementation; drop sparse range lookup, eager request registration/coalescing heuristics, and ready-completion shortcuts. - Keep its file and plan lifetime; drop persistent preparation, support caches, and dictionary retention across file scans. - Keep its scheduler, ValueCache, lowering, and pipeline activation; drop inline ready queues, deferred concat producers, and capacity knobs. - Keep its sharing traversal; drop Reach::Selected/Reach::Ranges pruning. List elements still use exact offset-derived ranges for correctness. - Drop the grouped-list two-range overlap heuristic pending measurements. - Keep the base's documentation deletion and compress-bench V2 selection. The initial diff is 14 files, +1493/-26 including tests and benchmark infrastructure, down from 34 files, +4593/-259. Removed diagnostic modes that depended on the old builder's mapping API. No removed optimization has been restored without post-rebase measurements. The dedicated CI workflow on ji/scan-v2-pr10540 compares the original ad83fcb V2, this V2, and current V1 using identical data and compiler flags. It retains all 48 cases, full Arrow decode/drop, three seeds, alternating order, and longer reruns. Results are pending at this commit. Validation: release_debug selection/rewrite examples built; 573 layout and 65 scan unit tests passed; 72 real-file V1 full-scan-plus-take checks passed across all six benchmark datasets, one and 30 cores, empty, singleton, clustered, uniform, larger, and full selections. Pinned format, Ruff, strict workflow yamllint, and diff whitespace checks passed. No workspace-wide checks, Clippy, or doctests were run. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Keep the benchmark worker-thread timing from develop and use the explicit V2 scan builder in the decompression task. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Ports #10540's planner-driven executor from `vortex_io::request` onto `vortex_io::segments`: - vortex-scan: `Run`/`Driver` submit each root's requests to its `SegmentIoSession` and hold the handles. Each item's fetches finish through its own `FuturesUnordered`, so a `poll_ready` report yields exactly the finished fetches without rescanning outstanding ones. `Run::poll_io` replaces `Run::complete`; sessions are dropped instead of cleared. The scripted harness is a recording `SegmentIoSession` and the driver tests are ported. - vortex-layout: `ScanAdaptor` fetches each segment once by `IoKey::segment` while any scan read of it is outstanding, and hands the result to every waiting read. `ScanFile` carries the file's `RegisteredSource`; each split reads through a new session of its service. The old `SegmentScanIo` adapter is removed. - vortex-file: `VortexFile::scan_file` registers the file's segment source with the session's `FileSegmentIo`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4PmceDHg8rFe5bgkhGFU9 Signed-off-by: Claude <noreply@anthropic.com>
Deviation from PR #10540 retained after the rebase: PackSource already knows the number of consumed rows, but assemble derived it from the first field. A nullable struct with no fields has only a validity inlet, leaving no field from which to recover its length. Pass the consumed length through the existing private helper. This does not restore the old point-projection executor or its assembly API. The regression test failed before the fix: 0 rows instead of 20 for all rows, and 0 instead of 10 for every-other selection. Both pass afterward. Validation: 578 vortex-layout and 65 vortex-scan unit tests passed in the current worktree; no workspace-wide checks or Clippy were run. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Measured deviation from PR #10540: remove the recursive supports_layout preflight. The explicit V2 builder has no fallback to select, and lower already reports unsupported layouts. Keep unrelated layout children lazy instead of deserializing every child before a sparse scan can start. Unknown roots and reached unknown chunks still fail. A chunk outside the requested row range can now remain unsupported and unread; tests cover both outcomes. No persistent file/support cache is restored. After rebasing, one-core clustered feature-vector reopen scans made about 26,100 allocations vs 1,400 before the rebase. In three-seed alternating 64-query runs, removing the walk improved 3.262 ms to 1.252 ms. Thirty-core 64 KiB list clustered reopen improved 1.192 ms to 0.428 ms (previous V2: 0.420 ms). Taxi remained about 31 ms vs 14 ms because fixed work chunks request 133 MB vs 48 MB of unique segment data, a separate issue. The initial base-preferred dedicated CI run 38931231485 completed all 48 cases and 38 longer confirmations; 35 confirmed cases exceed +3% versus ad83fcb. Passing workflow status is not a performance-regression gate. Local raw results and deviations are under random-access-v2/rebase-10540 on /mnt/vortex-ssd/vortex-scanning-v2. This change's focused comparison is lazy-validation-comparison; final full-matrix results are pending. Validation: 578 vortex-layout and 65 vortex-scan unit tests passed, including unsupported-layout cases and the prior nullable-struct fix. Release_debug example built; diff whitespace check passed. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Measured deviation from PR #10540: its 65,536-row ceiling repeatedly reads large stored segments when sparse selections span adjacent work chunks. Preserve fixed aligned chunks, the 8 MiB serialized-byte target, and the base executor. For at most 1/16 selected rows, allow larger power-of-two multiples while targeting four work chunks per worker. Dense scans, non-identity projections, and wide-row sizing are unchanged. This replaces the old stored-layout/list-element splitter with about 20 lines of sizing logic; no additional execution or cache path is added. Three-seed alternating full Arrow decode/drop comparisons after rebasing: - Taxi, 1 core, uniform cached: 31.743 -> 13.950 ms; previous V2 13.598. - Taxi, 1 core, uniform reopen: 32.428 -> 14.737 ms; previous V2 14.433. - Nested structs, 1 core, uniform cached: 6.652 -> 4.324 ms; previous 4.538. Instrumented queries confirm the cause: taxi requests fall from 825 / 133 MB to 327 / 48 MB; nested structs fall from 96 / 71 MB to 48 / 36 MB. Taxi peak live allocation increases from about 18 MB to 40 MB, below the prior implementation's measured peak. The byte target is an estimate of serialized work, not a hard bound on live heap or decoded values. A simpler byte-only variant improved 30-core uniform reads but worsened 30-core clustered taxi by about 9% relative to this worker-limited variant; it was rejected. Keep the base's multi-core sizing in those cases. Other pre-rebase optimizations remain omitted, so this is not a no-regression claim. The final dedicated 48-case comparison is pending publication. Validation: 583 vortex-layout and 65 vortex-scan unit tests passed; 72 real-file full-scan-plus-take checks passed across six datasets, 1/30 cores, empty/singleton/clustered/uniform/larger/full selections. Built instrumented and uninstrumented examples; pinned formatting and diff whitespace checks passed. No workspace-wide checks, Clippy, or doctests. Artifacts: /mnt/vortex-ssd/vortex-scanning-v2/random-access-v2/rebase-10540/ (sparse-budget-comparison, byte-budget-only-comparison, final-diagnostics, final-correctness). Original work remains on ji/scan-v2-before-pr10540 locally and ji/scan-v2-regression-ci remotely. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Start from 740e1ef and retain its explicit V2 ScanBuilder, fixed row chunks sized by serialized bytes, ScanAdaptor, and one output per work chunk. SelectionPlanner hands its selected rows to the existing ProjectionPlanner. Add ListPack compilation that reads selected boundaries/validity before scanning element ranges. This replaces the follow-up at ad83fcb; that history is preserved by ji/scan-v2-before-pr10540 locally and by the existing ji/scan-v2-regression-ci remote branch. The shared ancestor is 7b15cfc. Reconstructing the compatible additions avoids resurrecting files removed or replaced by the new base. Deviations resolved in favor of PR #10540 before benchmarking: - Keep its explicit API; drop the V1-builder environment gate. - Keep its 8,192-row multiples, at most 65,536 rows, and 8 MiB serialized target; drop the stored-chunk/list-element sparse splitter and separate 32 MiB list-work admission cap. - Keep its ScanAdaptor and aggregate output; drop the alternate ScanGraph, direct point morsel, and per-split streaming channels. - Keep its I/O implementation; drop sparse range lookup, eager request registration/coalescing heuristics, and ready-completion shortcuts. - Keep its file and plan lifetime; drop persistent preparation, support caches, and dictionary retention across file scans. - Keep its scheduler, ValueCache, lowering, and pipeline activation; drop inline ready queues, deferred concat producers, and capacity knobs. - Keep its sharing traversal; drop Reach::Selected/Reach::Ranges pruning. List elements still use exact offset-derived ranges for correctness. - Drop the grouped-list two-range overlap heuristic pending measurements. - Keep the base's documentation deletion and compress-bench V2 selection. The initial diff is 14 files, +1493/-26 including tests and benchmark infrastructure, down from 34 files, +4593/-259. Removed diagnostic modes that depended on the old builder's mapping API. No removed optimization has been restored without post-rebase measurements. The dedicated CI workflow on ji/scan-v2-pr10540 compares the original ad83fcb V2, this V2, and current V1 using identical data and compiler flags. It retains all 48 cases, full Arrow decode/drop, three seeds, alternating order, and longer reruns. Results are pending at this commit. Validation: release_debug selection/rewrite examples built; 573 layout and 65 scan unit tests passed; 72 real-file V1 full-scan-plus-take checks passed across all six benchmark datasets, one and 30 cores, empty, singleton, clustered, uniform, larger, and full selections. Pinned format, Ruff, strict workflow yamllint, and diff whitespace checks passed. No workspace-wide checks, Clippy, or doctests were run. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Deviation from PR #10540 retained after the rebase: PackSource already knows the number of consumed rows, but assemble derived it from the first field. A nullable struct with no fields has only a validity inlet, leaving no field from which to recover its length. Pass the consumed length through the existing private helper. This does not restore the old point-projection executor or its assembly API. The regression test failed before the fix: 0 rows instead of 20 for all rows, and 0 instead of 10 for every-other selection. Both pass afterward. Validation: 578 vortex-layout and 65 vortex-scan unit tests passed in the current worktree; no workspace-wide checks or Clippy were run. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Measured deviation from PR #10540: remove the recursive supports_layout preflight. The explicit V2 builder has no fallback to select, and lower already reports unsupported layouts. Keep unrelated layout children lazy instead of deserializing every child before a sparse scan can start. Unknown roots and reached unknown chunks still fail. A chunk outside the requested row range can now remain unsupported and unread; tests cover both outcomes. No persistent file/support cache is restored. After rebasing, one-core clustered feature-vector reopen scans made about 26,100 allocations vs 1,400 before the rebase. In three-seed alternating 64-query runs, removing the walk improved 3.262 ms to 1.252 ms. Thirty-core 64 KiB list clustered reopen improved 1.192 ms to 0.428 ms (previous V2: 0.420 ms). Taxi remained about 31 ms vs 14 ms because fixed work chunks request 133 MB vs 48 MB of unique segment data, a separate issue. The initial base-preferred dedicated CI run 38931231485 completed all 48 cases and 38 longer confirmations; 35 confirmed cases exceed +3% versus ad83fcb. Passing workflow status is not a performance-regression gate. Local raw results and deviations are under random-access-v2/rebase-10540 on /mnt/vortex-ssd/vortex-scanning-v2. This change's focused comparison is lazy-validation-comparison; final full-matrix results are pending. Validation: 578 vortex-layout and 65 vortex-scan unit tests passed, including unsupported-layout cases and the prior nullable-struct fix. Release_debug example built; diff whitespace check passed. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Measured deviation from PR #10540: its 65,536-row ceiling repeatedly reads large stored segments when sparse selections span adjacent work chunks. Preserve fixed aligned chunks, the 8 MiB serialized-byte target, and the base executor. For at most 1/16 selected rows, allow larger power-of-two multiples while targeting four work chunks per worker. Dense scans, non-identity projections, and wide-row sizing are unchanged. This replaces the old stored-layout/list-element splitter with about 20 lines of sizing logic; no additional execution or cache path is added. Three-seed alternating full Arrow decode/drop comparisons after rebasing: - Taxi, 1 core, uniform cached: 31.743 -> 13.950 ms; previous V2 13.598. - Taxi, 1 core, uniform reopen: 32.428 -> 14.737 ms; previous V2 14.433. - Nested structs, 1 core, uniform cached: 6.652 -> 4.324 ms; previous 4.538. Instrumented queries confirm the cause: taxi requests fall from 825 / 133 MB to 327 / 48 MB; nested structs fall from 96 / 71 MB to 48 / 36 MB. Taxi peak live allocation increases from about 18 MB to 40 MB, below the prior implementation's measured peak. The byte target is an estimate of serialized work, not a hard bound on live heap or decoded values. A simpler byte-only variant improved 30-core uniform reads but worsened 30-core clustered taxi by about 9% relative to this worker-limited variant; it was rejected. Keep the base's multi-core sizing in those cases. Other pre-rebase optimizations remain omitted, so this is not a no-regression claim. The final dedicated 48-case comparison is pending publication. Validation: 583 vortex-layout and 65 vortex-scan unit tests passed; 72 real-file full-scan-plus-take checks passed across six datasets, 1/30 cores, empty/singleton/clustered/uniform/larger/full selections. Built instrumented and uninstrumented examples; pinned formatting and diff whitespace checks passed. No workspace-wide checks, Clippy, or doctests. Artifacts: /mnt/vortex-ssd/vortex-scanning-v2/random-access-v2/rebase-10540/ (sparse-budget-comparison, byte-budget-only-comparison, final-diagnostics, final-correctness). Original work remains on ji/scan-v2-before-pr10540 locally and ji/scan-v2-regression-ci remotely. Rebase update: PR #10540 merged as d3bac42. Replay on develop preserves every incoming base change, including the new BitPacked/FSST take paths and writer defaults. The merged base tree equals a9e2601, so the replay has no additional code conflicts. Earlier timing figures above describe the 740e1ef checkpoint; new-base results are pending. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
The final branch now extends develop at d3bac42 (#10540), preserving the base's merged BitPacked/FSST changes and writer defaults. Cancel older runs of this experiment branch when a newer head is published, so the benchmark runner validates the intended source instead of queuing behind a superseded checkpoint. Other branches use different concurrency groups. The 740e1ef base-preferred run 38931231485 is complete and archived. Run 38935258274 targets the previous 15f2fed checkpoint and can be superseded. Its results must not be described as the merged-base comparison. Validation: strict yamllint for the changed workflow and diff whitespace check passed. This commit changes no Rust behavior. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
CI run 38936290519 failed before timing: rewrite_list_layout still called WriteStrategyBuilder::with_list_layout(), removed by upstream #10563 and inherited through the merged #10540 base. Keep the base's edition-driven writer policy and adapt the benchmark helper instead of restoring the API. Enable the experimental list edition only for list/list-elements modes. Flat mode leaves it disabled, preserving the flat control. Drop the obsolete environment guard and explicit writer toggle. Scanner runtime is unchanged, so the completed local 48-case merged-comparison remains applicable. Validation: built both release_debug examples with --locked; rewrote all 1,000,000 rows in flat, list, list-elements/1 MiB and list-elements/64 KiB modes; all four full Arrow equality and layout-kind checks passed, as did four V2 selection comparisons against full V1 scans followed by take. Pinned formatting and diff whitespace checks passed. No new Rust-library checks were needed for this example-only API adaptation. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
#10540 landed on develop with the V2 executor on vortex_io::request. Keep this branch's port onto vortex_io::segments for the V2 executor files, and drop scan/v2/io.rs again. Signed-off-by: Claude <noreply@anthropic.com>
ListSource supplies disjoint offset-derived element ranges to Scan. The merged-base sharing walk took their bounding range and eagerly lowered unread chunks between those ranges. Walk the union of sorted disjoint ranges instead, merging adjacent ranges to preserve the dense-scan path. Keep the existing bounding walk for overlapping or unordered splits. This restores only the measured gap pruning benefit from the original pre-#10540 branch, without changing its scheduler, projection morsels, sharing implementation, or cache lifetimes. Selection planners still hand selected row scopes to projection planners. Two lazy-gap regression cases fail before this change and pass after it. Additional cases cover gaps, overlaps, unordered/empty ranges, FIFO/LIFO completion, and shared segments read once across active split counts. 601 vortex-layout and 69 vortex-scan unit tests pass, as do 72 real-file checks against V1 full scan plus take. Layout all-target/all-feature Clippy with -D warnings, pinned format, and diff whitespace checks pass. The uninstrumented local comparison against ad47e105d uses the same six stored datasets, 3 seeds, and 2 alternating rounds of 64 queries. In its 14 targeted cases, uniform 64 KiB lists improve 12.1/25.5 percent with one core (cached/reopen) and 20.3/33.0 percent with 30 cores. No case regresses more than 0.9 percent. Separate diagnostics reduce 30-core uniform-reopen allocations from 20,636 to 11,143 with requested bytes unchanged at 11.55 MB. These are local measurements, not the earlier native CI comparison. Results: /mnt/vortex-ssd/vortex-scanning-v2/random-access-v2/post-rebase/ gaps-comparison/results.json and gaps-diagnostics/summary.json. Full 48-case comparison is next. Five of these 14 cases remain over 3 percent slower than V1; this checkpoint does not establish the all-cases performance goal or fix repeated I/O across independent projection tasks. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
A projection morsel runs one physical split with a selection mask. The sharing walk still lowered every chunk in its bounding range, even though compilation later skipped chunks with no selected rows. Carry the mask through linear row mappings and skip such children before lowering them. Preserve full reads when a child changes row domains, including dictionary values and list offsets. Dense and multiple-split scans keep their existing sharing walk. Use cached indices or bitmap range counts without making a new sliced mask for each child. This is a measured restoration of selected reach pruning from the original pre-#10540 branch; it does not restore its splitter, executor, or persistent caches. SelectionPlanner still returns ProjectionPlanner with absolute row coordinates. The preceding published checkpoint is 26aa0be. Four masked-gap regression cases fail before this change. Eight cases now cover nested/nonzero ranges, empty masks, and cached/uncached indices, and all 609 layout unit tests pass. All 72 real-file full-scan-plus-take checks pass. Layout all-target/all-feature Clippy with -D warnings, pinned format, and whitespace checks pass. No wider workspace checks or doctests ran. In separate instrumented runs, uniform feature-vector allocation counts fall about 19 percent cached and 31 percent reopening. Requested bytes stay at 85.02 MB; peak memory varies, so no general peak-memory win is claimed. The 20-case uninstrumented comparison uses three seeds and two alternating rounds of 64 queries, full Arrow decode/drop, one and 30 pinned cores. Feature-vector uniform reopen improves 5.6 percent on one core and 11.2 percent on 30 cores against 26aa0be. No tested case regresses more than 1.8 percent. Five cases remain over 3 percent slower than V1, including clustered lists; the all-random-access performance goal remains open. Artifacts: /mnt/vortex-ssd/vortex-scanning-v2/random-access-v2/post-rebase/ mask-comparison/results.json and mask-diagnostics/summary.json. The standard random-access harness also needs explicit V2 coverage; that benchmark-only switch is a separate follow-up, not part of this checkpoint. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Copy the already validated chunk start offsets into the existing Concat Arc instead of repeatedly asking the layout for each child's row count. Keep V1's offset storage and the base planner/scheduler unchanged. This is a measured deviation from PR #10540, isolated for comparison with 5231b70. Four regression cases cover regular, empty, absent, and zero-row chunks; three fail before the change. No child layouts are materialized to lower the boundaries. Production change is +7/-10 lines in two files. Local four-round, five-second standard comparisons show clustered feature vectors improving 8.0% cached / 3.5% reopen on one core and 17.1% / 4.9% on 30 cores. The initial taxi cached +6.4% reduced to +0.8% in the longer run. Nested-struct reopen is still +4.9%; identical-binary controls vary up to 7.8%, so that result is unresolved rather than dismissed as noise. Sixteen full-Arrow list cases initially show at most +2.01% slowdown; longer list confirmation and isolated parent CI remain pending. Repeated memory checks show no increase in taxi maximum live allocation, and median requested read counts/bytes are unchanged. No all-cases V1 win is claimed. Validation: 618 layout tests, all-target/all-feature layout Clippy with -D warnings, pinned formatting, whitespace, release benchmark builds, and 72 real-file V1 full-scan-plus-take correctness comparisons passed. No workspace-wide checks or doctests were run. Keep separate from the draft PR until the exact-parent CI comparison is assessed. Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Summary
Benchmark-only PR, stacked on #10530 (planner-driven V2 executor). It makes compress-bench decode Vortex on the V2 scan executor, so the PR compression benchmark compares V2 decompression with develop's V1 baseline on CI's runners. Do not merge: if this landed, develop's stored Vortex decompress numbers would switch to V2.
The only new commit on top of #10530 is
4632a21.