Synchronize HikariCP-java6 code with HikariCP for pull request #113

pull/114/merge
Brett Wooldridge 11 years ago
parent e54fe43567
commit a2c2b28fb0

@ -26,6 +26,7 @@ import java.sql.SQLException;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.sql.DataSource; import javax.sql.DataSource;
@ -81,6 +82,7 @@ public class HikariConfig implements HikariConfigMBean
private Properties dataSourceProperties; private Properties dataSourceProperties;
private IConnectionCustomizer customizer; private IConnectionCustomizer customizer;
private int transactionIsolation; private int transactionIsolation;
private ThreadFactory threadFactory;
static { static {
JavassistProxyFactory.initialize(); JavassistProxyFactory.initialize();
@ -625,6 +627,26 @@ public class HikariConfig implements HikariConfigMBean
this.username = username; this.username = username;
} }
/**
* Get the thread factory used to create threads.
*
* @return the thread factory (may be null, in which case the default thread factory is used)
*/
public ThreadFactory getThreadFactory()
{
return threadFactory;
}
/**
* Set the thread factory to be used to create threads.
*
* @param threadFactory the thread factory (setting to null causes the default thread factory to be used)
*/
public void setThreadFactory(ThreadFactory threadFactory)
{
this.threadFactory = threadFactory;
}
public void validate() public void validate()
{ {
Logger logger = LoggerFactory.getLogger(getClass()); Logger logger = LoggerFactory.getLogger(getClass());

@ -26,8 +26,8 @@ import static com.zaxxer.hikari.util.PoolUtilities.quietlySleep;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.Timer; import java.util.concurrent.ExecutorService;
import java.util.TimerTask; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -48,6 +48,7 @@ import com.zaxxer.hikari.proxy.IHikariConnectionProxy;
import com.zaxxer.hikari.proxy.ProxyFactory; import com.zaxxer.hikari.proxy.ProxyFactory;
import com.zaxxer.hikari.util.ConcurrentBag; import com.zaxxer.hikari.util.ConcurrentBag;
import com.zaxxer.hikari.util.ConcurrentBag.IBagStateListener; import com.zaxxer.hikari.util.ConcurrentBag.IBagStateListener;
import com.zaxxer.hikari.util.DefaultThreadFactory;
import com.zaxxer.hikari.util.DriverDataSource; import com.zaxxer.hikari.util.DriverDataSource;
import com.zaxxer.hikari.util.PropertyBeanSetter; import com.zaxxer.hikari.util.PropertyBeanSetter;
@ -71,7 +72,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
private final AtomicReference<Throwable> lastConnectionFailure; private final AtomicReference<Throwable> lastConnectionFailure;
private final AtomicInteger totalConnections; private final AtomicInteger totalConnections;
private final Timer houseKeepingTimer; private final ScheduledThreadPoolExecutor houseKeepingExecutorService;
private final boolean isAutoCommit; private final boolean isAutoCommit;
private final boolean isIsolateInternalQueries; private final boolean isIsolateInternalQueries;
@ -136,13 +137,14 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
HikariMBeanElf.registerMBeans(configuration, this); HikariMBeanElf.registerMBeans(configuration, this);
} }
addConnectionExecutor = createThreadPoolExecutor(configuration.getMaximumPoolSize(), "HikariCP connection filler"); addConnectionExecutor = createThreadPoolExecutor(configuration.getMaximumPoolSize(), "HikariCP connection filler", configuration.getThreadFactory());
fillPool(); fillPool();
long delayPeriod = Long.getLong("com.zaxxer.hikari.housekeeping.periodMs", TimeUnit.SECONDS.toMillis(30L)); long delayPeriod = Long.getLong("com.zaxxer.hikari.housekeeping.periodMs", TimeUnit.SECONDS.toMillis(30L));
houseKeepingTimer = new Timer("Hikari Housekeeping Timer (pool " + configuration.getPoolName() + ")", true); houseKeepingExecutorService = new ScheduledThreadPoolExecutor(1, configuration.getThreadFactory() != null ? configuration.getThreadFactory() : new DefaultThreadFactory("Hikari Housekeeping Timer (pool " + configuration.getPoolName() + ")", true));
houseKeepingTimer.scheduleAtFixedRate(new HouseKeeper(), delayPeriod, delayPeriod); houseKeepingExecutorService.setRemoveOnCancelPolicy(true);
houseKeepingExecutorService.scheduleAtFixedRate(new HouseKeeper(), delayPeriod, delayPeriod, TimeUnit.MILLISECONDS);
} }
/** /**
@ -181,7 +183,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
} }
if (leakDetectionThreshold != 0) { if (leakDetectionThreshold != 0) {
connection.captureStack(leakDetectionThreshold, houseKeepingTimer); connection.captureStack(leakDetectionThreshold, houseKeepingExecutorService);
} }
return connection; return connection;
@ -234,7 +236,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
LOGGER.info("HikariCP pool {} is shutting down.", configuration.getPoolName()); LOGGER.info("HikariCP pool {} is shutting down.", configuration.getPoolName());
logPoolState("Before shutdown "); logPoolState("Before shutdown ");
houseKeepingTimer.cancel(); houseKeepingExecutorService.shutdownNow();
addConnectionExecutor.shutdownNow(); addConnectionExecutor.shutdownNow();
final long start = System.currentTimeMillis(); final long start = System.currentTimeMillis();
@ -473,7 +475,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
*/ */
private void abortActiveConnections() throws InterruptedException private void abortActiveConnections() throws InterruptedException
{ {
ThreadPoolExecutor assassinExecutor = createThreadPoolExecutor(configuration.getMaximumPoolSize(), "HikariCP connection assassin"); ExecutorService assassinExecutor = createThreadPoolExecutor(configuration.getMaximumPoolSize(), "HikariCP connection assassin", configuration.getThreadFactory());
for (IHikariConnectionProxy connectionProxy : connectionBag.values(ConcurrentBag.STATE_IN_USE)) { for (IHikariConnectionProxy connectionProxy : connectionBag.values(ConcurrentBag.STATE_IN_USE)) {
try { try {
connectionProxy.abort(assassinExecutor); connectionProxy.abort(assassinExecutor);
@ -539,7 +541,7 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
/** /**
* The house keeping task to retire idle and maxAge connections. * The house keeping task to retire idle and maxAge connections.
*/ */
private class HouseKeeper extends TimerTask private class HouseKeeper implements Runnable
{ {
@Override @Override
public void run() public void run()
@ -547,7 +549,6 @@ public final class HikariPool implements HikariPoolMBean, IBagStateListener
logPoolState("Before cleanup "); logPoolState("Before cleanup ");
connectionTimeout = configuration.getConnectionTimeout(); // refresh member in case it changed connectionTimeout = configuration.getConnectionTimeout(); // refresh member in case it changed
houseKeepingTimer.purge(); // purge cancelled timers
final long now = System.currentTimeMillis(); final long now = System.currentTimeMillis();
final long idleTimeout = configuration.getIdleTimeout(); final long idleTimeout = configuration.getIdleTimeout();

@ -23,8 +23,8 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.Timer; import java.util.concurrent.ScheduledExecutorService;
import java.util.TimerTask; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -64,7 +64,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
private volatile long lastAccess; private volatile long lastAccess;
private long uncloseTime; private long uncloseTime;
private TimerTask leakTask; private LeakTask leakTask;
private final int hashCode; private final int hashCode;
@ -151,14 +151,14 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final void captureStack(long leakDetectionThreshold, Timer scheduler) public final void captureStack(long leakDetectionThreshold, ScheduledExecutorService executorService)
{ {
StackTraceElement[] trace = Thread.currentThread().getStackTrace(); StackTraceElement[] trace = Thread.currentThread().getStackTrace();
StackTraceElement[] leakTrace = new StackTraceElement[trace.length - 4]; StackTraceElement[] leakTrace = new StackTraceElement[trace.length - 4];
System.arraycopy(trace, 4, leakTrace, 0, leakTrace.length); System.arraycopy(trace, 4, leakTrace, 0, leakTrace.length);
leakTask = new LeakTask(leakTrace, leakDetectionThreshold); leakTask = new LeakTask(leakTrace, leakDetectionThreshold);
scheduler.schedule(leakTask, leakDetectionThreshold); executorService.schedule(leakTask, leakDetectionThreshold, TimeUnit.MILLISECONDS);
} }
/** {@inheritDoc} */ /** {@inheritDoc} */

@ -19,7 +19,7 @@ package com.zaxxer.hikari.proxy;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.Timer; import java.util.concurrent.ScheduledExecutorService;
import com.zaxxer.hikari.util.ConcurrentBag.IBagManagable; import com.zaxxer.hikari.util.ConcurrentBag.IBagManagable;
@ -35,9 +35,9 @@ public interface IHikariConnectionProxy extends Connection, IBagManagable
* Catpure the stack and start leak detection. * Catpure the stack and start leak detection.
* *
* @param leakThreshold the number of milliseconds before a leak is reported * @param leakThreshold the number of milliseconds before a leak is reported
* @param houseKeepingTimer the timer to run the leak detection task with * @param houseKeepingExecutorService the executor service to run the leak detection task with
*/ */
void captureStack(long leakThreshold, Timer houseKeepingTimer); void captureStack(long leakThreshold, ScheduledExecutorService houseKeepingExecutorService);
/** /**
* Check if the provided SQLException contains a SQLSTATE that indicates * Check if the provided SQLException contains a SQLSTATE that indicates

@ -16,14 +16,12 @@
package com.zaxxer.hikari.proxy; package com.zaxxer.hikari.proxy;
import java.util.TimerTask;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* @author Brett Wooldridge * @author Brett Wooldridge
*/ */
class LeakTask extends TimerTask class LeakTask implements Runnable
{ {
private final long leakTime; private final long leakTime;
private StackTraceElement[] stackTrace; private StackTraceElement[] stackTrace;
@ -46,13 +44,8 @@ class LeakTask extends TimerTask
} }
} }
@Override public void cancel()
public boolean cancel()
{ {
boolean cancelled = super.cancel();
if (cancelled) {
stackTrace = null; stackTrace = null;
} }
return cancelled;
}
} }

@ -0,0 +1,36 @@
/*
* Copyright (C) 2013, 2014 Brett Wooldridge
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.zaxxer.hikari.util;
import java.util.concurrent.ThreadFactory;
public class DefaultThreadFactory implements ThreadFactory {
private String threadName;
private boolean daemon;
public DefaultThreadFactory(String threadName, boolean daemon) {
this.threadName = threadName;
this.daemon = daemon;
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, threadName);
thread.setDaemon(daemon);
return thread;
}
}

@ -106,16 +106,11 @@ public final class PoolUtilities
} }
} }
public static ThreadPoolExecutor createThreadPoolExecutor(final int queueSize, final String threadName) public static ThreadPoolExecutor createThreadPoolExecutor(final int queueSize, final String threadName, ThreadFactory threadFactory)
{ {
ThreadFactory threadFactory = new ThreadFactory() { if (threadFactory == null) {
public Thread newThread(Runnable r) threadFactory = new DefaultThreadFactory(threadName, true);
{
Thread t = new Thread(r, threadName);
t.setDaemon(true);
return t;
} }
};
int processors = Math.max(1, Runtime.getRuntime().availableProcessors() / 2); int processors = Math.max(1, Runtime.getRuntime().availableProcessors() / 2);
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(queueSize); LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(queueSize);

@ -1,3 +1,18 @@
/*
* Copyright (C) 2013, 2014 Brett Wooldridge
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.zaxxer.hikari.util; package com.zaxxer.hikari.util;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;

Loading…
Cancel
Save