From 31447dd1e23ba72c89be91f08be258c2cacd6c63 Mon Sep 17 00:00:00 2001 From: Brett Wooldridge Date: Wed, 30 Sep 2015 00:49:49 +0900 Subject: [PATCH] Evict connection immediately upon broken state detection. --- .../com/zaxxer/hikari/pool/HikariPool.java | 13 ++++-------- .../com/zaxxer/hikari/pool/PoolEntry.java | 21 ++++++++++++------- .../zaxxer/hikari/pool/ProxyConnection.java | 12 +++++++---- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/zaxxer/hikari/pool/HikariPool.java b/src/main/java/com/zaxxer/hikari/pool/HikariPool.java index 3a87b7fe..d5c9e1ea 100644 --- a/src/main/java/com/zaxxer/hikari/pool/HikariPool.java +++ b/src/main/java/com/zaxxer/hikari/pool/HikariPool.java @@ -165,7 +165,7 @@ public class HikariPool extends PoolBase implements HikariPoolMXBean, IBagStateL } 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 timeout = hardTimeout - clockSource.elapsedMillis(startTime); } @@ -206,12 +206,7 @@ public class HikariPool extends PoolBase implements HikariPoolMXBean, IBagStateL { metricsTracker.recordConnectionUsage(poolEntry); - if (poolEntry.evict) { - closeConnection(poolEntry, "(connection broken or evicted)"); - } - else { - connectionBag.requite(poolEntry); - } + connectionBag.requite(poolEntry); } /** @@ -506,7 +501,7 @@ public class HikariPool extends PoolBase implements HikariPoolMXBean, IBagStateL { for (PoolEntry poolEntry : connectionBag.values(STATE_IN_USE)) { try { - poolEntry.evict = true; + poolEntry.markEvicted(); poolEntry.connection.abort(assassinExecutor); } 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) { - poolEntry.evict(); + poolEntry.markEvicted(); if (connectionBag.reserve(poolEntry) || owner) { closeConnection(poolEntry, reason); } diff --git a/src/main/java/com/zaxxer/hikari/pool/PoolEntry.java b/src/main/java/com/zaxxer/hikari/pool/PoolEntry.java index 320586b1..29e16473 100644 --- a/src/main/java/com/zaxxer/hikari/pool/PoolEntry.java +++ b/src/main/java/com/zaxxer/hikari/pool/PoolEntry.java @@ -42,10 +42,10 @@ final class PoolEntry implements IConcurrentBagEntry Connection connection; long lastAccessed; long lastBorrowed; - volatile boolean evict; + private volatile boolean evict; private final FastList openStatements; - private final PoolBase poolBase; + private final HikariPool hikariPool; private final AtomicInteger state; private volatile ScheduledFuture endOfLife; @@ -63,7 +63,7 @@ final class PoolEntry implements IConcurrentBagEntry PoolEntry(final Connection connection, final PoolBase pool) { this.connection = connection; - this.poolBase = pool; + this.hikariPool = (HikariPool) pool; this.state = new AtomicInteger(STATE_NOT_IN_USE); this.lastAccessed = ClockSource.INSTANCE.currentTime(); this.openStatements = new FastList<>(Statement.class, 16); @@ -77,7 +77,7 @@ final class PoolEntry implements IConcurrentBagEntry void recycle(final long 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 { - poolBase.resetConnectionState(connection, proxyConnection, dirtyBits); + hikariPool.resetConnectionState(connection, proxyConnection, dirtyBits); } String getPoolName() { - return poolBase.toString(); + return hikariPool.toString(); } Connection getConnection() @@ -108,16 +108,21 @@ final class PoolEntry implements IConcurrentBagEntry return connection; } - boolean isEvicted() + boolean isMarkedEvicted() { return evict; } - void evict() + void markEvicted() { this.evict = true; } + void evict(final String closureReason) + { + hikariPool.closeConnection(this, closureReason); + } + FastList getStatementsList() { return openStatements; diff --git a/src/main/java/com/zaxxer/hikari/pool/ProxyConnection.java b/src/main/java/com/zaxxer/hikari/pool/ProxyConnection.java index 3bb6ebfd..4a44e5b6 100644 --- a/src/main/java/com/zaxxer/hikari/pool/ProxyConnection.java +++ b/src/main/java/com/zaxxer/hikari/pool/ProxyConnection.java @@ -140,10 +140,12 @@ public abstract class ProxyConnection implements Connection String sqlState = sqle.getSQLState(); if (sqlState != null) { boolean isForceClose = sqlState.startsWith("08") || SQL_ERRORS.contains(sqlState); - if (isForceClose) { - poolEntry.evict(); + if (isForceClose && delegate != ClosedConnection.CLOSED_CONNECTION) { LOGGER.warn("{} - Connection {} marked as broken because of SQLSTATE({}), ErrorCode({})", poolEntry.getPoolName(), delegate, sqlState, sqle.getErrorCode(), sqle); + leakTask.cancel(); + delegate = ClosedConnection.CLOSED_CONNECTION; + poolEntry.evict("(connection broken)"); } else { SQLException nse = sqle.getNextException(); @@ -211,11 +213,13 @@ public abstract class ProxyConnection implements Connection @Override 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) { leakTask.cancel(); try { - closeStatements(); if (isCommitStateDirty && !isAutoCommit) { delegate.rollback(); lastAccess = clockSource.currentTime(); @@ -231,7 +235,7 @@ public abstract class ProxyConnection implements Connection } catch (SQLException e) { // when connections are aborted, exceptions are often thrown that should not reach the application - if (!poolEntry.isEvicted()) { + if (!poolEntry.isMarkedEvicted()) { throw checkException(e); } }