Small LeakTask refactor just to make HikariPool.getConnection() a little tighter (and more readable).

pull/201/head
Brett Wooldridge 10 years ago
parent 24750fef94
commit 0b8779ed26

@ -2,16 +2,11 @@ HikariCP Changes
Changes in 2.2.6
* Fix an InvalidStateException thrown from the ConcurrentBag when two separate
threads call close() on the same connection by making the isClosed state of
the ConnectionProxy visible across threads through volatility.
* Support pool suspend/resume though JMX to support certain failover scenarios.
* Fix theoretical race in JDBC 4.0 detection support.
* Suppress ordinary internal accounting sanity checks when the pool is being
undergoing forced shutdown. All bets are off when live connections are being
* Improve shutdown() semantics to avoid exceptions as connections are forcefully
aborted.
Changes in 2.2.5

@ -92,6 +92,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
private final IConnectionCustomizer connectionCustomizer;
private final Semaphore acquisitionSemaphore;
private final LeakTask leakTask;
private final AtomicInteger totalConnections;
private final AtomicReference<Throwable> lastConnectionFailure;
private final ScheduledThreadPoolExecutor houseKeepingExecutorService;
@ -100,7 +101,6 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
private final String password;
private final boolean isRecordMetrics;
private final boolean isIsolateInternalQueries;
private final long leakDetectionThreshold;
private volatile boolean isShutdown;
private volatile long connectionTimeout;
@ -143,7 +143,6 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
this.catalog = configuration.getCatalog();
this.connectionCustomizer = initializeCustomizer();
this.transactionIsolation = getTransactionIsolation(configuration.getTransactionIsolation());
this.leakDetectionThreshold = configuration.getLeakDetectionThreshold();
this.isIsolateInternalQueries = configuration.isIsolateInternalQueries();
this.isRecordMetrics = configuration.getMetricRegistry() != null;
@ -160,6 +159,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
this.houseKeepingExecutorService.setRemoveOnCancelPolicy(true);
}
this.houseKeepingExecutorService.scheduleAtFixedRate(new HouseKeeper(), delayPeriod, delayPeriod, TimeUnit.MILLISECONDS);
this.leakTask = (configuration.getLeakDetectionThreshold() == 0) ? LeakTask.NO_LEAK : new LeakTask(configuration.getLeakDetectionThreshold(), houseKeepingExecutorService);
setLoginTimeout(dataSource, connectionTimeout, LOGGER);
registerMBeans(configuration, this);
@ -193,12 +193,9 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
continue;
}
final LeakTask leakTask = (leakDetectionThreshold == 0) ? LeakTask.NO_LEAK : new LeakTask(leakDetectionThreshold, houseKeepingExecutorService);
final IHikariConnectionProxy proxyConnection = ProxyFactory.getProxyConnection(this, bagEntry, leakTask);
metricsContext.setConnectionLastOpen(bagEntry, now);
return proxyConnection;
return ProxyFactory.getProxyConnection(this, bagEntry, leakTask.start());
}
while (timeout > 0L);
}

@ -34,28 +34,42 @@ public class LeakTask implements Runnable
public static final LeakTask NO_LEAK;
private static final Logger LOGGER = LoggerFactory.getLogger(LeakTask.class);
private final ScheduledFuture<?> scheduledFuture;
private final Exception exception;
private final ScheduledExecutorService executorService;
private final long leakDetectionThreshold;
private ScheduledFuture<?> scheduledFuture;
private Exception exception;
static
{
NO_LEAK = new LeakTask() {
@Override
public void cancel() {};
@Override
public LeakTask start()
{
return this;
}
};
}
public LeakTask()
{
scheduledFuture = null;
exception = null;
executorService = null;
leakDetectionThreshold = 0;
}
public LeakTask(final long leakDetectionThreshold, final ScheduledExecutorService executorService)
{
this.exception = new Exception();
this.executorService = executorService;
this.leakDetectionThreshold = leakDetectionThreshold;
}
public LeakTask start()
{
exception = new Exception();
scheduledFuture = executorService.schedule(this, leakDetectionThreshold, TimeUnit.MILLISECONDS);
return this;
}
/** {@inheritDoc} */

@ -91,6 +91,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
private final IConnectionCustomizer connectionCustomizer;
private final Semaphore acquisitionSemaphore;
private final LeakTask leakTask;
private final AtomicInteger totalConnections;
private final AtomicReference<Throwable> lastConnectionFailure;
private final ScheduledThreadPoolExecutor houseKeepingExecutorService;
@ -99,7 +100,6 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
private final String password;
private final boolean isRecordMetrics;
private final boolean isIsolateInternalQueries;
private final long leakDetectionThreshold;
private volatile boolean isShutdown;
private volatile long connectionTimeout;
@ -142,7 +142,6 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
this.catalog = configuration.getCatalog();
this.connectionCustomizer = initializeCustomizer();
this.transactionIsolation = getTransactionIsolation(configuration.getTransactionIsolation());
this.leakDetectionThreshold = configuration.getLeakDetectionThreshold();
this.isIsolateInternalQueries = configuration.isIsolateInternalQueries();
this.isRecordMetrics = configuration.getMetricRegistry() != null;
@ -157,6 +156,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
this.houseKeepingExecutorService = new ScheduledThreadPoolExecutor(1, configuration.getThreadFactory() != null ? configuration.getThreadFactory() : new DefaultThreadFactory("Hikari Housekeeping Timer (pool " + configuration.getPoolName() + ")", true));
this.houseKeepingExecutorService.setRemoveOnCancelPolicy(true);
this.houseKeepingExecutorService.scheduleAtFixedRate(new HouseKeeper(), delayPeriod, delayPeriod, TimeUnit.MILLISECONDS);
this.leakTask = (configuration.getLeakDetectionThreshold() == 0) ? LeakTask.NO_LEAK : new LeakTask(configuration.getLeakDetectionThreshold(), houseKeepingExecutorService);
setLoginTimeout(dataSource, connectionTimeout, LOGGER);
registerMBeans(configuration, this);
@ -190,12 +190,9 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
continue;
}
final LeakTask leakTask = (leakDetectionThreshold == 0) ? LeakTask.NO_LEAK : new LeakTask(leakDetectionThreshold, houseKeepingExecutorService);
final IHikariConnectionProxy proxyConnection = ProxyFactory.getProxyConnection(this, bagEntry, leakTask);
metricsContext.setConnectionLastOpen(bagEntry, now);
return proxyConnection;
return ProxyFactory.getProxyConnection(this, bagEntry, leakTask.start());
}
while (timeout > 0L);
}

@ -34,28 +34,42 @@ public class LeakTask implements Runnable
public static final LeakTask NO_LEAK;
private static final Logger LOGGER = LoggerFactory.getLogger(LeakTask.class);
private final ScheduledFuture<?> scheduledFuture;
private final Exception exception;
private final ScheduledExecutorService executorService;
private final long leakDetectionThreshold;
private ScheduledFuture<?> scheduledFuture;
private Exception exception;
static
{
NO_LEAK = new LeakTask() {
@Override
public void cancel() {};
@Override
public LeakTask start()
{
return this;
}
};
}
public LeakTask()
{
scheduledFuture = null;
exception = null;
executorService = null;
leakDetectionThreshold = 0;
}
public LeakTask(final long leakDetectionThreshold, final ScheduledExecutorService executorService)
{
this.exception = new Exception();
this.executorService = executorService;
this.leakDetectionThreshold = leakDetectionThreshold;
}
public LeakTask start()
{
exception = new Exception();
scheduledFuture = executorService.schedule(this, leakDetectionThreshold, TimeUnit.MILLISECONDS);
return this;
}
/** {@inheritDoc} */

Loading…
Cancel
Save