Clean up and better JavaDoc.

pull/1009/head
Brett Wooldridge 7 years ago
parent 4e00e8cd6a
commit 4b796b5209

@ -58,7 +58,7 @@ public class HikariConfig implements HikariConfigMXBean
private static boolean unitTest = false;
// Properties changeable at runtime through the MBean
// Properties changeable at runtime through the HikariConfigMXBean
//
private volatile long connectionTimeout;
private volatile long validationTimeout;
@ -67,6 +67,8 @@ public class HikariConfig implements HikariConfigMXBean
private volatile long maxLifetime;
private volatile int maxPoolSize;
private volatile int minIdle;
private volatile String username;
private volatile String password;
// Properties NOT changeable at runtime
//
@ -78,11 +80,9 @@ public class HikariConfig implements HikariConfigMXBean
private String dataSourceJndiName;
private String driverClassName;
private String jdbcUrl;
private String password;
private String poolName;
private String schema;
private String transactionIsolationName;
private String username;
private boolean isAutoCommit;
private boolean isReadOnly;
private boolean isIsolateInternalQueries;
@ -145,6 +145,173 @@ public class HikariConfig implements HikariConfigMXBean
loadProperties(propertyFileName);
}
// ***********************************************************************
// HikariConfigMXBean methods
// ***********************************************************************
/** {@inheritDoc} */
@Override
public long getConnectionTimeout()
{
return connectionTimeout;
}
/** {@inheritDoc} */
@Override
public void setConnectionTimeout(long connectionTimeoutMs)
{
if (connectionTimeoutMs == 0) {
this.connectionTimeout = Integer.MAX_VALUE;
}
else if (connectionTimeoutMs < 250) {
throw new IllegalArgumentException("connectionTimeout cannot be less than 250ms");
}
else {
this.connectionTimeout = connectionTimeoutMs;
}
}
/** {@inheritDoc} */
@Override
public long getIdleTimeout()
{
return idleTimeout;
}
/** {@inheritDoc} */
@Override
public void setIdleTimeout(long idleTimeoutMs)
{
if (idleTimeoutMs < 0) {
throw new IllegalArgumentException("idleTimeout cannot be negative");
}
this.idleTimeout = idleTimeoutMs;
}
/** {@inheritDoc} */
@Override
public long getLeakDetectionThreshold()
{
return leakDetectionThreshold;
}
/** {@inheritDoc} */
@Override
public void setLeakDetectionThreshold(long leakDetectionThresholdMs)
{
this.leakDetectionThreshold = leakDetectionThresholdMs;
}
/** {@inheritDoc} */
@Override
public long getMaxLifetime()
{
return maxLifetime;
}
/** {@inheritDoc} */
@Override
public void setMaxLifetime(long maxLifetimeMs)
{
this.maxLifetime = maxLifetimeMs;
}
/** {@inheritDoc} */
@Override
public int getMaximumPoolSize()
{
return maxPoolSize;
}
/** {@inheritDoc} */
@Override
public void setMaximumPoolSize(int maxPoolSize)
{
if (maxPoolSize < 1) {
throw new IllegalArgumentException("maxPoolSize cannot be less than 1");
}
this.maxPoolSize = maxPoolSize;
}
/** {@inheritDoc} */
@Override
public int getMinimumIdle()
{
return minIdle;
}
/** {@inheritDoc} */
@Override
public void setMinimumIdle(int minIdle)
{
if (minIdle < 0) {
throw new IllegalArgumentException("minimumIdle cannot be negative");
}
this.minIdle = minIdle;
}
/**
* Get the default password to use for DataSource.getConnection(username, password) calls.
* @return the password
*/
public String getPassword()
{
return password;
}
/**
* Set the default password to use for DataSource.getConnection(username, password) calls.
* @param password the password
*/
@Override
public void setPassword(String password)
{
this.password = password;
}
/**
* Get the default username used for DataSource.getConnection(username, password) calls.
*
* @return the username
*/
public String getUsername()
{
return username;
}
/**
* Set the default username used for DataSource.getConnection(username, password) calls.
*
* @param username the username
*/
@Override
public void setUsername(String username)
{
this.username = username;
}
/** {@inheritDoc} */
@Override
public long getValidationTimeout()
{
return validationTimeout;
}
/** {@inheritDoc} */
@Override
public void setValidationTimeout(long validationTimeoutMs)
{
if (validationTimeoutMs < 250) {
throw new IllegalArgumentException("validationTimeout cannot be less than 250ms");
}
this.validationTimeout = validationTimeoutMs;
}
// ***********************************************************************
// All other configuration methods
// ***********************************************************************
/**
* Get the default catalog name to be set on connections.
*
@ -210,46 +377,6 @@ public class HikariConfig implements HikariConfigMXBean
this.connectionInitSql = connectionInitSql;
}
/** {@inheritDoc} */
@Override
public long getConnectionTimeout()
{
return connectionTimeout;
}
/** {@inheritDoc} */
@Override
public void setConnectionTimeout(long connectionTimeoutMs)
{
if (connectionTimeoutMs == 0) {
this.connectionTimeout = Integer.MAX_VALUE;
}
else if (connectionTimeoutMs < 250) {
throw new IllegalArgumentException("connectionTimeout cannot be less than 250ms");
}
else {
this.connectionTimeout = connectionTimeoutMs;
}
}
/** {@inheritDoc} */
@Override
public long getValidationTimeout()
{
return validationTimeout;
}
/** {@inheritDoc} */
@Override
public void setValidationTimeout(long validationTimeoutMs)
{
if (validationTimeoutMs < 250) {
throw new IllegalArgumentException("validationTimeout cannot be less than 250ms");
}
this.validationTimeout = validationTimeoutMs;
}
/**
* Get the {@link DataSource} that has been explicitly specified to be wrapped by the
* pool.
@ -272,16 +399,39 @@ public class HikariConfig implements HikariConfigMXBean
this.dataSource = dataSource;
}
/**
* Get the name of the JDBC {@link DataSource} class used to create Connections.
*
* @return the fully qualified name of the JDBC {@link DataSource} class
*/
public String getDataSourceClassName()
{
return dataSourceClassName;
}
/**
* Set the fully qualified class name of the JDBC {@link DataSource} that will be used create Connections.
*
* @param className the fully qualified name of the JDBC {@link DataSource} class
*/
public void setDataSourceClassName(String className)
{
this.dataSourceClassName = className;
}
/**
* Add a property (name/value pair) that will be used to configure the {@link DataSource}/{@link java.sql.Driver}.
*
* In the case of a {@link DataSource}, the property names will be translated to Java setters following the Java Bean
* naming convention. For example, the property {@code cachePrepStmts} will translate into {@code setCachePrepStmts()}
* with the {@code value} passed as a parameter.
*
* In the case of a {@link java.sql.Driver}, the property will be added to a {@link Properties} instance that will
* be passed to the driver during {@link java.sql.Driver#connect(String, Properties)} calls.
*
* @param propertyName the name of the property
* @param value the value to be used by the DataSource/Driver
*/
public void addDataSourceProperty(String propertyName, Object value)
{
dataSourceProperties.put(propertyName, value);
@ -349,23 +499,6 @@ public class HikariConfig implements HikariConfigMXBean
}
}
/** {@inheritDoc} */
@Override
public long getIdleTimeout()
{
return idleTimeout;
}
/** {@inheritDoc} */
@Override
public void setIdleTimeout(long idleTimeoutMs)
{
if (idleTimeoutMs < 0) {
throw new IllegalArgumentException("idleTimeout cannot be negative");
}
this.idleTimeout = idleTimeoutMs;
}
public String getJdbcUrl()
{
return jdbcUrl;
@ -496,11 +629,23 @@ public class HikariConfig implements HikariConfigMXBean
initializationFailTimeout = (failFast ? 1 : -1);
}
/**
* Determine whether internal pool queries, principally aliveness checks, will be isolated in their own transaction
* (via {@link java.sql.Connection#rollback()). Defaults to {@code false}.
*
* @return {@code true} if internal pool queries are isolated, {@code false} if not
*/
public boolean isIsolateInternalQueries()
{
return isIsolateInternalQueries;
}
/**
* Configure whether internal pool queries, principally aliveness checks, will be isolated in their own transaction
* (via {@link java.sql.Connection#rollback()). Defaults to {@code false}.
*
* @param isolate {@code true} if internal pool queries should be isolated, {@code false} if not
*/
public void setIsolateInternalQueries(boolean isolate)
{
this.isIsolateInternalQueries = isolate;
@ -533,9 +678,9 @@ public class HikariConfig implements HikariConfigMXBean
}
/**
* Get the Codahale MetricRegistry, could be null.
* Get the MetricRegistry instance to used for registration of metrics used by HikariCP. Default is {@code null}.
*
* @return the codahale MetricRegistry instance
* @return the MetricRegistry instance that will be used
*/
public Object getMetricRegistry()
{
@ -543,9 +688,9 @@ public class HikariConfig implements HikariConfigMXBean
}
/**
* Set a Codahale MetricRegistry to use for HikariCP.
* Set a MetricRegistry instance to use for registration of metrics used by HikariCP.
*
* @param metricRegistry the Codahale MetricRegistry to set
* @param metricRegistry the MetricRegistry instance to use
*/
public void setMetricRegistry(Object metricRegistry)
{
@ -565,24 +710,11 @@ public class HikariConfig implements HikariConfigMXBean
this.metricRegistry = metricRegistry;
}
private Object getObjectOrPerformJndiLookup(Object object)
{
if (object instanceof String) {
try {
InitialContext initCtx = new InitialContext();
return initCtx.lookup((String) object);
}
catch (NamingException e) {
throw new IllegalArgumentException(e);
}
}
return object;
}
/**
* Get the Codahale HealthCheckRegistry, could be null.
* Get the HealthCheckRegistry that will be used for registration of health checks by HikariCP. Currently only
* Codahale/DropWizard is supported for health checks.
*
* @return the Codahale HealthCheckRegistry instance
* @return the HealthCheckRegistry instance that will be used
*/
public Object getHealthCheckRegistry()
{
@ -590,9 +722,10 @@ public class HikariConfig implements HikariConfigMXBean
}
/**
* Set a Codahale HealthCheckRegistry to use for HikariCP.
* Set the HealthCheckRegistry that will be used for registration of health checks by HikariCP. Currently only
* Codahale/DropWizard is supported for health checks. Default is {@code null}.
*
* @param healthCheckRegistry the Codahale HealthCheckRegistry to set
* @param healthCheckRegistry the HealthCheckRegistry to be used
*/
public void setHealthCheckRegistry(Object healthCheckRegistry)
{
@ -622,105 +755,45 @@ public class HikariConfig implements HikariConfigMXBean
healthCheckProperties.setProperty(key, value);
}
/**
* Determine whether the Connections in the pool are in read-only mode.
*
* @return {@code true} if the Connections in the pool are read-only, {@code false} if not
*/
public boolean isReadOnly()
{
return isReadOnly;
}
/**
* Configures the Connections to be added to the pool as read-only Connections.
*
* @param readOnly {@code true} if the Connections in the pool are read-only, {@code false} if not
*/
public void setReadOnly(boolean readOnly)
{
this.isReadOnly = readOnly;
}
public boolean isRegisterMbeans()
{
return isRegisterMbeans;
}
public void setRegisterMbeans(boolean register)
{
this.isRegisterMbeans = register;
}
/** {@inheritDoc} */
@Override
public long getLeakDetectionThreshold()
{
return leakDetectionThreshold;
}
/** {@inheritDoc} */
@Override
public void setLeakDetectionThreshold(long leakDetectionThresholdMs)
{
this.leakDetectionThreshold = leakDetectionThresholdMs;
}
/** {@inheritDoc} */
@Override
public long getMaxLifetime()
{
return maxLifetime;
}
/** {@inheritDoc} */
@Override
public void setMaxLifetime(long maxLifetimeMs)
{
this.maxLifetime = maxLifetimeMs;
}
/** {@inheritDoc} */
@Override
public int getMaximumPoolSize()
{
return maxPoolSize;
}
/** {@inheritDoc} */
@Override
public void setMaximumPoolSize(int maxPoolSize)
{
if (maxPoolSize < 1) {
throw new IllegalArgumentException("maxPoolSize cannot be less than 1");
}
this.maxPoolSize = maxPoolSize;
}
/** {@inheritDoc} */
@Override
public int getMinimumIdle()
{
return minIdle;
}
/** {@inheritDoc} */
@Override
public void setMinimumIdle(int minIdle)
{
if (minIdle < 0) {
throw new IllegalArgumentException("minimumIdle cannot be negative");
}
this.minIdle = minIdle;
}
/**
* Get the default password to use for DataSource.getConnection(username, password) calls.
* @return the password
* Determine whether HikariCP will self-register {@link HikariConfigMXBean} and {@link HikariPoolMXBean} instances
* in JMX.
*
* @return {@code true} if HikariCP will register MXBeans, {@code false} if it will not
*/
public String getPassword()
public boolean isRegisterMbeans()
{
return password;
return isRegisterMbeans;
}
/**
* Set the default password to use for DataSource.getConnection(username, password) calls.
* @param password the password
* Configures whether HikariCP self-registers the {@link HikariConfigMXBean} and {@link HikariPoolMXBean} in JMX.
*
* @param register {@code true} if HikariCP should register MXBeans, {@code false} if it should not
*/
@Override
public void setPassword(String password)
public void setRegisterMbeans(boolean register)
{
this.password = password;
this.isRegisterMbeans = register;
}
/** {@inheritDoc} */
@ -817,46 +890,63 @@ public class HikariConfig implements HikariConfigMXBean
}
/**
* Get the default username used for DataSource.getConnection(username, password) calls.
* Get the thread factory used to create threads.
*
* @return the username
* @return the thread factory (may be null, in which case the default thread factory is used)
*/
public String getUsername()
public ThreadFactory getThreadFactory()
{
return username;
return threadFactory;
}
/**
* Set the default username used for DataSource.getConnection(username, password) calls.
* Set the thread factory to be used to create threads.
*
* @param username the username
* @param threadFactory the thread factory (setting to null causes the default thread factory to be used)
*/
@Override
public void setUsername(String username)
public void setThreadFactory(ThreadFactory threadFactory)
{
this.username = username;
this.threadFactory = threadFactory;
}
/**
* Get the thread factory used to create threads.
* Deprecated, use {@link #copyStateTo(HikariConfig)}.
* <p>
* Copies the state of {@code this} into {@code other}.
*</p>
*
* @return the thread factory (may be null, in which case the default thread factory is used)
* @param other Other {@link HikariConfig} to copy the state to.
*/
public ThreadFactory getThreadFactory()
@Deprecated
public void copyState(HikariConfig other)
{
return threadFactory;
copyStateTo(other);
}
/**
* Set the thread factory to be used to create threads.
* Copies the state of {@code this} into {@code other}.
*
* @param threadFactory the thread factory (setting to null causes the default thread factory to be used)
* @param other Other {@link HikariConfig} to copy the state to.
*/
public void setThreadFactory(ThreadFactory threadFactory)
public void copyStateTo(HikariConfig other)
{
this.threadFactory = threadFactory;
for (Field field : HikariConfig.class.getDeclaredFields()) {
if (!Modifier.isFinal(field.getModifiers())) {
field.setAccessible(true);
try {
field.set(other, field.get(this));
}
catch (Exception e) {
throw new RuntimeException("Failed to copy HikariConfig state: " + e.getMessage(), e);
}
}
}
}
// ***********************************************************************
// Private methods
// ***********************************************************************
@SuppressWarnings("StatementWithEmptyBody")
public void validate()
{
@ -1043,37 +1133,17 @@ public class HikariConfig implements HikariConfigMXBean
}
}
/**
* Deprecated, use {@link #copyStateTo(HikariConfig)}.
* <p>
* Copies the state of {@code this} into {@code other}.
*</p>
*
* @param other Other {@link HikariConfig} to copy the state to.
*/
@Deprecated
public void copyState(HikariConfig other)
{
copyStateTo(other);
}
/**
* Copies the state of {@code this} into {@code other}.
*
* @param other Other {@link HikariConfig} to copy the state to.
*/
public void copyStateTo(HikariConfig other)
private Object getObjectOrPerformJndiLookup(Object object)
{
for (Field field : HikariConfig.class.getDeclaredFields()) {
if (!Modifier.isFinal(field.getModifiers())) {
field.setAccessible(true);
try {
field.set(other, field.get(this));
}
catch (Exception e) {
throw new RuntimeException("Failed to copy HikariConfig state: " + e.getMessage(), e);
}
if (object instanceof String) {
try {
InitialContext initCtx = new InitialContext();
return initCtx.lookup((String) object);
}
catch (NamingException e) {
throw new IllegalArgumentException(e);
}
}
return object;
}
}

@ -16,17 +16,22 @@
package com.zaxxer.hikari.pool;
import static com.zaxxer.hikari.util.ClockSource.currentTime;
import static com.zaxxer.hikari.util.ClockSource.elapsedDisplayString;
import static com.zaxxer.hikari.util.ClockSource.elapsedMillis;
import static com.zaxxer.hikari.util.ClockSource.plusMillis;
import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_IN_USE;
import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_NOT_IN_USE;
import static com.zaxxer.hikari.util.UtilityElf.createThreadPoolExecutor;
import static com.zaxxer.hikari.util.UtilityElf.quietlySleep;
import static java.util.Collections.unmodifiableCollection;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.health.HealthCheckRegistry;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariPoolMXBean;
import com.zaxxer.hikari.metrics.MetricsTrackerFactory;
import com.zaxxer.hikari.metrics.PoolStats;
import com.zaxxer.hikari.metrics.dropwizard.CodahaleHealthChecker;
import com.zaxxer.hikari.metrics.dropwizard.CodahaleMetricsTrackerFactory;
import com.zaxxer.hikari.metrics.micrometer.MicrometerMetricsTrackerFactory;
import com.zaxxer.hikari.util.ConcurrentBag;
import com.zaxxer.hikari.util.ConcurrentBag.IBagStateListener;
import com.zaxxer.hikari.util.SuspendResumeLock;
import com.zaxxer.hikari.util.UtilityElf.DefaultThreadFactory;
import io.micrometer.core.instrument.MeterRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.SQLException;
@ -35,7 +40,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
@ -45,23 +49,17 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.ThreadPoolExecutor;
import com.zaxxer.hikari.metrics.micrometer.MicrometerMetricsTrackerFactory;
import io.micrometer.core.instrument.MeterRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.health.HealthCheckRegistry;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariPoolMXBean;
import com.zaxxer.hikari.metrics.MetricsTrackerFactory;
import com.zaxxer.hikari.metrics.PoolStats;
import com.zaxxer.hikari.metrics.dropwizard.CodahaleHealthChecker;
import com.zaxxer.hikari.metrics.dropwizard.CodahaleMetricsTrackerFactory;
import com.zaxxer.hikari.util.ConcurrentBag;
import com.zaxxer.hikari.util.ConcurrentBag.IBagStateListener;
import com.zaxxer.hikari.util.SuspendResumeLock;
import com.zaxxer.hikari.util.UtilityElf.DefaultThreadFactory;
import static com.zaxxer.hikari.util.ClockSource.currentTime;
import static com.zaxxer.hikari.util.ClockSource.elapsedDisplayString;
import static com.zaxxer.hikari.util.ClockSource.elapsedMillis;
import static com.zaxxer.hikari.util.ClockSource.plusMillis;
import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_IN_USE;
import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_NOT_IN_USE;
import static com.zaxxer.hikari.util.UtilityElf.createThreadPoolExecutor;
import static com.zaxxer.hikari.util.UtilityElf.quietlySleep;
import static java.util.Collections.unmodifiableCollection;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
/**
* This is the primary connection pool class that provides the basic
@ -85,7 +83,7 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
private static final String EVICTED_CONNECTION_MESSAGE = "(connection was evicted)";
private static final String DEAD_CONNECTION_MESSAGE = "(connection is dead)";
private final PoolEntryCreator POOL_ENTRY_CREATOR = new PoolEntryCreator(null);
private final PoolEntryCreator POOL_ENTRY_CREATOR = new PoolEntryCreator(null /*logging prefix*/);
private final PoolEntryCreator POST_FILL_POOL_ENTRY_CREATOR = new PoolEntryCreator("After adding ");
private final Collection<Runnable> addConnectionQueue;
private final ThreadPoolExecutor addConnectionExecutor;
@ -96,7 +94,7 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
private final ProxyLeakTaskFactory leakTaskFactory;
private final SuspendResumeLock suspendResumeLock;
private ScheduledExecutorService houseKeepingExecutorService;
private final ScheduledExecutorService houseKeepingExecutorService;
private ScheduledFuture<?> houseKeeperTask;
/**
@ -171,7 +169,7 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
final long now = currentTime();
if (poolEntry.isMarkedEvicted() || (elapsedMillis(poolEntry.lastAccessed, now) > ALIVE_BYPASS_WINDOW_MS && !isConnectionAlive(poolEntry.connection))) {
closeConnection(poolEntry, poolEntry.isMarkedEvicted() ? EVICTED_CONNECTION_MESSAGE : DEAD_CONNECTION_MESSAGE); // Throw away the dead connection (passed max age or failed alive test)
closeConnection(poolEntry, poolEntry.isMarkedEvicted() ? EVICTED_CONNECTION_MESSAGE : DEAD_CONNECTION_MESSAGE);
timeout = hardTimeout - elapsedMillis(startTime);
}
else {
@ -181,6 +179,7 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
} while (timeout > 0L);
metricsTracker.recordBorrowTimeoutStats(startTime);
throw createTimeoutException(startTime);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
@ -189,8 +188,6 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
finally {
suspendResumeLock.release();
}
throw createTimeoutException(startTime);
}
/**
@ -204,7 +201,7 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
try {
poolState = POOL_SHUTDOWN;
if (addConnectionExecutor == null) {
if (addConnectionExecutor == null) { // pool never started
return;
}
@ -250,9 +247,9 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
}
/**
* Evict a connection from the pool.
* Evict a Connection from the pool.
*
* @param connection the connection to evict
* @param connection the Connection to evict (actually a {@link ProxyConnection})
*/
public void evictConnection(Connection connection)
{
@ -267,6 +264,12 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
}
}
/**
* Set a metrics registry to be used when registering metrics collectors. The HikariDataSource prevents this
* method from being called more than once.
*
* @param metricRegistry the metrics registry instance to use
*/
public void setMetricRegistry(Object metricRegistry)
{
if (metricRegistry != null && metricRegistry.getClass().getName().contains("MetricRegistry")) {
@ -280,6 +283,11 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
}
}
/**
* Set the MetricsTrackerFactory to be used to create the IMetricsTracker instance used by the pool.
*
* @param metricsTrackerFactory an instance of a class that subclasses MetricsTrackerFactory
*/
public void setMetricsTrackerFactory(MetricsTrackerFactory metricsTrackerFactory)
{
if (metricsTrackerFactory != null) {
@ -290,6 +298,12 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
}
}
/**
* Set the health check registry to be used when registering health checks. Currently only Codahale health
* checks are supported.
*
* @param healthCheckRegistry the health check registry instance to use
*/
public void setHealthCheckRegistry(Object healthCheckRegistry)
{
if (healthCheckRegistry != null) {
@ -309,8 +323,6 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
if (shouldAdd) {
addConnectionExecutor.submit(POOL_ENTRY_CREATOR);
}
CompletableFuture.completedFuture(Boolean.TRUE);
}
// ***********************************************************************
@ -432,12 +444,14 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
return connectionBag.getStateCounts();
}
// ***********************************************************************
// Private methods
// ***********************************************************************
/**
* Creating new poolEntry.
* Creating new poolEntry. If maxLifetime is configured, create a future End-of-life task with 2.5% variance from
* the maxLifetime time to ensure there is no massive die-off of Connections in the pool.
*/
private PoolEntry createPoolEntry()
{
@ -461,7 +475,7 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
return poolEntry;
}
catch (Exception e) {
if (poolState == POOL_NORMAL) {
if (poolState == POOL_NORMAL) { // we check POOL_NORMAL to avoid a flood of messages if shutdown() is running concurrently
LOGGER.debug("{} - Cannot acquire connection from data source", poolName, (e instanceof ConnectionSetupException ? e.getCause() : e));
}
return null;
@ -482,6 +496,8 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
/**
* Attempt to abort or close active connections.
*
* @param assassinExecutor the ExecutorService to pass to Connection.abort()
*/
private void abortActiveConnections(final ExecutorService assassinExecutor)
{
@ -503,6 +519,7 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
* If initializationFailFast is configured, check that we have DB connectivity.
*
* @throws PoolInitializationException if fails to create or validate connection
* @see HikariConfig#setInitializationFailTimeout(long)
*/
private void checkFailFast()
{
@ -530,7 +547,7 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
throwPoolInitializationException(getLastConnectionFailure().getCause());
}
quietlySleep(1000L);
quietlySleep(SECONDS.toMillis(1));
} while (elapsedMillis(startTime) < initializationTimeout);
if (initializationTimeout > 0) {
@ -538,6 +555,12 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
}
}
/**
* Log the Throwable that caused pool initialization to fail, and then throw a PoolInitializationException with
* that cause attached.
*
* @param t the Throwable that caused the pool to fail to initialize (possibly null)
*/
private void throwPoolInitializationException(Throwable t)
{
LOGGER.error("{} - Exception during pool initialization.", poolName, t);
@ -545,6 +568,19 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
throw new PoolInitializationException(t);
}
/**
* "Soft" evict a Connection (/PoolEntry) from the pool. If this method is being called by the user directly
* through {@link com.zaxxer.hikari.HikariDataSource#evictConnection(Connection)} then {@code owner} is {@code true}.
*
* If the caller is the owner, or if the Connection is idle (i.e. can be "reserved" in the {@link ConcurrentBag}),
* then we can close the connection immediately. Otherwise, we leave it "marked" for eviction so that it is evicted
* the next time someone tries to acquire it from the pool.
*
* @param poolEntry the PoolEntry (/Connection) to "soft" evict from the pool
* @param reason the reason that the connection is being evicted
* @param owner true if the caller is the owner of the connection, false otherwise
* @return true if the connection was evicted (closed), false if it was merely marked for eviction
*/
private boolean softEvictConnection(final PoolEntry poolEntry, final String reason, final boolean owner)
{
poolEntry.markEvicted();
@ -556,6 +592,13 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
return false;
}
/**
* Create/initialize the Housekeeping service {@link ScheduledExecutorService}. If the user specified an Executor
* to be used in the {@link HikariConfig}, then we use that. If no Executor was specified (typical), then create
* an Executor and configure it.
*
* @return either the user specified {@link ScheduledExecutorService}, or the one we created
*/
private ScheduledExecutorService initializeHouseKeepingExecutorService()
{
if (config.getScheduledExecutor() == null) {
@ -570,6 +613,9 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
}
}
/**
* Destroy (/shutdown) the Housekeeping service Executor, if it was the one that we created.
*/
private void destroyHouseKeepingExecutorService()
{
if (config.getScheduledExecutor() == null) {
@ -577,6 +623,11 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
}
}
/**
* Create a PoolStats instance that will be used by metrics tracking, with a pollable resolution of 1 second.
*
* @return a PoolStats instance
*/
private PoolStats getPoolStats()
{
return new PoolStats(SECONDS.toMillis(1)) {
@ -590,6 +641,18 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
};
}
/**
* Create a timeout exception (specifically, {@link SQLTransientConnectionException}) to be thrown, because a
* timeout occurred when trying to acquire a Connection from the pool. If there was an underlying cause for the
* timeout, e.g. a SQLException thrown by the driver while trying to create a new Connection, then use the
* SQL State from that exception as our own and additionally set that exception as the "next" SQLException inside
* of our exception.
*
* As a side-effect, log the timeout failure at DEBUG, and record the timeout failure in the metrics tracker.
*
* @param startTime the start time (timestamp) of the acquisition attempt
* @return a SQLException to be thrown from {@link #getConnection()}
*/
private SQLException createTimeoutException(long startTime)
{
logPoolState("Timeout failure ");
@ -608,6 +671,7 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
return connectionException;
}
// ***********************************************************************
// Non-anonymous Inner-classes
// ***********************************************************************
@ -647,9 +711,13 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
return Boolean.FALSE;
}
/**
* We only create connections if we need another idle connection or have threads still waiting
* for a new connection. Otherwise we bail out of the request to create.
*
* @return true if we should create a connection, false if the need has disappeared
*/
private boolean shouldCreateAnotherConnection() {
// only create connections if we need another idle connection or have threads still waiting
// for a new connection, otherwise bail
return getTotalConnections() < config.getMaximumPoolSize() &&
(connectionBag.getWaitingThreadCount() > 0 || getIdleConnections() < config.getMinimumIdle());
}
@ -680,7 +748,6 @@ public final class HikariPool extends PoolBase implements HikariPoolMXBean, IBag
poolName, elapsedDisplayString(previous, now));
previous = now;
softEvictConnections();
fillPool();
return;
}
else if (now > plusMillis(previous, (3 * HOUSEKEEPING_PERIOD_MS) / 2)) {

Loading…
Cancel
Save