How druid CP recycles connections
Selected data structures
public final class DruidConnectionHolder {
protected final DruidAbstractDataSource dataSource;
protected final long connectionId;
protected final Connection conn;
protected final List<ConnectionEventListener> connectionEventListeners = new CopyOnWriteArrayList<ConnectionEventListener>();
protected final List<StatementEventListener> statementEventListeners = new CopyOnWriteArrayList<StatementEventListener>();
protected final long connectTimeMillis;
protected volatile long lastActiveTimeMillis;
protected volatile long lastExecTimeMillis;
protected volatile long lastKeepTimeMillis;
protected volatile long lastValidTimeMillis;
protected long useCount = 0;
private long keepAliveCheckCount = 0;
private long lastNotEmptyWaitNanos;
private final long createNanoSpan;
protected PreparedStatementPool statementPool;
protected final List<Statement> statementTrace = new ArrayList<Statement>(2);
protected final boolean defaultReadOnly;
protected final int defaultHoldability;
protected final int defaultTransactionIsolation;
protected final boolean defaultAutoCommit;
protected boolean underlyingReadOnly;
protected int underlyingHoldability;
protected int underlyingTransactionIsolation;
protected boolean underlyingAutoCommit;
protected volatile boolean discard = false;
protected volatile boolean active = false;
protected final Map<String, Object> variables;
protected final Map<String, Object> globleVariables;
final ReentrantLock lock = new ReentrantLock();
}
How shrink() works
Assume we turn on time check and keep-alive
DruidConnectionHolder connection = connections[i];
long idleMillis = currentTimeMillis - connection.lastActiveTimeMillis;
if (idleMillis < minEvictableIdleTimeMillis
&& idleMillis < keepAliveBetweenTimeMillis) {
break; //stop shrinking all together
}
if (idleMillis >= minEvictableIdleTimeMillis) {
if (checkTime && i < checkCount) {
evictConnections[evictCount++] = connection;
continue;
} else if (idleMillis > maxEvictableIdleTimeMillis) {
evictConnections[evictCount++] = connection;
continue;
}
}
if (keepAlive && idleMillis >= keepAliveBetweenTimeMillis) {
keepAliveConnections[keepAliveCount++] = connection;
}
int removeCount = evictCount + keepAliveCount;
if (removeCount > 0) {
System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);
Arrays.fill(connections, poolingCount - removeCount, poolingCount, null);
poolingCount -= removeCount;
}
- After this check, it will validate connections for all that requires keep alive
- Finally
int fillCount = minIdle - (activeCount + poolingCount + createTaskCount); for (int i = 0; i < fillCount; ++i) { emptySignal(); }
- Validation is done via
MySqlValidConnectionChecker
and if it is not set
String query = validateQuery;
if (validateQuery == null || validateQuery.isEmpty()) {
query = DEFAULT_VALIDATION_QUERY;
}
Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
if (validationQueryTimeout > 0) {
stmt.setQueryTimeout(validationQueryTimeout);
}
rs = stmt.executeQuery(query);
return true;
} finally {
JdbcUtils.close(rs);
JdbcUtils.close(stmt);
}