sunchao commented on code in PR #3726:
URL: https://github.com/apache/parquet-java/pull/3726#discussion_r4178558095
##########
parquet-hadoop/src/main/java/org/apache/parquet/hadoop/ParquetFileReader.java:
##########
@@ -1358,32 +1355,150 @@ private boolean
arePartsValidForVectoredIo(List<ConsecutivePartList> allParts) {
* If directly implemented by a Filesystem then it is likely to be a more
efficient
* operation such as a scatter-gather read (native IO) or set of parallel
* GET requests against an object store.
+ * Submission and all requested ranges share the vectored-read timeout.
Failed
+ * operations invalidate the stream; cleanup waits for submission to exit
before
+ * closing it, even if the backend does not respond promptly to interruption.
+ * The allocation limit bounds requested range lengths. Filesystems may
merge or
+ * checksum-align ranges and allocate larger buffers; decoders may also
require
+ * larger contiguous buffers. This is not a total memory limit.
* @param allParts all parts to be read.
* @param builder used to build chunk list to read the pages for the
different columns.
- * @throws IOException any IOE.
- * @throws IllegalArgumentException arguments are invalid.
- * @throws UnsupportedOperationException if the filesystem does not support
vectored IO.
+ * @throws IOException if submitting or consuming the vectored reads fails.
+ * @throws IllegalArgumentException if range preparation fails before any
reads are submitted.
*/
private void readVectored(List<ConsecutivePartList> allParts,
ChunkListBuilder builder) throws IOException {
-
+ final int maximumAllocation = options.getMaxAllocationSize();
+ Preconditions.checkArgument(maximumAllocation > 0, "Invalid maximum
allocation size %s", maximumAllocation);
+ final long fileLength = vectoredReadFileLength;
List<ParquetFileRange> ranges = new ArrayList<>(allParts.size());
+ List<Integer> partRangeCounts = new ArrayList<>(allParts.size());
long totalSize = 0;
for (ConsecutivePartList consecutiveChunks : allParts) {
final long len = consecutiveChunks.length;
- Preconditions.checkArgument(
- len < Integer.MAX_VALUE,
- "Invalid length %s for vectored read operation. It must be less than
max integer value.",
- len);
- ranges.add(new ParquetFileRange(consecutiveChunks.offset, (int) len));
+ final long start = consecutiveChunks.offset;
+ if (start < 0 || len < 0 || start > fileLength || len > fileLength -
start) {
+ throw new IOException(String.format(
+ "Invalid vectored read range (offset %d, length %d) for file
length %d",
+ start, len, fileLength));
+ }
+ final int firstRange = ranges.size();
+ long remaining = len;
+ long offset = start;
+ do {
+ int rangeLength = (int) Math.min(remaining, maximumAllocation);
+ ranges.add(new ParquetFileRange(offset, rangeLength));
+ offset += rangeLength;
+ remaining -= rangeLength;
+ } while (remaining > 0);
+ partRangeCounts.add(ranges.size() - firstRange);
totalSize += len;
}
LOG.debug("Reading {} bytes of data with vectored IO in {} ranges",
totalSize, ranges.size());
- // Request a vectored read;
- f.readVectored(ranges, options.getAllocator());
- int k = 0;
- for (ConsecutivePartList consecutivePart : allParts) {
- ParquetFileRange currRange = ranges.get(k++);
- consecutivePart.readFromVectoredRange(currRange, builder);
+ if (vectoredReadExecutor == null) {
+ vectoredReadExecutor = VectoredReadOperation.newExecutor();
Review Comment:
Agreed: idle expiry did not bound workers held by blocked submissions, and
retries could accumulate them. Fixed in
[8ea4302](https://github.com/apache/parquet-java/pull/3726/commits/8ea4302a61254de697f66ef20e5edc75729bbf69)
with a shared bounded executor and deadline-aware admission. The default is 64
workers, configurable before first use through the JVM system property
`parquet.hadoop.vectored.io.threads`.
A worker retains capacity until the backend call actually exits, the caller
transfers or abandons buffer ownership, and failure cleanup finishes. Cleanup
runs on that same worker after submission, so cancellation cannot release
capacity early or let cleanup overtake the backend. Admission shares the
existing 300-second deadline; if capacity is unavailable, the read fails before
submission and its stream remains reader-owned. Readers no longer shut down the
shared executor.
Tests cover two blocked submissions followed by repeated admission timeouts
without extra backend calls/workers, recovery after real completion, blocked
stream close, interruption before admission with reader reuse, and abort before
the worker starts. The 110-test Hadoop 3.4.1 run also passed with the
production shared pool capped at two workers; full default-Hadoop module passed
869 tests with 26 capability skips. The README documents saturation behavior
and the limits: stuck calls can consume capacity indefinitely, and
filesystem-owned threads/total memory are outside this cap. No live S3 or
throughput validation was performed.
--
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]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]