Skip to content

feat(scan): Support split and parallel scans - Part-2a: read Parquet files by task range - #1002

Open
kamcheungting-db wants to merge 13 commits into
apache:mainfrom
kamcheungting-db:feat/file-scan-task-range-reading
Open

kamcheungting-db wants to merge 13 commits into
apache:mainfrom
kamcheungting-db:feat/file-scan-task-range-reading

Conversation

@kamcheungting-db

@kamcheungting-db kamcheungting-db commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Let FileScanTaskReader read a byte range of a Parquet file. #976 added task ranges but rejected them at read time.

Depends on #976. Please review only the last five commits.

How it works

Each row group goes to the split that contains its midpoint: the first column's first page plus half the row group's compressed size. This matches Java Iceberg, which reads splits through parquet-java's withRange() filter. So splits that cover the file read every row exactly once, and C++ and Java pick the same row groups even when a split boundary cuts through a row group.

Example: a file with 100-row groups starting at bytes 4, 1000, and 2000, each about 1000 bytes (midpoints near 500, 1500, and 2500):

Task Row groups _pos
start=0, length=1000 0 0–99
start=1000, length=2000 1, 2 100–299

_pos and _row_id stay relative to the whole file, so deletes and row lineage still work.

Other changes:

  • works when the optional row-group file_offset is missing
  • recheck the range against the file size when opening
  • skip empty row groups; reject invalid page offsets and compressed sizes
  • non-Parquet partial tasks still return NotSupported

Testing

Splits return the same rows, _pos, and _row_id as a whole-file read, with and without deletes. Also covers missing offsets, out-of-order row groups, invalid offsets and sizes, and splits that contain a row group's start but not its midpoint (and the reverse).

  • ctest --test-dir build-clang -R "^(data_test|parquet_test|scan_test)$" --output-on-failure
  • clang-format --dry-run --Werror, git diff --check

This pull request and its description were written by Isaac.

kamcheungting-db and others added 3 commits October 11, 2026 23:55
Preserve start and length in core and REST JSON, and reject partial reads until the reader can honor ranges.
@kamcheungting-db
kamcheungting-db force-pushed the feat/file-scan-task-range-reading branch from c06580b to cc5f910 Compare October 12, 2026 00:23
@kamcheungting-db
kamcheungting-db force-pushed the feat/file-scan-task-range-reading branch from c7ca242 to e94e6b1 Compare October 13, 2026 18:12
kamcheungting-db and others added 6 commits October 14, 2026 20:41
A shared DataFile's size may change after MakeSplit, so ToJson could
emit a range that FileScanTaskFromJson rejects. Revalidate the range
before serializing, matching the REST serializer.

Co-authored-by: Isaac <[email protected]>
FileScanTaskReader previously rejected tasks that read part of a file.
It now passes Parquet task ranges to the reader while keeping the full
file size available for reading the footer.

Use the first column's starting page to assign each row group to a range.
This works when optional row-group offsets are missing and ensures that
adjacent ranges read every row exactly once. Keep row positions and
inherited row IDs relative to the whole file so deletes still remove the
correct rows, even when page offsets are out of order.

Recheck task bounds when opening a file, skip empty row groups, and reject
invalid page offsets and partial tasks for unsupported formats. Add tests
for split boundaries, deletes, row lineage, changed file sizes, and files
with missing row-group offsets.

Validation: all 306 tests in parquet_test and data_test pass. Formatting
and whitespace checks pass. pre-commit could not run because it is not
installed and PyPI DNS resolution failed during installation.
…alled

InitReadContext advanced to the next row-group range before the output
schema was built. If schema setup failed, a retried Next() skipped the
first range. Opening a range no longer consumes it; ConsumeRowGroupRange()
does that once the reader is in place.

Co-authored-by: Isaac <[email protected]>
Java Iceberg reads a split through parquet-java's withRange(), which keeps
a row group when its midpoint (first-column start plus half the compressed
size) falls in [start, start + length). Use the same rule so C++ and Java
readers pick the same row groups for splits that cut through a row group.

Co-authored-by: Isaac <[email protected]>
@kamcheungting-db
kamcheungting-db force-pushed the feat/file-scan-task-range-reading branch from e94e6b1 to 4396b2f Compare October 14, 2026 22:25

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant