|
|
|
@ -118,7 +118,8 @@ public class Pool implements BagStateListener {
|
|
|
|
|
*
|
|
|
|
|
* @param config the config
|
|
|
|
|
*/
|
|
|
|
|
public Pool(PoolConfig config) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
|
|
|
|
|
public Pool(PoolConfig config) throws ClassNotFoundException,
|
|
|
|
|
NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
|
|
|
|
|
config.validate();
|
|
|
|
|
this.config = config;
|
|
|
|
|
logger.log(Level.INFO, () -> "starting new pool: " + config.getPoolName());
|
|
|
|
@ -146,18 +147,26 @@ public class Pool implements BagStateListener {
|
|
|
|
|
checkFailFast(initializationTimeout);
|
|
|
|
|
}
|
|
|
|
|
ThreadFactory threadFactory = config.getThreadFactory();
|
|
|
|
|
ClassLoader contextClassLoader = config.getContextClassLoader();
|
|
|
|
|
int maxPoolSize = config.getMaximumPoolSize();
|
|
|
|
|
LinkedBlockingQueue<Runnable> addConnectionQueue = new LinkedBlockingQueue<>(maxPoolSize);
|
|
|
|
|
this.addConnectionQueueReadOnlyView = Collections.unmodifiableCollection(addConnectionQueue);
|
|
|
|
|
this.addConnectionExecutor = createThreadPoolExecutor(addConnectionQueue,
|
|
|
|
|
poolName + " connection adder", threadFactory, new ThreadPoolExecutor.DiscardOldestPolicy());
|
|
|
|
|
poolName + " connection adder",
|
|
|
|
|
threadFactory,
|
|
|
|
|
contextClassLoader,
|
|
|
|
|
new ThreadPoolExecutor.DiscardOldestPolicy());
|
|
|
|
|
this.closeConnectionExecutor = createThreadPoolExecutor(maxPoolSize,
|
|
|
|
|
poolName + " connection closer", threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());
|
|
|
|
|
poolName + " connection closer",
|
|
|
|
|
threadFactory,
|
|
|
|
|
contextClassLoader,
|
|
|
|
|
new ThreadPoolExecutor.CallerRunsPolicy());
|
|
|
|
|
this.leakTaskFactory = new ProxyLeakTaskFactory(config.getLeakDetectionThreshold(), houseKeepingExecutorService);
|
|
|
|
|
this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(new HouseKeeper(this), 100L, config.getHousekeepingPeriodMs(), TimeUnit.MILLISECONDS);
|
|
|
|
|
if (Boolean.getBoolean("org.xbib.jdbc.connection.pool.blockUntilFilled") && config.getInitializationFailTimeout() > 1) {
|
|
|
|
|
addConnectionExecutor.setCorePoolSize(Math.min(16, Runtime.getRuntime().availableProcessors()));
|
|
|
|
|
addConnectionExecutor.setMaximumPoolSize(Math.min(16, Runtime.getRuntime().availableProcessors()));
|
|
|
|
|
int procs = Math.min(16, Runtime.getRuntime().availableProcessors());
|
|
|
|
|
addConnectionExecutor.setCorePoolSize(procs);
|
|
|
|
|
addConnectionExecutor.setMaximumPoolSize(procs);
|
|
|
|
|
final long startTime = ClockSource.currentTime();
|
|
|
|
|
while (ClockSource.elapsedMillis(startTime) < config.getInitializationFailTimeout() && getTotalConnections() < config.getMinimumIdle()) {
|
|
|
|
|
quietlySleep(TimeUnit.MILLISECONDS.toMillis(100));
|
|
|
|
@ -305,8 +314,11 @@ public class Pool implements BagStateListener {
|
|
|
|
|
addConnectionExecutor.awaitTermination(getLoginTimeout(), TimeUnit.SECONDS);
|
|
|
|
|
destroyHouseKeepingExecutorService();
|
|
|
|
|
bag.close();
|
|
|
|
|
final ExecutorService assassinExecutor = createThreadPoolExecutor(config.getMaximumPoolSize(), poolName + " connection assassinator",
|
|
|
|
|
config.getThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
|
|
|
|
|
final ExecutorService assassinExecutor = createThreadPoolExecutor(config.getMaximumPoolSize(),
|
|
|
|
|
poolName + " connection assassinator",
|
|
|
|
|
config.getThreadFactory(),
|
|
|
|
|
config.getContextClassLoader(),
|
|
|
|
|
new ThreadPoolExecutor.CallerRunsPolicy());
|
|
|
|
|
try {
|
|
|
|
|
final long start = ClockSource.currentTime();
|
|
|
|
|
do {
|
|
|
|
@ -415,6 +427,7 @@ public class Pool implements BagStateListener {
|
|
|
|
|
if (ds == null) {
|
|
|
|
|
String dsClassName = config.getDataSourceClassName();
|
|
|
|
|
if (dsClassName != null) {
|
|
|
|
|
// we must use the system class loader
|
|
|
|
|
Class<?> clazz = Class.forName(dsClassName, true, ClassLoader.getSystemClassLoader());
|
|
|
|
|
ds = (DataSource) clazz.getDeclaredConstructor().newInstance();
|
|
|
|
|
} else if (url != null) {
|
|
|
|
@ -816,7 +829,8 @@ public class Pool implements BagStateListener {
|
|
|
|
|
private ScheduledExecutorService initializeHouseKeepingExecutorService() {
|
|
|
|
|
if (config.getScheduledExecutor() == null) {
|
|
|
|
|
ThreadFactory threadFactory = Optional.ofNullable(config.getThreadFactory()).orElseGet(() ->
|
|
|
|
|
new DefaultThreadFactory(poolName + "-housekeeper", true));
|
|
|
|
|
new DefaultThreadFactory(poolName + "-housekeeper",
|
|
|
|
|
Thread.currentThread().getContextClassLoader(), true));
|
|
|
|
|
ScheduledThreadPoolExecutor executor =
|
|
|
|
|
new ScheduledThreadPoolExecutor(1, threadFactory,
|
|
|
|
|
new ThreadPoolExecutor.DiscardPolicy());
|
|
|
|
@ -869,16 +883,18 @@ public class Pool implements BagStateListener {
|
|
|
|
|
*
|
|
|
|
|
* @param queueSize the queue size
|
|
|
|
|
* @param threadName the thread name
|
|
|
|
|
* @param threadFactory an optional ThreadFactory
|
|
|
|
|
* @param threadFactory an optional ThreadFactory, if null, a DefaultThreadFactory will be used
|
|
|
|
|
* @param contextClassLoader the context class loader if the thread factory is null
|
|
|
|
|
* @param policy the RejectedExecutionHandler policy
|
|
|
|
|
* @return a ThreadPoolExecutor
|
|
|
|
|
*/
|
|
|
|
|
private ThreadPoolExecutor createThreadPoolExecutor(int queueSize,
|
|
|
|
|
String threadName,
|
|
|
|
|
ThreadFactory threadFactory,
|
|
|
|
|
ClassLoader contextClassLoader,
|
|
|
|
|
RejectedExecutionHandler policy) {
|
|
|
|
|
if (threadFactory == null) {
|
|
|
|
|
threadFactory = new DefaultThreadFactory(threadName, true);
|
|
|
|
|
threadFactory = new DefaultThreadFactory(threadName, contextClassLoader, true);
|
|
|
|
|
}
|
|
|
|
|
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(queueSize);
|
|
|
|
|
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1,
|
|
|
|
@ -899,9 +915,10 @@ public class Pool implements BagStateListener {
|
|
|
|
|
private ThreadPoolExecutor createThreadPoolExecutor(BlockingQueue<Runnable> queue,
|
|
|
|
|
String threadName,
|
|
|
|
|
ThreadFactory threadFactory,
|
|
|
|
|
ClassLoader contextClassLoader,
|
|
|
|
|
RejectedExecutionHandler policy) {
|
|
|
|
|
if (threadFactory == null) {
|
|
|
|
|
threadFactory = new DefaultThreadFactory(threadName, true);
|
|
|
|
|
threadFactory = new DefaultThreadFactory(threadName, contextClassLoader, true);
|
|
|
|
|
}
|
|
|
|
|
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1,
|
|
|
|
|
5, TimeUnit.SECONDS, queue, threadFactory, policy);
|
|
|
|
@ -977,7 +994,7 @@ public class Pool implements BagStateListener {
|
|
|
|
|
*
|
|
|
|
|
* @return true if we should create a connection, false if the need has disappeared
|
|
|
|
|
*/
|
|
|
|
|
synchronized boolean shouldCreateAnotherConnection() {
|
|
|
|
|
public synchronized boolean shouldCreateAnotherConnection() {
|
|
|
|
|
return getTotalConnections() < config.getMaximumPoolSize() &&
|
|
|
|
|
(bag.getWaitingThreadCount() > 0 || getIdleConnections() < config.getMinimumIdle());
|
|
|
|
|
}
|
|
|
|
|