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 fcbe301971 [core] Preserve reader errors for compacted changelog files 
(#9995)
fcbe301971 is described below

commit fcbe30197174e3849973769500c487a3706d85ba
Author: LsomeYeah <[email protected]>
AuthorDate: Sun Sep 20 16:16:30 2026 +0800

    [core] Preserve reader errors for compacted changelog files (#9995)
---
 .../org/apache/paimon/io/DataFileRecordReader.java |  10 +-
 .../CompactedChangelogFormatReaderFactoryTest.java | 117 +++++++++++++++++++++
 2 files changed, 124 insertions(+), 3 deletions(-)

diff --git 
a/paimon-core/src/main/java/org/apache/paimon/io/DataFileRecordReader.java 
b/paimon-core/src/main/java/org/apache/paimon/io/DataFileRecordReader.java
index 70650fbf4b..4569926dd4 100644
--- a/paimon-core/src/main/java/org/apache/paimon/io/DataFileRecordReader.java
+++ b/paimon-core/src/main/java/org/apache/paimon/io/DataFileRecordReader.java
@@ -32,6 +32,7 @@ import org.apache.paimon.reader.FileRecordIterator;
 import org.apache.paimon.reader.FileRecordReader;
 import org.apache.paimon.table.SpecialFields;
 import org.apache.paimon.types.RowType;
+import org.apache.paimon.utils.CompactedChangelogPathResolver;
 import org.apache.paimon.utils.FileUtils;
 import org.apache.paimon.utils.ProjectedRow;
 import org.apache.paimon.utils.RoaringBitmap32;
@@ -128,15 +129,18 @@ public class DataFileRecordReader implements 
FileRecordReader<InternalRow> {
         try {
             return readerFactory.createReader(context);
         } catch (Exception e) {
-            boolean exists = context.fileIO().exists(context.filePath());
+            Path actualPath =
+                    
CompactedChangelogPathResolver.resolveCompactedChangelogPath(
+                            context.filePath());
+            boolean exists = context.fileIO().exists(actualPath);
             if (!exists) {
                 if (ignoreLostFiles) {
                     LOG.warn(
                             "Failed to create FileRecordReader for file: {}, 
file lost",
-                            context.filePath());
+                            actualPath);
                     return null;
                 } else {
-                    throw 
FileUtils.newFileNotFoundException(context.filePath());
+                    throw FileUtils.newFileNotFoundException(actualPath);
                 }
             } else {
                 if (ignoreCorruptException(e, ignoreCorruptFiles)) {
diff --git 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/compact/changelog/format/CompactedChangelogFormatReaderFactoryTest.java
 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/compact/changelog/format/CompactedChangelogFormatReaderFactoryTest.java
new file mode 100644
index 0000000000..1b59758fb3
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/compact/changelog/format/CompactedChangelogFormatReaderFactoryTest.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.flink.compact.changelog.format;
+
+import org.apache.paimon.format.FormatReaderFactory;
+import org.apache.paimon.fs.FileIO;
+import org.apache.paimon.fs.Path;
+import org.apache.paimon.fs.PositionOutputStream;
+import org.apache.paimon.fs.local.LocalFileIO;
+import org.apache.paimon.io.DataFileRecordReader;
+import org.apache.paimon.types.DataTypes;
+import org.apache.paimon.types.RowType;
+import org.apache.paimon.utils.RoaringBitmap32;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import javax.annotation.Nullable;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Collections;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/** Tests for {@link CompactedChangelogFormatReaderFactory}. */
+class CompactedChangelogFormatReaderFactoryTest {
+
+    @TempDir java.nio.file.Path tempDir;
+
+    @Test
+    void testReaderCreationExceptionIsNotReportedAsMissingFile() throws 
Exception {
+        FileIO fileIO = LocalFileIO.create();
+        Path partitionPath = new Path(tempDir.toUri());
+        Path realPath =
+                new Path(partitionPath, 
"bucket-74/compacted-changelog-test$74-1.cc-parquet");
+        fileIO.mkdirs(realPath.getParent());
+        try (PositionOutputStream out = fileIO.newOutputStream(realPath, 
false)) {
+            out.write(new byte[] {1, 2});
+        }
+
+        Path virtualPath =
+                new Path(partitionPath, 
"bucket-75/compacted-changelog-test$74-1-1-1.cc-parquet");
+        FormatReaderFactory failingReaderFactory =
+                context -> {
+                    
assertThat(context.fileIO().exists(context.filePath())).isTrue();
+                    throw new IOException("simulated transient read failure");
+                };
+
+        FormatReaderFactory.Context context = context(fileIO, virtualPath);
+        CompactedChangelogFormatReaderFactory readerFactory =
+                new 
CompactedChangelogFormatReaderFactory(failingReaderFactory);
+
+        assertThat(fileIO.exists(realPath)).isTrue();
+        assertThat(fileIO.exists(virtualPath)).isFalse();
+        assertThatThrownBy(
+                        () ->
+                                new DataFileRecordReader(
+                                        RowType.of(DataTypes.INT()),
+                                        readerFactory,
+                                        context,
+                                        false,
+                                        false,
+                                        null,
+                                        null,
+                                        null,
+                                        false,
+                                        null,
+                                        0,
+                                        Collections.emptyMap()))
+                .isInstanceOf(IOException.class)
+                .isNotInstanceOf(FileNotFoundException.class)
+                .hasRootCauseMessage("simulated transient read failure");
+    }
+
+    private static FormatReaderFactory.Context context(FileIO fileIO, Path 
filePath) {
+        return new FormatReaderFactory.Context() {
+            @Override
+            public FileIO fileIO() {
+                return fileIO;
+            }
+
+            @Override
+            public Path filePath() {
+                return filePath;
+            }
+
+            @Override
+            public long fileSize() {
+                return 1;
+            }
+
+            @Nullable
+            @Override
+            public RoaringBitmap32 selection() {
+                return null;
+            }
+        };
+    }
+}

Reply via email to