Full refactor.

pull/422/head
Brett Wooldridge 10 years ago
parent 0e6a595612
commit aca80d3ed9

@ -171,7 +171,7 @@
</execution>
</executions>
<configuration>
<mainClass>com.zaxxer.hikari.proxy.JavassistProxyFactory</mainClass>
<mainClass>com.zaxxer.hikari.util.JavassistProxyFactory</mainClass>
</configuration>
</plugin>

@ -40,8 +40,8 @@ import org.slf4j.LoggerFactory;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.health.HealthCheckRegistry;
import com.zaxxer.hikari.metrics.MetricsTrackerFactory;
import com.zaxxer.hikari.pool.Mediator;
import com.zaxxer.hikari.util.PropertyElf;
import com.zaxxer.hikari.util.UtilityElf;
public class HikariConfig implements HikariConfigMXBean
{
@ -775,7 +775,7 @@ public class HikariConfig implements HikariConfigMXBean
}
if (transactionIsolationName != null) {
Mediator.getTransactionIsolation(transactionIsolationName);
UtilityElf.getTransactionIsolation(transactionIsolationName);
}
if (LOGGER.isDebugEnabled() || unitTest) {

@ -30,7 +30,6 @@ import org.slf4j.LoggerFactory;
import com.zaxxer.hikari.metrics.MetricsTrackerFactory;
import com.zaxxer.hikari.pool.HikariPool;
import com.zaxxer.hikari.proxy.IHikariConnectionProxy;
/**
* The HikariCP pooled DataSource.
@ -111,7 +110,7 @@ public class HikariDataSource extends HikariConfig implements DataSource, Closea
@Override
public PrintWriter getLogWriter() throws SQLException
{
return (pool != null ? pool.getDataSource().getLogWriter() : null);
return (pool != null ? pool.getUnwrappedDataSource().getLogWriter() : null);
}
/** {@inheritDoc} */
@ -119,7 +118,7 @@ public class HikariDataSource extends HikariConfig implements DataSource, Closea
public void setLogWriter(PrintWriter out) throws SQLException
{
if (pool != null) {
pool.getDataSource().setLogWriter(out);
pool.getUnwrappedDataSource().setLogWriter(out);
}
}
@ -128,7 +127,7 @@ public class HikariDataSource extends HikariConfig implements DataSource, Closea
public void setLoginTimeout(int seconds) throws SQLException
{
if (pool != null) {
pool.getDataSource().setLoginTimeout(seconds);
pool.getUnwrappedDataSource().setLoginTimeout(seconds);
}
}
@ -136,7 +135,7 @@ public class HikariDataSource extends HikariConfig implements DataSource, Closea
@Override
public int getLoginTimeout() throws SQLException
{
return (pool != null ? pool.getDataSource().getLoginTimeout() : 0);
return (pool != null ? pool.getUnwrappedDataSource().getLoginTimeout() : 0);
}
/** {@inheritDoc} */
@ -156,12 +155,12 @@ public class HikariDataSource extends HikariConfig implements DataSource, Closea
}
if (pool != null) {
if (iface.isInstance(pool.getDataSource())) {
return (T) pool.getDataSource();
if (iface.isInstance(pool.getUnwrappedDataSource())) {
return (T) pool.getUnwrappedDataSource();
}
if (pool.getDataSource() != null) {
return (T) pool.getDataSource().unwrap(iface);
if (pool.getUnwrappedDataSource() != null) {
return (T) pool.getUnwrappedDataSource().unwrap(iface);
}
}
@ -177,12 +176,12 @@ public class HikariDataSource extends HikariConfig implements DataSource, Closea
}
if (pool != null) {
if (iface.isInstance(pool.getDataSource())) {
if (iface.isInstance(pool.getUnwrappedDataSource())) {
return true;
}
if (pool.getDataSource() != null) {
return pool.getDataSource().isWrapperFor(iface);
if (pool.getUnwrappedDataSource() != null) {
return pool.getUnwrappedDataSource().isWrapperFor(iface);
}
}
@ -247,8 +246,8 @@ public class HikariDataSource extends HikariConfig implements DataSource, Closea
*/
public void evictConnection(Connection connection)
{
if (!isClosed() && pool != null && connection instanceof IHikariConnectionProxy) {
pool.evictConnection((IHikariConnectionProxy) connection);
if (!isClosed() && pool != null && connection.getClass().getName().startsWith("com.zaxxer.hikari")) {
pool.evictConnection(connection);
}
}

@ -36,8 +36,6 @@ import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -51,14 +49,11 @@ import com.zaxxer.hikari.metrics.MetricsTracker;
import com.zaxxer.hikari.metrics.MetricsTracker.MetricsContext;
import com.zaxxer.hikari.metrics.MetricsTrackerFactory;
import com.zaxxer.hikari.metrics.PoolStats;
import com.zaxxer.hikari.pool.Mediators.PoolEntryMediator;
import com.zaxxer.hikari.pool.Mediators.JdbcMediator;
import com.zaxxer.hikari.pool.Mediators.PoolMediator;
import com.zaxxer.hikari.proxy.IHikariConnectionProxy;
import com.zaxxer.hikari.util.ClockSource;
import com.zaxxer.hikari.util.ConcurrentBag;
import com.zaxxer.hikari.util.ConcurrentBag.IBagStateListener;
import com.zaxxer.hikari.util.DefaultThreadFactory;
import com.zaxxer.hikari.util.SuspendResumeLock;
/**
* This is the primary connection pool class that provides the basic
@ -66,7 +61,7 @@ import com.zaxxer.hikari.util.DefaultThreadFactory;
*
* @author Brett Wooldridge
*/
public class HikariPool implements HikariPoolMXBean, IBagStateListener
public class HikariPool extends PoolBase implements HikariPoolMXBean, IBagStateListener
{
private static final Logger LOGGER = LoggerFactory.getLogger(HikariPool.class);
@ -79,13 +74,12 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
private static final int POOL_SUSPENDED = 1;
private static final int POOL_SHUTDOWN = 2;
final HikariConfig config;
final ConcurrentBag<PoolEntry> connectionBag;
final ScheduledThreadPoolExecutor houseKeepingExecutorService;
private final JdbcMediator jdbcMediator;
private final PoolMediator poolMediator;
private final PoolEntryMediator entryMediator;
// private final JdbcMediator jdbcMediator;
// private final PoolMediator poolMediator;
// private final PoolEntryMediator entryMediator;
private final AtomicInteger totalConnections;
private final ThreadPoolExecutor addConnectionExecutor;
@ -95,7 +89,7 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
private long connectionTimeout;
private final String poolName;
private final LeakTask leakTask;
private final ProxyLeakTask leakTask;
private final SuspendResumeLock suspendResumeLock;
private volatile MetricsTracker metricsTracker;
@ -108,18 +102,17 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
*/
public HikariPool(final HikariConfig config)
{
this.config = config;
super(config);
final Mediator mediators = new Mediator(this);
this.jdbcMediator = mediators.getJdbcMediator();
this.poolMediator = mediators.getPoolMediator();
this.entryMediator = mediators.getConnectionStateMediator();
// this.jdbcMediator = mediators.getJdbcMediator();
// this.poolMediator = mediators.getPoolMediator();
// this.entryMediator = mediators.getConnectionStateMediator();
this.poolName = config.getPoolName();
this.connectionBag = new ConcurrentBag<>(this);
this.totalConnections = new AtomicInteger();
this.connectionTimeout = config.getConnectionTimeout();
this.suspendResumeLock = config.isAllowPoolSuspension() ? new SuspendResumeLock(true) : SuspendResumeLock.FAUX_LOCK;
this.suspendResumeLock = config.isAllowPoolSuspension() ? new SuspendResumeLock() : SuspendResumeLock.FAUX_LOCK;
this.addConnectionExecutor = createThreadPoolExecutor(config.getMaximumPoolSize(), "Hikari connection filler (pool " + poolName + ")", config.getThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());
this.closeConnectionExecutor = createThreadPoolExecutor(4, "Hikari connection closer (pool " + poolName + ")", config.getThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
@ -136,7 +129,7 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
this.houseKeepingExecutorService.scheduleAtFixedRate(new HouseKeeper(), HOUSEKEEPING_PERIOD_MS, HOUSEKEEPING_PERIOD_MS, TimeUnit.MILLISECONDS);
this.leakTask = new LeakTask(config.getLeakDetectionThreshold(), houseKeepingExecutorService);
this.leakTask = new ProxyLeakTask(config.getLeakDetectionThreshold(), houseKeepingExecutorService);
if (config.getMetricsTrackerFactory() != null) {
setMetricsTrackerFactory(config.getMetricsTrackerFactory());
@ -147,7 +140,7 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
setHealthCheckRegistry(config.getHealthCheckRegistry());
poolMediator.registerMBeans();
registerMBeans(this);
initializeConnections();
}
@ -185,7 +178,7 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
}
final long now = clockSource.currentTime();
if (poolEntry.evict || (clockSource.elapsedMillis(poolEntry.lastAccess, now) > ALIVE_BYPASS_WINDOW_MS && !jdbcMediator.isConnectionAlive(poolEntry.connection))) {
if (poolEntry.evict || (clockSource.elapsedMillis(poolEntry.lastAccess, 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, now);
}
@ -207,7 +200,7 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
logPoolState("Timeout failure\t");
String sqlState = null;
final Throwable originalException = jdbcMediator.getLastConnectionFailure();
final Throwable originalException = getLastConnectionFailure();
if (originalException instanceof SQLException) {
sqlState = ((SQLException) originalException).getSQLState();
}
@ -272,14 +265,14 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
assassinExecutor.awaitTermination(5L, TimeUnit.SECONDS);
}
poolMediator.shutdownTimeoutExecutor();
shutdownNetworkTimeoutExecutor();
closeConnectionExecutor.shutdown();
closeConnectionExecutor.awaitTermination(5L, TimeUnit.SECONDS);
}
finally {
logPoolState("After closing\t");
poolMediator.unregisterMBeans();
unregisterMBeans();
metricsTracker.close();
}
}
@ -289,19 +282,9 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
*
* @param proxyConnection the connection to evict
*/
public final void evictConnection(IHikariConnectionProxy proxyConnection)
{
softEvictConnection(proxyConnection.getPoolEntry(), "(connection evicted by user)", true /* owner */);
}
/**
* Get the wrapped DataSource.
*
* @return the wrapped DataSource
*/
public final DataSource getDataSource()
public final void evictConnection(Connection proxyConnection)
{
return jdbcMediator.getUnwrappedDataSource();
softEvictConnection(((ProxyConnection) proxyConnection).getPoolEntry(), "(connection evicted by user)", true /* owner */);
}
public void setMetricRegistry(Object metricRegistry)
@ -468,7 +451,7 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
closeConnectionExecutor.execute(new Runnable() {
@Override
public void run() {
jdbcMediator.quietlyCloseConnection(connection, closureReason);
quietlyCloseConnection(connection, closureReason);
}
});
}
@ -490,7 +473,7 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
}
try {
final PoolEntry poolEntry = entryMediator.newPoolEntry();
final PoolEntry poolEntry = newPoolEntry();
connectionBag.add(poolEntry);
final long maxLifetime = config.getMaxLifetime();
@ -548,7 +531,7 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
poolEntry.connection.abort(assassinExecutor);
}
catch (Throwable e) {
jdbcMediator.quietlyCloseConnection(poolEntry.connection, "(connection aborted during shutdown)");
quietlyCloseConnection(poolEntry.connection, "(connection aborted during shutdown)");
}
finally {
poolEntry.close();
@ -567,7 +550,7 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
if (config.isInitializationFailFast()) {
try {
if (!addConnection()) {
throw jdbcMediator.getLastConnectionFailure();
throw getLastConnectionFailure();
}
final PoolEntry poolEntry = connectionBag.borrow(connectionTimeout, TimeUnit.MILLISECONDS);
@ -667,4 +650,18 @@ public class HikariPool implements HikariPoolMXBean, IBagStateListener
fillPool(); // Try to maintain minimum connections
}
}
public static class PoolInitializationException extends RuntimeException
{
private static final long serialVersionUID = 929872118275916520L;
/**
* Construct an exception, possibly wrapping the provided Throwable as the cause.
* @param t the Throwable to wrap
*/
public PoolInitializationException(Throwable t)
{
super("Exception during pool initialization: " + t.getMessage(), t);
}
}
}

@ -3,7 +3,6 @@ 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.SQLException;
import java.sql.Statement;
@ -23,17 +22,16 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.pool.Mediators.PoolEntryMediator;
import com.zaxxer.hikari.pool.Mediators.JdbcMediator;
import com.zaxxer.hikari.pool.Mediators.PoolMediator;
import com.zaxxer.hikari.proxy.ConnectionState;
import com.zaxxer.hikari.util.DefaultThreadFactory;
import com.zaxxer.hikari.util.DriverDataSource;
import com.zaxxer.hikari.util.PropertyElf;
import com.zaxxer.hikari.util.UtilityElf;
public final class Mediator implements Mediators, JdbcMediator, PoolMediator, PoolEntryMediator
abstract class PoolBase
{
private static final Logger LOGGER = LoggerFactory.getLogger(Mediator.class);
protected final Logger LOGGER = LoggerFactory.getLogger(getClass());
protected final HikariConfig config;
private static final String[] RESET_STATES = {"readOnly", "autoCommit", "isolation", "catalog", "netTimeout"};
private static final int UNINITIALIZED = -1;
private static final int TRUE = 1;
@ -46,8 +44,7 @@ public final class Mediator implements Mediators, JdbcMediator, PoolMediator, Po
private Executor netTimeoutExecutor;
private DataSource dataSource;
private final HikariPool hikariPool;
private final HikariConfig config;
// private final HikariPool hikariPool;
private final String poolName;
private final String catalog;
private final boolean isReadOnly;
@ -58,16 +55,15 @@ public final class Mediator implements Mediators, JdbcMediator, PoolMediator, Po
private volatile boolean isValidChecked;
public Mediator(final HikariPool pool)
public PoolBase(final HikariConfig config)
{
this.hikariPool = pool;
this.config = pool.config;
this.config = config;
this.networkTimeout = -1;
this.catalog = config.getCatalog();
this.isReadOnly = config.isReadOnly();
this.isAutoCommit = config.isAutoCommit();
this.transactionIsolation = getTransactionIsolation(config.getTransactionIsolation());
this.transactionIsolation = UtilityElf.getTransactionIsolation(config.getTransactionIsolation());
this.isQueryTimeoutSupported = UNINITIALIZED;
this.isNetworkTimeoutSupported = UNINITIALIZED;
@ -80,12 +76,17 @@ public final class Mediator implements Mediators, JdbcMediator, PoolMediator, Po
initializeDataSource();
}
public String getPoolName()
{
return poolName;
}
abstract void releaseConnection(final PoolEntry poolEntry);
// ***********************************************************************
// JdbcMediator methods
// JDBC methods
// ***********************************************************************
/** {@inheritDoc} */
@Override
public void quietlyCloseConnection(final Connection connection, final String closureReason)
{
try {
@ -107,8 +108,6 @@ public final class Mediator implements Mediators, JdbcMediator, PoolMediator, Po
}
}
/** {@inheritDoc} */
@Override
public boolean isConnectionAlive(final Connection connection)
{
try {
@ -143,15 +142,11 @@ public final class Mediator implements Mediators, JdbcMediator, PoolMediator, Po
}
}
/** {@inheritDoc} */
@Override
public DataSource getUnwrappedDataSource()
{
return dataSource;
}
/** {@inheritDoc} */
@Override
public Throwable getLastConnectionFailure()
{
return lastConnectionFailure.getAndSet(null);
@ -159,17 +154,15 @@ public final class Mediator implements Mediators, JdbcMediator, PoolMediator, Po
// ***********************************************************************
// ConnectionStateMediator methods
// PoolEntry methods
// ***********************************************************************
/** {@inheritDoc} */
@Override
public PoolEntry newPoolEntry() throws Exception
{
return new PoolEntry(newConnection(), hikariPool, this);
return new PoolEntry(newConnection(), this);
}
public void resetConnectionState(final Connection connection, final ConnectionState liveState, final int dirtyBits) throws SQLException
public void resetConnectionState(final Connection connection, final ProxyConnection liveState, final int dirtyBits) throws SQLException
{
int resetBits = 0;
@ -216,7 +209,7 @@ public final class Mediator implements Mediators, JdbcMediator, PoolMediator, Po
*
* @param pool a HikariPool instance
*/
public void registerMBeans()
public void registerMBeans(final HikariPool hikariPool)
{
if (!config.isRegisterMbeans()) {
return;
@ -264,79 +257,13 @@ public final class Mediator implements Mediators, JdbcMediator, PoolMediator, Po
}
}
public void shutdownTimeoutExecutor()
public void shutdownNetworkTimeoutExecutor()
{
if (netTimeoutExecutor != null && netTimeoutExecutor instanceof ThreadPoolExecutor) {
((ThreadPoolExecutor) netTimeoutExecutor).shutdownNow();
}
}
// ***********************************************************************
// Mediators accessors
// ***********************************************************************
/** {@inheritDoc} */
@Override
public JdbcMediator getJdbcMediator()
{
return this;
}
/** {@inheritDoc} */
@Override
public PoolEntryMediator getConnectionStateMediator()
{
return this;
}
/** {@inheritDoc} */
@Override
public PoolMediator getPoolMediator()
{
return this;
}
// ***********************************************************************
// Misc. public methods
// ***********************************************************************
/**
* 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 {
final String upperName = transactionIsolationName.toUpperCase();
if (upperName.startsWith("TRANSACTION_")) {
Field field = Connection.class.getField(upperName);
return field.getInt(null);
}
final int level = Integer.parseInt(transactionIsolationName);
switch (level) {
case Connection.TRANSACTION_READ_UNCOMMITTED:
case Connection.TRANSACTION_READ_COMMITTED:
case Connection.TRANSACTION_REPEATABLE_READ:
case Connection.TRANSACTION_SERIALIZABLE:
case Connection.TRANSACTION_NONE:
return level;
default:
throw new IllegalArgumentException();
}
}
catch (Exception e) {
throw new IllegalArgumentException("Invalid transaction isolation value: " + transactionIsolationName);
}
}
return -1;
}
// ***********************************************************************
// Private methods
// ***********************************************************************
@ -571,7 +498,7 @@ public final class Mediator implements Mediators, JdbcMediator, PoolMediator, Po
command.run();
}
catch (Throwable t) {
LOGGER.debug("Exception executing {}", command, t);
LoggerFactory.getLogger(PoolBase.class).debug("Exception executing {}", command, t);
}
}
}

@ -26,9 +26,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zaxxer.hikari.pool.Mediators.PoolEntryMediator;
import com.zaxxer.hikari.proxy.ConnectionState;
import com.zaxxer.hikari.proxy.ProxyFactory;
import com.zaxxer.hikari.util.ClockSource;
import com.zaxxer.hikari.util.ConcurrentBag.IConcurrentBagEntry;
import com.zaxxer.hikari.util.FastList;
@ -52,8 +49,7 @@ public final class PoolEntry implements IConcurrentBagEntry
public volatile boolean evict;
private final FastList<Statement> openStatements;
private final HikariPool hikariPool;
private final PoolEntryMediator stateMediator;
private final PoolBase poolBase;
private final AtomicInteger state;
private volatile ScheduledFuture<?> endOfLife;
@ -64,15 +60,14 @@ public final class PoolEntry implements IConcurrentBagEntry
DATE_FORMAT = new SimpleDateFormat("MMM dd, HH:mm:ss.SSS");
}
PoolEntry(final Connection connection, final HikariPool pool, final PoolEntryMediator stateMediator)
PoolEntry(final Connection connection, final PoolBase pool)
{
this.connection = connection;
this.hikariPool = pool;
this.poolBase = pool;
this.creationTime = System.currentTimeMillis();
this.state = new AtomicInteger(STATE_NOT_IN_USE);
this.lastAccess = ClockSource.INSTANCE.currentTime();
this.openStatements = new FastList<>(Statement.class, 16);
this.stateMediator = stateMediator;
}
/**
@ -83,7 +78,7 @@ public final class PoolEntry implements IConcurrentBagEntry
public void recycle(final long lastAccess)
{
this.lastAccess = lastAccess;
hikariPool.releaseConnection(this);
poolBase.releaseConnection(this);
}
/**
@ -94,19 +89,19 @@ public final class PoolEntry implements IConcurrentBagEntry
this.endOfLife = endOfLife;
}
Connection createProxyConnection(final LeakTask leakTask, final long now)
Connection createProxyConnection(final ProxyLeakTask leakTask, final long now)
{
return ProxyFactory.getProxyConnection(this, connection, openStatements, leakTask, now);
}
public void resetConnectionState(final ConnectionState connectionState, final int dirtyBits) throws SQLException
public void resetConnectionState(final ProxyConnection liveState, final int dirtyBits) throws SQLException
{
stateMediator.resetConnectionState(connection, connectionState, dirtyBits);
poolBase.resetConnectionState(connection, liveState, dirtyBits);
}
public String getPoolName()
{
return hikariPool.config.getPoolName();
return poolBase.getPoolName();
}
public Connection getConnection()

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.zaxxer.hikari.proxy;
package com.zaxxer.hikari.pool;
import java.sql.CallableStatement;
@ -23,9 +23,9 @@ import java.sql.CallableStatement;
*
* @author Brett Wooldridge
*/
public abstract class CallableStatementProxy extends PreparedStatementProxy implements CallableStatement
public abstract class ProxyCallableStatement extends ProxyPreparedStatement implements CallableStatement
{
protected CallableStatementProxy(ConnectionProxy connection, CallableStatement statement)
protected ProxyCallableStatement(ProxyConnection connection, CallableStatement statement)
{
super(connection, statement);
}

@ -14,8 +14,11 @@
* limitations under the License.
*/
package com.zaxxer.hikari.proxy;
package com.zaxxer.hikari.pool;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
@ -30,8 +33,6 @@ import java.util.concurrent.Executor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zaxxer.hikari.pool.LeakTask;
import com.zaxxer.hikari.pool.PoolEntry;
import com.zaxxer.hikari.util.ClockSource;
import com.zaxxer.hikari.util.FastList;
@ -40,7 +41,7 @@ import com.zaxxer.hikari.util.FastList;
*
* @author Brett Wooldridge
*/
public abstract class ConnectionProxy implements IHikariConnectionProxy, ConnectionState
public abstract class ProxyConnection implements Connection
{
private static final Logger LOGGER;
private static final Set<String> SQL_ERRORS;
@ -48,7 +49,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy, Connect
protected Connection delegate;
private final LeakTask leakTask;
private final ProxyLeakTask leakTask;
private final PoolEntry poolEntry;
private final FastList<Statement> openStatements;
@ -64,7 +65,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy, Connect
// static initializer
static {
LOGGER = LoggerFactory.getLogger(ConnectionProxy.class);
LOGGER = LoggerFactory.getLogger(ProxyConnection.class);
clockSource = ClockSource.INSTANCE;
SQL_ERRORS = new HashSet<>();
@ -76,7 +77,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy, Connect
SQL_ERRORS.add("JZ0C1"); // Sybase disconnect error
}
protected ConnectionProxy(final PoolEntry poolEntry, final Connection connection, final FastList<Statement> openStatements, final LeakTask leakTask, final long now) {
protected ProxyConnection(final PoolEntry poolEntry, final Connection connection, final FastList<Statement> openStatements, final ProxyLeakTask leakTask, final long now) {
this.poolEntry = poolEntry;
this.delegate = connection;
this.openStatements = openStatements;
@ -95,39 +96,29 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy, Connect
}
// ***********************************************************************
// ConnectionState methods
// Live Connection State accessors
// ***********************************************************************
/** {@inheritDoc} */
@Override
public final boolean getAutoCommitState()
{
return isAutoCommit;
}
/** {@inheritDoc} */
@Override
public final String getCatalogState()
{
return dbcatalog;
}
/** {@inheritDoc} */
@Override
public final int getTransactionIsolationState()
{
return transactionIsolation;
}
/** {@inheritDoc} */
@Override
public final boolean getReadOnlyState()
{
return isReadOnly;
}
/** {@inheritDoc} */
@Override
public final int getNetworkTimeoutState()
{
return networkTimeout;
@ -138,14 +129,12 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy, Connect
// ***********************************************************************
/** {@inheritDoc} */
@Override
public final PoolEntry getPoolEntry()
{
return poolEntry;
}
/** {@inheritDoc} */
@Override
public final SQLException checkException(final SQLException sqle)
{
String sqlState = sqle.getSQLState();
@ -167,14 +156,12 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy, Connect
}
/** {@inheritDoc} */
@Override
public final void untrackStatement(final Statement statement)
{
openStatements.remove(statement);
}
/** {@inheritDoc} */
@Override
public final void markCommitStateDirty()
{
if (isAutoCommit) {
@ -439,4 +426,38 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy, Connect
throw new SQLException("Wrapped connection is not an instance of " + iface);
}
// **********************************************************************
// Private classes
// **********************************************************************
private static final class ClosedConnection
{
static final Connection CLOSED_CONNECTION = getClosedConnection();
private static Connection getClosedConnection()
{
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
final String methodName = method.getName();
if ("abort".equals(methodName)) {
return Void.TYPE;
}
else if ("isValid".equals(methodName)) {
return Boolean.FALSE;
}
else if ("toString".equals(methodName)) {
return ClosedConnection.class.getCanonicalName();
}
throw new SQLException("Connection is closed");
}
};
return (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), new Class[] { Connection.class }, handler);
}
}
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.zaxxer.hikari.proxy;
package com.zaxxer.hikari.pool;
import java.sql.CallableStatement;
import java.sql.Connection;
@ -22,8 +22,6 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import com.zaxxer.hikari.pool.LeakTask;
import com.zaxxer.hikari.pool.PoolEntry;
import com.zaxxer.hikari.util.FastList;
/**
@ -49,31 +47,31 @@ public final class ProxyFactory
* @param now current timestamp in milliseconds
* @return a proxy that wraps the specified {@link Connection}
*/
public static IHikariConnectionProxy getProxyConnection(final PoolEntry poolEntry, final Connection connection, final FastList<Statement> openStatements, final LeakTask leakTask, final long now)
static ProxyConnection getProxyConnection(final PoolEntry poolEntry, final Connection connection, final FastList<Statement> openStatements, final ProxyLeakTask leakTask, final long now)
{
// Body is replaced (injected) by JavassistProxyFactory
throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run.");
}
static Statement getProxyStatement(final ConnectionProxy connection, final Statement statement)
static Statement getProxyStatement(final ProxyConnection connection, final Statement statement)
{
// Body is replaced (injected) by JavassistProxyFactory
throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run.");
}
static CallableStatement getProxyCallableStatement(final ConnectionProxy connection, final CallableStatement statement)
static CallableStatement getProxyCallableStatement(final ProxyConnection connection, final CallableStatement statement)
{
// Body is replaced (injected) by JavassistProxyFactory
throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run.");
}
static PreparedStatement getProxyPreparedStatement(final ConnectionProxy connection, final PreparedStatement statement)
static PreparedStatement getProxyPreparedStatement(final ProxyConnection connection, final PreparedStatement statement)
{
// Body is replaced (injected) by JavassistProxyFactory
throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run.");
}
static ResultSet getProxyResultSet(final ConnectionProxy connection, final StatementProxy statement, final ResultSet resultSet)
static ResultSet getProxyResultSet(final ProxyConnection connection, final ProxyStatement statement, final ResultSet resultSet)
{
// Body is replaced (injected) by JavassistProxyFactory
throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run.");

@ -29,10 +29,10 @@ import org.slf4j.LoggerFactory;
*
* @author Brett Wooldridge
*/
public class LeakTask implements Runnable
class ProxyLeakTask implements Runnable
{
private static final Logger LOGGER = LoggerFactory.getLogger(LeakTask.class);
private static final LeakTask NO_LEAK;
private static final Logger LOGGER = LoggerFactory.getLogger(ProxyLeakTask.class);
private static final ProxyLeakTask NO_LEAK;
private ScheduledExecutorService executorService;
private long leakDetectionThreshold;
@ -42,32 +42,32 @@ public class LeakTask implements Runnable
static
{
NO_LEAK = new LeakTask() {
NO_LEAK = new ProxyLeakTask() {
@Override
public void cancel() {}
};
}
LeakTask(final long leakDetectionThreshold, final ScheduledExecutorService executorService)
ProxyLeakTask(final long leakDetectionThreshold, final ScheduledExecutorService executorService)
{
this.executorService = executorService;
this.leakDetectionThreshold = leakDetectionThreshold;
}
private LeakTask(final LeakTask parent, final PoolEntry poolEntry)
private ProxyLeakTask(final ProxyLeakTask parent, final PoolEntry poolEntry)
{
this.exception = new Exception("Apparent connection leak detected");
this.connectionName = poolEntry.connection.toString();
scheduledFuture = parent.executorService.schedule(this, parent.leakDetectionThreshold, TimeUnit.MILLISECONDS);
}
private LeakTask()
private ProxyLeakTask()
{
}
LeakTask start(final PoolEntry bagEntry)
ProxyLeakTask start(final PoolEntry bagEntry)
{
return (leakDetectionThreshold == 0) ? NO_LEAK : new LeakTask(this, bagEntry);
return (leakDetectionThreshold == 0) ? NO_LEAK : new ProxyLeakTask(this, bagEntry);
}
void updateLeakDetectionThreshold(final long leakDetectionThreshold)

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.zaxxer.hikari.proxy;
package com.zaxxer.hikari.pool;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -25,9 +25,9 @@ import java.sql.SQLException;
*
* @author Brett Wooldridge
*/
public abstract class PreparedStatementProxy extends StatementProxy implements PreparedStatement
public abstract class ProxyPreparedStatement extends ProxyStatement implements PreparedStatement
{
protected PreparedStatementProxy(ConnectionProxy connection, PreparedStatement statement)
protected ProxyPreparedStatement(ProxyConnection connection, PreparedStatement statement)
{
super(connection, statement);
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.zaxxer.hikari.proxy;
package com.zaxxer.hikari.pool;
import java.sql.ResultSet;
import java.sql.SQLException;
@ -26,13 +26,13 @@ import java.sql.Wrapper;
*
* @author Brett Wooldridge
*/
public abstract class ResultSetProxy implements ResultSet
public abstract class ProxyResultSet implements ResultSet
{
protected final ConnectionProxy connection;
protected final StatementProxy statement;
protected final ProxyConnection connection;
protected final ProxyStatement statement;
protected final ResultSet delegate;
protected ResultSetProxy(ConnectionProxy connection, StatementProxy statement, ResultSet resultSet)
protected ProxyResultSet(ProxyConnection connection, ProxyStatement statement, ResultSet resultSet)
{
this.connection = connection;
this.statement = statement;

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.zaxxer.hikari.proxy;
package com.zaxxer.hikari.pool;
import java.sql.Connection;
import java.sql.ResultSet;
@ -27,14 +27,14 @@ import java.sql.Wrapper;
*
* @author Brett Wooldridge
*/
public abstract class StatementProxy implements Statement
public abstract class ProxyStatement implements Statement
{
protected final ConnectionProxy connection;
protected final ProxyConnection connection;
protected final Statement delegate;
private boolean isClosed;
protected StatementProxy(ConnectionProxy connection, Statement statement)
protected ProxyStatement(ProxyConnection connection, Statement statement)
{
this.connection = connection;
this.delegate = statement;

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.zaxxer.hikari.proxy;
package com.zaxxer.hikari.util;
import java.lang.reflect.Array;
import java.sql.CallableStatement;
@ -28,6 +28,13 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.zaxxer.hikari.pool.ProxyCallableStatement;
import com.zaxxer.hikari.pool.ProxyConnection;
import com.zaxxer.hikari.pool.ProxyFactory;
import com.zaxxer.hikari.pool.ProxyPreparedStatement;
import com.zaxxer.hikari.pool.ProxyResultSet;
import com.zaxxer.hikari.pool.ProxyStatement;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
@ -57,14 +64,14 @@ public final class JavassistProxyFactory
try {
// Cast is not needed for these
String methodBody = "{ try { return delegate.method($$); } catch (SQLException e) { throw checkException(e); } }";
generateProxyClass(Connection.class, ConnectionProxy.class.getName(), methodBody);
generateProxyClass(Statement.class, StatementProxy.class.getName(), methodBody);
generateProxyClass(ResultSet.class, ResultSetProxy.class.getName(), methodBody);
generateProxyClass(Connection.class, ProxyConnection.class.getName(), methodBody);
generateProxyClass(Statement.class, ProxyStatement.class.getName(), methodBody);
generateProxyClass(ResultSet.class, ProxyResultSet.class.getName(), methodBody);
// For these we have to cast the delegate
methodBody = "{ try { return ((cast) delegate).method($$); } catch (SQLException e) { throw checkException(e); } }";
generateProxyClass(PreparedStatement.class, PreparedStatementProxy.class.getName(), methodBody);
generateProxyClass(CallableStatement.class, CallableStatementProxy.class.getName(), methodBody);
generateProxyClass(PreparedStatement.class, ProxyPreparedStatement.class.getName(), methodBody);
generateProxyClass(CallableStatement.class, ProxyCallableStatement.class.getName(), methodBody);
modifyProxyFactory();
}
@ -77,24 +84,24 @@ public final class JavassistProxyFactory
{
System.out.println("Generating method bodies for com.zaxxer.hikari.proxy.ProxyFactory");
String packageName = JavassistProxyFactory.class.getPackage().getName();
CtClass proxyCt = classPool.getCtClass("com.zaxxer.hikari.proxy.ProxyFactory");
String packageName = ProxyConnection.class.getPackage().getName();
CtClass proxyCt = classPool.getCtClass("com.zaxxer.hikari.pool.ProxyFactory");
for (CtMethod method : proxyCt.getMethods()) {
switch (method.getName()) {
case "getProxyConnection":
method.setBody("{return new " + packageName + ".HikariConnectionProxy($$);}");
method.setBody("{return new " + packageName + ".HikariProxyConnection($$);}");
break;
case "getProxyStatement":
method.setBody("{return new " + packageName + ".HikariStatementProxy($$);}");
method.setBody("{return new " + packageName + ".HikariProxyStatement($$);}");
break;
case "getProxyPreparedStatement":
method.setBody("{return new " + packageName + ".HikariPreparedStatementProxy($$);}");
method.setBody("{return new " + packageName + ".HikariProxyPreparedStatement($$);}");
break;
case "getProxyCallableStatement":
method.setBody("{return new " + packageName + ".HikariCallableStatementProxy($$);}");
method.setBody("{return new " + packageName + ".HikariProxyCallableStatement($$);}");
break;
case "getProxyResultSet":
method.setBody("{return new " + packageName + ".HikariResultSetProxy($$);}");
method.setBody("{return new " + packageName + ".HikariProxyResultSet($$);}");
break;
}
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.zaxxer.hikari.pool;
package com.zaxxer.hikari.util;
import java.util.concurrent.Semaphore;
@ -25,9 +25,9 @@ import java.util.concurrent.Semaphore;
*
* @author Brett Wooldridge
*/
class SuspendResumeLock
public class SuspendResumeLock
{
static final SuspendResumeLock FAUX_LOCK = new SuspendResumeLock(false) {
public static final SuspendResumeLock FAUX_LOCK = new SuspendResumeLock(false) {
@Override
public void acquire() {}
@ -47,7 +47,13 @@ class SuspendResumeLock
/**
* Default constructor
*/
SuspendResumeLock(final boolean createSemaphore) {
public SuspendResumeLock()
{
this(true);
}
private SuspendResumeLock(final boolean createSemaphore)
{
acquisitionSemaphore = (createSemaphore ? new Semaphore(MAX_PERMITS, true) : null);
}

@ -17,6 +17,8 @@
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;
@ -100,4 +102,43 @@ public final class UtilityElf
executor.allowCoreThreadTimeOut(true);
return executor;
}
// ***********************************************************************
// Misc. public methods
// ***********************************************************************
/**
* 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 {
final String upperName = transactionIsolationName.toUpperCase();
if (upperName.startsWith("TRANSACTION_")) {
Field field = Connection.class.getField(upperName);
return field.getInt(null);
}
final int level = Integer.parseInt(transactionIsolationName);
switch (level) {
case Connection.TRANSACTION_READ_UNCOMMITTED:
case Connection.TRANSACTION_READ_COMMITTED:
case Connection.TRANSACTION_REPEATABLE_READ:
case Connection.TRANSACTION_SERIALIZABLE:
case Connection.TRANSACTION_NONE:
return level;
default:
throw new IllegalArgumentException();
}
}
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.pool.Mediator;
import com.zaxxer.hikari.util.UtilityElf;
public class ConnectionStateTest
{
@ -70,7 +70,7 @@ public class ConnectionStateTest
config.setTransactionIsolation("TRANSACTION_REPEATABLE_READ");
config.validate();
int transactionIsolation = Mediator.getTransactionIsolation(config.getTransactionIsolation());
int transactionIsolation = UtilityElf.getTransactionIsolation(config.getTransactionIsolation());
Assert.assertSame(Connection.TRANSACTION_REPEATABLE_READ, transactionIsolation);
}

@ -29,8 +29,6 @@ import org.junit.Test;
import org.slf4j.spi.LocationAwareLogger;
import com.zaxxer.hikari.pool.HikariPool;
import com.zaxxer.hikari.pool.LeakTask;
import com.zaxxer.hikari.pool.Mediator;
import com.zaxxer.hikari.util.UtilityElf;
/**
@ -66,7 +64,7 @@ public class MiscTest
public void testInvalidIsolation()
{
try {
Mediator.getTransactionIsolation("INVALID");
UtilityElf.getTransactionIsolation("INVALID");
Assert.fail();
}
catch (Exception e) {
@ -87,11 +85,11 @@ public class MiscTest
}
@Test
public void testLeakDetection() throws SQLException
public void testLeakDetection() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos, true);
TestElf.setSlf4jTargetStream(LeakTask.class, ps);
TestElf.setSlf4jTargetStream(Class.forName("com.zaxxer.hikari.pool.ProxyLeakTask"), ps);
HikariConfig config = new HikariConfig();
config.setMinimumIdle(0);

@ -28,7 +28,6 @@ import org.junit.Test;
import com.zaxxer.hikari.mocks.StubConnection;
import com.zaxxer.hikari.pool.HikariPool;
import com.zaxxer.hikari.pool.Mediator;
import com.zaxxer.hikari.util.ClockSource;
import com.zaxxer.hikari.util.UtilityElf;
@ -292,7 +291,7 @@ public class ShutdownTest
Assert.fail(e.getMessage());
}
finally {
new Mediator(TestElf.getPool(ds)).quietlyCloseConnection(connection, "(because this is a test)");
TestElf.getPool(ds).quietlyCloseConnection(connection, "(because this is a test)");
ds.close();
}
};

@ -28,7 +28,7 @@ import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import com.zaxxer.hikari.pool.Mediator;
import com.zaxxer.hikari.pool.HikariPool;
import com.zaxxer.hikari.pool.PoolEntry;
import com.zaxxer.hikari.util.ConcurrentBag;
import com.zaxxer.hikari.util.ConcurrentBag.IBagStateListener;
@ -40,7 +40,7 @@ import com.zaxxer.hikari.util.ConcurrentBag.IBagStateListener;
public class TestConcurrentBag
{
private static HikariDataSource ds;
private static Mediator mediator;
private static HikariPool pool;
@BeforeClass
public static void setup()
@ -53,7 +53,7 @@ public class TestConcurrentBag
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
ds = new HikariDataSource(config);
mediator = new Mediator(TestElf.getPool(ds));
pool = TestElf.getPool(ds);
}
@AfterClass
@ -104,15 +104,15 @@ public class TestConcurrentBag
});
Assert.assertEquals(0, bag.values(8).size());
PoolEntry reserved = mediator.newPoolEntry();
PoolEntry reserved = pool.newPoolEntry();
bag.add(reserved);
bag.reserve(reserved); // reserved
PoolEntry inuse = mediator.newPoolEntry();
PoolEntry inuse = pool.newPoolEntry();
bag.add(inuse);
bag.borrow(2, TimeUnit.MILLISECONDS); // in use
PoolEntry notinuse = mediator.newPoolEntry();
PoolEntry notinuse = pool.newPoolEntry();
bag.add(notinuse); // not in use
bag.dumpState();
@ -135,7 +135,7 @@ public class TestConcurrentBag
bag.close();
try {
PoolEntry bagEntry = mediator.newPoolEntry();
PoolEntry bagEntry = pool.newPoolEntry();
bag.add(bagEntry);
Assert.assertNotEquals(bagEntry, bag.borrow(100, TimeUnit.MILLISECONDS));
}

@ -16,6 +16,8 @@
package com.zaxxer.hikari;
import static com.zaxxer.hikari.util.UtilityElf.quietlySleep;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -31,11 +33,9 @@ import com.zaxxer.hikari.mocks.StubConnection;
import com.zaxxer.hikari.mocks.StubDataSource;
import com.zaxxer.hikari.mocks.StubStatement;
import com.zaxxer.hikari.pool.HikariPool;
import com.zaxxer.hikari.pool.PoolInitializationException;
import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
import com.zaxxer.hikari.util.UtilityElf;
import static com.zaxxer.hikari.util.UtilityElf.quietlySleep;
/**
* System property testProxy can be one of:
* "com.zaxxer.hikari.JavaProxyFactory"

@ -24,8 +24,8 @@ import java.util.HashMap;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.SimpleLogger;
import com.zaxxer.hikari.pool.ProxyConnection;
import com.zaxxer.hikari.pool.HikariPool;
import com.zaxxer.hikari.proxy.ConnectionProxy;
/**
* Utility methods for testing.
@ -66,7 +66,7 @@ public final class TestElf
public static boolean getConnectionCommitDirtyState(Connection connection)
{
try {
Field field = ConnectionProxy.class.getDeclaredField("isCommitStateDirty");
Field field = ProxyConnection.class.getDeclaredField("isCommitStateDirty");
field.setAccessible(true);
return field.getBoolean(connection);
}

Loading…
Cancel
Save