Significant state ownership refactor following class relationship analysis. Probably a bit more to be done here, but better than it was.

pull/333/head
Brett Wooldridge 10 years ago
parent bd0d3aa01e
commit 5062bd142b

@ -40,8 +40,8 @@ import org.slf4j.LoggerFactory;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.health.HealthCheckRegistry;
import com.zaxxer.hikari.pool.PoolElf;
import com.zaxxer.hikari.util.PropertyElf;
import com.zaxxer.hikari.util.UtilityElf;
public class HikariConfig implements HikariConfigMBean
{
@ -439,7 +439,7 @@ public class HikariConfig implements HikariConfigMBean
@Deprecated
public void setJdbc4ConnectionTest(boolean useIsValid)
{
throw new IllegalArgumentException("The jdbcConnectionTest property is now deprecated, see the documentation for connectionTestQuery");
LOGGER.warn("The jdbcConnectionTest property is now deprecated, see the documentation for connectionTestQuery");
}
/**
@ -758,7 +758,7 @@ public class HikariConfig implements HikariConfigMBean
}
if (transactionIsolationName != null) {
UtilityElf.getTransactionIsolation(transactionIsolationName);
PoolElf.getTransactionIsolation(transactionIsolationName);
}
if (LOGGER.isDebugEnabled() || unitTest) {

@ -20,14 +20,11 @@ import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_IN_
import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_NOT_IN_USE;
import static com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry.STATE_REMOVED;
import static com.zaxxer.hikari.util.UtilityElf.createThreadPoolExecutor;
import static com.zaxxer.hikari.util.UtilityElf.getTransactionIsolation;
import static com.zaxxer.hikari.util.UtilityElf.quietlySleep;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLTimeoutException;
import java.sql.Statement;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
@ -69,7 +66,7 @@ import com.zaxxer.hikari.util.PropertyElf;
*/
public class HikariPool implements HikariPoolMBean, IBagStateListener
{
private final Logger LOGGER = LoggerFactory.getLogger(getClass());
final Logger LOGGER = LoggerFactory.getLogger(getClass());
private static final ClockSource clockSource = ClockSource.INSTANCE;
@ -80,12 +77,7 @@ public class HikariPool implements HikariPoolMBean, IBagStateListener
private static final int POOL_SUSPENDED = 1;
private static final int POOL_SHUTDOWN = 2;
public int transactionIsolation;
public final String catalog;
public final boolean isReadOnly;
public final boolean isAutoCommit;
public final PoolElf poolElf;
final PoolElf poolElf;
final HikariConfig config;
final ConcurrentBag<PoolBagEntry> connectionBag;
final ScheduledThreadPoolExecutor houseKeepingExecutorService;
@ -94,9 +86,6 @@ public class HikariPool implements HikariPoolMBean, IBagStateListener
private final ThreadPoolExecutor addConnectionExecutor;
private final ThreadPoolExecutor closeConnectionExecutor;
private final boolean isUseJdbc4Validation;
private final boolean isIsolateInternalQueries;
private volatile int poolState;
private long connectionTimeout;
@ -124,14 +113,6 @@ public class HikariPool implements HikariPoolMBean, IBagStateListener
this.totalConnections = new AtomicInteger();
this.connectionTimeout = config.getConnectionTimeout();
this.lastConnectionFailure = new AtomicReference<>();
this.catalog = config.getCatalog();
this.isReadOnly = config.isReadOnly();
this.isAutoCommit = config.isAutoCommit();
this.isUseJdbc4Validation = config.getConnectionTestQuery() == null;
this.isIsolateInternalQueries = config.isIsolateInternalQueries();
this.transactionIsolation = getTransactionIsolation(config.getTransactionIsolation());
this.suspendResumeLock = config.isAllowPoolSuspension() ? new SuspendResumeLock(true) : SuspendResumeLock.FAUX_LOCK;
this.addConnectionExecutor = createThreadPoolExecutor(config.getMaximumPoolSize(), "Hikari connection filler (pool " + config.getPoolName() + ")", config.getThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());
@ -193,7 +174,7 @@ public class HikariPool implements HikariPoolMBean, IBagStateListener
}
final long now = clockSource.currentTime();
if (bagEntry.evicted || (clockSource.elapsedMillis(bagEntry.lastAccess, now) > ALIVE_BYPASS_WINDOW_MS && !isConnectionAlive(bagEntry.connection))) {
if (bagEntry.evicted || (clockSource.elapsedMillis(bagEntry.lastAccess, now) > ALIVE_BYPASS_WINDOW_MS && !poolElf.isConnectionAlive(bagEntry.connection))) {
closeConnection(bagEntry, "(connection evicted or dead)"); // Throw away the dead connection and try again
timeout = hardTimeout - clockSource.elapsedMillis(startTime, now);
}
@ -487,21 +468,12 @@ public class HikariPool implements HikariPoolMBean, IBagStateListener
String password = config.getPassword();
connection = (username == null && password == null) ? dataSource.getConnection() : dataSource.getConnection(username, password);
if (isUseJdbc4Validation && !poolElf.isJdbc4ValidationSupported(connection)) {
throw new SQLException("JDBC4 Connection.isValid() method not supported, connection test query must be configured");
}
final int originalTimeout = poolElf.getAndSetNetworkTimeout(connection, connectionTimeout);
transactionIsolation = (transactionIsolation < 0 ? connection.getTransactionIsolation() : transactionIsolation);
poolElf.setupConnection(connection, config.getConnectionInitSql(), isAutoCommit, isReadOnly, transactionIsolation, catalog);
poolElf.setupConnection(connection, connectionTimeout);
poolElf.setNetworkTimeout(connection, originalTimeout);
connectionBag.add(new PoolBagEntry(connection, originalTimeout, this));
connectionBag.add(new PoolBagEntry(connection, this));
lastConnectionFailure.set(null);
LOGGER.debug("Connection {} added to pool {} ", connection, config.getPoolName());
return true;
}
catch (Exception e) {
@ -535,44 +507,6 @@ public class HikariPool implements HikariPoolMBean, IBagStateListener
}
}
/**
* Check whether the connection is alive or not.
*
* @param connection the connection to test
* @return true if the connection is alive, false if it is not alive or we timed out
*/
private boolean isConnectionAlive(final Connection connection)
{
try {
int timeoutSec = (int) TimeUnit.MILLISECONDS.toSeconds(config.getValidationTimeout());
if (isUseJdbc4Validation) {
return connection.isValid(timeoutSec);
}
final int originalTimeout = poolElf.getAndSetNetworkTimeout(connection, config.getValidationTimeout());
try (Statement statement = connection.createStatement()) {
poolElf.setQueryTimeout(statement, timeoutSec);
try (ResultSet rs = statement.executeQuery(config.getConnectionTestQuery())) {
/* auto close */
}
}
if (isIsolateInternalQueries && !isAutoCommit) {
connection.rollback();
}
poolElf.setNetworkTimeout(connection, originalTimeout);
return true;
}
catch (SQLException e) {
LOGGER.warn("Exception during alive check, Connection ({}) declared dead.", connection, e);
return false;
}
}
/**
* Attempt to abort() active connections, or close() them.
*/
@ -652,7 +586,9 @@ public class HikariPool implements HikariPoolMBean, IBagStateListener
@Override
public void run()
{
connectionTimeout = config.getConnectionTimeout(); // refresh member in case it changed
// refresh timeouts in case they changed via MBean
connectionTimeout = config.getConnectionTimeout();
poolElf.setValidationTimeout(config.getValidationTimeout());
final long now = clockSource.currentTime();
final long idleTimeout = config.getIdleTimeout();

@ -16,6 +16,7 @@
package com.zaxxer.hikari.pool;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadLocalRandom;
@ -33,26 +34,36 @@ import com.zaxxer.hikari.util.FastList;
*/
public final class PoolBagEntry implements IConcurrentBagEntry
{
public final AtomicInteger state = new AtomicInteger();
public final FastList<Statement> openStatements;
public final HikariPool parentPool;
public Connection connection;
public int networkTimeout;
public long lastAccess;
public volatile long lastOpenTime;
public volatile boolean evicted;
public volatile boolean aborted;
int networkTimeout;
int transactionIsolation;
String catalog;
boolean isAutoCommit;
boolean isReadOnly;
private final PoolElf poolElf;
private final AtomicInteger state = new AtomicInteger();
private volatile ScheduledFuture<?> endOfLife;
public PoolBagEntry(final Connection connection, final int networkTimeout, final HikariPool pool) {
public PoolBagEntry(final Connection connection, final HikariPool pool) {
this.connection = connection;
this.networkTimeout = networkTimeout;
this.parentPool = pool;
this.poolElf = pool.poolElf;
this.lastAccess = ClockSource.INSTANCE.currentTime();
this.openStatements = new FastList<>(Statement.class, 16);
poolElf.resetPoolEntry(this);
final long maxLifetime = pool.config.getMaxLifetime();
final long variance = maxLifetime > 60_000 ? ThreadLocalRandom.current().nextLong(10_000) : 0;
final long lifetime = maxLifetime - variance;
@ -74,6 +85,68 @@ public final class PoolBagEntry implements IConcurrentBagEntry
}
}
/**
* Release this entry back to the pool.
*
* @param lastAccess last access time-stamp
*/
public void releaseConnection(final long lastAccess)
{
this.lastAccess = lastAccess;
parentPool.releaseConnection(this);
}
/**
* Reset the connection to its original state.
* @throws SQLException thrown if there is an error resetting the connection state
*/
public void resetConnectionState() throws SQLException
{
poolElf.resetConnectionState(this);
poolElf.resetPoolEntry(this);
}
/**
* @param networkTimeout the networkTimeout to set
*/
public void setNetworkTimeout(int networkTimeout)
{
this.networkTimeout = networkTimeout;
}
/**
* @param transactionIsolation the transactionIsolation to set
*/
public void setTransactionIsolation(int transactionIsolation)
{
this.transactionIsolation = transactionIsolation;
}
/**
* @param catalog the catalog to set
*/
public void setCatalog(String catalog)
{
this.catalog = catalog;
}
/**
* @param isAutoCommit the isAutoCommit to set
*/
public void setAutoCommit(boolean isAutoCommit)
{
this.isAutoCommit = isAutoCommit;
}
/**
* @param isReadOnly the isReadOnly to set
*/
public void setReadOnly(boolean isReadOnly)
{
this.isReadOnly = isReadOnly;
}
void cancelMaxLifeTermination()
{
if (endOfLife != null) {

@ -3,7 +3,9 @@ package com.zaxxer.hikari.pool;
import static com.zaxxer.hikari.util.UtilityElf.createInstance;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
@ -29,22 +31,41 @@ public final class PoolElf
{
private static final Logger LOGGER = LoggerFactory.getLogger(PoolElf.class);
private int networkTimeout;
private int transactionIsolation;
private long validationTimeout;
private boolean isNetworkTimeoutSupported;
private boolean isQueryTimeoutSupported;
private Executor netTimeoutExecutor;
private final HikariConfig config;
private final String poolName;
private final String catalog;
private final boolean isReadOnly;
private final boolean isAutoCommit;
private final boolean isUseJdbc4Validation;
private final boolean isIsolateInternalQueries;
private volatile boolean isValidChecked;
private volatile boolean isValidSupported;
private boolean isNetworkTimeoutSupported;
private boolean isQueryTimeoutSupported;
public PoolElf(final HikariConfig configuration)
{
this.config = configuration;
this.poolName = configuration.getPoolName();
this.networkTimeout = -1;
this.catalog = config.getCatalog();
this.isReadOnly = config.isReadOnly();
this.isAutoCommit = config.isAutoCommit();
this.validationTimeout = config.getValidationTimeout();
this.transactionIsolation = getTransactionIsolation(config.getTransactionIsolation());
this.isValidSupported = true;
this.isNetworkTimeoutSupported = true;
this.isQueryTimeoutSupported = true;
this.isNetworkTimeoutSupported = true;
this.isUseJdbc4Validation = config.getConnectionTestQuery() == null;
this.isIsolateInternalQueries = config.isIsolateInternalQueries();
this.poolName = config.getPoolName();
}
/**
@ -74,12 +95,33 @@ public final class PoolElf
}
}
/**
* Get the int value of a transaction isolation level by name.
*
* @param transactionIsolationName the name of the transaction isolation level
* @return the int value of the isolation level or -1
*/
public static int getTransactionIsolation(final String transactionIsolationName)
{
if (transactionIsolationName != null) {
try {
Field field = Connection.class.getField(transactionIsolationName);
return field.getInt(null);
}
catch (Exception e) {
throw new IllegalArgumentException("Invalid transaction isolation value: " + transactionIsolationName);
}
}
return -1;
}
/**
* Create/initialize the underlying DataSource.
*
* @return a DataSource instance
*/
public DataSource initializeDataSource()
DataSource initializeDataSource()
{
final String jdbcUrl = config.getJdbcUrl();
final String username = config.getUsername();
@ -109,6 +151,7 @@ public final class PoolElf
* Setup a connection initial state.
*
* @param connection a Connection
* @param connectionTimeout
* @param initSql
* @param isAutoCommit auto-commit state
* @param isReadOnly read-only state
@ -116,18 +159,161 @@ public final class PoolElf
* @param catalog default catalog
* @throws SQLException thrown from driver
*/
public void setupConnection(final Connection connection, final String initSql, final boolean isAutoCommit, final boolean isReadOnly, final int transactionIsolation, final String catalog) throws SQLException
void setupConnection(final Connection connection, final long connectionTimeout) throws SQLException
{
if (isUseJdbc4Validation && !isJdbc4ValidationSupported(connection)) {
throw new SQLException("JDBC4 Connection.isValid() method not supported, connection test query must be configured");
}
networkTimeout = (networkTimeout < 0 ? getAndSetNetworkTimeout(connection, connectionTimeout) : networkTimeout);
transactionIsolation = (transactionIsolation < 0 ? connection.getTransactionIsolation() : transactionIsolation);
connection.setAutoCommit(isAutoCommit);
connection.setReadOnly(isReadOnly);
if (transactionIsolation != connection.getTransactionIsolation()) {
connection.setTransactionIsolation(transactionIsolation);
}
if (catalog != null) {
connection.setCatalog(catalog);
}
executeSql(connection, initSql, isAutoCommit);
executeSql(connection, config.getConnectionInitSql(), isAutoCommit);
setNetworkTimeout(connection, networkTimeout);
}
/**
* Check whether the connection is alive or not.
*
* @param connection the connection to test
* @return true if the connection is alive, false if it is not alive or we timed out
*/
boolean isConnectionAlive(final Connection connection)
{
try {
int timeoutSec = (int) TimeUnit.MILLISECONDS.toSeconds(validationTimeout);
if (isUseJdbc4Validation) {
return connection.isValid(timeoutSec);
}
networkTimeout = getAndSetNetworkTimeout(connection, validationTimeout);
try (Statement statement = connection.createStatement()) {
setQueryTimeout(statement, timeoutSec);
try (ResultSet rs = statement.executeQuery(config.getConnectionTestQuery())) {
/* auto close */
}
}
if (isIsolateInternalQueries && !isAutoCommit) {
connection.rollback();
}
setNetworkTimeout(connection, networkTimeout);
return true;
}
catch (SQLException e) {
LOGGER.warn("Exception during alive check, Connection ({}) declared dead.", connection, e);
return false;
}
}
void resetConnectionState(final PoolBagEntry poolEntry) throws SQLException
{
if (poolEntry.isReadOnly != isReadOnly) {
poolEntry.connection.setReadOnly(isReadOnly);
}
if (poolEntry.isAutoCommit != isAutoCommit) {
poolEntry.connection.setAutoCommit(isAutoCommit);
}
if (poolEntry.transactionIsolation != transactionIsolation) {
poolEntry.connection.setTransactionIsolation(transactionIsolation);
}
final String currentCatalog = poolEntry.catalog;
if ((currentCatalog != null && !currentCatalog.equals(catalog)) || (currentCatalog == null && catalog != null)) {
poolEntry.connection.setCatalog(catalog);
}
if (poolEntry.networkTimeout != networkTimeout) {
setNetworkTimeout(poolEntry.connection, networkTimeout);
}
}
void resetPoolEntry(final PoolBagEntry poolEntry)
{
poolEntry.setCatalog(catalog);
poolEntry.setReadOnly(isReadOnly);
poolEntry.setAutoCommit(isAutoCommit);
poolEntry.setNetworkTimeout(networkTimeout);
poolEntry.setTransactionIsolation(transactionIsolation);
}
void setValidationTimeout(final long validationTimeout)
{
this.validationTimeout = validationTimeout;
}
/**
* Register MBeans for HikariConfig and HikariPool.
*
* @param configuration a HikariConfig instance
* @param pool a HikariPool instance
*/
void registerMBeans(final HikariPool pool)
{
if (!config.isRegisterMbeans()) {
return;
}
try {
final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
final ObjectName beanConfigName = new ObjectName("com.zaxxer.hikari:type=PoolConfig (" + poolName + ")");
final ObjectName beanPoolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + poolName + ")");
if (!mBeanServer.isRegistered(beanConfigName)) {
mBeanServer.registerMBean(config, beanConfigName);
mBeanServer.registerMBean(pool, beanPoolName);
}
else {
LOGGER.error("You cannot use the same pool name for separate pool instances.");
}
}
catch (Exception e) {
LOGGER.warn("Unable to register management beans.", e);
}
}
/**
* Unregister MBeans for HikariConfig and HikariPool.
*
* @param configuration a HikariConfig instance
*/
void unregisterMBeans()
{
if (!config.isRegisterMbeans()) {
return;
}
try {
final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
final ObjectName beanConfigName = new ObjectName("com.zaxxer.hikari:type=PoolConfig (" + poolName + ")");
final ObjectName beanPoolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + poolName + ")");
if (mBeanServer.isRegistered(beanConfigName)) {
mBeanServer.unregisterMBean(beanConfigName);
mBeanServer.unregisterMBean(beanPoolName);
}
}
catch (Exception e) {
LOGGER.warn("Unable to unregister management beans.", e);
}
}
/**
@ -136,7 +322,7 @@ public final class PoolElf
* @param connection a Connection to check
* @return true if JDBC 4.1 compliance, false otherwise
*/
public boolean isJdbc4ValidationSupported(final Connection connection)
private boolean isJdbc4ValidationSupported(final Connection connection)
{
if (!isValidChecked) {
try {
@ -161,7 +347,7 @@ public final class PoolElf
* @param statement a statement to set the query timeout on
* @param timeoutSec the number of seconds before timeout
*/
public void setQueryTimeout(final Statement statement, final int timeoutSec)
private void setQueryTimeout(final Statement statement, final int timeoutSec)
{
if (isQueryTimeoutSupported) {
try {
@ -182,7 +368,7 @@ public final class PoolElf
* @param timeoutMs the number of milliseconds before timeout
* @return the pre-existing network timeout value
*/
public int getAndSetNetworkTimeout(final Connection connection, final long timeoutMs)
private int getAndSetNetworkTimeout(final Connection connection, final long timeoutMs)
{
if (isNetworkTimeoutSupported) {
try {
@ -207,69 +393,13 @@ public final class PoolElf
* @param timeoutMs the number of milliseconds before timeout
* @throws SQLException throw if the connection.setNetworkTimeout() call throws
*/
public void setNetworkTimeout(final Connection connection, final long timeoutMs) throws SQLException
private void setNetworkTimeout(final Connection connection, final long timeoutMs) throws SQLException
{
if (isNetworkTimeoutSupported) {
connection.setNetworkTimeout(netTimeoutExecutor, (int) timeoutMs);
}
}
/**
* Register MBeans for HikariConfig and HikariPool.
*
* @param configuration a HikariConfig instance
* @param pool a HikariPool instance
*/
void registerMBeans(final HikariPool pool)
{
if (!config.isRegisterMbeans()) {
return;
}
try {
final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
final ObjectName beanConfigName = new ObjectName("com.zaxxer.hikari:type=PoolConfig (" + poolName + ")");
final ObjectName beanPoolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + poolName + ")");
if (!mBeanServer.isRegistered(beanConfigName)) {
mBeanServer.registerMBean(config, beanConfigName);
mBeanServer.registerMBean(pool, beanPoolName);
}
else {
LOGGER.error("You cannot use the same pool name for separate pool instances.");
}
}
catch (Exception e) {
LOGGER.warn("Unable to register management beans.", e);
}
}
/**
* Unregister MBeans for HikariConfig and HikariPool.
*
* @param configuration a HikariConfig instance
*/
void unregisterMBeans()
{
if (!config.isRegisterMbeans()) {
return;
}
try {
final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
final ObjectName beanConfigName = new ObjectName("com.zaxxer.hikari:type=PoolConfig (" + poolName + ")");
final ObjectName beanPoolName = new ObjectName("com.zaxxer.hikari:type=Pool (" + poolName + ")");
if (mBeanServer.isRegistered(beanConfigName)) {
mBeanServer.unregisterMBean(beanConfigName);
mBeanServer.unregisterMBean(beanPoolName);
}
}
catch (Exception e) {
LOGGER.warn("Unable to unregister management beans.", e);
}
}
/**
* Execute the user-specified init SQL.
*

@ -49,17 +49,12 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
protected Connection delegate;
private final LeakTask leakTask;
private final PoolBagEntry bagEntry;
private final PoolBagEntry poolEntry;
private final FastList<Statement> openStatements;
private int networkTimeout;
private long lastAccess;
private boolean isCommitStateDirty;
private boolean isConnectionStateDirty;
private boolean isAutoCommitDirty;
private boolean isCatalogDirty;
private boolean isReadOnlyDirty;
private boolean isTransactionIsolationDirty;
// static initializer
static {
@ -75,7 +70,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
protected ConnectionProxy(final PoolBagEntry bagEntry, final LeakTask leakTask, final long now) {
this.bagEntry = bagEntry;
this.poolEntry = bagEntry;
this.leakTask = leakTask;
this.lastAccess = now;
@ -101,7 +96,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
@Override
public final PoolBagEntry getPoolBagEntry()
{
return bagEntry;
return poolEntry;
}
/** {@inheritDoc} */
@ -112,9 +107,9 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
if (sqlState != null) {
boolean isForceClose = sqlState.startsWith("08") | SQL_ERRORS.contains(sqlState);
if (isForceClose) {
bagEntry.evicted = true;
poolEntry.evicted = true;
LOGGER.warn("Connection {} ({}) marked as broken because of SQLSTATE({}), ErrorCode({}).",
delegate, bagEntry.parentPool, sqlState, sqle.getErrorCode(), sqle);
delegate, poolEntry.parentPool, sqlState, sqle.getErrorCode(), sqle);
}
else {
SQLException nse = sqle.getNextException();
@ -153,25 +148,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
private final void resetConnectionState() throws SQLException
{
if (isReadOnlyDirty) {
delegate.setReadOnly(bagEntry.parentPool.isReadOnly);
}
if (isAutoCommitDirty) {
delegate.setAutoCommit(bagEntry.parentPool.isAutoCommit);
}
if (isTransactionIsolationDirty) {
delegate.setTransactionIsolation(bagEntry.parentPool.transactionIsolation);
}
if (isCatalogDirty && bagEntry.parentPool.catalog != null) {
delegate.setCatalog(bagEntry.parentPool.catalog);
}
if (networkTimeout != bagEntry.networkTimeout) {
bagEntry.parentPool.poolUtils.setNetworkTimeout(delegate, bagEntry.networkTimeout);
}
poolEntry.resetConnectionState();
lastAccess = clockSource.currentTime();
}
@ -216,14 +193,13 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
}
catch (SQLException e) {
// when connections are aborted, exceptions are often thrown that should not reach the application
if (!bagEntry.aborted) {
if (!poolEntry.aborted) {
throw checkException(e);
}
}
finally {
delegate = ClosedConnection.CLOSED_CONNECTION;
bagEntry.lastAccess = this.lastAccess;
bagEntry.parentPool.releaseConnection(bagEntry);
poolEntry.releaseConnection(lastAccess);
}
}
}
@ -351,8 +327,8 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
public void setAutoCommit(boolean autoCommit) throws SQLException
{
delegate.setAutoCommit(autoCommit);
poolEntry.setAutoCommit(autoCommit);
isConnectionStateDirty = true;
isAutoCommitDirty = (autoCommit != bagEntry.parentPool.isAutoCommit);
}
/** {@inheritDoc} */
@ -360,8 +336,8 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
public void setReadOnly(boolean readOnly) throws SQLException
{
delegate.setReadOnly(readOnly);
poolEntry.setReadOnly(readOnly);
isConnectionStateDirty = true;
isReadOnlyDirty = (readOnly != bagEntry.parentPool.isReadOnly);
}
/** {@inheritDoc} */
@ -369,8 +345,8 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
public void setTransactionIsolation(int level) throws SQLException
{
delegate.setTransactionIsolation(level);
poolEntry.setTransactionIsolation(level);
isConnectionStateDirty = true;
isTransactionIsolationDirty = (level != bagEntry.parentPool.transactionIsolation);
}
/** {@inheritDoc} */
@ -378,8 +354,8 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
public void setCatalog(String catalog) throws SQLException
{
delegate.setCatalog(catalog);
poolEntry.setCatalog(catalog);
isConnectionStateDirty = true;
isCatalogDirty = (catalog != null && !catalog.equals(bagEntry.parentPool.catalog)) || (catalog == null && bagEntry.parentPool.catalog != null);
}
/** {@inheritDoc} */
@ -387,7 +363,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException
{
delegate.setNetworkTimeout(executor, milliseconds);
networkTimeout = milliseconds;
poolEntry.setNetworkTimeout(milliseconds);
isConnectionStateDirty = true;
}

@ -17,8 +17,6 @@
package com.zaxxer.hikari.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
@ -102,25 +100,4 @@ public final class UtilityElf
executor.allowCoreThreadTimeOut(true);
return executor;
}
/**
* Get the int value of a transaction isolation level by name.
*
* @param transactionIsolationName the name of the transaction isolation level
* @return the int value of the isolation level or -1
*/
public static int getTransactionIsolation(final String transactionIsolationName)
{
if (transactionIsolationName != null) {
try {
Field field = Connection.class.getField(transactionIsolationName);
return field.getInt(null);
}
catch (Exception e) {
throw new IllegalArgumentException("Invalid transaction isolation value: " + transactionIsolationName);
}
}
return -1;
}
}

@ -8,7 +8,7 @@ import java.sql.Statement;
import org.junit.Assert;
import org.junit.Test;
import com.zaxxer.hikari.util.UtilityElf;
import com.zaxxer.hikari.pool.PoolElf;
public class ConnectionStateTest
{
@ -70,7 +70,7 @@ public class ConnectionStateTest
config.setTransactionIsolation("TRANSACTION_REPEATABLE_READ");
config.validate();
int transactionIsolation = UtilityElf.getTransactionIsolation(config.getTransactionIsolation());
int transactionIsolation = PoolElf.getTransactionIsolation(config.getTransactionIsolation());
Assert.assertSame(Connection.TRANSACTION_REPEATABLE_READ, transactionIsolation);
}

@ -30,6 +30,7 @@ import org.slf4j.spi.LocationAwareLogger;
import com.zaxxer.hikari.pool.HikariPool;
import com.zaxxer.hikari.pool.LeakTask;
import com.zaxxer.hikari.pool.PoolElf;
import com.zaxxer.hikari.util.UtilityElf;
/**
@ -65,7 +66,7 @@ public class MiscTest
public void testInvalidIsolation()
{
try {
UtilityElf.getTransactionIsolation("INVALID");
PoolElf.getTransactionIsolation("INVALID");
Assert.fail();
}
catch (Exception e) {

@ -103,15 +103,15 @@ public class TestConcurrentBag
Assert.assertEquals(0, bag.values(8).size());
HikariPool pool = TestElf.getPool(ds);
PoolBagEntry reserved = new PoolBagEntry(null, 0, TestElf.getPool(ds));
PoolBagEntry reserved = new PoolBagEntry(null, TestElf.getPool(ds));
bag.add(reserved);
bag.reserve(reserved); // reserved
PoolBagEntry inuse = new PoolBagEntry(null, 0, pool);
PoolBagEntry inuse = new PoolBagEntry(null, pool);
bag.add(inuse);
bag.borrow(2, TimeUnit.MILLISECONDS); // in use
PoolBagEntry notinuse = new PoolBagEntry(null, 0, pool);
PoolBagEntry notinuse = new PoolBagEntry(null, pool);
bag.add(notinuse); // not in use
bag.dumpState();
@ -135,7 +135,7 @@ public class TestConcurrentBag
bag.close();
try {
PoolBagEntry bagEntry = new PoolBagEntry(null, 0, pool);
PoolBagEntry bagEntry = new PoolBagEntry(null, pool);
bag.add(bagEntry);
Assert.assertNotEquals(bagEntry, bag.borrow(100, TimeUnit.MILLISECONDS));
}

Loading…
Cancel
Save