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

@ -16,6 +16,8 @@
package com.zaxxer.hikari.pool; package com.zaxxer.hikari.pool;
import java.sql.Connection; import java.sql.Connection;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import com.zaxxer.hikari.util.AbstractBagEntry; import com.zaxxer.hikari.util.AbstractBagEntry;
@ -27,23 +29,45 @@ import com.zaxxer.hikari.util.AbstractBagEntry;
public final class PoolBagEntry extends AbstractBagEntry public final class PoolBagEntry extends AbstractBagEntry
{ {
public final Connection connection; public final Connection connection;
public final long expirationTime;
public long lastOpenTime; public long lastOpenTime;
public volatile boolean evicted; public volatile boolean evicted;
public volatile boolean aborted; 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; this.connection = connection;
lastAccess = System.currentTimeMillis(); this.lastAccess = System.currentTimeMillis();
expirationTime = (maxLifetime > 0 ? lastAccess + maxLifetime : Long.MAX_VALUE);
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 @Override
public String toString() public String toString()
{ {
return "Connection......" + connection + "\n" return "Connection......" + connection + "\n"
+ " Expiration...." + expirationTime + "\n"
+ " Last access.." + lastAccess + "\n" + " Last access.." + lastAccess + "\n"
+ " Last open....." + lastOpenTime + "\n"; + " Last open....." + lastOpenTime + "\n";
} }

@ -129,6 +129,7 @@ public final class HikariPool extends BaseHikariPool
*/ */
protected void closeConnection(final PoolBagEntry bagEntry) protected void closeConnection(final PoolBagEntry bagEntry)
{ {
bagEntry.cancelMaxLifeTermination();
if (connectionBag.remove(bagEntry)) { if (connectionBag.remove(bagEntry)) {
final int tc = totalConnections.decrementAndGet(); final int tc = totalConnections.decrementAndGet();
if (tc < 0) { 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 private class HouseKeeper implements Runnable
{ {
@ -248,7 +249,7 @@ public final class HikariPool extends BaseHikariPool
for (PoolBagEntry bagEntry : connectionBag.values(STATE_NOT_IN_USE)) { for (PoolBagEntry bagEntry : connectionBag.values(STATE_NOT_IN_USE)) {
if (connectionBag.reserve(bagEntry)) { if (connectionBag.reserve(bagEntry)) {
if ((idleTimeout > 0L && now > bagEntry.lastAccess + idleTimeout) || (now > bagEntry.expirationTime)) { if (idleTimeout > 0L && now > bagEntry.lastAccess + idleTimeout) {
closeConnection(bagEntry); closeConnection(bagEntry);
} }
else { else {

@ -114,8 +114,10 @@ public final class HikariPool extends BaseHikariPool
* *
* @param connectionProxy the connection to actually close * @param connectionProxy the connection to actually close
*/ */
@Override
protected void closeConnection(final PoolBagEntry bagEntry) protected void closeConnection(final PoolBagEntry bagEntry)
{ {
bagEntry.cancelMaxLifeTermination();
if (connectionBag.remove(bagEntry)) { if (connectionBag.remove(bagEntry)) {
final int tc = totalConnections.decrementAndGet(); final int tc = totalConnections.decrementAndGet();
if (tc < 0) { 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 private class HouseKeeper implements Runnable
{ {
@ -220,7 +222,7 @@ public final class HikariPool extends BaseHikariPool
final long idleTimeout = configuration.getIdleTimeout(); final long idleTimeout = configuration.getIdleTimeout();
connectionBag.values(STATE_NOT_IN_USE).stream().filter(p -> connectionBag.reserve(p)).forEach(bagEntry -> { 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); closeConnection(bagEntry);
} }
else { else {

@ -18,9 +18,12 @@ package com.zaxxer.hikari;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.junit.AfterClass;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import com.zaxxer.hikari.pool.HikariPool;
import com.zaxxer.hikari.pool.PoolBagEntry; import com.zaxxer.hikari.pool.PoolBagEntry;
import com.zaxxer.hikari.util.ConcurrentBag; import com.zaxxer.hikari.util.ConcurrentBag;
import com.zaxxer.hikari.util.Java8ConcurrentBag; import com.zaxxer.hikari.util.Java8ConcurrentBag;
@ -31,21 +34,43 @@ import com.zaxxer.hikari.util.Java8ConcurrentBag;
*/ */
public class TestConcurrentBag 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 @Test
public void testConcurrentBag() throws InterruptedException public void testConcurrentBag() throws InterruptedException
{ {
ConcurrentBag<PoolBagEntry> bag = new Java8ConcurrentBag(null); ConcurrentBag<PoolBagEntry> bag = new Java8ConcurrentBag(null);
Assert.assertEquals(0, bag.values(8).size()); 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.add(reserved);
bag.reserve(reserved); // reserved bag.reserve(reserved); // reserved
PoolBagEntry inuse = new PoolBagEntry(null, 0); PoolBagEntry inuse = new PoolBagEntry(null, pool);
bag.add(inuse); bag.add(inuse);
bag.borrow(2L, TimeUnit.SECONDS); // in use 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.add(notinuse); // not in use
bag.dumpState(); bag.dumpState();
@ -85,7 +110,7 @@ public class TestConcurrentBag
bag.close(); bag.close();
try { try {
PoolBagEntry bagEntry = new PoolBagEntry(null, 0); PoolBagEntry bagEntry = new PoolBagEntry(null, pool);
bag.add(bagEntry); bag.add(bagEntry);
Assert.assertNotEquals(bagEntry, bag.borrow(100, TimeUnit.MILLISECONDS)); Assert.assertNotEquals(bagEntry, bag.borrow(100, TimeUnit.MILLISECONDS));
} }

Loading…
Cancel
Save