Author: markt
Date: Wed Dec 14 22:15:50 2011
New Revision: 1214507
URL: http://svn.apache.org/viewvc?rev=1214507&view=rev
Log:
Fix POOL-199. Ensure only one thread can call evict() at a time. Use a
dedicated (more fine-grained) lock rather than locking on the object.
Modified:
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPool.java
Modified:
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
URL:
http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java?rev=1214507&r1=1214506&r2=1214507&view=diff
==============================================================================
---
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
(original)
+++
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
Wed Dec 14 22:15:50 2011
@@ -1280,97 +1280,99 @@ public class GenericKeyedObjectPool<K,T>
return;
}
- boolean testWhileIdle = getTestWhileIdle();
- long idleEvictTime = Long.MAX_VALUE;
-
- if (getMinEvictableIdleTimeMillis() > 0) {
- idleEvictTime = getMinEvictableIdleTimeMillis();
- }
-
- PooledObject<T> underTest = null;
- LinkedBlockingDeque<PooledObject<T>> idleObjects = null;
-
- for (int i = 0, m = getNumTests(); i < m; i++) {
- if(evictionIterator == null || !evictionIterator.hasNext()) {
- if (evictionKeyIterator == null ||
- !evictionKeyIterator.hasNext()) {
- List<K> keyCopy = new ArrayList<K>();
- keyCopy.addAll(poolKeyList);
- evictionKeyIterator = keyCopy.iterator();
- }
- while (evictionKeyIterator.hasNext()) {
- evictionKey = evictionKeyIterator.next();
- ObjectDeque<T> objectDeque = poolMap.get(evictionKey);
- if (objectDeque == null) {
- continue;
- }
- idleObjects = objectDeque.getIdleObjects();
-
- if (getLifo()) {
- evictionIterator = idleObjects.descendingIterator();
- } else {
- evictionIterator = idleObjects.iterator();
+ synchronized (evictionLock) {
+ boolean testWhileIdle = getTestWhileIdle();
+ long idleEvictTime = Long.MAX_VALUE;
+
+ if (getMinEvictableIdleTimeMillis() > 0) {
+ idleEvictTime = getMinEvictableIdleTimeMillis();
+ }
+
+ PooledObject<T> underTest = null;
+ LinkedBlockingDeque<PooledObject<T>> idleObjects = null;
+
+ for (int i = 0, m = getNumTests(); i < m; i++) {
+ if(evictionIterator == null || !evictionIterator.hasNext()) {
+ if (evictionKeyIterator == null ||
+ !evictionKeyIterator.hasNext()) {
+ List<K> keyCopy = new ArrayList<K>();
+ keyCopy.addAll(poolKeyList);
+ evictionKeyIterator = keyCopy.iterator();
}
- if (evictionIterator.hasNext()) {
- break;
+ while (evictionKeyIterator.hasNext()) {
+ evictionKey = evictionKeyIterator.next();
+ ObjectDeque<T> objectDeque = poolMap.get(evictionKey);
+ if (objectDeque == null) {
+ continue;
+ }
+ idleObjects = objectDeque.getIdleObjects();
+
+ if (getLifo()) {
+ evictionIterator =
idleObjects.descendingIterator();
+ } else {
+ evictionIterator = idleObjects.iterator();
+ }
+ if (evictionIterator.hasNext()) {
+ break;
+ }
+ evictionIterator = null;
}
+ }
+ if (evictionIterator == null) {
+ // Pools exhausted
+ return;
+ }
+ try {
+ underTest = evictionIterator.next();
+ } catch (NoSuchElementException nsee) {
+ // Object was borrowed in another thread
+ // Don't count this as an eviction test so reduce i;
+ i--;
evictionIterator = null;
+ continue;
}
- }
- if (evictionIterator == null) {
- // Pools exhausted
- return;
- }
- try {
- underTest = evictionIterator.next();
- } catch (NoSuchElementException nsee) {
- // Object was borrowed in another thread
- // Don't count this as an eviction test so reduce i;
- i--;
- evictionIterator = null;
- continue;
- }
-
- if (!underTest.startEvictionTest()) {
- // Object was borrowed in another thread
- // Don't count this as an eviction test so reduce i;
- i--;
- continue;
- }
-
- if (idleEvictTime < underTest.getIdleTimeMillis()) {
- destroy(evictionKey, underTest, true);
- destroyedByEvictorCount.incrementAndGet();
- } else {
- if (testWhileIdle) {
- boolean active = false;
- try {
- factory.activateObject(evictionKey,
- underTest.getObject());
- active = true;
- } catch (Exception e) {
- destroy(evictionKey, underTest, true);
- destroyedByEvictorCount.incrementAndGet();
- }
- if (active) {
- if (!factory.validateObject(evictionKey,
- underTest.getObject())) {
+
+ if (!underTest.startEvictionTest()) {
+ // Object was borrowed in another thread
+ // Don't count this as an eviction test so reduce i;
+ i--;
+ continue;
+ }
+
+ if (idleEvictTime < underTest.getIdleTimeMillis()) {
+ destroy(evictionKey, underTest, true);
+ destroyedByEvictorCount.incrementAndGet();
+ } else {
+ if (testWhileIdle) {
+ boolean active = false;
+ try {
+ factory.activateObject(evictionKey,
+ underTest.getObject());
+ active = true;
+ } catch (Exception e) {
destroy(evictionKey, underTest, true);
destroyedByEvictorCount.incrementAndGet();
- } else {
- try {
- factory.passivateObject(evictionKey,
- underTest.getObject());
- } catch (Exception e) {
+ }
+ if (active) {
+ if (!factory.validateObject(evictionKey,
+ underTest.getObject())) {
destroy(evictionKey, underTest, true);
destroyedByEvictorCount.incrementAndGet();
+ } else {
+ try {
+ factory.passivateObject(evictionKey,
+ underTest.getObject());
+ } catch (Exception e) {
+ destroy(evictionKey, underTest, true);
+ destroyedByEvictorCount.incrementAndGet();
+ }
}
}
}
- }
- if (!underTest.endEvictionTest(idleObjects)) {
- // TODO - May need to add code here once additional states
- // are used
+ if (!underTest.endEvictionTest(idleObjects)) {
+ // TODO - May need to add code here once additional
states
+ // are used
+ }
}
}
}
@@ -1638,14 +1640,16 @@ public class GenericKeyedObjectPool<K,T>
* @param delay milliseconds between evictor runs.
*/
// Needs to be final; see POOL-195. Make protected method final as it is
called from constructor.
- protected final synchronized void startEvictor(long delay) {
- if (null != evictor) {
- EvictionTimer.cancel(evictor);
- evictor = null;
- }
- if (delay > 0) {
- evictor = new Evictor();
- EvictionTimer.schedule(evictor, delay, delay);
+ protected final void startEvictor(long delay) {
+ synchronized (evictionLock) {
+ if (null != evictor) {
+ EvictionTimer.cancel(evictor);
+ evictor = null;
+ }
+ if (delay > 0) {
+ evictor = new Evictor();
+ EvictionTimer.schedule(evictor, delay, delay);
+ }
}
}
@@ -2062,11 +2066,6 @@ public class GenericKeyedObjectPool<K,T>
/** My {@link KeyedPoolableObjectFactory}. */
final private KeyedPoolableObjectFactory<K,T> factory;
- /**
- * My idle object eviction {@link TimerTask}, if any.
- */
- private Evictor evictor = null; // @GuardedBy("this")
-
/** My hash of pools (ObjectQueue). */
private final Map<K,ObjectDeque<T>> poolMap =
new ConcurrentHashMap<K,ObjectDeque<T>>();
@@ -2086,21 +2085,29 @@ public class GenericKeyedObjectPool<K,T>
private final AtomicInteger numTotal = new AtomicInteger(0);
/**
+ * My idle object eviction {@link TimerTask}, if any.
+ */
+ private Evictor evictor = null; // @GuardedBy("evictionLock")
+
+ /**
* An iterator for {@link ObjectDeque#getIdleObjects()} that is used by the
* evictor.
*/
- private Iterator<PooledObject<T>> evictionIterator = null;
+ private Iterator<PooledObject<T>> evictionIterator = null; //
@GuardedBy("evictionLock") - except close()
/**
* An iterator for {@link #poolMap} entries.
*/
- private Iterator<K> evictionKeyIterator = null;
+ private Iterator<K> evictionKeyIterator = null; //
@GuardedBy("evictionLock") - except close()
/**
* The key associated with the {@link ObjectDeque#getIdleObjects()}
* currently being evicted.
*/
- private K evictionKey = null;
+ private K evictionKey = null; // @GuardedBy("evictionLock")
+
+ /** Object used to ensure thread safety of eviction process */
+ private final Object evictionLock = new Object();
/** Object used to ensure closed() is only called once. */
private final Object closeLock = new Object();
Modified:
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPool.java
URL:
http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPool.java?rev=1214507&r1=1214506&r2=1214507&view=diff
==============================================================================
---
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPool.java
(original)
+++
commons/proper/pool/trunk/src/java/org/apache/commons/pool2/impl/GenericObjectPool.java
Wed Dec 14 22:15:50 2011
@@ -1044,84 +1044,84 @@ public class GenericObjectPool<T> extend
PooledObject<T> underTest = null;
- boolean testWhileIdle = getTestWhileIdle();
- long idleEvictTime = Long.MAX_VALUE;
- long idleSoftEvictTime = Long.MAX_VALUE;
-
- if (getMinEvictableIdleTimeMillis() > 0) {
- idleEvictTime = getMinEvictableIdleTimeMillis();
- }
- if (getSoftMinEvictableIdleTimeMillis() > 0) {
- idleSoftEvictTime = getSoftMinEvictableIdleTimeMillis();
- }
-
- for (int i = 0, m = getNumTests(); i < m; i++) {
- if (evictionIterator == null || !evictionIterator.hasNext()) {
- if (getLifo()) {
- evictionIterator = idleObjects.descendingIterator();
- } else {
- evictionIterator = idleObjects.iterator();
- }
- }
- if (!evictionIterator.hasNext()) {
- // Pool exhausted, nothing to do here
- return;
- }
-
- try {
- underTest = evictionIterator.next();
- } catch (NoSuchElementException nsee) {
- // Object was borrowed in another thread
- // Don't count this as an eviction test so reduce i;
- i--;
- evictionIterator = null;
- continue;
- }
-
- if (!underTest.startEvictionTest()) {
- // Object was borrowed in another thread
- // Don't count this as an eviction test so reduce i;
- i--;
- continue;
- }
-
- if (idleEvictTime < underTest.getIdleTimeMillis() ||
- (idleSoftEvictTime < underTest.getIdleTimeMillis() &&
- getMinIdle() < idleObjects.size())) {
- destroy(underTest);
- destroyedByEvictorCount.incrementAndGet();
- } else {
- if (testWhileIdle) {
- boolean active = false;
- try {
- factory.activateObject(underTest.getObject());
- active = true;
- } catch (Exception e) {
- destroy(underTest);
- destroyedByEvictorCount.incrementAndGet();
+ synchronized (evictionLock) {
+ boolean testWhileIdle = getTestWhileIdle();
+ long idleEvictTime = Long.MAX_VALUE;
+ long idleSoftEvictTime = Long.MAX_VALUE;
+
+ if (getMinEvictableIdleTimeMillis() > 0) {
+ idleEvictTime = getMinEvictableIdleTimeMillis();
+ }
+ if (getSoftMinEvictableIdleTimeMillis() > 0) {
+ idleSoftEvictTime = getSoftMinEvictableIdleTimeMillis();
+ }
+
+ for (int i = 0, m = getNumTests(); i < m; i++) {
+ if (evictionIterator == null || !evictionIterator.hasNext()) {
+ if (getLifo()) {
+ evictionIterator = idleObjects.descendingIterator();
+ } else {
+ evictionIterator = idleObjects.iterator();
}
- if (active) {
- if (!factory.validateObject(underTest.getObject())) {
+ }
+ if (!evictionIterator.hasNext()) {
+ // Pool exhausted, nothing to do here
+ return;
+ }
+
+ try {
+ underTest = evictionIterator.next();
+ } catch (NoSuchElementException nsee) {
+ // Object was borrowed in another thread
+ // Don't count this as an eviction test so reduce i;
+ i--;
+ evictionIterator = null;
+ continue;
+ }
+
+ if (!underTest.startEvictionTest()) {
+ // Object was borrowed in another thread
+ // Don't count this as an eviction test so reduce i;
+ i--;
+ continue;
+ }
+
+ if (idleEvictTime < underTest.getIdleTimeMillis() ||
+ (idleSoftEvictTime < underTest.getIdleTimeMillis() &&
+ getMinIdle() < idleObjects.size())) {
+ destroy(underTest);
+ destroyedByEvictorCount.incrementAndGet();
+ } else {
+ if (testWhileIdle) {
+ boolean active = false;
+ try {
+ factory.activateObject(underTest.getObject());
+ active = true;
+ } catch (Exception e) {
destroy(underTest);
destroyedByEvictorCount.incrementAndGet();
- } else {
- try {
- factory.passivateObject(underTest.getObject());
- } catch (Exception e) {
+ }
+ if (active) {
+ if
(!factory.validateObject(underTest.getObject())) {
destroy(underTest);
destroyedByEvictorCount.incrementAndGet();
+ } else {
+ try {
+
factory.passivateObject(underTest.getObject());
+ } catch (Exception e) {
+ destroy(underTest);
+ destroyedByEvictorCount.incrementAndGet();
+ }
}
}
}
- }
- if (!underTest.endEvictionTest(idleObjects)) {
- // TODO - May need to add code here once additional states
- // are used
+ if (!underTest.endEvictionTest(idleObjects)) {
+ // TODO - May need to add code here once additional
states
+ // are used
+ }
}
}
}
-
- return;
}
private PooledObject<T> create() throws Exception {
@@ -1223,14 +1223,16 @@ public class GenericObjectPool<T> extend
* milliseconds between evictor runs.
*/
// Needs to be final; see POOL-195. Make protected method final as it is
called from constructor.
- protected final synchronized void startEvictor(long delay) {
- if (null != evictor) {
- EvictionTimer.cancel(evictor);
- evictor = null;
- }
- if (delay > 0) {
- evictor = new Evictor();
- EvictionTimer.schedule(evictor, delay, delay);
+ protected final void startEvictor(long delay) {
+ synchronized (evictionLock) {
+ if (null != evictor) {
+ EvictionTimer.cancel(evictor);
+ evictor = null;
+ }
+ if (delay > 0) {
+ evictor = new Evictor();
+ EvictionTimer.schedule(evictor, delay, delay);
+ }
}
}
@@ -1522,11 +1524,6 @@ public class GenericObjectPool<T> extend
final private PoolableObjectFactory<T> factory;
/**
- * My idle object eviction {@link TimerTask}, if any.
- */
- private Evictor evictor = null; // @GuardedBy("this")
-
- /**
* All of the objects currently associated with this pool in any state. It
* excludes objects that have been destroyed. The size of
* {@link #allObjects} will always be less than or equal to {@link
@@ -1548,9 +1545,17 @@ public class GenericObjectPool<T> extend
private final LinkedBlockingDeque<PooledObject<T>> idleObjects =
new LinkedBlockingDeque<PooledObject<T>>();
+ /**
+ * My idle object eviction {@link TimerTask}, if any.
+ */
+ private Evictor evictor = null; // @GuardedBy("evictionLock")
+
/** An iterator for {@link #idleObjects} that is used by the evictor. */
- private Iterator<PooledObject<T>> evictionIterator = null;
+ private Iterator<PooledObject<T>> evictionIterator = null; //
@GuardedBy("evictionLock")
+ /** Object used to ensure thread safety of eviction process */
+ private final Object evictionLock = new Object();
+
/** Object used to ensure closed() is only called once. */
private final Object closeLock = new Object();