This is an automated email from the ASF dual-hosted git repository.
jshao pushed a commit to branch branch-1.2
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-1.2 by this push:
new f7f9bc249b [Cherry-pick to branch-1.2] [#10253] Optimize driver
degisteration logic for JDBC catalog to avoid possible OOM problem (#10255)
(#10310)
f7f9bc249b is described below
commit f7f9bc249b135cb147e4bfb628ea4a646dc20952
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Mon Mar 9 19:56:40 2026 +0800
[Cherry-pick to branch-1.2] [#10253] Optimize driver degisteration logic
for JDBC catalog to avoid possible OOM problem (#10255) (#10310)
**Cherry-pick Information:**
- Original commit: 892167250926a5c6c8694d497da4b0866cd98a27
- Target branch: `branch-1.2`
- Status: ⚠️ **Has conflicts - manual resolution required**
Please review and resolve the conflicts before merging.
Co-authored-by: Qi Yu <[email protected]>
Co-authored-by: Copilot <[email protected]>
---
.../operations/ClickHouseCatalogOperations.java | 15 +----
.../hologres/HologresCatalogOperations.java | 25 ++++---
.../catalog/oceanbase/OceanBaseCatalog.java | 4 +-
.../catalog/jdbc/JdbcCatalogOperations.java | 24 +++++++
.../MySQLProtocolCompatibleCatalogOperations.java | 13 ++--
.../catalog/jdbc/TestJdbcCatalogOperations.java | 78 ++++++++++++++++++++++
.../postgresql/PostgreSQLCatalogOperations.java | 13 +---
7 files changed, 129 insertions(+), 43 deletions(-)
diff --git
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseCatalogOperations.java
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseCatalogOperations.java
index 01631f3337..fb9a3d7140 100644
---
a/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseCatalogOperations.java
+++
b/catalogs-contrib/catalog-jdbc-clickhouse/src/main/java/org/apache/gravitino/catalog/clickhouse/operations/ClickHouseCatalogOperations.java
@@ -21,6 +21,7 @@ package org.apache.gravitino.catalog.clickhouse.operations;
import java.sql.Driver;
import java.sql.DriverManager;
+import java.sql.SQLException;
import org.apache.gravitino.catalog.jdbc.JdbcCatalogOperations;
import
org.apache.gravitino.catalog.jdbc.converter.JdbcColumnDefaultValueConverter;
import org.apache.gravitino.catalog.jdbc.converter.JdbcExceptionConverter;
@@ -45,17 +46,7 @@ public class ClickHouseCatalogOperations extends
JdbcCatalogOperations {
}
@Override
- public void close() {
- super.close();
-
- // deregister ClickHouse JDBC driver to prevent memory leak in
long-running applications
- try {
- Driver clickhouseDriver =
-
DriverManager.getDriver("jdbc:clickhouse://dummy_address:8443/default");
- deregisterDriver(clickhouseDriver);
- } catch (java.sql.SQLException e) {
- // log and ignore
- System.err.println("Failed to deregister ClickHouse JDBC driver: " +
e.getMessage());
- }
+ protected Driver getDriver() throws SQLException {
+ return
DriverManager.getDriver("jdbc:clickhouse://dummy_address:8443/default");
}
}
diff --git
a/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/PostgreSQLCatalogOperations.java
b/catalogs-contrib/catalog-jdbc-hologres/src/main/java/org/apache/gravitino/catalog/hologres/HologresCatalogOperations.java
similarity index 76%
copy from
catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/PostgreSQLCatalogOperations.java
copy to
catalogs-contrib/catalog-jdbc-hologres/src/main/java/org/apache/gravitino/catalog/hologres/HologresCatalogOperations.java
index 527a27072a..2c2442569e 100644
---
a/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/PostgreSQLCatalogOperations.java
+++
b/catalogs-contrib/catalog-jdbc-hologres/src/main/java/org/apache/gravitino/catalog/hologres/HologresCatalogOperations.java
@@ -16,10 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.gravitino.catalog.postgresql;
+package org.apache.gravitino.catalog.hologres;
import java.sql.Driver;
import java.sql.DriverManager;
+import java.sql.SQLException;
import org.apache.gravitino.catalog.jdbc.JdbcCatalogOperations;
import
org.apache.gravitino.catalog.jdbc.converter.JdbcColumnDefaultValueConverter;
import org.apache.gravitino.catalog.jdbc.converter.JdbcExceptionConverter;
@@ -27,9 +28,15 @@ import
org.apache.gravitino.catalog.jdbc.converter.JdbcTypeConverter;
import org.apache.gravitino.catalog.jdbc.operation.JdbcDatabaseOperations;
import org.apache.gravitino.catalog.jdbc.operation.JdbcTableOperations;
-public class PostgreSQLCatalogOperations extends JdbcCatalogOperations {
+/**
+ * Hologres catalog operations implementation.
+ *
+ * <p>Since Hologres uses the PostgreSQL JDBC driver, this class handles the
driver deregistration
+ * properly to avoid memory leaks when the catalog is closed.
+ */
+public class HologresCatalogOperations extends JdbcCatalogOperations {
- public PostgreSQLCatalogOperations(
+ public HologresCatalogOperations(
JdbcExceptionConverter exceptionConverter,
JdbcTypeConverter jdbcTypeConverter,
JdbcDatabaseOperations databaseOperation,
@@ -44,15 +51,7 @@ public class PostgreSQLCatalogOperations extends
JdbcCatalogOperations {
}
@Override
- public void close() {
- super.close();
- try {
- // Unload the PostgreSQL driver, only Unload the driver if it is loaded
by
- // IsolatedClassLoader.
- Driver pgDriver =
DriverManager.getDriver("jdbc:postgresql://dummy_address:12345/");
- deregisterDriver(pgDriver);
- } catch (Exception e) {
- LOG.warn("Failed to deregister PostgreSQL driver", e);
- }
+ protected Driver getDriver() throws SQLException {
+ return DriverManager.getDriver("jdbc:postgresql://dummy_address:12345/");
}
}
diff --git
a/catalogs-contrib/catalog-jdbc-oceanbase/src/main/java/org/apache/gravitino/catalog/oceanbase/OceanBaseCatalog.java
b/catalogs-contrib/catalog-jdbc-oceanbase/src/main/java/org/apache/gravitino/catalog/oceanbase/OceanBaseCatalog.java
index 1231926441..200d501de5 100644
---
a/catalogs-contrib/catalog-jdbc-oceanbase/src/main/java/org/apache/gravitino/catalog/oceanbase/OceanBaseCatalog.java
+++
b/catalogs-contrib/catalog-jdbc-oceanbase/src/main/java/org/apache/gravitino/catalog/oceanbase/OceanBaseCatalog.java
@@ -20,7 +20,7 @@ package org.apache.gravitino.catalog.oceanbase;
import java.util.Map;
import org.apache.gravitino.catalog.jdbc.JdbcCatalog;
-import org.apache.gravitino.catalog.jdbc.JdbcCatalogOperations;
+import
org.apache.gravitino.catalog.jdbc.MySQLProtocolCompatibleCatalogOperations;
import
org.apache.gravitino.catalog.jdbc.converter.JdbcColumnDefaultValueConverter;
import org.apache.gravitino.catalog.jdbc.converter.JdbcTypeConverter;
import org.apache.gravitino.catalog.jdbc.operation.JdbcDatabaseOperations;
@@ -42,7 +42,7 @@ public class OceanBaseCatalog extends JdbcCatalog {
@Override
protected CatalogOperations newOps(Map<String, String> config) {
- return new JdbcCatalogOperations(
+ return new MySQLProtocolCompatibleCatalogOperations(
createExceptionConverter(),
createJdbcTypeConverter(),
createJdbcDatabaseOperations(),
diff --git
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/JdbcCatalogOperations.java
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/JdbcCatalogOperations.java
index b70abc354d..e9716749fa 100644
---
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/JdbcCatalogOperations.java
+++
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/JdbcCatalogOperations.java
@@ -102,6 +102,7 @@ public class JdbcCatalogOperations implements
CatalogOperations, SupportsSchemas
private final TableOperation tableOperation;
private DataSource dataSource;
+ private String jdbcUrl;
private final JdbcColumnDefaultValueConverter columnDefaultValueConverter;
@@ -170,6 +171,7 @@ public class JdbcCatalogOperations implements
CatalogOperations, SupportsSchemas
resultConf.putAll(gravitinoConfig);
JdbcConfig jdbcConfig = new JdbcConfig(resultConf);
+ this.jdbcUrl = jdbcConfig.getJdbcUrl();
this.dataSource = DataSourceUtils.createDataSource(jdbcConfig);
checkJDBCDriverVersion();
@@ -199,6 +201,28 @@ public class JdbcCatalogOperations implements
CatalogOperations, SupportsSchemas
metricsSystem.unregister(catalogMetricsSource);
}
DataSourceUtils.closeDataSource(dataSource);
+ try {
+ Driver driver = getDriver();
+ if (driver != null) {
+ deregisterDriver(driver);
+ }
+ } catch (SQLException e) {
+ LOG.warn("Failed to deregister JDBC driver", e);
+ }
+ }
+
+ /**
+ * Gets the JDBC driver for the provided JDBC URL.
+ *
+ * @return The JDBC driver instance if the JDBC URL is not blank; null if
the JDBC URL is blank.
+ * @throws SQLException if failing to get driver from JDBC URL.
+ */
+ protected Driver getDriver() throws SQLException {
+ if (StringUtils.isBlank(jdbcUrl)) {
+ return null;
+ }
+
+ return DriverManager.getDriver(jdbcUrl);
}
/**
diff --git
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/MySQLProtocolCompatibleCatalogOperations.java
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/MySQLProtocolCompatibleCatalogOperations.java
index b4ee565dce..2a5bddaa99 100644
---
a/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/MySQLProtocolCompatibleCatalogOperations.java
+++
b/catalogs/catalog-jdbc-common/src/main/java/org/apache/gravitino/catalog/jdbc/MySQLProtocolCompatibleCatalogOperations.java
@@ -21,6 +21,7 @@ package org.apache.gravitino.catalog.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
+import java.sql.SQLException;
import
org.apache.gravitino.catalog.jdbc.converter.JdbcColumnDefaultValueConverter;
import org.apache.gravitino.catalog.jdbc.converter.JdbcExceptionConverter;
import org.apache.gravitino.catalog.jdbc.converter.JdbcTypeConverter;
@@ -70,13 +71,13 @@ public class MySQLProtocolCompatibleCatalogOperations
extends JdbcCatalogOperati
.getMethod("uncheckedShutdown")
.invoke(null);
LOG.info("AbandonedConnectionCleanupThread has been shutdown...");
-
- // Unload the MySQL driver, only Unload the driver if it is loaded by
- // IsolatedClassLoader.
- Driver mysqlDriver =
DriverManager.getDriver("jdbc:mysql://dumpy_address");
- deregisterDriver(mysqlDriver);
} catch (Exception e) {
- LOG.warn("Failed to shutdown AbandonedConnectionCleanupThread or
deregister MySQL driver", e);
+ LOG.warn("Failed to shutdown AbandonedConnectionCleanupThread", e);
}
}
+
+ @Override
+ protected Driver getDriver() throws SQLException {
+ return DriverManager.getDriver("jdbc:mysql://dummy_address");
+ }
}
diff --git
a/catalogs/catalog-jdbc-common/src/test/java/org/apache/gravitino/catalog/jdbc/TestJdbcCatalogOperations.java
b/catalogs/catalog-jdbc-common/src/test/java/org/apache/gravitino/catalog/jdbc/TestJdbcCatalogOperations.java
index 0b082d5916..d7f711e20f 100644
---
a/catalogs/catalog-jdbc-common/src/test/java/org/apache/gravitino/catalog/jdbc/TestJdbcCatalogOperations.java
+++
b/catalogs/catalog-jdbc-common/src/test/java/org/apache/gravitino/catalog/jdbc/TestJdbcCatalogOperations.java
@@ -20,6 +20,8 @@ package org.apache.gravitino.catalog.jdbc;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
+import java.sql.Driver;
+import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import javax.sql.DataSource;
@@ -27,6 +29,8 @@ import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.gravitino.Catalog;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.catalog.jdbc.config.JdbcConfig;
+import org.apache.gravitino.catalog.jdbc.converter.JdbcExceptionConverter;
+import org.apache.gravitino.catalog.jdbc.converter.JdbcTypeConverter;
import
org.apache.gravitino.catalog.jdbc.converter.SqliteColumnDefaultValueConverter;
import org.apache.gravitino.catalog.jdbc.converter.SqliteExceptionConverter;
import org.apache.gravitino.catalog.jdbc.converter.SqliteTypeConverter;
@@ -75,4 +79,78 @@ public class TestJdbcCatalogOperations {
Assertions.assertFalse(((BasicDataSource) dataSource).getTestOnBorrow());
((BasicDataSource) dataSource).close();
}
+
+ @Test
+ public void testCloseDeregisterDriver() throws SQLException {
+ TestableJdbcCatalogOperations catalogOperations =
+ new TestableJdbcCatalogOperations(
+ new SqliteExceptionConverter(),
+ new SqliteTypeConverter(),
+ new SqliteDatabaseOperations("/illegal/path"),
+ new SqliteTableOperations(),
+ new SqliteColumnDefaultValueConverter());
+
catalogOperations.setDriver(DriverManager.getDriver("jdbc:sqlite::memory:"));
+
+ Assertions.assertDoesNotThrow(catalogOperations::close);
+ Assertions.assertTrue(catalogOperations.isDeregisterCalled());
+ }
+
+ @Test
+ public void testCloseIgnoreGetDriverException() {
+ TestableJdbcCatalogOperations catalogOperations =
+ new TestableJdbcCatalogOperations(
+ new SqliteExceptionConverter(),
+ new SqliteTypeConverter(),
+ new SqliteDatabaseOperations("/illegal/path"),
+ new SqliteTableOperations(),
+ new SqliteColumnDefaultValueConverter());
+ catalogOperations.setThrowExceptionInGetDriver(true);
+
+ Assertions.assertDoesNotThrow(catalogOperations::close);
+ }
+
+ private static class TestableJdbcCatalogOperations extends
JdbcCatalogOperations {
+ private Driver driver;
+ private boolean deregisterCalled;
+ private boolean throwExceptionInGetDriver;
+
+ private TestableJdbcCatalogOperations(
+ JdbcExceptionConverter exceptionConverter,
+ JdbcTypeConverter jdbcTypeConverter,
+ SqliteDatabaseOperations databaseOperation,
+ SqliteTableOperations tableOperation,
+ SqliteColumnDefaultValueConverter columnDefaultValueConverter) {
+ super(
+ exceptionConverter,
+ jdbcTypeConverter,
+ databaseOperation,
+ tableOperation,
+ columnDefaultValueConverter);
+ }
+
+ @Override
+ protected Driver getDriver() throws SQLException {
+ if (throwExceptionInGetDriver) {
+ throw new SQLException("failed to get driver");
+ }
+ return driver;
+ }
+
+ @Override
+ public void deregisterDriver(Driver driver) {
+ this.deregisterCalled = true;
+ }
+
+ private void setDriver(Driver driver) {
+ this.driver = driver;
+ }
+
+ private void setThrowExceptionInGetDriver(boolean
throwExceptionInGetDriver) {
+ this.throwExceptionInGetDriver = throwExceptionInGetDriver;
+ }
+
+ private boolean isDeregisterCalled() {
+ return deregisterCalled;
+ }
+ }
}
diff --git
a/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/PostgreSQLCatalogOperations.java
b/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/PostgreSQLCatalogOperations.java
index 527a27072a..b04ac0dad0 100644
---
a/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/PostgreSQLCatalogOperations.java
+++
b/catalogs/catalog-jdbc-postgresql/src/main/java/org/apache/gravitino/catalog/postgresql/PostgreSQLCatalogOperations.java
@@ -20,6 +20,7 @@ package org.apache.gravitino.catalog.postgresql;
import java.sql.Driver;
import java.sql.DriverManager;
+import java.sql.SQLException;
import org.apache.gravitino.catalog.jdbc.JdbcCatalogOperations;
import
org.apache.gravitino.catalog.jdbc.converter.JdbcColumnDefaultValueConverter;
import org.apache.gravitino.catalog.jdbc.converter.JdbcExceptionConverter;
@@ -44,15 +45,7 @@ public class PostgreSQLCatalogOperations extends
JdbcCatalogOperations {
}
@Override
- public void close() {
- super.close();
- try {
- // Unload the PostgreSQL driver, only Unload the driver if it is loaded
by
- // IsolatedClassLoader.
- Driver pgDriver =
DriverManager.getDriver("jdbc:postgresql://dummy_address:12345/");
- deregisterDriver(pgDriver);
- } catch (Exception e) {
- LOG.warn("Failed to deregister PostgreSQL driver", e);
- }
+ protected Driver getDriver() throws SQLException {
+ return DriverManager.getDriver("jdbc:postgresql://dummy_address:12345/");
}
}