sunchao opened a new pull request, #11165:
URL: https://github.com/apache/arrow-rs/pull/11165

   ## Why are the changes needed?
   
   A caller-driven Parquet reader needs to know **which bytes the decoder will 
ask for next** before it can schedule a useful optional read. Knowing only the 
next row-group index is not enough: projection, row selection, offset/limit, 
and existing input buffers can all change that request. Reimplementing this 
logic in an I/O scheduler risks drifting from the decoder. Advancing the 
decoder just to discover a future request also changes ordered execution.
   
   For example, consider a file with many columns where a scan projects only 
column `a` and selects a small interval in the next row group. A useful preview 
follows the existing planner's column/page decisions; it does not simply 
request the whole row group. When the scan reaches its limit, later row groups 
should disappear from the preview as well.
   
   There is a related ownership gap during scan preparation. A custom 
`AsyncFileReader` may retain metadata, cache entries, or a file-version token. 
After moving it into `ParquetRecordBatchStreamBuilder` to read metadata or 
Bloom filters, a caller that wants to drive a push decoder needs that **same 
reader** back. Constructing a replacement can discard the state established 
during preparation.
   
   ## What changes were proposed in this PR?
   
   This adds two small, opt-in APIs for that workflow. Neither API starts reads 
or introduces a scheduler.
   
   `ParquetPushDecoder::preview_row_group_ranges(max_row_groups)` returns an 
advisory snapshot containing the selected row-group indices and the ranges that 
the demand planner would request against the current input buffers. It walks a 
clone of the remaining row-group plan, applies the existing selection and 
offset/limit accounting, and shares the projected-range construction with 
ordinary demand. The decoder itself does not advance.
   
   ```mermaid
   flowchart LR
     A["Decoder at a row-group boundary"] --> B["Preview one or two groups"]
     B --> C["Caller may schedule optional I/O"]
     A --> D["Normal ordered decoding: NeedsData"]
     C --> E["Reconcile with actual demand"]
     D --> E
   ```
   
   For a concrete buffering example, if the planner requests `[100, 200)` and 
one input buffer already covers that whole range, the preview omits it. If only 
`[100, 150)` is buffered, the preview still reports `[100, 200)`, exactly like 
`NeedsData`; it does not invent a partial-range subtraction policy. Likewise, 
the two-group snapshot does not predict how reading the first group will 
consume buffers. Callers must reconcile a preview with later ordered demand 
before using speculative results.
   
   The initial API accepts a depth of one or two. It returns `None` while a row 
group is active or row predicates are present, and an empty preview when no 
selected work remains. It never evaluates a predicate, decodes a batch, or 
reads data. Errors leave the decoder unchanged and should be deferred to normal 
demand by speculative callers. Previewing does clone the remaining plan and 
selections, so it is not a constant-time operation.
   
   `ParquetRecordBatchStreamBuilder::into_inner()` consumes the builder and 
returns its original reader without I/O. The caller can retain metadata 
separately, recover the reader after metadata/Bloom-filter preparation, and 
move it into its own I/O loop. Builder settings are discarded. The test checks 
both metadata-only preparation and a real Bloom-filter read, including 
reader-state identity and the resulting decoded batch.
   
   ## How was this PR tested?
   
   Using Rust 1.98.1 with the `async` feature:
   
   ```text
   cargo test --locked -p parquet --features async --lib arrow::push_decoder::
   # 67 passed, including the eight new preview tests
   
   cargo test --locked -p parquet --features async --lib 
test_builder_into_inner_preserves_reader_after_bloom_filter
   # 1 passed
   
   cargo fmt --all -- --check
   git diff --check
   # both passed
   ```
   
   The preview tests compare actual `NeedsData` requests and decoded batches, 
not just expected row-group indices. They cover projection, global and 
per-row-group selections (including bitmap/RLE, reversed order, empty 
selections, and duplicates), offset/limit, full and partial buffered ranges, 
unsupported predicate/active states, and a preview error that must not consume 
an earlier valid group.
   
   **Local dependency qualification:** the configured registry did not provide 
the upstream lockfile's `opendal 0.59.2`. These focused tests used a temporary 
local resolution with `opendal`/`opendal-core 0.59.1`, `asyncband 0.6.7`, and 
its resolved transitive graph. No manifest changes were made, and the exact 
upstream `Cargo.lock` was restored before committing. The PR contains no 
dependency changes; CI coverage with the committed lockfile is still pending.
   
   No full local suite was run. This PR makes no standalone query-time, 
throughput, or memory-saving claim; scheduling policy and performance 
measurement remain the caller's responsibility.
   
   ## Which issue does this PR close?
   
   Closes #11164.
   
   ## Are there any user-facing changes?
   
   Additive public APIs: `RowGroupRangePreview`, 
`ParquetPushDecoder::preview_row_group_ranges`, and 
`ParquetRecordBatchStreamBuilder::into_inner`. Existing decoding and I/O 
behavior are unchanged when the APIs are not used. Their boundaries, 
invalidation rules, and ownership behavior are documented in the API comments. 
No new dependency or configuration default is introduced.
   
   ## AI assistance
   
   OpenAI Codex assisted with porting the implementation, writing focused 
tests, reviewing the change, and drafting this description.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to