Describe the bug, including details regarding any error messages, version, and platform.
ParquetFileReader can produce unsafe fallback behavior when Hadoop vectored I/O
is enabled and a filesystem partially submits or completes a vectored read before
raising IllegalArgumentException or UnsupportedOperationException.
The current implementation catches those exceptions around readVectored(...)
and retries every range using ordinary reads against the same ChunkListBuilder.
If an earlier range already populated the builder, its data is appended again.
For a filtered column with selected pages P0 and P2, the buffered page
sequence can become [P0, P0, P2] although the page index still describes
[P0, P2]. Depending on the page contents, decoding can fail or silently
associate the wrong page with the selected rows. Even when no page has been
consumed yet, scalar fallback is unsafe once sibling asynchronous reads may still
be operating on the same stream.
Current upstream code:
|
private void readAllPartsVectoredOrNormal(List<ConsecutivePartList> allParts, ChunkListBuilder builder) |
|
throws IOException { |
|
|
|
if (shouldUseVectoredIo(allParts)) { |
|
try { |
|
readVectored(allParts, builder); |
|
return; |
|
} catch (IllegalArgumentException | UnsupportedOperationException e) { |
|
// Either the arguments are wrong or somehow this is being invoked against |
|
// a hadoop release which doesn't have the API and yet somehow it got here. |
|
LOG.warn("readVectored() failed; falling back to normal IO against {}", f, e); |
|
} |
|
} |
|
for (ConsecutivePartList consecutiveChunks : allParts) { |
|
consecutiveChunks.readAll(f, builder); |
The same vectored path also allocates one buffer for an entire contiguous
requested range instead of honoring parquet.read.allocation.size (8 MiB by
default), unlike the ordinary read path. Large projected column chunks or
filtered pages can therefore create unexpectedly large heap allocations.
The current master branch and Apache Parquet Java 1.18.0 contain this behavior.
The vulnerable path is also present in the 1.15.x, 1.16.x, and 1.17.x release
lines. Vectored I/O defaults to enabled starting in 1.16.0, so supported Hadoop
filesystems can reach this path without an explicit opt-in; in 1.15.2 it is
reachable when explicitly enabled.
Expected behavior:
- Preserve ordinary fallback only when vectored I/O is unavailable or range
preparation fails before asynchronous submission starts.
- Once submission begins, fail the read safely rather than replaying scalar reads
against a partially populated builder or an active stream.
- Wait for already-published sibling reads before returning the original failure.
- Split filesystem byte ranges to respect the configured allocation limit without
changing the logical read plan or decoded results.
- Add regression coverage for partial submission/completion, pending sibling
futures, filtered pages, oversized columns, and checksum-enabled reads.
Component(s)
parquet-hadoop
Describe the bug, including details regarding any error messages, version, and platform.
ParquetFileReadercan produce unsafe fallback behavior when Hadoop vectored I/Ois enabled and a filesystem partially submits or completes a vectored read before
raising
IllegalArgumentExceptionorUnsupportedOperationException.The current implementation catches those exceptions around
readVectored(...)and retries every range using ordinary reads against the same
ChunkListBuilder.If an earlier range already populated the builder, its data is appended again.
For a filtered column with selected pages
P0andP2, the buffered pagesequence can become
[P0, P0, P2]although the page index still describes[P0, P2]. Depending on the page contents, decoding can fail or silentlyassociate the wrong page with the selected rows. Even when no page has been
consumed yet, scalar fallback is unsafe once sibling asynchronous reads may still
be operating on the same stream.
Current upstream code:
parquet-java/parquet-hadoop/src/main/java/org/apache/parquet/hadoop/ParquetFileReader.java
Lines 1293 to 1307 in 8e30c4c
The same vectored path also allocates one buffer for an entire contiguous
requested range instead of honoring
parquet.read.allocation.size(8 MiB bydefault), unlike the ordinary read path. Large projected column chunks or
filtered pages can therefore create unexpectedly large heap allocations.
The current
masterbranch and Apache Parquet Java 1.18.0 contain this behavior.The vulnerable path is also present in the 1.15.x, 1.16.x, and 1.17.x release
lines. Vectored I/O defaults to enabled starting in 1.16.0, so supported Hadoop
filesystems can reach this path without an explicit opt-in; in 1.15.2 it is
reachable when explicitly enabled.
Expected behavior:
preparation fails before asynchronous submission starts.
against a partially populated builder or an active stream.
changing the logical read plan or decoded results.
futures, filtered pages, oversized columns, and checksum-enabled reads.
Component(s)
parquet-hadoop