[jboss-cvs] JBossAS SVN: r79358 - in projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton: unit and 1 other directory.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Sat Oct 11 04:58:22 EDT 2008
Author: alex.loubyansky at jboss.com
Date: 2008-10-11 04:58:22 -0400 (Sat, 11 Oct 2008)
New Revision: 79358
Modified:
projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonBean.java
projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonLockInterceptor.java
projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonRemote.java
projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/unit/SingletonUnitTestCase.java
Log:
EJBTHREE-1518 test writing thread block until the currently active reading threads are complete before proceeding
Modified: projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonBean.java
===================================================================
--- projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonBean.java 2008-10-11 00:32:10 UTC (rev 79357)
+++ projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonBean.java 2008-10-11 08:58:22 UTC (rev 79358)
@@ -50,6 +50,9 @@
// some instance variable
private int value;
+ // the name of the last executed method
+ private String lastReturnedValueMethod;
+
// instance initialization
{
synchronized(instanceCount)
@@ -101,27 +104,35 @@
/**
* This method demonstrates that two threads can be active in the same session bean instance in case of read concurrency.
*
- * 1. Increase the current value
- * 2. If the current value is less than valueThreshold then wait and let other threads to increase the value
+ * 1. if current value is bigger than or equal the valueThreshold then return the current value.
+ * 2. Increase the current value
+ * 3. If the current value is less than valueThreshold then wait and let other threads to increase the value
* until it reaches the valueThreshold.
- * 3. Return the current value (which should be equal to valueThreshold).
+ * 4. Return the current value (which should be bigger than or equal to valueThreshold).
*
* if waiting takes longer than timeout then throw an exception.
*/
- public int getReadLock(int valueThreshold, long timeout)
+ public int getValue(int valueThreshold, long timeout)
{
- synchronized(instanceLock)
+ synchronized (instanceLock)
{
+ if (value >= valueThreshold)
+ {
+ lastReturnedValueMethod = "getValue";
+ return value;
+ }
+
++this.value;
instanceLock.notify();
-
+
// wait until the other thread increases the current value
long startTime = System.currentTimeMillis();
while (this.value < valueThreshold)
{
- if (System.currentTimeMillis() - startTime > timeout)
- throw new IllegalStateException("The method took too long.");
+ long waitTime = System.currentTimeMillis() - startTime;
+ if (waitTime > timeout)
+ throw new IllegalStateException("The method took too long. Timeout=" + timeout + ", waitTime=" + waitTime + ", value=" + value);
try
{
@@ -131,8 +142,29 @@
{
}
}
+
+ lastReturnedValueMethod = "getValue";
+ instanceLock.notify();
+ return this.value;
}
-
- return this.value;
}
+
+ public int setValue(int newValue)
+ {
+ try
+ {
+ int prev = this.value;
+ this.value = newValue;
+ return prev;
+ }
+ finally
+ {
+ lastReturnedValueMethod = "setValue";
+ }
+ }
+
+ public String getLastReturnedValueMethod()
+ {
+ return lastReturnedValueMethod;
+ }
}
Modified: projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonLockInterceptor.java
===================================================================
--- projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonLockInterceptor.java 2008-10-11 00:32:10 UTC (rev 79357)
+++ projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonLockInterceptor.java 2008-10-11 08:58:22 UTC (rev 79358)
@@ -61,7 +61,7 @@
{
String methodName = mi.getMethod().getName();
isReadMethod = methodName.startsWith("get") || methodName.startsWith("is");
- log.info(container.getEjbName() + '.' + methodName + " is read concurrency: " + isReadMethod);
+ //log.info(container.getEjbName() + '.' + methodName + " is read concurrency: " + isReadMethod);
}
lock.sync();
Modified: projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonRemote.java
===================================================================
--- projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonRemote.java 2008-10-11 00:32:10 UTC (rev 79357)
+++ projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonRemote.java 2008-10-11 08:58:22 UTC (rev 79358)
@@ -43,5 +43,20 @@
/**
* This method demonstrates that two threads can be active in the same session bean instance in case of read concurrency.
*/
- int getReadLock(int valueThreshold, long timeout);
+ int getValue(int valueThreshold, long timeout);
+
+ /**
+ * Sets the new value and returns the previous one.
+ *
+ * @param i new value
+ * @return previous value
+ */
+ int setValue(int i);
+
+ /**
+ * Returns the name of the last executed method
+ *
+ * @return
+ */
+ String getLastReturnedValueMethod();
}
Modified: projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/unit/SingletonUnitTestCase.java
===================================================================
--- projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/unit/SingletonUnitTestCase.java 2008-10-11 00:32:10 UTC (rev 79357)
+++ projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/unit/SingletonUnitTestCase.java 2008-10-11 08:58:22 UTC (rev 79358)
@@ -148,7 +148,7 @@
{
try
{
- results[threadIndex] = remote.getReadLock(threads.length, 1000);
+ results[threadIndex] = remote.getValue(threads.length, 1000);
}
catch(Throwable t)
{
@@ -192,4 +192,221 @@
assertEquals(1, remote.getInstanceCount());
}
+
+ /**
+ * This method demonstrates that an invocation of a method with write concurrency
+ * can't proceed until all the currently in progress methods with read concurrency are done.
+ */
+ public void testWriteThreadWaitingOnReadThreadsToComplete() throws Throwable
+ {
+ final SingletonRemote singleton = (SingletonRemote) getInitialContext().lookup("SingletonBean/remote");
+
+ // set the initial value to 0
+ SetValueThread setter = new SetValueThread(singleton, 0);
+ setter.start();
+ setter.waitOnTheResult();
+ assertEquals("setValue", singleton.getLastReturnedValueMethod());
+
+ // assert current value is 0
+ GetValueThread getter = new GetValueThread(singleton);
+ getter.start();
+ getter.waitOnTheResult();
+ getter.assertResult(0);
+ assertEquals("getValue", singleton.getLastReturnedValueMethod());
+
+ // this getter will block on the server until the value reaches 6
+ GetValueThread getter6 = new GetValueThread(singleton, 6);
+ getter6.start();
+
+ // this getter will block on the server until the value reaches 5
+ GetValueThread getter5 = new GetValueThread(singleton, 5);
+ getter5.start();
+
+ // this getter will block on the server until the value reaches 4
+ GetValueThread getter4 = new GetValueThread(singleton, 4);
+ getter4.start();
+
+ // current value should now be 3
+ // this getter will make it 4 and resume getter4
+ getter = new GetValueThread(singleton, 4);
+ assertFalse(getter6.isDone());
+ assertFalse(getter5.isDone());
+ assertFalse(getter4.isDone());
+ getter.start();
+
+ getter.waitOnTheResult();
+ assertTrue(getter.isDone());
+ getter.assertResult(4);
+
+ getter4.waitOnTheResult();
+ assertTrue(getter4.isDone());
+ getter4.assertResult(4);
+
+ // at this point getter5 and getter6 are blocked
+ // invoke setter (which would block until the getters are done) and set the value to 1 again
+ setter = new SetValueThread(singleton, 1);
+ assertFalse(getter6.isDone());
+ assertFalse(getter5.isDone());
+ setter.start();
+
+ // invoke getter again which would unblock getter5
+ getter = new GetValueThread(singleton, 5);
+ assertFalse(getter6.isDone());
+ assertFalse(getter5.isDone());
+ assertFalse(setter.isDone());
+ getter.start();
+
+ getter.waitOnTheResult();
+ getter.assertResult(5);
+ getter5.waitOnTheResult();
+ getter5.assertResult(5);
+
+ // at this point getter5 is blocked and blocking the setter
+ // invoke getter again and unblock getter5
+ getter = new GetValueThread(singleton, 6);
+ assertFalse(getter6.isDone());
+ assertFalse(setter.isDone());
+ getter.start();
+
+ // wait for the results on all threads
+ // the setter must end last on the server
+ setter.waitOnTheResult();
+ setter.assertResult(6);
+ // although the setter must end last on the server the response might not arrive last on the client
+ getter6.waitOnTheResult();
+ getter6.assertResult(6);
+ getter.waitOnTheResult();
+ getter.assertResult(6);
+ // make sure setValue ended last on the server
+ assertEquals("setValue", singleton.getLastReturnedValueMethod());
+
+ // assert the current value is 1
+ getter = new GetValueThread(singleton);
+ getter.start();
+ getter.waitOnTheResult();
+ getter.assertResult(1);
+
+ assertEquals(1, singleton.getInstanceCount());
+ }
+
+ private static abstract class AbstractValueThread extends Thread
+ {
+ final private SingletonRemote singleton;
+ private int result;
+ private boolean[] done = new boolean[1];
+ private Throwable error;
+
+ public AbstractValueThread(SingletonRemote singleton)
+ {
+ super();
+ this.singleton = singleton;
+ }
+
+ protected abstract int execute(SingletonRemote singleton);
+
+ public void run()
+ {
+ try
+ {
+ result = execute(singleton);
+ }
+ catch(Throwable t)
+ {
+ error = t;
+ }
+ finally
+ {
+ synchronized(done)
+ {
+ done[0] = true;
+ done.notify();
+ }
+ }
+ }
+
+ public int getResult()
+ {
+ return result;
+ }
+
+ public boolean isDone()
+ {
+ return done[0];
+ }
+
+ public void waitOnTheResult()
+ {
+ synchronized(done)
+ {
+ while (!done[0])
+ {
+ try
+ {
+ done.wait();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+ }
+ }
+
+ public Throwable getError()
+ {
+ return error;
+ }
+
+ public void assertResult(int expected)
+ {
+ if(error != null)
+ fail(error.getMessage());
+ assertEquals(expected, result);
+ }
+ }
+
+ private static class SetValueThread extends AbstractValueThread
+ {
+ final int newValue;
+
+ public SetValueThread(SingletonRemote singleton, int newValue)
+ {
+ super(singleton);
+ this.newValue = newValue;
+ }
+
+ @Override
+ protected int execute(SingletonRemote singleton)
+ {
+ return singleton.setValue(newValue);
+ }
+ }
+
+ private static class GetValueThread extends AbstractValueThread
+ {
+ final int valueThreshold;
+ final int timeout;
+
+ public GetValueThread(SingletonRemote singleton)
+ {
+ this(singleton, 0, 1000);
+ }
+
+ public GetValueThread(SingletonRemote singleton, int valueThreshold)
+ {
+ this(singleton, valueThreshold, 2000);
+ }
+
+ public GetValueThread(SingletonRemote singleton, int valueThreshold, int timeout)
+ {
+ super(singleton);
+ this.valueThreshold = valueThreshold;
+ this.timeout = timeout;
+ }
+
+ @Override
+ protected int execute(SingletonRemote singleton)
+ {
+ return singleton.getValue(valueThreshold, timeout);
+ }
+ }
}
More information about the jboss-cvs-commits
mailing list