Skip to content

Commit 2c536a7

Browse files
committed
Simplify ExecutorService to start and stop once
- Start on pool creation - Stop on fullShutdown of pool - ExecutorService becomes final
1 parent b0c8ad4 commit 2c536a7

File tree

1 file changed

+21
-41
lines changed

1 file changed

+21
-41
lines changed

ebean-datasource/src/main/java/io/ebean/datasource/pool/ConnectionPool.java

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import java.sql.*;
88
import java.util.*;
99
import java.util.concurrent.ExecutorService;
10-
import java.util.concurrent.Executors;
10+
import java.util.concurrent.RejectedExecutionException;
1111
import java.util.concurrent.TimeUnit;
1212
import java.util.concurrent.atomic.AtomicBoolean;
1313
import java.util.concurrent.atomic.AtomicInteger;
@@ -30,7 +30,6 @@ final class ConnectionPool implements DataSourcePool {
3030

3131
private static final String APPLICATION_NAME = "ApplicationName";
3232
private final ReentrantLock heartbeatLock = new ReentrantLock(false);
33-
private final ReentrantLock executorLock = new ReentrantLock(false);
3433
private final ReentrantLock notifyLock = new ReentrantLock(false);
3534
/**
3635
* The name given to this dataSource.
@@ -85,7 +84,7 @@ final class ConnectionPool implements DataSourcePool {
8584
private final PooledConnectionQueue queue;
8685
private Timer heartBeatTimer;
8786
private int heartbeatPoolExhaustedCount;
88-
private ExecutorService executor;
87+
private final ExecutorService executor;
8988

9089
/**
9190
* Used to find and close() leaked connections. Leaked connections are
@@ -140,6 +139,7 @@ final class ConnectionPool implements DataSourcePool {
140139
init();
141140
}
142141
this.nextTrimTime = System.currentTimeMillis() + trimPoolFreqMillis;
142+
this.executor = ExecutorFactory.newExecutor();
143143
}
144144

145145
private void init() {
@@ -195,7 +195,6 @@ private void tryEnsureMinimumConnections() {
195195
private void initialiseConnections() throws SQLException {
196196
long start = System.currentTimeMillis();
197197
dataSourceUp.set(true);
198-
startExecutor();
199198
if (failOnStart) {
200199
queue.ensureMinimumConnections();
201200
} else {
@@ -334,7 +333,6 @@ private void notifyUp() {
334333
// check such that we only notify once
335334
if (!dataSourceUp.get()) {
336335
dataSourceUp.set(true);
337-
startExecutor();
338336
startHeartBeatIfStopped();
339337
dataSourceDownReason = null;
340338
Log.error("RESOLVED FATAL: DataSource [" + name + "] is back up!");
@@ -657,11 +655,13 @@ public void offline() {
657655
shutdownPool(false, false);
658656
}
659657

660-
private void shutdownPool(boolean closeBusyConnections, boolean fromHook) {
658+
private void shutdownPool(boolean fullShutdown, boolean fromHook) {
661659
stopHeartBeatIfRunning();
662-
PoolStatus status = queue.shutdown(closeBusyConnections);
660+
PoolStatus status = queue.shutdown(fullShutdown);
663661
dataSourceUp.set(false);
664-
stopExecutor();
662+
if (fullShutdown) {
663+
shutdownExecutor();
664+
}
665665
if (fromHook) {
666666
Log.info("DataSource [{0}] shutdown on JVM exit {1} psc[hit:{2} miss:{3} put:{4} rem:{5}]", name, status, pscHit, pscMiss, pscPut, pscRem);
667667
} else {
@@ -751,51 +751,31 @@ public String toString() {
751751
* Closes the connection in the background as it may be slow or block.
752752
*/
753753
void closeConnectionFullyAsync(PooledConnection pc, boolean logErrors) {
754-
executorLock.lock();
755-
try {
756-
if (executor != null) {
754+
if (!executor.isShutdown()) {
755+
try {
757756
executor.submit(new AsyncCloser(pc, logErrors));
758757
return;
758+
} catch (RejectedExecutionException e) {
759+
Log.trace("DataSource [{0}] closing connection synchronously", name);
759760
}
760-
} finally {
761-
executorLock.unlock();
762761
}
763762
// it is possible that we receive runnables after shutdown.
764763
// in this case, we will execute them immediately (outside lock)
765764
pc.doCloseConnection(logErrors);
766765
}
767766

768-
private void startExecutor() {
769-
executorLock.lock();
767+
private void shutdownExecutor() {
768+
executor.shutdown();
770769
try {
771-
if (executor == null) {
772-
executor = ExecutorFactory.newExecutor();
770+
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
771+
Log.warn("DataSource [{0}] on shutdown, timeout waiting for connections to close", name);
773772
}
774-
} finally {
775-
executorLock.unlock();
773+
} catch (InterruptedException ie) {
774+
Log.warn("DataSource [{0}] on shutdown, interrupted closing connections", name, ie);
776775
}
777-
}
778-
779-
private void stopExecutor() {
780-
executorLock.lock();
781-
try {
782-
if (executor != null) {
783-
executor.shutdown();
784-
try {
785-
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
786-
Log.warn("DataSource [{0}] timeout waiting for connections to close", name);
787-
}
788-
} catch (InterruptedException ie) {
789-
Log.warn("DataSource [{0}] could not terminate executor.", name, ie);
790-
}
791-
final var pendingTasks = executor.shutdownNow();
792-
if (!pendingTasks.isEmpty()) {
793-
Log.warn("DataSource [{0}] {1} pending connections were not closed", name, pendingTasks.size());
794-
}
795-
executor = null;
796-
}
797-
} finally {
798-
executorLock.unlock();
776+
final var pendingTasks = executor.shutdownNow();
777+
if (!pendingTasks.isEmpty()) {
778+
Log.warn("DataSource [{0}] on shutdown, {1} pending connections were not closed", name, pendingTasks.size());
799779
}
800780
}
801781

0 commit comments

Comments
 (0)