cshuo commented on code in PR #19118:
URL: https://github.com/apache/hudi/pull/19118#discussion_r3526199482


##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/io/cdc/HoodieNativeCDCFileWriter.java:
##########
@@ -120,14 +131,16 @@ void close() throws IOException {
     }
   }
 
+  @SuppressWarnings("unchecked")
   private void ensureCDCWriter() throws IOException {
     if (cdcWriter != null && cdcWriter.canWrite()) {
       return;
     }
     close();
     HoodieLogFile cdcLogFile = createNativeCDCLogFile();
-    cdcWriter = HoodieFileWriterFactory.getFileWriter(
+    cdcWriter = (HoodieFileWriter<T>) HoodieFileWriterFactory.getFileWriter(
         commitTime, cdcLogFile.getPath(), storage, config, cdcSchema, 
taskContextSupplier, recordType);
+    
cdcWriter.addFooterMetadata(NativeLogFooterMetadata.toFooterMetadata(cdcDataBlockHeader));

Review Comment:
   rename `cdcDataBlockHeader`



##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/util/CommonClientUtils.java:
##########
@@ -120,6 +131,41 @@ public static HoodieLogBlock.HoodieLogBlockType 
getLogBlockType(HoodieWriteConfi
     }
   }
 
+  /**
+   * Whether log blocks should be written in the native (v2) log format 
(standalone native
+   * files written via {@code HoodieNativeLogFormatWriter}) instead of the 
legacy inline
+   * log format. The native format is the default for write version &gt;= 
{@link HoodieTableVersion#TEN},
+   * except for Lance base files.
+   *
+   * <p>This decision is keyed on the effective write version (i.e. {@code 
HoodieWriteConfig#getWriteVersion()})
+   * and the effective base file format, consistent with how the inline log 
block layout is
+   * selected, so that the on-disk format follows what the writer is targeting 
during
+   * upgrade/downgrade windows. Lance remains on the legacy inline log format 
until native Lance log
+   * support is complete.
+   *
+   * @param writeConfig the writer configuration.
+   * @param tableConfig the persisted table configuration.
+   */
+  public static boolean shouldWriteNativeLogs(HoodieWriteConfig writeConfig, 
HoodieTableConfig tableConfig) {

Review Comment:
   todo: issue, remove table config.



##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/io/cdc/HoodieCDCLogWriterFactory.java:
##########
@@ -79,7 +80,7 @@ public static <T, I, K, O> HoodieCDCLogWriter<IndexedRecord> 
createAvroCDCLogWri
         IOUtils.getMaxMemoryPerPartitionMerge(taskContextSupplier, config));
   }
 
-  public static boolean shouldWriteNativeCDCLogs(HoodieTableConfig 
tableConfig) {
-    return tableConfig.isLSMTreeStorageLayout();
+  public static boolean shouldWriteNativeCDCLogs(HoodieWriteConfig 
writeConfig, HoodieTableConfig tableConfig) {

Review Comment:
   remove this method.



##########
hudi-client/hudi-flink-client/src/main/java/org/apache/hudi/util/WriteStatMerger.java:
##########
@@ -125,18 +125,18 @@ private static HoodieWriteStat.RuntimeStats 
getMergedRuntimeStats(
     return runtimeStats;
   }
 
-  private static Map<String, Long> getMergedCdcStats(Map<String, Long> 
cdcStats1, Map<String, Long> cdcStats2) {
-    final Map<String, Long> cdcStats;
-    if (cdcStats1 != null && cdcStats2 != null) {
-      cdcStats = new HashMap<>();
-      cdcStats.putAll(cdcStats1);
-      cdcStats.putAll(cdcStats2);
-    } else if (cdcStats1 == null) {
-      cdcStats = cdcStats2;
+  private static Map<String, Long> getMergedStringLongMap(Map<String, Long> 
map1, Map<String, Long> map2) {

Review Comment:
   revert.



##########
hudi-client/hudi-spark-client/src/main/scala/org/apache/hudi/SparkFileFormatInternalRowReaderContext.scala:
##########
@@ -160,10 +160,31 @@ class 
SparkFileFormatInternalRowReaderContext(baseFileReader: SparkColumnarFileR
     val (readSchema, readFilters) = 
getSchemaAndFiltersForRead(parquetReadStructType, hasRowIndexField)
     if (FSUtils.isLogFile(filePath)) {
       // NOTE: now only primary key based filtering is supported for log files
+      // Position-based merging pairs log records with the RECORD_POSITIONS 
bitmap by index (see
+      // PositionBasedFileGroupRecordBuffer), which requires the record stream 
to contain every
+      // record of the block. Pushing filters into the scan can physically 
drop records (e.g. with
+      // parquet record-level filtering) and misalign that pairing, so push no 
filters in that case.
+      val logReadFilters = if (getShouldMergeUseRecordPosition) 
Seq.empty[Filter] else readFilters
       // Variant alignment happens later via getLogBlockRecordProjection in 
the merge buffer.
-      new HoodieSparkFileReaderFactory(storage).newParquetFileReader(filePath)
-        
.asInstanceOf[HoodieSparkParquetReader].getUnsafeRowIterator(requiredSchema, 
readFilters.asJava)
-        .asInstanceOf[ClosableIterator[InternalRow]]
+      // Log files reach this method either as an inline parquet data block or 
as a native log file.
+      // Inline paths do not carry the parquet extension, so resolve them by 
the log block contract.
+      val fileFormat = if 
(FSUtils.matchNativeLogFile(filePath.getName).isEmpty) {

Review Comment:
   add isInlineLogFile



##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/metadata/HoodieMetadataWriteUtils.java:
##########
@@ -611,7 +611,9 @@ public static Set<String> 
getFilesToFetchColumnStats(List<HoodieWriteStat> parti
         .flatMap(fileSlice -> Stream.concat(
             
Stream.of(fileSlice.getBaseFile().map(HoodieBaseFile::getFileName).orElse(null)),
             fileSlice.getLogFiles().map(HoodieLogFile::getFileName)))
-        .filter(e -> Objects.nonNull(e) && !filesWithColumnStats.contains(e) 
&& !fileGroupIdsToReplace.contains(e))
+        .filter(e -> Objects.nonNull(e)

Review Comment:
   revert.



##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/io/HoodieAppendHandle.java:
##########
@@ -206,7 +208,7 @@ public List<WriteStatus> close() {
 
       if (isSecondaryIndexStatsStreamingWritesEnabled && !statuses.isEmpty()) {
         SecondaryIndexStreamingTracker.trackSecondaryIndexStats(partitionPath, 
fileId, getReadFileSlice(),
-            statuses.stream().map(status -> 
status.getStat().getPath()).collect(Collectors.toList()),
+            
SecondaryIndexStreamingTracker.collectNewLogFilesForSecondaryIndexStats(statuses),

Review Comment:
   revert.



##########
hudi-client/hudi-client-common/src/test/java/org/apache/hudi/io/TestSecondaryIndexStreamingTracker.java:
##########
@@ -366,6 +367,35 @@ void testTrackSecondaryIndexStats_RecordKeyExtraction() {
     });
   }
 
+  @Test

Review Comment:
   remove



##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/io/SecondaryIndexStreamingTracker.java:
##########
@@ -127,6 +132,25 @@ static void trackSecondaryIndexStats(String partitionPath, 
String fileId, Option
     });
   }
 
+  /**
+   * Collects the paths of the new log files written by an append handle, so 
that they can be added
+   * to the file slice when generating secondary index stats.
+   *
+   * @param statuses Write statuses produced by the append handle
+   * @return De-duplicated list of new log file paths in insertion order
+   */
+  @VisibleForTesting
+  static List<String> 
collectNewLogFilesForSecondaryIndexStats(List<WriteStatus> statuses) {

Review Comment:
   remove.



##########
hudi-common/src/main/java/org/apache/hudi/common/table/log/block/HoodieNativeDeleteBlock.java:
##########
@@ -20,24 +20,30 @@
 package org.apache.hudi.common.table.log.block;
 
 import org.apache.hudi.common.engine.HoodieReaderContext;
-import org.apache.hudi.common.engine.RecordContext;
 import org.apache.hudi.common.fs.FSUtils;
 import org.apache.hudi.common.model.DeleteRecord;
+import org.apache.hudi.common.model.HoodieFileFormat;
 import org.apache.hudi.common.model.HoodieLogFile;
 import org.apache.hudi.common.model.HoodieRecord;
 import org.apache.hudi.common.schema.HoodieSchema;
+import org.apache.hudi.common.schema.HoodieSchemas;
 import org.apache.hudi.common.table.read.BufferedRecord;
 import org.apache.hudi.common.table.read.BufferedRecords;
 import org.apache.hudi.common.util.Option;
 import org.apache.hudi.common.util.collection.ClosableIterator;
 import org.apache.hudi.exception.HoodieIOException;
-import org.apache.hudi.exception.HoodieNotSupportedException;
+import org.apache.hudi.io.storage.HoodieFileReader;
+import org.apache.hudi.io.storage.HoodieIOFactory;
 import org.apache.hudi.storage.HoodieStorage;
+import org.apache.hudi.storage.StoragePath;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
+
+import static 
org.apache.hudi.common.util.ConfigUtils.DEFAULT_HUDI_CONFIG_FOR_READER;

Review Comment:
   rename, HoodieNativeLogDeleteBlock



##########
hudi-common/src/main/java/org/apache/hudi/common/table/log/block/HoodieNativeDeleteBlock.java:
##########
@@ -46,51 +52,76 @@ public class HoodieNativeDeleteBlock extends 
HoodieDeleteBlock {
 
   private final HoodieStorage storage;
   private final HoodieLogFile logFile;
-  private final HoodieReaderContext<?> readerContext;
   private final HoodieSchema deleteLogSchema;
   private final List<String> orderingFieldNames;
+  private final String partitionPath;
+  private final Properties props;
+  private DeleteRecord[] recordsToDelete;
   private List<BufferedRecord<?>> bufferedRecordsToDelete;
 
   public HoodieNativeDeleteBlock(HoodieStorage storage,
                                  HoodieLogFile logFile,
-                                 HoodieReaderContext<?> readerContext,
-                                 HoodieSchema deleteLogSchema,
                                  List<String> orderingFieldNames,
+                                 String partitionPath,
+                                 Properties props,
                                  Map<HeaderMetadataType, String> header,
                                  Map<FooterMetadataType, String> footer) {
     super(Option.empty(), null, true, getContentLocation(storage, logFile), 
header, footer);
     this.storage = storage;
     this.logFile = logFile;
-    this.readerContext = readerContext;
-    this.deleteLogSchema = deleteLogSchema;
+    this.deleteLogSchema = 
HoodieSchemas.createDeleteLogSchema(getSchemaFromHeader(), orderingFieldNames);
     this.orderingFieldNames = orderingFieldNames;
+    this.partitionPath = partitionPath;
+    this.props = props == null ? new Properties() : props;
   }
 
   @Override
   public DeleteRecord[] getRecordsToDelete() {
-    throw new HoodieNotSupportedException("Native delete log files do not 
support the legacy DeleteRecord[] API. "
-        + "Use getRecordsToDelete(RecordContext) instead. Log file: " + 
logFile);
+    if (recordsToDelete == null) {
+      recordsToDelete = readRecordsToDelete();

Review Comment:
   todo: add issue, refactor.



##########
hudi-flink-datasource/hudi-flink/src/main/java/org/apache/hudi/table/format/FlinkRowDataReaderContext.java:
##########
@@ -98,24 +101,39 @@ public ClosableIterator<RowData> getFileRecordIterator(
       HoodieSchema dataSchema,
       HoodieSchema requiredSchema,
       HoodieStorage storage) throws IOException {
-    boolean isLogFile = FSUtils.isLogFile(filePath);
     // disable schema evolution in fileReader if it's log file, since schema 
evolution for log file is handled in `FileGroupRecordBuffer`
-    InternalSchemaManager schemaManager = isLogFile ? 
InternalSchemaManager.DISABLED : internalSchemaManager.get();
+    InternalSchemaManager schemaManager = FSUtils.isLogFile(filePath) ? 
InternalSchemaManager.DISABLED : internalSchemaManager.get();
 
     // Log files only reach this method for parquet data blocks; base files 
are resolved by their extension.
     // Format-specific handling lives in the readers themselves, so this 
method stays format-agnostic.
-    HoodieFileFormat format = isLogFile ? HoodieFileFormat.PARQUET : 
HoodieFileFormat.fromFileExtension(filePath.getFileExtension());
+    boolean isInlineLogFile = FSUtils.isLogFile(filePath) && 
FSUtils.matchNativeLogFile(filePath.getName()).isEmpty();
+    HoodieFileFormat format = isInlineLogFile ? HoodieFileFormat.PARQUET : 
HoodieFileFormat.fromFileExtension(filePath.getFileExtension());
     HoodieRowDataFileReader reader = (HoodieRowDataFileReader) 
HoodieIOFactory.getIOFactory(storage)
         .getReaderFactory(HoodieRecord.HoodieRecordType.FLINK)
         .getFileReader(tableConfig, filePath, format, Option.empty());
     try {
-      return reader.getRowDataIterator(dataSchema, requiredSchema, 
schemaManager, getSafePredicates(requiredSchema));
+      ClosableIterator<RowData> rowDataIterator =
+          reader.getRowDataIterator(dataSchema, requiredSchema, schemaManager, 
getSafePredicates(requiredSchema));
+      return resolveRowKind(rowDataIterator, requiredSchema);
     } catch (Throwable e) {
       reader.close();
       throw new HoodieException("Failed to get record iterator for: " + 
filePath, e);
     }
   }
 
+  private ClosableIterator<RowData> resolveRowKind(ClosableIterator<RowData> 
rowDataIterator, HoodieSchema requiredSchema) {

Review Comment:
   todo: inline parquet data block bug.



##########
hudi-common/src/main/java/org/apache/hudi/common/table/log/block/HoodieNativeDataBlock.java:
##########
@@ -95,11 +94,7 @@ protected <T> ClosableIterator<T> 
readRecordsFromBlockPayload(HoodieReaderContex
 
   @Override
   protected <T> ClosableIterator<T> lookupEngineRecords(HoodieReaderContext<T> 
readerContext, List<String> keys, boolean fullKey) throws IOException {
-    return FilteringEngineRecordIterator.getInstance(
-        readRecordsFromBlockPayload(readerContext),
-        new HashSet<>(keys),
-        fullKey,
-        record -> 
Option.ofNullable(readerContext.getRecordContext().getRecordKey(record, 
readerSchema)));
+    return readerContext.lookupRecords(logFile.getPath(), fileFormat, 
readerSchema, storage, keys, fullKey);

Review Comment:
   rename, HoodieNativeLogDataBlock



-- 
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]

Reply via email to