Skip to content

Commit 69da13a

Browse files
authored
Merge pull request #149 from ebean-orm/feature/fix-close-busy-bug
Fix leak detection wrongly closing actively-in-use connections during…
2 parents 5e3ced8 + 7da5f4b commit 69da13a

3 files changed

Lines changed: 34 additions & 9 deletions

File tree

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,11 @@ void closeBusyConnections(long leakTimeMinutes) {
8989
Log.debug("Closing busy connections using leakTimeMinutes {0}", leakTimeMinutes);
9090
for (int i = 0; i < slots.length; i++) {
9191
if (slots[i] != null) {
92-
//tmp.add(slots[i]);
9392
PooledConnection pc = slots[i];
9493
//noinspection StatementWithEmptyBody
95-
if (pc.lastUsedTime() > olderThanTime) {
96-
// PooledConnection has been used recently or
97-
// expected to be longRunning so not closing...
94+
if (pc.startUseTime() > olderThanTime) {
95+
// PooledConnection was checked out recently so it is in active
96+
// use (not a leak) - leave it to be closed when returned to the pool
9897
} else {
9998
slots[i] = null;
10099
--size;
@@ -107,7 +106,6 @@ void closeBusyConnections(long leakTimeMinutes) {
107106
private void closeBusyConnection(PooledConnection pc) {
108107
try {
109108
Log.warn("DataSource closing busy connection? {0}", pc.fullDescription());
110-
System.out.println("CLOSING busy connection: " + pc.fullDescription());
111109
pc.closeConnectionFully(false);
112110
} catch (Exception ex) {
113111
Log.error("Error when closing potentially leaked connection " + pc.description(), ex);

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,12 @@ String fullDescription() {
232232
* @param logErrors if false then don't log errors when closing
233233
*/
234234
void closeConnectionFully(boolean logErrors) {
235-
if (Log.isLoggable(System.Logger.Level.TRACE)) {
236-
Log.trace("Closing Connection[{0}] reason[{1}], pstmtStats: {2}", name, closeReason, pstmtCache.description());
237-
}
238235
if (pool == null) {
239236
return; // this can happen in tests only.
240237
}
238+
if (Log.isLoggable(System.Logger.Level.TRACE)) {
239+
Log.trace("Closing Connection[{0}] reason[{1}], pstmtStats: {2}", name, closeReason, pstmtCache.description());
240+
}
241241
pool.pstmtCacheMetrics(pstmtCache);
242242
pool.closeConnectionFullyAsync(this, logErrors);
243243
}
@@ -585,7 +585,7 @@ boolean shouldTrim(long usedSince, long createdSince) {
585585
* <p>
586586
* Used to detect busy connections that could be leaks.
587587
*/
588-
private long startUseTime() {
588+
long startUseTime() {
589589
return startUseTime;
590590
}
591591

ebean-datasource/src/test/java/io/ebean/datasource/pool/BusyConnectionBufferTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import org.junit.jupiter.api.Test;
44

55
import static org.junit.jupiter.api.Assertions.assertEquals;
6+
import static org.junit.jupiter.api.Assertions.assertFalse;
7+
import static org.junit.jupiter.api.Assertions.assertTrue;
68

79
public class BusyConnectionBufferTest {
810

@@ -96,4 +98,29 @@ public void test_rotate() {
9698

9799
}
98100

101+
@Test
102+
public void closeBusyConnections_onlyClosesLeaks_notActiveConnections() {
103+
BusyConnectionBuffer b = new BusyConnectionBuffer(4, 4);
104+
105+
// a connection that was checked out long ago and never returned (a leak)
106+
PooledConnection leaked = new PooledConnection("leaked");
107+
// a connection that sat idle in the free list for a while then was just
108+
// checked out - it is in active use, not a leak (startUseTime is recent)
109+
PooledConnection active = new PooledConnection("active");
110+
active.resetForUse();
111+
112+
b.add(leaked);
113+
b.add(active);
114+
assertEquals(2, b.size());
115+
116+
// close connections considered leaked using a 1 minute leak time
117+
b.closeBusyConnections(1);
118+
119+
// the leaked connection is removed, the active connection is retained
120+
assertEquals(1, b.size());
121+
// active is still held in its slot, leaked is gone
122+
assertTrue(b.remove(active));
123+
assertFalse(b.remove(leaked));
124+
}
125+
99126
}

0 commit comments

Comments
 (0)