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 50f8951f8d [common] Close the file-index stream when reader 
construction fails (#9636)
50f8951f8d is described below

commit 50f8951f8dfd89ef48a181d106e3486633a75eb2
Author: YangJie <[email protected]>
AuthorDate: Thu Sep 10 02:53:36 2026 -0400

    [common] Close the file-index stream when reader construction fails (#9636)
---
 .../apache/paimon/fileindex/FileIndexFormat.java   |  5 ++++-
 .../paimon/fileindex/FileIndexPredicate.java       | 12 +++--------
 .../fileindex/FileIndexFormatFormatTest.java       | 25 ++++++++++++++++++++++
 .../fileindex/FileIndexPredicateCloseTest.java     |  3 ++-
 4 files changed, 34 insertions(+), 11 deletions(-)

diff --git 
a/paimon-common/src/main/java/org/apache/paimon/fileindex/FileIndexFormat.java 
b/paimon-common/src/main/java/org/apache/paimon/fileindex/FileIndexFormat.java
index e10a95c50c..c2d27ec9f0 100644
--- 
a/paimon-common/src/main/java/org/apache/paimon/fileindex/FileIndexFormat.java
+++ 
b/paimon-common/src/main/java/org/apache/paimon/fileindex/FileIndexFormat.java
@@ -318,7 +318,10 @@ public final class FileIndexFormat {
                         }
                     }
                 }
-            } catch (IOException e) {
+            } catch (IOException | RuntimeException e) {
+                // Callers wrap the constructor in try-with-resources on the 
stream,
+                // but a throwing constructor never assigns the resource, so 
both
+                // checked and unchecked validation failures must close here.
                 IOUtils.closeQuietly(seekableInputStream);
                 throw new RuntimeException(
                         "Exception happens while construct file index 
reader.", e);
diff --git 
a/paimon-common/src/main/java/org/apache/paimon/fileindex/FileIndexPredicate.java
 
b/paimon-common/src/main/java/org/apache/paimon/fileindex/FileIndexPredicate.java
index 829b2ecd9f..82d14cf7ca 100644
--- 
a/paimon-common/src/main/java/org/apache/paimon/fileindex/FileIndexPredicate.java
+++ 
b/paimon-common/src/main/java/org/apache/paimon/fileindex/FileIndexPredicate.java
@@ -32,7 +32,6 @@ import org.apache.paimon.predicate.PredicateVisitor;
 import org.apache.paimon.predicate.SortValue;
 import org.apache.paimon.predicate.TopN;
 import org.apache.paimon.types.RowType;
-import org.apache.paimon.utils.IOUtils;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -69,14 +68,9 @@ public class FileIndexPredicate implements Closeable {
     }
 
     public FileIndexPredicate(SeekableInputStream inputStream, RowType 
fileRowType) {
-        try {
-            this.reader = FileIndexFormat.createReader(inputStream, 
fileRowType);
-        } catch (RuntimeException e) {
-            // nothing else holds a reference to inputStream yet, so this is 
the only chance to
-            // release it: createReader rejects a file whose magic or version 
does not match.
-            IOUtils.closeQuietly(inputStream);
-            throw e;
-        }
+        // createReader itself closes the stream when the header fails 
validation, so
+        // there is no stream to release here anymore.
+        this.reader = FileIndexFormat.createReader(inputStream, fileRowType);
     }
 
     public FileIndexResult evaluate(@Nullable Predicate predicate) {
diff --git 
a/paimon-common/src/test/java/org/apache/paimon/fileindex/FileIndexFormatFormatTest.java
 
b/paimon-common/src/test/java/org/apache/paimon/fileindex/FileIndexFormatFormatTest.java
index 0f5f6e299e..c6ce94c89a 100644
--- 
a/paimon-common/src/test/java/org/apache/paimon/fileindex/FileIndexFormatFormatTest.java
+++ 
b/paimon-common/src/test/java/org/apache/paimon/fileindex/FileIndexFormatFormatTest.java
@@ -20,6 +20,7 @@ package org.apache.paimon.fileindex;
 
 import org.apache.paimon.fileindex.empty.EmptyFileIndexReader;
 import org.apache.paimon.fs.ByteArraySeekableStream;
+import org.apache.paimon.fs.SeekableInputStream;
 import org.apache.paimon.types.DataTypes;
 import org.apache.paimon.types.RowType;
 
@@ -35,6 +36,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import static org.apache.paimon.utils.RandomUtil.randomBytes;
 import static org.apache.paimon.utils.RandomUtil.randomString;
@@ -45,6 +47,29 @@ public class FileIndexFormatFormatTest {
 
     private static final Random RANDOM = new Random();
 
+    @Test
+    public void testCreateReaderClosesStreamOnBadMagic() {
+        byte[] notIndexFile = "this is definitely not a file index".getBytes();
+        AtomicBoolean closed = new AtomicBoolean();
+        SeekableInputStream counting =
+                new ByteArraySeekableStream(notIndexFile) {
+                    @Override
+                    public void close() throws IOException {
+                        closed.set(true);
+                        super.close();
+                    }
+                };
+        Throwable thrown =
+                Assertions.catchThrowable(
+                        () -> FileIndexFormat.createReader(counting, 
RowType.builder().build()));
+        // A throwing constructor never assigns the caller's 
try-with-resources resource,
+        // so closing the stream is the constructor's job.
+        Assertions.assertThat(closed.get()).isTrue();
+        Assertions.assertThat(thrown)
+                .isInstanceOf(RuntimeException.class)
+                .hasRootCauseMessage("This file is not file index file.");
+    }
+
     @Test
     public void testWriteRead() throws IOException {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
diff --git 
a/paimon-common/src/test/java/org/apache/paimon/fileindex/FileIndexPredicateCloseTest.java
 
b/paimon-common/src/test/java/org/apache/paimon/fileindex/FileIndexPredicateCloseTest.java
index 98b6cf9370..9e84dc7d62 100644
--- 
a/paimon-common/src/test/java/org/apache/paimon/fileindex/FileIndexPredicateCloseTest.java
+++ 
b/paimon-common/src/test/java/org/apache/paimon/fileindex/FileIndexPredicateCloseTest.java
@@ -47,7 +47,8 @@ public class FileIndexPredicateCloseTest {
 
         assertThatThrownBy(() -> new 
FileIndexPredicate(tracking(notAnIndexFile, closed), ROW_TYPE))
                 .isInstanceOf(RuntimeException.class)
-                .hasMessageContaining("not file index file");
+                .hasMessageContaining("Exception happens while construct file 
index reader.")
+                .hasRootCauseMessage("This file is not file index file.");
 
         assertThat(closed).hasValue(1);
     }

Reply via email to