diff --git a/hikaricp-common/src/main/java/com/zaxxer/hikari/AbstractHikariConfig.java b/hikaricp-common/src/main/java/com/zaxxer/hikari/AbstractHikariConfig.java index 44fe4b59..4dc4d067 100644 --- a/hikaricp-common/src/main/java/com/zaxxer/hikari/AbstractHikariConfig.java +++ b/hikaricp-common/src/main/java/com/zaxxer/hikari/AbstractHikariConfig.java @@ -39,6 +39,7 @@ public abstract class AbstractHikariConfig implements HikariConfigMBean private static final Logger LOGGER = LoggerFactory.getLogger(HikariConfig.class); private static final long CONNECTION_TIMEOUT = TimeUnit.SECONDS.toMillis(30); + private static final long VALIDATION_TIMEOUT = TimeUnit.SECONDS.toMillis(5); private static final long IDLE_TIMEOUT = TimeUnit.MINUTES.toMillis(10); private static final long MAX_LIFETIME = TimeUnit.MINUTES.toMillis(30); @@ -48,6 +49,7 @@ public abstract class AbstractHikariConfig implements HikariConfigMBean // Properties changeable at runtime through the MBean // private volatile long connectionTimeout; + private volatile long validationTimeout; private volatile long idleTimeout; private volatile long leakDetectionThreshold; private volatile long maxLifetime; @@ -88,6 +90,7 @@ public abstract class AbstractHikariConfig implements HikariConfigMBean dataSourceProperties = new Properties(); connectionTimeout = CONNECTION_TIMEOUT; + validationTimeout = VALIDATION_TIMEOUT; idleTimeout = IDLE_TIMEOUT; isAutoCommit = true; isInitializationFailFast = true; @@ -263,14 +266,33 @@ public abstract class AbstractHikariConfig implements HikariConfigMBean if (connectionTimeoutMs == 0) { this.connectionTimeout = Integer.MAX_VALUE; } - else if (connectionTimeoutMs < 100) { - throw new IllegalArgumentException("connectionTimeout cannot be less than 100ms"); + else if (connectionTimeoutMs < 1000) { + throw new IllegalArgumentException("connectionTimeout cannot be less than 1000ms"); } else { this.connectionTimeout = connectionTimeoutMs; } } + /** {@inheritDoc} */ + @Override + public long getValidationTimeout() + { + return validationTimeout; + } + + /** {@inheritDoc} */ + @Override + public void setValidationTimeout(long validationTimeoutMs) + { + if (validationTimeoutMs < 1000) { + throw new IllegalArgumentException("connectionTimeout cannot be less than 1000ms"); + } + else { + this.validationTimeout = validationTimeoutMs; + } + } + /** * Get the {@link DataSource} that has been explicitly specified to be wrapped by the * pool. @@ -708,6 +730,11 @@ public abstract class AbstractHikariConfig implements HikariConfigMBean logger.warn("No connection wait timeout is set, this might cause an infinite wait."); } + if (validationTimeout > connectionTimeout) { + logger.warn("validationTimeout is greater than connectionTimeout, setting validationTimeout to connectionTimeout."); + validationTimeout = connectionTimeout; + } + if (minIdle < 0 || minIdle > maxPoolSize) { minIdle = maxPoolSize; } diff --git a/hikaricp-common/src/main/java/com/zaxxer/hikari/HikariConfigMBean.java b/hikaricp-common/src/main/java/com/zaxxer/hikari/HikariConfigMBean.java index 8b55741a..11d8f95f 100644 --- a/hikaricp-common/src/main/java/com/zaxxer/hikari/HikariConfigMBean.java +++ b/hikaricp-common/src/main/java/com/zaxxer/hikari/HikariConfigMBean.java @@ -41,6 +41,22 @@ public interface HikariConfigMBean */ void setConnectionTimeout(long connectionTimeoutMs); + /** + * Get the maximum number of milliseconds that the pool will wait for a connection to be validated as + * alive. + * + * @return the validation timeout in milliseconds + */ + long getValidationTimeout(); + + /** + * Sets the maximum number of milliseconds that the pool will wait for a connection to be validated as + * alive. + * + * @param validationTimeoutMs the validation timeout in milliseconds + */ + void setValidationTimeout(long validationTimeoutMs); + /** * This property controls the maximum amount of time (in milliseconds) that a connection is allowed to sit * idle in the pool. Whether a connection is retired as idle or not is subject to a maximum variation of +30 diff --git a/hikaricp-common/src/main/java/com/zaxxer/hikari/pool/BaseHikariPool.java b/hikaricp-common/src/main/java/com/zaxxer/hikari/pool/BaseHikariPool.java index a6347a9f..28aa9c7f 100644 --- a/hikaricp-common/src/main/java/com/zaxxer/hikari/pool/BaseHikariPool.java +++ b/hikaricp-common/src/main/java/com/zaxxer/hikari/pool/BaseHikariPool.java @@ -89,6 +89,7 @@ public abstract class BaseHikariPool implements HikariPoolMBean, IBagStateListen protected volatile int poolState; protected volatile long connectionTimeout; + protected volatile long validationTimeout; private final LeakTask leakTask; private final DataSource dataSource; @@ -129,6 +130,7 @@ public abstract class BaseHikariPool implements HikariPoolMBean, IBagStateListen this.connectionBag = createConcurrentBag(this); this.totalConnections = new AtomicInteger(); this.connectionTimeout = configuration.getConnectionTimeout(); + this.validationTimeout = configuration.getValidationTimeout(); this.lastConnectionFailure = new AtomicReference(); this.isReadOnly = configuration.isReadOnly(); @@ -183,7 +185,7 @@ public abstract class BaseHikariPool implements HikariPoolMBean, IBagStateListen } final long now = System.currentTimeMillis(); - if (bagEntry.evicted || (now - bagEntry.lastAccess > ALIVE_BYPASS_WINDOW && !isConnectionAlive(bagEntry.connection, timeout))) { + if (bagEntry.evicted || (now - bagEntry.lastAccess > ALIVE_BYPASS_WINDOW && !isConnectionAlive(bagEntry.connection))) { closeConnection(bagEntry); // Throw away the dead connection and try again timeout = connectionTimeout - elapsedTimeMs(start); } @@ -378,14 +380,14 @@ public abstract class BaseHikariPool implements HikariPoolMBean, IBagStateListen final boolean timeoutEnabled = (connectionTimeout != Integer.MAX_VALUE); final long timeoutMs = timeoutEnabled ? Math.max(250L, connectionTimeout) : 0L; - final int originalTimeout = poolUtils.getAndSetNetworkTimeout(connection, timeoutMs, timeoutEnabled); + final int originalTimeout = poolUtils.getAndSetNetworkTimeout(connection, timeoutMs); transactionIsolation = (transactionIsolation < 0 ? connection.getTransactionIsolation() : transactionIsolation); poolUtils.setupConnection(connection, isAutoCommit, isReadOnly, transactionIsolation, catalog); connectionCustomizer.customize(connection); poolUtils.executeSql(connection, configuration.getConnectionInitSql(), isAutoCommit); - poolUtils.setNetworkTimeout(connection, originalTimeout, timeoutEnabled); + poolUtils.setNetworkTimeout(connection, originalTimeout); connectionBag.add(new PoolBagEntry(connection, this)); lastConnectionFailure.set(null); @@ -431,7 +433,7 @@ public abstract class BaseHikariPool implements HikariPoolMBean, IBagStateListen * @param timeoutMs the timeout before we consider the test a failure * @return true if the connection is alive, false if it is not alive or we timed out */ - protected abstract boolean isConnectionAlive(final Connection connection, final long timeoutMs); + protected abstract boolean isConnectionAlive(final Connection connection); /** * Attempt to abort() active connections on Java7+, or close() them on Java6. diff --git a/hikaricp-common/src/main/java/com/zaxxer/hikari/pool/PoolUtilities.java b/hikaricp-common/src/main/java/com/zaxxer/hikari/pool/PoolUtilities.java index c66274ea..a8b5eced 100644 --- a/hikaricp-common/src/main/java/com/zaxxer/hikari/pool/PoolUtilities.java +++ b/hikaricp-common/src/main/java/com/zaxxer/hikari/pool/PoolUtilities.java @@ -49,7 +49,7 @@ public final class PoolUtilities { if (connection != null) { try { - setNetworkTimeout(connection, TimeUnit.SECONDS.toMillis(30), true); + setNetworkTimeout(connection, TimeUnit.SECONDS.toMillis(30)); connection.close(); } catch (Throwable e) { @@ -177,12 +177,11 @@ public final class PoolUtilities * * @param connection the connection to set the network timeout on * @param timeoutMs the number of milliseconds before timeout - * @param isUseNetworkTimeout true if the network timeout should be set, false otherwise * @return the pre-existing network timeout value */ - public int getAndSetNetworkTimeout(final Connection connection, final long timeoutMs, final boolean isUseNetworkTimeout) + public int getAndSetNetworkTimeout(final Connection connection, final long timeoutMs) { - if (isUseNetworkTimeout && isNetworkTimeoutSupported) { + if (isNetworkTimeoutSupported) { try { final int networkTimeout = connection.getNetworkTimeout(); connection.setNetworkTimeout(executorService, (int) timeoutMs); @@ -203,11 +202,10 @@ public final class PoolUtilities * * @param connection the connection to set the network timeout on * @param timeoutMs the number of milliseconds before timeout - * @param isUseNetworkTimeout true if the network timeout should be set, false otherwise */ - public void setNetworkTimeout(final Connection connection, final long timeoutMs, final boolean isUseNetworkTimeout) + public void setNetworkTimeout(final Connection connection, final long timeoutMs) { - if (isUseNetworkTimeout && isNetworkTimeoutSupported) { + if (isNetworkTimeoutSupported) { try { connection.setNetworkTimeout(executorService, (int) timeoutMs); } diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/pool/HikariPool.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/pool/HikariPool.java index 4b5af7bc..827b956c 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/pool/HikariPool.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/pool/HikariPool.java @@ -139,17 +139,16 @@ public final class HikariPool extends BaseHikariPool * @return true if the connection is alive, false if it is not alive or we timed out */ @Override - protected boolean isConnectionAlive(final Connection connection, final long timeoutMs) + protected boolean isConnectionAlive(final Connection connection) { try { - final boolean timeoutEnabled = (connectionTimeout != Integer.MAX_VALUE); - int timeoutSec = timeoutEnabled ? (int) Math.max(1L, TimeUnit.MILLISECONDS.toSeconds(timeoutMs)) : 0; + final int timeoutSec = (int) TimeUnit.MILLISECONDS.toSeconds(validationTimeout); if (isUseJdbc4Validation) { return connection.isValid(timeoutSec); } - final int originalTimeout = poolUtils.getAndSetNetworkTimeout(connection, Math.max(1000, (int) timeoutMs), timeoutEnabled); + final int originalTimeout = poolUtils.getAndSetNetworkTimeout(connection, validationTimeout); Statement statement = connection.createStatement(); try { @@ -164,7 +163,7 @@ public final class HikariPool extends BaseHikariPool connection.rollback(); } - poolUtils.setNetworkTimeout(connection, originalTimeout, timeoutEnabled); + poolUtils.setNetworkTimeout(connection, originalTimeout); return true; } diff --git a/hikaricp/src/main/java/com/zaxxer/hikari/pool/HikariPool.java b/hikaricp/src/main/java/com/zaxxer/hikari/pool/HikariPool.java index e998689c..475f1c5e 100644 --- a/hikaricp/src/main/java/com/zaxxer/hikari/pool/HikariPool.java +++ b/hikaricp/src/main/java/com/zaxxer/hikari/pool/HikariPool.java @@ -118,21 +118,19 @@ public final class HikariPool extends BaseHikariPool * Check whether the connection is alive or not. * * @param connection the connection to test - * @param timeoutMs the timeout before we consider the test a failure * @return true if the connection is alive, false if it is not alive or we timed out */ @Override - protected boolean isConnectionAlive(final Connection connection, final long timeoutMs) + protected boolean isConnectionAlive(final Connection connection) { try { - final boolean timeoutEnabled = (connectionTimeout != Integer.MAX_VALUE); - int timeoutSec = timeoutEnabled ? (int) Math.max(1L, TimeUnit.MILLISECONDS.toSeconds(timeoutMs)) : 0; + final int timeoutSec = (int) TimeUnit.MILLISECONDS.toSeconds(validationTimeout); if (isUseJdbc4Validation) { return connection.isValid(timeoutSec); } - final int originalTimeout = poolUtils.getAndSetNetworkTimeout(connection, Math.max(1000, (int) timeoutMs), timeoutEnabled); + final int originalTimeout = poolUtils.getAndSetNetworkTimeout(connection, validationTimeout); try (Statement statement = connection.createStatement()) { poolUtils.setQueryTimeout(statement, timeoutSec); @@ -143,7 +141,7 @@ public final class HikariPool extends BaseHikariPool connection.rollback(); } - poolUtils.setNetworkTimeout(connection, originalTimeout, timeoutEnabled); + poolUtils.setNetworkTimeout(connection, originalTimeout); return true; } @@ -206,6 +204,7 @@ public final class HikariPool extends BaseHikariPool logPoolState("Before cleanup "); connectionTimeout = configuration.getConnectionTimeout(); // refresh member in case it changed + validationTimeout = configuration.getValidationTimeout(); // refresh member in case it changed final long now = System.currentTimeMillis(); final long idleTimeout = configuration.getIdleTimeout();