Performance enhancements.

pull/77/head
Brett Wooldridge
parent b5161499b8
commit f4e28160ce

@ -1,5 +1,17 @@
HikariCP Changes
Changes between 1.3.8 and 1.3.9
*) Added pool name to housekeeping thread name to make thread dumps
more meaningful in containers with multiple pools.
*) Performance enhancements.
Changes between 1.3.7 and 1.3.8
*) Fixed incorrect logic when using JDBC4 isValid() test for alive
status of connection.
Changes between 1.3.6 and 1.3.7
*) Added JNDI object factory (com.zaxxer.hikari.HikariJNDIFactory)

@ -24,12 +24,13 @@ package com.zaxxer.hikari.metrics;
*/
public class MetricsTracker
{
protected static final Context NO_CONTEXT = new Context();
public static final Context NO_CONTEXT = new Context();
public static class Context
{
public void stop()
{
// do nothing
}
}

@ -151,8 +151,8 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
public Connection getConnection() throws SQLException
{
final long start = System.currentTimeMillis();
final long maxLife = configuration.getMaxLifetime();
final Context context = metricsTracker.recordConnectionRequest(start);
final Context context = (isRecordMetrics ? metricsTracker.recordConnectionRequest(start) : MetricsTracker.NO_CONTEXT);
long timeout = configuration.getConnectionTimeout();
try
{
@ -164,16 +164,16 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
break;
}
connection.unclose();
final long now = System.currentTimeMillis();
if ((maxLife != 0 && now - connection.getCreationTime() > maxLife) || (now - connection.getLastAccess() > 1000 && !isConnectionAlive(connection, timeout)))
connection.unclose(now);
if (now > connection.getExpirationTime() || (now - connection.getLastAccess() > 1000 && !isConnectionAlive(connection, timeout)))
{
closeConnection(connection); // Throw away the dead connection, try again
timeout -= (System.currentTimeMillis() - start);
continue;
}
else if (leakDetectionThreshold > 0)
else if (leakDetectionThreshold != 0)
{
connection.captureStack(leakDetectionThreshold, houseKeepingTimer);
}
@ -250,7 +250,6 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
return dataSource;
}
/**
* Permanently close a connection.
*
@ -289,7 +288,8 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
public void run()
{
int sleepBackoff = 200;
while (totalConnections.get() < configuration.getMaximumPoolSize())
final int maxPoolSize = configuration.getMaximumPoolSize();
while (totalConnections.get() < maxPoolSize)
{
final int minIdle = configuration.getMinimumIdle();
if (minIdle != 0 && getIdleConnections() >= minIdle)
@ -395,7 +395,8 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
PoolUtilities.executeSqlAutoCommit(connection, configuration.getConnectionInitSql());
IHikariConnectionProxy proxyConnection = ProxyFactory.getProxyConnection(this, connection, transactionIsolation, isAutoCommit, isReadOnly, catalog);
IHikariConnectionProxy proxyConnection = ProxyFactory.getProxyConnection(this, connection, configuration.getMaxLifetime(),
transactionIsolation, isAutoCommit, isReadOnly, catalog);
proxyConnection.resetConnectionState();
connectionBag.add(proxyConnection);
lastConnectionFailure.set(null);
@ -433,10 +434,9 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
{
timeoutMs = Math.max(1000, timeoutMs);
boolean valid = true;
if (isJdbc4ConnectionTest)
{
valid = connection.isValid((int) TimeUnit.MILLISECONDS.toSeconds(timeoutMs));
return connection.isValid((int) TimeUnit.MILLISECONDS.toSeconds(timeoutMs));
}
else
{
@ -453,14 +453,14 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
{
statement.close();
}
}
if (isIsolateInternalQueries && !isAutoCommit)
{
connection.rollback();
if (isIsolateInternalQueries && !isAutoCommit)
{
connection.rollback();
}
return true;
}
return valid;
}
catch (SQLException e)
{
@ -535,8 +535,8 @@ 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] : ""), configuration.getPoolName(), total, total - idle, idle,
getThreadsAwaitingConnection());
LOGGER.debug("{}Pool stats {} (total={}, inUse={}, avail={}, waiting={})", (prefix.length > 0 ? prefix[0] : ""),
configuration.getPoolName(), total, total - idle, idle, getThreadsAwaitingConnection());
}
/**
@ -554,7 +554,6 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
final long now = System.currentTimeMillis();
final long idleTimeout = configuration.getIdleTimeout();
final long maxLifetime = configuration.getMaxLifetime();
for (IHikariConnectionProxy connectionProxy : connectionBag.values(ConcurrentBag.STATE_NOT_IN_USE))
{
@ -562,7 +561,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
{
if ((idleTimeout > 0 && now > connectionProxy.getLastAccess() + idleTimeout)
||
(maxLifetime > 0 && now > connectionProxy.getCreationTime() + maxLifetime))
(now > connectionProxy.getExpirationTime()))
{
closeConnection(connectionProxy);
continue;

@ -46,14 +46,14 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
protected final Connection delegate;
private final long creationTime;
private final FastStatementList 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 String defaultCatalog;
private final AtomicInteger state;
private boolean forceClose;
private boolean isAutoCommitDirty;
@ -81,7 +81,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
SQL_ERRORS.add("JZ0C1"); // Sybase disconnect error
}
protected ConnectionProxy(HikariPool pool, Connection connection, int defaultIsolationLevel, boolean defaultAutoCommit, boolean defaultReadOnly, String defaultCatalog)
protected ConnectionProxy(HikariPool pool, Connection connection, long maxLifetime, int defaultIsolationLevel, boolean defaultAutoCommit, boolean defaultReadOnly, String defaultCatalog)
{
this.parentPool = pool;
this.delegate = connection;
@ -91,7 +91,9 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
this.defaultCatalog = defaultCatalog;
this.state = new AtomicInteger();
this.creationTime = lastAccess = System.currentTimeMillis();
long now = System.currentTimeMillis();
this.expirationTime = (maxLifetime > 0 ? now + maxLifetime : Long.MAX_VALUE);
this.lastAccess = now;
this.openStatements = new FastStatementList();
this.hashCode = System.identityHashCode(this);
@ -152,9 +154,9 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
/** {@inheritDoc} */
@Override
public final long getCreationTime()
public final long getExpirationTime()
{
return creationTime;
return expirationTime;
}
/** {@inheritDoc} */
@ -223,10 +225,10 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
/** {@inheritDoc} */
@Override
public final void unclose()
public final void unclose(final long now)
{
isClosed = false;
uncloseTime = System.currentTimeMillis();
uncloseTime = now;
}
/** {@inheritDoc} */

@ -47,11 +47,11 @@ public interface IHikariConnectionProxy extends Connection, IBagManagable
void checkException(SQLException sqle);
/**
* Get the creation timestamp of the connection.
* Get the expiration timestamp of the connection.
*
* @return the creation timestamp
* @return the expiration timestamp, or Long.MAX_VALUE if there is no maximum lifetime
*/
long getCreationTime();
long getExpirationTime();
/**
* Get the last access timestamp of the connection.
@ -91,8 +91,9 @@ public interface IHikariConnectionProxy extends Connection, IBagManagable
/**
* Make the Connection available for use again by marking it as not closed.
* @param now the current time in milliseconds
*/
void unclose();
void unclose(long now);
/**
* Called by Statement and its subclasses when they are closed to remove them

@ -47,7 +47,7 @@ public final class ProxyFactory
* @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, int defaultIsolationLevel, boolean defaultAutoCommit, boolean defaultIReadOnly, String defaultCatalog)
public static IHikariConnectionProxy getProxyConnection(HikariPool pool, Connection connection, long maxLifeTime, int defaultIsolationLevel, boolean defaultAutoCommit, boolean defaultIReadOnly, String defaultCatalog)
{
// Body is injected by JavassistProxyFactory
return null;

@ -86,7 +86,7 @@ public class TestConnections
public void testMaxLifetime() throws Exception
{
HikariConfig config = new HikariConfig();
config.setMinimumIdle(1);
config.setMinimumIdle(0);
config.setMaximumPoolSize(1);
config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
@ -102,8 +102,8 @@ public class TestConnections
ds.setMaxLifetime(700);
Assert.assertSame("Total connections not as expected", 1, TestElf.getPool(ds).getTotalConnections());
Assert.assertSame("Idle connections not as expected", 1, TestElf.getPool(ds).getIdleConnections());
Assert.assertSame("Total connections not as expected", 0, TestElf.getPool(ds).getTotalConnections());
Assert.assertSame("Idle connections not as expected", 0, TestElf.getPool(ds).getIdleConnections());
Connection connection = ds.getConnection();
Assert.assertNotNull(connection);
@ -136,6 +136,56 @@ public class TestConnections
}
}
@Test
public void testMaxLifetime2() throws Exception
{
HikariConfig config = new HikariConfig();
config.setMinimumIdle(0);
config.setMaximumPoolSize(1);
config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
HikariDataSource ds = new HikariDataSource(config);
try
{
ds.setMaxLifetime(700);
Assert.assertSame("Total connections not as expected", 0, TestElf.getPool(ds).getTotalConnections());
Assert.assertSame("Idle connections not as expected", 0, TestElf.getPool(ds).getIdleConnections());
Connection connection = ds.getConnection();
Assert.assertNotNull(connection);
Assert.assertSame("Second total connections not as expected", 1, TestElf.getPool(ds).getTotalConnections());
Assert.assertSame("Second idle connections not as expected", 0, TestElf.getPool(ds).getIdleConnections());
connection.close();
Assert.assertSame("Idle connections not as expected", 1, TestElf.getPool(ds).getIdleConnections());
Connection connection2 = ds.getConnection();
Assert.assertSame("Expected the same connection", connection, connection2);
Assert.assertSame("Second total connections not as expected", 1, TestElf.getPool(ds).getTotalConnections());
Assert.assertSame("Second idle connections not as expected", 0, TestElf.getPool(ds).getIdleConnections());
connection2.close();
Thread.sleep(800);
connection2 = ds.getConnection();
Assert.assertNotSame("Expected a different connection", connection, connection2);
connection2.close();
Assert.assertSame("Post total connections not as expected", 1, TestElf.getPool(ds).getTotalConnections());
Assert.assertSame("Post idle connections not as expected", 1, TestElf.getPool(ds).getIdleConnections());
}
finally
{
ds.shutdown();
}
}
@Test
public void testDoubleClose() throws Exception
{

Loading…
Cancel
Save