Skip to content

Commit c7f0922

Browse files
committed
ConnectionBuffer maintains free and busy connections as LinkedList now
1 parent ce090ad commit c7f0922

6 files changed

Lines changed: 229 additions & 321 deletions

File tree

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

Lines changed: 0 additions & 159 deletions
This file was deleted.

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

Lines changed: 114 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,22 @@
55
/**
66
* A buffer designed especially to hold pooled connections (free and busy ones)
77
* <p>
8+
* The buffer contains two linkedLists (free and busy connection nodes)
9+
* <p>
10+
* When a node from the free list is removed, the node is attached to the
11+
* PooledConnection, so that the node object can be reused. This avoids object
12+
* creation/gc during remove operations.
13+
* <p>
814
* All thread safety controlled externally (by PooledConnectionQueue).
915
* </p>
1016
*/
1117
final class ConnectionBuffer {
1218

13-
1419
private final Node free = Node.init();
20+
private final Node busy = Node.init();
1521

1622
int freeSize = 0;
23+
int busySize = 0;
1724

1825
/**
1926
* Return the number of entries in the buffer.
@@ -22,6 +29,13 @@ int freeSize() {
2229
return freeSize;
2330
}
2431

32+
/**
33+
* Return the number of busy connections.
34+
*/
35+
int busySize() {
36+
return busySize;
37+
}
38+
2539
/**
2640
* Return true if the buffer is empty.
2741
*/
@@ -30,28 +44,74 @@ boolean hasFreeConnections() {
3044
}
3145

3246
/**
33-
* Add connection to the free list.
47+
* Adds a new connection to the free list.
3448
*/
3549
void addFree(PooledConnection pc) {
50+
assert pc.busyNode() == null : "Connection seems not to be new";
3651
new Node(pc).addAfter(free);
3752
freeSize++;
3853
}
3954

55+
/**
56+
* Removes the connection from the busy list. (For full close)
57+
* Returns true, if this connection was part of the busy list or false, if not (or removed twice)
58+
*/
59+
boolean removeBusy(PooledConnection c) {
60+
if (c.busyNode() == null) {
61+
return false;
62+
}
63+
c.busyNode().remove();
64+
busySize--;
65+
c.setBusyNode(null);
66+
return true;
67+
}
68+
69+
/**
70+
* Moves the connection from the busy list to the free list.
71+
*/
72+
boolean moveToFreeList(PooledConnection c) {
73+
Node node = c.busyNode();
74+
if (node == null) {
75+
return false;
76+
}
77+
node.remove();
78+
busySize--;
79+
node.addAfter(free);
80+
freeSize++;
81+
c.setBusyNode(null);
82+
return true;
83+
}
84+
4085
/**
4186
* Remove a connection from the free list. Returns <code>null</code> if there is not any.
4287
*/
43-
PooledConnection popFree () {
88+
PooledConnection popFree() {
4489
Node node = free.next;
4590
if (node.isBoundaryNode()) {
4691
return null;
4792
}
4893
node.remove();
4994
freeSize--;
95+
node.pc.setBusyNode(node); // sets the node for reuse in "addBusy"
5096
return node.pc;
5197
}
5298

5399
/**
54-
* Close all connections in the free list.
100+
* Adds the connection to the busy list. The connection must be either new or popped from the free list.
101+
*/
102+
int addBusy(PooledConnection c) {
103+
Node node = c.busyNode(); // we try to reuse the node to avoid object creation.
104+
if (node == null) {
105+
node = new Node(c);
106+
c.setBusyNode(node);
107+
}
108+
node.addAfter(busy);
109+
busySize++;
110+
return busySize;
111+
}
112+
113+
/**
114+
* Close all free connections in this buffer.
55115
*/
56116
void closeAllFree(boolean logErrors) {
57117
List<PooledConnection> tempList = new ArrayList<>();
@@ -92,6 +152,56 @@ int trim(int minSize, long usedSince, long createdSince) {
92152
return trimCount;
93153
}
94154

155+
void closeBusyConnections(long leakTimeMinutes) {
156+
long olderThanTime = System.currentTimeMillis() - (leakTimeMinutes * 60000);
157+
Log.debug("Closing busy connections using leakTimeMinutes {0}", leakTimeMinutes);
158+
Node node = busy.next;
159+
while (!node.isBoundaryNode()) {
160+
Node current = node;
161+
node = node.next;
162+
163+
PooledConnection pc = current.pc;
164+
//noinspection StatementWithEmptyBody
165+
if (pc.lastUsedTime() > olderThanTime) {
166+
// PooledConnection has been used recently or
167+
// expected to be longRunning so not closing...
168+
} else {
169+
current.remove();
170+
--busySize;
171+
closeBusyConnection(pc);
172+
}
173+
}
174+
}
175+
176+
private void closeBusyConnection(PooledConnection pc) {
177+
try {
178+
Log.warn("DataSource closing busy connection? {0}", pc.fullDescription());
179+
System.out.println("CLOSING busy connection: " + pc.fullDescription());
180+
pc.closeConnectionFully(false);
181+
} catch (Exception ex) {
182+
Log.error("Error when closing potentially leaked connection " + pc.description(), ex);
183+
}
184+
}
185+
186+
String busyConnectionInformation(boolean toLogger) {
187+
if (toLogger) {
188+
Log.info("Dumping [{0}] busy connections: (Use datasource.xxx.capturestacktrace=true ... to get stackTraces)", busySize());
189+
}
190+
StringBuilder sb = new StringBuilder();
191+
Node node = busy.next;
192+
while (!node.isBoundaryNode()) {
193+
PooledConnection pc = node.pc;
194+
node = node.next;
195+
if (toLogger) {
196+
Log.info("Busy Connection - {0}", pc.fullDescription());
197+
} else {
198+
sb.append(pc.fullDescription()).append("\r\n");
199+
}
200+
}
201+
return sb.toString();
202+
}
203+
204+
95205
/**
96206
* Node of a linkedlist. The linkedLists always have two empty nodes at the start and end.
97207
* (boundary nodes) They are generated with the init() method.

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
package io.ebean.datasource.pool;
22

3-
import java.sql.*;
3+
import java.sql.CallableStatement;
4+
import java.sql.Connection;
5+
import java.sql.DatabaseMetaData;
6+
import java.sql.PreparedStatement;
7+
import java.sql.SQLException;
8+
import java.sql.SQLWarning;
9+
import java.sql.Savepoint;
10+
import java.sql.Statement;
411
import java.util.ArrayList;
512
import java.util.Map;
613
import java.util.concurrent.locks.ReentrantLock;
@@ -135,7 +142,7 @@ final class PooledConnection extends ConnectionDelegator {
135142
/**
136143
* Slot position in the BusyConnectionBuffer.
137144
*/
138-
private int slotId;
145+
private ConnectionBuffer.Node busyNode;
139146

140147

141148
/**
@@ -184,17 +191,17 @@ final class PooledConnection extends ConnectionDelegator {
184191
}
185192

186193
/**
187-
* Return the slot position in the busy buffer.
194+
* Return the node in the busy list. If this is empty, the connection is free
188195
*/
189-
int slotId() {
190-
return slotId;
196+
ConnectionBuffer.Node busyNode() {
197+
return busyNode;
191198
}
192199

193200
/**
194-
* Set the slot position in the busy buffer.
201+
* Set the busy node.
195202
*/
196-
void setSlotId(int slotId) {
197-
this.slotId = slotId;
203+
void setBusyNode(ConnectionBuffer.Node busyNode) {
204+
this.busyNode = busyNode;
198205
}
199206

200207
/**

0 commit comments

Comments
 (0)