This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new a996b8a3c2 [core] Reuse file read targets for merged data evolution 
reads (#10793)
a996b8a3c2 is described below

commit a996b8a3c2889da6527b072405aef1e3e2da0ddd
Author: sanshi <[email protected]>
AuthorDate: Sun Oct 25 10:51:25 2026 +0800

    [core] Reuse file read targets for merged data evolution reads (#10793)
---
 .../paimon/operation/DataEvolutionSplitRead.java   |  5 +-
 .../paimon/table/DataEvolutionFileIndexTest.java   | 69 ++++++++++++++++++++++
 2 files changed, 73 insertions(+), 1 deletion(-)

diff --git 
a/paimon-core/src/main/java/org/apache/paimon/operation/DataEvolutionSplitRead.java
 
b/paimon-core/src/main/java/org/apache/paimon/operation/DataEvolutionSplitRead.java
index ee6f4ab8a3..953f73f935 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/operation/DataEvolutionSplitRead.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/operation/DataEvolutionSplitRead.java
@@ -571,6 +571,7 @@ public class DataEvolutionSplitRead implements 
SplitRead<InternalRow> {
                                     bunch,
                                     dataFilePathFactory,
                                     formatReaderMapping,
+                                    readTarget,
                                     rowRanges,
                                     partialReadRowType,
                                     deletionVector,
@@ -617,6 +618,7 @@ public class DataEvolutionSplitRead implements 
SplitRead<InternalRow> {
                 bunch,
                 dataFilePathFactory,
                 mapping,
+                readTarget,
                 rowRanges,
                 readRowType,
                 deletionVector,
@@ -684,6 +686,7 @@ public class DataEvolutionSplitRead implements 
SplitRead<InternalRow> {
             FieldBunch bunch,
             DataFilePathFactory dataFilePathFactory,
             FormatReaderMapping formatReaderMapping,
+            FileReadTarget readTarget,
             List<Range> rowRanges,
             RowType readRowType,
             @Nullable DeletionVectorWithRange deletionVector,
@@ -695,10 +698,10 @@ public class DataEvolutionSplitRead implements 
SplitRead<InternalRow> {
             return createFileReader(
                     partition,
                     bunch.files().get(0),
-                    dataFilePathFactory,
                     formatReaderMapping,
                     rowRanges,
                     readRowType,
+                    readTarget,
                     deletionVector,
                     groupSelection,
                     metadataCache);
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/table/DataEvolutionFileIndexTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/table/DataEvolutionFileIndexTest.java
index 149ce51310..53724961a1 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/table/DataEvolutionFileIndexTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/table/DataEvolutionFileIndexTest.java
@@ -20,6 +20,7 @@ package org.apache.paimon.table;
 
 import org.apache.paimon.CoreOptions;
 import org.apache.paimon.append.ForceSingleBatchReader;
+import org.apache.paimon.catalog.FileSystemCatalog;
 import org.apache.paimon.catalog.Identifier;
 import org.apache.paimon.data.BinaryRow;
 import org.apache.paimon.data.BinaryString;
@@ -39,7 +40,9 @@ import 
org.apache.paimon.fileindex.bitmap.ApplyBitmapIndexRecordReader;
 import org.apache.paimon.fileindex.bitmap.BitmapFileIndexFactory;
 import org.apache.paimon.fileindex.bloomfilter.BloomFilterFileIndexFactory;
 import org.apache.paimon.fileindex.bsi.BitSliceIndexBitmapFileIndexFactory;
+import org.apache.paimon.fs.FileStatus;
 import org.apache.paimon.fs.Path;
+import org.apache.paimon.fs.local.LocalFileIO;
 import org.apache.paimon.globalindex.IndexedSplit;
 import org.apache.paimon.globalindex.ScanResult;
 import org.apache.paimon.globalindex.sorted.SortedGlobalIndexScanner;
@@ -79,6 +82,7 @@ import org.junit.jupiter.params.provider.ValueSource;
 
 import javax.annotation.Nullable;
 
+import java.io.IOException;
 import java.io.OutputStream;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
@@ -612,6 +616,58 @@ public class DataEvolutionFileIndexTest extends 
DataEvolutionTestBase {
         assertRow(assertSingleRow(readAfterDeletingDataFiles(table, filter, 
null)), 50);
     }
 
+    @Test
+    public void testMergedGroupResolvesRowSidecarOncePerFile() throws 
Exception {
+        RowSidecarStatusCountingFileIO fileIO = new 
RowSidecarStatusCountingFileIO();
+        catalog =
+                new FileSystemCatalog(
+                        fileIO,
+                        new Path(tempPath.toUri().toString(), 
"counting-row-sidecar-status"));
+        catalog.createDatabase(database, true);
+
+        Map<String, String> options = new HashMap<>();
+        options.put(CoreOptions.DATA_EVOLUTION_ROW_SIDECAR_ENABLED.key(), 
"true");
+        FileStoreTable table = createTable("merged_row_sidecar_status", 
options);
+        writeSplitColumns(table, ROW_COUNT, bitmapOptions("f1"), 
Collections.emptyMap());
+
+        fileIO.rowSidecarStatusReads.clear();
+        assertRow(assertSingleRow(readWithFilter(table, equalAnyF1(50))), 50);
+        assertThat(fileIO.rowSidecarStatusReads).hasSize(2);
+        assertThat(fileIO.rowSidecarStatusReads.values()).containsOnly(1);
+    }
+
+    @Test
+    public void testMissingFieldsReaderResolvesRowSidecarOnce() throws 
Exception {
+        RowSidecarStatusCountingFileIO fileIO = new 
RowSidecarStatusCountingFileIO();
+        catalog =
+                new FileSystemCatalog(
+                        fileIO,
+                        new Path(tempPath.toUri().toString(), 
"counting-missing-field-status"));
+        catalog.createDatabase(database, true);
+
+        Map<String, String> options = new HashMap<>();
+        options.put(CoreOptions.DATA_EVOLUTION_ROW_SIDECAR_ENABLED.key(), 
"true");
+        FileStoreTable table = createTable("missing_field_row_sidecar_status", 
options);
+        writeSplitColumns(table, ROW_COUNT, Collections.emptyMap(), 
Collections.emptyMap());
+        catalog.alterTable(
+                identifier(table.name()), SchemaChange.addColumn("f3", 
DataTypes.STRING()), false);
+
+        FileStoreTable latest = getTable(identifier(table.name()));
+        RowType readType = latest.rowType().project("f3");
+        ReadBuilder readBuilder =
+                latest.newReadBuilder()
+                        .withReadType(readType)
+                        .withRowRanges(Collections.singletonList(new 
Range(50L, 50L)));
+        fileIO.rowSidecarStatusReads.clear();
+        List<InternalRow> rows =
+                collect(readBuilder.newRead(), readBuilder.newScan().plan(), 
readType);
+
+        assertThat(rows).hasSize(1);
+        assertThat(rows.get(0).isNullAt(0)).isTrue();
+        assertThat(fileIO.rowSidecarStatusReads).hasSize(1);
+        assertThat(fileIO.rowSidecarStatusReads.values()).containsOnly(1);
+    }
+
     @Test
     public void testSingleFileFinalSelectionChoosesRowSidecar() throws 
Exception {
         Map<String, String> options = bitmapOptions("f1");
@@ -1621,6 +1677,19 @@ public class DataEvolutionFileIndexTest extends 
DataEvolutionTestBase {
         return options;
     }
 
+    private static class RowSidecarStatusCountingFileIO extends LocalFileIO {
+
+        private final Map<String, Integer> rowSidecarStatusReads = new 
HashMap<>();
+
+        @Override
+        public FileStatus getFileStatus(Path path) throws IOException {
+            if (path.getName().endsWith(".row")) {
+                rowSidecarStatusReads.merge(path.getName(), 1, Integer::sum);
+            }
+            return super.getFileStatus(path);
+        }
+    }
+
     @ParameterizedTest
     @ValueSource(strings = {"parquet", "orc"})
     public void testSubMicrosecondTimestampBsiMatchesUnindexed(String format) 
throws Exception {

Reply via email to