[jboss-cvs] JBossAS SVN: r112502 - in projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src: test/java/org/jboss/ejb3/core/test and 2 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Sun Dec 4 23:54:07 EST 2011
Author: jameslivingston
Date: 2011-12-04 23:54:07 -0500 (Sun, 04 Dec 2011)
New Revision: 112502
Added:
projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/test/java/org/jboss/ejb3/core/test/jbpapp7523/
projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/test/java/org/jboss/ejb3/core/test/jbpapp7523/SimpleSFSB.java
projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/test/java/org/jboss/ejb3/core/test/jbpapp7523/unit/
projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/test/java/org/jboss/ejb3/core/test/jbpapp7523/unit/SimpleCachePassivationDeadlockTestCase.java
Modified:
projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/main/java/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java
Log:
apply backported patch for JBPAPP7523
Modified: projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/main/java/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java
===================================================================
--- projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/main/java/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java 2011-12-05 03:54:53 UTC (rev 112501)
+++ projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/main/java/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java 2011-12-05 04:54:07 UTC (rev 112502)
@@ -21,14 +21,17 @@
*/
package org.jboss.ejb3.cache.simple;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Queue;
-import java.util.Map.Entry;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
-
import javax.ejb.EJBException;
import javax.ejb.NoSuchEJBException;
@@ -68,6 +71,8 @@
private Queue<StatefulBeanContext> passivationQueue = new LinkedBlockingQueue<StatefulBeanContext>();
+ private Map<Object, FutureTask<StatefulBeanContext>> activations = new HashMap<Object, FutureTask<StatefulBeanContext>>();
+
protected class CacheMap extends LinkedHashMap<Object, StatefulBeanContext>
{
private static final long serialVersionUID = 4514182777643616159L;
@@ -430,7 +435,7 @@
return get(key, true);
}
- public StatefulBeanContext get(Object key, boolean markInUse) throws EJBException
+ public StatefulBeanContext get(final Object key, boolean markInUse) throws EJBException
{
StatefulBeanContext entry = null;
synchronized (cacheMap)
@@ -465,34 +470,69 @@
}
if (entry == null)
{
+ // JBPAPP-7523: create a task for activation while holding the a lock,
+ // then execute said task outside the lock
+ FutureTask<StatefulBeanContext> activation;
+ final boolean executeActivation;
synchronized(pm)
{
- synchronized (cacheMap)
+ activation = activations.get(key);
+ if (activation == null)
{
- entry = cacheMap.get(key);
- }
- if(entry == null)
- {
- entry = pm.activateSession(key);
- if (entry == null)
+ activation = new FutureTask<StatefulBeanContext>(new Callable<StatefulBeanContext>()
{
- throw new NoSuchEJBException("Could not find stateful bean: " + key);
- }
- --passivatedCount;
-
- // We cache the entry even if we will throw an exception below
- // as we may still need it for its children and XPC references
- if (log.isTraceEnabled())
- {
- log.trace("Caching activated context " + entry.getId() + " of type " + entry.getClass());
- }
-
- synchronized (cacheMap)
- {
- cacheMap.put(key, entry);
- }
+ @Override
+ public StatefulBeanContext call() throws Exception {
+ StatefulBeanContext entry;
+ synchronized (cacheMap)
+ {
+ entry = cacheMap.get(key);
+ }
+ if(entry == null)
+ {
+ entry = pm.activateSession(key);
+ if (entry == null)
+ {
+ throw new NoSuchEJBException("Could not find stateful bean: " + key);
+ }
+ --passivatedCount;
+
+ // We cache the entry even if we will throw an exception below
+ // as we may still need it for its children and XPC references
+ if (log.isTraceEnabled())
+ {
+ log.trace("Caching activated context " + entry.getId() + " of type " + entry.getClass());
+ }
+
+ synchronized (cacheMap)
+ {
+ cacheMap.put(key, entry);
+ }
+ }
+ return entry;
+ }
+ });
+ activations.put(key, activation);
+ executeActivation = true;
}
+ else
+ executeActivation = false;
}
+ if (executeActivation)
+ activation.run();
+ try {
+ entry = activation.get();
+ }
+ catch (InterruptedException e)
+ {
+ throw new EJBException(e);
+ }
+ catch (ExecutionException e)
+ {
+ if (e.getCause() instanceof RuntimeException)
+ throw (RuntimeException) e.getCause();
+ throw (EJBException) new EJBException().initCause(e.getCause());
+ }
}
// Now we know entry isn't null
Added: projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/test/java/org/jboss/ejb3/core/test/jbpapp7523/SimpleSFSB.java
===================================================================
--- projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/test/java/org/jboss/ejb3/core/test/jbpapp7523/SimpleSFSB.java (rev 0)
+++ projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/test/java/org/jboss/ejb3/core/test/jbpapp7523/SimpleSFSB.java 2011-12-05 04:54:07 UTC (rev 112502)
@@ -0,0 +1,13 @@
+package org.jboss.ejb3.core.test.jbpapp7523;
+
+import javax.ejb.Stateful;
+
+import org.jboss.ejb3.annotation.CacheConfig;
+
+/**
+ * @author <a href="mailto:cdewolf at redhat.com">Carlo de Wolf</a>
+ */
+ at Stateful
+ at CacheConfig(maxSize = 1) // passivate on second creation
+public class SimpleSFSB {
+}
Added: projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/test/java/org/jboss/ejb3/core/test/jbpapp7523/unit/SimpleCachePassivationDeadlockTestCase.java
===================================================================
--- projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/test/java/org/jboss/ejb3/core/test/jbpapp7523/unit/SimpleCachePassivationDeadlockTestCase.java (rev 0)
+++ projects/ejb3/branches/jboss-ejb3-core-1.3.7_JBPAPP-7602/src/test/java/org/jboss/ejb3/core/test/jbpapp7523/unit/SimpleCachePassivationDeadlockTestCase.java 2011-12-05 04:54:07 UTC (rev 112502)
@@ -0,0 +1,149 @@
+package org.jboss.ejb3.core.test.jbpapp7523.unit;
+
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.jboss.ejb3.cache.simple.SimpleStatefulCache;
+import org.jboss.ejb3.core.test.common.AbstractEJB3TestCase;
+import org.jboss.ejb3.core.test.jbpapp7523.SimpleSFSB;
+import org.jboss.ejb3.session.SessionContainer;
+import org.jboss.ejb3.stateful.StatefulBeanContext;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.junit.Assert.fail;
+
+/**
+ * @author <a href="mailto:cdewolf at redhat.com">Carlo de Wolf</a>
+ */
+public class SimpleCachePassivationDeadlockTestCase extends AbstractEJB3TestCase {
+ private static SessionContainer container;
+
+ private static SimpleStatefulCache cache;
+
+ private static final CyclicBarrier barrier = new CyclicBarrier(2);
+
+ private ExecutorService service;
+
+ @After
+ public void after() {
+ service.shutdown();
+ }
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ cache.stop();
+
+ undeployEjb(container);
+
+ AbstractEJB3TestCase.afterClass();
+ }
+
+ private static int await(final CyclicBarrier barrier, final long timeout, final TimeUnit unit) {
+ try {
+ return barrier.await(timeout, unit);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } catch (BrokenBarrierException e) {
+ throw new RuntimeException(e);
+ } catch (TimeoutException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Before
+ public void before() {
+ service = Executors.newFixedThreadPool(2);
+ }
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ AbstractEJB3TestCase.beforeClass();
+
+ // Deploy the test SLSB
+ container = deploySessionEjb(SimpleSFSB.class);
+
+ cache = new SimpleStatefulCache() {
+ protected void passivate(final StatefulBeanContext ctx) {
+ if (!barrier.isBroken())
+ await(barrier, 10, SECONDS);
+ //await(barrier, 10, SECONDS);
+ super.passivate(ctx);
+ }
+ };
+ cache.initialize(container);
+ cache.start();
+ }
+
+ @Test
+ public void testSmallCacheCreates() throws Exception {
+ // Fill the cache.
+ final StatefulBeanContext bean1 = cache.create();
+ cache.release(bean1);
+ final Future<StatefulBeanContext> futureBean2 = service.submit(new Callable<StatefulBeanContext>() {
+ @Override
+ public StatefulBeanContext call() throws Exception {
+ final StatefulBeanContext ctx = cache.create();
+ cache.release(ctx);
+ return ctx;
+ }
+ });
+ // Force bean1 in the first cacheMap sync.
+ final Future<StatefulBeanContext> futureBean1 = service.submit(new Callable<StatefulBeanContext>() {
+ @Override
+ public StatefulBeanContext call() throws Exception {
+ return cache.get(bean1.getId());
+ }
+ });
+ // Setup another create run to lock the cacheMap after bean1 proceeds.
+ final Future<StatefulBeanContext> futureBean3 = service.submit(new Callable<StatefulBeanContext>() {
+ @Override
+ public StatefulBeanContext call() throws Exception {
+ final StatefulBeanContext ctx = cache.create();
+ cache.release(ctx);
+ return ctx;
+ }
+ });
+ // Go bean 2! This will make either bean1 or bean3 move forward as well.
+ barrier.await(10, SECONDS);
+ // Either bean1 should be at SimpleStatefulCachemap:492 (or bean3 moved).
+ // Since there is nothing in SimpleStatefulCache.get where we can control movement, we can only hope.
+ /*
+ final Future<StatefulBeanContext> futureBean4 = service.submit(new Callable<StatefulBeanContext>() {
+ @Override
+ public StatefulBeanContext call() throws Exception {
+ final StatefulBeanContext ctx = cache.create();
+ cache.release(ctx);
+ return ctx;
+ }
+ });
+ */
+ // Go bean 3!
+ barrier.await(10, SECONDS);
+ // Break the barrier (bean3 needs to be passivated to make room for bean1).
+ try {
+ barrier.await(0, SECONDS);
+ } catch (TimeoutException e) {
+ // good
+ }
+ // Now we should have a response within 10 seconds.
+ try {
+ futureBean1.get(10, SECONDS);
+ } catch (TimeoutException e) {
+ fail("JBPAPP-7523: cache failed to respond in time");
+ }
+ futureBean2.get(10, SECONDS);
+ futureBean3.get(10, SECONDS);
+ //futureBean4.get(10, SECONDS);
+ }
+}
More information about the jboss-cvs-commits
mailing list