Remove maxLifeTime check from getConnection() and use housekeeping scheduler instead.

pull/212/head
Brett Wooldridge 10 years ago
parent 44ecfd7f01
commit fafa5050ad

@ -179,7 +179,7 @@ public abstract class BaseHikariPool implements HikariPoolMBean, IBagStateListen
}
final long now = System.currentTimeMillis();
if (now > bagEntry.expirationTime || (now - bagEntry.lastAccess > ALIVE_BYPASS_WINDOW && !isConnectionAlive(bagEntry.connection, timeout))) {
if (now - bagEntry.lastAccess > ALIVE_BYPASS_WINDOW && !isConnectionAlive(bagEntry.connection, timeout)) {
closeConnection(bagEntry); // Throw away the dead connection and try again
timeout = connectionTimeout - elapsedTimeMs(start);
}
@ -234,11 +234,13 @@ public abstract class BaseHikariPool implements HikariPoolMBean, IBagStateListen
isShutdown = true;
LOGGER.info("HikariCP pool {} is shutting down.", configuration.getPoolName());
logPoolState("Before shutdown ");
connectionBag.close();
softEvictConnections();
houseKeepingExecutorService.shutdownNow();
addConnectionExecutor.shutdownNow();
addConnectionExecutor.shutdown();
addConnectionExecutor.awaitTermination(5L, TimeUnit.SECONDS);
logPoolState("Before shutdown ");
final long start = System.currentTimeMillis();
do {
softEvictConnections();
@ -387,7 +389,7 @@ public abstract class BaseHikariPool implements HikariPoolMBean, IBagStateListen
poolUtils.executeSql(connection, configuration.getConnectionInitSql(), isAutoCommit);
poolUtils.setNetworkTimeout(houseKeepingExecutorService, connection, originalTimeout, timeoutEnabled);
connectionBag.add(new PoolBagEntry(connection, configuration.getMaxLifetime()));
connectionBag.add(new PoolBagEntry(connection, this));
lastConnectionFailure.set(null);
return true;
}

@ -16,6 +16,8 @@
package com.zaxxer.hikari.pool;
import java.sql.Connection;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import com.zaxxer.hikari.util.AbstractBagEntry;
@ -27,23 +29,45 @@ import com.zaxxer.hikari.util.AbstractBagEntry;
public final class PoolBagEntry extends AbstractBagEntry
{
public final Connection connection;
public final long expirationTime;
public long lastOpenTime;
public volatile boolean evicted;
public volatile boolean aborted;
long lastAccess;
protected long lastAccess;
public PoolBagEntry(final Connection connection, long maxLifetime) {
private volatile ScheduledFuture<?> endOfLife;
public PoolBagEntry(final Connection connection, final BaseHikariPool pool) {
this.connection = connection;
lastAccess = System.currentTimeMillis();
expirationTime = (maxLifetime > 0 ? lastAccess + maxLifetime : Long.MAX_VALUE);
this.lastAccess = System.currentTimeMillis();
final long maxLifetime = pool.configuration.getMaxLifetime();
if (maxLifetime > 0) {
endOfLife = pool.houseKeepingExecutorService.schedule(new Runnable() {
public void run()
{
if (pool.connectionBag.reserve(PoolBagEntry.this)) {
pool.closeConnection(PoolBagEntry.this);
}
else {
PoolBagEntry.this.evicted = true;
}
}
}, maxLifetime, TimeUnit.MILLISECONDS);
}
}
void cancelMaxLifeTermination()
{
if (endOfLife != null) {
endOfLife.cancel(false);
}
}
@Override
public String toString()
{
return "Connection......" + connection + "\n"
+ " Expiration...." + expirationTime + "\n"
+ " Last access.." + lastAccess + "\n"
+ " Last open....." + lastOpenTime + "\n";
}

@ -129,6 +129,7 @@ public final class HikariPool extends BaseHikariPool
*/
protected void closeConnection(final PoolBagEntry bagEntry)
{
bagEntry.cancelMaxLifeTermination();
if (connectionBag.remove(bagEntry)) {
final int tc = totalConnections.decrementAndGet();
if (tc < 0) {
@ -232,7 +233,7 @@ public final class HikariPool extends BaseHikariPool
}
/**
* The house keeping task to retire idle and maxAge connections.
* The house keeping task to retire idle connections.
*/
private class HouseKeeper implements Runnable
{
@ -248,7 +249,7 @@ public final class HikariPool extends BaseHikariPool
for (PoolBagEntry bagEntry : connectionBag.values(STATE_NOT_IN_USE)) {
if (connectionBag.reserve(bagEntry)) {
if ((idleTimeout > 0L && now > bagEntry.lastAccess + idleTimeout) || (now > bagEntry.expirationTime)) {
if (idleTimeout > 0L && now > bagEntry.lastAccess + idleTimeout) {
closeConnection(bagEntry);
}
else {

@ -114,8 +114,10 @@ public final class HikariPool extends BaseHikariPool
*
* @param connectionProxy the connection to actually close
*/
@Override
protected void closeConnection(final PoolBagEntry bagEntry)
{
bagEntry.cancelMaxLifeTermination();
if (connectionBag.remove(bagEntry)) {
final int tc = totalConnections.decrementAndGet();
if (tc < 0) {
@ -205,7 +207,7 @@ public final class HikariPool extends BaseHikariPool
}
/**
* The house keeping task to retire idle and maxAge connections.
* The house keeping task to retire idle connections.
*/
private class HouseKeeper implements Runnable
{
@ -220,7 +222,7 @@ public final class HikariPool extends BaseHikariPool
final long idleTimeout = configuration.getIdleTimeout();
connectionBag.values(STATE_NOT_IN_USE).stream().filter(p -> connectionBag.reserve(p)).forEach(bagEntry -> {
if ((idleTimeout > 0L && now > bagEntry.lastAccess + idleTimeout) || (now > bagEntry.expirationTime)) {
if (idleTimeout > 0L && now > bagEntry.lastAccess + idleTimeout) {
closeConnection(bagEntry);
}
else {

@ -18,9 +18,12 @@ package com.zaxxer.hikari;
import java.util.concurrent.TimeUnit;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import com.zaxxer.hikari.pool.HikariPool;
import com.zaxxer.hikari.pool.PoolBagEntry;
import com.zaxxer.hikari.util.ConcurrentBag;
import com.zaxxer.hikari.util.Java8ConcurrentBag;
@ -31,21 +34,43 @@ import com.zaxxer.hikari.util.Java8ConcurrentBag;
*/
public class TestConcurrentBag
{
private static HikariDataSource ds;
@BeforeClass
public static void setup()
{
HikariConfig config = new HikariConfig();
config.setMinimumIdle(1);
config.setMaximumPoolSize(2);
config.setInitializationFailFast(true);
config.setConnectionTestQuery("VALUES 1");
config.setDataSourceClassName("com.zaxxer.hikari.mocks.StubDataSource");
ds = new HikariDataSource(config);
}
@AfterClass
public static void teardown()
{
ds.close();
}
@Test
public void testConcurrentBag() throws InterruptedException
{
ConcurrentBag<PoolBagEntry> bag = new Java8ConcurrentBag(null);
Assert.assertEquals(0, bag.values(8).size());
PoolBagEntry reserved = new PoolBagEntry(null, 0);
HikariPool pool = TestElf.getPool(ds);
PoolBagEntry reserved = new PoolBagEntry(null, TestElf.getPool(ds));
bag.add(reserved);
bag.reserve(reserved); // reserved
PoolBagEntry inuse = new PoolBagEntry(null, 0);
PoolBagEntry inuse = new PoolBagEntry(null, pool);
bag.add(inuse);
bag.borrow(2L, TimeUnit.SECONDS); // in use
PoolBagEntry notinuse = new PoolBagEntry(null, 0);
PoolBagEntry notinuse = new PoolBagEntry(null, pool);
bag.add(notinuse); // not in use
bag.dumpState();
@ -85,7 +110,7 @@ public class TestConcurrentBag
bag.close();
try {
PoolBagEntry bagEntry = new PoolBagEntry(null, 0);
PoolBagEntry bagEntry = new PoolBagEntry(null, pool);
bag.add(bagEntry);
Assert.assertNotEquals(bagEntry, bag.borrow(100, TimeUnit.MILLISECONDS));
}

Loading…
Cancel
Save