org.apache.tomcat.dbcp.pool.impl.GenericKeyedObjectPool Maven / Gradle / Ivy
/*
* 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.dbcp.pool.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TreeMap;
import java.util.TimerTask;
import java.util.Map.Entry;
import org.apache.tomcat.dbcp.pool.BaseKeyedObjectPool;
import org.apache.tomcat.dbcp.pool.KeyedObjectPool;
import org.apache.tomcat.dbcp.pool.KeyedPoolableObjectFactory;
import org.apache.tomcat.dbcp.pool.PoolUtils;
import org.apache.tomcat.dbcp.pool.PoolableObjectFactory;
/**
* A configurable KeyedObjectPool
implementation.
*
* When coupled with the appropriate {@link KeyedPoolableObjectFactory},
* GenericKeyedObjectPool
provides robust pooling functionality for
* keyed objects. A GenericKeyedObjectPool
can be viewed as a map
* of pools, keyed on the (unique) key values provided to the
* {@link #preparePool preparePool}, {@link #addObject addObject} or
* {@link #borrowObject borrowObject} methods. Each time a new key value is
* provided to one of these methods, a new pool is created under the given key
* to be managed by the containing GenericKeyedObjectPool.
*
* A GenericKeyedObjectPool
provides a number of configurable
* parameters:
*
* -
* {@link #setMaxActive maxActive} controls the maximum number of objects
* (per key) that can allocated by the pool (checked out to client threads,
* or idle in the pool) at one time. When non-positive, there is no limit
* to the number of objects per key. When {@link #setMaxActive maxActive} is
* reached, the keyed pool is said to be exhausted. The default setting for
* this parameter is 8.
*
* -
* {@link #setMaxTotal maxTotal} sets a global limit on the number of objects
* that can be in circulation (active or idle) within the combined set of
* pools. When non-positive, there is no limit to the total number of
* objects in circulation. When {@link #setMaxTotal maxTotal} is exceeded,
* all keyed pools are exhausted. When
maxTotal
is set to a
* positive value and {@link #borrowObject borrowObject} is invoked
* when at the limit with no idle instances available, an attempt is made to
* create room by clearing the oldest 15% of the elements from the keyed
* pools. The default setting for this parameter is -1 (no limit).
*
* -
* {@link #setMaxIdle maxIdle} controls the maximum number of objects that can
* sit idle in the pool (per key) at any time. When negative, there
* is no limit to the number of objects that may be idle per key. The
* default setting for this parameter is 8.
*
* -
* {@link #setWhenExhaustedAction whenExhaustedAction} specifies the
* behavior of the {@link #borrowObject borrowObject} method when a keyed
* pool is exhausted:
*
* -
* When {@link #setWhenExhaustedAction whenExhaustedAction} is
* {@link #WHEN_EXHAUSTED_FAIL}, {@link #borrowObject borrowObject} will throw
* a {@link NoSuchElementException}
*
* -
* When {@link #setWhenExhaustedAction whenExhaustedAction} is
* {@link #WHEN_EXHAUSTED_GROW}, {@link #borrowObject borrowObject} will create a new
* object and return it (essentially making {@link #setMaxActive maxActive}
* meaningless.)
*
* -
* When {@link #setWhenExhaustedAction whenExhaustedAction}
* is {@link #WHEN_EXHAUSTED_BLOCK}, {@link #borrowObject borrowObject} will block
* (invoke {@link Object#wait() wait} until a new or idle object is available.
* If a positive {@link #setMaxWait maxWait}
* value is supplied, the {@link #borrowObject borrowObject} will block for at
* most that many milliseconds, after which a {@link NoSuchElementException}
* will be thrown. If {@link #setMaxWait maxWait} is non-positive,
* the {@link #borrowObject borrowObject} method will block indefinitely.
*
*
* The default whenExhaustedAction
setting is
* {@link #WHEN_EXHAUSTED_BLOCK}.
*
* -
* When {@link #setTestOnBorrow testOnBorrow} is set, the pool will
* attempt to validate each object before it is returned from the
* {@link #borrowObject borrowObject} method. (Using the provided factory's
* {@link KeyedPoolableObjectFactory#validateObject validateObject} method.)
* Objects that fail to validate will be dropped from the pool, and a
* different object will be borrowed. The default setting for this parameter
* is
false.
*
* -
* When {@link #setTestOnReturn testOnReturn} is set, the pool will
* attempt to validate each object before it is returned to the pool in the
* {@link #returnObject returnObject} method. (Using the provided factory's
* {@link KeyedPoolableObjectFactory#validateObject validateObject}
* method.) Objects that fail to validate will be dropped from the pool.
* The default setting for this parameter is
false.
*
*
*
* Optionally, one may configure the pool to examine and possibly evict objects
* as they sit idle in the pool and to ensure that a minimum number of idle
* objects is maintained for each key. This is performed by an
* "idle object eviction" thread, which runs asynchronously. Caution should be
* used when configuring this optional feature. Eviction runs contend with client
* threads for access to objects in the pool, so if they run too frequently
* performance issues may result. The idle object eviction thread may be
* configured using the following attributes:
*
* -
* {@link #setTimeBetweenEvictionRunsMillis timeBetweenEvictionRunsMillis}
* indicates how long the eviction thread should sleep before "runs" of examining
* idle objects. When non-positive, no eviction thread will be launched. The
* default setting for this parameter is -1 (i.e., by default, idle object
* eviction is disabled).
*
* -
* {@link #setMinEvictableIdleTimeMillis minEvictableIdleTimeMillis}
* specifies the minimum amount of time that an object may sit idle in the
* pool before it is eligible for eviction due to idle time. When
* non-positive, no object will be dropped from the pool due to idle time
* alone. This setting has no effect unless
*
timeBetweenEvictionRunsMillis > 0.
The default setting
* for this parameter is 30 minutes.
*
* -
* {@link #setTestWhileIdle testWhileIdle} indicates whether or not idle
* objects should be validated using the factory's
* {@link KeyedPoolableObjectFactory#validateObject validateObject} method
* during idle object eviction runs. Objects that fail to validate will be
* dropped from the pool. This setting has no effect unless
*
timeBetweenEvictionRunsMillis > 0.
The default setting
* for this parameter is false.
*
* -
* {@link #setMinIdle minIdle} sets a target value for the minimum number of
* idle objects (per key) that should always be available. If this parameter
* is set to a positive number and
*
timeBetweenEvictionRunsMillis > 0,
each time the idle object
* eviction thread runs, it will try to create enough idle instances so that
* there will be minIdle
idle instances available under each
* key. This parameter is also used by {@link #preparePool preparePool}
* if true
is provided as that method's
* populateImmediately
parameter. The default setting for this
* parameter is 0.
*
*
*
* The pools can be configured to behave as LIFO queues with respect to idle
* objects - always returning the most recently used object from the pool,
* or as FIFO queues, where borrowObject always returns the oldest object
* in the idle object pool.
*
* -
* {@link #setLifo Lifo}
* determines whether or not the pools return idle objects in
* last-in-first-out order. The default setting for this parameter is
*
true.
*
*
*
* GenericKeyedObjectPool is not usable without a {@link KeyedPoolableObjectFactory}. A
* non-null
factory must be provided either as a constructor argument
* or via a call to {@link #setFactory setFactory} before the pool is used.
*
*
* Implementation note: To prevent possible deadlocks, care has been taken to
* ensure that no call to a factory method will occur within a synchronization
* block. See POOL-125 and DBCP-44 for more information.
*
* @see GenericObjectPool
* @author Rodney Waldhoff
* @author Dirk Verbeeck
* @author Sandy McArthur
* @version $Revision: 990683 $ $Date: 2010-08-29 21:40:36 -0400 (Sun, 29 Aug 2010) $
* @since Pool 1.0
*/
public class GenericKeyedObjectPool extends BaseKeyedObjectPool implements KeyedObjectPool {
//--- public constants -------------------------------------------
/**
* A "when exhausted action" type indicating that when the pool is
* exhausted (i.e., the maximum number of active objects has
* been reached), the {@link #borrowObject}
* method should fail, throwing a {@link NoSuchElementException}.
* @see #WHEN_EXHAUSTED_BLOCK
* @see #WHEN_EXHAUSTED_GROW
* @see #setWhenExhaustedAction
*/
public static final byte WHEN_EXHAUSTED_FAIL = 0;
/**
* A "when exhausted action" type indicating that when the pool
* is exhausted (i.e., the maximum number
* of active objects has been reached), the {@link #borrowObject}
* method should block until a new object is available, or the
* {@link #getMaxWait maximum wait time} has been reached.
* @see #WHEN_EXHAUSTED_FAIL
* @see #WHEN_EXHAUSTED_GROW
* @see #setMaxWait
* @see #getMaxWait
* @see #setWhenExhaustedAction
*/
public static final byte WHEN_EXHAUSTED_BLOCK = 1;
/**
* A "when exhausted action" type indicating that when the pool is
* exhausted (i.e., the maximum number
* of active objects has been reached), the {@link #borrowObject}
* method should simply create a new object anyway.
* @see #WHEN_EXHAUSTED_FAIL
* @see #WHEN_EXHAUSTED_GROW
* @see #setWhenExhaustedAction
*/
public static final byte WHEN_EXHAUSTED_GROW = 2;
/**
* The default cap on the number of idle instances (per key) in the pool.
* @see #getMaxIdle
* @see #setMaxIdle
*/
public static final int DEFAULT_MAX_IDLE = 8;
/**
* The default cap on the total number of active instances (per key)
* from the pool.
* @see #getMaxActive
* @see #setMaxActive
*/
public static final int DEFAULT_MAX_ACTIVE = 8;
/**
* The default cap on the the overall maximum number of objects that can
* exist at one time.
* @see #getMaxTotal
* @see #setMaxTotal
*/
public static final int DEFAULT_MAX_TOTAL = -1;
/**
* The default "when exhausted action" for the pool.
* @see #WHEN_EXHAUSTED_BLOCK
* @see #WHEN_EXHAUSTED_FAIL
* @see #WHEN_EXHAUSTED_GROW
* @see #setWhenExhaustedAction
*/
public static final byte DEFAULT_WHEN_EXHAUSTED_ACTION = WHEN_EXHAUSTED_BLOCK;
/**
* The default maximum amount of time (in milliseconds) the
* {@link #borrowObject} method should block before throwing
* an exception when the pool is exhausted and the
* {@link #getWhenExhaustedAction "when exhausted" action} is
* {@link #WHEN_EXHAUSTED_BLOCK}.
* @see #getMaxWait
* @see #setMaxWait
*/
public static final long DEFAULT_MAX_WAIT = -1L;
/**
* The default "test on borrow" value.
* @see #getTestOnBorrow
* @see #setTestOnBorrow
*/
public static final boolean DEFAULT_TEST_ON_BORROW = false;
/**
* The default "test on return" value.
* @see #getTestOnReturn
* @see #setTestOnReturn
*/
public static final boolean DEFAULT_TEST_ON_RETURN = false;
/**
* The default "test while idle" value.
* @see #getTestWhileIdle
* @see #setTestWhileIdle
* @see #getTimeBetweenEvictionRunsMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
public static final boolean DEFAULT_TEST_WHILE_IDLE = false;
/**
* The default "time between eviction runs" value.
* @see #getTimeBetweenEvictionRunsMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L;
/**
* The default number of objects to examine per run in the
* idle object evictor.
* @see #getNumTestsPerEvictionRun
* @see #setNumTestsPerEvictionRun
* @see #getTimeBetweenEvictionRunsMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
/**
* The default value for {@link #getMinEvictableIdleTimeMillis}.
* @see #getMinEvictableIdleTimeMillis
* @see #setMinEvictableIdleTimeMillis
*/
public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L;
/**
* The default minimum level of idle objects in the pool.
* @since Pool 1.3
* @see #setMinIdle
* @see #getMinIdle
*/
public static final int DEFAULT_MIN_IDLE = 0;
/**
* The default LIFO status. True means that borrowObject returns the
* most recently used ("last in") idle object in a pool (if there are
* idle instances available). False means that pools behave as FIFO
* queues - objects are taken from idle object pools in the order that
* they are returned.
* @see #setLifo
*/
public static final boolean DEFAULT_LIFO = true;
//--- constructors -----------------------------------------------
/**
* Create a new GenericKeyedObjectPool
with no factory.
*
* @see #GenericKeyedObjectPool(KeyedPoolableObjectFactory)
* @see #setFactory(KeyedPoolableObjectFactory)
*/
public GenericKeyedObjectPool() {
this(null, DEFAULT_MAX_ACTIVE, DEFAULT_WHEN_EXHAUSTED_ACTION, DEFAULT_MAX_WAIT, DEFAULT_MAX_IDLE,
DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
DEFAULT_NUM_TESTS_PER_EVICTION_RUN, DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericKeyedObjectPool
using the specified values.
* @param factory the KeyedPoolableObjectFactory
to use to create, validate, and destroy
* objects if not null
*/
public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory) {
this(factory, DEFAULT_MAX_ACTIVE, DEFAULT_WHEN_EXHAUSTED_ACTION, DEFAULT_MAX_WAIT, DEFAULT_MAX_IDLE,
DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
DEFAULT_NUM_TESTS_PER_EVICTION_RUN, DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericKeyedObjectPool
using the specified values.
* @param factory the KeyedPoolableObjectFactory
to use to create, validate, and destroy objects
* if not null
* @param config a non-null
{@link GenericKeyedObjectPool.Config} describing the configuration
*/
public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, GenericKeyedObjectPool.Config config) {
this(factory, config.maxActive, config.whenExhaustedAction, config.maxWait, config.maxIdle, config.maxTotal,
config.minIdle, config.testOnBorrow, config.testOnReturn, config.timeBetweenEvictionRunsMillis,
config.numTestsPerEvictionRun, config.minEvictableIdleTimeMillis, config.testWhileIdle, config.lifo);
}
/**
* Create a new GenericKeyedObjectPool
using the specified values.
* @param factory the KeyedPoolableObjectFactory
to use to create, validate, and destroy objects
* if not null
* @param maxActive the maximum number of objects that can be borrowed from me at one time (see {@link #setMaxActive})
*/
public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive) {
this(factory,maxActive, DEFAULT_WHEN_EXHAUSTED_ACTION, DEFAULT_MAX_WAIT, DEFAULT_MAX_IDLE,
DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
DEFAULT_NUM_TESTS_PER_EVICTION_RUN, DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericKeyedObjectPool
using the specified values.
* @param factory the KeyedPoolableObjectFactory
to use to create, validate, and destroy objects
* if not null
* @param maxActive the maximum number of objects that can be borrowed from me at one time (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction
is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
*/
public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction,
long maxWait) {
this(factory, maxActive, whenExhaustedAction, maxWait, DEFAULT_MAX_IDLE, DEFAULT_TEST_ON_BORROW,
DEFAULT_TEST_ON_RETURN, DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericKeyedObjectPool
using the specified values.
* @param factory the KeyedPoolableObjectFactory
to use to create, validate, and destroy objects
* if not null
* @param maxActive the maximum number of objects that can be borrowed from me at one time (see {@link #setMaxActive})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction
is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
* @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject}
* method (see {@link #setTestOnBorrow})
* @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject}
* method (see {@link #setTestOnReturn})
*/
public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction,
long maxWait, boolean testOnBorrow, boolean testOnReturn) {
this(factory, maxActive, whenExhaustedAction, maxWait, DEFAULT_MAX_IDLE,testOnBorrow,testOnReturn,
DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericKeyedObjectPool
using the specified values.
* @param factory the KeyedPoolableObjectFactory
to use to create, validate, and destroy objects
* if not null
* @param maxActive the maximum number of objects that can be borrowed from me at one time
* (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction
is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
* @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
*/
public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction,
long maxWait, int maxIdle) {
this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN,
DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericKeyedObjectPool
using the specified values.
* @param factory the KeyedPoolableObjectFactory
to use to create, validate, and destroy objects
* if not null
* @param maxActive the maximum number of objects that can be borrowed from me at one time
* (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction
is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait})
* @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
* @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject}
* method (see {@link #setTestOnBorrow})
* @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject}
* method (see {@link #setTestOnReturn})
*/
public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction,
long maxWait, int maxIdle, boolean testOnBorrow, boolean testOnReturn) {
this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, testOnBorrow, testOnReturn,
DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, DEFAULT_TEST_WHILE_IDLE);
}
/**
* Create a new GenericKeyedObjectPool
using the specified values.
* @param factory the KeyedPoolableObjectFactory
to use to create, validate, and destroy objects
* if not null
* @param maxActive the maximum number of objects that can be borrowed from me at one time
* (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted
* (see {@link #setWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction
is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
* @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
* @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject}
* method (see {@link #setTestOnBorrow})
* @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject}
* method (see {@link #setTestOnReturn})
* @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle
* objects for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
* @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction
* thread (if any) (see {@link #setNumTestsPerEvictionRun})
* @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before
* it is eligible for eviction (see {@link #setMinEvictableIdleTimeMillis})
* @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any
* (see {@link #setTestWhileIdle})
*/
public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction,
long maxWait, int maxIdle, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis,
int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) {
this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, GenericKeyedObjectPool.DEFAULT_MAX_TOTAL,
testOnBorrow, testOnReturn, timeBetweenEvictionRunsMillis, numTestsPerEvictionRun,
minEvictableIdleTimeMillis, testWhileIdle);
}
/**
* Create a new GenericKeyedObjectPool
using the specified values.
* @param factory the KeyedPoolableObjectFactory
to use to create, validate, and destroy objects
* if not null
* @param maxActive the maximum number of objects that can be borrowed from me at one time
* (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction
is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
* @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
* @param maxTotal the maximum number of objects that can exists at one time (see {@link #setMaxTotal})
* @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject}
* method (see {@link #setTestOnBorrow})
* @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject}
* method (see {@link #setTestOnReturn})
* @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle
* objects for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
* @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction
* thread (if any) (see {@link #setNumTestsPerEvictionRun})
* @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool
* before it is eligible for eviction (see {@link #setMinEvictableIdleTimeMillis})
* @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any
* (see {@link #setTestWhileIdle})
*/
public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction,
long maxWait, int maxIdle, int maxTotal, boolean testOnBorrow, boolean testOnReturn,
long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long minEvictableIdleTimeMillis,
boolean testWhileIdle) {
this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, maxTotal,
GenericKeyedObjectPool.DEFAULT_MIN_IDLE, testOnBorrow, testOnReturn, timeBetweenEvictionRunsMillis,
numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle);
}
/**
* Create a new GenericKeyedObjectPool
using the specified values.
* @param factory the KeyedPoolableObjectFactory
to use to create, validate, and destroy objects
* if not null
* @param maxActive the maximum number of objects that can be borrowed at one time (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction
is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
* @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
* @param maxTotal the maximum number of objects that can exists at one time (see {@link #setMaxTotal})
* @param minIdle the minimum number of idle objects to have in the pool at any one time (see {@link #setMinIdle})
* @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject}
* method (see {@link #setTestOnBorrow})
* @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject}
* method (see {@link #setTestOnReturn})
* @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle
* objects
* for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
* @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction
* thread (if any) (see {@link #setNumTestsPerEvictionRun})
* @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before
* it is eligible for eviction (see {@link #setMinEvictableIdleTimeMillis})
* @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any
* (see {@link #setTestWhileIdle})
* @since Pool 1.3
*/
public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction,
long maxWait, int maxIdle, int maxTotal, int minIdle, boolean testOnBorrow, boolean testOnReturn,
long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long minEvictableIdleTimeMillis,
boolean testWhileIdle) {
this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, maxTotal, minIdle, testOnBorrow, testOnReturn,
timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle,
DEFAULT_LIFO);
}
/**
* Create a new GenericKeyedObjectPool
using the specified values.
* @param factory the KeyedPoolableObjectFactory
to use to create, validate, and destroy objects
* if not null
* @param maxActive the maximum number of objects that can be borrowed at one time
* (see {@link #setMaxActive})
* @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
* @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted and
* whenExhaustedAction
is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
* @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
* @param maxTotal the maximum number of objects that can exists at one time (see {@link #setMaxTotal})
* @param minIdle the minimum number of idle objects to have in the pool at any one time (see {@link #setMinIdle})
* @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject}
* method (see {@link #setTestOnBorrow})
* @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject}
* method (see {@link #setTestOnReturn})
* @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle
* objects for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
* @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction
* thread (if any) (see {@link #setNumTestsPerEvictionRun})
* @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before
* it is eligible for eviction (see {@link #setMinEvictableIdleTimeMillis})
* @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any
* (see {@link #setTestWhileIdle})
* @param lifo whether or not the pools behave as LIFO (last in first out) queues (see {@link #setLifo})
* @since Pool 1.4
*/
public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction,
long maxWait, int maxIdle, int maxTotal, int minIdle, boolean testOnBorrow, boolean testOnReturn,
long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long minEvictableIdleTimeMillis,
boolean testWhileIdle, boolean lifo) {
_factory = factory;
_maxActive = maxActive;
_lifo = lifo;
switch (whenExhaustedAction) {
case WHEN_EXHAUSTED_BLOCK:
case WHEN_EXHAUSTED_FAIL:
case WHEN_EXHAUSTED_GROW:
_whenExhaustedAction = whenExhaustedAction;
break;
default:
throw new IllegalArgumentException("whenExhaustedAction " + whenExhaustedAction + " not recognized.");
}
_maxWait = maxWait;
_maxIdle = maxIdle;
_maxTotal = maxTotal;
_minIdle = minIdle;
_testOnBorrow = testOnBorrow;
_testOnReturn = testOnReturn;
_timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
_numTestsPerEvictionRun = numTestsPerEvictionRun;
_minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
_testWhileIdle = testWhileIdle;
_poolMap = new HashMap();
_poolList = new CursorableLinkedList();
startEvictor(_timeBetweenEvictionRunsMillis);
}
//--- public methods ---------------------------------------------
//--- configuration methods --------------------------------------
/**
* Returns the cap on the number of object instances allocated by the pool
* (checked out or idle), per key.
* A negative value indicates no limit.
*
* @return the cap on the number of active instances per key.
* @see #setMaxActive
*/
public synchronized int getMaxActive() {
return _maxActive;
}
/**
* Sets the cap on the number of object instances managed by the pool per key.
* @param maxActive The cap on the number of object instances per key.
* Use a negative value for no limit.
*
* @see #getMaxActive
*/
public synchronized void setMaxActive(int maxActive) {
_maxActive = maxActive;
allocate();
}
/**
* Returns the overall maximum number of objects (across pools) that can
* exist at one time. A negative value indicates no limit.
* @return the maximum number of instances in circulation at one time.
* @see #setMaxTotal
*/
public synchronized int getMaxTotal() {
return _maxTotal;
}
/**
* Sets the cap on the total number of instances from all pools combined.
* When maxTotal
is set to a
* positive value and {@link #borrowObject borrowObject} is invoked
* when at the limit with no idle instances available, an attempt is made to
* create room by clearing the oldest 15% of the elements from the keyed
* pools.
*
* @param maxTotal The cap on the total number of instances across pools.
* Use a negative value for no limit.
* @see #getMaxTotal
*/
public synchronized void setMaxTotal(int maxTotal) {
_maxTotal = maxTotal;
allocate();
}
/**
* Returns the action to take when the {@link #borrowObject} method
* is invoked when the pool is exhausted (the maximum number
* of "active" objects has been reached).
*
* @return one of {@link #WHEN_EXHAUSTED_BLOCK},
* {@link #WHEN_EXHAUSTED_FAIL} or {@link #WHEN_EXHAUSTED_GROW}
* @see #setWhenExhaustedAction
*/
public synchronized byte getWhenExhaustedAction() {
return _whenExhaustedAction;
}
/**
* Sets the action to take when the {@link #borrowObject} method
* is invoked when the pool is exhausted (the maximum number
* of "active" objects has been reached).
*
* @param whenExhaustedAction the action code, which must be one of
* {@link #WHEN_EXHAUSTED_BLOCK}, {@link #WHEN_EXHAUSTED_FAIL},
* or {@link #WHEN_EXHAUSTED_GROW}
* @see #getWhenExhaustedAction
*/
public synchronized void setWhenExhaustedAction(byte whenExhaustedAction) {
switch(whenExhaustedAction) {
case WHEN_EXHAUSTED_BLOCK:
case WHEN_EXHAUSTED_FAIL:
case WHEN_EXHAUSTED_GROW:
_whenExhaustedAction = whenExhaustedAction;
allocate();
break;
default:
throw new IllegalArgumentException("whenExhaustedAction " + whenExhaustedAction + " not recognized.");
}
}
/**
* Returns the maximum amount of time (in milliseconds) the
* {@link #borrowObject} method should block before throwing
* an exception when the pool is exhausted and the
* {@link #setWhenExhaustedAction "when exhausted" action} is
* {@link #WHEN_EXHAUSTED_BLOCK}.
*
* When less than or equal to 0, the {@link #borrowObject} method
* may block indefinitely.
*
* @return the maximum number of milliseconds borrowObject will block.
* @see #setMaxWait
* @see #setWhenExhaustedAction
* @see #WHEN_EXHAUSTED_BLOCK
*/
public synchronized long getMaxWait() {
return _maxWait;
}
/**
* Sets the maximum amount of time (in milliseconds) the
* {@link #borrowObject} method should block before throwing
* an exception when the pool is exhausted and the
* {@link #setWhenExhaustedAction "when exhausted" action} is
* {@link #WHEN_EXHAUSTED_BLOCK}.
*
* When less than or equal to 0, the {@link #borrowObject} method
* may block indefinitely.
*
* @param maxWait the maximum number of milliseconds borrowObject will block or negative for indefinitely.
* @see #getMaxWait
* @see #setWhenExhaustedAction
* @see #WHEN_EXHAUSTED_BLOCK
*/
public synchronized void setMaxWait(long maxWait) {
_maxWait = maxWait;
}
/**
* Returns the cap on the number of "idle" instances per key.
* @return the maximum number of "idle" instances that can be held
* in a given keyed pool.
* @see #setMaxIdle
*/
public synchronized int getMaxIdle() {
return _maxIdle;
}
/**
* Sets the cap on the number of "idle" instances in the pool.
* If maxIdle is set too low on heavily loaded systems it is possible you
* will see objects being destroyed and almost immediately new objects
* being created. This is a result of the active threads momentarily
* returning objects faster than they are requesting them them, causing the
* number of idle objects to rise above maxIdle. The best value for maxIdle
* for heavily loaded system will vary but the default is a good starting
* point.
* @param maxIdle the maximum number of "idle" instances that can be held
* in a given keyed pool. Use a negative value for no limit.
* @see #getMaxIdle
* @see #DEFAULT_MAX_IDLE
*/
public synchronized void setMaxIdle(int maxIdle) {
_maxIdle = maxIdle;
allocate();
}
/**
* Sets the minimum number of idle objects to maintain in each of the keyed
* pools. This setting has no effect unless
* timeBetweenEvictionRunsMillis > 0
and attempts to ensure
* that each pool has the required minimum number of instances are only
* made during idle object eviction runs.
* @param poolSize - The minimum size of the each keyed pool
* @since Pool 1.3
* @see #getMinIdle
* @see #setTimeBetweenEvictionRunsMillis
*/
public void setMinIdle(int poolSize) {
_minIdle = poolSize;
}
/**
* Returns the minimum number of idle objects to maintain in each of the keyed
* pools. This setting has no effect unless
* timeBetweenEvictionRunsMillis > 0
and attempts to ensure
* that each pool has the required minimum number of instances are only
* made during idle object eviction runs.
* @return minimum size of the each keyed pool
* @since Pool 1.3
* @see #setTimeBetweenEvictionRunsMillis
*/
public int getMinIdle() {
return _minIdle;
}
/**
* When true
, objects will be
* {@link org.apache.tomcat.dbcp.pool.PoolableObjectFactory#validateObject validated}
* before being returned by the {@link #borrowObject}
* method. If the object fails to validate,
* it will be dropped from the pool, and we will attempt
* to borrow another.
*
* @return true
if objects are validated before being borrowed.
* @see #setTestOnBorrow
*/
public boolean getTestOnBorrow() {
return _testOnBorrow;
}
/**
* When true
, objects will be
* {@link org.apache.tomcat.dbcp.pool.PoolableObjectFactory#validateObject validated}
* before being returned by the {@link #borrowObject}
* method. If the object fails to validate,
* it will be dropped from the pool, and we will attempt
* to borrow another.
*
* @param testOnBorrow whether object should be validated before being returned by borrowObject.
* @see #getTestOnBorrow
*/
public void setTestOnBorrow(boolean testOnBorrow) {
_testOnBorrow = testOnBorrow;
}
/**
* When true
, objects will be
* {@link org.apache.tomcat.dbcp.pool.PoolableObjectFactory#validateObject validated}
* before being returned to the pool within the
* {@link #returnObject}.
*
* @return true
when objects will be validated before being returned.
* @see #setTestOnReturn
*/
public boolean getTestOnReturn() {
return _testOnReturn;
}
/**
* When true
, objects will be
* {@link org.apache.tomcat.dbcp.pool.PoolableObjectFactory#validateObject validated}
* before being returned to the pool within the
* {@link #returnObject}.
*
* @param testOnReturn true
so objects will be validated before being returned.
* @see #getTestOnReturn
*/
public void setTestOnReturn(boolean testOnReturn) {
_testOnReturn = testOnReturn;
}
/**
* Returns the number of milliseconds to sleep between runs of the
* idle object evictor thread.
* When non-positive, no idle object evictor thread will be
* run.
*
* @return milliseconds to sleep between evictor runs.
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized long getTimeBetweenEvictionRunsMillis() {
return _timeBetweenEvictionRunsMillis;
}
/**
* Sets the number of milliseconds to sleep between runs of the
* idle object evictor thread.
* When non-positive, no idle object evictor thread will be
* run.
*
* @param timeBetweenEvictionRunsMillis milliseconds to sleep between evictor runs.
* @see #getTimeBetweenEvictionRunsMillis
*/
public synchronized void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
_timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
startEvictor(_timeBetweenEvictionRunsMillis);
}
/**
* Returns the max number of objects to examine during each run of the
* idle object evictor thread (if any).
*
* @return number of objects to examine each eviction run.
* @see #setNumTestsPerEvictionRun
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized int getNumTestsPerEvictionRun() {
return _numTestsPerEvictionRun;
}
/**
* Sets the max number of objects to examine during each run of the
* idle object evictor thread (if any).
*
* When a negative value is supplied,
* ceil({@link #getNumIdle()})/abs({@link #getNumTestsPerEvictionRun})
* tests will be run. I.e., when the value is -n
, roughly one n
th of the
* idle objects will be tested per run. When the value is positive, the number of tests
* actually performed in each run will be the minimum of this value and the number of instances
* idle in the pools.
*
* @param numTestsPerEvictionRun number of objects to examine each eviction run.
* @see #setNumTestsPerEvictionRun
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
_numTestsPerEvictionRun = numTestsPerEvictionRun;
}
/**
* Returns the minimum amount of time an object may sit idle in the pool
* before it is eligible for eviction by the idle object evictor
* (if any).
*
* @return minimum amount of time an object may sit idle in the pool before it is eligible for eviction.
* @see #setMinEvictableIdleTimeMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized long getMinEvictableIdleTimeMillis() {
return _minEvictableIdleTimeMillis;
}
/**
* Sets the minimum amount of time an object may sit idle in the pool
* before it is eligible for eviction by the idle object evictor
* (if any).
* When non-positive, no objects will be evicted from the pool
* due to idle time alone.
*
* @param minEvictableIdleTimeMillis minimum amount of time an object may sit idle in the pool before
* it is eligible for eviction.
* @see #getMinEvictableIdleTimeMillis
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
_minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}
/**
* When true
, objects will be
* {@link org.apache.tomcat.dbcp.pool.PoolableObjectFactory#validateObject validated}
* by the idle object evictor (if any). If an object
* fails to validate, it will be dropped from the pool.
*
* @return true
when objects are validated when borrowed.
* @see #setTestWhileIdle
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized boolean getTestWhileIdle() {
return _testWhileIdle;
}
/**
* When true
, objects will be
* {@link org.apache.tomcat.dbcp.pool.PoolableObjectFactory#validateObject validated}
* by the idle object evictor (if any). If an object
* fails to validate, it will be dropped from the pool.
*
* @param testWhileIdle true
so objects are validated when borrowed.
* @see #getTestWhileIdle
* @see #setTimeBetweenEvictionRunsMillis
*/
public synchronized void setTestWhileIdle(boolean testWhileIdle) {
_testWhileIdle = testWhileIdle;
}
/**
* Sets the configuration.
* @param conf the new configuration to use.
* @see GenericKeyedObjectPool.Config
*/
public synchronized void setConfig(GenericKeyedObjectPool.Config conf) {
setMaxIdle(conf.maxIdle);
setMaxActive(conf.maxActive);
setMaxTotal(conf.maxTotal);
setMinIdle(conf.minIdle);
setMaxWait(conf.maxWait);
setWhenExhaustedAction(conf.whenExhaustedAction);
setTestOnBorrow(conf.testOnBorrow);
setTestOnReturn(conf.testOnReturn);
setTestWhileIdle(conf.testWhileIdle);
setNumTestsPerEvictionRun(conf.numTestsPerEvictionRun);
setMinEvictableIdleTimeMillis(conf.minEvictableIdleTimeMillis);
setTimeBetweenEvictionRunsMillis(conf.timeBetweenEvictionRunsMillis);
}
/**
* Whether or not the idle object pools act as LIFO queues. True means
* that borrowObject returns the most recently used ("last in") idle object
* in a pool (if there are idle instances available). False means that
* the pools behave as FIFO queues - objects are taken from idle object
* pools in the order that they are returned.
*
* @return true
if the pools are configured to act as LIFO queues
* @since 1.4
*/
public synchronized boolean getLifo() {
return _lifo;
}
/**
* Sets the LIFO property of the pools. True means that borrowObject returns
* the most recently used ("last in") idle object in a pool (if there are
* idle instances available). False means that the pools behave as FIFO
* queues - objects are taken from idle object pools in the order that
* they are returned.
*
* @param lifo the new value for the lifo property
* @since 1.4
*/
public synchronized void setLifo(boolean lifo) {
this._lifo = lifo;
}
//-- ObjectPool methods ------------------------------------------
/**
*
Borrows an object from the keyed pool associated with the given key.
*
* If there is an idle instance available in the pool associated with the given key, then
* either the most-recently returned (if {@link #getLifo() lifo} == true) or "oldest" (lifo == false)
* instance sitting idle in the pool will be activated and returned. If activation fails, or
* {@link #getTestOnBorrow() testOnBorrow} is set to true and validation fails, the instance is destroyed and the
* next available instance is examined. This continues until either a valid instance is returned or there
* are no more idle instances available.
*
* If there are no idle instances available in the pool associated with the given key, behavior
* depends on the {@link #getMaxActive() maxActive}, {@link #getMaxTotal() maxTotal}, and (if applicable)
* {@link #getWhenExhaustedAction() whenExhaustedAction} and {@link #getMaxWait() maxWait} properties. If the
* number of instances checked out from the pool under the given key is less than maxActive
and
* the total number of instances in circulation (under all keys) is less than maxTotal
, a new instance
* is created, activated and (if applicable) validated and returned to the caller.
*
* If the associated keyed pool is exhausted (no available idle instances and no capacity to create new ones),
* this method will either block ({@link #WHEN_EXHAUSTED_BLOCK}), throw a NoSuchElementException
* ({@link #WHEN_EXHAUSTED_FAIL}), or grow ({@link #WHEN_EXHAUSTED_GROW} - ignoring maxActive, maxTotal properties).
* The length of time that this method will block when whenExhaustedAction == WHEN_EXHAUSTED_BLOCK
* is determined by the {@link #getMaxWait() maxWait} property.
*
* When the pool is exhausted, multiple calling threads may be simultaneously blocked waiting for instances
* to become available. As of pool 1.5, a "fairness" algorithm has been implemented to ensure that threads receive
* available instances in request arrival order.
*
* @param key pool key
* @return object instance from the keyed pool
* @throws NoSuchElementException if a keyed object instance cannot be returned.
*/
public Object borrowObject(Object key) throws Exception {
long starttime = System.currentTimeMillis();
Latch latch = new Latch(key);
byte whenExhaustedAction;
long maxWait;
synchronized (this) {
// Get local copy of current config. Can't sync when used later as
// it can result in a deadlock. Has the added advantage that config
// is consistent for entire method execution
whenExhaustedAction = _whenExhaustedAction;
maxWait = _maxWait;
// Add this request to the queue
_allocationQueue.add(latch);
// Work the allocation queue, allocating idle instances and
// instance creation permits in request arrival order
allocate();
}
for(;;) {
synchronized (this) {
assertOpen();
}
// If no object was allocated
if (null == latch.getPair()) {
// Check to see if we were allowed to create one
if (latch.mayCreate()) {
// allow new object to be created
} else {
// the pool is exhausted
switch(whenExhaustedAction) {
case WHEN_EXHAUSTED_GROW:
// allow new object to be created
synchronized (this) {
// Make sure another thread didn't allocate us an object
// or permit a new object to be created
if (latch.getPair() == null && !latch.mayCreate()) {
_allocationQueue.remove(latch);
latch.getPool().incrementInternalProcessingCount();
}
}
break;
case WHEN_EXHAUSTED_FAIL:
synchronized (this) {
// Make sure allocate hasn't already assigned an object
// in a different thread or permitted a new object to be created
if (latch.getPair() != null || latch.mayCreate()) {
break;
}
_allocationQueue.remove(latch);
}
throw new NoSuchElementException("Pool exhausted");
case WHEN_EXHAUSTED_BLOCK:
try {
synchronized (latch) {
// Before we wait, make sure another thread didn't allocate us an object
// or permit a new object to be created
if (latch.getPair() == null && !latch.mayCreate()) {
if (maxWait <= 0) {
latch.wait();
} else {
// this code may be executed again after a notify then continue cycle
// so, need to calculate the amount of time to wait
final long elapsed = (System.currentTimeMillis() - starttime);
final long waitTime = maxWait - elapsed;
if (waitTime > 0)
{
latch.wait(waitTime);
}
}
} else {
break;
}
}
} catch(InterruptedException e) {
synchronized (this) {
// Make sure allocate hasn't already assigned an object
// in a different thread or permitted a new object to be created
if (latch.getPair() == null && !latch.mayCreate()) {
_allocationQueue.remove(latch);
} else {
break;
}
}
Thread.currentThread().interrupt();
throw e;
}
if (maxWait > 0 && ((System.currentTimeMillis() - starttime) >= maxWait)) {
synchronized (this) {
// Make sure allocate hasn't already assigned an object
// in a different thread or permitted a new object to be created
if (latch.getPair() == null && !latch.mayCreate()) {
_allocationQueue.remove(latch);
} else {
break;
}
}
throw new NoSuchElementException("Timeout waiting for idle object");
} else {
continue; // keep looping
}
default:
throw new IllegalArgumentException("whenExhaustedAction " + whenExhaustedAction +
" not recognized.");
}
}
}
boolean newlyCreated = false;
if (null == latch.getPair()) {
try {
Object obj = _factory.makeObject(key);
latch.setPair(new ObjectTimestampPair(obj));
newlyCreated = true;
} finally {
if (!newlyCreated) {
// object cannot be created
synchronized (this) {
latch.getPool().decrementInternalProcessingCount();
// No need to reset latch - about to throw exception
allocate();
}
}
}
}
// activate & validate the object
try {
_factory.activateObject(key, latch.getPair().value);
if (_testOnBorrow && !_factory.validateObject(key, latch.getPair().value)) {
throw new Exception("ValidateObject failed");
}
synchronized (this) {
latch.getPool().decrementInternalProcessingCount();
latch.getPool().incrementActiveCount();
}
return latch.getPair().value;
} catch (Throwable e) {
PoolUtils.checkRethrow(e);
// object cannot be activated or is invalid
try {
_factory.destroyObject(key, latch.getPair().value);
} catch (Throwable e2) {
PoolUtils.checkRethrow(e2);
// cannot destroy broken object
}
synchronized (this) {
latch.getPool().decrementInternalProcessingCount();
if (!newlyCreated) {
latch.reset();
_allocationQueue.add(0, latch);
}
allocate();
}
if (newlyCreated) {
throw new NoSuchElementException(
"Could not create a validated object, cause: " +
e.getMessage());
}
else {
continue; // keep looping
}
}
}
}
/**
* Allocate available instances to latches in the allocation queue. Then
* set _mayCreate to true for as many additional latches remaining in queue
* as _maxActive allows for each key.
*/
private void allocate() {
boolean clearOldest = false;
synchronized (this) {
if (isClosed()) return;
Iterator allocationQueueIter = _allocationQueue.iterator();
while (allocationQueueIter.hasNext()) {
// First use any objects in the pool to clear the queue
Latch latch = (Latch) allocationQueueIter.next();
ObjectQueue pool = (ObjectQueue)(_poolMap.get(latch.getkey()));
if (null == pool) {
pool = new ObjectQueue();
_poolMap.put(latch.getkey(), pool);
_poolList.add(latch.getkey());
}
latch.setPool(pool);
if (!pool.queue.isEmpty()) {
allocationQueueIter.remove();
latch.setPair(
(ObjectTimestampPair) pool.queue.removeFirst());
pool.incrementInternalProcessingCount();
_totalIdle--;
synchronized (latch) {
latch.notify();
}
// Next item in queue
continue;
}
// If there is a totalMaxActive and we are at the limit then
// we have to make room
if ((_maxTotal > 0) &&
(_totalActive + _totalIdle + _totalInternalProcessing >= _maxTotal)) {
clearOldest = true;
break;
}
// Second utilise any spare capacity to create new objects
if ((_maxActive < 0 || pool.activeCount + pool.internalProcessingCount < _maxActive) &&
(_maxTotal < 0 || _totalActive + _totalIdle + _totalInternalProcessing < _maxTotal)) {
// allow new object to be created
allocationQueueIter.remove();
latch.setMayCreate(true);
pool.incrementInternalProcessingCount();
synchronized (latch) {
latch.notify();
}
// Next item in queue
continue;
}
// If there is no per-key limit and we reach this point we
// must have allocated all the objects we possibly can and there
// is no point looking at the rest of the allocation queue
if (_maxActive < 0) {
break;
}
}
}
if (clearOldest) {
/* Clear oldest calls factory methods so it must be called from
* outside the sync block.
* It also needs to be outside the sync block as it calls
* allocate(). If called inside the sync block, the call to
* allocate() would be able to enter the sync block (since the
* thread already has the lock) which may have unexpected,
* unpleasant results.
*/
clearOldest();
}
}
/**
* Clears any objects sitting idle in the pool by removing them from the
* idle instance pool and then invoking the configured PoolableObjectFactory's
* {@link KeyedPoolableObjectFactory#destroyObject(Object, Object)} method on
* each idle instance.
*
* Implementation notes:
*
- This method does not destroy or effect in any way instances that are
* checked out when it is invoked.
* - Invoking this method does not prevent objects being
* returned to the idle instance pool, even during its execution. It locks
* the pool only during instance removal. Additional instances may be returned
* while removed items are being destroyed.
* - Exceptions encountered destroying idle instances are swallowed.
*/
public void clear() {
Map toDestroy = new HashMap();
synchronized (this) {
for (Iterator it = _poolMap.keySet().iterator(); it.hasNext();) {
Object key = it.next();
ObjectQueue pool = (ObjectQueue)_poolMap.get(key);
// Copy objects to new list so pool.queue can be cleared inside
// the sync
List objects = new ArrayList();
objects.addAll(pool.queue);
toDestroy.put(key, objects);
it.remove();
_poolList.remove(key);
_totalIdle = _totalIdle - pool.queue.size();
_totalInternalProcessing =
_totalInternalProcessing + pool.queue.size();
pool.queue.clear();
}
}
destroy(toDestroy, _factory);
}
/**
* Clears oldest 15% of objects in pool. The method sorts the
* objects into a TreeMap and then iterates the first 15% for removal.
*
* @since Pool 1.3
*/
public void clearOldest() {
// Map of objects to destroy my key
final Map toDestroy = new HashMap();
// build sorted map of idle objects
final Map map = new TreeMap();
synchronized (this) {
for (Iterator keyiter = _poolMap.keySet().iterator(); keyiter.hasNext();) {
final Object key = keyiter.next();
final CursorableLinkedList list = ((ObjectQueue)_poolMap.get(key)).queue;
for (Iterator it = list.iterator(); it.hasNext();) {
// each item into the map uses the objectimestamppair object
// as the key. It then gets sorted based on the timstamp field
// each value in the map is the parent list it belongs in.
map.put(it.next(), key);
}
}
// Now iterate created map and kill the first 15% plus one to account for zero
Set setPairKeys = map.entrySet();
int itemsToRemove = ((int) (map.size() * 0.15)) + 1;
Iterator iter = setPairKeys.iterator();
while (iter.hasNext() && itemsToRemove > 0) {
Map.Entry entry = (Map.Entry) iter.next();
// kind of backwards on naming. In the map, each key is the objecttimestamppair
// because it has the ordering with the timestamp value. Each value that the
// key references is the key of the list it belongs to.
Object key = entry.getValue();
ObjectTimestampPair pairTimeStamp = (ObjectTimestampPair) entry.getKey();
final CursorableLinkedList list =
((ObjectQueue)(_poolMap.get(key))).queue;
list.remove(pairTimeStamp);
if (toDestroy.containsKey(key)) {
((List)toDestroy.get(key)).add(pairTimeStamp);
} else {
List listForKey = new ArrayList();
listForKey.add(pairTimeStamp);
toDestroy.put(key, listForKey);
}
// if that was the last object for that key, drop that pool
if (list.isEmpty()) {
_poolMap.remove(key);
_poolList.remove(key);
}
_totalIdle--;
_totalInternalProcessing++;
itemsToRemove--;
}
}
destroy(toDestroy, _factory);
}
/**
* Clears the specified pool, removing all pooled instances corresponding to the given key
.
*
* @param key the key to clear
*/
public void clear(Object key) {
Map toDestroy = new HashMap();
final ObjectQueue pool;
synchronized (this) {
pool = (ObjectQueue)(_poolMap.remove(key));
if (pool == null) {
return;
} else {
_poolList.remove(key);
}
// Copy objects to new list so pool.queue can be cleared inside
// the sync
List objects = new ArrayList();
objects.addAll(pool.queue);
toDestroy.put(key, objects);
_totalIdle = _totalIdle - pool.queue.size();
_totalInternalProcessing =
_totalInternalProcessing + pool.queue.size();
pool.queue.clear();
}
destroy(toDestroy, _factory);
}
/**
* Assuming Map