[jbosscache-commits] JBoss Cache SVN: r7195 - in core/trunk/src/main/java/org/jboss/cache: interceptors and 1 other directory.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Tue Nov 25 06:48:34 EST 2008


Author: manik.surtani at jboss.com
Date: 2008-11-25 06:48:32 -0500 (Tue, 25 Nov 2008)
New Revision: 7195

Modified:
   core/trunk/src/main/java/org/jboss/cache/InvocationContext.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyActivationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyCacheLoaderInterceptor.java
Log:
Detection of whether a node is loaded, and accordingly optimize activation

Modified: core/trunk/src/main/java/org/jboss/cache/InvocationContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/InvocationContext.java	2008-11-25 11:08:02 UTC (rev 7194)
+++ core/trunk/src/main/java/org/jboss/cache/InvocationContext.java	2008-11-25 11:48:32 UTC (rev 7195)
@@ -34,9 +34,11 @@
 
 import javax.transaction.Transaction;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * A context that holds information regarding the scope of a single invocation.  May delegate some calls to a {@link org.jboss.cache.transaction.TransactionContext}
@@ -67,6 +69,8 @@
    @Deprecated
    private VisitableCommand command;
 
+   private Set<Fqn> fqnsLoaded;
+
    /**
     * LinkedHashSet of locks acquired by the invocation. We use a LinkedHashSet because we need efficient Set semantics
     * but also need guaranteed ordering for use by lock release code (see JBCCACHE-874).
@@ -415,6 +419,7 @@
       invocationLocks = null;
       methodCall = null;
       command = null;
+      fqnsLoaded = null;
    }
 
    /**
@@ -549,7 +554,9 @@
       if (!shouldRethtrow)
       {
          if (trace)
+         {
             log.trace("There was a problem handling this request, but failSilently was set, so suppressing exception", e);
+         }
          return;
       }
       throw e;
@@ -568,6 +575,22 @@
       copy.transactionContext = transactionContext;
    }
 
+   public void addFqnLoaded(Fqn fqn)
+   {
+      if (fqnsLoaded == null) fqnsLoaded = new HashSet<Fqn>();
+      fqnsLoaded.add(fqn);
+   }
+
+   public Set<Fqn> getFqnsLoaded()
+   {
+      return fqnsLoaded;
+   }
+
+   public void setFqnsLoaded(Set<Fqn> fqnsLoaded)
+   {
+      this.fqnsLoaded = fqnsLoaded;
+   }
+
    @Override
    public String toString()
    {

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java	2008-11-25 11:08:02 UTC (rev 7194)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java	2008-11-25 11:48:32 UTC (rev 7195)
@@ -32,7 +32,13 @@
 import org.jboss.cache.commands.read.GetNodeCommand;
 import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
 import org.jboss.cache.commands.tx.PrepareCommand;
-import org.jboss.cache.commands.write.*;
+import org.jboss.cache.commands.write.ClearDataCommand;
+import org.jboss.cache.commands.write.MoveCommand;
+import org.jboss.cache.commands.write.PutDataMapCommand;
+import org.jboss.cache.commands.write.PutForExternalReadCommand;
+import org.jboss.cache.commands.write.PutKeyValueCommand;
+import org.jboss.cache.commands.write.RemoveKeyCommand;
+import org.jboss.cache.commands.write.RemoveNodeCommand;
 import org.jboss.cache.factories.annotations.Inject;
 import org.jboss.cache.factories.annotations.Start;
 import org.jboss.cache.jmx.annotations.ManagedAttribute;
@@ -42,7 +48,11 @@
 
 import javax.transaction.SystemException;
 import javax.transaction.TransactionManager;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -53,308 +63,386 @@
  * @author <a href="mailto:{hmesha at novell.com}">{Hany Mesha}</a>
  * @version $Id$
  */
-public class ActivationInterceptor extends CacheLoaderInterceptor {
+public class ActivationInterceptor extends CacheLoaderInterceptor
+{
 
-    protected TransactionManager txMgr = null;
-    private long activations = 0;
-    ActivationModificationsBuilder builder;
+   protected TransactionManager txMgr = null;
+   private long activations = 0;
+   ActivationModificationsBuilder builder;
 
-    /**
-     * List<Transaction> that we have registered for
-     */
-    protected ConcurrentHashMap transactions = new ConcurrentHashMap(16);
-    protected static final Object NULL = new Object();
+   /**
+    * List<Transaction> that we have registered for
+    */
+   protected ConcurrentHashMap transactions = new ConcurrentHashMap(16);
+   protected static final Object NULL = new Object();
 
-    public ActivationInterceptor() {
-        isActivation = true;
-        useCacheStore = false;
-    }
+   public ActivationInterceptor()
+   {
+      isActivation = true;
+      useCacheStore = false;
+   }
 
-    @Inject
-    public void injectTransactionManager(TransactionManager txMgr) {
-        this.txMgr = txMgr;
-    }
+   @Inject
+   public void injectTransactionManager(TransactionManager txMgr)
+   {
+      this.txMgr = txMgr;
+   }
 
-    @Start
-    public void createModificationsBuilder() {
-        builder = new ActivationModificationsBuilder();
-    }
+   @Start
+   public void createModificationsBuilder()
+   {
+      builder = new ActivationModificationsBuilder();
+   }
 
-    @Override
-    public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable {
-        Object returnValue = super.visitClearDataCommand(ctx, command);
-        if (trace)
-            log.trace("This is a remove data operation; removing the data from the loader, no activation processing needed.");
-        loader.removeData(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
+   {
+      Object returnValue = super.visitClearDataCommand(ctx, command);
+      if (trace)
+      {
+         log.trace("This is a remove data operation; removing the data from the loader, no activation processing needed.");
+      }
+      loader.removeData(command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand command) throws Throwable {
-        Object returnValue = super.visitRemoveNodeCommand(ctx, command);
-        if (trace)
-            log.trace("This is a remove operation; removing the node from the loader, no activation processing needed.");
-        loader.remove(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand command) throws Throwable
+   {
+      Object returnValue = super.visitRemoveNodeCommand(ctx, command);
+      if (trace)
+      {
+         log.trace("This is a remove operation; removing the node from the loader, no activation processing needed.");
+      }
+      loader.remove(command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitGetChildrenNamesCommand(InvocationContext ctx, GetChildrenNamesCommand command) throws Throwable {
-        Object returnValue = super.visitGetChildrenNamesCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitGetChildrenNamesCommand(InvocationContext ctx, GetChildrenNamesCommand command) throws Throwable
+   {
+      Object returnValue = super.visitGetChildrenNamesCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command) throws Throwable {
-        Object returnValue = super.visitGetKeysCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command) throws Throwable
+   {
+      Object returnValue = super.visitGetKeysCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command) throws Throwable {
-        Object returnValue = super.visitGetNodeCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command) throws Throwable
+   {
+      Object returnValue = super.visitGetNodeCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable {
-        Object returnValue = super.visitGetKeyValueCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable
+   {
+      Object returnValue = super.visitGetKeyValueCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitPutForExternalReadCommand(InvocationContext ctx, PutForExternalReadCommand command) throws Throwable {
-        return visitPutKeyValueCommand(ctx, command);
-    }
+   @Override
+   public Object visitPutForExternalReadCommand(InvocationContext ctx, PutForExternalReadCommand command) throws Throwable
+   {
+      return visitPutKeyValueCommand(ctx, command);
+   }
 
-    @Override
-    public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
-        Object returnValue = super.visitPutKeyValueCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
+   {
+      Object returnValue = super.visitPutKeyValueCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable {
-        Object returnValue = super.visitPutDataMapCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
+   {
+      Object returnValue = super.visitPutDataMapCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable {
-        Object returnValue = super.visitRemoveKeyCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable
+   {
+      Object returnValue = super.visitRemoveKeyCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitMoveCommand(InvocationContext ctx, MoveCommand command) throws Throwable {
-        Object returnValue = super.visitMoveCommand(ctx, command);
-        if (trace)
-            log.trace("This is a move operation; removing the FROM node from the loader, no activation processing needed.");
-        loader.remove(command.getFqn());
-        removeNodeFromCacheLoader(command.getFqn().getParent());
-        removeNodeFromCacheLoader(command.getTo());
-        return returnValue;
-    }
+   @Override
+   public Object visitMoveCommand(InvocationContext ctx, MoveCommand command) throws Throwable
+   {
+      Object returnValue = super.visitMoveCommand(ctx, command);
+      if (trace)
+      {
+         log.trace("This is a move operation; removing the FROM node from the loader, no activation processing needed.");
+      }
+      loader.remove(command.getFqn());
+      removeNodeFromCacheLoader(ctx, command.getFqn().getParent());
+      removeNodeFromCacheLoader(ctx, command.getTo());
+      return returnValue;
+   }
 
+   private boolean wasLoadedIntoMemory(InvocationContext ctx, Fqn fqn)
+   {
+      Set<Fqn> fqnsLoaded = ctx.getFqnsLoaded();
+      return fqnsLoaded != null && fqnsLoaded.contains(fqn);
+   }
 
-    /**
-     * Remove the node from the cache loader if it exists in memory,
-     * its attributes have been initialized, its children have been loaded,
-     * AND it was found in the cache loader (nodeLoaded = true).
-     */
-    private void removeNodeFromCacheLoader(Fqn fqn) throws Throwable {
-        if (fqn == null) return;
-        InternalNode n;
-        if (((n = dataContainer.peekInternalNode(fqn, true)) != null) && n.isDataLoaded()) {
+   /**
+    * Remove the node from the cache loader if it exists in memory,
+    * its attributes have been initialized, its children have been loaded,
+    * AND it was found in the cache loader (nodeLoaded = true).
+    */
+   private void removeNodeFromCacheLoader(InvocationContext ctx, Fqn fqn) throws Throwable
+   {
+      if (fqn != null && wasLoadedIntoMemory(ctx, fqn))
+      {
+         InternalNode n;
+         if (((n = dataContainer.peekInternalNode(fqn, true)) != null) && n.isDataLoaded() && loader.exists(fqn))
+         {
             // node not null and attributes have been loaded?
-            if (n.hasChildren()) {
-                boolean result = childrenLoaded(n);
-                if (result) {
-                    log.debug("children all initialized");
-                    remove(fqn);
-                }
-            } else if (loaderNoChildren(fqn)) {
-                if (log.isDebugEnabled()) log.debug("no children " + n);
-                remove(fqn);
+            if (n.hasChildren())
+            {
+               boolean result = childrenLoaded(n);
+               if (result)
+               {
+                  log.debug("children all initialized");
+                  remove(fqn);
+               }
             }
-        }
-    }
+            else if (loaderNoChildren(fqn))
+            {
+               if (log.isDebugEnabled()) log.debug("no children " + n);
+               remove(fqn);
+            }
+         }
+      }
+   }
 
-    private boolean childrenLoaded(InternalNode<?, ?> node) {
-        if (!node.isChildrenLoaded()) {
+   private boolean childrenLoaded(InternalNode<?, ?> node)
+   {
+      if (!node.isChildrenLoaded())
+      {
+         return false;
+      }
+      for (InternalNode child : node.getChildren())
+      {
+         if (!child.isDataLoaded())
+         {
             return false;
-        }
-        for (InternalNode child : node.getChildren()) {
-            if (!child.isDataLoaded()) {
-                return false;
-            }
+         }
 
-            if (child.hasChildren()) {
-                if (!childrenLoaded(child))
-                    return false;
-            } else if (!loaderNoChildren(child.getFqn())) {
-                return false;
+         if (child.hasChildren())
+         {
+            if (!childrenLoaded(child))
+            {
+               return false;
             }
-        }
-        return true;
+         }
+         else if (!loaderNoChildren(child.getFqn()))
+         {
+            return false;
+         }
+      }
+      return true;
 
-    }
+   }
 
-    @Override
-    public Object visitOptimisticPrepareCommand(InvocationContext ctx, OptimisticPrepareCommand command) throws Throwable {
-        Object retval = invokeNextInterceptor(ctx, command);
-        if (inTransaction()) {
-            prepareCacheLoader(ctx);
-        }
-        return retval;
-    }
+   @Override
+   public Object visitOptimisticPrepareCommand(InvocationContext ctx, OptimisticPrepareCommand command) throws Throwable
+   {
+      Object retval = invokeNextInterceptor(ctx, command);
+      if (inTransaction())
+      {
+         prepareCacheLoader(ctx);
+      }
+      return retval;
+   }
 
-    private boolean inTransaction() throws SystemException {
-        return txMgr != null && txMgr.getTransaction() != null;
-    }
+   private boolean inTransaction() throws SystemException
+   {
+      return txMgr != null && txMgr.getTransaction() != null;
+   }
 
-    @Override
-    public Object visitPrepareCommand(InvocationContext ctx, PrepareCommand command) throws Throwable {
-        Object retval = invokeNextInterceptor(ctx, command);
-        if (inTransaction()) {
-            prepareCacheLoader(ctx);
-        }
-        return retval;
-    }
+   @Override
+   public Object visitPrepareCommand(InvocationContext ctx, PrepareCommand command) throws Throwable
+   {
+      Object retval = invokeNextInterceptor(ctx, command);
+      if (inTransaction())
+      {
+         prepareCacheLoader(ctx);
+      }
+      return retval;
+   }
 
-    private void remove(Fqn fqn) throws Exception {
-        loader.remove(fqn);
-        if (getStatisticsEnabled()) activations++;
-    }
+   private void remove(Fqn fqn) throws Exception
+   {
+      loader.remove(fqn);
+      if (getStatisticsEnabled()) activations++;
+   }
 
-    /**
-     * Returns true if the loader indicates no children for this node.
-     * Return false on error.
-     */
-    private boolean loaderNoChildren(Fqn fqn) {
-        try {
-            Set childrenNames = loader.getChildrenNames(fqn);
-            return (childrenNames == null);
-        }
-        catch (Exception e) {
-            log.error("failed getting the children names for " + fqn + " from the cache loader", e);
-            return false;
-        }
-    }
+   /**
+    * Returns true if the loader indicates no children for this node.
+    * Return false on error.
+    */
+   private boolean loaderNoChildren(Fqn fqn)
+   {
+      try
+      {
+         Set childrenNames = loader.getChildrenNames(fqn);
+         return (childrenNames == null);
+      }
+      catch (Exception e)
+      {
+         log.error("failed getting the children names for " + fqn + " from the cache loader", e);
+         return false;
+      }
+   }
 
-    private void prepareCacheLoader(InvocationContext ctx) throws Throwable {
-        GlobalTransaction gtx = ctx.getGlobalTransaction();
-        TransactionContext tCtx = ctx.getTransactionContext();
-        if (tCtx == null) {
-            throw new Exception("tCtx for transaction " + gtx + " not found in transaction table");
-        }
-        List<Modification> cacheLoaderModifications = new ArrayList<Modification>();
+   private void prepareCacheLoader(InvocationContext ctx) throws Throwable
+   {
+      GlobalTransaction gtx = ctx.getGlobalTransaction();
+      TransactionContext tCtx = ctx.getTransactionContext();
+      if (tCtx == null)
+      {
+         throw new Exception("tCtx for transaction " + gtx + " not found in transaction table");
+      }
+      List<Modification> cacheLoaderModifications = new ArrayList<Modification>();
 
-        builder.visitCollection(ctx, tCtx.getModifications());
-        if (cacheLoaderModifications.size() > 0) {
-            loader.prepare(gtx, cacheLoaderModifications, false);
-        }
-    }
+      builder.visitCollection(ctx, tCtx.getModifications());
+      if (cacheLoaderModifications.size() > 0)
+      {
+         loader.prepare(gtx, cacheLoaderModifications, false);
+      }
+   }
 
-    public class ActivationModificationsBuilder extends AbstractVisitor {
+   public class ActivationModificationsBuilder extends AbstractVisitor
+   {
 
-        private List<Modification> cacheLoaderModifications = new ArrayList<Modification>();
+      private List<Modification> cacheLoaderModifications = new ArrayList<Modification>();
 
-        private int txActs = 0;
+      private int txActs = 0;
 
-        @Override
-        public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand removeNodeCommand) throws Throwable {
-            Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, removeNodeCommand.getFqn());
-            cacheLoaderModifications.add(mod);
-            return null;
-        }
+      @Override
+      public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand removeNodeCommand) throws Throwable
+      {
+         Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, removeNodeCommand.getFqn());
+         cacheLoaderModifications.add(mod);
+         return null;
+      }
 
-        @Override
-        public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable {
-            Fqn fqn = command.getFqn();
-            handlePutCommand(ctx, fqn);
-            return null;
-        }
+      @Override
+      public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
+      {
+         Fqn fqn = command.getFqn();
+         handlePutCommand(ctx, fqn);
+         return null;
+      }
 
-        @Override
-        public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
-            Fqn fqn = command.getFqn();
-            handlePutCommand(ctx, fqn);
-            return null;
-        }
+      @Override
+      public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
+      {
+         Fqn fqn = command.getFqn();
+         handlePutCommand(ctx, fqn);
+         return null;
+      }
 
-        // On the way out, remove the node from the cache loader.
-        // Only remove the node if it exists in memory, its attributes have
-        // been initialized, its children have been loaded
-        // AND it was found in the cache loader (nodeLoaded = true).
-        // Then notify the listeners that the node has been activated.
-        private void handlePutCommand(InvocationContext ctx, Fqn fqn)
-                throws Exception {
-            if (fqn != null && dataContainer.exists(fqn) && loader.exists(fqn)) {
-                InternalNode n = dataContainer.peekInternalNode(fqn, true);// don't load
-                // node not null and attributes have been loaded?
-                if (n != null && n.isDataLoaded()) {
-                    // has children?
-                    boolean result = childrenLoaded(n);
-                    if (n.hasChildren() && result) {
-                        // children have been loaded, remove the node
-                        addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getData());
-                        txActs++;
-                    }
-                    // doesn't have children, check the cache loader
-                    else if (loaderNoChildren(fqn)) {
-                        addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getData());
-                        txActs++;
-                    }
-                }
+      // On the way out, remove the node from the cache loader.
+      // Only remove the node if it exists in memory, its attributes have
+      // been initialized, its children have been loaded
+      // AND it was found in the cache loader (nodeLoaded = true).
+      // Then notify the listeners that the node has been activated.
+      private void handlePutCommand(InvocationContext ctx, Fqn fqn)
+            throws Exception
+      {
+         if (fqn != null && dataContainer.exists(fqn) && loader.exists(fqn))
+         {
+            InternalNode n = dataContainer.peekInternalNode(fqn, true);// don't load
+            // node not null and attributes have been loaded?
+            if (n != null && n.isDataLoaded())
+            {
+               // has children?
+               boolean result = childrenLoaded(n);
+               if (n.hasChildren() && result)
+               {
+                  // children have been loaded, remove the node
+                  addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getData());
+                  txActs++;
+               }
+               // doesn't have children, check the cache loader
+               else if (loaderNoChildren(fqn))
+               {
+                  addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getData());
+                  txActs++;
+               }
             }
-        }
+         }
+      }
 
-        private boolean loaderNoChildren(Fqn fqn) throws Exception {
-            return loader.getChildrenNames(fqn) != null;
-        }
+      private boolean loaderNoChildren(Fqn fqn) throws Exception
+      {
+         return loader.getChildrenNames(fqn) != null;
+      }
 
-        private void addRemoveMod(InvocationContext ctx, List<Modification> l, Fqn fqn, Map data) {
-            Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, fqn);
-            l.add(mod);
-            notifier.notifyNodeActivated(fqn, false, data, ctx);
-        }
+      private void addRemoveMod(InvocationContext ctx, List<Modification> l, Fqn fqn, Map data)
+      {
+         Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, fqn);
+         l.add(mod);
+         notifier.notifyNodeActivated(fqn, false, data, ctx);
+      }
 
-        public List<Modification> getCacheLoaderModifications() {
-            return cacheLoaderModifications;
-        }
+      public List<Modification> getCacheLoaderModifications()
+      {
+         return cacheLoaderModifications;
+      }
 
-        public int getTxActs() {
-            return txActs;
-        }
+      public int getTxActs()
+      {
+         return txActs;
+      }
 
-    }
+   }
 
-    @ManagedAttribute(description = "number of cache node activations")
-    public long getActivations() {
-        return activations;
-    }
+   @ManagedAttribute(description = "number of cache node activations")
+   public long getActivations()
+   {
+      return activations;
+   }
 
-    @ManagedOperation
-    public void resetStatistics() {
-        super.resetStatistics();
-        activations = 0;
-    }
+   @ManagedOperation
+   public void resetStatistics()
+   {
+      super.resetStatistics();
+      activations = 0;
+   }
 
-    @ManagedOperation
-    public Map<String, Object> dumpStatistics() {
-        Map<String, Object> retval = super.dumpStatistics();
-        if (retval == null) {
-            retval = new HashMap<String, Object>();
-        }
-        retval.put("Activations", activations);
-        return retval;
-    }
+   @ManagedOperation
+   public Map<String, Object> dumpStatistics()
+   {
+      Map<String, Object> retval = super.dumpStatistics();
+      if (retval == null)
+      {
+         retval = new HashMap<String, Object>();
+      }
+      retval.put("Activations", activations);
+      return retval;
+   }
+
+   @Override
+   protected void recordNodeLoaded(InvocationContext ctx, Fqn fqn)
+   {
+      ctx.addFqnLoaded(fqn);
+   }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java	2008-11-25 11:08:02 UTC (rev 7194)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java	2008-11-25 11:48:32 UTC (rev 7195)
@@ -294,7 +294,7 @@
             }
             else
             {
-               nodeData = loadData(fqn);
+               nodeData = loadData(ctx, fqn);
                exists = nodeData != null;
             }
             if (n == null && exists)
@@ -380,7 +380,7 @@
          if ((isMove || isActivation) && recursive)
          {
             // load data for children as well!
-            child.setInternalState(loader.get(child.getFqn()));
+            child.setInternalState(loadData(ctxt, child.getFqn()));
             child.setDataLoaded(true);
          }
 
@@ -466,13 +466,13 @@
       }
    }
 
-   private Map loadData(Fqn fqn) throws Exception
+   private Map loadData(InvocationContext ctx, Fqn fqn) throws Exception
    {
 
       Map nodeData = loader.get(fqn);
       boolean nodeExists = (nodeData != null);
       if (trace) log.trace("nodeExists " + nodeExists);
-
+      if (nodeExists) recordNodeLoaded(ctx, fqn);
       if (getStatisticsEnabled())
       {
          if (nodeExists)
@@ -516,4 +516,9 @@
       retval.put("CacheLoaderMisses", cacheMisses);
       return retval;
    }
+
+   protected void recordNodeLoaded(InvocationContext ctx, Fqn fqn)
+   {
+      // this is a no-op.  Only used by subclasses.
+   }
 }
\ No newline at end of file

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyActivationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyActivationInterceptor.java	2008-11-25 11:08:02 UTC (rev 7194)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyActivationInterceptor.java	2008-11-25 11:48:32 UTC (rev 7195)
@@ -32,7 +32,13 @@
 import org.jboss.cache.commands.read.GetNodeCommand;
 import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
 import org.jboss.cache.commands.tx.PrepareCommand;
-import org.jboss.cache.commands.write.*;
+import org.jboss.cache.commands.write.ClearDataCommand;
+import org.jboss.cache.commands.write.MoveCommand;
+import org.jboss.cache.commands.write.PutDataMapCommand;
+import org.jboss.cache.commands.write.PutForExternalReadCommand;
+import org.jboss.cache.commands.write.PutKeyValueCommand;
+import org.jboss.cache.commands.write.RemoveKeyCommand;
+import org.jboss.cache.commands.write.RemoveNodeCommand;
 import org.jboss.cache.factories.annotations.Inject;
 import org.jboss.cache.factories.annotations.Start;
 import org.jboss.cache.jmx.annotations.ManagedOperation;
@@ -41,7 +47,11 @@
 
 import javax.transaction.SystemException;
 import javax.transaction.TransactionManager;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -54,306 +64,386 @@
  * @deprecated will be removed along with optimistic and pessimistic locking.
  */
 @Deprecated
-public class LegacyActivationInterceptor extends LegacyCacheLoaderInterceptor {
+public class LegacyActivationInterceptor extends LegacyCacheLoaderInterceptor
+{
 
-    protected TransactionManager txMgr = null;
-    private long activations = 0;
-    ActivationModificationsBuilder builder;
+   protected TransactionManager txMgr = null;
+   private long activations = 0;
+   ActivationModificationsBuilder builder;
 
-    /**
-     * List<Transaction> that we have registered for
-     */
-    protected ConcurrentHashMap transactions = new ConcurrentHashMap(16);
-    protected static final Object NULL = new Object();
+   /**
+    * List<Transaction> that we have registered for
+    */
+   protected ConcurrentHashMap transactions = new ConcurrentHashMap(16);
+   protected static final Object NULL = new Object();
 
-    public LegacyActivationInterceptor() {
-        isActivation = true;
-        useCacheStore = false;
-    }
+   public LegacyActivationInterceptor()
+   {
+      isActivation = true;
+      useCacheStore = false;
+   }
 
-    @Inject
-    public void injectTransactionManager(TransactionManager txMgr) {
-        this.txMgr = txMgr;
-    }
+   @Inject
+   public void injectTransactionManager(TransactionManager txMgr)
+   {
+      this.txMgr = txMgr;
+   }
 
-    @Start
-    public void createModificationsBuilder() {
-        builder = new ActivationModificationsBuilder();
-    }
+   @Start
+   public void createModificationsBuilder()
+   {
+      builder = new ActivationModificationsBuilder();
+   }
 
-    @Override
-    public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable {
-        Object returnValue = super.visitClearDataCommand(ctx, command);
-        if (trace)
-            log.trace("This is a remove data operation; removing the data from the loader, no activation processing needed.");
-        loader.removeData(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
+   {
+      Object returnValue = super.visitClearDataCommand(ctx, command);
+      if (trace)
+      {
+         log.trace("This is a remove data operation; removing the data from the loader, no activation processing needed.");
+      }
+      loader.removeData(command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand command) throws Throwable {
-        Object returnValue = super.visitRemoveNodeCommand(ctx, command);
-        if (trace)
-            log.trace("This is a remove operation; removing the node from the loader, no activation processing needed.");
-        loader.remove(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand command) throws Throwable
+   {
+      Object returnValue = super.visitRemoveNodeCommand(ctx, command);
+      if (trace)
+      {
+         log.trace("This is a remove operation; removing the node from the loader, no activation processing needed.");
+      }
+      loader.remove(command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitGetChildrenNamesCommand(InvocationContext ctx, GetChildrenNamesCommand command) throws Throwable {
-        Object returnValue = super.visitGetChildrenNamesCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitGetChildrenNamesCommand(InvocationContext ctx, GetChildrenNamesCommand command) throws Throwable
+   {
+      Object returnValue = super.visitGetChildrenNamesCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command) throws Throwable {
-        Object returnValue = super.visitGetKeysCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command) throws Throwable
+   {
+      Object returnValue = super.visitGetKeysCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command) throws Throwable {
-        Object returnValue = super.visitGetNodeCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command) throws Throwable
+   {
+      Object returnValue = super.visitGetNodeCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable {
-        Object returnValue = super.visitGetKeyValueCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable
+   {
+      Object returnValue = super.visitGetKeyValueCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitPutForExternalReadCommand(InvocationContext ctx, PutForExternalReadCommand command) throws Throwable {
-        return visitPutKeyValueCommand(ctx, command);
-    }
+   @Override
+   public Object visitPutForExternalReadCommand(InvocationContext ctx, PutForExternalReadCommand command) throws Throwable
+   {
+      return visitPutKeyValueCommand(ctx, command);
+   }
 
-    @Override
-    public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
-        Object returnValue = super.visitPutKeyValueCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
+   {
+      Object returnValue = super.visitPutKeyValueCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable {
-        Object returnValue = super.visitPutDataMapCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
+   {
+      Object returnValue = super.visitPutDataMapCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable {
-        Object returnValue = super.visitRemoveKeyCommand(ctx, command);
-        removeNodeFromCacheLoader(command.getFqn());
-        return returnValue;
-    }
+   @Override
+   public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable
+   {
+      Object returnValue = super.visitRemoveKeyCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
 
-    @Override
-    public Object visitMoveCommand(InvocationContext ctx, MoveCommand command) throws Throwable {
-        Object returnValue = super.visitMoveCommand(ctx, command);
-        if (trace)
-            log.trace("This is a move operation; removing the FROM node from the loader, no activation processing needed.");
-        loader.remove(command.getFqn());
-        removeNodeFromCacheLoader(command.getFqn().getParent());
-        removeNodeFromCacheLoader(command.getTo());
-        return returnValue;
-    }
+   @Override
+   public Object visitMoveCommand(InvocationContext ctx, MoveCommand command) throws Throwable
+   {
+      Object returnValue = super.visitMoveCommand(ctx, command);
+      if (trace)
+      {
+         log.trace("This is a move operation; removing the FROM node from the loader, no activation processing needed.");
+      }
+      loader.remove(command.getFqn());
+      removeNodeFromCacheLoader(ctx, command.getFqn().getParent());
+      removeNodeFromCacheLoader(ctx, command.getTo());
+      return returnValue;
+   }
 
+   private boolean wasLoadedIntoMemory(InvocationContext ctx, Fqn fqn)
+   {
+      Set<Fqn> fqnsLoaded = ctx.getFqnsLoaded();
+      return fqnsLoaded != null && fqnsLoaded.contains(fqn);
+   }
 
-    /**
-     * Remove the node from the cache loader if it exists in memory,
-     * its attributes have been initialized, its children have been loaded,
-     * AND it was found in the cache loader (nodeLoaded = true).
-     */
-    private void removeNodeFromCacheLoader(Fqn fqn) throws Throwable {
-        NodeSPI n;
-        if (((n = dataContainer.peek(fqn, true, false)) != null) && n.isDataLoaded()) {
+   /**
+    * Remove the node from the cache loader if it exists in memory,
+    * its attributes have been initialized, its children have been loaded,
+    * AND it was found in the cache loader (nodeLoaded = true).
+    */
+   private void removeNodeFromCacheLoader(InvocationContext ctx, Fqn fqn) throws Throwable
+   {
+      // only bother with this if the node has been loaded by the cache loader previous to this call.
+      if (fqn != null && wasLoadedIntoMemory(ctx, fqn))
+      {
+         NodeSPI n;
+         if (((n = dataContainer.peek(fqn, true, false)) != null) && n.isDataLoaded() && loader.exists(fqn))
+         {
             // node not null and attributes have been loaded?
-            if (!n.getChildrenDirect().isEmpty()) {
-                boolean result = childrenLoaded(n);
-                if (result) {
-                    log.debug("children all initialized");
-                    remove(fqn);
-                }
-            } else if (loaderNoChildren(fqn)) {
-                if (log.isDebugEnabled()) log.debug("no children " + n);
-                remove(fqn);
+            if (!n.getChildrenDirect().isEmpty())
+            {
+               boolean result = childrenLoaded(n);
+               if (result)
+               {
+                  log.debug("children all initialized");
+                  remove(fqn);
+               }
             }
-        }
-    }
+            else if (loaderNoChildren(fqn))
+            {
+               if (log.isDebugEnabled()) log.debug("no children " + n);
+               remove(fqn);
+            }
+         }
+      }
+   }
 
-    private boolean childrenLoaded(NodeSPI<?, ?> node) {
-        if (!node.isChildrenLoaded()) {
+   private boolean childrenLoaded(NodeSPI<?, ?> node)
+   {
+      if (!node.isChildrenLoaded())
+      {
+         return false;
+      }
+      for (NodeSPI child : node.getChildrenDirect())
+      {
+         if (!child.isDataLoaded())
+         {
             return false;
-        }
-        for (NodeSPI child : node.getChildrenDirect()) {
-            if (!child.isDataLoaded()) {
-                return false;
-            }
+         }
 
-            if (child.getChildrenDirect().size() > 0) {
-                if (!childrenLoaded(child))
-                    return false;
-            } else if (!loaderNoChildren(child.getFqn())) {
-                return false;
+         if (child.getChildrenDirect().size() > 0)
+         {
+            if (!childrenLoaded(child))
+            {
+               return false;
             }
-        }
-        return true;
+         }
+         else if (!loaderNoChildren(child.getFqn()))
+         {
+            return false;
+         }
+      }
+      return true;
 
-    }
+   }
 
-    @Override
-    public Object visitOptimisticPrepareCommand(InvocationContext ctx, OptimisticPrepareCommand command) throws Throwable {
-        Object retval = invokeNextInterceptor(ctx, command);
-        if (inTransaction()) {
-            prepareCacheLoader(ctx);
-        }
-        return retval;
-    }
+   @Override
+   public Object visitOptimisticPrepareCommand(InvocationContext ctx, OptimisticPrepareCommand command) throws Throwable
+   {
+      Object retval = invokeNextInterceptor(ctx, command);
+      if (inTransaction())
+      {
+         prepareCacheLoader(ctx);
+      }
+      return retval;
+   }
 
-    private boolean inTransaction() throws SystemException {
-        return txMgr != null && txMgr.getTransaction() != null;
-    }
+   private boolean inTransaction() throws SystemException
+   {
+      return txMgr != null && txMgr.getTransaction() != null;
+   }
 
-    @Override
-    public Object visitPrepareCommand(InvocationContext ctx, PrepareCommand command) throws Throwable {
-        Object retval = invokeNextInterceptor(ctx, command);
-        if (inTransaction()) {
-            prepareCacheLoader(ctx);
-        }
-        return retval;
-    }
+   @Override
+   public Object visitPrepareCommand(InvocationContext ctx, PrepareCommand command) throws Throwable
+   {
+      Object retval = invokeNextInterceptor(ctx, command);
+      if (inTransaction())
+      {
+         prepareCacheLoader(ctx);
+      }
+      return retval;
+   }
 
-    private void remove(Fqn fqn) throws Exception {
-        loader.remove(fqn);
-        if (getStatisticsEnabled()) activations++;
-    }
+   private void remove(Fqn fqn) throws Exception
+   {
+      loader.remove(fqn);
+      if (getStatisticsEnabled()) activations++;
+   }
 
-    /**
-     * Returns true if the loader indicates no children for this node.
-     * Return false on error.
-     */
-    private boolean loaderNoChildren(Fqn fqn) {
-        try {
-            Set childrenNames = loader.getChildrenNames(fqn);
-            return (childrenNames == null);
-        }
-        catch (Exception e) {
-            log.error("failed getting the children names for " + fqn + " from the cache loader", e);
-            return false;
-        }
-    }
+   /**
+    * Returns true if the loader indicates no children for this node.
+    * Return false on error.
+    */
+   private boolean loaderNoChildren(Fqn fqn)
+   {
+      try
+      {
+         Set childrenNames = loader.getChildrenNames(fqn);
+         return (childrenNames == null);
+      }
+      catch (Exception e)
+      {
+         log.error("failed getting the children names for " + fqn + " from the cache loader", e);
+         return false;
+      }
+   }
 
-    public long getActivations() {
-        return activations;
-    }
+   public long getActivations()
+   {
+      return activations;
+   }
 
-    private void prepareCacheLoader(InvocationContext ctx) throws Throwable {
-        GlobalTransaction gtx = ctx.getGlobalTransaction();
-        TransactionContext tCtx = ctx.getTransactionContext();
-        if (tCtx == null) {
-            throw new Exception("tCtx for transaction " + gtx + " not found in transaction table");
-        }
-        List<Modification> cacheLoaderModifications = new ArrayList<Modification>();
+   private void prepareCacheLoader(InvocationContext ctx) throws Throwable
+   {
+      GlobalTransaction gtx = ctx.getGlobalTransaction();
+      TransactionContext tCtx = ctx.getTransactionContext();
+      if (tCtx == null)
+      {
+         throw new Exception("tCtx for transaction " + gtx + " not found in transaction table");
+      }
+      List<Modification> cacheLoaderModifications = new ArrayList<Modification>();
 
-        builder.visitCollection(ctx, tCtx.getModifications());
-        if (cacheLoaderModifications.size() > 0) {
-            loader.prepare(gtx, cacheLoaderModifications, false);
-        }
-    }
+      builder.visitCollection(ctx, tCtx.getModifications());
+      if (cacheLoaderModifications.size() > 0)
+      {
+         loader.prepare(gtx, cacheLoaderModifications, false);
+      }
+   }
 
-    public class ActivationModificationsBuilder extends AbstractVisitor {
+   public class ActivationModificationsBuilder extends AbstractVisitor
+   {
 
-        private List<Modification> cacheLoaderModifications = new ArrayList<Modification>();
+      private List<Modification> cacheLoaderModifications = new ArrayList<Modification>();
 
-        private int txActs = 0;
+      private int txActs = 0;
 
-        @Override
-        public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand removeNodeCommand) throws Throwable {
-            Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, removeNodeCommand.getFqn());
-            cacheLoaderModifications.add(mod);
-            return null;
-        }
+      @Override
+      public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand removeNodeCommand) throws Throwable
+      {
+         Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, removeNodeCommand.getFqn());
+         cacheLoaderModifications.add(mod);
+         return null;
+      }
 
-        @Override
-        public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable {
-            Fqn fqn = command.getFqn();
-            handlePutCommand(ctx, fqn);
-            return null;
-        }
+      @Override
+      public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
+      {
+         Fqn fqn = command.getFqn();
+         handlePutCommand(ctx, fqn);
+         return null;
+      }
 
-        @Override
-        public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
-            Fqn fqn = command.getFqn();
-            handlePutCommand(ctx, fqn);
-            return null;
-        }
+      @Override
+      public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
+      {
+         Fqn fqn = command.getFqn();
+         handlePutCommand(ctx, fqn);
+         return null;
+      }
 
-        // On the way out, remove the node from the cache loader.
-        // Only remove the node if it exists in memory, its attributes have
-        // been initialized, its children have been loaded
-        // AND it was found in the cache loader (nodeLoaded = true).
-        // Then notify the listeners that the node has been activated.
-        private void handlePutCommand(InvocationContext ctx, Fqn fqn)
-                throws Exception {
-            if (fqn != null && dataContainer.peek(fqn, false, false) != null && loader.exists(fqn)) {
-                NodeSPI n = dataContainer.peek(fqn, true, false);// don't load
-                // node not null and attributes have been loaded?
-                if (n != null && n.isDataLoaded()) {
-                    // has children?
-                    boolean result = childrenLoaded(n);
-                    if (!n.getChildrenDirect().isEmpty() && result) {
-                        // children have been loaded, remove the node
-                        addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getDataDirect());
-                        txActs++;
-                    }
-                    // doesn't have children, check the cache loader
-                    else if (loaderNoChildren(fqn)) {
-                        addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getDataDirect());
-                        txActs++;
-                    }
-                }
+      // On the way out, remove the node from the cache loader.
+      // Only remove the node if it exists in memory, its attributes have
+      // been initialized, its children have been loaded
+      // AND it was found in the cache loader (nodeLoaded = true).
+      // Then notify the listeners that the node has been activated.
+      private void handlePutCommand(InvocationContext ctx, Fqn fqn)
+            throws Exception
+      {
+         if (fqn != null && dataContainer.peek(fqn, false, false) != null && loader.exists(fqn))
+         {
+            NodeSPI n = dataContainer.peek(fqn, true, false);// don't load
+            // node not null and attributes have been loaded?
+            if (n != null && n.isDataLoaded())
+            {
+               // has children?
+               boolean result = childrenLoaded(n);
+               if (!n.getChildrenDirect().isEmpty() && result)
+               {
+                  // children have been loaded, remove the node
+                  addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getDataDirect());
+                  txActs++;
+               }
+               // doesn't have children, check the cache loader
+               else if (loaderNoChildren(fqn))
+               {
+                  addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getDataDirect());
+                  txActs++;
+               }
             }
-        }
+         }
+      }
 
-        private boolean loaderNoChildren(Fqn fqn) throws Exception {
-            return loader.getChildrenNames(fqn) != null;
-        }
+      private boolean loaderNoChildren(Fqn fqn) throws Exception
+      {
+         return loader.getChildrenNames(fqn) != null;
+      }
 
-        private void addRemoveMod(InvocationContext ctx, List<Modification> l, Fqn fqn, Map data) {
-            Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, fqn);
-            l.add(mod);
-            notifier.notifyNodeActivated(fqn, false, data, ctx);
-        }
+      private void addRemoveMod(InvocationContext ctx, List<Modification> l, Fqn fqn, Map data)
+      {
+         Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, fqn);
+         l.add(mod);
+         notifier.notifyNodeActivated(fqn, false, data, ctx);
+      }
 
-        public List<Modification> getCacheLoaderModifications() {
-            return cacheLoaderModifications;
-        }
+      public List<Modification> getCacheLoaderModifications()
+      {
+         return cacheLoaderModifications;
+      }
 
-        public int getTxActs() {
-            return txActs;
-        }
+      public int getTxActs()
+      {
+         return txActs;
+      }
 
-    }
+   }
 
-    @ManagedOperation
-    public void resetStatistics() {
-        super.resetStatistics();
-        activations = 0;
-    }
+   @ManagedOperation
+   public void resetStatistics()
+   {
+      super.resetStatistics();
+      activations = 0;
+   }
 
-    @ManagedOperation
-    public Map<String, Object> dumpStatistics() {
-        Map<String, Object> retval = super.dumpStatistics();
-        if (retval == null) {
-            retval = new HashMap<String, Object>();
-        }
-        retval.put("Activations", activations);
-        return retval;
-    }
+   @ManagedOperation
+   public Map<String, Object> dumpStatistics()
+   {
+      Map<String, Object> retval = super.dumpStatistics();
+      if (retval == null)
+      {
+         retval = new HashMap<String, Object>();
+      }
+      retval.put("Activations", activations);
+      return retval;
+   }
+
+   @Override
+   protected void recordNodeLoaded(InvocationContext ctx, Fqn fqn)
+   {
+      ctx.addFqnLoaded(fqn);
+   }
 }
\ No newline at end of file

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyCacheLoaderInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyCacheLoaderInterceptor.java	2008-11-25 11:08:02 UTC (rev 7194)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyCacheLoaderInterceptor.java	2008-11-25 11:48:32 UTC (rev 7195)
@@ -400,7 +400,7 @@
          if ((isMove || isActivation) && recursive)
          {
             // load data for children as well!
-            child.setInternalState(loader.get(child.getFqn()));
+            child.setInternalState(loadData(ctxt, child.getFqn()));
             child.setDataLoaded(true);
          }
 
@@ -457,9 +457,13 @@
       if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC) return;
 
       if (recursive)
+      {
          lockManager.lockAllAndRecord(fqn, lockType, ctx);
+      }
       else
+      {
          lockManager.lockAndRecord(fqn, lockType, ctx);
+      }
    }
 
    /**
@@ -487,7 +491,7 @@
    private NodeSPI loadNode(InvocationContext ctx, Fqn fqn, NodeSPI n, TransactionContext transactionContext) throws Exception
    {
       if (trace) log.trace("loadNode " + fqn);
-      Map nodeData = loadData(fqn);
+      Map nodeData = loadData(ctx, fqn);
       if (nodeData != null)
       {
          if (trace) log.trace("Node data is not null, loading");
@@ -557,13 +561,13 @@
       return (NodeSPI) results[1];
    }
 
-   private Map loadData(Fqn fqn) throws Exception
+   private Map loadData(InvocationContext ctx, Fqn fqn) throws Exception
    {
 
       Map nodeData = loader.get(fqn);
       boolean nodeExists = (nodeData != null);
       if (trace) log.trace("nodeExists " + nodeExists);
-
+      if (nodeExists) recordNodeLoaded(ctx, fqn);
       if (getStatisticsEnabled())
       {
          if (nodeExists)
@@ -606,4 +610,8 @@
       return retval;
    }
 
+   protected void recordNodeLoaded(InvocationContext ctx, Fqn fqn)
+   {
+      // this is a no-op.  Only used by subclasses.
+   }
 }
\ No newline at end of file




More information about the jbosscache-commits mailing list