Skip to content

Commit 7b508b0

Browse files
committed
Better recovery after reset on high pool load
1 parent e8c042e commit 7b508b0

File tree

2 files changed

+90
-11
lines changed

2 files changed

+90
-11
lines changed

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

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -226,18 +226,13 @@ private PooledConnection _obtainConnection() throws InterruptedException, SQLExc
226226
hitCount++;
227227
// are other threads already waiting? (they get priority)
228228
if (waitingThreads == 0) {
229-
PooledConnection freeConnection = extractFromFreeList();
230-
if (freeConnection != null) {
231-
return freeConnection;
229+
PooledConnection connection = extractFromFreeList();
230+
if (connection != null) {
231+
return connection;
232232
}
233-
if (busyList.size() < maxSize) {
234-
// grow the connection pool
235-
PooledConnection c = pool.createConnectionForQueue(connectionId++);
236-
int busySize = registerBusyConnection(c);
237-
if (Log.isLoggable(DEBUG)) {
238-
Log.debug("DataSource [{0}] grow; id[{1}] busy[{2}] max[{3}]", name, c.name(), busySize, maxSize);
239-
}
240-
return c;
233+
connection = createConnection();
234+
if (connection != null) {
235+
return connection;
241236
}
242237
}
243238
try {
@@ -257,13 +252,32 @@ private PooledConnection _obtainConnection() throws InterruptedException, SQLExc
257252
}
258253
}
259254

255+
private PooledConnection createConnection() throws SQLException {
256+
if (busyList.size() < maxSize) {
257+
// grow the connection pool
258+
PooledConnection c = pool.createConnectionForQueue(connectionId++);
259+
int busySize = registerBusyConnection(c);
260+
if (Log.isLoggable(DEBUG)) {
261+
Log.debug("DataSource [{0}] grow; id[{1}] busy[{2}] max[{3}]", name, c.name(), busySize, maxSize);
262+
}
263+
return c;
264+
} else {
265+
return null;
266+
}
267+
}
268+
260269
/**
261270
* Got into a loop waiting for connections to be returned to the pool.
262271
*/
263272
private PooledConnection _obtainConnectionWaitLoop() throws SQLException, InterruptedException {
264273
long nanos = MILLIS_TIME_UNIT.toNanos(waitTimeoutMillis);
265274
for (; ; ) {
266275
if (nanos <= 0) {
276+
// We waited long enough, that a connection was returned, so we try to create a new connection.
277+
PooledConnection conn = createConnection();
278+
if (conn != null) {
279+
return conn;
280+
}
267281
String msg = "Unsuccessfully waited [" + waitTimeoutMillis + "] millis for a connection to be returned."
268282
+ " No connections are free. You need to Increase the max connections of [" + maxSize + "]"
269283
+ " or look for a connection pool leak using datasource.xxx.capturestacktrace=true";
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package io.ebean.datasource.pool;
2+
3+
import io.ebean.datasource.DataSourceBuilder;
4+
import io.ebean.datasource.DataSourcePool;
5+
import org.junit.jupiter.api.Test;
6+
7+
import java.sql.Connection;
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
import java.util.concurrent.ExecutorService;
11+
import java.util.concurrent.Executors;
12+
import java.util.concurrent.Future;
13+
14+
import static org.assertj.core.api.Assertions.assertThat;
15+
16+
public class ConnectionPoolRecoverTest {
17+
18+
private int success;
19+
private int failure;
20+
21+
@Test
22+
void testHeavyLoadPool() throws Exception {
23+
DataSourcePool pool = DataSourceBuilder.create()
24+
.url("jdbc:h2:mem:testConnectionPoolFull")
25+
.username("sa")
26+
.password("sa")
27+
.heartbeatFreqSecs(1)
28+
.minConnections(1)
29+
.maxConnections(1)
30+
.trimPoolFreqSecs(1)
31+
// .heartbeatMaxPoolExhaustedCount(1)
32+
.failOnStart(false)
33+
.build();
34+
ExecutorService executorService = Executors.newCachedThreadPool();
35+
try {
36+
List<Future<?>> futures = new ArrayList<>();
37+
for (int i = 0; i < 2; i++) {
38+
futures.add(executorService.submit(() -> doSomeWork(pool)));
39+
}
40+
41+
for (Future<?> future : futures) {
42+
future.get();
43+
}
44+
assertThat(success).isGreaterThan(1);
45+
} finally {
46+
executorService.shutdownNow();
47+
pool.shutdown();
48+
}
49+
50+
}
51+
52+
private void doSomeWork(DataSourcePool pool) {
53+
for (int i = 0; i < 20; i++) {
54+
System.out.println("Success: " + success + " failure: " + failure);
55+
try (Connection conn = pool.getConnection()) {
56+
Thread.sleep(2000);
57+
success++;
58+
} catch (Exception e) {
59+
// nop
60+
failure++;
61+
}
62+
}
63+
}
64+
65+
}

0 commit comments

Comments
 (0)