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 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. * Support pool suspend/resume though JMX to support certain failover scenarios.
* Fix theoretical race in JDBC 4.0 detection support. * Fix theoretical race in JDBC 4.0 detection support.
* Suppress ordinary internal accounting sanity checks when the pool is being * Improve shutdown() semantics to avoid exceptions as connections are forcefully
undergoing forced shutdown. All bets are off when live connections are being
aborted. aborted.
Changes in 2.2.5 Changes in 2.2.5

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

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

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

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

Loading…
Cancel
Save