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 dd1b91d57d [core] Avoid repeated sorted-index source lookups (#9187)
dd1b91d57d is described below

commit dd1b91d57d9ef5d519c956d511f826e1dacd520d
Author: QuakeWang <[email protected]>
AuthorDate: Thu Aug 13 22:01:02 2026 +0800

    [core] Avoid repeated sorted-index source lookups (#9187)
---
 .../table/source/PrimaryKeySortedIndexScan.java    | 55 ++++++++++++++--------
 .../source/PrimaryKeySortedIndexScanTest.java      | 27 +++++++----
 2 files changed, 53 insertions(+), 29 deletions(-)

diff --git 
a/paimon-core/src/main/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScan.java
 
b/paimon-core/src/main/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScan.java
index 7bc04f5d6f..cb03736b7b 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScan.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScan.java
@@ -54,6 +54,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
@@ -274,8 +275,7 @@ public final class PrimaryKeySortedIndexScan {
                                                                         
totalRowCount));
                                         sharedReaders.put(indexGroup, reader);
                                     }
-                                    return Collections.singletonList(
-                                            fileLocalReader(file, group.get(), 
reader));
+                                    return 
Collections.singletonList(fileLocalReader(file, reader));
                                 });
                 Optional<GlobalIndexResult> result;
                 try {
@@ -300,23 +300,20 @@ public final class PrimaryKeySortedIndexScan {
     }
 
     private static GlobalIndexReader fileLocalReader(
-            FilePlan file, PkSortedIndexGroup group, SharedGlobalIndexReader 
reader) {
-        List<PrimaryKeyIndexSourceFile> sourceFiles = group.sourceFiles();
-        PrimaryKeyIndexSourceFile target =
-                new PrimaryKeyIndexSourceFile(
-                        file.dataFile().fileName(), 
file.dataFile().rowCount());
-        int sourceIndex = -1;
-        for (int i = 0; i < sourceFiles.size(); i++) {
-            if (sourceFiles.get(i).equals(target)) {
-                sourceIndex = i;
-                break;
-            }
-        }
+            FilePlan file, SharedGlobalIndexReader reader) {
+        DataFileMeta dataFile = file.dataFile();
+        SourceLocation sourceLocation = 
reader.sourceLocations.get(dataFile.fileName());
         checkArgument(
-                sourceIndex >= 0,
+                sourceLocation != null,
                 "Data file %s is not covered by its sorted-index source 
group.",
-                file.dataFile().fileName());
-        return new FileLocalGlobalIndexReader(reader, sourceIndex);
+                dataFile.fileName());
+        checkArgument(
+                dataFile.rowCount() == sourceLocation.rowCount,
+                "Data file %s row count %s does not match sorted-index source 
row count %s.",
+                dataFile.fileName(),
+                dataFile.rowCount(),
+                sourceLocation.rowCount);
+        return new FileLocalGlobalIndexReader(reader, 
sourceLocation.sourceIndex);
     }
 
     private static long totalRowCount(List<PrimaryKeyIndexSourceFile> 
sourceFiles) {
@@ -333,6 +330,17 @@ public final class PrimaryKeySortedIndexScan {
         }
     }
 
+    private static final class SourceLocation {
+
+        private final long rowCount;
+        private final int sourceIndex;
+
+        private SourceLocation(long rowCount, int sourceIndex) {
+            this.rowCount = rowCount;
+            this.sourceIndex = sourceIndex;
+        }
+    }
+
     /** Shares one source-group reader and its group-global query results 
across source files. */
     private static final class SharedGlobalIndexReader implements 
GlobalIndexReader {
 
@@ -342,6 +350,7 @@ public final class PrimaryKeySortedIndexScan {
                         CompletableFuture<Optional<GlobalIndexResult>>,
                         CompletableFuture<List<Optional<GlobalIndexResult>>>>
                 localizedResults;
+        private final Map<String, SourceLocation> sourceLocations;
         private final long[] sourceOffsets;
 
         private GlobalIndexReader reader;
@@ -353,10 +362,18 @@ public final class PrimaryKeySortedIndexScan {
             this.readerFactory = readerFactory;
             this.results = new ConcurrentHashMap<>();
             this.localizedResults = new ConcurrentHashMap<>();
+            this.sourceLocations = new HashMap<>();
             this.sourceOffsets = new long[sourceFiles.size() + 1];
             for (int i = 0; i < sourceFiles.size(); i++) {
-                sourceOffsets[i + 1] =
-                        Math.addExact(sourceOffsets[i], 
sourceFiles.get(i).rowCount());
+                PrimaryKeyIndexSourceFile sourceFile = sourceFiles.get(i);
+                checkArgument(
+                        sourceLocations.put(
+                                        sourceFile.fileName(),
+                                        new 
SourceLocation(sourceFile.rowCount(), i))
+                                == null,
+                        "Duplicate sorted-index source file %s.",
+                        sourceFile.fileName());
+                sourceOffsets[i + 1] = Math.addExact(sourceOffsets[i], 
sourceFile.rowCount());
             }
         }
 
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScanTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScanTest.java
index c704589af7..b800fb1c61 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScanTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScanTest.java
@@ -205,7 +205,8 @@ class PrimaryKeySortedIndexScanTest {
     void testReadMergedSourceGroupInFileLocalPositions() throws IOException {
         DataFileMeta first = dataFile("data-1", 2);
         DataFileMeta second = dataFile("data-2", 3);
-        DataSplit split = dataSplit(11, 0, true, second, first);
+        DataFileMeta third = dataFile("data-3", 4);
+        DataSplit split = dataSplit(11, 0, true, third, first, second);
         PrimaryKeyIndexDefinition definition =
                 definition(
                         7,
@@ -216,10 +217,11 @@ class PrimaryKeySortedIndexScanTest {
                         "btree-merged",
                         Arrays.asList(
                                 new PrimaryKeyIndexSourceFile("data-1", 2),
-                                new PrimaryKeyIndexSourceFile("data-2", 3)),
+                                new PrimaryKeyIndexSourceFile("data-2", 3),
+                                new PrimaryKeyIndexSourceFile("data-3", 4)),
                         "btree",
                         7,
-                        5);
+                        9);
         PrimaryKeySortedIndexScan.Plan plan =
                 PrimaryKeySortedIndexScan.plan(
                         11,
@@ -232,8 +234,10 @@ class PrimaryKeySortedIndexScanTest {
         AtomicInteger queries = new AtomicInteger();
         CountingRoaringNavigableMap64 groupPositions = new 
CountingRoaringNavigableMap64();
         groupPositions.add(1);
-        groupPositions.add(3);
+        groupPositions.add(2);
         groupPositions.add(4);
+        groupPositions.add(6);
+        groupPositions.add(7);
         GlobalIndexReader reader = mock(GlobalIndexReader.class);
         when(reader.visitEqual(any(), eq(42)))
                 .thenAnswer(
@@ -251,23 +255,26 @@ class PrimaryKeySortedIndexScanTest {
                         (ignoredFile, ignoredDefinition, payloads, 
totalRowCount) -> {
                             readersCreated.incrementAndGet();
                             
assertThat(payloads).containsExactly(mergedPayload);
-                            assertThat(totalRowCount).isEqualTo(5);
+                            assertThat(totalRowCount).isEqualTo(9);
                             return reader;
                         });
         PrimaryKeySortedIndexResult result = new 
PrimaryKeySortedIndexResult(evaluated);
 
         assertThat(readersCreated).hasValue(1);
         assertThat(queries).hasValue(1);
-        assertThat(groupPositions.iteratedPositions()).isEqualTo(3);
+        assertThat(groupPositions.iteratedPositions()).isEqualTo(5);
         verify(reader, times(1)).close();
-        assertThat(result.splits()).hasSize(2);
+        assertThat(result.splits()).hasSize(3);
         assertThat(result.splits()).allMatch(IndexedSplit.class::isInstance);
-        IndexedSplit secondSplit = (IndexedSplit) result.splits().get(0);
-        
assertThat(secondSplit.dataSplit().dataFiles()).containsExactly(second);
-        assertThat(secondSplit.rowRanges()).containsExactly(new Range(1, 2));
+        IndexedSplit thirdSplit = (IndexedSplit) result.splits().get(0);
+        assertThat(thirdSplit.dataSplit().dataFiles()).containsExactly(third);
+        assertThat(thirdSplit.rowRanges()).containsExactly(new Range(1, 2));
         IndexedSplit firstSplit = (IndexedSplit) result.splits().get(1);
         assertThat(firstSplit.dataSplit().dataFiles()).containsExactly(first);
         assertThat(firstSplit.rowRanges()).containsExactly(new Range(1, 1));
+        IndexedSplit secondSplit = (IndexedSplit) result.splits().get(2);
+        
assertThat(secondSplit.dataSplit().dataFiles()).containsExactly(second);
+        assertThat(secondSplit.rowRanges()).containsExactly(new Range(0, 0), 
new Range(2, 2));
     }
 
     @Test

Reply via email to