diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/HikariDataSource.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/HikariDataSource.java index d56c235e..0e6b50ef 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/HikariDataSource.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/HikariDataSource.java @@ -211,7 +211,7 @@ public class HikariDataSource extends HikariConfig implements DataSource, Closea public void evictConnection(Connection connection) { if (!isShutdown && pool != null && connection instanceof IHikariConnectionProxy) { - pool.closeConnection((IHikariConnectionProxy) connection); + pool.evictConnection((IHikariConnectionProxy) connection); } } diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/pool/HikariPool.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/pool/HikariPool.java index 94b0b81c..35bfada3 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/pool/HikariPool.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/pool/HikariPool.java @@ -16,6 +16,9 @@ package com.zaxxer.hikari.pool; +import static com.zaxxer.hikari.util.ConcurrentBag.STATE_IN_USE; +import static com.zaxxer.hikari.util.ConcurrentBag.STATE_NOT_IN_USE; +import static com.zaxxer.hikari.util.PoolUtilities.IS_JAVA7; import static com.zaxxer.hikari.util.PoolUtilities.createInstance; import static com.zaxxer.hikari.util.PoolUtilities.createThreadPoolExecutor; import static com.zaxxer.hikari.util.PoolUtilities.elapsedTimeMs; @@ -51,9 +54,6 @@ import com.zaxxer.hikari.util.ConcurrentBag.IBagStateListener; import com.zaxxer.hikari.util.DefaultThreadFactory; import com.zaxxer.hikari.util.DriverDataSource; import com.zaxxer.hikari.util.PropertyBeanSetter; -import static com.zaxxer.hikari.util.PoolUtilities.IS_JAVA7; -import static com.zaxxer.hikari.util.ConcurrentBag.STATE_IN_USE; -import static com.zaxxer.hikari.util.ConcurrentBag.STATE_NOT_IN_USE; /** * This is the primary connection pool class that provides the basic @@ -65,11 +65,16 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener { private static final Logger LOGGER = LoggerFactory.getLogger(HikariPool.class); + public int transactionIsolation; + public final String catalog; + public final boolean isAutoCommit; + public final boolean isReadOnly; + private final DataSource dataSource; private final IConnectionCustomizer connectionCustomizer; private final HikariConfig configuration; - private final ConcurrentBag connectionBag; + private final ConcurrentBag connectionBag; private final ThreadPoolExecutor addConnectionExecutor; private final IMetricsTracker metricsTracker; @@ -77,20 +82,16 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener private final AtomicInteger totalConnections; private final ScheduledThreadPoolExecutor houseKeepingExecutorService; - private final boolean isAutoCommit; private final boolean isIsolateInternalQueries; - private final boolean isReadOnly; private final boolean isRecordMetrics; private final boolean isRegisteredMbeans; private final boolean isJdbc4ConnectionTest; private final long leakDetectionThreshold; - private final String catalog; private final String username; private final String password; private volatile long connectionTimeout; private volatile boolean isShutdown; - private int transactionIsolation; /** * Construct a HikariPool with the specified configuration. @@ -116,7 +117,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener this.password = password; this.totalConnections = new AtomicInteger(); - this.connectionBag = new ConcurrentBag(); + this.connectionBag = new ConcurrentBag(); this.connectionBag.addBagStateListener(this); this.lastConnectionFailure = new AtomicReference(); this.connectionTimeout = configuration.getConnectionTimeout(); @@ -166,32 +167,29 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener try { do { - IHikariConnectionProxy connection = connectionBag.borrow(timeout, TimeUnit.MILLISECONDS); - if (connection == null) { + final PoolBagEntry bagEntry = connectionBag.borrow(timeout, TimeUnit.MILLISECONDS); + if (bagEntry == null) { break; // We timed out... break and throw exception } final long now = System.currentTimeMillis(); - connection.unclose(now); - - if (now > connection.getExpirationTime() || (now - connection.getLastAccess() > 1000L && !isConnectionAlive(connection, timeout))) { - closeConnection(connection); // Throw away the dead connection and try again + if (now > bagEntry.expirationTime || (now - bagEntry.lastAccess > 1000L && !isConnectionAlive(bagEntry.connection, timeout))) { + closeConnection(bagEntry); // Throw away the dead connection and try again timeout = connectionTimeout - elapsedTimeMs(start); continue; } - if (isIsolateInternalQueries) { - IHikariConnectionProxy newProxy = ProxyFactory.getProxyConnection(connection); - connectionBag.remove(connection); - connectionBag.add(newProxy); - connection = newProxy; - } + final IHikariConnectionProxy proxyConnection = ProxyFactory.getProxyConnection(this, bagEntry); if (leakDetectionThreshold != 0) { - connection.captureStack(leakDetectionThreshold, houseKeepingExecutorService); + proxyConnection.captureStack(leakDetectionThreshold, houseKeepingExecutorService); + } + + if (isRecordMetrics) { + bagEntry.lastOpenTime = now; } - return connection; + return proxyConnection; } while (timeout > 0L); } @@ -213,19 +211,20 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener * @param connectionProxy the connection to release back to the pool * @param isBroken true if the connection was detected as broken */ - public void releaseConnection(final IHikariConnectionProxy connectionProxy, final boolean isBroken) + public void releaseConnection(final PoolBagEntry bagEntry, final boolean isBroken) { if (isRecordMetrics) { - metricsTracker.recordConnectionUsage(elapsedTimeMs(connectionProxy.getLastOpenTime())); + metricsTracker.recordConnectionUsage(elapsedTimeMs(bagEntry.lastOpenTime)); } if (isBroken || isShutdown) { LOGGER.debug("Connection returned to pool {} is broken, or the pool is shutting down. Closing connection.", configuration.getPoolName()); - closeConnection(connectionProxy); + closeConnection(bagEntry); return; } - connectionBag.requite(connectionProxy); + bagEntry.lastAccess = System.currentTimeMillis(); + connectionBag.requite(bagEntry); } /** @@ -259,6 +258,10 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener } } + public void evictConnection(IHikariConnectionProxy proxyConnection) { + closeConnection(proxyConnection.getPoolBagEntry()); + } + /** * Get the wrapped DataSource. * @@ -269,28 +272,6 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener return dataSource; } - /** - * Permanently close the real (underlying) connection (eat any exception). - * - * @param connectionProxy the connection to actually close - */ - public void closeConnection(final IHikariConnectionProxy connectionProxy) - { - try { - int tc = totalConnections.decrementAndGet(); - if (tc < 0) { - LOGGER.warn("Internal accounting inconsistency, totalConnections={}", tc, new Exception()); - } - connectionProxy.realClose(); - } - catch (SQLException e) { - return; - } - finally { - connectionBag.remove(connectionProxy); - } - } - @Override public String toString() { @@ -365,9 +346,9 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener @Override public void closeIdleConnections() { - for (IHikariConnectionProxy connectionProxy : connectionBag.values(STATE_NOT_IN_USE)) { - if (connectionBag.reserve(connectionProxy)) { - closeConnection(connectionProxy); + for (PoolBagEntry bagEntry : connectionBag.values(STATE_NOT_IN_USE)) { + if (connectionBag.reserve(bagEntry)) { + closeConnection(bagEntry); } } } @@ -383,6 +364,28 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener // Private methods // *********************************************************************** + /** + * Permanently close the real (underlying) connection (eat any exception). + * + * @param connectionProxy the connection to actually close + */ + private void closeConnection(final PoolBagEntry bagEntry) + { + try { + int tc = totalConnections.decrementAndGet(); + if (tc < 0) { + LOGGER.warn("Internal accounting inconsistency, totalConnections={}", tc, new Exception()); + } + bagEntry.connection.close(); + } + catch (SQLException e) { + return; + } + finally { + connectionBag.remove(bagEntry); + } + } + /** * Create and add a single connection to the pool. */ @@ -402,10 +405,16 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener executeSqlAutoCommit(connection, configuration.getConnectionInitSql()); - IHikariConnectionProxy proxyConnection = ProxyFactory.getProxyConnection(this, connection, configuration.getMaxLifetime(), transactionIsolation, - isAutoCommit, isReadOnly, catalog); - proxyConnection.resetConnectionState(); - connectionBag.add(proxyConnection); + connection.setAutoCommit(isAutoCommit); + connection.setTransactionIsolation(transactionIsolation); + connection.setReadOnly(isReadOnly); + if (catalog != null) { + connection.setCatalog(catalog); + } + + PoolBagEntry bagEntry = new PoolBagEntry(connection, configuration.getMaxLifetime()); + + connectionBag.add(bagEntry); lastConnectionFailure.set(null); return true; } @@ -427,7 +436,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener * @param timeoutMs the timeout before we consider the test a failure * @return true if the connection is alive, false if it is not alive or we timed out */ - private boolean isConnectionAlive(final IHikariConnectionProxy connection, long timeoutMs) + private boolean isConnectionAlive(final Connection connection, long timeoutMs) { try { final boolean timeoutEnabled = (configuration.getConnectionTimeout() != Integer.MAX_VALUE); @@ -481,23 +490,23 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener private void abortActiveConnections() throws InterruptedException { ExecutorService assassinExecutor = createThreadPoolExecutor(configuration.getMaximumPoolSize(), "HikariCP connection assassin", configuration.getThreadFactory()); - for (IHikariConnectionProxy connectionProxy : connectionBag.values(STATE_IN_USE)) { + for (PoolBagEntry bagEntry : connectionBag.values(STATE_IN_USE)) { try { - connectionProxy.abort(assassinExecutor); - totalConnections.decrementAndGet(); + bagEntry.connection.abort(assassinExecutor); } catch (AbstractMethodError e) { - quietlyCloseConnection(connectionProxy); + quietlyCloseConnection(bagEntry.connection); } catch (SQLException e) { - quietlyCloseConnection(connectionProxy); + quietlyCloseConnection(bagEntry.connection); } finally { try { - connectionBag.remove(connectionProxy); + connectionBag.remove(bagEntry); + totalConnections.decrementAndGet(); } catch (IllegalStateException ise) { - continue; + break; } } } @@ -558,14 +567,14 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener final long now = System.currentTimeMillis(); final long idleTimeout = configuration.getIdleTimeout(); - for (IHikariConnectionProxy connectionProxy : connectionBag.values(STATE_NOT_IN_USE)) { - if (connectionBag.reserve(connectionProxy)) { - if ((idleTimeout > 0L && now > connectionProxy.getLastAccess() + idleTimeout) || (now > connectionProxy.getExpirationTime())) { - closeConnection(connectionProxy); + for (PoolBagEntry bagEntry : connectionBag.values(STATE_NOT_IN_USE)) { + if (connectionBag.reserve(bagEntry)) { + if ((idleTimeout > 0L && now > bagEntry.lastAccess + idleTimeout) || (now > bagEntry.expirationTime)) { + closeConnection(bagEntry); continue; } - connectionBag.unreserve(connectionProxy); + connectionBag.unreserve(bagEntry); } } diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/pool/PoolBagEntry.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/pool/PoolBagEntry.java new file mode 100644 index 00000000..3db2edbb --- /dev/null +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/pool/PoolBagEntry.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2013 Brett Wooldridge + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.zaxxer.hikari.pool; + +import java.sql.Connection; + +import com.zaxxer.hikari.util.ConcurrentBag.BagEntry; + +/** + * + * @author Brett Wooldridge + */ +public class PoolBagEntry extends BagEntry +{ + public final Connection connection; + public final long expirationTime; + long lastOpenTime; + long lastAccess; + + PoolBagEntry(final Connection connection, long maxLifetime) { + this.connection = connection; + expirationTime = (maxLifetime > 0 ? System.currentTimeMillis() + maxLifetime : Long.MAX_VALUE); + lastAccess = expirationTime; + } +} + diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java index 1a82a446..ced52162 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java @@ -26,12 +26,12 @@ import java.util.HashSet; import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.zaxxer.hikari.pool.HikariPool; +import com.zaxxer.hikari.pool.PoolBagEntry; import com.zaxxer.hikari.util.FastList; /** @@ -47,14 +47,8 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy protected final Connection delegate; - private final FastList openStatements; private final HikariPool parentPool; - private final AtomicInteger state; - private final String defaultCatalog; - private final long expirationTime; - private final int defaultIsolationLevel; - private final boolean defaultAutoCommit; - private final boolean defaultReadOnly; + private final PoolBagEntry bagEntry; private boolean forceClose; private boolean isAutoCommitDirty; @@ -62,13 +56,10 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy private boolean isClosed; private boolean isReadOnlyDirty; private boolean isTransactionIsolationDirty; - private volatile long lastAccess; - private long uncloseTime; + private FastList openStatements; private LeakTask leakTask; - private final int hashCode; - // static initializer static { SQL_ERRORS = new HashSet(); @@ -80,64 +71,12 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy SQL_ERRORS.add("JZ0C1"); // Sybase disconnect error } - protected ConnectionProxy(HikariPool pool, Connection connection, long maxLifetime, int defaultIsolationLevel, boolean defaultAutoCommit, - boolean defaultReadOnly, String defaultCatalog) - { + protected ConnectionProxy(final HikariPool pool, final PoolBagEntry bagEntry) { this.parentPool = pool; - this.delegate = connection; - this.defaultIsolationLevel = defaultIsolationLevel; - this.defaultAutoCommit = defaultAutoCommit; - this.defaultReadOnly = defaultReadOnly; - this.defaultCatalog = defaultCatalog; - this.state = new AtomicInteger(); - - long now = System.currentTimeMillis(); - this.expirationTime = (maxLifetime > 0 ? now + maxLifetime : Long.MAX_VALUE); - this.lastAccess = now; - this.openStatements = new FastList(Statement.class); - this.hashCode = System.identityHashCode(this); - - isCatalogDirty = true; - isReadOnlyDirty = defaultReadOnly; - isAutoCommitDirty = true; - isTransactionIsolationDirty = true; - } - - protected ConnectionProxy(final IHikariConnectionProxy proxy) - { - final ConnectionProxy copyProxy = (ConnectionProxy) proxy; - - this.parentPool = copyProxy.parentPool; - this.delegate = copyProxy.delegate; - this.defaultIsolationLevel = copyProxy.defaultIsolationLevel; - this.defaultAutoCommit = copyProxy.defaultAutoCommit; - this.defaultReadOnly = copyProxy.defaultReadOnly; - this.defaultCatalog = copyProxy.defaultCatalog; - this.state = new AtomicInteger(copyProxy.getState()); - - this.expirationTime = copyProxy.expirationTime; - this.lastAccess = this.uncloseTime = System.currentTimeMillis(); - this.openStatements = new FastList(Statement.class); - this.hashCode = System.identityHashCode(this); - - this.isCatalogDirty = copyProxy.isCatalogDirty; - this.isReadOnlyDirty = copyProxy.isReadOnlyDirty; - this.isAutoCommitDirty = copyProxy.isAutoCommitDirty; - this.isTransactionIsolationDirty = copyProxy.isTransactionIsolationDirty; - } + this.bagEntry = bagEntry; + this.delegate = bagEntry.connection; - /** {@inheritDoc} */ - @Override - public final boolean equals(Object other) - { - return this == other; - } - - /** {@inheritDoc} */ - @Override - public final int hashCode() - { - return hashCode; + this.openStatements = new FastList(Statement.class, 16); } @Override @@ -150,6 +89,13 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy // IHikariConnectionProxy methods // *********************************************************************** + /** {@inheritDoc} */ + @Override + public PoolBagEntry getPoolBagEntry() + { + return bagEntry; + } + /** {@inheritDoc} */ @Override public final void captureStack(long leakDetectionThreshold, ScheduledExecutorService executorService) @@ -179,27 +125,6 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy } } - /** {@inheritDoc} */ - @Override - public final long getExpirationTime() - { - return expirationTime; - } - - /** {@inheritDoc} */ - @Override - public final long getLastAccess() - { - return lastAccess; - } - - /** {@inheritDoc} */ - @Override - public long getLastOpenTime() - { - return uncloseTime; - } - /** {@inheritDoc} */ @Override public final boolean isBrokenConnection() @@ -207,52 +132,6 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy return forceClose; } - /** {@inheritDoc} */ - @Override - public final void realClose() throws SQLException - { - delegate.close(); - } - - /** {@inheritDoc} */ - @Override - public final void resetConnectionState() throws SQLException - { - if (!delegate.getAutoCommit()) { - delegate.rollback(); - } - - if (isReadOnlyDirty) { - delegate.setReadOnly(defaultReadOnly); - isReadOnlyDirty = false; - } - - if (isAutoCommitDirty) { - delegate.setAutoCommit(defaultAutoCommit); - isAutoCommitDirty = false; - } - - if (isTransactionIsolationDirty) { - delegate.setTransactionIsolation(defaultIsolationLevel); - isTransactionIsolationDirty = false; - } - - if (isCatalogDirty && defaultCatalog != null) { - delegate.setCatalog(defaultCatalog); - isCatalogDirty = false; - } - - delegate.clearWarnings(); - } - - /** {@inheritDoc} */ - @Override - public final void unclose(final long now) - { - isClosed = false; - uncloseTime = now; - } - /** {@inheritDoc} */ @Override public final void untrackStatement(Statement statement) @@ -283,22 +162,29 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy return statement; } - // ********************************************************************** - // IBagManagable Methods - // ********************************************************************** - - /** {@inheritDoc} */ - @Override - public final int getState() + private final void resetConnectionState() throws SQLException { - return state.get(); - } + if (!delegate.getAutoCommit()) { + delegate.rollback(); + } - /** {@inheritDoc} */ - @Override - public final boolean compareAndSetState(int expectedState, int newState) - { - return state.compareAndSet(expectedState, newState); + if (isReadOnlyDirty) { + delegate.setReadOnly(parentPool.isReadOnly); + } + + if (isAutoCommitDirty) { + delegate.setAutoCommit(parentPool.isAutoCommit); + } + + if (isTransactionIsolationDirty) { + delegate.setTransactionIsolation(parentPool.transactionIsolation); + } + + if (isCatalogDirty && parentPool.catalog != null) { + delegate.setCatalog(parentPool.catalog); + } + + delegate.clearWarnings(); } // ********************************************************************** @@ -329,7 +215,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy } } - openStatements.clear(); + openStatements = null; } resetConnectionState(); @@ -339,8 +225,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy throw e; } finally { - lastAccess = System.currentTimeMillis(); - parentPool.releaseConnection(this, forceClose); + parentPool.releaseConnection(bagEntry, forceClose); } } } @@ -560,7 +445,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy checkClosed(); try { delegate.setAutoCommit(autoCommit); - isAutoCommitDirty = (autoCommit != defaultAutoCommit); + isAutoCommitDirty = (autoCommit != parentPool.isAutoCommit); } catch (SQLException e) { checkException(e); @@ -575,7 +460,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy checkClosed(); try { delegate.setReadOnly(readOnly); - isReadOnlyDirty = (readOnly != defaultReadOnly); + isReadOnlyDirty = (readOnly != parentPool.isReadOnly); } catch (SQLException e) { checkException(e); @@ -590,7 +475,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy checkClosed(); try { delegate.setTransactionIsolation(level); - isTransactionIsolationDirty = (level != defaultIsolationLevel); + isTransactionIsolationDirty = (level != parentPool.transactionIsolation); } catch (SQLException e) { checkException(e); @@ -604,7 +489,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy checkClosed(); try { delegate.setCatalog(catalog); - isCatalogDirty = !catalog.equals(defaultCatalog); + isCatalogDirty = !catalog.equals(parentPool.catalog); } catch (SQLException e) { checkException(e); diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java index 77698a10..1bbda158 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java @@ -21,7 +21,7 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.concurrent.ScheduledExecutorService; -import com.zaxxer.hikari.util.ConcurrentBag.IBagManagable; +import com.zaxxer.hikari.pool.PoolBagEntry; /** * The interface used by the Connection proxy and through which all interaction @@ -29,8 +29,15 @@ import com.zaxxer.hikari.util.ConcurrentBag.IBagManagable; * * @author Brett Wooldridge */ -public interface IHikariConnectionProxy extends Connection, IBagManagable +public interface IHikariConnectionProxy extends Connection { + /** + * Get the ConcurrentBag entry that is associated in the pool with the underlying connection. + * + * @return the PoolBagEntry + */ + PoolBagEntry getPoolBagEntry(); + /** * Catpure the stack and start leak detection. * @@ -76,26 +83,6 @@ public interface IHikariConnectionProxy extends Connection, IBagManagable */ boolean isBrokenConnection(); - /** - * Actually close the underlying delegate Connection. - * - * @throws SQLException rethrown from the underlying delegate Connection - */ - void realClose() throws SQLException; - - /** - * Reset the delegate Connection back to pristine state. - * - * @throws SQLException thrown if there is an error resetting any of the state - */ - void resetConnectionState() throws SQLException; - - /** - * Make the Connection available for use again by marking it as not closed. - * @param now the current time in milliseconds - */ - void unclose(long now); - /** * Called by Statement and its subclasses when they are closed to remove them * from the tracking list. diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java index 8fa96fa5..8de9c28e 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java @@ -22,6 +22,7 @@ import java.sql.PreparedStatement; import java.sql.Statement; import com.zaxxer.hikari.pool.HikariPool; +import com.zaxxer.hikari.pool.PoolBagEntry; /** * A factory class that produces proxies around instances of the standard @@ -41,39 +42,32 @@ public final class ProxyFactory * * @param pool the {@link HikariPool} that will own this proxy * @param connection the {@link Connection} that will be wrapped by this proxy - * @param maxLifeTime the lifetime of the connection + * @param bagManagable the IBagManagable entry for this proxy * @param defaultIsolationLevel the default transaction isolation level of the underlying {@link Connection} * @param defaultAutoCommit the default auto-commit state of the underlying {@link Connection} * @param defaultIReadOnly the default readOnly state of the underlying {@link Connection} * @param defaultCatalog the default catalog of the underlying {@link Connection} * @return a proxy that wraps the specified {@link Connection} */ - public static IHikariConnectionProxy getProxyConnection(HikariPool pool, Connection connection, long maxLifeTime, int defaultIsolationLevel, - boolean defaultAutoCommit, boolean defaultIReadOnly, String defaultCatalog) + public static IHikariConnectionProxy getProxyConnection(final HikariPool pool, final PoolBagEntry bagEntry) { // Body is injected by JavassistProxyFactory return null; } - public static IHikariConnectionProxy getProxyConnection(IHikariConnectionProxy copyProxy) - { - // Body is injected by JavassistProxyFactory - return null; - } - - static Statement getProxyStatement(ConnectionProxy connection, Statement statement) + static Statement getProxyStatement(final ConnectionProxy connection, final Statement statement) { // Body is injected by JavassistProxyFactory return null; } - static CallableStatement getProxyCallableStatement(ConnectionProxy connection, CallableStatement statement) + static CallableStatement getProxyCallableStatement(final ConnectionProxy connection, final CallableStatement statement) { // Body is injected by JavassistProxyFactory return null; } - static PreparedStatement getProxyPreparedStatement(ConnectionProxy connection, PreparedStatement statement) + static PreparedStatement getProxyPreparedStatement(final ConnectionProxy connection, final PreparedStatement statement) { // Body is injected by JavassistProxyFactory return null; diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/util/ConcurrentBag.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/util/ConcurrentBag.java index 28703e00..6adf0890 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/util/ConcurrentBag.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/util/ConcurrentBag.java @@ -22,12 +22,15 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.AbstractQueuedLongSynchronizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.zaxxer.hikari.util.ConcurrentBag.BagEntry; + /** * This is a specialized concurrent bag that achieves superior performance * to LinkedBlockingQueue and LinkedTransferQueue for the purposes of a @@ -48,7 +51,7 @@ import org.slf4j.LoggerFactory; * * @param the templated type to store in the bag */ -public class ConcurrentBag +public final class ConcurrentBag { private static final Logger LOGGER = LoggerFactory.getLogger(ConcurrentBag.class); @@ -57,17 +60,9 @@ public class ConcurrentBagget() and compareAndSet(). - */ - public interface IBagManagable + public static abstract class BagEntry { - int getState(); - - boolean compareAndSetState(int expectedState, int newState); + final AtomicInteger state = new AtomicInteger(); } /** @@ -76,7 +71,7 @@ public class ConcurrentBag= 0; i--) { - final WeakReference reference = list.removeLast(); - final T element = reference.get(); - if (element != null && element.compareAndSetState(STATE_NOT_IN_USE, STATE_IN_USE)) { + for (int i = list.size(); i > 0; i--) { + final T element = list.removeLast().get(); + if (element != null && element.state.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) { return element; } } @@ -133,7 +127,7 @@ public class ConcurrentBag> list = threadList.get(); + if (value.state.compareAndSet(STATE_IN_USE, STATE_NOT_IN_USE)) { + final FastList> list = threadList.get(); if (list == null) { - list = new FastList>(WeakReference.class); - threadList.set(list); + FastList> newList = new FastList>(WeakReference.class); + threadList.set(newList); + newList.add(new WeakReference(value)); + } + else { + list.add(new WeakReference(value)); } - - list.add(new WeakReference(value)); synchronizer.releaseShared(sequence.incrementAndGet()); } else { @@ -202,7 +198,7 @@ public class ConcurrentBag list = new ArrayList(sharedList.size()); if (state == STATE_IN_USE || state == STATE_NOT_IN_USE) { for (T reference : sharedList) { - if (reference.getState() == state) { + if (reference.state.get() == state) { list.add(reference); } } @@ -248,7 +244,7 @@ public class ConcurrentBag { - if (connectionBag.reserve(connectionProxy)) { - closeConnection(connectionProxy); + connectionBag.values(STATE_NOT_IN_USE).forEach(bagEntry -> { + if (connectionBag.reserve(bagEntry)) { + closeConnection(bagEntry); } }); } diff --git a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java index 88d198e2..ced52162 100644 --- a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java +++ b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java @@ -501,7 +501,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy @Override public final boolean isWrapperFor(Class iface) throws SQLException { - return iface.isInstance(delegate) || (delegate instanceof Wrapper && delegate.isWrapperFor(iface)); + return iface.isInstance(delegate) || (delegate instanceof Wrapper && delegate.isWrapperFor(iface)); } /** {@inheritDoc} */ diff --git a/hikaricp/src/test/java/com/zaxxer/hikari/TestFastList.java b/hikaricp/src/test/java/com/zaxxer/hikari/TestFastList.java index 0a6dc91b..4d7deae3 100644 --- a/hikaricp/src/test/java/com/zaxxer/hikari/TestFastList.java +++ b/hikaricp/src/test/java/com/zaxxer/hikari/TestFastList.java @@ -86,7 +86,7 @@ public class TestFastList } - FastList list = new FastList<>(Base.class, 2); + FastList list = new FastList(Base.class, 2); list.add(new Foo()); list.add(new Foo()); list.add(new Bar());