[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