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

diqiu50 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 93bdc3b182 [#9581] fix(hive): Perform resource cleanup in 
HiveClientPool close (#9617)
93bdc3b182 is described below

commit 93bdc3b182018cbd793a4cd1e5bd75230a426ec4
Author: Joey Tong <[email protected]>
AuthorDate: Mon Jan 12 09:56:33 2026 +0800

    [#9581] fix(hive): Perform resource cleanup in HiveClientPool close (#9617)
    
    <!--
    1. Title: [#<issue>] <type>(<scope>): <subject>
       Examples:
         - "[#123] feat(operator): support xxx"
         - "[#233] fix: check null before access result in xxx"
         - "[MINOR] refactor: fix typo in variable name"
         - "[MINOR] docs: fix typo in README"
         - "[#255] test: fix flaky test NameOfTheTest"
       Reference: https://www.conventionalcommits.org/en/v1.0.0/
    2. If the PR is unfinished, please mark this PR as draft.
    -->
    
    ### What changes were proposed in this pull request?
    
    This PR performs actual resource cleanup in `HiveClientPool.close`
    
    ### Why are the changes needed?
    
    Any code path in the current implementation that close the pool via
    `ClientPoolImpl.close()` will cause the connection leaks because the
    HiveClientPool.close is a no-op.
    
    Fix: #9581
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    Add UTs.
---
 catalogs/hive-metastore-common/build.gradle.kts    |   1 +
 .../org/apache/gravitino/hive/HiveClientPool.java  |   5 +-
 .../apache/gravitino/hive/TestHiveClientPool.java  | 100 +++++++++++++++++++++
 3 files changed, 105 insertions(+), 1 deletion(-)

diff --git a/catalogs/hive-metastore-common/build.gradle.kts 
b/catalogs/hive-metastore-common/build.gradle.kts
index 406b0fd31c..de36565189 100644
--- a/catalogs/hive-metastore-common/build.gradle.kts
+++ b/catalogs/hive-metastore-common/build.gradle.kts
@@ -120,6 +120,7 @@ dependencies {
     exclude("org.slf4j")
   }
   testImplementation(libs.junit.jupiter.api)
+  testImplementation(libs.mockito.core)
   testImplementation(libs.woodstox.core)
   testImplementation(libs.testcontainers)
   testImplementation(project(":integration-test-common", "testArtifacts"))
diff --git 
a/catalogs/hive-metastore-common/src/main/java/org/apache/gravitino/hive/HiveClientPool.java
 
b/catalogs/hive-metastore-common/src/main/java/org/apache/gravitino/hive/HiveClientPool.java
index 7fa0098a34..e4d78e58c7 100644
--- 
a/catalogs/hive-metastore-common/src/main/java/org/apache/gravitino/hive/HiveClientPool.java
+++ 
b/catalogs/hive-metastore-common/src/main/java/org/apache/gravitino/hive/HiveClientPool.java
@@ -41,7 +41,7 @@ public class HiveClientPool extends 
ClientPoolImpl<HiveClient, GravitinoRuntimeE
    * @param properties The configuration used to initialize the Hive Metastore 
clients.
    */
   public HiveClientPool(String name, int poolSize, Properties properties) {
-    // Do not allow retry by default as we rely on RetryingHiveClient
+    // Do not allow retry by default as we rely on RetryingMetaStoreClient
     super(poolSize, GravitinoRuntimeException.class, false);
     this.clientFactory = new HiveClientFactory(properties, name);
   }
@@ -58,17 +58,20 @@ public class HiveClientPool extends 
ClientPoolImpl<HiveClient, GravitinoRuntimeE
 
   @Override
   protected HiveClient reconnect(HiveClient client) {
+    // No-op reconnect: RetryingMetaStoreClient handles reconnect logic.
     LOG.warn("Reconnecting to Hive Metastore");
     return client;
   }
 
   @Override
   protected boolean isConnectionException(Exception e) {
+    // Pool-level reconnection is not required by design.
     return false;
   }
 
   @Override
   protected void close(HiveClient client) {
     LOG.info("Closing Hive Metastore client");
+    client.close();
   }
 }
diff --git 
a/catalogs/hive-metastore-common/src/test/java/org/apache/gravitino/hive/TestHiveClientPool.java
 
b/catalogs/hive-metastore-common/src/test/java/org/apache/gravitino/hive/TestHiveClientPool.java
new file mode 100644
index 0000000000..83f397606d
--- /dev/null
+++ 
b/catalogs/hive-metastore-common/src/test/java/org/apache/gravitino/hive/TestHiveClientPool.java
@@ -0,0 +1,100 @@
+/*
+ * 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.gravitino.hive;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import com.google.common.collect.Lists;
+import java.util.List;
+import java.util.Properties;
+import org.apache.gravitino.exceptions.GravitinoRuntimeException;
+import org.apache.gravitino.hive.client.HiveClient;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+/**
+ * Referenced from Apache Iceberg's {@code TestHiveClientPool} implementation.
+ *
+ * <p>Source: 
hive-metastore/src/test/java/org/apache/iceberg/hive/TestHiveClientPool.java
+ */
+public class TestHiveClientPool {
+
+  private HiveClientPool clients;
+
+  @BeforeEach
+  public void before() {
+    HiveClientPool clientPool = new HiveClientPool("hive", 2, new 
Properties());
+    clients = Mockito.spy(clientPool);
+  }
+
+  @AfterEach
+  public void after() {
+    clients.close();
+    clients = null;
+  }
+
+  @Test
+  public void testNewClientFailure() {
+    Mockito.doThrow(new RuntimeException("Connection 
exception")).when(clients).newClient();
+    RuntimeException ex = assertThrows(RuntimeException.class, () -> 
clients.run(Object::toString));
+    assertEquals("Connection exception", ex.getMessage());
+  }
+
+  @Test
+  public void testReconnect() {
+    HiveClient hiveClient = newClient();
+
+    String metaMessage = "Got exception: 
org.apache.thrift.transport.TTransportException";
+    Mockito.doThrow(new GravitinoRuntimeException(metaMessage))
+        .when(hiveClient)
+        .getAllDatabases("");
+
+    GravitinoRuntimeException ex =
+        assertThrows(
+            GravitinoRuntimeException.class,
+            () -> clients.run(client -> client.getAllDatabases("")));
+    assertEquals("Got exception: 
org.apache.thrift.transport.TTransportException", ex.getMessage());
+    // Verify that the method is never called.
+    Mockito.verify(clients, Mockito.never()).reconnect(hiveClient);
+  }
+
+  @Test
+  public void testClose() throws Exception {
+    HiveClient hiveClient = newClient();
+
+    List<String> databases = Lists.newArrayList("db1", "db2");
+    Mockito.doReturn(databases).when(hiveClient).getAllDatabases("");
+    assertEquals(clients.run(client -> client.getAllDatabases("")), databases);
+
+    clients.close();
+    assertTrue(clients.isClosed());
+    Mockito.verify(hiveClient).close();
+  }
+
+  private HiveClient newClient() {
+    HiveClient hiveClient = Mockito.mock(HiveClient.class);
+    Mockito.doReturn(hiveClient).when(clients).newClient();
+    return hiveClient;
+  }
+}

Reply via email to