This is an automated email from the ASF dual-hosted git repository.
morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.1 by this push:
new 9aff673894b branch-3.1: [fix](jdbc) Fix JNI global reference leak in
JdbcConnector close #58574 (#58752)
9aff673894b is described below
commit 9aff673894b2f88b6ea293c3a1dcbb810cc06cf3
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Fri Dec 5 18:22:26 2025 +0800
branch-3.1: [fix](jdbc) Fix JNI global reference leak in JdbcConnector
close #58574 (#58752)
Cherry-picked from #58574
Co-authored-by: zy-kkk <[email protected]>
---
be/src/vec/exec/vjdbc_connector.cpp | 50 +++++++++++++++++-----
.../org/apache/doris/jdbc/BaseJdbcExecutor.java | 19 ++++++--
2 files changed, 54 insertions(+), 15 deletions(-)
diff --git a/be/src/vec/exec/vjdbc_connector.cpp
b/be/src/vec/exec/vjdbc_connector.cpp
index d4cf31f4f78..d55dd4b48e1 100644
--- a/be/src/vec/exec/vjdbc_connector.cpp
+++ b/be/src/vec/exec/vjdbc_connector.cpp
@@ -68,23 +68,51 @@ JdbcConnector::~JdbcConnector() {
Status JdbcConnector::close(Status /*unused*/) {
SCOPED_RAW_TIMER(&_jdbc_statistic._connector_close_timer);
- _closed = true;
+ if (_closed) {
+ return Status::OK();
+ }
if (!_is_open) {
+ _closed = true;
return Status::OK();
}
+
+ JNIEnv* env = nullptr;
+ Status status = JniUtil::GetJNIEnv(&env);
+ if (!status.ok() || env == nullptr) {
+ LOG(WARNING) << "Failed to get JNIEnv in close(): " <<
status.to_string();
+ _closed = true;
+ return status;
+ }
+
+ // Try to abort transaction and call Java close(), but don't block cleanup
if (_is_in_transaction) {
- RETURN_IF_ERROR(abort_trans());
+ Status abort_status = abort_trans();
+ if (!abort_status.ok()) {
+ LOG(WARNING) << "Failed to abort transaction: " <<
abort_status.to_string();
+ }
}
- JNIEnv* env = nullptr;
- RETURN_IF_ERROR(JniUtil::GetJNIEnv(&env));
+
env->CallNonvirtualVoidMethod(_executor_obj, _executor_clazz,
_executor_close_id);
- RETURN_ERROR_IF_EXC(env);
- env->DeleteGlobalRef(_executor_factory_clazz);
- RETURN_ERROR_IF_EXC(env);
- env->DeleteGlobalRef(_executor_clazz);
- RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
- env->DeleteGlobalRef(_executor_obj);
- RETURN_ERROR_IF_EXC(env);
+ if (env->ExceptionCheck()) {
+ LOG(WARNING) << "Java close() failed: " <<
JniUtil::GetJniExceptionMsg(env).to_string();
+ env->ExceptionClear();
+ }
+
+ // Always delete Global References to allow Java GC
+ if (_executor_factory_clazz != nullptr) {
+ env->DeleteGlobalRef(_executor_factory_clazz);
+ _executor_factory_clazz = nullptr;
+ }
+ if (_executor_clazz != nullptr) {
+ env->DeleteGlobalRef(_executor_clazz);
+ _executor_clazz = nullptr;
+ }
+ if (_executor_obj != nullptr) {
+ env->DeleteGlobalRef(_executor_obj);
+ _executor_obj = nullptr;
+ }
+
+ _closed = true;
return Status::OK();
}
diff --git
a/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java
b/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java
index 3e71cc5abdd..151e9cffe1a 100644
---
a/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java
+++
b/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java
@@ -127,7 +127,11 @@ public abstract class BaseJdbcExecutor implements
JdbcExecutor {
public void close() throws Exception {
if (outputTable != null) {
- outputTable.close();
+ try {
+ outputTable.close();
+ } finally {
+ outputTable = null;
+ }
}
try {
if (stmt != null && !stmt.isClosed()) {
@@ -143,10 +147,17 @@ public abstract class BaseJdbcExecutor implements
JdbcExecutor {
}
} finally {
closeResources(resultSet, stmt, conn);
+ // Always clear references to help GC, even if close() failed
+ resultSet = null;
+ stmt = null;
+ conn = null;
if (config.getConnectionPoolMinSize() == 0 && hikariDataSource !=
null) {
- hikariDataSource.close();
-
JdbcDataSource.getDataSource().getSourcesMap().remove(config.createCacheKey());
- hikariDataSource = null;
+ try {
+ hikariDataSource.close();
+
JdbcDataSource.getDataSource().getSourcesMap().remove(config.createCacheKey());
+ } finally {
+ hikariDataSource = null;
+ }
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]