Skip to content

HIVE-30059: LLAP IO Cache: native parquet data cache - #6793

Open
abstractdog wants to merge 17 commits into
apache:masterfrom
abstractdog:parquet-io-cache
Open

abstractdog wants to merge 17 commits into
apache:masterfrom
abstractdog:parquet-io-cache

Conversation

@abstractdog

@abstractdog abstractdog commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

Native LLAP encoded-data path for Parquet, mirroring the existing ORC pipeline:

  • ParquetColumnVectorProducerParquetEncodedDataReaderParquetEncodedDataConsumer, feeding VectorizedColumnReaders through a shared ParquetRowGroupDecoder (extracted from VectorizedParquetRecordReader).
  • Column chunks are held natively as MemoryBuffer[] in ParquetEncodedColumnBatch; ParquetCachedPageReadStore parses pages in place over those cached buffers with lazy per-page decompression — no ParquetFileReader, no copy from cache into a Parquet read buffer.
  • Enabled by default via hive.llap.io.parquet.native.enable=true.

Design doc: HIVE-30059-design.pdf.

Why are the changes needed?

Parquet under LLAP already caches byte-ranges via LlapCacheAwareFs, but reads still go through a stock ParquetFileReader over a virtual llapcache:// URL: cached bytes get copied into the reader's own buffers, page parsing and decompression run per-read, and the path isn't wired into LLAP's encoded-column pipeline or fragment counters. This PR brings Parquet to parity with ORC's native LLAP path: zero-copy page parsing over cached buffers, lazy decompression, full LLAP IO counter integration (METADATA_CACHE_HIT/MISS, SELECTED_ROWGROUPS, HDFS/IO time), and the shared ColumnVectorProducer/EncodedDataConsumer execution model.

Does this PR introduce any user-facing change?

Better Parquet read performance under LLAP (zero-copy page parsing over cached buffers, lazy decompression). Query summaries now report DATA_HIT / METADATA_CACHE_HIT (and their _MISS counterparts) for Parquet, so cache effectiveness is visible the same way it is for ORC. Opt-out via hive.llap.io.parquet.native.enable=false.

How was this patch tested?

  • TestParquetEncodedDataReader (27 tests) — plan/fetch/assemble, cache hit/miss, footer caching, encryption fallback, schema evolution.
  • TestParquetCacheLayout, TestParquetRangeBuffers (8 tests) — page-range math and buffer reuse.
  • Existing TestVectorizedParquetRecordReader unchanged (shared ParquetRowGroupDecoder).
  • Manual verification through miniHS2 with LLAP.

@abstractdog abstractdog changed the title Parquet io cache HIVE-30059: LLAP IO Cache: native parquet data cache Sep 16, 2026
* Vectorized reads of parquet files from columns with list or map type is only supported if the nested types are of
* primitive type category
* check {@link VectorizedParquetRecordReader#checkListColumnSupport} for details on nested types under lists
* check {@link org.apache.hadoop.hive.ql.io.parquet.vector.ParquetRowGroupDecoder#checkListColumnSupport} for

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need full name with package here?

serdeCache, bufferManagerGeneric, conf, cacheMetrics, ioMetrics, tracePool, encodeExecutor) : null;
// Native Parquet IO is gated per query by the job conf at the dispatch sites.
this.parquetCvp = dataCache != null
? new ParquetColumnVectorProducer(dataCache, bufferManagerOrc, conf, cacheMetrics, ioMetrics)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we drop orc from bufferManagerOrc ?

private boolean checkOrcSchemaEvolution() {
SchemaEvolution evolution = rp.getSchemaEvolution();
if (evolution == null) {
// No ORC-style schema evolution to validate (e.g. native parquet path);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we check non-ORC schema inside checkOrcSchemaEvolution ?


/** Slices of the cached buffers covering exactly the chunk's byte region, in file order. */
private static List<ByteBuffer> chunkBuffers(ParquetEncodedColumnBatch batch, int pc) {
long start = batch.chunks[pc].getStartingPos(), end = start + batch.chunks[pc].getTotalSize();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move env var on a new line

List<ByteBuffer> slices = new ArrayList<>(batch.columnBuffers[pc].length);
for (int i = 0; i < batch.columnBuffers[pc].length; ++i) {
long offset = batch.bufferOffsets[pc][i];
long from = Math.max(start, offset), to = Math.min(end, offset + batch.bufferLengths[pc][i]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same, new line for to, maybe need better naming

super(consumer, includes.getPhysicalColumnIds().size(), ioMetrics, counters);
this.jobConf = jobConf;
this.useDecimal64ColumnVectors = HiveConf.getVar(jobConf,
ConfVars.HIVE_VECTORIZED_INPUT_FORMAT_SUPPORTS_ENABLED).equalsIgnoreCase("decimal_64");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have constant for "decimal_64" ?

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved critical and moderate findings affect schema projection, cache ownership, row lineage, configuration, and fallback behavior.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds opt-in native Parquet LLAP caching with vectored reads, cached-page decoding, fallback integration, and supporting tests.

Changes:

  • Adds native Parquet LLAP configuration, APIs, and dispatch.
  • Implements cache layouts, range buffers, vectored reads, and page decoding.
  • Refactors shared Parquet reader logic and expands test coverage.
File summaries
File Reviewed changes and final comments
ql/src/test/org/apache/hadoop/hive/llap/TestParquetRangeBuffers.java Tests range-buffer reuse and slicing; no final comments.
ql/src/test/org/apache/hadoop/hive/llap/TestParquetCacheLayout.java Tests cache layout behavior; no final comments.
ql/src/java/org/apache/hadoop/hive/ql/plan/MapWork.java Enables native Parquet LLAP eligibility; no final comments.
ql/src/java/org/apache/hadoop/hive/ql/io/parquet/vector/VectorizedParquetRecordReader.java Critical, 1 vote: Native reads omit row-lineage columns, producing null/default lineage values.
ql/src/java/org/apache/hadoop/hive/ql/io/parquet/vector/ParquetRowGroupDecoder.java Shares row-group decoder construction; no final comments.
ql/src/java/org/apache/hadoop/hive/ql/io/parquet/ParquetRecordReaderBase.java Reviewed as part of Parquet reader integration; no final comments.
ql/src/java/org/apache/hadoop/hive/ql/io/HiveInputFormat.java Gates native Parquet wrapping; no final comments.
ql/src/java/org/apache/hadoop/hive/llap/ParquetRangeBuffers.java Manages vectored-read buffers; no final comments.
ql/src/java/org/apache/hadoop/hive/llap/ParquetCacheLayout.java Moderate, 1 vote: Native layout can create fallback-incompatible cache gaps and trigger an assertion instead of refetching.
ql/src/java/org/apache/hadoop/hive/llap/LlapCacheAwareFs.java Supports cache-aware fallback reads; no final comments.
llap-server/src/test/org/apache/hadoop/hive/llap/io/encoded/TestParquetEncodedDataReader.java Tests native reads and caching; no final comments.
llap-server/src/test/org/apache/hadoop/hive/llap/io/api/impl/TestLlapRecordReader.java Tests LLAP reader behavior; no final comments.
llap-server/src/java/org/apache/hadoop/hive/llap/io/encoded/ParquetEncodedDataReader.java Critical, 2 votes: Top-level field indexes are used against flattened leaf columns, misselecting nested projections. Critical, 1 vote: Partial cache insertion failure can cause cache-owned buffers to be deallocated. Nit, 1 vote: count(*) fetches and caches unnecessary column chunks.
llap-server/src/java/org/apache/hadoop/hive/llap/io/encoded/ParquetEncodedColumnBatch.java Carries cached row-group data; no final comments.
llap-server/src/java/org/apache/hadoop/hive/llap/io/decode/ParquetEncodedDataConsumer.java Moderate, 1 vote: Decode exceptions are swallowed, allowing later I/O and resource use after failure.
llap-server/src/java/org/apache/hadoop/hive/llap/io/decode/ParquetColumnVectorProducer.java Creates native Parquet pipelines; no final comments.
llap-server/src/java/org/apache/hadoop/hive/llap/io/decode/ParquetCachedPageReadStore.java Reads cached Parquet pages; no final comments.
llap-server/src/java/org/apache/hadoop/hive/llap/io/api/impl/LlapRecordReader.java Supports producer fallback; no final comments.
llap-server/src/java/org/apache/hadoop/hive/llap/io/api/impl/LlapIoImpl.java Moderate, 1 vote: Discards supplied fileKey and tag. Moderate, 1 vote: Can create the native producer without a metadata cache in memory mode none. Moderate, 1 vote: Does not honor the per-query native Parquet disable flag.
llap-server/src/java/org/apache/hadoop/hive/llap/io/api/impl/LlapInputFormat.java Integrates LLAP input handling; no final comments.
llap-client/src/java/org/apache/hadoop/hive/llap/io/api/LlapIo.java Extends the Parquet LLAP API; no final comments.
iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/vector/HiveVectorizedReader.java Updates footer-cache API usage; no final comments.
iceberg/iceberg-handler/src/main/java/org/apache/iceberg/mr/hive/HiveIcebergStorageHandler.java Reviewed for storage-handler integration; no final comments.
common/src/java/org/apache/hadoop/hive/conf/HiveConf.java Adds native Parquet configuration; no final comments.
Review details

Suppressed comments (6)

llap-server/src/java/org/apache/hadoop/hive/llap/io/api/impl/LlapIoImpl.java:503

  • This constructs a plain FileSplit and silently discards the fileKey and tag supplied by the public API. The native reader then derives a different key from the job configuration/filesystem in loadFooter() and computes its own tag, so callers that provide a stable file identity cannot read or populate the intended data-cache entry or preserve the administrative cache tag. Propagate these arguments through the native reader, or remove them from the API instead of ignoring them.
    FileSplit split = new FileSplit(path, offset, length, (String[]) null);
    try {
      LlapRecordReader rr = LlapRecordReader.create(conf, split, tableIncludedCols, HiveStringUtils.getHostname(),

llap-server/src/java/org/apache/hadoop/hive/llap/io/api/impl/LlapIoImpl.java:285

  • dataCache is non-null in LLAP_IO_MEMORY_MODE=none because LlapIoImpl assigns a SimpleBufferManager to it while leaving fileMetadataCache null. With the native flag enabled, this condition still creates parquetCvp; ParquetEncodedDataReader.loadFooter then calls getParquetFooterBuffersFromCache, whose first operation requires a non-null metadata cache, so the LLAP input format fails instead of falling back to the normal Parquet reader. Gate this producer on the metadata cache as well (or make the native reader bypass the footer cache when it is unavailable).
    this.parquetCvp = dataCache != null
        ? new ParquetColumnVectorProducer(dataCache, bufferManagerOrc, conf, cacheMetrics, ioMetrics)
        : null;

llap-server/src/java/org/apache/hadoop/hive/llap/io/api/impl/LlapIoImpl.java:500

  • The API contract says this method returns null when native Parquet IO is disabled, but parquetCvp is constructed independently of the per-query flag and this check only tests for null. A caller can therefore set hive.llap.io.parquet.native.enabled=false and still start the native reader, bypassing the configuration gate used by HiveInputFormat. Include ConfVars.LLAP_IO_PARQUET_NATIVE_ENABLED in this guard.
    if (parquetCvp == null) {
      return null;
    }

llap-server/src/java/org/apache/hadoop/hive/llap/io/decode/ParquetEncodedDataConsumer.java:195

  • These exceptions are reported but swallowed, so EncodedDataConsumer.consumeData returns normally and ParquetEncodedDataReader.performDataRead continues fetching and decoding later row groups before calling setDone. A corrupt page in an early group can therefore keep doing I/O and holding cache resources after the downstream reader has failed. Propagate the decode failure after recording it (or let consumeData perform the error notification) so the reader's abort path stops the split.
    } catch (IOException | RuntimeException e) {
      // parquet-mr reports decode failures as runtime ParquetDecodingException.
      LlapIoImpl.LOG.error("Parquet decodeBatch failed for rowGroup " + batch.rowGroupIx + " of " + path, e);
      downstreamConsumer.setError(e);
    } finally {

llap-server/src/java/org/apache/hadoop/hive/llap/io/encoded/ParquetEncodedDataReader.java:197

  • For the count(*) projection, colsToInclude can be empty while requestedSchema still contains the table fields; the shared decoder explicitly documents that all readers are null in this case. This code nevertheless derives every requested field as a projected leaf, so the native path fetches and caches every column chunk even though it only needs each row group's row count. Short-circuit the projected-leaf list when includes.getPhysicalColumnIds() is empty.
    int[] projected = projectedLeaves(requestedSchema, fileSchema);

ql/src/java/org/apache/hadoop/hive/llap/ParquetCacheLayout.java:88

  • This native layout is incompatible with the existing Parquet fallback cache writer. LlapCacheAwareFs.getAndValidateMissingChunks requires every missing gap to start and end on maxAlloc boundaries, while this method can split a 5 MiB chunk into 4 MiB + 1 MiB. If the 1 MiB native buffer is evicted and a later nested-type/fallback reader requests the chunk, the fallback sees a gap starting at chunkStart + 4 MiB and throws an AssertionError instead of refetching it. Both paths need to share the same layout, or the fallback must accept arbitrary cache gaps.
  public int[] bufferSizes(long length) {
    int count = 0;
    for (long left = length; left > 0; ++count) {
      left -= left < minBuffer ? left : Math.min(maxBuffer, Long.highestOneBit(left));
    }
  • Files reviewed: 24/24 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

abstractdog added a commit to abstractdog/hive that referenced this pull request Sep 17, 2026
Three Critical findings on the native Parquet cache path:

- projectedLeaves used fileSchema.getFieldIndex to pick column chunks, but
  BlockMetaData.getColumns() is in flat leaf order. A file schema like
  'group nested {a,b}, x' projecting 'x' would hit nested.b instead of x.
  Map each requested top-level primitive to its single-segment leaf in
  fileSchema.getColumns() instead. Add a regression test.
- putColumn set part.owned only after processing all missing ranges for the
  column, so a mid-run throw from putFileData (e.g. its length-mismatch
  guard) left already-inserted cache buffers looking like raw allocations
  and finishFetch would allocator.deallocate cache-owned memory. Insert
  one range at a time and flip ownership per part.
- ParquetEncodedDataReader.loadFooter builds requestedSchema without the
  row-lineage columns the fallback reader adds via
  RowLineageUtils.getRequestedSchemaWithRowLineageColumns, so with row
  lineage on the native path would silently emit nulls for
  ROW__LINEAGE__ID / LAST__UPDATED__SEQUENCE__NUMBER. Detect that case in
  the producer and fall back, matching the nested-projection fallback.

Co-Authored-By: Claude Code <noreply@anthropic.com>
abstractdog added a commit to abstractdog/hive that referenced this pull request Sep 17, 2026
Fix the mechanical issues flagged on files this PR modifies. Skips the
15 findings inside verbatim extractions from VectorizedParquetRecordReader
(kept behavior-preserving) and the switch/case indentation reports.

Notable non-trivial fixes:
- LlapIo.llapVectorizedParquetReaderForPath: 9 params -> 3, collected
  into a new LlapParquetReadRequest record.
- LlapInputFormat.getRecordReader: extract wrapOrFallback() to bring
  cognitive complexity under threshold.
- ParquetEncodedDataReader: extract planMissRun() from planColumnChunk;
  drop unused 'includes' field/param, unused maxAlloc param, and Part.miss;
  narrow catch(Throwable) -> catch(Exception) at four sites and preserve
  InterruptedException on the thread instead of masking it.
- ParquetCacheLayout / ParquetEncodedDataReader: replace loop-counter
  mutation with while loops.
- CacheChunk: drop stale @VisibleForTesting; it is part of the cache's
  public read surface for both ORC and Parquet.
- checkstyle/suppressions.xml: suppress VisibilityModifier for
  ParquetEncodedColumnBatch (matches parent EncodedColumnBatch pattern).
- Delete stale checkListColumnSupport from VectorizedParquetRecordReader
  (moved to ParquetRowGroupDecoder).

Style-only elsewhere: pattern-instanceof, split multi-decls, empty-body
'why' comments, header rewraps, paren-pad, restricted-identifier rename
(record() -> recordRanges()).

Verified: mvn checkstyle:check on llap-server (0 violations) and the
existing test suites: TestParquetEncodedDataReader (27/27),
TestLlapRecordReader (2/2), TestParquetRangeBuffers (2/2).

Co-Authored-By: Claude Code <noreply@anthropic.com>
LLAP_IO_ENCODE_ENABLED("hive.llap.io.encode.enabled", true,
"Whether LLAP should try to re-encode and cache data for non-ORC formats. This is used\n" +
"on LLAP Server side to determine if the infrastructure for that is initialized."),
LLAP_IO_PARQUET_NATIVE_ENABLED("hive.llap.io.parquet.native.enabled", false,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be this enabled by default?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could be, tpcds 10TB testing is already done, we might be confident enough to make it true

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's keep false for now, we need to retest after merge

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack, feature is going to be present in the code anyway

private boolean checkOrcSchemaEvolution() {
SchemaEvolution evolution = rp.getSchemaEvolution();
if (evolution == null) {
// No ORC-style schema evolution to validate (e.g. native parquet path);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no orc-style?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you might be looking at an old commit, the current state of PR already has an improved comment:
https://github.com/apache/hive/pull/6793/changes#diff-f00087a16c2c9fed9e0899d7a3718edad0215e33cc41fdd38895945ba45f2517R357-R361

      // Only the ORC pipeline hangs an ORC SchemaEvolution off the ReadPipeline; other formats
      // (native Parquet today) handle column resolution themselves, so there is nothing to
      // validate here.

deniskuzZ and others added 9 commits September 18, 2026 09:15
…LLAP cache

Whoever puts a Parquet column chunk in the LLAP cache decides how the file is
cut into cacheable pieces. Today that is the cache-aware stream under the
vectorized reader; the native reader added later does the same. If the two cut
a file differently, a chunk cached by one is not reusable by the other and the
same bytes end up held twice under different keys.

Define the layout once, before either uses it: the piece sizes, the largest
range a vectored read may ask for, and the pooled buffers those ranges are read
into.

Pieces are powers of two, largest first, so each fills its buddy allocation
exactly. The cache-aware stream cached a chunk as one buffer and left the
allocator to round it up, so a 5 Mb chunk took 8 Mb; over a mix of chunk sizes
that lost about half the cache. Any contiguous run of pieces decomposes into
itself, so a gap left by eviction re-caches on the same boundaries.

The range bound is the larger of 8 Mb -- where reads against S3 stop getting
faster, and where Trino also splits -- and the allocator's maximum, since a
cache buffer is always read whole. The buffer pool is per stream: the pool
never evicts, so one shared across the daemon would pin every executor's peak
on the heap for the daemon's life.
… its own class

VectorizedParquetRecordReader built its VectorizedColumnReader array inline: walk
the requested schema, match each Hive type to a Parquet column, apply the column
defaults a schema-evolved file needs, and decide which nested shapes are readable
at all. That logic depends only on the schemas and the Hive types, not on how the
pages were obtained, but it could not be called from anywhere else.

Move it to ParquetRowGroupDecoder unchanged, so a reader that gets its pages from
somewhere other than a file -- an LLAP cache-backed consumer, next -- builds the
same readers from the same rules rather than growing a second copy that drifts.

No behaviour change: the reader now delegates to the new class and the qtests are
untouched. checkListColumnSupport moves with it, so the Iceberg storage handler's
reference to it follows.
Parquet is cache-only in LLAP IO: the file bytes are cached, but every task
re-runs the vectorized Parquet reader over them. ORC instead caches the column
chunks it decoded and hands the consumer a column-vector batch. This adds the
same three pieces for Parquet -- an encoded data reader, an encoded data
consumer and a column vector producer -- so a Parquet scan is served from the
cache in the same shape as ORC.

The reader reads the footer, prunes row groups against the search argument and
fetches only the projected column chunks, filling the cache with what it read.
The consumer decodes a row group from a cache-backed InputFile, so a second
reader of the same chunk decodes from memory and never touches the filesystem.
Rather than a second set of readers, as ORC needed, the cached pages are served
through parquet's own PageReadStore, so both paths run the same decode: the
row-group logic moves out of VectorizedParquetRecordReader into
ParquetRowGroupDecoder unchanged, and both callers use it.

Off by default behind hive.llap.io.parquet.native.enabled. A projection that
reaches into a nested type falls back to the vectorized Parquet reader, as does
any error in the native path.
… summary (META_HIT, META_MISS)

The summary's META_HIT / META_MISS columns are wired to METADATA_CACHE_HIT
and METADATA_CACHE_MISS, which OrcEncodedDataReader bumps around its file
tail lookups. The Parquet path uses the same FileMetadataCache (LlapIoImpl.
getParquetFooterBuffersFromCache calls getFileMetadata / putFileMetadata
on it) but never bumped the counters, so a Parquet-only run showed zeroes
in those columns.

Bump them from the same site. LlapIoImpl cannot see QueryFragmentCounters
(it lives in llap-server; LlapIo in llap-client), so the impl reports the
outcome through a nullable BooleanRef out-parameter -- the same signalling
pattern storage-api already uses -- and ParquetEncodedDataReader.loadFooter
increments the counter it already holds. The two non-native callers
(VectorizedParquetRecordReader on the vectorized fallback, HiveVectorizedReader
on the Iceberg path) do not have per-fragment counters plumbed and pass null;
their footer traffic continues to go unaccounted, as it did before.

TestParquetEncodedDataReader reads the file twice and asserts the second
read reports one hit and zero misses; only the second read is asserted
because the footer cache is a @BeforeClass singleton and any earlier test
in the class may have populated it.

Co-Authored-By: Claude Code <noreply@anthropic.com>
abstractdog and others added 7 commits September 18, 2026 09:15
Verifies the descriptors and time counters wired into ParquetEncodedDataReader
in the previous commit: SELECTED_ROWGROUPS, TOTAL_IO_TIME_NS, HDFS_TIME_NS,
METADATA_CACHE_HIT/MISS, plus FILE and STRIPES descriptors visible via the
QueryFragmentCounters summary string.

Co-Authored-By: Claude Code <noreply@anthropic.com>
- HiveIcebergStorageHandler: import ParquetRowGroupDecoder so the javadoc
  {@link} can use the short name.
- LlapIoImpl: rename local bufferManagerOrc -> bufferManagerData; the
  buffer manager is now shared with the native Parquet producer, so the
  Orc suffix is stale.
- LlapRecordReader: rename checkOrcSchemaEvolution -> checkSchemaEvolution
  since the method already tolerates producers (like native Parquet) that
  do not expose an ORC-style SchemaEvolution.
- ParquetCachedPageReadStore.chunkBuffers: split the two-per-line locals,
  and rename from/to -> sliceStart/sliceEnd (with chunkStart/chunkEnd and
  bufferStart/bufferEnd for the surrounding bounds).

Co-Authored-By: Claude Code <noreply@anthropic.com>
Three Critical findings on the native Parquet cache path:

- projectedLeaves used fileSchema.getFieldIndex to pick column chunks, but
  BlockMetaData.getColumns() is in flat leaf order. A file schema like
  'group nested {a,b}, x' projecting 'x' would hit nested.b instead of x.
  Map each requested top-level primitive to its single-segment leaf in
  fileSchema.getColumns() instead. Add a regression test.
- putColumn set part.owned only after processing all missing ranges for the
  column, so a mid-run throw from putFileData (e.g. its length-mismatch
  guard) left already-inserted cache buffers looking like raw allocations
  and finishFetch would allocator.deallocate cache-owned memory. Insert
  one range at a time and flip ownership per part.
- ParquetEncodedDataReader.loadFooter builds requestedSchema without the
  row-lineage columns the fallback reader adds via
  RowLineageUtils.getRequestedSchemaWithRowLineageColumns, so with row
  lineage on the native path would silently emit nulls for
  ROW__LINEAGE__ID / LAST__UPDATED__SEQUENCE__NUMBER. Detect that case in
  the producer and fall back, matching the nested-projection fallback.

Co-Authored-By: Claude Code <noreply@anthropic.com>
Fix the mechanical issues flagged on files this PR modifies. Skips the
15 findings inside verbatim extractions from VectorizedParquetRecordReader
(kept behavior-preserving) and the switch/case indentation reports.

Notable non-trivial fixes:
- LlapIo.llapVectorizedParquetReaderForPath: 9 params -> 3, collected
  into a new LlapParquetReadRequest record.
- LlapInputFormat.getRecordReader: extract wrapOrFallback() to bring
  cognitive complexity under threshold.
- ParquetEncodedDataReader: extract planMissRun() from planColumnChunk;
  drop unused 'includes' field/param, unused maxAlloc param, and Part.miss;
  narrow catch(Throwable) -> catch(Exception) at four sites and preserve
  InterruptedException on the thread instead of masking it.
- ParquetCacheLayout / ParquetEncodedDataReader: replace loop-counter
  mutation with while loops.
- CacheChunk: drop stale @VisibleForTesting; it is part of the cache's
  public read surface for both ORC and Parquet.
- checkstyle/suppressions.xml: suppress VisibilityModifier for
  ParquetEncodedColumnBatch (matches parent EncodedColumnBatch pattern).
- Delete stale checkListColumnSupport from VectorizedParquetRecordReader
  (moved to ParquetRowGroupDecoder).

Style-only elsewhere: pattern-instanceof, split multi-decls, empty-body
'why' comments, header rewraps, paren-pad, restricted-identifier rename
(record() -> recordRanges()).

Verified: mvn checkstyle:check on llap-server (0 violations) and the
existing test suites: TestParquetEncodedDataReader (27/27),
TestLlapRecordReader (2/2), TestParquetRangeBuffers (2/2).

Co-Authored-By: Claude Code <noreply@anthropic.com>
- ORC dot-continuation lines: fix 4-space continuation indent
- LlapIoImpl: split combined declarations, remove chained assignments
- ParquetEncodedDataConsumer: NOSONAR on try line for S2093
- ParquetEncodedColumnBatch: make fields private, add accessors
- ParquetEncodedDataReader / TestParquetEncodedDataReader: fix
  '{ '-after-brace whitespace, use accessors
- ParquetCachedPageReadStore: use accessors
- ParquetRowGroupDecoder: reduce parameter counts via
  TimestampConversionOptions record; replace generic
  RuntimeException with UnsupportedOperationException /
  IllegalStateException / InvalidSchemaException; pattern-match
  instanceof; rewrite commented-out MAP schema example; merge
  case labels; retire the moved TODO
- TestParquetRangeBuffers: drop unused throws IOException

Co-Authored-By: Claude Code <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants