Merge branch 'dev' of github.com:brettwooldridge/HikariCP into dev

# By Brett Wooldridge (3) and Guillaume Smet (3)
* 'dev' of github.com:brettwooldridge/HikariCP:
  More clean-up/tighten-up of code.
  More clean-up/tighten-up of code.
  Fix typo: s/&/&&/.
  Use entrySet() instead of keySet().
  Make leakTrace local as there is no need to make it an attribute.
  Use some static imports.
pull/84/head
Brett Wooldridge 11 years ago
commit cf8bb4ff8d

@ -40,7 +40,9 @@ public class HikariDataSource extends HikariConfig implements DataSource
{
private static final Logger LOGGER = LoggerFactory.getLogger(HikariDataSource.class);
// We use a concrete HashMap rather than Map to avoid an invokeinterface callsite
private final HashMap<MultiPoolKey, HikariPool> multiPool;
private volatile boolean isShutdown;
private int loginTimeout;
@ -190,7 +192,7 @@ public class HikariDataSource extends HikariConfig implements DataSource
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException
{
return (pool != null & pool.getDataSource().getClass().isAssignableFrom(iface));
return (pool != null && pool.getDataSource().getClass().isAssignableFrom(iface));
}
/**
@ -228,41 +230,14 @@ public class HikariDataSource extends HikariConfig implements DataSource
isShutdown = true;
if (pool != null)
if (fastPathPool != null)
{
try
{
pool.shutdown();
}
catch (InterruptedException e)
{
LoggerFactory.getLogger(getClass()).warn("Interrupted during shutdown", e);
}
if (pool.getDataSource() instanceof DriverDataSource)
{
((DriverDataSource) pool.getDataSource()).shutdown();
}
shutdownHelper(fastPathPool);
}
if (!multiPool.isEmpty())
for (HikariPool hikariPool : multiPool.values())
{
for (HikariPool hikariPool : multiPool.values())
{
try
{
hikariPool.shutdown();
}
catch (InterruptedException e)
{
LoggerFactory.getLogger(getClass()).warn("Interrupted during shutdown", e);
}
if (hikariPool.getDataSource() instanceof DriverDataSource)
{
((DriverDataSource) hikariPool.getDataSource()).shutdown();
}
}
shutdownHelper(hikariPool);
}
}
@ -273,6 +248,23 @@ public class HikariDataSource extends HikariConfig implements DataSource
return String.format("HikariDataSource (%s)", pool);
}
private void shutdownHelper(HikariPool hPool)
{
try
{
hPool.shutdown();
}
catch (InterruptedException e)
{
LoggerFactory.getLogger(getClass()).warn("Interrupted during shutdown", e);
}
if (hPool.getDataSource() instanceof DriverDataSource)
{
((DriverDataSource) hPool.getDataSource()).shutdown();
}
}
private static class MultiPoolKey
{
private String username;

@ -42,9 +42,16 @@ import com.zaxxer.hikari.proxy.ProxyFactory;
import com.zaxxer.hikari.util.ConcurrentBag;
import com.zaxxer.hikari.util.ConcurrentBag.IBagStateListener;
import com.zaxxer.hikari.util.DriverDataSource;
import com.zaxxer.hikari.util.PoolUtilities;
import com.zaxxer.hikari.util.PropertyBeanSetter;
import static com.zaxxer.hikari.util.PoolUtilities.elapsedTimeMs;
import static com.zaxxer.hikari.util.PoolUtilities.createInstance;
import static com.zaxxer.hikari.util.PoolUtilities.createThreadPoolExecutor;
import static com.zaxxer.hikari.util.PoolUtilities.executeSqlAutoCommit;
import static com.zaxxer.hikari.util.PoolUtilities.quietlySleep;
import static com.zaxxer.hikari.util.PoolUtilities.quietlyCloseConnection;
import static com.zaxxer.hikari.util.PoolUtilities.IS_JAVA7;
/**
* This is the primary connection pool class that provides the basic
* pooling behavior for HikariCP.
@ -127,7 +134,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
HikariMBeanElf.registerMBeans(configuration, this);
}
addConnectionExecutor = PoolUtilities.createThreadPoolExecutor(configuration.getMaximumPoolSize(), "HikariCP connection filler");
addConnectionExecutor = createThreadPoolExecutor(configuration.getMaximumPoolSize(), "HikariCP connection filler");
fillPool();
@ -149,16 +156,16 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
{
final long start = System.currentTimeMillis();
final Context context = (isRecordMetrics ? metricsTracker.recordConnectionRequest(start) : MetricsTracker.NO_CONTEXT);
long timeout = configuration.getConnectionTimeout();
try
{
do
{
IHikariConnectionProxy connection = connectionBag.borrow(timeout, TimeUnit.MILLISECONDS);
if (connection == null) // We timed out... break and throw exception
if (connection == null)
{
break;
break; // We timed out... break and throw exception
}
final long now = System.currentTimeMillis();
@ -166,8 +173,8 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
if (now > connection.getExpirationTime() || (now - connection.getLastAccess() > 1000 && !isConnectionAlive(connection, timeout)))
{
closeConnection(connection); // Throw away the dead connection, try again
timeout -= PoolUtilities.elapsedTimeMs(start);
closeConnection(connection); // Throw away the dead connection and try again
timeout -= elapsedTimeMs(start);
continue;
}
else if (leakDetectionThreshold != 0)
@ -178,19 +185,19 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
return connection;
}
while (timeout > 0);
logPoolState("Timeout failure ");
throw new SQLException(String.format("Timeout of %dms encountered waiting for connection.",
configuration.getConnectionTimeout()), lastConnectionFailure.getAndSet(null));
}
catch (InterruptedException e)
{
return null;
throw new SQLException("Interrupted during connection acquisition", e);
}
finally
{
context.stop();
}
logPoolState("Timeout failure ");
throw new SQLException(String.format("Timeout of %dms encountered waiting for connection.",
configuration.getConnectionTimeout()), lastConnectionFailure.getAndSet(null));
}
/**
@ -203,28 +210,33 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
{
if (isRecordMetrics)
{
metricsTracker.recordConnectionUsage(PoolUtilities.elapsedTimeMs(connectionProxy.getLastOpenTime()));
metricsTracker.recordConnectionUsage(elapsedTimeMs(connectionProxy.getLastOpenTime()));
}
if (isBroken || isShutdown)
{
LOGGER.debug("Connection returned to pool {} is broken, or the pool is shutting down. Closing connection.", configuration.getPoolName());
closeConnection(connectionProxy);
return;
}
else
{
connectionBag.requite(connectionProxy);
}
connectionBag.requite(connectionProxy);
}
/**
* Shutdown the pool, closing all idle connections and aborting or closing
* active connections.
*
* @throws InterruptedException thrown if the thread is interrupted during shutdown
*/
public void shutdown() throws InterruptedException
{
if (!isShutdown)
{
isShutdown = true;
LOGGER.info("HikariCP pool {} is shutting down.", configuration.getPoolName());
logPoolState("State at shutdown ");
logPoolState("Before shutdown ");
houseKeepingTimer.cancel();
addConnectionExecutor.shutdownNow();
@ -234,9 +246,9 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
closeIdleConnections();
abortActiveConnections();
}
while ((getIdleConnections() > 0 || getActiveConnections() > 0 ) && PoolUtilities.elapsedTimeMs(start) < TimeUnit.SECONDS.toMillis(5));
while ((getIdleConnections() > 0 || getActiveConnections() > 0 ) && elapsedTimeMs(start) < TimeUnit.SECONDS.toMillis(5));
logPoolState("State after shutdown ");
logPoolState("After shutdown ");
if (isRegisteredMbeans)
{
@ -245,13 +257,18 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
}
}
/**
* Get the wrapped DataSource.
*
* @return the wrapped DataSource
*/
public DataSource getDataSource()
{
return dataSource;
}
/**
* Permanently close a connection.
* Permanently close the real (underlying) connection (eat any exception).
*
* @param connectionProxy the connection to actually close
*/
@ -283,7 +300,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
}
// ***********************************************************************
// IBagStateListener methods
// IBagStateListener callback
// ***********************************************************************
/** {@inheritDoc} */
@ -293,21 +310,21 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
class AddConnection implements Runnable {
public void run()
{
int sleepBackoff = 200;
long sleepBackoff = 200;
final int maxPoolSize = configuration.getMaximumPoolSize();
final int minIdle = configuration.getMinimumIdle();
while (!isShutdown && totalConnections.get() < maxPoolSize && (minIdle == 0 || getIdleConnections() < minIdle))
{
if (!addConnection())
{
PoolUtilities.quietlySleep(sleepBackoff);
sleepBackoff = (int) Math.min(1000f, ((float) sleepBackoff) * 1.5);
quietlySleep(sleepBackoff);
sleepBackoff = (long) Math.min(1000f, ((float) sleepBackoff) * 1.5);
continue;
}
if (minIdle == 0) // This break is here so we only add one connection when demanded
if (minIdle == 0)
{
break;
break; // This break is here so we only add one connection when there is no min. idle
}
}
}
@ -385,7 +402,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
transactionIsolation = (transactionIsolation < 0 ? connection.getTransactionIsolation() : transactionIsolation);
connectionCustomizer.customize(connection);
PoolUtilities.executeSqlAutoCommit(connection, configuration.getConnectionInitSql());
executeSqlAutoCommit(connection, configuration.getConnectionInitSql());
IHikariConnectionProxy proxyConnection = ProxyFactory.getProxyConnection(this, connection, configuration.getMaxLifetime(),
transactionIsolation, isAutoCommit, isReadOnly, catalog);
@ -400,9 +417,8 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
totalConnections.decrementAndGet();
lastConnectionFailure.set(e);
PoolUtilities.quietlyCloseConnection(connection);
quietlyCloseConnection(connection);
LOGGER.debug("Connection attempt to database {} failed: {}", configuration.getPoolName(), e.getMessage(), e);
return false;
}
}
@ -424,29 +440,26 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
{
return connection.isValid((int) TimeUnit.MILLISECONDS.toSeconds(timeoutMs));
}
else
Statement statement = connection.createStatement();
try
{
Statement statement = connection.createStatement();
try
if (configuration.getConnectionTimeout() < Integer.MAX_VALUE)
{
if (configuration.getConnectionTimeout() < Integer.MAX_VALUE)
{
statement.setQueryTimeout((int) TimeUnit.MILLISECONDS.toSeconds(timeoutMs));
}
statement.executeQuery(configuration.getConnectionTestQuery());
statement.setQueryTimeout((int) TimeUnit.MILLISECONDS.toSeconds(timeoutMs));
}
finally
{
statement.close();
}
statement.executeQuery(configuration.getConnectionTestQuery());
}
finally
{
statement.close();
if (isIsolateInternalQueries && !isAutoCommit)
{
connection.rollback();
}
return true;
}
return true;
}
catch (SQLException e)
{
@ -483,19 +496,18 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
*/
private void abortActiveConnections() throws InterruptedException
{
ThreadPoolExecutor assassinExecutor = PoolUtilities.createThreadPoolExecutor(1, "HikariCP connection assassin");
ThreadPoolExecutor assassinExecutor = createThreadPoolExecutor(1, "HikariCP connection assassin");
for (IHikariConnectionProxy connectionProxy : connectionBag.values(ConcurrentBag.STATE_IN_USE))
{
try
{
if (PoolUtilities.IS_JAVA7)
if (IS_JAVA7)
{
connectionProxy.abort(assassinExecutor);
continue;
}
else
{
connectionProxy.close();
}
connectionProxy.close();
}
catch (SQLException e)
{
@ -531,7 +543,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
{
try
{
DataSource dataSource = PoolUtilities.createInstance(dsClassName, DataSource.class);
DataSource dataSource = createInstance(dsClassName, DataSource.class);
PropertyBeanSetter.setTargetFromProperties(dataSource, configuration.getDataSourceProperties());
return dataSource;
}
@ -554,7 +566,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
{
try
{
return PoolUtilities.createInstance(configuration.getConnectionCustomizerClassName(), IConnectionCustomizer.class);
return createInstance(configuration.getConnectionCustomizerClassName(), IConnectionCustomizer.class);
}
catch (Exception e)
{
@ -569,7 +581,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
{
int total = totalConnections.get();
int idle = getIdleConnections();
LOGGER.debug("{}Pool stats {} (total={}, inUse={}, avail={}, waiting={})", (prefix.length > 0 ? prefix[0] : ""),
LOGGER.debug("{}pool stats {} (total={}, inUse={}, avail={}, waiting={})", (prefix.length > 0 ? prefix[0] : ""),
configuration.getPoolName(), total, total - idle, idle, getThreadsAwaitingConnection());
}
@ -581,10 +593,9 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
@Override
public void run()
{
logPoolState("Before cleanup ");
houseKeepingTimer.purge();
logPoolState("Before pool cleanup ");
final long now = System.currentTimeMillis();
final long idleTimeout = configuration.getIdleTimeout();
@ -604,12 +615,9 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
}
}
logPoolState("After pool cleanup ");
logPoolState("After cleanup ");
if (getIdleConnections() < configuration.getMinimumIdle() && totalConnections.get() < configuration.getMaximumPoolSize())
{
addBagItem(); // TRY to maintain minimum connections
}
addBagItem(); // Try to maintain minimum connections
}
}
}

@ -64,7 +64,6 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
private volatile long lastAccess;
private long uncloseTime;
private StackTraceElement[] leakTrace;
private TimerTask leakTask;
private final int hashCode;
@ -126,7 +125,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
public final void captureStack(long leakDetectionThreshold, Timer scheduler)
{
StackTraceElement[] trace = Thread.currentThread().getStackTrace();
leakTrace = new StackTraceElement[trace.length - 4];
StackTraceElement[] leakTrace = new StackTraceElement[trace.length - 4];
System.arraycopy(trace, 4, leakTrace, 0, leakTrace.length);
leakTask = new LeakTask(leakTrace, leakDetectionThreshold);

@ -322,18 +322,20 @@ public class ConcurrentBag<T extends com.zaxxer.hikari.util.ConcurrentBag.IBagMa
private static class Synchronizer extends AbstractQueuedLongSynchronizer
{
private static final long serialVersionUID = 104753538004341218L;
private static boolean JAVA7;
private static final boolean JAVA7;
static
{
boolean b = false;
try
{
JAVA7 = AbstractQueuedLongSynchronizer.class.getMethod("hasQueuedPredecessors", new Class<?>[0]) != null;
b = AbstractQueuedLongSynchronizer.class.getMethod("hasQueuedPredecessors", new Class<?>[0]) != null;
}
catch (Exception e)
{
// nothing
}
JAVA7 = b;
}
@Override

@ -27,7 +27,6 @@ import java.lang.reflect.Array;
public final class FastList<T>
{
private T[] elementData;
private int size;
/**
@ -60,8 +59,7 @@ public final class FastList<T>
{
try
{
elementData[size] = element;
size++;
elementData[size++] = element;
}
catch (ArrayIndexOutOfBoundsException e)
{
@ -71,7 +69,7 @@ public final class FastList<T>
@SuppressWarnings("unchecked")
final T[] newElementData = (T[]) Array.newInstance(element.getClass(), newCapacity);
System.arraycopy(elementData, 0, newElementData, 0, oldCapacity);
newElementData[size++] = element;
newElementData[size - 1] = element;
elementData = newElementData;
}
}

@ -11,18 +11,20 @@ import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
public final class PoolUtilities
{
public static boolean IS_JAVA7;
public static final boolean IS_JAVA7;
static
{
boolean b = false;
try
{
IS_JAVA7 = AbstractQueuedLongSynchronizer.class.getMethod("hasQueuedPredecessors", new Class<?>[0]) != null;
b = AbstractQueuedLongSynchronizer.class.getMethod("hasQueuedPredecessors", new Class<?>[0]) != null;
}
catch (Exception e)
{
IS_JAVA7 = false;
}
IS_JAVA7 = b;
}
public static void quietlyCloseConnection(Connection connection)
@ -119,7 +121,7 @@ public final class PoolUtilities
int processors = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(queueSize);
ThreadPoolExecutor executor = new ThreadPoolExecutor(processors, processors, 10, TimeUnit.SECONDS, queue, threadFactory, new ThreadPoolExecutor.DiscardPolicy());
ThreadPoolExecutor executor = new ThreadPoolExecutor(processors, processors, 2, TimeUnit.SECONDS, queue, threadFactory, new ThreadPoolExecutor.DiscardPolicy());
executor.allowCoreThreadTimeOut(true);
return executor;
}

@ -22,6 +22,7 @@ import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
@ -46,10 +47,10 @@ public final class PropertyBeanSetter
return;
}
for (Object propKey : properties.keySet())
for (Entry<Object, Object> propEntry : properties.entrySet())
{
String propName = propKey.toString();
Object propValue = properties.get(propKey);
String propName = propEntry.getKey().toString();
Object propValue = propEntry.getValue();
if (target instanceof HikariConfig && propName.startsWith("dataSource."))
{

Loading…
Cancel
Save