[jboss-cvs] JBossAS SVN: r60248 - branches/Branch_4_2/ejb3/src/main/org/jboss/ejb3/cache/tree.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Sun Feb 4 00:05:42 EST 2007


Author: bstansberry at jboss.com
Date: 2007-02-04 00:05:42 -0500 (Sun, 04 Feb 2007)
New Revision: 60248

Modified:
   branches/Branch_4_2/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java
Log:
Sync up with trunk

Modified: branches/Branch_4_2/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java
===================================================================
--- branches/Branch_4_2/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java	2007-02-04 04:59:10 UTC (rev 60247)
+++ branches/Branch_4_2/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java	2007-02-04 05:05:42 UTC (rev 60248)
@@ -21,7 +21,7 @@
  */
 package org.jboss.ejb3.cache.tree;
 
-import java.util.HashMap;
+import java.util.Set;
 
 import javax.ejb.EJBException;
 import javax.ejb.NoSuchEJBException;
@@ -35,12 +35,13 @@
 import org.jboss.cache.CacheException;
 import org.jboss.cache.AbstractTreeCacheListener;
 import org.jboss.cache.DataNode;
-import org.jboss.cache.Node;
 import org.jboss.cache.TreeCache;
 import org.jboss.cache.TreeCacheMBean;
 import org.jboss.ejb3.Container;
+import org.jboss.ejb3.EJBContainer;
 import org.jboss.ejb3.Pool;
 import org.jboss.ejb3.cache.ClusteredStatefulCache;
+import org.jboss.ejb3.stateful.ProxiedStatefulBeanContext;
 import org.jboss.ejb3.stateful.StatefulBeanContext;
 import org.jboss.mx.util.MBeanProxyExt;
 import org.jboss.mx.util.MBeanServerLocator;
@@ -77,7 +78,7 @@
       try
       {
          ctx = (StatefulBeanContext) pool.get();
-         cache.put(cacheNode + "/" + ctx.getId(), "bean", ctx);
+         cache.put(new Fqn(cacheNode, ctx.getId().toString()), "bean", ctx);
          ctx.inUse = true;
          ctx.lastUsed = System.currentTimeMillis();
          ++createCount;
@@ -99,7 +100,7 @@
       try
       {
          ctx = (StatefulBeanContext) pool.get(initTypes, initValues);
-         Fqn id = Fqn.fromString(cacheNode + "/" + ctx.getId());
+         Fqn id = new Fqn(cacheNode, ctx.getId().toString());
          cache.put(id, "bean", ctx);
          ctx.inUse = true;
          ctx.lastUsed = System.currentTimeMillis();
@@ -119,7 +120,7 @@
    public StatefulBeanContext get(Object key) throws EJBException
    {
       StatefulBeanContext entry = null;
-      Fqn id = Fqn.fromString(cacheNode + "/" +key);
+      Fqn id = new Fqn(cacheNode, key.toString());
       try
       {
          Object obj = cache.get(id, "bean");
@@ -127,7 +128,8 @@
       }
       catch (CacheException e)
       {
-         throw new RuntimeException(e);
+         RuntimeException re = convertToRuntimeException(e);
+         throw re;
       }
       if (entry == null)
       {
@@ -136,32 +138,33 @@
       entry.inUse = true;
       // Mark it to eviction thread that don't passivate it yet.
       evictRegionManager.markNodeCurrentlyInUse(id, MarkInUseWaitTime);
-      if(log.isDebugEnabled())
+      entry.lastUsed = System.currentTimeMillis();
+      
+      if(log.isTraceEnabled())
       {
-         log.debug("get: retrieved bean with cache id " +id.toString());
+         log.trace("get: retrieved bean with cache id " +id.toString());
       }
-
-      entry.lastUsed = System.currentTimeMillis();
       return entry;
    }
 
    public void remove(Object key)
    {
       StatefulBeanContext ctx = null;
-      Fqn id = Fqn.fromString(cacheNode + "/" +key);
+      Fqn id = new Fqn(cacheNode, key.toString());
       try
       {
-         if(log.isDebugEnabled())
+         if(log.isTraceEnabled())
          {
-            log.debug("remove: cache id " +id.toString());
+            log.trace("remove: cache id " +id.toString());
          }
          cache.remove(id);
       }
       catch (CacheException e)
       {
-         throw new RuntimeException(e);
+         RuntimeException re = convertToRuntimeException(e);
+         throw re;
       }
-//      if (ctx != null) pool.remove(ctx);
+      if (ctx != null) pool.remove(ctx);
    }
 
    public void finished(StatefulBeanContext ctx)
@@ -170,7 +173,7 @@
       {
          ctx.inUse = false;
          ctx.lastUsed = System.currentTimeMillis();
-         Fqn id = Fqn.fromString(cacheNode + "/" + ctx.getId());
+         Fqn id = new Fqn(cacheNode, ctx.getId().toString());
          // OK, it is free to passivate now.
          evictRegionManager.unmarkNodeCurrentlyInUse(id);
       }
@@ -180,11 +183,24 @@
    {
       try
       {
-         cache.put(cacheNode + "/" + ctx.getId(), "bean", ctx);
+         // Don't replicate proxies, as they are in the cache
+         // as elements of their containing bean context
+         // TODO -- if this is a ProxiedStatefulBeanContext
+         // should we replicate the parent context, since that's where
+         // the data is? 
+         if (!(ctx instanceof ProxiedStatefulBeanContext))
+         {
+            cache.put(new Fqn(cacheNode, ctx.getId().toString()), "bean", ctx);
+         }
+         else if (log.isTraceEnabled())
+         {
+            log.trace("replicate(): ignoring replicate call for proxy to " + ctx.getId());
+         }
       }
       catch (CacheException e)
       {
-         throw new RuntimeException(e);
+         RuntimeException re = convertToRuntimeException(e);
+         throw re;
       }
    }
 
@@ -218,9 +234,11 @@
 
    public void start()
    {
-      // register to listen for cache event
-      // TODO this approach may not be scalable when there are many beans since then we will need to go thru
-      // N listeners to figure out which this event this belongs to.
+      // register to listen for cache events
+      
+      // TODO this approach may not be scalable when there are many beans 
+      // since then we will need to go thru N listeners to figure out which 
+      // one this event belongs to. Consider having a singleton listener
       listener = new ClusteredStatefulCacheListener();
       cache.addTreeCacheListener(listener);
    }
@@ -229,29 +247,39 @@
    {
       // Remove the listener
       cache.removeTreeCacheListener(listener);
+      
+      // BES 11/16/2006 uncomment if we switch to per-region marshalling
+      // If we do, we don't need to remove the node below; deactivate() does it
+//      if (region != null)
+//      {
+//         region.deactivate();
+//         region.unregisterContextClassLoader();
+//      }
 
+      // Remove the eviction region
+      RegionManager rm = cache.getEvictionRegionManager();
+      rm.removeRegion(cacheNode);
+
       Option opt = new Option();
       opt.setCacheModeLocal(true);
       try {
          // remove locally.
          cache.remove(cacheNode, opt);
-      } catch (CacheException e) {
+      } 
+      catch (CacheException e) 
+      {
          log.error("Stop(): can't remove bean from the underlying distributed cache");
       }
 
-      // Remove the eviction region
-      RegionManager rm = cache.getEvictionRegionManager();
-      rm.removeRegion(cacheNode);
-
-      log.info("stop(): StatefulTreeCache stopped successfully for " +cacheNode);
+      log.debug("stop(): StatefulTreeCache stopped successfully for " +cacheNode);
    }
    
    public int getCacheSize()
    {
 	   try 
 	   {
-		   Node node = cache.get(cacheNode);
-		   return node.getChildren().size();
+		   Set children = cache.getChildrenNames(cacheNode);
+		   return (children == null ? 0 : children.size());
 	   } catch (CacheException e)
 	   {
 		   e.printStackTrace();
@@ -268,71 +296,127 @@
    {
 	   return passivatedCount;
    }
+   
+   /** 
+    * Creates a RuntimeException, but doesn't pass CacheException as the cause
+    * as it is a type that likely doesn't exist on a client.
+    * Instead creates a RuntimeException with the original exception's
+    * stack trace.
+    */   
+   private RuntimeException convertToRuntimeException(CacheException e)
+   {
+      RuntimeException re = new RuntimeException(e.getClass().getName() + " " + e.getMessage());
+      re.setStackTrace(e.getStackTrace());
+      return re;
+   }
 
    /**
-    * A TreeCacheListener. Note that extends it from AbstractTreeCacheListener is a bit heavy since
-    * it will get all the treecache events (instead of just passivation/activation). But we will have to
-    * wait untill JBossCache2.0 for the refactoring then.
+    * A TreeCacheListener that allows us to get notifications of passivations and
+    * activations and thus notify the cached StatefulBeanContext.
     */
    public class ClusteredStatefulCacheListener extends AbstractTreeCacheListener
    {
       protected Logger log = Logger.getLogger(ClusteredStatefulCacheListener.class);
 
-      public void nodeActivate(Fqn fqn, boolean pre) {
-         if(pre) return;  // we are not interested in postActivate event
+      @Override
+      public void nodeActivate(Fqn fqn, boolean pre) 
+      {
+         // Ignore everything but "post" events for nodes in our region
+         if(pre) return;
          if(fqn.size() != FQN_SIZE) return;
-         if(!fqn.isChildOrEquals(cacheNode)) return;  // don't care about fqn that doesn't belong to me.
+         if(!fqn.isChildOrEquals(cacheNode)) return;
 
          StatefulBeanContext bean = null;
          try {
             // TODO Can this cause deadlock in the cache level? Should be ok but need review.
             bean = (StatefulBeanContext) cache.get(fqn, "bean");    
-         } catch (CacheException e) {
+         } 
+         catch (CacheException e) 
+         {
             log.error("nodeActivate(): can't retrieve bean instance from: " +fqn + " with exception: " +e);
             return;
          }
+         
          if(bean == null)
          {
-            throw new IllegalStateException("StatefuleTreeCache.nodeActivate(): null bean instance.");
+            throw new IllegalStateException("nodeActivate(): null bean instance.");
          }
          
          --passivatedCount;
 
-//         log.debug("nodeActivate(): send postActivate event on fqn: " +fqn);
          if(log.isTraceEnabled())
          {
-            log.trace("nodeActivate(): send postActivate event on fqn: " +fqn);
+            log.trace("nodeActivate(): sending postActivate event on fqn: " +fqn);
          }
 
          bean.postActivate();
       }
 
-      public void nodePassivate(Fqn fqn, boolean pre) {
-         if(!pre) return;  // we are not interested in postPassivate event
+      @Override
+      public void nodePassivate(Fqn fqn, boolean pre) 
+      {
+         // Ignore everything but "pre" events for nodes in our region
+         if(!pre) return;
          if(fqn.size() != FQN_SIZE) return;
-         if(!fqn.isChildOrEquals(cacheNode)) return;  // don't care about fqn that doesn't belong to me.
+         if(!fqn.isChildOrEquals(cacheNode)) return;
 
-         try {
-            // TODO Can this cause deadlock in the cache level? Should be ok but need review.
-            Node node = cache.get(fqn);
-            StatefulBeanContext bean = (StatefulBeanContext) node.getData().get("bean");
-            if (bean != null)
+         StatefulBeanContext bean = null;
+         try 
+         {
+            // EJBTHREE-746 Use peek to bypass interceptors and thus avoid generating another 
+            // eviction event (which will cause another attempt to passivate)
+            // Caller thread (eviction) already has a lock on the node
+            // With JBC 2.0 there is a BypassInterceptors Option we can use
+            DataNode node = cache.peek(fqn);
+            if (node != null)
             {
-               bean.prePassivate();
-               ++passivatedCount;
+               bean = (StatefulBeanContext) node.get("bean");
+               if (bean != null)
+               {
+                  if (bean.inUse)
+                  {
+                     // Abort the eviction
+                     throw new IllegalStateException("Cannot passivate bean " + fqn + " -- it is currently in use");                     
+                  }
+                  if(log.isTraceEnabled())
+                  {
+                     log.trace("nodePassivate(): send prePassivate event to bean at fqn: " +fqn);
+                  }
+                  bean.prePassivate();
+                  ++passivatedCount;
+               }
             }
-
-         } catch (CacheException e) {
-            log.error("nodePassivate(): can't retrieve bean instance from: " +fqn + " with exception: " +e);
-            return;
          }
-
-//         log.debug("nodePassivate(): send prePassivate event on fqn: " +fqn);
-         if(log.isTraceEnabled())
+         catch (NoSuchEJBException e)
          {
-            log.trace("nodePassivate(): send prePassivate event on fqn: " +fqn);
+            if (bean instanceof ProxiedStatefulBeanContext)
+            {
+               // This is probably an orphaned proxy; double check and remove it
+               try
+               {
+                  bean.getContainedIn();
+                  // If that didn't fail, it's not an orphan
+                  throw e;
+               }
+               catch (NoSuchEJBException n)
+               {
+                  log.debug("nodePassivate(): removing orphaned proxy at " + fqn);
+                  try
+                  {
+                     cache.remove(fqn);
+                  }
+                  catch (CacheException c)
+                  {
+                     log.error("nodePassivate(): could not remove orphaned proxy at " + fqn, c);
+                     // Just fall through and let the eviction try
+                  }
+               }
+            }
+            else
+            {
+               throw e;
+            }
          }
-
       }
    }
 }




More information about the jboss-cvs-commits mailing list