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

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Thu Sep 18 07:02:46 EDT 2008


Author: manik.surtani at jboss.com
Date: 2008-09-18 07:02:45 -0400 (Thu, 18 Sep 2008)
New Revision: 6749

Modified:
   core/trunk/src/main/java/org/jboss/cache/AbstractNode.java
   core/trunk/src/main/java/org/jboss/cache/AbstractNodeFactory.java
   core/trunk/src/main/java/org/jboss/cache/DataContainer.java
   core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java
   core/trunk/src/main/java/org/jboss/cache/InternalNode.java
   core/trunk/src/main/java/org/jboss/cache/NodeFactory.java
   core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
   core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/NullMarkerNode.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java
Log:
Optimised for performance, minimising additional node lookups on completion of an update

Modified: core/trunk/src/main/java/org/jboss/cache/AbstractNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/AbstractNode.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/AbstractNode.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -227,6 +227,11 @@
       throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
    }
 
+   public void addChild(InternalNode<K, V> child, boolean safe)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
    public void setChildrenMap(ConcurrentMap<Object, InternalNode<K, V>> children)
    {
       throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());

Modified: core/trunk/src/main/java/org/jboss/cache/AbstractNodeFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/AbstractNodeFactory.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/AbstractNodeFactory.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -105,7 +105,7 @@
       throw new UnsupportedOperationException("Unsupported in this implementation (" + getClass().getSimpleName() + ")!");
    }
 
-   public ReadCommittedNode createWrappedNode(InternalNode<K, V> node)
+   public ReadCommittedNode createWrappedNode(InternalNode<K, V> node, InternalNode<K, V> parent)
    {
       throw new UnsupportedOperationException("Unsupported in this implementation (" + getClass().getSimpleName() + ")!");
    }

Modified: core/trunk/src/main/java/org/jboss/cache/DataContainer.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DataContainer.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/DataContainer.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -192,6 +192,15 @@
    InternalNode peekInternalNode(Fqn f, boolean includeInvalidNodes);
 
    /**
+    * Similar to {@link #peekInternalNode(Fqn, boolean)} except that the node AND it's *direct* parent are retrieved.
+    *
+    * @param fqn                 fqn to find
+    * @param includeInvalidNodes if true, invalid nodes are considered.
+    * @return an array of InternalNodes, containing 2 elements.  Element [0] is the node being peeked, and element [1] is it's direct parent.
+    */
+   public InternalNode[] peekInternalNodeAndDirectParent(Fqn fqn, boolean includeInvalidNodes);
+
+   /**
     * Sets a new root node
     *
     * @param nodeInvocationDelegate

Modified: core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -47,6 +47,7 @@
    private BuddyFqnTransformer buddyFqnTransformer;
    private Configuration config;
    private boolean usingMvcc;
+   private static final InternalNode[] NULL_ARRAY = {null, null};
 
    @Inject
    public void injectDependencies(NodeFactory nodeFactory, LockManager lockManager, BuddyFqnTransformer transformer, Configuration configuration)
@@ -724,6 +725,36 @@
       return n;
    }
 
+   /**
+    * Similar to {@link #peekInternalNode(Fqn, boolean)} except that the node AND it's *direct* parent are retrieved.
+    *
+    * @param fqn                 fqn to find
+    * @param includeInvalidNodes if true, invalid nodes are considered.
+    * @return an array of InternalNodes, containing 2 elements.  Element [0] is the node being peeked, and element [1] is it's direct parent.
+    */
+   public InternalNode[] peekInternalNodeAndDirectParent(Fqn fqn, boolean includeInvalidNodes)
+   {
+      if (fqn == null || fqn.size() == 0) return new InternalNode[]{rootInternal, null};
+      InternalNode n = rootInternal;
+      InternalNode directParent = null;
+      int fqnSize = fqn.size();
+      for (int i = 0; i < fqnSize; i++)
+      {
+         directParent = n;
+         Object obj = fqn.get(i);
+         n = directParent.getChild(obj);
+         if (n == null)
+         {
+            return NULL_ARRAY;
+         }
+         else if (!includeInvalidNodes && !n.isValid())
+         {
+            return NULL_ARRAY;
+         }
+      }
+      return new InternalNode[]{n, directParent};
+   }
+
    public void setBuddyFqnTransformer(BuddyFqnTransformer buddyFqnTransformer)
    {
       this.buddyFqnTransformer = buddyFqnTransformer;

Modified: core/trunk/src/main/java/org/jboss/cache/InternalNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/InternalNode.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/InternalNode.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -117,6 +117,15 @@
 
    void addChild(InternalNode<K, V> child);
 
+   /**
+    * Same as above, except that if safe is true, any Fqn ancestry checking is skipped.  Don't set safe to true unless
+    * you really know what you are doing!
+    *
+    * @param child child to add
+    * @param safe  safety flag
+    */
+   void addChild(InternalNode<K, V> child, boolean safe);
+
    // *****************End new methods *****************
 
 

Modified: core/trunk/src/main/java/org/jboss/cache/NodeFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/NodeFactory.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/NodeFactory.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -15,7 +15,7 @@
  */
 public interface NodeFactory<K, V>
 {
-   ReadCommittedNode createWrappedNode(InternalNode<K, V> node);
+   ReadCommittedNode createWrappedNode(InternalNode<K, V> node, InternalNode<K, V> parent);
 
    WorkspaceNode<K, V> createWrappedNode(NodeSPI<K, V> dataNode, TransactionWorkspace workspace);
 

Modified: core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -18,6 +18,9 @@
 import org.jboss.cache.factories.annotations.Stop;
 import org.jboss.cache.interceptors.InterceptorChain;
 import org.jboss.cache.invocation.InvocationContextContainer;
+import org.jboss.cache.jmx.annotations.MBean;
+import org.jboss.cache.jmx.annotations.ManagedAttribute;
+import org.jboss.cache.jmx.annotations.ManagedOperation;
 import org.jboss.cache.lock.LockManager;
 import org.jboss.cache.lock.LockUtil;
 import org.jboss.cache.lock.TimeoutException;
@@ -31,9 +34,6 @@
 import org.jboss.cache.transaction.TransactionTable;
 import org.jboss.cache.util.ThreadGate;
 import org.jboss.cache.util.reflect.ReflectionUtil;
-import org.jboss.cache.jmx.annotations.ManagedOperation;
-import org.jboss.cache.jmx.annotations.ManagedAttribute;
-import org.jboss.cache.jmx.annotations.MBean;
 import org.jgroups.Address;
 import org.jgroups.Channel;
 import org.jgroups.ChannelException;
@@ -42,14 +42,15 @@
 import org.jgroups.JChannel;
 import org.jgroups.StateTransferException;
 import org.jgroups.View;
+import org.jgroups.blocks.GroupRequest;
+import org.jgroups.blocks.RspFilter;
 import org.jgroups.protocols.TP;
 import org.jgroups.stack.ProtocolStack;
-import org.jgroups.blocks.GroupRequest;
-import org.jgroups.blocks.RspFilter;
 import org.jgroups.util.Rsp;
 import org.jgroups.util.RspList;
 
 import javax.transaction.TransactionManager;
+import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -57,14 +58,13 @@
 import java.util.List;
 import java.util.Set;
 import java.util.Vector;
-import java.text.NumberFormat;
 
 /**
  * Manager that handles all RPC calls between JBoss Cache instances
  *
  * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
  */
- at MBean (objectName = "RPCManager") 
+ at MBean(objectName = "RPCManager")
 public class RPCManagerImpl implements RPCManager
 {
    private Channel channel;
@@ -72,7 +72,7 @@
    private List<Address> members;
    private long replicationCount;
    private long replicationFailures;
-   private boolean statisticsEnabled;
+   private boolean statisticsEnabled = false;
 
    private final Object coordinatorLock = new Object();
    /**
@@ -417,7 +417,8 @@
    public List<Object> callRemoteMethods(Vector<Address> recipients, ReplicableCommand command, int mode, long timeout, RspFilter responseFilter, boolean useOutOfBandMessage) throws Exception
    {
       boolean success = true;
-      try {
+      try
+      {
          // short circuit if we don't have an RpcDispatcher!
          if (rpcDispatcher == null) return null;
          int modeToUse = mode;
@@ -469,10 +470,14 @@
             }
          }
          return retval;
-      } catch (Exception e) {
+      }
+      catch (Exception e)
+      {
          success = false;
          throw e;
-      } finally {
+      }
+      finally
+      {
          computeStats(success);
       }
    }
@@ -538,7 +543,7 @@
                }
                catch (Exception transferFailed)
                {
-                  if (log.isTraceEnabled()) log.trace("Error while fetching state",transferFailed);
+                  if (log.isTraceEnabled()) log.trace("Error while fetching state", transferFailed);
                   successfulTransfer = false;
                }
             }
@@ -707,17 +712,18 @@
 
    }
 
-
    //jmx operations
-   private void computeStats(boolean success) {
-      if (this.isStatisticsEnabled() && rpcDispatcher != null)
+   private void computeStats(boolean success)
+   {
+      if (statisticsEnabled && rpcDispatcher != null)
       {
          if (success)
          {
-            replicationCount ++;
-         } else
+            replicationCount++;
+         }
+         else
          {
-            replicationFailures ++;
+            replicationFailures++;
          }
       }
    }
@@ -730,22 +736,26 @@
    }
 
    @ManagedAttribute(description = "number of successful replications")
-   public long getReplicationCount() {
+   public long getReplicationCount()
+   {
       return replicationCount;
    }
 
-   @ManagedAttribute (description = "number of failed replications")
-   public long getReplicationFailures() {
+   @ManagedAttribute(description = "number of failed replications")
+   public long getReplicationFailures()
+   {
       return replicationFailures;
    }
 
-   @ManagedAttribute (description = "whether or not jmx statistics are enabled")
-   public boolean isStatisticsEnabled() {
+   @ManagedAttribute(description = "whether or not jmx statistics are enabled")
+   public boolean isStatisticsEnabled()
+   {
       return statisticsEnabled;
    }
 
    @ManagedAttribute
-   public void setStatisticsEnabled(boolean statisticsEnabled) {
+   public void setStatisticsEnabled(boolean statisticsEnabled)
+   {
       this.statisticsEnabled = statisticsEnabled;
    }
 
@@ -757,8 +767,8 @@
          return "N/A";
       }
       double totalCount = replicationCount + replicationFailures;
-      double ration = (double)replicationCount / totalCount * 100d;
-      return NumberFormat.getInstance().format(ration) +"%";
+      double ration = (double) replicationCount / totalCount * 100d;
+      return NumberFormat.getInstance().format(ration) + "%";
    }
 
    /**
@@ -773,7 +783,7 @@
       Configuration.CacheMode cacheMode = configuration.getCacheMode();
       if (!cacheMode.equals(Configuration.CacheMode.LOCAL) && configuration.getCacheMode().isSynchronous())
       {
-         ProtocolStack stack = ((JChannel)channel).getProtocolStack();
+         ProtocolStack stack = ((JChannel) channel).getProtocolStack();
          TP transport = stack.getTransport();
          if (transport.isEnableBundling())
          {
@@ -784,7 +794,7 @@
       //bundling is good for async caches
       if (!cacheMode.isSynchronous())
       {
-         ProtocolStack stack = ((JChannel)channel).getProtocolStack();
+         ProtocolStack stack = ((JChannel) channel).getProtocolStack();
          TP transport = stack.getTransport();
          if (!transport.isEnableBundling())
          {

Modified: core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -245,8 +245,14 @@
    @Override
    public void addChild(InternalNode<K, V> child)
    {
-      Fqn childFqn = child.getFqn();
-      if (childFqn.isDirectChildOf(fqn))
+      addChild(child, false);
+   }
+
+   @Override
+   public void addChild(InternalNode<K, V> child, boolean safe)
+   {
+      Fqn<?> childFqn = child.getFqn();
+      if (safe || childFqn.isDirectChildOf(fqn))
       {
          children().put(childFqn.getLastElement(), child);
       }

Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -22,7 +22,7 @@
 public class MVCCNodeFactory<K, V> extends AbstractNodeFactory<K, V>
 {
    private boolean useRepeatableRead;
-   private static final NullMarkerNode NULL_MARKER = new NullMarkerNode(null);
+   private static final NullMarkerNode NULL_MARKER = new NullMarkerNode();
    private static final Log log = LogFactory.getLog(MVCCNodeFactory.class);
    private static final boolean trace = log.isTraceEnabled();
    private boolean lockChildForInsertRemove;
@@ -48,10 +48,10 @@
     */
    @Override
    @SuppressWarnings("unchecked")
-   public ReadCommittedNode createWrappedNode(InternalNode<K, V> node)
+   public ReadCommittedNode createWrappedNode(InternalNode<K, V> node, InternalNode<K, V> parent)
    {
       if (node == null) return useRepeatableRead ? NULL_MARKER : null;
-      ReadCommittedNode rcn = useRepeatableRead ? new RepeatableReadNode(node) : new ReadCommittedNode(node);
+      ReadCommittedNode rcn = useRepeatableRead ? new RepeatableReadNode(node, parent) : new ReadCommittedNode(node, parent);
       rcn.initialize(configuration, invocationContextContainer, componentRegistry, interceptorChain);
       rcn.injectDependencies(cache);
       return rcn;
@@ -73,7 +73,7 @@
    @SuppressWarnings("unchecked")
    public NodeSPI<K, V> createRootNode()
    {
-      return createWrappedNode(createInternalNode(Fqn.ROOT));
+      return createWrappedNode(createInternalNode(Fqn.ROOT), null);
    }
 
    @Override

Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -66,8 +66,8 @@
     * Attempts to provide the context with a set of wrapped nodes based on the Collection of fqns passed in.  If the nodes
     * already exist in the context then the node is not wrapped again.
     * <p/>
-    * {@link InternalNode}s are wrapped using {@link org.jboss.cache.NodeFactory#createWrappedNode(org.jboss.cache.InternalNode)}
-    * and as such, null internal nodes are treated according to isolation level used.  See {@link org.jboss.cache.NodeFactory#createWrappedNode(org.jboss.cache.InternalNode)}
+    * {@link InternalNode}s are wrapped using {@link org.jboss.cache.NodeFactory#createWrappedNode(org.jboss.cache.InternalNode, org.jboss.cache.InternalNode)}
+    * and as such, null internal nodes are treated according to isolation level used.  See {@link org.jboss.cache.NodeFactory#createWrappedNode(org.jboss.cache.InternalNode, org.jboss.cache.InternalNode)}
     * for details on this behaviour.
     * <p/>
     * Note that if the context has the {@link org.jboss.cache.config.Option#isForceWriteLock()} option set, then write locks are
@@ -113,8 +113,8 @@
       {
          if (trace) log.trace("Node " + f + " is not in context, fetching from container.");
          // simple implementation.  Peek the node, wrap it, put wrapped node in the context.
-         InternalNode node = dataContainer.peekInternalNode(f, false);
-         ReadCommittedNode wrapped = nodeFactory.createWrappedNode(node);
+         InternalNode[] nodes = dataContainer.peekInternalNodeAndDirectParent(f, false);
+         ReadCommittedNode wrapped = nodeFactory.createWrappedNode(nodes[0], nodes[1]);  // even though parents aren't needed for reading, we hold on to this ref in case the node is later written to.
          if (wrapped != null) ctx.putLookedUpNode(f, wrapped);
          return wrapped;
       }
@@ -170,10 +170,10 @@
     * @throws InterruptedException if interrupted
     */
    @SuppressWarnings("unchecked")
-   public NodeSPI wrapNodeForWriting(InvocationContext context, Fqn fqn, boolean lockForWriting, boolean createIfAbsent, boolean includeInvalidNodes, boolean forRemoval, boolean force) throws InterruptedException
+   public ReadCommittedNode wrapNodeForWriting(InvocationContext context, Fqn fqn, boolean lockForWriting, boolean createIfAbsent, boolean includeInvalidNodes, boolean forRemoval, boolean force) throws InterruptedException
    {
       Fqn parentFqn = null;
-      NodeSPI n = context.lookUpNode(fqn);
+      ReadCommittedNode n = (ReadCommittedNode) context.lookUpNode(fqn);
       if (createIfAbsent && n != null && n.isNullNode()) n = null;
       if (n != null) // exists in context!  Just acquire lock if needed, and wrap.
       {
@@ -194,7 +194,8 @@
       else
       {
          // else, fetch from dataContainer.
-         InternalNode in = dataContainer.peekInternalNode(fqn, includeInvalidNodes);
+         InternalNode[] nodes = dataContainer.peekInternalNodeAndDirectParent(fqn, includeInvalidNodes);
+         InternalNode in = nodes[0];
          if (in != null)
          {
             // exists in cache!  Just acquire lock if needed, and wrap.
@@ -204,7 +205,7 @@
             {
                needToCopy = true;
             }
-            n = nodeFactory.createWrappedNode(in);
+            n = nodeFactory.createWrappedNode(in, nodes[1]);
             context.putLookedUpNode(fqn, n);
             if (needToCopy) n.markForUpdate(dataContainer, writeSkewCheck);
          }
@@ -225,7 +226,7 @@
             acquireLock(context, fqn);
             in = nodeFactory.createChildNode(fqn, null, context, false);
 
-            n = nodeFactory.createWrappedNode(in);
+            n = nodeFactory.createWrappedNode(in, parent.getDelegationTarget());
             n.setCreated(true);
             context.putLookedUpNode(fqn, n);
             n.markForUpdate(dataContainer, writeSkewCheck);
@@ -255,7 +256,7 @@
     * @throws InterruptedException if interrupted
     */
    @SuppressWarnings("unchecked")
-   public NodeSPI wrapNodeForWriting(InvocationContext context, InternalNode node) throws InterruptedException
+   public NodeSPI wrapNodeForWriting(InvocationContext context, InternalNode node, InternalNode parent) throws InterruptedException
    {
       Fqn fqn = node.getFqn();
       NodeSPI n = context.lookUpNode(fqn);
@@ -278,7 +279,7 @@
          {
             needToCopy = true;
          }
-         n = nodeFactory.createWrappedNode(node);
+         n = nodeFactory.createWrappedNode(node, parent);
          context.putLookedUpNode(fqn, n);
          if (needToCopy) n.markForUpdate(dataContainer, writeSkewCheck);
       }
@@ -361,12 +362,13 @@
       if (fqnList != null) fqnList.add(fqn);
 
       // now wrap and add to the context
-      NodeSPI rcn = wrapNodeForWriting(ctx, fqn, true, false, true, false, false);
+      ReadCommittedNode rcn = wrapNodeForWriting(ctx, fqn, true, false, true, false, false);
       if (rcn != null)
       {
          rcn.markForUpdate(dataContainer, writeSkewCheck);
          Map<Object, InternalNode<?, ?>> children = rcn.getDelegationTarget().getChildrenMap();
-         for (InternalNode child : children.values()) lockForWritingRecursive(child, ctx, fqnList);
+         for (InternalNode child : children.values())
+            lockForWritingRecursive(child, rcn.getInternalParent(), ctx, fqnList);
       }
    }
 
@@ -380,19 +382,19 @@
     * @throws InterruptedException if interrupted
     */
    @SuppressWarnings("unchecked")
-   private void lockForWritingRecursive(InternalNode node, InvocationContext ctx, List<Fqn> fqnList) throws InterruptedException
+   private void lockForWritingRecursive(InternalNode node, InternalNode parent, InvocationContext ctx, List<Fqn> fqnList) throws InterruptedException
    {
       Fqn fqn = node.getFqn();
       acquireLock(ctx, fqn); // lock node
       if (fqnList != null) fqnList.add(fqn);
 
       // now wrap and add to the context
-      NodeSPI rcn = wrapNodeForWriting(ctx, node);
+      NodeSPI rcn = wrapNodeForWriting(ctx, node, parent);
       if (rcn != null)
       {
          rcn.markForUpdate(dataContainer, writeSkewCheck);
-         Map<Object, InternalNode<?, ?>> children = rcn.getDelegationTarget().getChildrenMap();
-         for (InternalNode child : children.values()) lockForWritingRecursive(child, ctx, fqnList);
+         Map<Object, InternalNode<?, ?>> children = node.getChildrenMap();
+         for (InternalNode child : children.values()) lockForWritingRecursive(child, node, ctx, fqnList);
       }
    }
 
@@ -413,8 +415,8 @@
       ReadCommittedNode node = (ReadCommittedNode) ctx.lookUpNode(fqn);
       if (node == null)
       {
-         InternalNode in = dataContainer.peekInternalNode(fqn, false);
-         node = nodeFactory.createWrappedNode(in);
+         InternalNode[] nodes = dataContainer.peekInternalNodeAndDirectParent(fqn, false);
+         node = nodeFactory.createWrappedNode(nodes[0], nodes[1]);
          ctx.putLookedUpNode(fqn, node);
       }
 

Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -136,6 +136,11 @@
       delegate.addChild(child);
    }
 
+   public final void addChild(InternalNode<K, V> child, boolean safe)
+   {
+      delegate.addChild(child, safe);
+   }
+
    public final V remove(K key)
    {
       return delegate.remove(key);

Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/NullMarkerNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/NullMarkerNode.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/NullMarkerNode.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -1,7 +1,6 @@
 package org.jboss.cache.mvcc;
 
 import org.jboss.cache.DataContainer;
-import org.jboss.cache.InternalNode;
 
 /**
  * A marker node to represent a null node for repeatable read, so that a read that returns a null can continue to return
@@ -12,9 +11,9 @@
  */
 public class NullMarkerNode extends RepeatableReadNode
 {
-   public NullMarkerNode(InternalNode node)
+   public NullMarkerNode()
    {
-      super(node);
+      super(null, null);
    }
 
    /**

Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -24,7 +24,11 @@
 
    protected volatile InternalNode backup;
    protected byte flags = 0;
+   protected Fqn fqn;
 
+   protected InternalNode parent;
+   protected Fqn parentFqn;
+
    protected static enum Flags
    {
       CHANGED(0x1), CREATED(0x2), DELETED(0x4);
@@ -37,11 +41,18 @@
    }
 
    @SuppressWarnings("unchecked")
-   public ReadCommittedNode(InternalNode node)
+   public ReadCommittedNode(InternalNode node, InternalNode parent)
    {
       super(node);
+      this.parent = parent;
+      if (parent != null) parentFqn = parent.getFqn();
    }
 
+   public InternalNode getInternalParent()
+   {
+      return parent;
+   }
+
    /**
     * Tests whether a flag is set.
     *
@@ -79,6 +90,13 @@
       return false;
    }
 
+   // convenience fqn retrieval method
+   protected final Fqn fqn()
+   {
+      if (fqn == null) fqn = getFqn();
+      return fqn;
+   }
+
    @Override
    public void markForUpdate(DataContainer container, boolean writeSkewCheck)
    {
@@ -101,7 +119,7 @@
       // only do stuff if there are changes.
       if (isFlagSet(CHANGED))
       {
-         Fqn fqn = getFqn();
+         Fqn fqn = fqn();
          if (trace)
             log.trace("Updating node [" + fqn + "].  deleted=" + isDeleted() + " valid=" + isValid() + " changed=" + isChanged() + " created=" + isFlagSet(CREATED));
 
@@ -125,7 +143,7 @@
          {
             // add newly created nodes to parents.
             InternalNode parent = lookupParent(fqn, ctx, container);
-            parent.addChild(node);
+            parent.addChild(node, true); // we know this is safe since we calculated the parent from the child.  No need to have the parent re-do checks when adding the child again.
          }
          else
          {
@@ -156,8 +174,10 @@
     */
    protected final InternalNode lookupParent(Fqn fqn, InvocationContext ctx, DataContainer container) throws NodeNotExistsException
    {
+      if (parent != null) return parent;
+
       InternalNode retval;
-      Fqn parentFqn = fqn.getParent();
+      Fqn parentFqn = this.parentFqn == null ? fqn.getParent() : this.parentFqn; // use the class-level parentFqn where possible since this will already have a hashcode computed.
       NodeSPI parent = ctx.lookUpNode(parentFqn);
       // first check if the parent is cached in the context.
       if (parent != null)

Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java	2008-09-18 11:01:52 UTC (rev 6748)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java	2008-09-18 11:02:45 UTC (rev 6749)
@@ -6,7 +6,6 @@
 import org.jboss.cache.Fqn;
 import org.jboss.cache.InternalNode;
 import org.jboss.cache.InvocationContext;
-
 import static org.jboss.cache.mvcc.ReadCommittedNode.Flags.CHANGED;
 import static org.jboss.cache.mvcc.ReadCommittedNode.Flags.DELETED;
 import org.jboss.cache.optimistic.DataVersioningException;
@@ -21,9 +20,9 @@
 {
    private static final Log log = LogFactory.getLog(RepeatableReadNode.class);
 
-   public RepeatableReadNode(InternalNode node)
+   public RepeatableReadNode(InternalNode node, InternalNode parent)
    {
-      super(node);
+      super(node, parent);
    }
 
    @Override
@@ -31,7 +30,7 @@
    {
       if (isFlagSet(CHANGED)) return; // already copied
 
-      Fqn fqn = getFqn();
+      Fqn fqn = fqn();
 
       // mark node as changed.
       setFlag(CHANGED);
@@ -58,7 +57,7 @@
    @SuppressWarnings("unchecked")
    protected void updateNode(InvocationContext ctx, DataContainer dataContainer)
    {
-      Fqn fqn = getFqn();
+      Fqn fqn = fqn();
       if (fqn.isRoot())
       {
          dataContainer.setRoot(node);
@@ -66,7 +65,7 @@
       else if (!isFlagSet(DELETED))
       {
          InternalNode parent = lookupParent(fqn, ctx, dataContainer);
-         parent.addChild(node);
+         parent.addChild(node, true);  // we know this is safe since we calculated the parent from the child.  No need to have the parent re-do checks when adding the child again.
       }
    }
 }




More information about the jbosscache-commits mailing list