[ 
https://issues.apache.org/jira/browse/HIVE-30143?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

László Bodor updated HIVE-30143:
--------------------------------
    Description: 
h2. Background

HIVE-30059 added a native Parquet read path to LLAP IO: it caches column-chunk 
bytes and
decodes them with the same {{VectorizedColumnReader}}s the stock reader uses. 
The decode
step is shared (via {{ParquetRowGroupDecoder}}), but everything leading up to 
it is not.
Each reader independently derives the same per-file facts from the same two 
inputs -- the
Parquet footer and the job conf -- in its own place.

h2. The duplication

||Decision||Stock reader||Native reader||
|requested schema|{{VectorizedParquetRecordReader.initialize}} 
:270-272|{{ParquetEncodedDataReader.readFooter}} :196|
|timestamp / proleptic / legacy-zone flags|{{ParquetRecordReaderBase.getSplit}} 
:160-170|{{ParquetEncodedDataConsumer.initSchema}} :131-144|
|writer timezone|{{VectorizedParquetRecordReader}} 
:266-267|{{ParquetEncodedDataConsumer.initSchema}} :143|
|row groups in the split (first-data-page 
rule)|{{ParquetRecordReaderBase.getSplit}} 
:130-140|{{ParquetEncodedDataReader.selectRowGroups}} :293-303|
|SARG to {{FilterPredicate}}, statistics 
filter|{{ParquetRecordReaderBase.setFilter}} :144, 
:189-205|{{ParquetEncodedDataReader.selectRowGroups}} :304-308|

The two sides agree today. The problem is that they agree by coincidence of 
maintenance
rather than by construction: each of these five decisions has two independent
implementations that must be changed together, and nothing in the build or the 
test suite
fails if only one of them is. A divergence would not throw -- it would return 
wrong values
for some subset of files (a timestamp shifted by a zone, a row group read that 
the
predicate had ruled out), visible only as a query answering differently 
depending on
whether the data happened to be in the cache.

h2. Proposal

One class in {{ql}}, built once per split from inputs both readers already 
hold, whose
fields are exactly those decisions:

{code:java}
/** Everything a Parquet split read decides once from the footer and the job 
conf, shared by both readers. */
public final class ParquetSplitPlan {
  public final MessageType requestedSchema;
  public final List<BlockMetaData> rowGroups; // in-split, statistics-filtered
  public final TimestampConversionOptions conversions;
  public final FilterPredicate predicate; // may be null

  public static ParquetSplitPlan of(JobConf conf, ParquetMetadata footer, long 
splitStart, long splitLength) { ... }
}
{code}

h2. Resulting shape

* {{VectorizedParquetRecordReader.initialize}} and 
{{ParquetEncodedDataReader.readFooter}}
  both reduce to "read the footer, then {{ParquetSplitPlan.of(...)}}".
* {{ParquetEncodedDataConsumer.initSchema}} disappears -- the consumer is 
handed the plan
  instead of re-deriving it, which also removes its lazy {{schemaInitialized}} 
latch.
* {{ParquetRecordReaderBase.toFilterPredicate}} and the five 
{{DataWritableReadSupport}}
  statics stop being called across the module boundary and go back behind the 
plan. The
  public surface between {{ql}} and {{llap-server}} becomes one type rather 
than six
  methods.

h2. Notes

* No behaviour change is intended. The decisions are the same; only the number 
of places
  that make them changes.
* Scoped as a follow-up deliberately: it touches the stock reader, which serves 
every
  Parquet query whether or not LLAP IO is on, so it should not ride along with 
the native
  path's own review.
* A sixth fact, the decimal64 physical variation, was on this list but has 
since converged
  -- both readers now take it from the plan's {{VectorizedRowBatchCtx}}
  ({{VectorizedParquetRecordReader:369}} via {{createVectorizedRowBatch}},
  {{ParquetEncodedDataConsumer:128-129}} via 
{{getRowdataTypePhysicalVariations}}). It is
  listed here only so the history is not confusing.
* Regression net for the refactor already exists: 
{{TestVectorizedColumnReader}},
  {{TestVectorizedListColumnReader}}, {{TestVectorizedMapColumnReader}},
  {{TestVectorizedDictionaryEncodingColumnReader}} (43 tests) cover the stock 
side, and
  {{TestParquetEncodedDataReader}} plus {{TestParquetCachedPageReadStore}} (49) 
the native
  side.

> Parquet: share one per-split read plan between the stock and native LLAP 
> readers
> --------------------------------------------------------------------------------
>
>                 Key: HIVE-30143
>                 URL: https://issues.apache.org/jira/browse/HIVE-30143
>             Project: Hive
>          Issue Type: Improvement
>            Reporter: László Bodor
>            Priority: Major
>
> h2. Background
> HIVE-30059 added a native Parquet read path to LLAP IO: it caches 
> column-chunk bytes and
> decodes them with the same {{VectorizedColumnReader}}s the stock reader uses. 
> The decode
> step is shared (via {{ParquetRowGroupDecoder}}), but everything leading up to 
> it is not.
> Each reader independently derives the same per-file facts from the same two 
> inputs -- the
> Parquet footer and the job conf -- in its own place.
> h2. The duplication
> ||Decision||Stock reader||Native reader||
> |requested schema|{{VectorizedParquetRecordReader.initialize}} 
> :270-272|{{ParquetEncodedDataReader.readFooter}} :196|
> |timestamp / proleptic / legacy-zone 
> flags|{{ParquetRecordReaderBase.getSplit}} 
> :160-170|{{ParquetEncodedDataConsumer.initSchema}} :131-144|
> |writer timezone|{{VectorizedParquetRecordReader}} 
> :266-267|{{ParquetEncodedDataConsumer.initSchema}} :143|
> |row groups in the split (first-data-page 
> rule)|{{ParquetRecordReaderBase.getSplit}} 
> :130-140|{{ParquetEncodedDataReader.selectRowGroups}} :293-303|
> |SARG to {{FilterPredicate}}, statistics 
> filter|{{ParquetRecordReaderBase.setFilter}} :144, 
> :189-205|{{ParquetEncodedDataReader.selectRowGroups}} :304-308|
> The two sides agree today. The problem is that they agree by coincidence of 
> maintenance
> rather than by construction: each of these five decisions has two independent
> implementations that must be changed together, and nothing in the build or 
> the test suite
> fails if only one of them is. A divergence would not throw -- it would return 
> wrong values
> for some subset of files (a timestamp shifted by a zone, a row group read 
> that the
> predicate had ruled out), visible only as a query answering differently 
> depending on
> whether the data happened to be in the cache.
> h2. Proposal
> One class in {{ql}}, built once per split from inputs both readers already 
> hold, whose
> fields are exactly those decisions:
> {code:java}
> /** Everything a Parquet split read decides once from the footer and the job 
> conf, shared by both readers. */
> public final class ParquetSplitPlan {
>   public final MessageType requestedSchema;
>   public final List<BlockMetaData> rowGroups; // in-split, statistics-filtered
>   public final TimestampConversionOptions conversions;
>   public final FilterPredicate predicate; // may be null
>   public static ParquetSplitPlan of(JobConf conf, ParquetMetadata footer, 
> long splitStart, long splitLength) { ... }
> }
> {code}
> h2. Resulting shape
> * {{VectorizedParquetRecordReader.initialize}} and 
> {{ParquetEncodedDataReader.readFooter}}
>   both reduce to "read the footer, then {{ParquetSplitPlan.of(...)}}".
> * {{ParquetEncodedDataConsumer.initSchema}} disappears -- the consumer is 
> handed the plan
>   instead of re-deriving it, which also removes its lazy 
> {{schemaInitialized}} latch.
> * {{ParquetRecordReaderBase.toFilterPredicate}} and the five 
> {{DataWritableReadSupport}}
>   statics stop being called across the module boundary and go back behind the 
> plan. The
>   public surface between {{ql}} and {{llap-server}} becomes one type rather 
> than six
>   methods.
> h2. Notes
> * No behaviour change is intended. The decisions are the same; only the 
> number of places
>   that make them changes.
> * Scoped as a follow-up deliberately: it touches the stock reader, which 
> serves every
>   Parquet query whether or not LLAP IO is on, so it should not ride along 
> with the native
>   path's own review.
> * A sixth fact, the decimal64 physical variation, was on this list but has 
> since converged
>   -- both readers now take it from the plan's {{VectorizedRowBatchCtx}}
>   ({{VectorizedParquetRecordReader:369}} via {{createVectorizedRowBatch}},
>   {{ParquetEncodedDataConsumer:128-129}} via 
> {{getRowdataTypePhysicalVariations}}). It is
>   listed here only so the history is not confusing.
> * Regression net for the refactor already exists: 
> {{TestVectorizedColumnReader}},
>   {{TestVectorizedListColumnReader}}, {{TestVectorizedMapColumnReader}},
>   {{TestVectorizedDictionaryEncodingColumnReader}} (43 tests) cover the stock 
> side, and
>   {{TestParquetEncodedDataReader}} plus {{TestParquetCachedPageReadStore}} 
> (49) the native
>   side.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to