You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ps...@apache.org on 2007/10/07 00:17:42 UTC
svn commit: r582538 [2/2] - in /commons/proper/pool/trunk:
src/java/org/apache/commons/pool/impl/ src/test/org/apache/commons/pool/
src/test/org/apache/commons/pool/impl/ xdocs/
Modified: commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericKeyedObjectPool.java
URL: http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericKeyedObjectPool.java?rev=582538&r1=582537&r2=582538&view=diff
==============================================================================
--- commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericKeyedObjectPool.java (original)
+++ commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericKeyedObjectPool.java Sat Oct 6 15:17:41 2007
@@ -22,9 +22,12 @@
import org.apache.commons.pool.KeyedObjectPool;
import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.apache.commons.pool.TestBaseKeyedObjectPool;
+import org.apache.commons.pool.VisitTracker;
+import org.apache.commons.pool.VisitTrackerFactory;
import java.util.HashMap;
import java.util.NoSuchElementException;
+import java.util.Random;
/**
* @author Rodney Waldhoff
@@ -76,6 +79,9 @@
}
private GenericKeyedObjectPool pool = null;
+ private Integer zero = new Integer(0);
+ private Integer one = new Integer(1);
+ private Integer two = new Integer(2);
public void setUp() throws Exception {
super.setUp();
@@ -585,6 +591,7 @@
}
public void testFIFO() throws Exception {
+ pool.setLifo(false);
final Object key = "key";
pool.addObject(key); // "key0"
pool.addObject(key); // "key1"
@@ -597,6 +604,284 @@
assertEquals("returned", "r", pool.borrowObject(key));
assertEquals("new-4", "key4", pool.borrowObject(key));
}
+
+ public void testLIFO() throws Exception {
+ pool.setLifo(true);
+ final Object key = "key";
+ pool.addObject(key); // "key0"
+ pool.addObject(key); // "key1"
+ pool.addObject(key); // "key2"
+ assertEquals("Youngest", "key2", pool.borrowObject(key));
+ assertEquals("Middle", "key1", pool.borrowObject(key));
+ assertEquals("Oldest", "key0", pool.borrowObject(key));
+ assertEquals("new-3", "key3", pool.borrowObject(key));
+ pool.returnObject(key, "r");
+ assertEquals("returned", "r", pool.borrowObject(key));
+ assertEquals("new-4", "key4", pool.borrowObject(key));
+ }
+
+ /**
+ * Test to make sure evictor visits least recently used objects first,
+ * regardless of FIFO/LIFO
+ *
+ * JIRA: POOL-86
+ */
+ public void testEvictionOrder() throws Exception {
+ checkEvictionOrder(false);
+ checkEvictionOrder(true);
+ }
+
+ private void checkEvictionOrder(boolean lifo) throws Exception {
+ SimpleFactory factory = new SimpleFactory();
+ GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
+ pool.setNumTestsPerEvictionRun(2);
+ pool.setMinEvictableIdleTimeMillis(100);
+ pool.setLifo(lifo);
+
+ for (int i = 0; i < 3; i ++) {
+ Integer key = new Integer(i);
+ for (int j = 0; j < 5; j++) {
+ pool.addObject(key);
+ }
+ }
+
+ // Make all evictable
+ Thread.sleep(200);
+
+ /*
+ * Initial state (Key, Object) pairs in order of age:
+ *
+ * (0,0), (0,1), (0,2), (0,3), (0,4)
+ * (1,5), (1,6), (1,7), (1,8), (1,9)
+ * (2,10), (2,11), (2,12), (2,13), (2,14)
+ */
+
+ pool.evict(); // Kill (0,0),(0,1)
+ assertEquals(3, pool.getNumIdle(zero));
+ Object obj = pool.borrowObject(zero);
+ assertTrue(lifo ? obj.equals("04") : obj.equals("02"));
+ assertEquals(2, pool.getNumIdle(zero));
+ obj = pool.borrowObject(zero);
+ assertTrue(obj.equals("03"));
+ assertEquals(1, pool.getNumIdle(zero));
+
+ pool.evict(); // Kill remaining 0 survivor and (1,5)
+ assertEquals(0, pool.getNumIdle(zero));
+ assertEquals(4, pool.getNumIdle(one));
+ obj = pool.borrowObject(one);
+ assertTrue(lifo ? obj.equals("19") : obj.equals("16"));
+ assertEquals(3, pool.getNumIdle(one));
+ obj = pool.borrowObject(one);
+ assertTrue(lifo ? obj.equals("18") : obj.equals("17"));
+ assertEquals(2, pool.getNumIdle(one));
+
+ pool.evict(); // Kill remaining 1 survivors
+ assertEquals(0, pool.getNumIdle(one));
+ pool.evict(); // Kill (2,10), (2,11)
+ assertEquals(3, pool.getNumIdle(two));
+ obj = pool.borrowObject(two);
+ assertTrue(lifo ? obj.equals("214") : obj.equals("212"));
+ assertEquals(2, pool.getNumIdle(two));
+ pool.evict(); // All dead now
+ assertEquals(0, pool.getNumIdle(two));
+
+ pool.evict(); // Should do nothing - make sure no exception
+ pool.evict();
+
+ // Reload
+ pool.setMinEvictableIdleTimeMillis(500);
+ factory.counter = 0; // Reset counter
+ for (int i = 0; i < 3; i ++) {
+ Integer key = new Integer(i);
+ for (int j = 0; j < 5; j++) {
+ pool.addObject(key);
+ }
+ Thread.sleep(200);
+ }
+
+ // 0's are evictable, others not
+ pool.evict(); // Kill (0,0),(0,1)
+ assertEquals(3, pool.getNumIdle(zero));
+ pool.evict(); // Kill (0,2),(0,3)
+ assertEquals(1, pool.getNumIdle(zero));
+ pool.evict(); // Kill (0,4), leave (1,5)
+ assertEquals(0, pool.getNumIdle(zero));
+ assertEquals(5, pool.getNumIdle(one));
+ assertEquals(5, pool.getNumIdle(two));
+ pool.evict(); // (1,6), (1,7)
+ assertEquals(5, pool.getNumIdle(one));
+ assertEquals(5, pool.getNumIdle(two));
+ pool.evict(); // (1,8), (1,9)
+ assertEquals(5, pool.getNumIdle(one));
+ assertEquals(5, pool.getNumIdle(two));
+ pool.evict(); // (2,10), (2,11)
+ assertEquals(5, pool.getNumIdle(one));
+ assertEquals(5, pool.getNumIdle(two));
+ pool.evict(); // (2,12), (2,13)
+ assertEquals(5, pool.getNumIdle(one));
+ assertEquals(5, pool.getNumIdle(two));
+ pool.evict(); // (2,14), (1,5)
+ assertEquals(5, pool.getNumIdle(one));
+ assertEquals(5, pool.getNumIdle(two));
+ Thread.sleep(200); // Ones now timed out
+ pool.evict(); // kill (1,6), (1,7) - (1,5) missed
+ assertEquals(3, pool.getNumIdle(one));
+ assertEquals(5, pool.getNumIdle(two));
+ obj = pool.borrowObject(one);
+ assertTrue(lifo ? obj.equals("19") : obj.equals("15"));
+ }
+
+
+ /**
+ * Verifies that the evictor visits objects in expected order
+ * and frequency.
+ */
+ public void testEvictorVisiting() throws Exception {
+ checkEvictorVisiting(true);
+ checkEvictorVisiting(false);
+ }
+
+ private void checkEvictorVisiting(boolean lifo) throws Exception {
+ VisitTrackerFactory factory = new VisitTrackerFactory();
+ GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
+ pool.setNumTestsPerEvictionRun(2);
+ pool.setMinEvictableIdleTimeMillis(-1);
+ pool.setTestWhileIdle(true);
+ pool.setLifo(lifo);
+ pool.setTestOnReturn(false);
+ pool.setTestOnBorrow(false);
+ for (int i = 0; i < 3; i ++) {
+ factory.resetId();
+ Integer key = new Integer(i);
+ for (int j = 0; j < 8; j++) {
+ pool.addObject(key);
+ }
+ }
+ pool.evict(); // Visit oldest 2 - 00 and 01
+ Object obj = pool.borrowObject(zero);
+ pool.returnObject(zero, obj);
+ obj = pool.borrowObject(zero);
+ pool.returnObject(zero, obj);
+ // borrow, return, borrow, return
+ // FIFO will move 0 and 1 to end - 2,3,4,5,6,7,0,1
+ // LIFO, 7 out, then in, then out, then in - 7,6,5,4,3,2,1,0
+ pool.evict(); // Should visit 02 and 03 in either case
+ for (int i = 0; i < 8; i++) {
+ VisitTracker tracker = (VisitTracker) pool.borrowObject(zero);
+ if (tracker.getId() >= 4) {
+ assertEquals("Unexpected instance visited " + tracker.getId(),
+ 0, tracker.getValidateCount());
+ } else {
+ assertEquals("Instance " + tracker.getId() +
+ " visited wrong number of times.",
+ 1, tracker.getValidateCount());
+ }
+ }
+ // 0's are all out
+
+ pool.setNumTestsPerEvictionRun(3);
+
+ pool.evict(); // 10, 11, 12
+ pool.evict(); // 13, 14, 15
+
+ obj = pool.borrowObject(one);
+ pool.returnObject(one, obj);
+ obj = pool.borrowObject(one);
+ pool.returnObject(one, obj);
+ obj = pool.borrowObject(one);
+ pool.returnObject(one, obj);
+ // borrow, return, borrow, return
+ // FIFO 3,4,5,^,6,7,0,1,2
+ // LIFO 7,6,^,5,4,3,2,1,0
+ // In either case, pointer should be at 6
+ pool.evict();
+ // LIFO - 16, 17, 20
+ // FIFO - 16, 17, 10
+ pool.evict();
+ // LIFO - 21, 22, 23
+ // FIFO - 11, 12, 20
+ pool.evict();
+ // LIFO - 24, 25, 26
+ // FIFO - 21, 22, 23
+ pool.evict();
+ // LIFO - 27, skip, 10
+ // FIFO - 24, 25, 26
+ for (int i = 0; i < 8; i++) {
+ VisitTracker tracker = (VisitTracker) pool.borrowObject(one);
+ if ((lifo && tracker.getId() > 0) ||
+ (!lifo && tracker.getId() > 2)) {
+ assertEquals("Instance " + tracker.getId() +
+ " visited wrong number of times.",
+ 1, tracker.getValidateCount());
+ } else {
+ assertEquals("Instance " + tracker.getId() +
+ " visited wrong number of times.",
+ 2, tracker.getValidateCount());
+ }
+ }
+
+ // Randomly generate some pools with random numTests
+ // and make sure evictor cycles through elements appropriately
+ int[] smallPrimes = {2, 3, 5, 7};
+ Random random = new Random();
+ random.setSeed(System.currentTimeMillis());
+ pool.setMaxIdle(-1);
+ for (int i = 0; i < 4; i++) {
+ pool.setNumTestsPerEvictionRun(smallPrimes[i]);
+ for (int j = 0; j < 5; j++) {
+ pool.clear();
+ int zeroLength = 10 + random.nextInt(20);
+ for (int k = 0; k < zeroLength; k++) {
+ pool.addObject(zero);
+ }
+ int oneLength = 10 + random.nextInt(20);
+ for (int k = 0; k < oneLength; k++) {
+ pool.addObject(one);
+ }
+ int twoLength = 10 + random.nextInt(20);
+ for (int k = 0; k < twoLength; k++) {
+ pool.addObject(two);
+ }
+
+ // Choose a random number of evictor runs
+ int runs = 10 + random.nextInt(50);
+ for (int k = 0; k < runs; k++) {
+ pool.evict();
+ }
+
+ // Total instances in pool
+ int totalInstances = zeroLength + oneLength + twoLength;
+
+ // Number of times evictor should have cycled through pools
+ int cycleCount = (runs * pool.getNumTestsPerEvictionRun())
+ / totalInstances;
+
+ // Look at elements and make sure they are visited cycleCount
+ // or cycleCount + 1 times
+ VisitTracker tracker = null;
+ int visitCount = 0;
+ for (int k = 0; k < zeroLength; k++) {
+ tracker = (VisitTracker) pool.borrowObject(zero);
+ visitCount = tracker.getValidateCount();
+ assertTrue(visitCount >= cycleCount &&
+ visitCount <= cycleCount + 1);
+ }
+ for (int k = 0; k < oneLength; k++) {
+ tracker = (VisitTracker) pool.borrowObject(one);
+ visitCount = tracker.getValidateCount();
+ assertTrue(visitCount >= cycleCount &&
+ visitCount <= cycleCount + 1);
+ }
+ for (int k = 0; k < twoLength; k++) {
+ tracker = (VisitTracker) pool.borrowObject(two);
+ visitCount = tracker.getValidateCount();
+ assertTrue(visitCount >= cycleCount &&
+ visitCount <= cycleCount + 1);
+ }
+ }
+ }
+ }
+
class TestThread implements Runnable {
java.util.Random _random = new java.util.Random();
@@ -680,11 +965,11 @@
}
protected boolean isLifo() {
- return false;
+ return true;
}
protected boolean isFifo() {
- return true;
+ return false;
}
}
Modified: commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericObjectPool.java
URL: http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericObjectPool.java?rev=582538&r1=582537&r2=582538&view=diff
==============================================================================
--- commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericObjectPool.java (original)
+++ commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericObjectPool.java Sat Oct 6 15:17:41 2007
@@ -25,8 +25,11 @@
import org.apache.commons.pool.TestObjectPool;
import org.apache.commons.pool.PoolUtils;
import org.apache.commons.pool.TestBaseObjectPool;
+import org.apache.commons.pool.VisitTracker;
+import org.apache.commons.pool.VisitTrackerFactory;
import java.util.NoSuchElementException;
+import java.util.Random;
/**
* @author Rodney Waldhoff
@@ -47,6 +50,7 @@
GenericObjectPool pool = new GenericObjectPool(new SimpleFactory());
pool.setMaxActive(mincap);
pool.setMaxIdle(mincap);
+ pool.setLifo(false);
return pool;
}
@@ -122,13 +126,22 @@
pool.close();
}
- public void testEvict() throws Exception {
+ public void testEvictLIFO() throws Exception {
+ checkEvict(true);
+ }
+
+ public void testEvictFIFO() throws Exception {
+ checkEvict(false);
+ }
+
+ public void checkEvict(boolean lifo) throws Exception {
// yea this is hairy but it tests all the code paths in GOP.evict()
final SimpleFactory factory = new SimpleFactory();
final GenericObjectPool pool = new GenericObjectPool(factory);
pool.setSoftMinEvictableIdleTimeMillis(10);
pool.setMinIdle(2);
pool.setTestWhileIdle(true);
+ pool.setLifo(lifo);
PoolUtils.prefill(pool, 5);
pool.evict();
factory.setEvenValid(false);
@@ -146,6 +159,169 @@
pool.evict();
assertEquals(2, pool.getNumIdle());
}
+
+ /**
+ * Test to make sure evictor visits least recently used objects first,
+ * regardless of FIFO/LIFO
+ *
+ * JIRA: POOL-86
+ */
+ public void testEvictionOrder() throws Exception {
+ checkEvictionOrder(false);
+ checkEvictionOrder(true);
+ }
+
+ private void checkEvictionOrder(boolean lifo) throws Exception {
+ SimpleFactory factory = new SimpleFactory();
+ GenericObjectPool pool = new GenericObjectPool(factory);
+ pool.setNumTestsPerEvictionRun(2);
+ pool.setMinEvictableIdleTimeMillis(100);
+ pool.setLifo(lifo);
+ for (int i = 0; i < 5; i++) {
+ pool.addObject();
+ Thread.sleep(100);
+ }
+ // Order, oldest to youngest, is "0", "1", ...,"4"
+ pool.evict(); // Should evict "0" and "1"
+ Object obj = pool.borrowObject();
+ assertTrue("oldest not evicted", !obj.equals("0"));
+ assertTrue("second oldest not evicted", !obj.equals("1"));
+ // 2 should be next out for FIFO, 4 for LIFO
+ assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj);
+
+ // Two eviction runs in sequence
+ factory = new SimpleFactory();
+ pool = new GenericObjectPool(factory);
+ pool.setNumTestsPerEvictionRun(2);
+ pool.setMinEvictableIdleTimeMillis(100);
+ pool.setLifo(lifo);
+ for (int i = 0; i < 5; i++) {
+ pool.addObject();
+ Thread.sleep(100);
+ }
+ pool.evict(); // Should evict "0" and "1"
+ pool.evict(); // Should evict "2" and "3"
+ obj = pool.borrowObject();
+ assertEquals("Wrong instance remaining in pool", "4", obj);
+ }
+
+ /**
+ * Verifies that the evictor visits objects in expected order
+ * and frequency.
+ */
+ public void testEvictorVisiting() throws Exception {
+ checkEvictorVisiting(true);
+ checkEvictorVisiting(false);
+ }
+
+ private void checkEvictorVisiting(boolean lifo) throws Exception {
+ VisitTrackerFactory factory = new VisitTrackerFactory();
+ GenericObjectPool pool = new GenericObjectPool(factory);
+ pool.setNumTestsPerEvictionRun(2);
+ pool.setMinEvictableIdleTimeMillis(-1);
+ pool.setTestWhileIdle(true);
+ pool.setLifo(lifo);
+ pool.setTestOnReturn(false);
+ pool.setTestOnBorrow(false);
+ for (int i = 0; i < 8; i++) {
+ pool.addObject();
+ }
+ pool.evict(); // Visit oldest 2 - 0 and 1
+ Object obj = pool.borrowObject();
+ pool.returnObject(obj);
+ obj = pool.borrowObject();
+ pool.returnObject(obj);
+ // borrow, return, borrow, return
+ // FIFO will move 0 and 1 to end
+ // LIFO, 7 out, then in, then out, then in
+ pool.evict(); // Should visit 2 and 3 in either case
+ for (int i = 0; i < 8; i++) {
+ VisitTracker tracker = (VisitTracker) pool.borrowObject();
+ if (tracker.getId() >= 4) {
+ assertEquals("Unexpected instance visited " + tracker.getId(),
+ 0, tracker.getValidateCount());
+ } else {
+ assertEquals("Instance " + tracker.getId() +
+ " visited wrong number of times.",
+ 1, tracker.getValidateCount());
+ }
+ }
+
+ factory = new VisitTrackerFactory();
+ pool = new GenericObjectPool(factory);
+ pool.setNumTestsPerEvictionRun(3);
+ pool.setMinEvictableIdleTimeMillis(-1);
+ pool.setTestWhileIdle(true);
+ pool.setLifo(lifo);
+ pool.setTestOnReturn(false);
+ pool.setTestOnBorrow(false);
+ for (int i = 0; i < 8; i++) {
+ pool.addObject();
+ }
+ pool.evict(); // 0, 1, 2
+ pool.evict(); // 3, 4, 5
+ obj = pool.borrowObject();
+ pool.returnObject(obj);
+ obj = pool.borrowObject();
+ pool.returnObject(obj);
+ obj = pool.borrowObject();
+ pool.returnObject(obj);
+ // borrow, return, borrow, return
+ // FIFO 3,4,5,6,7,0,1,2
+ // LIFO 7,6,5,4,3,2,1,0
+ // In either case, pointer should be at 6
+ pool.evict();
+ // Should hit 6,7,0 - 0 for second time
+ for (int i = 0; i < 8; i++) {
+ VisitTracker tracker = (VisitTracker) pool.borrowObject();
+ if (tracker.getId() != 0) {
+ assertEquals("Instance " + tracker.getId() +
+ " visited wrong number of times.",
+ 1, tracker.getValidateCount());
+ } else {
+ assertEquals("Instance " + tracker.getId() +
+ " visited wrong number of times.",
+ 2, tracker.getValidateCount());
+ }
+ }
+ // Randomly generate a pools with random numTests
+ // and make sure evictor cycles through elements appropriately
+ int[] smallPrimes = {2, 3, 5, 7};
+ Random random = new Random();
+ random.setSeed(System.currentTimeMillis());
+ pool.setMaxIdle(-1);
+ for (int i = 0; i < 4; i++) {
+ pool.setNumTestsPerEvictionRun(smallPrimes[i]);
+ for (int j = 0; j < 5; j++) {
+ pool.clear();
+ int instanceCount = 10 + random.nextInt(20);
+ for (int k = 0; k < instanceCount; k++) {
+ pool.addObject();
+ }
+
+ // Execute a random number of evictor runs
+ int runs = 10 + random.nextInt(50);
+ for (int k = 0; k < runs; k++) {
+ pool.evict();
+ }
+
+ // Number of times evictor should have cycled through the pool
+ int cycleCount = (runs * pool.getNumTestsPerEvictionRun())
+ / instanceCount;
+
+ // Look at elements and make sure they are visited cycleCount
+ // or cycleCount + 1 times
+ VisitTracker tracker = null;
+ int visitCount = 0;
+ for (int k = 0; k < instanceCount; k++) {
+ tracker = (VisitTracker) pool.borrowObject();
+ visitCount = tracker.getValidateCount();
+ assertTrue(visitCount >= cycleCount &&
+ visitCount <= cycleCount + 1);
+ }
+ }
+ }
+ }
public void testExceptionOnPassivateDuringReturn() throws Exception {
SimpleFactory factory = new SimpleFactory();
@@ -820,12 +996,27 @@
}
public void testFIFO() throws Exception {
+ pool.setLifo(false);
pool.addObject(); // "0"
pool.addObject(); // "1"
pool.addObject(); // "2"
assertEquals("Oldest", "0", pool.borrowObject());
assertEquals("Middle", "1", pool.borrowObject());
assertEquals("Youngest", "2", pool.borrowObject());
+ assertEquals("new-3", "3", pool.borrowObject());
+ pool.returnObject("r");
+ assertEquals("returned", "r", pool.borrowObject());
+ assertEquals("new-4", "4", pool.borrowObject());
+ }
+
+ public void testLIFO() throws Exception {
+ pool.setLifo(true);
+ pool.addObject(); // "0"
+ pool.addObject(); // "1"
+ pool.addObject(); // "2"
+ assertEquals("Youngest", "2", pool.borrowObject());
+ assertEquals("Middle", "1", pool.borrowObject());
+ assertEquals("Oldest", "0", pool.borrowObject());
assertEquals("new-3", "3", pool.borrowObject());
pool.returnObject("r");
assertEquals("returned", "r", pool.borrowObject());
Modified: commons/proper/pool/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/pool/trunk/xdocs/changes.xml?rev=582538&r1=582537&r2=582538&view=diff
==============================================================================
--- commons/proper/pool/trunk/xdocs/changes.xml (original)
+++ commons/proper/pool/trunk/xdocs/changes.xml Sat Oct 6 15:17:41 2007
@@ -69,6 +69,20 @@
<action dev="psteitz" type="fix" issue="POOL-102" due-to="John Sumsion">
Allowed blocked threads in GenericObjectPool borrowObject to be interrupted.
</action>
+ <action dev="psteitz" type="fix" issue="POOL-86">
+ Fixes to address idle object eviction and LIFO/FIFO behavior reported
+ in POOL-86.
+ <ul>
+ <li>Made LIFO/FIFO behavior configurable for GenericObjectPool and
+ GenericKeyedObjectPool, with default set back to LIFO
+ (reverting to 1.2 behavior)</li>
+ <li>Fixed GOP, GKOP evict method and added tests to ensure objects
+ are visited in oldest-to-youngest order</li>
+ <li>Changed backing store for GOP, GKOP pools back to Commons
+ Collections CursorableLinkedList (brought this class in,
+ repackaged with package scope).</li>
+ </ul>
+ </action>
</release>
<release version="1.3" date="2006-pending" description="1.x bugfix release">