/** * Copyright 2010 Wallace Wadge * * 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.jolbox.bonecp; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Watches a partition to create new connections when required. * @author wwadge * */ public class PoolWatchThread implements Runnable { /** Partition being monitored. */ private ConnectionPartition partition; /** Pool handle. */ private BoneCP pool; /** Mostly used to break out easily in unit testing. */ private boolean signalled; /** How long to wait before retrying to add a connection upon failure. */ private long acquireRetryDelayInMs = 1000L; /** Start off lazily. */ protected boolean lazyInit; /** Occupancy% threshold. */ private int poolAvailabilityThreshold; /** Logger handle. */ private static final Logger logger = LoggerFactory.getLogger(PoolWatchThread.class); /** Thread constructor * @param connectionPartition partition to monitor * @param pool Pool handle. */ public PoolWatchThread(ConnectionPartition connectionPartition, BoneCP pool) { this.partition = connectionPartition; this.pool = pool; this.lazyInit = this.pool.getConfig().isLazyInit(); this.acquireRetryDelayInMs = this.pool.getConfig().getAcquireRetryDelayInMs(); this.poolAvailabilityThreshold = this.pool.getConfig().getPoolAvailabilityThreshold(); } public void run() { int maxNewConnections; while (!this.signalled){ maxNewConnections=0; try{ if (this.lazyInit){ // block the first time if this is on. this.partition.getPoolWatchThreadSignalQueue().take(); } maxNewConnections = this.partition.getMaxConnections()-this.partition.getCreatedConnections(); // loop for spurious interrupt while (maxNewConnections == 0 || (this.partition.getAvailableConnections() *100/this.partition.getMaxConnections() > this.poolAvailabilityThreshold)){ if (maxNewConnections == 0){ this.partition.setUnableToCreateMoreTransactions(true); } this.partition.getPoolWatchThreadSignalQueue().take(); maxNewConnections = this.partition.getMaxConnections()-this.partition.getCreatedConnections(); } if (maxNewConnections > 0 && !this.pool.poolShuttingDown){ fillConnections(Math.min(maxNewConnections, this.partition.getAcquireIncrement())); // for the case where we have killed off all our connections due to network/db error if (this.partition.getCreatedConnections() < this.partition.getMinConnections()){ fillConnections(this.partition.getMinConnections() - this.partition.getCreatedConnections() ); } } if (this.pool.poolShuttingDown){ return; } } catch (InterruptedException e) { logger.debug("Terminating pool watch thread"); return; // we've been asked to terminate. } } } /** Adds new connections to the partition. * @param connectionsToCreate number of connections to create * @throws InterruptedException */ private void fillConnections(int connectionsToCreate) throws InterruptedException { try { for (int i=0; i < connectionsToCreate; i++){ // boolean dbDown = this.pool.getDbIsDown().get(); if (this.pool.poolShuttingDown){ break; } this.partition.addFreeConnection(new ConnectionHandle(null, this.partition, this.pool, false)); } } catch (Exception e) { logger.error("Error in trying to obtain a connection. Retrying in "+this.acquireRetryDelayInMs+"ms", e); Thread.sleep(this.acquireRetryDelayInMs); } } }