aboutsummaryrefslogtreecommitdiffstats
path: root/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
diff options
context:
space:
mode:
Diffstat (limited to 'dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java')
-rw-r--r--dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java1500
1 files changed, 0 insertions, 1500 deletions
diff --git a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java b/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
deleted file mode 100644
index 7b081df..0000000
--- a/dblib/common/src/main/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java
+++ /dev/null
@@ -1,1500 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * openecomp
- * ================================================================================
- * Copyright (C) 2016 - 2017 AT&T
- * ================================================================================
- * 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.
- * ============LICENSE_END=========================================================
- */
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.tomcat.jdbc.pool;
-
-import java.lang.ref.WeakReference;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Proxy;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.ConcurrentModificationException;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-
-/**
- * Implementation of simple connection pool.
- * The ConnectionPool uses a {@link PoolProperties} object for storing all the meta information about the connection pool.
- * As the underlying implementation, the connection pool uses {@link java.util.concurrent.BlockingQueue} to store active and idle connections.
- * A custom implementation of a fair {@link FairBlockingQueue} blocking queue is provided with the connection pool itself.
- * @version 1.0
- */
-public class ConnectionPool {
-
- /**
- * Default domain for objects registering with an mbean server
- */
- public static final String POOL_JMX_DOMAIN = "tomcat.jdbc";
- /**
- * Prefix type for JMX registration
- */
- public static final String POOL_JMX_TYPE_PREFIX = POOL_JMX_DOMAIN+":type=";
-
- /**
- * Logger
- */
- private static final Log log = LogFactory.getLog(ConnectionPool.class);
-
- //===============================================================================
- // INSTANCE/QUICK ACCESS VARIABLE
- //===============================================================================
- /**
- * Carries the size of the pool, instead of relying on a queue implementation
- * that usually iterates over to get an exact count
- */
- private AtomicInteger size = new AtomicInteger(0);
-
- /**
- * All the information about the connection pool
- * These are the properties the pool got instantiated with
- */
- private PoolConfiguration poolProperties;
-
- /**
- * Contains all the connections that are in use
- * TODO - this shouldn't be a blocking queue, simply a list to hold our objects
- */
- private BlockingQueue<PooledConnection> busy;
-
- /**
- * Contains all the idle connections
- */
- private BlockingQueue<PooledConnection> idle;
-
- /**
- * The thread that is responsible for checking abandoned and idle threads
- */
- private volatile PoolCleaner poolCleaner;
-
- /**
- * Pool closed flag
- */
- private volatile boolean closed = false;
-
- /**
- * Since newProxyInstance performs the same operation, over and over
- * again, it is much more optimized if we simply store the constructor ourselves.
- */
- private Constructor<?> proxyClassConstructor;
-
- /**
- * Executor service used to cancel Futures
- */
- private ThreadPoolExecutor cancellator = new ThreadPoolExecutor(0,1,1000,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
-
- /**
- * reference to the JMX mbean
- */
- protected org.apache.tomcat.jdbc.pool.jmx.ConnectionPool jmxPool = null;
-
- /**
- * counter to track how many threads are waiting for a connection
- */
- private AtomicInteger waitcount = new AtomicInteger(0);
-
- private AtomicLong poolVersion = new AtomicLong(Long.MIN_VALUE);
-
- /**
- * The counters for statistics of the pool.
- */
- private final AtomicLong borrowedCount = new AtomicLong(0);
- private final AtomicLong returnedCount = new AtomicLong(0);
- private final AtomicLong createdCount = new AtomicLong(0);
- private final AtomicLong releasedCount = new AtomicLong(0);
- private final AtomicLong reconnectedCount = new AtomicLong(0);
- private final AtomicLong removeAbandonedCount = new AtomicLong(0);
- private final AtomicLong releasedIdleCount = new AtomicLong(0);
-
- //===============================================================================
- // PUBLIC METHODS
- //===============================================================================
-
- /**
- * Instantiate a connection pool. This will create connections if initialSize is larger than 0.
- * The {@link PoolProperties} should not be reused for another connection pool.
- * @param prop PoolProperties - all the properties for this connection pool
- * @throws SQLException Pool initialization error
- */
- public ConnectionPool(PoolConfiguration prop) throws SQLException {
- //setup quick access variables and pools
- init(prop);
- }
-
-
- /**
- * Retrieves a Connection future. If a connection is not available, one can block using future.get()
- * until a connection has become available.
- * If a connection is not retrieved, the Future must be cancelled in order for the connection to be returned
- * to the pool.
- * @return a Future containing a reference to the connection or the future connection
- * @throws SQLException Cannot use asynchronous connect
- */
- public Future<Connection> getConnectionAsync() throws SQLException {
- try {
- PooledConnection pc = borrowConnection(0, null, null);
- if (pc!=null) {
- return new ConnectionFuture(pc);
- }
- }catch (SQLException x) {
- if (x.getMessage().indexOf("NoWait")<0) {
- throw x;
- }
- }
- //we can only retrieve a future if the underlying queue supports it.
- if (idle instanceof FairBlockingQueue<?>) {
- Future<PooledConnection> pcf = ((FairBlockingQueue<PooledConnection>)idle).pollAsync();
- return new ConnectionFuture(pcf);
- } else if (idle instanceof MultiLockFairBlockingQueue<?>) {
- Future<PooledConnection> pcf = ((MultiLockFairBlockingQueue<PooledConnection>)idle).pollAsync();
- return new ConnectionFuture(pcf);
- } else {
- throw new SQLException("Connection pool is misconfigured, doesn't support async retrieval. Set the 'fair' property to 'true'");
- }
- }
-
- /**
- * Borrows a connection from the pool. If a connection is available (in the idle queue) or the pool has not reached
- * {@link PoolProperties#maxActive maxActive} connections a connection is returned immediately.
- * If no connection is available, the pool will attempt to fetch a connection for {@link PoolProperties#maxWait maxWait} milliseconds.
- * @return Connection - a java.sql.Connection/javax.sql.PooledConnection reflection proxy, wrapping the underlying object.
- * @throws SQLException - if the wait times out or a failure occurs creating a connection
- */
- public Connection getConnection() throws SQLException {
- //check out a connection
- PooledConnection con = borrowConnection(-1,null,null);
- return setupConnection(con);
- }
-
-
- /**
- * Borrows a connection from the pool. If a connection is available (in the
- * idle queue) or the pool has not reached {@link PoolProperties#maxActive
- * maxActive} connections a connection is returned immediately. If no
- * connection is available, the pool will attempt to fetch a connection for
- * {@link PoolProperties#maxWait maxWait} milliseconds.
- * @param username The user name to use for the connection
- * @param password The password for the connection
- * @return Connection - a java.sql.Connection/javax.sql.PooledConnection
- * reflection proxy, wrapping the underlying object.
- * @throws SQLException
- * - if the wait times out or a failure occurs creating a
- * connection
- */
- public Connection getConnection(String username, String password) throws SQLException {
- // check out a connection
- PooledConnection con = borrowConnection(-1, username, password);
- return setupConnection(con);
- }
-
- /**
- * Returns the name of this pool
- * @return String - the name of the pool
- */
- public String getName() {
- return getPoolProperties().getPoolName();
- }
-
- /**
- * Return the number of threads waiting for a connection
- * @return number of threads waiting for a connection
- */
- public int getWaitCount() {
- return waitcount.get();
- }
-
- /**
- * Returns the pool properties associated with this connection pool
- * @return PoolProperties
- *
- */
- public PoolConfiguration getPoolProperties() {
- return this.poolProperties;
- }
-
- /**
- * Returns the total size of this pool, this includes both busy and idle connections
- * @return int - number of established connections to the database
- */
- public int getSize() {
- return size.get();
- }
-
- /**
- * Returns the number of connections that are in use
- * @return int - number of established connections that are being used by the application
- */
- public int getActive() {
- return busy.size();
- }
-
- /**
- * Returns the number of idle connections
- * @return int - number of established connections not being used
- */
- public int getIdle() {
- return idle.size();
- }
-
- /**
- * Returns true if {@link #close close} has been called, and the connection pool is unusable
- * @return boolean
- */
- public boolean isClosed() {
- return this.closed;
- }
-
- //===============================================================================
- // PROTECTED METHODS
- //===============================================================================
-
-
- /**
- * configures a pooled connection as a proxy.
- * This Proxy implements {@link java.sql.Connection} and {@link javax.sql.PooledConnection} interfaces.
- * All calls on {@link java.sql.Connection} methods will be propagated down to the actual JDBC connection except for the
- * {@link java.sql.Connection#close()} method.
- * @param con a {@link PooledConnection} to wrap in a Proxy
- * @return a {@link java.sql.Connection} object wrapping a pooled connection.
- * @throws SQLException if an interceptor can't be configured, if the proxy can't be instantiated
- */
- protected Connection setupConnection(PooledConnection con) throws SQLException {
- //fetch previously cached interceptor proxy - one per connection
- JdbcInterceptor handler = con.getHandler();
- if (handler==null) {
- //build the proxy handler
- handler = new ProxyConnection(this,con,getPoolProperties().isUseEquals());
- //set up the interceptor chain
- PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
- for (int i=proxies.length-1; i>=0; i--) {
- try {
- //create a new instance
- JdbcInterceptor interceptor = proxies[i].getInterceptorClass().newInstance();
- //configure properties
- interceptor.setProperties(proxies[i].getProperties());
- //setup the chain
- interceptor.setNext(handler);
- //call reset
- interceptor.reset(this, con);
- //configure the last one to be held by the connection
- handler = interceptor;
- }catch(Exception x) {
- SQLException sx = new SQLException("Unable to instantiate interceptor chain.");
- sx.initCause(x);
- throw sx;
- }
- }
- //cache handler for the next iteration
- con.setHandler(handler);
- } else {
- JdbcInterceptor next = handler;
- //we have a cached handler, reset it
- while (next!=null) {
- next.reset(this, con);
- next = next.getNext();
- }
- }
-
- try {
- getProxyConstructor(con.getXAConnection() != null);
- //create the proxy
- //TODO possible optimization, keep track if this connection was returned properly, and don't generate a new facade
- Connection connection = null;
- if (getPoolProperties().getUseDisposableConnectionFacade() ) {
- connection = (Connection)proxyClassConstructor.newInstance(new Object[] { new DisposableConnectionFacade(handler) });
- } else {
- connection = (Connection)proxyClassConstructor.newInstance(new Object[] {handler});
- }
- //return the connection
- return connection;
- }catch (Exception x) {
- SQLException s = new SQLException();
- s.initCause(x);
- throw s;
- }
-
- }
-
- /**
- * Creates and caches a {@link java.lang.reflect.Constructor} used to instantiate the proxy object.
- * We cache this, since the creation of a constructor is fairly slow.
- * @param xa Use a XA connection
- * @return constructor used to instantiate the wrapper object
- * @throws NoSuchMethodException Failed to get a constructor
- */
- public Constructor<?> getProxyConstructor(boolean xa) throws NoSuchMethodException {
- //cache the constructor
- if (proxyClassConstructor == null ) {
- Class<?> proxyClass = xa ?
- Proxy.getProxyClass(ConnectionPool.class.getClassLoader(), new Class[] {java.sql.Connection.class,javax.sql.PooledConnection.class, javax.sql.XAConnection.class}) :
- Proxy.getProxyClass(ConnectionPool.class.getClassLoader(), new Class[] {java.sql.Connection.class,javax.sql.PooledConnection.class});
- proxyClassConstructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
- }
- return proxyClassConstructor;
- }
-
- /**
- * Closes the pool and all disconnects all idle connections
- * Active connections will be closed upon the {@link java.sql.Connection#close close} method is called
- * on the underlying connection instead of being returned to the pool
- * @param force - true to even close the active connections
- */
- protected void close(boolean force) {
- //are we already closed
- if (this.closed) return;
- //prevent other threads from entering
- this.closed = true;
- //stop background thread
- if (poolCleaner!=null) {
- poolCleaner.stopRunning();
- }
-
- /* release all idle connections */
- BlockingQueue<PooledConnection> pool = (idle.size()>0)?idle:(force?busy:idle);
- while (pool.size()>0) {
- try {
- //retrieve the next connection
- PooledConnection con = pool.poll(1000, TimeUnit.MILLISECONDS);
- //close it and retrieve the next one, if one is available
- while (con != null) {
- //close the connection
- if (pool==idle)
- release(con);
- else
- abandon(con);
- if (pool.size()>0) {
- con = pool.poll(1000, TimeUnit.MILLISECONDS);
- } else {
- break;
- }
- } //while
- } catch (InterruptedException ex) {
- if (getPoolProperties().getPropagateInterruptState()) {
- Thread.currentThread().interrupt();
- }
- }
- if (pool.size()==0 && force && pool!=busy) pool = busy;
- }
- if (this.getPoolProperties().isJmxEnabled()) this.jmxPool = null;
- PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
- for (int i=0; i<proxies.length; i++) {
- try {
- JdbcInterceptor interceptor = proxies[i].getInterceptorClass().newInstance();
- interceptor.setProperties(proxies[i].getProperties());
- interceptor.poolClosed(this);
- }catch (Exception x) {
- log.debug("Unable to inform interceptor of pool closure.",x);
- }
- }
- } //closePool
-
-
- /**
- * Initialize the connection pool - called from the constructor
- * @param properties PoolProperties - properties used to initialize the pool with
- * @throws SQLException if initialization fails
- */
- protected void init(PoolConfiguration properties) throws SQLException {
- poolProperties = properties;
-
- //make sure the pool is properly configured
- checkPoolConfiguration(properties);
-
- //make space for 10 extra in case we flow over a bit
- busy = new LinkedBlockingQueue<>();
- //busy = new FairBlockingQueue<PooledConnection>();
- //make space for 10 extra in case we flow over a bit
- if (properties.isFairQueue()) {
- idle = new FairBlockingQueue<>();
- //idle = new MultiLockFairBlockingQueue<PooledConnection>();
- //idle = new LinkedTransferQueue<PooledConnection>();
- //idle = new ArrayBlockingQueue<PooledConnection>(properties.getMaxActive(),false);
- } else {
- idle = new LinkedBlockingQueue<>();
- }
-
- initializePoolCleaner(properties);
-
- //create JMX MBean
- if (this.getPoolProperties().isJmxEnabled()) createMBean();
-
- //Parse and create an initial set of interceptors. Letting them know the pool has started.
- //These interceptors will not get any connection.
- PoolProperties.InterceptorDefinition[] proxies = getPoolProperties().getJdbcInterceptorsAsArray();
- for (int i=0; i<proxies.length; i++) {
- try {
- if (log.isDebugEnabled()) {
- log.debug("Creating interceptor instance of class:"+proxies[i].getInterceptorClass());
- }
- JdbcInterceptor interceptor = proxies[i].getInterceptorClass().newInstance();
- interceptor.setProperties(proxies[i].getProperties());
- interceptor.poolStarted(this);
- }catch (Exception x) {
- log.error("Unable to inform interceptor of pool start.",x);
- if (jmxPool!=null) jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_INIT, getStackTrace(x));
- close(true);
- SQLException ex = new SQLException();
- ex.initCause(x);
- throw ex;
- }
- }
-
- //initialize the pool with its initial set of members
- PooledConnection[] initialPool = new PooledConnection[poolProperties.getInitialSize()];
- try {
- for (int i = 0; i < initialPool.length; i++) {
- initialPool[i] = this.borrowConnection(0, null, null); //don't wait, should be no contention
- } //for
-
- } catch (SQLException x) {
- log.error("Unable to create initial connections of pool.", x);
- if (!poolProperties.isIgnoreExceptionOnPreLoad()) {
- if (jmxPool!=null) jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_INIT, getStackTrace(x));
- close(true);
- throw x;
- }
- } finally {
- //return the members as idle to the pool
- for (int i = 0; i < initialPool.length; i++) {
- if (initialPool[i] != null) {
- try {this.returnConnection(initialPool[i]);}catch(Exception x){/*NOOP*/}
- } //end if
- } //for
- } //catch
-
- closed = false;
- }
-
- public void checkPoolConfiguration(PoolConfiguration properties) {
- //make sure the pool is properly configured
- if (properties.getMaxActive()<1) {
- log.warn("maxActive is smaller than 1, setting maxActive to: "+PoolProperties.DEFAULT_MAX_ACTIVE);
- properties.setMaxActive(PoolProperties.DEFAULT_MAX_ACTIVE);
- }
- if (properties.getMaxActive()<properties.getInitialSize()) {
- log.warn("initialSize is larger than maxActive, setting initialSize to: "+properties.getMaxActive());
- properties.setInitialSize(properties.getMaxActive());
- }
- if (properties.getMinIdle()>properties.getMaxActive()) {
- log.warn("minIdle is larger than maxActive, setting minIdle to: "+properties.getMaxActive());
- properties.setMinIdle(properties.getMaxActive());
- }
- if (properties.getMaxIdle()>properties.getMaxActive()) {
- log.warn("maxIdle is larger than maxActive, setting maxIdle to: "+properties.getMaxActive());
- properties.setMaxIdle(properties.getMaxActive());
- }
- if (properties.getMaxIdle()<properties.getMinIdle()) {
- log.warn("maxIdle is smaller than minIdle, setting maxIdle to: "+properties.getMinIdle());
- properties.setMaxIdle(properties.getMinIdle());
- }
- }
-
- public void initializePoolCleaner(PoolConfiguration properties) {
- //if the evictor thread is supposed to run, start it now
- if (properties.isPoolSweeperEnabled()) {
- poolCleaner = new PoolCleaner(this, properties.getTimeBetweenEvictionRunsMillis());
- poolCleaner.start();
- } //end if
- }
-
- public void terminatePoolCleaner() {
- if (poolCleaner!= null) {
- poolCleaner.stopRunning();
- poolCleaner = null;
- }
- }
-
-
-//===============================================================================
-// CONNECTION POOLING IMPL LOGIC
-//===============================================================================
-
- /**
- * thread safe way to abandon a connection
- * signals a connection to be abandoned.
- * this will disconnect the connection, and log the stack trace if logAbandoned=true
- * @param con PooledConnection
- */
- protected void abandon(PooledConnection con) {
- if (con == null)
- return;
- try {
- con.lock();
- String trace = con.getStackTrace();
- if (getPoolProperties().isLogAbandoned()) {
- log.warn("Connection has been abandoned " + con + ":" + trace);
- }
- if (jmxPool!=null) {
- jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_ABANDON, trace);
- }
- //release the connection
- removeAbandonedCount.incrementAndGet();
- release(con);
- } finally {
- con.unlock();
- }
- }
-
- /**
- * Thread safe way to suspect a connection. Similar to
- * {@link #abandon(PooledConnection)}, but instead of actually abandoning
- * the connection, this will log a warning and set the suspect flag on the
- * {@link PooledConnection} if logAbandoned=true
- *
- * @param con PooledConnection
- */
- protected void suspect(PooledConnection con) {
- if (con == null)
- return;
- if (con.isSuspect())
- return;
- try {
- con.lock();
- String trace = con.getStackTrace();
- if (getPoolProperties().isLogAbandoned()) {
- log.warn("Connection has been marked suspect, possibly abandoned " + con + "["+(System.currentTimeMillis()-con.getTimestamp())+" ms.]:" + trace);
- }
- if (jmxPool!=null) {
- jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.SUSPECT_ABANDONED_NOTIFICATION, trace);
- }
- con.setSuspect(true);
- } finally {
- con.unlock();
- }
- }
-
- /**
- * thread safe way to release a connection
- * @param con PooledConnection
- */
- protected void release(PooledConnection con) {
- if (con == null)
- return;
- try {
- con.lock();
- if (con.release()) {
- //counter only decremented once
- size.addAndGet(-1);
- con.setHandler(null);
- }
- releasedCount.incrementAndGet();
- } finally {
- con.unlock();
- }
- // we've asynchronously reduced the number of connections
- // we could have threads stuck in idle.poll(timeout) that will never be
- // notified
- if (waitcount.get() > 0) {
- idle.offer(create(true));
- }
- }
-
- /**
- * Thread safe way to retrieve a connection from the pool
- * @param wait - time to wait, overrides the maxWait from the properties,
- * set to -1 if you wish to use maxWait, 0 if you wish no wait time.
- * @param username The user name to use for the connection
- * @param password The password for the connection
- * @return a connection
- * @throws SQLException Failed to get a connection
- */
- private PooledConnection borrowConnection(int wait, String username, String password) throws SQLException {
-
- if (isClosed()) {
- throw new SQLException("Connection pool closed.");
- } //end if
-
- //get the current time stamp
- long now = System.currentTimeMillis();
- //see if there is one available immediately
- PooledConnection con = idle.poll();
-
- while (true) {
- if (con!=null) {
- //configure the connection and return it
- PooledConnection result = borrowConnection(now, con, username, password);
- borrowedCount.incrementAndGet();
- if (result!=null) return result;
- }
-
- //if we get here, see if we need to create one
- //this is not 100% accurate since it doesn't use a shared
- //atomic variable - a connection can become idle while we are creating
- //a new connection
- if (size.get() < getPoolProperties().getMaxActive()) {
- //atomic duplicate check
- if (size.addAndGet(1) > getPoolProperties().getMaxActive()) {
- //if we got here, two threads passed through the first if
- size.decrementAndGet();
- } else {
- //create a connection, we're below the limit
- return createConnection(now, con, username, password);
- }
- } //end if
-
- //calculate wait time for this iteration
- long maxWait = wait;
- //if the passed in wait time is -1, means we should use the pool property value
- if (wait==-1) {
- maxWait = (getPoolProperties().getMaxWait()<=0)?Long.MAX_VALUE:getPoolProperties().getMaxWait();
- }
-
- long timetowait = Math.max(0, maxWait - (System.currentTimeMillis() - now));
- waitcount.incrementAndGet();
- try {
- //retrieve an existing connection
- con = idle.poll(timetowait, TimeUnit.MILLISECONDS);
- } catch (InterruptedException ex) {
- if (getPoolProperties().getPropagateInterruptState()) {
- Thread.currentThread().interrupt();
- }
- SQLException sx = new SQLException("Pool wait interrupted.");
- sx.initCause(ex);
- throw sx;
- } finally {
- waitcount.decrementAndGet();
- }
- if (maxWait==0 && con == null) { //no wait, return one if we have one
- if (jmxPool!=null) {
- jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.POOL_EMPTY, "Pool empty - no wait.");
- }
- throw new PoolExhaustedException("[" + Thread.currentThread().getName()+"] " +
- "NoWait: Pool empty. Unable to fetch a connection, none available["+busy.size()+" in use].");
- }
- //we didn't get a connection, lets see if we timed out
- if (con == null) {
- if ((System.currentTimeMillis() - now) >= maxWait) {
- if (jmxPool!=null) {
- jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.POOL_EMPTY, "Pool empty - timeout.");
- }
- throw new PoolExhaustedException("[" + Thread.currentThread().getName()+"] " +
- "Timeout: Pool empty. Unable to fetch a connection in " + (maxWait / 1000) +
- " seconds, none available[size:"+size.get() +"; busy:"+busy.size()+"; idle:"+idle.size()+"; lastwait:"+timetowait+"].");
- } else {
- //no timeout, lets try again
- continue;
- }
- }
- } //while
- }
-
- /**
- * Creates a JDBC connection and tries to connect to the database.
- * @param now timestamp of when this was called
- * @param notUsed Argument not used
- * @param username The user name to use for the connection
- * @param password The password for the connection
- * @return a PooledConnection that has been connected
- * @throws SQLException Failed to get a connection
- */
- protected PooledConnection createConnection(long now, PooledConnection notUsed, String username, String password) throws SQLException {
- //no connections where available we'll create one
- PooledConnection con = create(false);
- if (username!=null) con.getAttributes().put(PooledConnection.PROP_USER, username);
- if (password!=null) con.getAttributes().put(PooledConnection.PROP_PASSWORD, password);
- boolean error = false;
- try {
- //connect and validate the connection
- con.lock();
- con.connect();
- if (con.validate(PooledConnection.VALIDATE_INIT)) {
- //no need to lock a new one, its not contented
- con.setTimestamp(now);
- if (getPoolProperties().isLogAbandoned()) {
- con.setStackTrace(getThreadDump());
- }
- if (!busy.offer(con)) {
- log.debug("Connection doesn't fit into busy array, connection will not be traceable.");
- }
- createdCount.incrementAndGet();
- return con;
- } else {
- //validation failed, make sure we disconnect
- //and clean up
- throw new SQLException("Validation Query Failed, enable logValidationErrors for more details.");
- } //end if
- } catch (Exception e) {
- error = true;
- if (log.isDebugEnabled())
- log.debug("Unable to create a new JDBC connection.", e);
- if (e instanceof SQLException) {
- throw (SQLException)e;
- } else {
- SQLException ex = new SQLException(e.getMessage());
- ex.initCause(e);
- throw ex;
- }
- } finally {
- // con can never be null here
- if (error ) {
- release(con);
- }
- con.unlock();
- }//catch
- }
-
- /**
- * Validates and configures a previously idle connection
- * @param now - timestamp
- * @param con - the connection to validate and configure
- * @param username The user name to use for the connection
- * @param password The password for the connection
- * @return a connection
- * @throws SQLException if a validation error happens
- */
- protected PooledConnection borrowConnection(long now, PooledConnection con, String username, String password) throws SQLException {
- //we have a connection, lets set it up
-
- //flag to see if we need to nullify
- boolean setToNull = false;
- try {
- con.lock();
- if (con.isReleased()) {
- return null;
- }
-
- //evaluate username/password change as well as max age functionality
- boolean forceReconnect = con.shouldForceReconnect(username, password) || con.isMaxAgeExpired();
-
- if (!con.isDiscarded() && !con.isInitialized()) {
- //here it states that the connection not discarded, but the connection is null
- //don't attempt a connect here. It will be done during the reconnect.
- forceReconnect = true;
- }
-
- if (!forceReconnect) {
- if ((!con.isDiscarded()) && con.validate(PooledConnection.VALIDATE_BORROW)) {
- //set the timestamp
- con.setTimestamp(now);
- if (getPoolProperties().isLogAbandoned()) {
- //set the stack trace for this pool
- con.setStackTrace(getThreadDump());
- }
- if (!busy.offer(con)) {
- log.debug("Connection doesn't fit into busy array, connection will not be traceable.");
- }
- return con;
- }
- }
- //if we reached here, that means the connection
- //is either has another principal, is discarded or validation failed.
- //we will make one more attempt
- //in order to guarantee that the thread that just acquired
- //the connection shouldn't have to poll again.
- try {
- con.reconnect();
- reconnectedCount.incrementAndGet();
- int validationMode = getPoolProperties().isTestOnConnect() || getPoolProperties().getInitSQL()!=null ?
- PooledConnection.VALIDATE_INIT :
- PooledConnection.VALIDATE_BORROW;
-
- if (con.validate(validationMode)) {
- //set the timestamp
- con.setTimestamp(now);
- if (getPoolProperties().isLogAbandoned()) {
- //set the stack trace for this pool
- con.setStackTrace(getThreadDump());
- }
- if (!busy.offer(con)) {
- log.debug("Connection doesn't fit into busy array, connection will not be traceable.");
- }
- return con;
- } else {
- //validation failed.
- throw new SQLException("Failed to validate a newly established connection.");
- }
- } catch (Exception x) {
- release(con);
- setToNull = true;
- if (x instanceof SQLException) {
- throw (SQLException)x;
- } else {
- SQLException ex = new SQLException(x.getMessage());
- ex.initCause(x);
- throw ex;
- }
- }
- } finally {
- con.unlock();
- if (setToNull) {
- con = null;
- }
- }
- }
- /**
- * Terminate the current transaction for the given connection.
- * @param con The connection
- * @return <code>true</code> if the connection TX termination succeeded
- * otherwise <code>false</code>
- */
- protected boolean terminateTransaction(PooledConnection con) {
- try {
- if (Boolean.FALSE.equals(con.getPoolProperties().getDefaultAutoCommit())) {
- if (this.getPoolProperties().getRollbackOnReturn()) {
- boolean autocommit = con.getConnection().getAutoCommit();
- if (!autocommit) con.getConnection().rollback();
- } else if (this.getPoolProperties().getCommitOnReturn()) {
- boolean autocommit = con.getConnection().getAutoCommit();
- if (!autocommit) con.getConnection().commit();
- }
- }
- return true;
- } catch (SQLException x) {
- log.warn("Unable to terminate transaction, connection will be closed.",x);
- return false;
- }
-
- }
-
- /**
- * Determines if a connection should be closed upon return to the pool.
- * @param con - the connection
- * @param action - the validation action that should be performed
- * @return <code>true</code> if the connection should be closed
- */
- protected boolean shouldClose(PooledConnection con, int action) {
- if (con.getConnectionVersion() < getPoolVersion()) return true;
- if (con.isDiscarded()) return true;
- if (isClosed()) return true;
- if (!con.validate(action)) return true;
- if (!terminateTransaction(con)) return true;
- if (con.isMaxAgeExpired()) return true;
- else return false;
- }
-
- /**
- * Returns a connection to the pool
- * If the pool is closed, the connection will be released
- * If the connection is not part of the busy queue, it will be released.
- * If {@link PoolProperties#testOnReturn} is set to true it will be validated
- * @param con PooledConnection to be returned to the pool
- */
- protected void returnConnection(PooledConnection con) {
- if (isClosed()) {
- //if the connection pool is closed
- //close the connection instead of returning it
- release(con);
- return;
- } //end if
-
- if (con != null) {
- try {
- returnedCount.incrementAndGet();
- con.lock();
- if (con.isSuspect()) {
- if (poolProperties.isLogAbandoned() && log.isInfoEnabled()) {
- log.info("Connection(" + con + ") that has been marked suspect was returned."
- + " The processing time is " + (System.currentTimeMillis()-con.getTimestamp()) + " ms.");
- }
- if (jmxPool!=null) {
- jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.SUSPECT_RETURNED_NOTIFICATION,
- "Connection(" + con + ") that has been marked suspect was returned.");
- }
- }
- if (busy.remove(con)) {
-
- if (!shouldClose(con,PooledConnection.VALIDATE_RETURN)) {
- con.setStackTrace(null);
- con.setTimestamp(System.currentTimeMillis());
- if (((idle.size()>=poolProperties.getMaxIdle()) && !poolProperties.isPoolSweeperEnabled()) || (!idle.offer(con))) {
- if (log.isDebugEnabled()) {
- log.debug("Connection ["+con+"] will be closed and not returned to the pool, idle["+idle.size()+"]>=maxIdle["+poolProperties.getMaxIdle()+"] idle.offer failed.");
- }
- release(con);
- }
- } else {
- if (log.isDebugEnabled()) {
- log.debug("Connection ["+con+"] will be closed and not returned to the pool.");
- }
- release(con);
- } //end if
- } else {
- if (log.isDebugEnabled()) {
- log.debug("Connection ["+con+"] will be closed and not returned to the pool, busy.remove failed.");
- }
- release(con);
- }
- } finally {
- con.unlock();
- }
- } //end if
- } //checkIn
-
- /**
- * Determines if a connection should be abandoned based on
- * {@link PoolProperties#abandonWhenPercentageFull} setting.
- * @return <code>true</code> if the connection should be abandoned
- */
- protected boolean shouldAbandon() {
- if (!poolProperties.isRemoveAbandoned()) return false;
- if (poolProperties.getAbandonWhenPercentageFull()==0) return true;
- float used = busy.size();
- float max = poolProperties.getMaxActive();
- float perc = poolProperties.getAbandonWhenPercentageFull();
- return (used/max*100f)>=perc;
- }
-
- /**
- * Iterates through all the busy connections and checks for connections that have timed out
- */
- public void checkAbandoned() {
- try {
- if (busy.size()==0) return;
- Iterator<PooledConnection> locked = busy.iterator();
- int sto = getPoolProperties().getSuspectTimeout();
- while (locked.hasNext()) {
- PooledConnection con = locked.next();
- boolean setToNull = false;
- try {
- con.lock();
- //the con has been returned to the pool or released
- //ignore it
- if (idle.contains(con) || con.isReleased())
- continue;
- long time = con.getTimestamp();
- long now = System.currentTimeMillis();
- if (shouldAbandon() && (now - time) > con.getAbandonTimeout()) {
- busy.remove(con);
- abandon(con);
- setToNull = true;
- } else if (sto > 0 && (now - time) > (sto * 1000L)) {
- suspect(con);
- } else {
- //do nothing
- } //end if
- } finally {
- con.unlock();
- if (setToNull)
- con = null;
- }
- } //while
- } catch (ConcurrentModificationException e) {
- log.debug("checkAbandoned failed." ,e);
- } catch (Exception e) {
- log.warn("checkAbandoned failed, it will be retried.",e);
- }
- }
-
- /**
- * Iterates through the idle connections and resizes the idle pool based on parameters
- * {@link PoolProperties#maxIdle}, {@link PoolProperties#minIdle}, {@link PoolProperties#minEvictableIdleTimeMillis}
- */
- public void checkIdle() {
- checkIdle(false);
- }
-
- public void checkIdle(boolean ignoreMinSize) {
-
- try {
- if (idle.size()==0) return;
- long now = System.currentTimeMillis();
- Iterator<PooledConnection> unlocked = idle.iterator();
- while ( (ignoreMinSize || (idle.size()>=getPoolProperties().getMinIdle())) && unlocked.hasNext()) {
- PooledConnection con = unlocked.next();
- boolean setToNull = false;
- try {
- con.lock();
- //the con been taken out, we can't clean it up
- if (busy.contains(con))
- continue;
- long time = con.getTimestamp();
- if (shouldReleaseIdle(now, con, time)) {
- releasedIdleCount.incrementAndGet();
- release(con);
- idle.remove(con);
- setToNull = true;
- } else {
- //do nothing
- } //end if
- } finally {
- con.unlock();
- if (setToNull)
- con = null;
- }
- } //while
- } catch (ConcurrentModificationException e) {
- log.debug("checkIdle failed." ,e);
- } catch (Exception e) {
- log.warn("checkIdle failed, it will be retried.",e);
- }
-
- }
-
-
- protected boolean shouldReleaseIdle(long now, PooledConnection con, long time) {
- if (con.getConnectionVersion() < getPoolVersion()) return true;
- else return (con.getReleaseTime()>0) && ((now - time) > con.getReleaseTime()) && (getSize()>getPoolProperties().getMinIdle());
- }
-
- /**
- * Forces a validation of all idle connections if {@link PoolProperties#testWhileIdle} is set.
- */
- public void testAllIdle() {
- try {
- if (idle.size()==0) return;
- Iterator<PooledConnection> unlocked = idle.iterator();
- while (unlocked.hasNext()) {
- PooledConnection con = unlocked.next();
- try {
- con.lock();
- //the con been taken out, we can't clean it up
- if (busy.contains(con))
- continue;
- if (!con.validate(PooledConnection.VALIDATE_IDLE)) {
- idle.remove(con);
- release(con);
- }
- } finally {
- con.unlock();
- }
- } //while
- } catch (ConcurrentModificationException e) {
- log.debug("testAllIdle failed." ,e);
- } catch (Exception e) {
- log.warn("testAllIdle failed, it will be retried.",e);
- }
-
- }
-
- /**
- * Creates a stack trace representing the existing thread's current state.
- * @return a string object representing the current state.
- * TODO investigate if we simply should store {@link java.lang.Thread#getStackTrace()} elements
- */
- protected static String getThreadDump() {
- Exception x = new Exception();
- x.fillInStackTrace();
- return getStackTrace(x);
- }
-
- /**
- * Convert an exception into a String
- * @param x - the throwable
- * @return a string representing the stack trace
- */
- public static String getStackTrace(Throwable x) {
- if (x == null) {
- return null;
- } else {
- java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
- java.io.PrintStream writer = new java.io.PrintStream(bout);
- x.printStackTrace(writer);
- String result = bout.toString();
- return (x.getMessage()!=null && x.getMessage().length()>0)? x.getMessage()+";"+result:result;
- } //end if
- }
-
-
- /**
- * Create a new pooled connection object. Not connected nor validated.
- * @param incrementCounter <code>true</code> to increment the connection count
- * @return a pooled connection object
- */
- protected PooledConnection create(boolean incrementCounter) {
- if (incrementCounter) size.incrementAndGet();
- PooledConnection con = new PooledConnection(getPoolProperties(), this);
- return con;
- }
-
- /**
- * Purges all connections in the pool.
- * For connections currently in use, these connections will be
- * purged when returned on the pool. This call also
- * purges connections that are idle and in the pool
- * To only purge used/active connections see {@link #purgeOnReturn()}
- */
- public void purge() {
- purgeOnReturn();
- checkIdle(true);
- }
-
- /**
- * Purges connections when they are returned from the pool.
- * This call does not purge idle connections until they are used.
- * To purge idle connections see {@link #purge()}
- */
- public void purgeOnReturn() {
- poolVersion.incrementAndGet();
- }
-
- /**
- * Hook to perform final actions on a pooled connection object once it has been disconnected and will be discarded
- * @param con The connection
- */
- protected void finalize(PooledConnection con) {
- JdbcInterceptor handler = con.getHandler();
- while (handler!=null) {
- handler.reset(null, null);
- handler=handler.getNext();
- }
- }
-
- /**
- * Hook to perform final actions on a pooled connection object once it has been disconnected and will be discarded
- * @param con The connection
- * @param finalizing <code>true</code> if finalizing the connection
- */
- protected void disconnectEvent(PooledConnection con, boolean finalizing) {
- JdbcInterceptor handler = con.getHandler();
- while (handler!=null) {
- handler.disconnected(this, con, finalizing);
- handler=handler.getNext();
- }
- }
-
- /**
- * Return the object that is potentially registered in JMX for notifications
- * @return the object implementing the {@link org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean} interface
- */
- public org.apache.tomcat.jdbc.pool.jmx.ConnectionPool getJmxPool() {
- return jmxPool;
- }
-
- /**
- * Create MBean object that can be registered.
- */
- protected void createMBean() {
- try {
- jmxPool = new org.apache.tomcat.jdbc.pool.jmx.ConnectionPool(this);
- } catch (Exception x) {
- log.warn("Unable to start JMX integration for connection pool. Instance["+getName()+"] can't be monitored.",x);
- }
- }
-
- /**
- * The total number of connections borrowed from this pool.
- * @return the borrowed connection count
- */
- public long getBorrowedCount() {
- return borrowedCount.get();
- }
-
- /**
- * The total number of connections returned to this pool.
- * @return the returned connection count
- */
- public long getReturnedCount() {
- return returnedCount.get();
- }
-
- /**
- * The total number of connections created by this pool.
- * @return the created connection count
- */
- public long getCreatedCount() {
- return createdCount.get();
- }
-
- /**
- * The total number of connections released from this pool.
- * @return the released connection count
- */
- public long getReleasedCount() {
- return releasedCount.get();
- }
-
- /**
- * The total number of connections reconnected by this pool.
- * @return the reconnected connection count
- */
- public long getReconnectedCount() {
- return reconnectedCount.get();
- }
-
- /**
- * The total number of connections released by remove abandoned.
- * @return the PoolCleaner removed abandoned connection count
- */
- public long getRemoveAbandonedCount() {
- return removeAbandonedCount.get();
- }
-
- /**
- * The total number of connections released by eviction.
- * @return the PoolCleaner evicted idle connection count
- */
- public long getReleasedIdleCount() {
- return releasedIdleCount.get();
- }
-
- /**
- * reset the statistics of this pool.
- */
- public void resetStats() {
- borrowedCount.set(0);
- returnedCount.set(0);
- createdCount.set(0);
- releasedCount.set(0);
- reconnectedCount.set(0);
- removeAbandonedCount.set(0);
- releasedIdleCount.set(0);
- }
-
- /**
- * Tread safe wrapper around a future for the regular queue
- * This one retrieves the pooled connection object
- * and performs the initialization according to
- * interceptors and validation rules.
- * This class is thread safe and is cancellable
- *
- */
- protected class ConnectionFuture implements Future<Connection>, Runnable {
- Future<PooledConnection> pcFuture = null;
- AtomicBoolean configured = new AtomicBoolean(false);
- CountDownLatch latch = new CountDownLatch(1);
- volatile Connection result = null;
- SQLException cause = null;
- AtomicBoolean cancelled = new AtomicBoolean(false);
- volatile PooledConnection pc = null;
- public ConnectionFuture(Future<PooledConnection> pcf) {
- this.pcFuture = pcf;
- }
-
- public ConnectionFuture(PooledConnection pc) throws SQLException {
- this.pc = pc;
- result = ConnectionPool.this.setupConnection(pc);
- configured.set(true);
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean cancel(boolean mayInterruptIfRunning) {
- if (pc!=null) {
- return false;
- } else if ((!cancelled.get()) && cancelled.compareAndSet(false, true)) {
- //cancel by retrieving the connection and returning it to the pool
- ConnectionPool.this.cancellator.execute(this);
- }
- return true;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Connection get() throws InterruptedException, ExecutionException {
- try {
- return get(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
- }catch (TimeoutException x) {
- throw new ExecutionException(x);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Connection get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
- PooledConnection pc = this.pc!=null?this.pc:pcFuture.get(timeout,unit);
- if (pc!=null) {
- if (result!=null) return result;
- if (configured.compareAndSet(false, true)) {
- try {
- pc = borrowConnection(System.currentTimeMillis(),pc, null, null);
- result = ConnectionPool.this.setupConnection(pc);
- } catch (SQLException x) {
- cause = x;
- } finally {
- latch.countDown();
- }
- } else {
- //if we reach here, another thread is configuring the actual connection
- latch.await(timeout,unit); //this shouldn't block for long
- }
- if (result==null) throw new ExecutionException(cause);
- return result;
- } else {
- return null;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isCancelled() {
- return pc==null && (pcFuture.isCancelled() || cancelled.get());
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isDone() {
- return pc!=null || pcFuture.isDone();
- }
-
- /**
- * run method to be executed when cancelled by an executor
- */
- @Override
- public void run() {
- try {
- Connection con = get(); //complete this future
- con.close(); //return to the pool
- }catch (ExecutionException ex) {
- //we can ignore this
- }catch (Exception x) {
- ConnectionPool.log.error("Unable to cancel ConnectionFuture.",x);
- }
- }
-
- }
-
-
-
- private static volatile Timer poolCleanTimer = null;
- private static HashSet<PoolCleaner> cleaners = new HashSet<>();
-
- private static synchronized void registerCleaner(PoolCleaner cleaner) {
- unregisterCleaner(cleaner);
- cleaners.add(cleaner);
- if (poolCleanTimer == null) {
- ClassLoader loader = Thread.currentThread().getContextClassLoader();
- try {
- Thread.currentThread().setContextClassLoader(ConnectionPool.class.getClassLoader());
- // Create the timer thread in a PrivilegedAction so that a
- // reference to the web application class loader is not created
- // via Thread.inheritedAccessControlContext
- PrivilegedAction<Timer> pa = new PrivilegedNewTimer();
- poolCleanTimer = AccessController.doPrivileged(pa);
- } finally {
- Thread.currentThread().setContextClassLoader(loader);
- }
- }
- poolCleanTimer.schedule(cleaner, cleaner.sleepTime,cleaner.sleepTime);
- }
-
- private static synchronized void unregisterCleaner(PoolCleaner cleaner) {
- boolean removed = cleaners.remove(cleaner);
- if (removed) {
- cleaner.cancel();
- if (poolCleanTimer != null) {
- poolCleanTimer.purge();
- if (cleaners.size() == 0) {
- poolCleanTimer.cancel();
- poolCleanTimer = null;
- }
- }
- }
- }
-
- private static class PrivilegedNewTimer implements PrivilegedAction<Timer> {
- @Override
- public Timer run() {
- return new Timer("Tomcat JDBC Pool Cleaner["+ System.identityHashCode(ConnectionPool.class.getClassLoader()) + ":"+
- System.currentTimeMillis() + "]", true);
- }
- }
-
- public static Set<TimerTask> getPoolCleaners() {
- return Collections.<TimerTask>unmodifiableSet(cleaners);
- }
-
- public long getPoolVersion() {
- return poolVersion.get();
- }
-
- public static Timer getPoolTimer() {
- return poolCleanTimer;
- }
-
- protected static class PoolCleaner extends TimerTask {
- protected WeakReference<ConnectionPool> pool;
- protected long sleepTime;
-
- PoolCleaner(ConnectionPool pool, long sleepTime) {
- this.pool = new WeakReference<>(pool);
- this.sleepTime = sleepTime;
- if (sleepTime <= 0) {
- log.warn("Database connection pool evicter thread interval is set to 0, defaulting to 30 seconds");
- this.sleepTime = 1000 * 30;
- } else if (sleepTime < 1000) {
- log.warn("Database connection pool evicter thread interval is set to lower than 1 second.");
- }
- }
-
- @Override
- public void run() {
- ConnectionPool pool = this.pool.get();
- if (pool == null) {
- stopRunning();
- } else if (!pool.isClosed()) {
- try {
- if (pool.getPoolProperties().isRemoveAbandoned()
- || pool.getPoolProperties().getSuspectTimeout() > 0)
- pool.checkAbandoned();
- if (pool.getPoolProperties().getMinIdle() < pool.idle
- .size())
- pool.checkIdle();
- if (pool.getPoolProperties().isTestWhileIdle())
- pool.testAllIdle();
- } catch (Exception x) {
- log.error("", x);
- }
- }
- }
-
- public void start() {
- registerCleaner(this);
- }
-
- public void stopRunning() {
- unregisterCleaner(this);
- }
- }
-}