zhf999 opened a new pull request, #167:
URL: https://github.com/apache/paimon-cpp/pull/167

   <!-- PR titles must follow Conventional Commits: <type>(<optional-scope>): 
<description> -->
   
   ### Purpose
   
   Page-level filtering currently installs a `data_page_filter` on Arrow's 
`PageReader`. This skips the page **body** (read/decrypt/decompress/decode) of 
unselected pages, but `SerializedPageReader::NextPage()` still walks the column 
chunk sequentially: it Peeks and Thrift-deserializes the header of **every** 
page, because the only way to find the next page boundary is the 
`compressed_page_size` field inside the header. On top of the page-level 
`ReadRangeCache`, each skipped page header whose bytes are not cached triggers 
a real positional read of up to 16 KiB (`kDefaultPageHeaderSize`), so skipping 
many pages still causes significant small-read I/O amplification and 
header-parsing CPU cost.
   
   This PR eliminates header reads for unselected pages by driving the 
`PageReader` with a precomputed read plan derived from the OffsetIndex:
   
   - **Arrow patch (`cmake_modules/arrow.diff`)**
     - Adds an experimental `DataPageReadPlanEntry {page_ordinal, offset, 
compressed_page_size}` and 
`PageReader::set_data_page_read_plan(first_data_page_offset, data_pages)`, 
mutually exclusive with `set_data_page_filter`. Offsets are relative to the 
column chunk stream.
     - `SerializedPageReader::NextPage()` reads the region before 
`first_data_page_offset` sequentially (dictionary page), then jumps directly to 
each planned data page via `Advance()` and returns EOS once the plan is 
exhausted. Unselected pages are never Peeked or deserialized.
     - Header Peek size is clamped to `min(16 KiB, compressed_page_size)` so a 
header probe never crosses the cached page range (which would fall back to real 
I/O).
   
   - **Paimon 
(`src/paimon/format/parquet/page_filtered_row_group_reader.{h,cpp}`)**
     - Replaces the per-page callback `MakePageFilter` with 
`MakeDataPageReadPlan`, which converts RowRanges + OffsetIndex into 
stream-relative plan entries.
     - `ComputePageRanges` now prefetches exact page ranges `{offset, 
compressed_page_size}` plus the dictionary prefix, and returns no ranges for an 
empty row selection.
     - An empty row selection no longer constructs a `PageReader` (the column 
iterator is created with no row groups), avoiding the eager whole-column-chunk 
read in `GetColumnPageReader()` when no range cache is present.
   
   Note: rebuilding the Arrow external project is required after this change, 
since `cmake_modules/arrow.diff` is applied at Arrow EP patch time and the 
stamp chain does not track it automatically.
   
   ### Tests
   
   New UT cases in 
`src/paimon/format/parquet/page_filtered_row_group_reader_test.cpp`, using a 
`ReadAtTrackingInputStream` that records every positional read issued while 
consuming data pages and asserts that no recorded range covers an unselected 
page header:
   
   - `DirectOffsetIndexJumpDoesNotReadUnselectedPageHeaders`: selects rows from 
pages 1 and 8 out of 10; asserts selected pages are read and unselected page 
headers are never touched (this assertion fails before this change).
   - `DirectOffsetIndexJumpReadsEachLeafDictionary`: two dictionary-encoded 
leaves selecting only the last data page; each leaf still loads its own 
dictionary before jumping.
   - `DirectOffsetIndexJumpSupportsDictionaryFallbackToPlain`: a column that 
falls back from dictionary encoding to PLAIN mid-chunk; one plan decodes both 
kinds of selected pages correctly.
   - `DirectOffsetIndexJumpDataPageV2AdjacentPages`: DATA_PAGE_V2 with two 
adjacent selected pages, verifying the plan cursor advances exactly once per 
page.
   - `DictionaryEmptySelectionDoesNotReadPages`: an empty row selection reads 
no dictionary/data page bytes.
   - `MissingOffsetIndexFallsBackToSequentialRead`: files written without a 
page index keep the original full-column read path and return correct results.
   
   All existing page-filtering tests in this suite now exercise the direct read 
plan path and continue to verify end-to-end results (flat/nested columns, V1/V2 
pages, predicates + bitmaps, multiple row groups).
   
   ### API and Format
   
   No changes under `include/paimon/` and no storage format or protocol change. 
The new `PageReader::set_data_page_read_plan` / `DataPageReadPlanEntry` are 
experimental APIs added only to the vendored Arrow patch 
(`cmake_modules/arrow.diff`), consumed internally by the Paimon Parquet reader. 
Read results are unchanged; only the I/O pattern of page-filtered reads is 
affected.
   
   ### Documentation
   
   No new user-facing feature; behavior and constraints are documented via 
comments on the new Arrow API and in `page_filtered_row_group_reader.{h,cpp}`.
   
   ### Generative AI tooling
   
   No.
   


-- 
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