Evict connection immediately upon broken state detection.

pull/437/head
Brett Wooldridge 10 years ago
parent 79386c6487
commit 31447dd1e2

@ -165,7 +165,7 @@ public class HikariPool extends PoolBase implements HikariPoolMXBean, IBagStateL
} }
final long now = clockSource.currentTime(); final long now = clockSource.currentTime();
if (poolEntry.evict || (clockSource.elapsedMillis(poolEntry.lastAccessed, now) > ALIVE_BYPASS_WINDOW_MS && !isConnectionAlive(poolEntry.connection))) { if (poolEntry.isMarkedEvicted() || (clockSource.elapsedMillis(poolEntry.lastAccessed, now) > ALIVE_BYPASS_WINDOW_MS && !isConnectionAlive(poolEntry.connection))) {
closeConnection(poolEntry, "(connection evicted or dead)"); // Throw away the dead connection and try again closeConnection(poolEntry, "(connection evicted or dead)"); // Throw away the dead connection and try again
timeout = hardTimeout - clockSource.elapsedMillis(startTime); timeout = hardTimeout - clockSource.elapsedMillis(startTime);
} }
@ -206,13 +206,8 @@ public class HikariPool extends PoolBase implements HikariPoolMXBean, IBagStateL
{ {
metricsTracker.recordConnectionUsage(poolEntry); metricsTracker.recordConnectionUsage(poolEntry);
if (poolEntry.evict) {
closeConnection(poolEntry, "(connection broken or evicted)");
}
else {
connectionBag.requite(poolEntry); connectionBag.requite(poolEntry);
} }
}
/** /**
* Shutdown the pool, closing all idle connections and aborting or closing * Shutdown the pool, closing all idle connections and aborting or closing
@ -506,7 +501,7 @@ public class HikariPool extends PoolBase implements HikariPoolMXBean, IBagStateL
{ {
for (PoolEntry poolEntry : connectionBag.values(STATE_IN_USE)) { for (PoolEntry poolEntry : connectionBag.values(STATE_IN_USE)) {
try { try {
poolEntry.evict = true; poolEntry.markEvicted();
poolEntry.connection.abort(assassinExecutor); poolEntry.connection.abort(assassinExecutor);
} }
catch (Throwable e) { catch (Throwable e) {
@ -557,7 +552,7 @@ public class HikariPool extends PoolBase implements HikariPoolMXBean, IBagStateL
private void softEvictConnection(final PoolEntry poolEntry, final String reason, final boolean owner) private void softEvictConnection(final PoolEntry poolEntry, final String reason, final boolean owner)
{ {
poolEntry.evict(); poolEntry.markEvicted();
if (connectionBag.reserve(poolEntry) || owner) { if (connectionBag.reserve(poolEntry) || owner) {
closeConnection(poolEntry, reason); closeConnection(poolEntry, reason);
} }

@ -42,10 +42,10 @@ final class PoolEntry implements IConcurrentBagEntry
Connection connection; Connection connection;
long lastAccessed; long lastAccessed;
long lastBorrowed; long lastBorrowed;
volatile boolean evict; private volatile boolean evict;
private final FastList<Statement> openStatements; private final FastList<Statement> openStatements;
private final PoolBase poolBase; private final HikariPool hikariPool;
private final AtomicInteger state; private final AtomicInteger state;
private volatile ScheduledFuture<?> endOfLife; private volatile ScheduledFuture<?> endOfLife;
@ -63,7 +63,7 @@ final class PoolEntry implements IConcurrentBagEntry
PoolEntry(final Connection connection, final PoolBase pool) PoolEntry(final Connection connection, final PoolBase pool)
{ {
this.connection = connection; this.connection = connection;
this.poolBase = pool; this.hikariPool = (HikariPool) pool;
this.state = new AtomicInteger(STATE_NOT_IN_USE); this.state = new AtomicInteger(STATE_NOT_IN_USE);
this.lastAccessed = ClockSource.INSTANCE.currentTime(); this.lastAccessed = ClockSource.INSTANCE.currentTime();
this.openStatements = new FastList<>(Statement.class, 16); this.openStatements = new FastList<>(Statement.class, 16);
@ -77,7 +77,7 @@ final class PoolEntry implements IConcurrentBagEntry
void recycle(final long lastAccessed) void recycle(final long lastAccessed)
{ {
this.lastAccessed = lastAccessed; this.lastAccessed = lastAccessed;
poolBase.releaseConnection(this); hikariPool.releaseConnection(this);
} }
/** /**
@ -95,12 +95,12 @@ final class PoolEntry implements IConcurrentBagEntry
void resetConnectionState(final ProxyConnection proxyConnection, final int dirtyBits) throws SQLException void resetConnectionState(final ProxyConnection proxyConnection, final int dirtyBits) throws SQLException
{ {
poolBase.resetConnectionState(connection, proxyConnection, dirtyBits); hikariPool.resetConnectionState(connection, proxyConnection, dirtyBits);
} }
String getPoolName() String getPoolName()
{ {
return poolBase.toString(); return hikariPool.toString();
} }
Connection getConnection() Connection getConnection()
@ -108,16 +108,21 @@ final class PoolEntry implements IConcurrentBagEntry
return connection; return connection;
} }
boolean isEvicted() boolean isMarkedEvicted()
{ {
return evict; return evict;
} }
void evict() void markEvicted()
{ {
this.evict = true; this.evict = true;
} }
void evict(final String closureReason)
{
hikariPool.closeConnection(this, closureReason);
}
FastList<Statement> getStatementsList() FastList<Statement> getStatementsList()
{ {
return openStatements; return openStatements;

@ -140,10 +140,12 @@ public abstract class ProxyConnection implements Connection
String sqlState = sqle.getSQLState(); String sqlState = sqle.getSQLState();
if (sqlState != null) { if (sqlState != null) {
boolean isForceClose = sqlState.startsWith("08") || SQL_ERRORS.contains(sqlState); boolean isForceClose = sqlState.startsWith("08") || SQL_ERRORS.contains(sqlState);
if (isForceClose) { if (isForceClose && delegate != ClosedConnection.CLOSED_CONNECTION) {
poolEntry.evict();
LOGGER.warn("{} - Connection {} marked as broken because of SQLSTATE({}), ErrorCode({})", LOGGER.warn("{} - Connection {} marked as broken because of SQLSTATE({}), ErrorCode({})",
poolEntry.getPoolName(), delegate, sqlState, sqle.getErrorCode(), sqle); poolEntry.getPoolName(), delegate, sqlState, sqle.getErrorCode(), sqle);
leakTask.cancel();
delegate = ClosedConnection.CLOSED_CONNECTION;
poolEntry.evict("(connection broken)");
} }
else { else {
SQLException nse = sqle.getNextException(); SQLException nse = sqle.getNextException();
@ -211,11 +213,13 @@ public abstract class ProxyConnection implements Connection
@Override @Override
public final void close() throws SQLException public final void close() throws SQLException
{ {
// Closing statements can cause connection eviction, so this must run before the conditional below
closeStatements();
if (delegate != ClosedConnection.CLOSED_CONNECTION) { if (delegate != ClosedConnection.CLOSED_CONNECTION) {
leakTask.cancel(); leakTask.cancel();
try { try {
closeStatements();
if (isCommitStateDirty && !isAutoCommit) { if (isCommitStateDirty && !isAutoCommit) {
delegate.rollback(); delegate.rollback();
lastAccess = clockSource.currentTime(); lastAccess = clockSource.currentTime();
@ -231,7 +235,7 @@ public abstract class ProxyConnection implements Connection
} }
catch (SQLException e) { catch (SQLException e) {
// when connections are aborted, exceptions are often thrown that should not reach the application // when connections are aborted, exceptions are often thrown that should not reach the application
if (!poolEntry.isEvicted()) { if (!poolEntry.isMarkedEvicted()) {
throw checkException(e); throw checkException(e);
} }
} }

Loading…
Cancel
Save