Skip to content

Commit 928389b

Browse files
committed
Minor improvements
1 parent edb8f8a commit 928389b

File tree

3 files changed

+86
-5
lines changed

3 files changed

+86
-5
lines changed

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

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import java.util.*;
99
import java.util.concurrent.ExecutorService;
1010
import java.util.concurrent.Executors;
11+
import java.util.concurrent.ThreadPoolExecutor;
12+
import java.util.concurrent.TimeUnit;
1113
import java.util.concurrent.atomic.AtomicBoolean;
1214
import java.util.concurrent.atomic.AtomicInteger;
1315
import java.util.concurrent.atomic.LongAdder;
@@ -733,19 +735,45 @@ private void stopHeartBeatIfRunning() {
733735
}
734736
}
735737

736-
void execute(Runnable runable) {
738+
static class AsyncCloser implements Runnable {
739+
final PooledConnection pc;
740+
final boolean logErrors;
741+
742+
public AsyncCloser(PooledConnection pc, boolean logErrors) {
743+
this.pc = pc;
744+
this.logErrors = logErrors;
745+
}
746+
747+
@Override
748+
public void run() {
749+
pc.doCloseConnection(logErrors);
750+
}
751+
752+
@Override
753+
public String toString() {
754+
return pc.toString();
755+
}
756+
}
757+
758+
/**
759+
* Tries to close the pc in an async thread. The method waits up to 5 seconds and returns true,
760+
* if connection was closed in this time.
761+
* <p>
762+
* If the connection could not be closed within 5 seconds,
763+
*/
764+
void closeConnectionFullyAsync(PooledConnection pc, boolean logErrors) {
737765
executorLock.lock();
738766
try {
739767
if (executor != null) {
740-
executor.submit(runable);
768+
executor.submit(new AsyncCloser(pc, logErrors));
741769
return;
742770
}
743771
} finally {
744772
executorLock.unlock();
745773
}
746774
// it is possible, that we receive runnables after shutdown.
747775
// in this case, we will execute them immediately (outside lock)
748-
runable.run();
776+
pc.doCloseConnection(logErrors);
749777
}
750778

751779
private void startExecutor() {
@@ -764,6 +792,13 @@ private void stopExecutor() {
764792
try {
765793
if (executor != null) {
766794
executor.shutdown();
795+
try {
796+
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
797+
Log.warn("DataSource [{0}] could not terminate executor.", name);
798+
}
799+
} catch (InterruptedException ie) {
800+
Log.warn("DataSource [{0}] could not terminate executor.", name, ie);
801+
}
767802
executor = null;
768803
}
769804
} finally {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,13 @@ void closeConnectionFully(boolean logErrors) {
239239
return; // this can happen in tests only.
240240
}
241241
pool.pstmtCacheMetrics(pstmtCache);
242-
pool.execute(() -> doCloseConnection(logErrors));
242+
pool.closeConnectionFullyAsync(this, logErrors);
243243
}
244244

245245
/**
246246
* this mehthod performs network IO and may block
247247
*/
248-
private void doCloseConnection(boolean logErrors) {
248+
void doCloseConnection(boolean logErrors) {
249249
long start = System.nanoTime();
250250
try {
251251
try {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package io.ebean.datasource.pool;
2+
3+
import io.ebean.datasource.DataSourceBuilder;
4+
import io.ebean.datasource.DataSourcePool;
5+
import org.h2.jdbc.JdbcConnection;
6+
import org.junit.jupiter.api.Disabled;
7+
import org.junit.jupiter.api.Test;
8+
9+
import java.sql.Connection;
10+
11+
public class ConnectionPoolHangUpTest {
12+
13+
@Test
14+
@Disabled("run manually")
15+
void testHoldLockOnObject() throws Exception {
16+
DataSourcePool pool = DataSourceBuilder.create()
17+
.url("jdbc:h2:mem:testConnectionPoolHangUp")
18+
.username("sa")
19+
.password("sa")
20+
.heartbeatFreqSecs(1)
21+
.minConnections(1)
22+
.maxConnections(1)
23+
.trimPoolFreqSecs(1)
24+
.heartbeatMaxPoolExhaustedCount(0)
25+
.failOnStart(false)
26+
.build();
27+
try {
28+
Connection conn = pool.getConnection();
29+
Thread t = new Thread(() -> {
30+
try {
31+
JdbcConnection h2Conn = conn.unwrap(JdbcConnection.class);
32+
synchronized (h2Conn) {
33+
Thread.sleep(300000);
34+
}
35+
} catch (Exception e) {
36+
// nop
37+
}
38+
});
39+
t.setDaemon(true);
40+
t.start();
41+
} finally {
42+
pool.shutdown();
43+
}
44+
}
45+
46+
}

0 commit comments

Comments
 (0)