Skip to content

Commit

Permalink
Update internal fork of Apache Commons Pool 2
Browse files Browse the repository at this point in the history
  • Loading branch information
markt-asf committed May 3, 2019
1 parent dacb2b6 commit d676a1e
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 60 deletions.
2 changes: 1 addition & 1 deletion MERGE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,4 @@ Pool2
Sub-tree
src/main/java/org/apache/commons/pool2
The SHA1 ID for the most recent commit to be merged to Tomcat is:
d4e0e88227ad91d8c8ef36ba01d656f71c770f83
0664f4dac9ef653703624cbe67272134cf0151cb (2019-04-30)
47 changes: 27 additions & 20 deletions java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@
*/
public final class PoolUtils {

private static final String MSG_FACTOR_NEGATIVE = "factor must be positive.";
private static final String MSG_MIN_IDLE = "minIdle must be non-negative.";
private static final String MSG_NULL_KEY = "key must not be null.";
private static final String MSG_NULL_KEYED_POOL = "keyedPool must not be null.";
private static final String MSG_NULL_KEYS = "keys must not be null.";
private static final String MSG_NULL_POOL = "pool must not be null.";

/**
* Timer used to periodically check pools idle object count. Because a
* {@link Timer} creates a {@link Thread}, an IODH is used.
Expand Down Expand Up @@ -101,10 +108,10 @@ public static <T> TimerTask checkMinIdle(final ObjectPool<T> pool,
final int minIdle, final long period)
throws IllegalArgumentException {
if (pool == null) {
throw new IllegalArgumentException("keyedPool must not be null.");
throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
}
if (minIdle < 0) {
throw new IllegalArgumentException("minIdle must be non-negative.");
throw new IllegalArgumentException(MSG_MIN_IDLE);
}
final TimerTask task = new ObjectPoolMinIdleTimerTask<>(pool, minIdle);
getMinIdleTimer().schedule(task, 0L, period);
Expand Down Expand Up @@ -142,13 +149,13 @@ public static <K, V> TimerTask checkMinIdle(
final int minIdle, final long period)
throws IllegalArgumentException {
if (keyedPool == null) {
throw new IllegalArgumentException("keyedPool must not be null.");
throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
}
if (key == null) {
throw new IllegalArgumentException("key must not be null.");
throw new IllegalArgumentException(MSG_NULL_KEY);
}
if (minIdle < 0) {
throw new IllegalArgumentException("minIdle must be non-negative.");
throw new IllegalArgumentException(MSG_MIN_IDLE);
}
final TimerTask task = new KeyedObjectPoolMinIdleTimerTask<>(
keyedPool, key, minIdle);
Expand Down Expand Up @@ -188,7 +195,7 @@ public static <K, V> Map<K, TimerTask> checkMinIdle(
final int minIdle, final long period)
throws IllegalArgumentException {
if (keys == null) {
throw new IllegalArgumentException("keys must not be null.");
throw new IllegalArgumentException(MSG_NULL_KEYS);
}
final Map<K, TimerTask> tasks = new HashMap<>(keys.size());
final Iterator<K> iter = keys.iterator();
Expand Down Expand Up @@ -217,7 +224,7 @@ public static <K, V> Map<K, TimerTask> checkMinIdle(
public static <T> void prefill(final ObjectPool<T> pool, final int count)
throws Exception, IllegalArgumentException {
if (pool == null) {
throw new IllegalArgumentException("pool must not be null.");
throw new IllegalArgumentException(MSG_NULL_POOL);
}
for (int i = 0; i < count; i++) {
pool.addObject();
Expand Down Expand Up @@ -246,10 +253,10 @@ public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
final K key, final int count) throws Exception,
IllegalArgumentException {
if (keyedPool == null) {
throw new IllegalArgumentException("keyedPool must not be null.");
throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
}
if (key == null) {
throw new IllegalArgumentException("key must not be null.");
throw new IllegalArgumentException(MSG_NULL_KEY);
}
for (int i = 0; i < count; i++) {
keyedPool.addObject(key);
Expand Down Expand Up @@ -281,7 +288,7 @@ public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
final Collection<K> keys, final int count) throws Exception,
IllegalArgumentException {
if (keys == null) {
throw new IllegalArgumentException("keys must not be null.");
throw new IllegalArgumentException(MSG_NULL_KEYS);
}
final Iterator<K> iter = keys.iterator();
while (iter.hasNext()) {
Expand All @@ -308,7 +315,7 @@ public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
*/
public static <T> ObjectPool<T> synchronizedPool(final ObjectPool<T> pool) {
if (pool == null) {
throw new IllegalArgumentException("pool must not be null.");
throw new IllegalArgumentException(MSG_NULL_POOL);
}
/*
* assert !(pool instanceof GenericObjectPool) :
Expand Down Expand Up @@ -436,10 +443,10 @@ public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool) {
public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool,
final float factor) {
if (pool == null) {
throw new IllegalArgumentException("pool must not be null.");
throw new IllegalArgumentException(MSG_NULL_POOL);
}
if (factor <= 0f) {
throw new IllegalArgumentException("factor must be positive.");
throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE);
}
return new ErodingObjectPool<>(pool, factor);
}
Expand Down Expand Up @@ -538,10 +545,10 @@ public static <K, V> KeyedObjectPool<K, V> erodingPool(
final KeyedObjectPool<K, V> keyedPool, final float factor,
final boolean perKey) {
if (keyedPool == null) {
throw new IllegalArgumentException("keyedPool must not be null.");
throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
}
if (factor <= 0f) {
throw new IllegalArgumentException("factor must be positive.");
throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE);
}
if (perKey) {
return new ErodingPerKeyKeyedObjectPool<>(keyedPool, factor);
Expand Down Expand Up @@ -587,7 +594,7 @@ private static final class ObjectPoolMinIdleTimerTask<T> extends TimerTask {
ObjectPoolMinIdleTimerTask(final ObjectPool<T> pool, final int minIdle)
throws IllegalArgumentException {
if (pool == null) {
throw new IllegalArgumentException("pool must not be null.");
throw new IllegalArgumentException(MSG_NULL_POOL);
}
this.pool = pool;
this.minIdle = minIdle;
Expand Down Expand Up @@ -665,7 +672,7 @@ private static final class KeyedObjectPoolMinIdleTimerTask<K, V> extends
final K key, final int minIdle) throws IllegalArgumentException {
if (keyedPool == null) {
throw new IllegalArgumentException(
"keyedPool must not be null.");
MSG_NULL_KEYED_POOL);
}
this.keyedPool = keyedPool;
this.key = key;
Expand Down Expand Up @@ -747,7 +754,7 @@ private static final class SynchronizedObjectPool<T> implements ObjectPool<T> {
SynchronizedObjectPool(final ObjectPool<T> pool)
throws IllegalArgumentException {
if (pool == null) {
throw new IllegalArgumentException("pool must not be null.");
throw new IllegalArgumentException(MSG_NULL_POOL);
}
this.pool = pool;
}
Expand Down Expand Up @@ -924,7 +931,7 @@ private static final class SynchronizedKeyedObjectPool<K, V> implements
throws IllegalArgumentException {
if (keyedPool == null) {
throw new IllegalArgumentException(
"keyedPool must not be null.");
MSG_NULL_KEYED_POOL);
}
this.keyedPool = keyedPool;
}
Expand Down Expand Up @@ -1605,7 +1612,7 @@ protected ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
final ErodingFactor erodingFactor) {
if (keyedPool == null) {
throw new IllegalArgumentException(
"keyedPool must not be null.");
MSG_NULL_KEYED_POOL);
}
this.keyedPool = keyedPool;
this.erodingFactor = erodingFactor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -772,11 +772,9 @@ final void assertOpen() throws IllegalStateException {
*/
final void startEvictor(final long delay) {
synchronized (evictionLock) {
if (null != evictor) {
EvictionTimer.cancel(evictor, evictorShutdownTimeoutMillis, TimeUnit.MILLISECONDS);
evictor = null;
evictionIterator = null;
}
EvictionTimer.cancel(evictor, evictorShutdownTimeoutMillis, TimeUnit.MILLISECONDS);
evictor = null;
evictionIterator = null;
if (delay > 0) {
evictor = new Evictor();
EvictionTimer.schedule(evictor, delay, delay);
Expand Down
8 changes: 1 addition & 7 deletions java/org/apache/tomcat/dbcp/pool2/impl/CallStackUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@
*/
public final class CallStackUtils {

private static final boolean CAN_CREATE_SECURITY_MANAGER;

static {
CAN_CREATE_SECURITY_MANAGER = canCreateSecurityManager();
}

/**
* @return {@code true} if it is able to create a security manager in the current environment, {@code false}
* otherwise.
Expand Down Expand Up @@ -76,7 +70,7 @@ public static CallStack newCallStack(final String messageFormat, final boolean u
public static CallStack newCallStack(final String messageFormat,
final boolean useTimestamp,
final boolean requireFullStackTrace) {
return CAN_CREATE_SECURITY_MANAGER && !requireFullStackTrace
return canCreateSecurityManager() && !requireFullStackTrace
? new SecurityManagerCallStack(messageFormat, useTimestamp)
: new ThrowableCallStack(messageFormat, useTimestamp);
}
Expand Down
35 changes: 20 additions & 15 deletions java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,20 @@
import java.util.concurrent.TimeUnit;

/**
* Provides a shared idle object eviction timer for all pools. This class is
* currently implemented using {@link ScheduledThreadPoolExecutor}. This
* implementation may change in any future release. This class keeps track of
* how many pools are using it. If no pools are using the timer, it is cancelled.
* This prevents a thread being left running which, in application server
* environments, can lead to memory leads and/or prevent applications from
* shutting down or reloading cleanly.
* Provides a shared idle object eviction timer for all pools.
* <p>
* This class has package scope to prevent its inclusion in the pool public API.
* The class declaration below should *not* be changed to public.
* This class is currently implemented using {@link ScheduledThreadPoolExecutor}. This implementation may change in any
* future release. This class keeps track of how many pools are using it. If no pools are using the timer, it is
* cancelled. This prevents a thread being left running which, in application server environments, can lead to memory
* leads and/or prevent applications from shutting down or reloading cleanly.
* </p>
* <p>
* This class has package scope to prevent its inclusion in the pool public API. The class declaration below should
* *not* be changed to public.
* </p>
* <p>
* This class is intended to be thread-safe.
* </p>
*
* @since 2.0
*/
Expand Down Expand Up @@ -66,6 +68,7 @@ public String toString() {
* call to this method *must* call {@link #cancel(BaseGenericObjectPool.Evictor,long,TimeUnit)}
* to cancel the task to prevent memory and/or thread leaks in application
* server environments.
*
* @param task Task to be scheduled
* @param delay Delay in milliseconds before task is executed
* @param period Time in milliseconds between executions
Expand All @@ -84,16 +87,18 @@ static synchronized void schedule(
/**
* Remove the specified eviction task from the timer.
*
* @param task Task to be cancelled
* @param evictor Task to be cancelled
* @param timeout If the associated executor is no longer required, how
* long should this thread wait for the executor to
* terminate?
* @param unit The units for the specified timeout
*/
static synchronized void cancel(
final BaseGenericObjectPool<?>.Evictor task, final long timeout, final TimeUnit unit) {
task.cancel();
if (executor.getQueue().size() == 0) {
final BaseGenericObjectPool<?>.Evictor evictor, final long timeout, final TimeUnit unit) {
if (evictor != null) {
evictor.cancel();
}
if (executor != null && executor.getQueue().isEmpty()) {
executor.shutdown();
try {
executor.awaitTermination(timeout, unit);
Expand All @@ -107,14 +112,14 @@ static synchronized void cancel(
}

/**
* Thread factory that creates a thread, with the context class loader from this class.
* Thread factory that creates a daemon thread, with the context class loader from this class.
*/
private static class EvictorThreadFactory implements ThreadFactory {

@Override
public Thread newThread(final Runnable runnable) {
final Thread thread = new Thread(null, runnable, "commons-pool-evictor-thread");

thread.setDaemon(true); // POOL-363 - Required for applications using Runtime.addShutdownHook(). --joshlandin 03.27.2019
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
Expand Down
25 changes: 14 additions & 11 deletions java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
Original file line number Diff line number Diff line change
Expand Up @@ -1145,26 +1145,29 @@ private ObjectDeque<T> register(final K k) {
* @param k The key to de-register
*/
private void deregister(final K k) {
Lock lock = keyLock.readLock();
ObjectDeque<T> objectDeque;

objectDeque = poolMap.get(k);
final long numInterested = objectDeque.getNumInterested().decrementAndGet();
if (numInterested == 0 && objectDeque.getCreateCount().get() == 0) {
// Potential to remove key
final Lock writeLock = keyLock.writeLock();
writeLock.lock();
try {
if (objectDeque.getCreateCount().get() == 0 &&
objectDeque.getNumInterested().get() == 0) {
try {
lock.lock();
objectDeque = poolMap.get(k);
final long numInterested = objectDeque.getNumInterested().decrementAndGet();
if (numInterested == 0 && objectDeque.getCreateCount().get() == 0) {
// Potential to remove key
// Upgrade to write lock
lock.unlock();
lock = keyLock.writeLock();
lock.lock();
if (objectDeque.getCreateCount().get() == 0 && objectDeque.getNumInterested().get() == 0) {
// NOTE: Keys must always be removed from both poolMap and
// poolKeyList at the same time while protected by
// keyLock.writeLock()
poolMap.remove(k);
poolKeyList.remove(k);
}
} finally {
writeLock.unlock();
}
} finally {
lock.unlock();
}
}

Expand Down
Loading

0 comments on commit d676a1e

Please sign in to comment.