Fix issue reported on users list. Ensure that a call to GKOP preparePool() takes account of other threads that might create objects concurrently, particularly the Evictor.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/pool/trunk@1782329 13f79535-47bb-0310-9956-ffa450edef68 Project: http://git-wip-us.apache.org/repos/asf/commons-pool/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-pool/commit/d00d176f Tree: http://git-wip-us.apache.org/repos/asf/commons-pool/tree/d00d176f Diff: http://git-wip-us.apache.org/repos/asf/commons-pool/diff/d00d176f Branch: refs/heads/master Commit: d00d176fc04d730f63b47dde9bc334b5c3a67f3c Parents: 6a088d1 Author: Mark Thomas <ma...@apache.org> Authored: Thu Feb 9 13:41:09 2017 +0000 Committer: Mark Thomas <ma...@apache.org> Committed: Thu Feb 9 13:41:09 2017 +0000 ---------------------------------------------------------------------- src/changes/changes.xml | 4 ++++ .../pool2/impl/GenericKeyedObjectPool.java | 22 +++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-pool/blob/d00d176f/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index fb3a878..7409dc3 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -79,6 +79,10 @@ The <action> type attribute can be add,update,fix,remove. an Evictor to allow the associated thread time to complete and current evictions and to terminate. </action> + <action dev="markt" type="fix"> + Ensure that a call to GKOP preparePool() takes account of other threads + that might create objects concurrently, particularly the Evictor. + </action> </release> <release version="2.4.2" date="2015-08-01" description= "This is a patch release, including bug fixes only."> http://git-wip-us.apache.org/repos/asf/commons-pool/blob/d00d176f/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java b/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java index 7fa21b5..396aaf9 100644 --- a/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java +++ b/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java @@ -76,7 +76,7 @@ import org.apache.commons.pool2.SwallowedExceptionListener; * @since 2.0 */ public class GenericKeyedObjectPool<K,T> extends BaseGenericObjectPool<T> - implements KeyedObjectPool<K,T>, GenericKeyedObjectPoolMXBean<K> { +implements KeyedObjectPool<K,T>, GenericKeyedObjectPoolMXBean<K> { /** * Create a new <code>GenericKeyedObjectPool</code> using defaults from @@ -524,7 +524,7 @@ public class GenericKeyedObjectPool<K,T> extends BaseGenericObjectPool<T> final int maxIdle = getMaxIdlePerKey(); final LinkedBlockingDeque<PooledObject<T>> idleObjects = - objectDeque.getIdleObjects(); + objectDeque.getIdleObjects(); if (isClosed() || maxIdle > -1 && maxIdle <= idleObjects.size()) { try { @@ -758,7 +758,7 @@ public class GenericKeyedObjectPool<K,T> extends BaseGenericObjectPool<T> // for zero int itemsToRemove = ((int) (map.size() * 0.15)) + 1; final Iterator<Map.Entry<PooledObject<T>, K>> iter = - map.entrySet().iterator(); + map.entrySet().iterator(); while (iter.hasNext() && itemsToRemove > 0) { final Map.Entry<PooledObject<T>, K> entry = iter.next(); @@ -843,7 +843,7 @@ public class GenericKeyedObjectPool<K,T> extends BaseGenericObjectPool<T> final ObjectDeque<T> deque = entry.getValue(); if (deque != null) { final LinkedBlockingDeque<PooledObject<T>> pool = - deque.getIdleObjects(); + deque.getIdleObjects(); if(pool.hasTakeWaiters()) { return true; } @@ -1210,7 +1210,7 @@ public class GenericKeyedObjectPool<K,T> extends BaseGenericObjectPool<T> */ private void ensureMinIdle(final K key) throws Exception { // Calculate current pool objects - final ObjectDeque<T> objectDeque = poolMap.get(key); + ObjectDeque<T> objectDeque = poolMap.get(key); // objectDeque == null is OK here. It is handled correctly by both // methods called below. @@ -1224,6 +1224,12 @@ public class GenericKeyedObjectPool<K,T> extends BaseGenericObjectPool<T> for (int i = 0; i < deficit && calculateDeficit(objectDeque) > 0; i++) { addObject(key); + // If objectDeque was null, it won't be any more. Obtain a reference + // to it so the deficit can be correctly calculated. It needs to + // take account of objects created in other threads. + if (objectDeque == null) { + objectDeque = poolMap.get(key); + } } } @@ -1548,9 +1554,9 @@ public class GenericKeyedObjectPool<K,T> extends BaseGenericObjectPool<T> private volatile int maxIdlePerKey = GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY; private volatile int minIdlePerKey = - GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY; + GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY; private volatile int maxTotalPerKey = - GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY; + GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY; private final KeyedPooledObjectFactory<K,T> factory; private final boolean fairness; @@ -1584,7 +1590,7 @@ public class GenericKeyedObjectPool<K,T> extends BaseGenericObjectPool<T> // JMX specific attributes private static final String ONAME_BASE = - "org.apache.commons.pool2:type=GenericKeyedObjectPool,name="; + "org.apache.commons.pool2:type=GenericKeyedObjectPool,name="; @Override protected void toStringAppendFields(final StringBuilder builder) {