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 b05616e523 [flink] Release both catalogs FlinkGenericCatalog wraps 
(#9422)
b05616e523 is described below

commit b05616e5231661ef5ba7fc6f3d6c2961f9036f4c
Author: ZIHAN DAI <[email protected]>
AuthorDate: Fri Aug 28 18:20:18 2026 +1000

    [flink] Release both catalogs FlinkGenericCatalog wraps (#9422)
---
 .../apache/paimon/flink/FlinkGenericCatalog.java   | 36 +++++++-
 .../paimon/flink/FlinkGenericCatalogCloseTest.java | 96 ++++++++++++++++++++++
 2 files changed, 129 insertions(+), 3 deletions(-)

diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/FlinkGenericCatalog.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/FlinkGenericCatalog.java
index 5f7a05d885..022f3b6216 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/FlinkGenericCatalog.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/FlinkGenericCatalog.java
@@ -19,6 +19,7 @@
 package org.apache.paimon.flink;
 
 import org.apache.paimon.flink.procedure.ProcedureUtil;
+import org.apache.paimon.utils.ExceptionUtils;
 
 import org.apache.flink.table.catalog.AbstractCatalog;
 import org.apache.flink.table.catalog.Catalog;
@@ -71,13 +72,42 @@ public class FlinkGenericCatalog extends AbstractCatalog {
     @Override
     public void open() throws CatalogException {
         paimon.open();
-        flink.open();
+        boolean opened = false;
+        try {
+            flink.open();
+            opened = true;
+        } finally {
+            if (!opened) {
+                // the caller will not close a catalog that failed to open
+                closeQuietly(paimon);
+            }
+        }
     }
 
     @Override
     public void close() throws CatalogException {
-        paimon.close();
-        flink.close();
+        Throwable failure = null;
+        try {
+            paimon.close();
+        } catch (Throwable t) {
+            failure = t;
+        }
+        try {
+            flink.close();
+        } catch (Throwable t) {
+            failure = ExceptionUtils.firstOrSuppressed(t, failure);
+        }
+        if (null != failure) {
+            ExceptionUtils.rethrow(failure);
+        }
+    }
+
+    private static void closeQuietly(Catalog catalog) {
+        try {
+            catalog.close();
+        } catch (Throwable ignored) {
+            // the failure that is already on its way out is the one worth 
reporting
+        }
     }
 
     @Override
diff --git 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/FlinkGenericCatalogCloseTest.java
 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/FlinkGenericCatalogCloseTest.java
new file mode 100644
index 0000000000..7ad845af55
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/FlinkGenericCatalogCloseTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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;
+
+import org.apache.flink.table.catalog.Catalog;
+import org.apache.flink.table.catalog.exceptions.CatalogException;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/** Tests that {@link FlinkGenericCatalog} releases both catalogs it wraps. */
+class FlinkGenericCatalogCloseTest {
+
+    private FlinkCatalog paimonCatalog() {
+        FlinkCatalog result = mock(FlinkCatalog.class);
+        when(result.getName()).thenReturn("paimon");
+        when(result.getDefaultDatabase()).thenReturn("default");
+        return result;
+    }
+
+    /** The two catalogs are separate resources; one failing must not strand 
the other. */
+    @Test
+    void testCloseClosesTheFlinkCatalogWhenPaimonFails() {
+        FlinkCatalog paimon = paimonCatalog();
+        Catalog flink = mock(Catalog.class);
+        CatalogException expected = new CatalogException("paimon is down");
+        doThrow(expected).when(paimon).close();
+
+        FlinkGenericCatalog catalog = new FlinkGenericCatalog(paimon, flink);
+        assertThatThrownBy(catalog::close).isSameAs(expected);
+
+        verify(flink).close();
+    }
+
+    /** Both failing must surface the first one, with the second attached 
rather than dropped. */
+    @Test
+    void testCloseKeepsBothFailures() {
+        FlinkCatalog paimon = paimonCatalog();
+        Catalog flink = mock(Catalog.class);
+        CatalogException paimonFailure = new CatalogException("paimon is 
down");
+        CatalogException flinkFailure = new CatalogException("flink is down");
+        doThrow(paimonFailure).when(paimon).close();
+        doThrow(flinkFailure).when(flink).close();
+
+        FlinkGenericCatalog catalog = new FlinkGenericCatalog(paimon, flink);
+        assertThatThrownBy(catalog::close).isSameAs(paimonFailure);
+        
assertThat(paimonFailure.getSuppressed()).containsExactly(flinkFailure);
+    }
+
+    /** open() is the same pairing in reverse: a caller does not close what 
failed to open. */
+    @Test
+    void testOpenClosesThePaimonCatalogWhenFlinkFails() {
+        FlinkCatalog paimon = paimonCatalog();
+        Catalog flink = mock(Catalog.class);
+        CatalogException expected = new CatalogException("flink is down");
+        doThrow(expected).when(flink).open();
+
+        FlinkGenericCatalog catalog = new FlinkGenericCatalog(paimon, flink);
+        assertThatThrownBy(catalog::open).isSameAs(expected);
+
+        verify(paimon).close();
+    }
+
+    /** Control: nothing fails, both are closed exactly once and nothing is 
thrown. */
+    @Test
+    void testCloseClosesBoth() {
+        FlinkCatalog paimon = paimonCatalog();
+        Catalog flink = mock(Catalog.class);
+
+        new FlinkGenericCatalog(paimon, flink).close();
+
+        verify(paimon).close();
+        verify(flink).close();
+    }
+}

Reply via email to