Author: markt Date: Wed Mar 23 18:56:10 2011 New Revision: 1084673 URL: http://svn.apache.org/viewvc?rev=1084673&view=rev Log: Fix POOL-184. Concurrent borrowObject() and evict() can trigger inappropriate pool starvation. Test case based on a patch by Adrian Nistor.
Modified: commons/proper/pool/branches/POOL_1_X/src/changes/changes.xml commons/proper/pool/branches/POOL_1_X/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPool.java commons/proper/pool/branches/POOL_1_X/src/java/org/apache/commons/pool/impl/GenericObjectPool.java commons/proper/pool/branches/POOL_1_X/src/test/org/apache/commons/pool/impl/TestGenericObjectPool.java Modified: commons/proper/pool/branches/POOL_1_X/src/changes/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/pool/branches/POOL_1_X/src/changes/changes.xml?rev=1084673&r1=1084672&r2=1084673&view=diff ============================================================================== --- commons/proper/pool/branches/POOL_1_X/src/changes/changes.xml (original) +++ commons/proper/pool/branches/POOL_1_X/src/changes/changes.xml Wed Mar 23 18:56:10 2011 @@ -32,6 +32,10 @@ <action dev="markt" type="update" issue="POOL-181"> Make BaseObjectPool.isClosed() public. </action> + <action dev="markt" type="fix" issue="POOL-184" dut-to="Adrian Nistor"> + Correct bug that could lead to inappropriate pool starvation when evict() + and borrowObject() are called concurrently. + </action> </release> <release version="1.5.5" date="2010-09-10" description= "This is a patch release, including bugfixes, documentation improvements and some deprecations Modified: commons/proper/pool/branches/POOL_1_X/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPool.java URL: http://svn.apache.org/viewvc/commons/proper/pool/branches/POOL_1_X/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPool.java?rev=1084673&r1=1084672&r2=1084673&view=diff ============================================================================== --- commons/proper/pool/branches/POOL_1_X/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPool.java (original) +++ commons/proper/pool/branches/POOL_1_X/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPool.java Wed Mar 23 18:56:10 2011 @@ -1977,6 +1977,7 @@ public class GenericKeyedObjectPool exte _totalInternalProcessing--; } } + allocate(); } /** Modified: commons/proper/pool/branches/POOL_1_X/src/java/org/apache/commons/pool/impl/GenericObjectPool.java URL: http://svn.apache.org/viewvc/commons/proper/pool/branches/POOL_1_X/src/java/org/apache/commons/pool/impl/GenericObjectPool.java?rev=1084673&r1=1084672&r2=1084673&view=diff ============================================================================== --- commons/proper/pool/branches/POOL_1_X/src/java/org/apache/commons/pool/impl/GenericObjectPool.java (original) +++ commons/proper/pool/branches/POOL_1_X/src/java/org/apache/commons/pool/impl/GenericObjectPool.java Wed Mar 23 18:56:10 2011 @@ -1583,6 +1583,7 @@ public class GenericObjectPool extends B _numInternalProcessing--; } } + allocate(); } /** Modified: commons/proper/pool/branches/POOL_1_X/src/test/org/apache/commons/pool/impl/TestGenericObjectPool.java URL: http://svn.apache.org/viewvc/commons/proper/pool/branches/POOL_1_X/src/test/org/apache/commons/pool/impl/TestGenericObjectPool.java?rev=1084673&r1=1084672&r2=1084673&view=diff ============================================================================== --- commons/proper/pool/branches/POOL_1_X/src/test/org/apache/commons/pool/impl/TestGenericObjectPool.java (original) +++ commons/proper/pool/branches/POOL_1_X/src/test/org/apache/commons/pool/impl/TestGenericObjectPool.java Wed Mar 23 18:56:10 2011 @@ -1164,6 +1164,49 @@ public class TestGenericObjectPool exten runTestThreads(5, 10, 50); } + public void testConcurrentBorrowAndEvict() throws Exception { + + pool.setMaxActive(1); + pool.addObject(); + + for( int i=0; i<5000; i++) { + ConcurrentBorrowAndEvictThread one = + new ConcurrentBorrowAndEvictThread(true); + ConcurrentBorrowAndEvictThread two = + new ConcurrentBorrowAndEvictThread(false); + + one.start(); + two.start(); + one.join(); + two.join(); + + pool.returnObject(one.obj); + + if (i % 10 == 0) { + System.out.println(i/10); + } + } + } + + private class ConcurrentBorrowAndEvictThread extends Thread { + private boolean borrow; + public Object obj; + + public ConcurrentBorrowAndEvictThread(boolean borrow) { + this.borrow = borrow; + } + + public void run() { + try { + if (borrow) { + obj = pool.borrowObject(); + } else { + pool.evict(); + } + } catch (Exception e) { /* Ignore */} + } + } + static class TestThread implements Runnable { private final java.util.Random _random = new java.util.Random();