Author: psteitz
Date: Mon Apr 19 11:26:17 2010
New Revision: 935532
URL: http://svn.apache.org/viewvc?rev=935532&view=rev
Log:
Eliminated unsynched read in makeObject, made r935362 changes consistent, made
validation latency configurable in SimpleFactory; added test confirming that
validation concurrent with return does not cause latch to be overwritten.
Modified:
commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericObjectPool.java
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=935532&r1=935531&r2=935532&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
Mon Apr 19 11:26:17 2010
@@ -1354,32 +1354,37 @@ public class TestGenericObjectPool exten
public synchronized void setMakeLatency(long makeLatency) {
this.makeLatency = makeLatency;
}
+ public synchronized void setValidateLatency(long validateLatency) {
+ this.validateLatency = validateLatency;
+ }
public Object makeObject() {
+ final long waitLatency;
synchronized(this) {
activeCount++;
if (activeCount > maxActive) {
throw new IllegalStateException(
"Too many active instances: " + activeCount);
}
+ waitLatency = makeLatency;
}
- if (makeLatency > 0) {
- doWait(makeLatency);
+ if (waitLatency > 0) {
+ doWait(waitLatency);
}
- int counter;
+ final int counter;
synchronized(this) {
counter = makeCounter++;
}
return String.valueOf(counter);
}
public void destroyObject(Object obj) throws Exception {
- boolean wait;
- boolean hurl;
+ final long waitLatency;
+ final boolean hurl;
synchronized(this) {
- wait = destroyLatency > 0;
+ waitLatency = destroyLatency;
hurl = exceptionOnDestroy;
}
- if (wait) {
- doWait(destroyLatency);
+ if (waitLatency > 0) {
+ doWait(waitLatency);
}
synchronized(this) {
activeCount--;
@@ -1389,15 +1394,20 @@ public class TestGenericObjectPool exten
}
}
public boolean validateObject(Object obj) {
- boolean validate;
- boolean evenTest;
- boolean oddTest;
- int counter;
+ final boolean validate;
+ final boolean evenTest;
+ final boolean oddTest;
+ final long waitLatency;
+ final int counter;
synchronized(this) {
validate = enableValidation;
evenTest = evenValid;
oddTest = oddValid;
counter = validateCounter++;
+ waitLatency = validateLatency;
+ }
+ if (waitLatency > 0) {
+ doWait(waitLatency);
}
if (validate) {
return counter%2 == 0 ? evenTest : oddTest;
@@ -1407,10 +1417,10 @@ public class TestGenericObjectPool exten
}
}
public void activateObject(Object obj) throws Exception {
- boolean hurl;
- boolean evenTest;
- boolean oddTest;
- int counter;
+ final boolean hurl;
+ final boolean evenTest;
+ final boolean oddTest;
+ final int counter;
synchronized(this) {
hurl = exceptionOnActivate;
evenTest = evenValid;
@@ -1424,7 +1434,7 @@ public class TestGenericObjectPool exten
}
}
public void passivateObject(Object obj) throws Exception {
- boolean hurl;
+ final boolean hurl;
synchronized(this) {
hurl = exceptionOnPassivate;
}
@@ -1443,6 +1453,7 @@ public class TestGenericObjectPool exten
boolean enableValidation = true;
long destroyLatency = 0;
long makeLatency = 0;
+ long validateLatency = 0;
int maxActive = Integer.MAX_VALUE;
public synchronized boolean isThrowExceptionOnActivate() {
@@ -1465,6 +1476,10 @@ public class TestGenericObjectPool exten
enableValidation = b;
}
+ public synchronized int getMakeCounter() {
+ return makeCounter;
+ }
+
private void doWait(long latency) {
try {
Thread.sleep(latency);
@@ -1673,4 +1688,29 @@ public class TestGenericObjectPool exten
}
assertEquals("Expected half the threads to fail",wtt.length/2,failed);
}
+
+ /**
+ * Test the following scenario:
+ * Thread 1 borrows an instance
+ * Thread 2 starts to borrow another instance before thread 1 returns
its instance
+ * Thread 1 returns its instance while thread 2 is validating its newly
created instance
+ * The test verifies that the instance created by Thread 2 is not leaked.
+ */
+ public void testMakeConcurrentWithReturn() throws Exception {
+ SimpleFactory factory = new SimpleFactory();
+ GenericObjectPool pool = new GenericObjectPool(factory);
+ pool.setTestOnBorrow(true);
+ factory.setValid(true);
+ // Borrow and return an instance, with a short wait
+ WaitingTestThread thread1 = new WaitingTestThread(pool, 200);
+ thread1.start();
+ Thread.sleep(50); // wait for validation to succeed
+ // Slow down validation and borrow an instance
+ factory.setValidateLatency(400);
+ Object instance = pool.borrowObject();
+ // Now make sure that we have not leaked an instance
+ assertEquals(factory.getMakeCounter(), pool.getNumIdle() + 1);
+ pool.returnObject(instance);
+ assertEquals(factory.getMakeCounter(), pool.getNumIdle());
+ }
}