Source:
<code>public final Connection getConnection(final long hardTimeout) throws SQLException { suspendResumeLock.acquire(); final long startTime = clockSource.currentTime(); try { long timeout = hardTimeout; do { final PoolEntry poolEntry = connectionBag.borrow(timeout, TimeUnit.MILLISECONDS); if (poolEntry == null) { break; } final long now = clockSource.currentTime(); if (poolEntry.isMarkedEvicted() || (clockSource.elapsedMillis(poolEntry.lastAccessed, now) > ALIVE_BYPASS_WINDOW_MS && !isConnectionAlive(poolEntry.connection))) { <START> closeConnection(poolEntry, "(connection is dead)"); END> timeout = hardTimeout - clockSource.elapsedMillis(startTime); } else { metricsTracker.recordBorrowStats(poolEntry, startTime); return poolEntry.createProxyConnection(leakTask.start(poolEntry), now); } } while (timeout > 0L); } catch (InterruptedException e) { throw new SQLException(poolName + " - Interrupted during connection acquisition", e); } finally { suspendResumeLock.release(); } logPoolState("Timeout failure "); metricsTracker.recordConnectionTimeout(); String sqlState = null; final Throwable originalException = getLastConnectionFailure(); if (originalException instanceof SQLException) { sqlState = ((SQLException) originalException).getSQLState(); } final SQLException connectionException = new SQLTransientConnectionException(poolName + " - Connection is not available, request timed out after " + clockSource.elapsedMillis(startTime) + "ms.", sqlState, originalException); if (originalException instanceof SQLException) { connectionException.setNextException((SQLException) originalException); } throw connectionException; }</code><technical_language>I prefer more explicit message. Put change to: closeConnection(poolEntry, "(connection is " + (poolEntry.isMarkedEvicted() ? "evicted)" : "dead)");</technical_language>

Target:
public final Connection getConnection(final long hardTimeout) throws SQLException { suspendResumeLock.acquire(); final long startTime = clockSource.currentTime(); try { long timeout = hardTimeout; do { final PoolEntry poolEntry = connectionBag.borrow(timeout, TimeUnit.MILLISECONDS); if (poolEntry == null) { break; } final long now = clockSource.currentTime(); if (poolEntry.isMarkedEvicted() || (clockSource.elapsedMillis(poolEntry.lastAccessed, now) > ALIVE_BYPASS_WINDOW_MS && !isConnectionAlive(poolEntry.connection))) { closeConnection(poolEntry, "(connection is evicted or dead)"); timeout = hardTimeout - clockSource.elapsedMillis(startTime); } else { metricsTracker.recordBorrowStats(poolEntry, startTime); return poolEntry.createProxyConnection(leakTask.start(poolEntry), now); } } while (timeout > 0L); } catch (InterruptedException e) { throw new SQLException(poolName + " - Interrupted during connection acquisition", e); } finally { suspendResumeLock.release(); } logPoolState("Timeout failure "); metricsTracker.recordConnectionTimeout(); String sqlState = null; final Throwable originalException = getLastConnectionFailure(); if (originalException instanceof SQLException) { sqlState = ((SQLException) originalException).getSQLState(); } final SQLException connectionException = new SQLTransientConnectionException(poolName + " - Connection is not available, request timed out after " + clockSource.elapsedMillis(startTime) + "ms.", sqlState, originalException); if (originalException instanceof SQLException) { connectionException.setNextException((SQLException) originalException); } throw connectionException; }