[jboss-cvs] JBossAS SVN: r79302 - in projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton: pool and 1 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Thu Oct 9 10:46:40 EDT 2008


Author: alex.loubyansky at jboss.com
Date: 2008-10-09 10:46:40 -0400 (Thu, 09 Oct 2008)
New Revision: 79302

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/pool/SingletonPool.java
   projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/unit/SingletonUnitTestCase.java
Log:
EJBTHREE-1518 basic pool impl and basic tests for read and write concurrency

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-09 12:37:20 UTC (rev 79301)
+++ projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonBean.java	2008-10-09 14:46:40 UTC (rev 79302)
@@ -47,6 +47,9 @@
    private static Object instanceLock = new Object();
    private static Thread lockerThread;
    
+   // some instance variable
+   private int value;
+   
    // instance initialization
    {
       synchronized(instanceCount)
@@ -60,7 +63,11 @@
       return instanceCount;
    }
    
-   public void testWriteLock(long pause)
+   /**
+    * This method demonstrates that once one thread is entered an instance method
+    * no other thread can enter any method of the same instance in case of write concurrency.
+    */
+   public void writeLock(long pause)
    {
       Thread currentThread = Thread.currentThread();
       synchronized(instanceLock)
@@ -69,7 +76,6 @@
             lockerThread = currentThread;
          else if(!lockerThread.equals(currentThread))
          {
-            //System.out.println("Another thread is active in the instance: " + lockerThread + ", current thread: " + currentThread);
             throw new IllegalStateException("Another thread is active in the instance: " + lockerThread + ", current thread: " + currentThread);
          }
       }
@@ -86,10 +92,70 @@
       {
          if(!currentThread.equals(lockerThread))
          {
-            //System.out.println("Another thread is active in the instance: " + lockerThread + ", current thread: " + currentThread);
             throw new IllegalStateException("Another thread is/was active in the instance: " + lockerThread + ", current thread: " + currentThread);
          }
          lockerThread = null;
       }
    }
+   
+   /**
+    * This method demonstrates that two threads can be active in the same session bean instance in case of read concurrency.
+    *  
+    * 1. check that the value (instance variable) is equal to the expectedCurrentValue.
+    *    If it's not then wait for the other thread to set it to the expectedCurrentValue.
+    * 2. increase the value
+    * 3. if the expectedCurrentValue != 0 then just return the current value.
+    *    Otherwise wait for the other thread to change the value and return the current value.
+    *    
+    * if waiting takes longer than timeout then throw an exception.
+    */
+   public int getReadLock(int expectedCurrentValue, long timeout)
+   {
+      long startTime = System.currentTimeMillis();
+      synchronized(instanceLock)
+      {
+         // make sure value has the expected value
+         while(expectedCurrentValue != this.value)
+         {
+            if (System.currentTimeMillis() - startTime > timeout)
+               throw new IllegalStateException("The method took too long.");
+            try
+            {
+               instanceLock.wait(timeout);
+            }
+            catch (InterruptedException e)
+            {
+            }            
+         }
+
+         // at this point value == expectedCurrentValue
+         if(expectedCurrentValue != this.value)
+            throw new IllegalStateException("Unexpected instance variable value. Expected " + expectedCurrentValue + " but was " + this.value);
+
+         // increase the value
+         ++this.value;
+         instanceLock.notify();
+         
+         if(expectedCurrentValue == 0)
+         {
+            // wait until the other thread increases the current value
+            startTime = System.currentTimeMillis();
+            while (this.value == expectedCurrentValue + 1)
+            {
+               if (System.currentTimeMillis() - startTime > timeout)
+                  throw new IllegalStateException("The method took too long.");
+
+               try
+               {
+                  instanceLock.wait(timeout);
+               }
+               catch (InterruptedException e)
+               {
+               }
+            }
+         }
+      }
+      
+      return this.value;
+   }
 }

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-09 12:37:20 UTC (rev 79301)
+++ projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonLockInterceptor.java	2008-10-09 14:46:40 UTC (rev 79302)
@@ -23,6 +23,7 @@
 
 import org.jboss.aop.joinpoint.Invocation;
 import org.jboss.aop.joinpoint.MethodInvocation;
+import org.jboss.ejb3.EJBContainer;
 import org.jboss.ejb3.aop.AbstractInterceptor;
 import org.jboss.logging.Logger;
 
@@ -46,8 +47,8 @@
 
    public Object invoke(Invocation invocation) throws Throwable
    {
+      EJBContainer container = getEJBContainer(invocation);
       /* way to get to the metadata and determine whether the method has READ or WRITE lock
-      EJBContainer container = getEJBContainer(invocation);
       JBossEnterpriseBeanMetaData xml = container.getXml();
       if(xml != null)
          log.info("metadata is available");
@@ -57,7 +58,11 @@
       boolean isReadMethod = false;
       MethodInvocation mi = (MethodInvocation) invocation;
       if(mi.getMethod() != null)
-         isReadMethod = mi.getMethod().getName().startsWith("get");
+      {
+         String methodName = mi.getMethod().getName();
+         isReadMethod = methodName.startsWith("get") || methodName.startsWith("is");
+         log.info(container.getEjbName() + '.' + methodName + " is read concurrency: " + isReadMethod);
+      }
       
       lock.sync();
       try

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-09 12:37:20 UTC (rev 79301)
+++ projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/SingletonRemote.java	2008-10-09 14:46:40 UTC (rev 79302)
@@ -29,7 +29,19 @@
  */
 public interface SingletonRemote
 {
+   /**
+    * @return current number of created instances (must always be 1)
+    */
    int getInstanceCount();
 
-   void testWriteLock(long pause);
+   /**
+    * This method demonstrates that once one thread is entered an instance method
+    * no other thread can enter any method of the same instance in case of write concurrency.
+    */
+   void writeLock(long pause);
+   
+   /**
+    * This method demonstrates that two threads can be active in the same session bean instance in case of read concurrency.
+    */
+   int getReadLock(int expectedCurrentValue, long timeout);
 }

Modified: projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/pool/SingletonPool.java
===================================================================
--- projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/pool/SingletonPool.java	2008-10-09 12:37:20 UTC (rev 79301)
+++ projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/pool/SingletonPool.java	2008-10-09 14:46:40 UTC (rev 79302)
@@ -21,8 +21,9 @@
  */
 package org.jboss.ejb3.test.singleton.pool;
 
+import org.jboss.ejb3.BeanContext;
 import org.jboss.ejb3.Container;
-import org.jboss.ejb3.pool.StrictMaxPool;
+import org.jboss.ejb3.pool.AbstractPool;
 
 /**
  * A SingletonPool.
@@ -30,11 +31,57 @@
  * @author <a href="alex at jboss.com">Alexey Loubyansky</a>
  * @version $Revision: 1.1 $
  */
-public class SingletonPool extends StrictMaxPool
+public class SingletonPool extends AbstractPool
 {
+   private BeanContext<?> instance;
+   
    @Override
    public void initialize(Container container, int maxSize, long timeout)
    {
-      super.initialize(container, 1, 11000);
+      super.initialize(container, 1, timeout);
+      instance = create(null, null);
+      System.out.println("SingletonPool.initialize: maxSize=" + maxSize);
    }
+   
+   @Override
+   public void setMaxSize(int maxSize)
+   {
+      if(maxSize != 1)
+         throw new IllegalArgumentException("Maximum size for this pool must be 1: " + maxSize);
+   }
+
+   public void destroy()
+   {
+      if(instance != null)
+         discard(instance);
+   }
+
+   public BeanContext<?> get()
+   {
+      return instance;
+   }
+
+   public BeanContext<?> get(Class<?>[] initTypes, Object[] initValues)
+   {
+      return instance;
+   }
+
+   public int getAvailableCount()
+   {
+      return 1;
+   }
+
+   public int getCurrentSize()
+   {
+      return getCreateCount() - getRemoveCount();
+   }
+
+   public int getMaxSize()
+   {
+      return 1;
+   }
+
+   public void release(BeanContext<?> obj)
+   {
+   }
 }

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-09 12:37:20 UTC (rev 79301)
+++ projects/ejb3/trunk/testsuite/src/test/java/org/jboss/ejb3/test/singleton/unit/SingletonUnitTestCase.java	2008-10-09 14:46:40 UTC (rev 79302)
@@ -66,7 +66,11 @@
       undeploy("singleton-test.jar");
    }
    
-   public void testWriteLock() throws Exception
+   /**
+    * This method demonstrates that once one thread is entered an instance method
+    * no other thread can enter any method of the same instance in case of write concurrency.
+    */
+   public void testWriteConcurrency() throws Exception
    {
       final SingletonRemote remote = (SingletonRemote) getInitialContext().lookup("SingletonBean/remote");
 
@@ -81,7 +85,7 @@
             {
                try
                {
-                  remote.testWriteLock((long) (1000*Math.random()));
+                  remote.writeLock((long) (1000*Math.random()));
                }
                catch(Throwable t)
                {
@@ -123,4 +127,66 @@
       assertNull("One of the threads failed: " + sawFailedThread[0], sawFailedThread[0]);
       assertEquals(1, remote.getInstanceCount());
    }
+
+   /**
+    * This method demonstrates that two threads can be active in the same session bean instance in case of read concurrency.
+    */
+   public void testReadConcurrency() throws Throwable
+   {
+      final SingletonRemote remote = (SingletonRemote) getInitialContext().lookup("SingletonBean/remote");
+
+      final Throwable error[] = new Throwable[1];
+      final int[] results = new int[2];
+      final Thread[] threads = new Thread[2];
+      for(int i = 0; i < threads.length; ++i)
+      {
+         final int threadIndex = i;
+         threads[i] = new Thread(new Runnable()
+         {
+            public void run()
+            {
+               try
+               {
+                  results[threadIndex] = remote.getReadLock(threadIndex, 1000);
+               }
+               catch(Throwable t)
+               {
+                  log.error(t);
+                  error[0] = t;
+               }
+               finally
+               {
+                  synchronized (results)
+                  {
+                     results.notify();
+                  }
+               }
+            }
+         });
+      }
+
+      for(int i = 0; i < threads.length; ++i)
+         threads[i].start();
+
+      synchronized(results)
+      {
+         while((results[0] == 0 || results[1] == 0) && error[0] == null)
+         {
+            try
+            {
+               results.wait();
+            }
+            catch(InterruptedException e)
+            {
+            }
+         }
+      }
+
+      if(error[0] != null)
+         throw error[0];
+      
+      assertEquals(2, results[0]);
+      assertEquals(2, results[1]);
+      assertEquals(1, remote.getInstanceCount());
+   }
 }




More information about the jboss-cvs-commits mailing list