This is an automated email from the ASF dual-hosted git repository.
gavinchou pushed a commit to branch bdbje
in repository https://gitbox.apache.org/repos/asf/doris-thirdparty.git
The following commit(s) were added to refs/heads/bdbje by this push:
new 70324a2452e [fix](bdbje) release SSL certificate monitor threads on
factory shutdown (#380)
70324a2452e is described below
commit 70324a2452e4ff717c872e431b5b385c82a54f84
Author: Siyang Tang <[email protected]>
AuthorDate: Mon Feb 9 20:31:40 2026 +0800
[fix](bdbje) release SSL certificate monitor threads on factory shutdown
(#380)
---
pom.xml | 2 +-
.../java/com/sleepycat/je/rep/impl/RepImpl.java | 33 ++++++++++++
.../java/com/sleepycat/je/rep/monitor/Monitor.java | 9 ++++
.../sleepycat/je/rep/net/DataChannelFactory.java | 9 ++++
.../com/sleepycat/je/rep/util/DbGroupAdmin.java | 60 ++++++++++++----------
.../java/com/sleepycat/je/rep/util/DbPing.java | 32 ++++++++++--
.../je/rep/util/ReplicationGroupAdmin.java | 27 +++++++++-
.../je/rep/utilint/net/SSLChannelFactory.java | 35 +++++++++++--
8 files changed, 171 insertions(+), 36 deletions(-)
diff --git a/pom.xml b/pom.xml
index 729aaf748e0..387f898e85d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
</parent>
<groupId>org.apache.doris</groupId>
<artifactId>je</artifactId>
- <version>18.3.17-doris-SNAPSHOT</version>
+ <version>18.3.18-doris-SNAPSHOT</version>
<name>bdb-je apache doris release</name>
<url>https://doris.apache.org/</url>
<description>fork from bdb-je 18.3.12 from maven with starrocks bdbje
patches</description>
diff --git a/src/main/java/com/sleepycat/je/rep/impl/RepImpl.java
b/src/main/java/com/sleepycat/je/rep/impl/RepImpl.java
index a37a93d4704..09d817207b9 100644
--- a/src/main/java/com/sleepycat/je/rep/impl/RepImpl.java
+++ b/src/main/java/com/sleepycat/je/rep/impl/RepImpl.java
@@ -645,6 +645,33 @@ public class RepImpl
}
}
+ private synchronized void shutdownChannelFactory(PrintWriter errors) {
+ if (channelFactory == null) {
+ return;
+ }
+
+ try {
+ channelFactory.shutdown();
+ } catch (RuntimeException e) {
+ if (errors != null) {
+ appendException(errors, e,
+ "shutting down channel factory " +
+ nameIdPair);
+ } else {
+ LoggerUtils.warning(
+ envLogger, this,
+ "Unexpected exception shutting down channel factory: " +
+ e.getMessage());
+ }
+ } finally {
+ channelFactory = null;
+ }
+ }
+
+ private void shutdownChannelFactory() {
+ shutdownChannelFactory(null);
+ }
+
@Override
protected Environment createInternalEnvironment() {
return new InternalReplicatedEnvironment
@@ -680,6 +707,8 @@ public class RepImpl
}
} catch (InterruptedException e) {
appendException(errors, e, "shutting down node " + nameIdPair);
+ } finally {
+ shutdownChannelFactory(errors);
}
}
@@ -774,6 +803,8 @@ public class RepImpl
repNode = null;
}
} catch (Exception ignore) {
+ } finally {
+ shutdownChannelFactory();
}
super.doCloseAfterInvalid();
@@ -811,6 +842,8 @@ public class RepImpl
}
} catch (InterruptedException ignore) {
/* ignore */
+ } finally {
+ shutdownChannelFactory();
}
try {
diff --git a/src/main/java/com/sleepycat/je/rep/monitor/Monitor.java
b/src/main/java/com/sleepycat/je/rep/monitor/Monitor.java
index 7d2a7250abb..c0b3b9defae 100644
--- a/src/main/java/com/sleepycat/je/rep/monitor/Monitor.java
+++ b/src/main/java/com/sleepycat/je/rep/monitor/Monitor.java
@@ -552,6 +552,15 @@ public class Monitor {
if (serviceDispatcher != null) {
serviceDispatcher.shutdown();
}
+
+ if (repGroupAdmin != null) {
+ repGroupAdmin.close();
+ }
+
+ if (channelFactory != null) {
+ channelFactory.shutdown();
+ channelFactory = null;
+ }
}
/**
diff --git a/src/main/java/com/sleepycat/je/rep/net/DataChannelFactory.java
b/src/main/java/com/sleepycat/je/rep/net/DataChannelFactory.java
index b8af5dda396..c22642ce1ba 100644
--- a/src/main/java/com/sleepycat/je/rep/net/DataChannelFactory.java
+++ b/src/main/java/com/sleepycat/je/rep/net/DataChannelFactory.java
@@ -215,4 +215,13 @@ public interface DataChannelFactory {
InetSocketAddress localAddr,
ConnectOptions connectOptions)
throws IOException;
+
+ /**
+ * Releases resources associated with this factory.
+ *
+ * Implementations that do not hold resources can use the default no-op
+ * behavior.
+ */
+ default void shutdown() {
+ }
}
diff --git a/src/main/java/com/sleepycat/je/rep/util/DbGroupAdmin.java
b/src/main/java/com/sleepycat/je/rep/util/DbGroupAdmin.java
index b9e26c342e5..78f69c7b2bd 100644
--- a/src/main/java/com/sleepycat/je/rep/util/DbGroupAdmin.java
+++ b/src/main/java/com/sleepycat/je/rep/util/DbGroupAdmin.java
@@ -277,40 +277,46 @@ public class DbGroupAdmin {
createGroupAdmin();
- if (actions.size() == 0) {
- return;
- }
+ try {
+ if (actions.size() == 0) {
+ return;
+ }
- for (Command action : actions) {
- switch (action) {
+ for (Command action : actions) {
+ switch (action) {
- /* Dump the group information. */
- case DUMP:
- dumpGroup();
- break;
+ /* Dump the group information. */
+ case DUMP:
+ dumpGroup();
+ break;
- /* Remove a member. */
- case REMOVE:
- removeMember(nodeName);
- break;
+ /* Remove a member. */
+ case REMOVE:
+ removeMember(nodeName);
+ break;
- /* Transfer the current mastership to a specified node. */
- case TRANSFER_MASTER:
- transferMaster(nodeName, timeout);
- break;
+ /* Transfer the current mastership to a specified node. */
+ case TRANSFER_MASTER:
+ transferMaster(nodeName, timeout);
+ break;
- /* Update the network address of a specified node. */
- case UPDATE_ADDRESS:
- updateAddress(nodeName, newHostName, newPort);
- break;
+ /* Update the network address of a specified node. */
+ case UPDATE_ADDRESS:
+ updateAddress(nodeName, newHostName, newPort);
+ break;
- /* Delete a member */
- case DELETE:
- deleteMember(nodeName);
- break;
+ /* Delete a member */
+ case DELETE:
+ deleteMember(nodeName);
+ break;
- default:
- throw new AssertionError();
+ default:
+ throw new AssertionError();
+ }
+ }
+ } finally {
+ if (groupAdmin != null) {
+ groupAdmin.close();
}
}
}
diff --git a/src/main/java/com/sleepycat/je/rep/util/DbPing.java
b/src/main/java/com/sleepycat/je/rep/util/DbPing.java
index 52ce91a9b5c..d32d5ea6045 100644
--- a/src/main/java/com/sleepycat/je/rep/util/DbPing.java
+++ b/src/main/java/com/sleepycat/je/rep/util/DbPing.java
@@ -50,6 +50,7 @@ public class DbPing {
private int socketTimeout = 10000;
/* The factory for channel creation */
private DataChannelFactory channelFactory;
+ private boolean ownsChannelFactory = false;
private static final String undocumentedUsageString =
" -netProps <optional> # name of a property file containing\n" +
@@ -93,8 +94,12 @@ public class DbPing {
throws Exception {
DbPing ping = new DbPing();
- ping.parseArgs(args);
- System.out.println(ping.getNodeState());
+ try {
+ ping.parseArgs(args);
+ System.out.println(ping.getNodeState());
+ } finally {
+ ping.close();
+ }
}
/**
@@ -201,6 +206,7 @@ public class DbPing {
}
this.channelFactory = initializeFactory(repNetConfig, nodeName);
+ this.ownsChannelFactory = true;
}
private DbPing() {
@@ -269,7 +275,8 @@ public class DbPing {
int socketTimeout,
ReplicationNetworkConfig netConfig) {
this(repNode, groupName, socketTimeout,
- initializeFactory(netConfig, repNode.getName()));
+ initializeFactory(netConfig, repNode.getName()),
+ true);
}
/**
@@ -289,11 +296,20 @@ public class DbPing {
String groupName,
int socketTimeout,
DataChannelFactory channelFactory) {
+ this(repNode, groupName, socketTimeout, channelFactory, false);
+ }
+
+ private DbPing(ReplicationNode repNode,
+ String groupName,
+ int socketTimeout,
+ DataChannelFactory channelFactory,
+ boolean ownsChannelFactory) {
this.nodeName = repNode.getName();
this.groupName = groupName;
this.socketAddress = repNode.getSocketAddress();
this.socketTimeout = socketTimeout;
this.channelFactory = channelFactory;
+ this.ownsChannelFactory = ownsChannelFactory;
}
/* Get the state of the specified node. */
@@ -333,6 +349,16 @@ public class DbPing {
}
}
+ /**
+ * Releases resources owned by this instance.
+ */
+ public void close() {
+ if (ownsChannelFactory && channelFactory != null) {
+ channelFactory.shutdown();
+ channelFactory = null;
+ }
+ }
+
private static ReplicationNetworkConfig makeRepNetConfig(File propFile)
throws FileNotFoundException {
diff --git a/src/main/java/com/sleepycat/je/rep/util/ReplicationGroupAdmin.java
b/src/main/java/com/sleepycat/je/rep/util/ReplicationGroupAdmin.java
index b1edb797209..ecb88536164 100644
--- a/src/main/java/com/sleepycat/je/rep/util/ReplicationGroupAdmin.java
+++ b/src/main/java/com/sleepycat/je/rep/util/ReplicationGroupAdmin.java
@@ -77,6 +77,8 @@ public class ReplicationGroupAdmin {
private final Logger logger;
private final Formatter formatter;
private final DataChannelFactory channelFactory;
+ private final boolean ownsChannelFactory;
+ private volatile boolean closed = false;
/**
* Constructs a group admin object.
@@ -104,7 +106,8 @@ public class ReplicationGroupAdmin {
Set<InetSocketAddress> helperSockets,
ReplicationNetworkConfig repNetConfig) {
this(groupName, helperSockets,
- initializeFactory(repNetConfig, groupName));
+ initializeFactory(repNetConfig, groupName),
+ true);
}
/**
@@ -119,9 +122,17 @@ public class ReplicationGroupAdmin {
public ReplicationGroupAdmin(String groupName,
Set<InetSocketAddress> helperSockets,
DataChannelFactory channelFactory) {
+ this(groupName, helperSockets, channelFactory, false);
+ }
+
+ private ReplicationGroupAdmin(String groupName,
+ Set<InetSocketAddress> helperSockets,
+ DataChannelFactory channelFactory,
+ boolean ownsChannelFactory) {
this.groupName = groupName;
this.helperSockets = helperSockets;
this.channelFactory = channelFactory;
+ this.ownsChannelFactory = ownsChannelFactory;
electionsProtocol =
new Protocol(TimebasedProposalGenerator.getParser(),
@@ -138,6 +149,20 @@ public class ReplicationGroupAdmin {
formatter = new ReplicationFormatter(NameIdPair.NOCHECK);
}
+ /**
+ * Releases resources owned by this instance.
+ */
+ public synchronized void close() {
+ if (closed) {
+ return;
+ }
+ closed = true;
+
+ if (ownsChannelFactory) {
+ channelFactory.shutdown();
+ }
+ }
+
/**
* Returns the helper sockets being used to contact a replication group
* member, in order to query for the information.
diff --git
a/src/main/java/com/sleepycat/je/rep/utilint/net/SSLChannelFactory.java
b/src/main/java/com/sleepycat/je/rep/utilint/net/SSLChannelFactory.java
index ae0c351abe9..01709b13dac 100644
--- a/src/main/java/com/sleepycat/je/rep/utilint/net/SSLChannelFactory.java
+++ b/src/main/java/com/sleepycat/je/rep/utilint/net/SSLChannelFactory.java
@@ -378,10 +378,17 @@ public class SSLChannelFactory implements
DataChannelFactory {
return;
}
- // Only monitor PEM configuration
- final String pemCert = config.getSSLPemCertFile();
- final String pemKey = config.getSSLPemKeyFile();
- final String pemCa = config.getSSLPemCaCertFile();
+ if (!isPemMonitoringEnabled(config)) {
+ logger.log(INFO,
+ "Certificate monitoring disabled " +
+ "(PEM certificate/key/CA files are not fully
configured " +
+ "or keystore mode is in use)");
+ return;
+ }
+
+ if (certificateCheckExecutor != null) {
+ return;
+ }
// Create scheduled executor for periodic certificate checking
certificateCheckExecutor =
Executors.newSingleThreadScheduledExecutor(r -> {
@@ -408,6 +415,25 @@ public class SSLChannelFactory implements
DataChannelFactory {
}
}
+ private boolean isPemMonitoringEnabled(ReplicationSSLConfig config) {
+ final String keyStore = config.getSSLKeyStore();
+ final String keyStoreProperty =
+ System.getProperty("javax.net.ssl.keyStore");
+
+ if ((keyStore != null && !keyStore.isEmpty()) ||
+ (keyStoreProperty != null && !keyStoreProperty.isEmpty())) {
+ return false;
+ }
+
+ return isNonEmpty(config.getSSLPemCaCertFile()) &&
+ isNonEmpty(config.getSSLPemKeyFile()) &&
+ isNonEmpty(config.getSSLPemCertFile());
+ }
+
+ private static boolean isNonEmpty(String value) {
+ return value != null && !value.isEmpty();
+ }
+
/**
* Initialize file modification times on startup.
*/
@@ -635,6 +661,7 @@ public class SSLChannelFactory implements
DataChannelFactory {
/**
* Stop the certificate monitoring executor and clean up resources.
*/
+ @Override
public void shutdown() {
if (certificateCheckExecutor != null) {
certificateCheckExecutor.shutdown();
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]