You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2012/10/24 19:38:39 UTC

svn commit: r1401794 - in /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak: plugins/memory/MemoryNodeBuilder.java spi/state/NodeBuilder.java spi/state/ReadOnlyBuilder.java

Author: jukka
Date: Wed Oct 24 17:38:38 2012
New Revision: 1401794

URL: http://svn.apache.org/viewvc?rev=1401794&view=rev
Log:
OAK-170: Child node state builder

Add a NodeBuidler.reset(NodeState) method to make rebase operations possible with builders

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java?rev=1401794&r1=1401793&r2=1401794&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java Wed Oct 24 17:38:38 2012
@@ -103,7 +103,7 @@ public class MemoryNodeBuilder implement
      * The base state of this builder, or {@code null} if this builder
      * represents a new node that didn't yet exist in the base content tree.
      */
-    private final NodeState baseState;
+    private NodeState baseState;
 
     /**
      * The shared mutable state of connected builder instances, or
@@ -150,25 +150,34 @@ public class MemoryNodeBuilder implement
         if (revision != root.revision) {
             assert(parent != null); // root never gets here
             parent.read();
-            MutableNodeState pstate = parent.writeState;
-            if (pstate != null) {
-                MutableNodeState mstate = pstate.nodes.get(name);
-                if (mstate == null) {
-                    if (pstate.nodes.containsKey(name)) {
-                        throw new IllegalStateException(
-                                "This node has been removed.");
-                    }
-                } else if (mstate != writeState) {
-                    writeState = mstate;
+
+            // The builder could have been reset, need to re-get base state
+            if (parent.baseState != null) {
+                baseState = parent.baseState.getChildNode(name);
+            } else {
+                baseState = null;
+            }
+
+            // ... same for the write state
+            if (parent.writeState != null) {
+                writeState = parent.writeState.nodes.get(name);
+                if (writeState == null
+                        && parent.writeState.nodes.containsKey(name)) {
+                    throw new IllegalStateException(
+                            "This node has been removed");
                 }
+            } else {
+                writeState = null;
             }
+
             revision = root.revision;
         }
         if (writeState != null) {
             return writeState;
-        } else {
-            assert baseState != null; // new nodes must have a writeState
+        } else if (baseState != null) {
             return baseState;
+        } else {
+            throw new IllegalStateException("This node does not exist");
         }
     }
 
@@ -179,32 +188,36 @@ public class MemoryNodeBuilder implement
     private MutableNodeState write(long newRevision) {
         if (writeState == null || revision != root.revision) {
             assert(parent != null); // root never gets here
-            MutableNodeState pstate = parent.write(newRevision);
-            MutableNodeState mstate = pstate.nodes.get(name);
-            if (mstate == null) {
-                if (pstate.nodes.containsKey(name)) {
+            parent.write(newRevision);
+
+            // The builder could have been reset, need to re-get base state
+            if (parent.baseState != null) {
+                baseState = parent.baseState.getChildNode(name);
+            } else {
+                baseState = null;
+            }
+
+            assert parent.writeState != null; // we just called parent.write()
+            writeState = parent.writeState.nodes.get(name);
+            if (writeState == null) {
+                if (parent.writeState.nodes.containsKey(name)) {
                     throw new IllegalStateException(
-                            "This node has been removed.");
-                }
-                NodeState base = baseState;
-                if (base == null) {
-                    base = NULL_STATE;
+                            "This node has been removed");
+                } else {
+                    // need to make this node writable
+                    NodeState base = baseState;
+                    if (base == null) {
+                        base = NULL_STATE;
+                    }
+                    writeState = new MutableNodeState(base);
+                    parent.writeState.nodes.put(name, writeState);
                 }
-                mstate = new MutableNodeState(base);
-                pstate.nodes.put(name, mstate);
-            }
-            if (mstate != writeState) {
-                writeState = mstate;
             }
         }
         revision = newRevision;
         return writeState;
     }
 
-    protected void reset(NodeState newBase) {
-        write().reset(newBase);
-    }
-
     /**
      * Factory method for creating new child state builders. Subclasses may
      * override this method to control the behavior of child state builders.
@@ -253,6 +266,17 @@ public class MemoryNodeBuilder implement
     }
 
     @Override
+    public void reset(NodeState newBase) {
+        if (this == root) {
+            baseState = checkNotNull(newBase);
+            writeState = new MutableNodeState(baseState);
+            revision++;
+        } else {
+            throw new IllegalStateException("Cannot reset a non-root builder");
+        }
+    }
+
+    @Override
     public long getChildNodeCount() {
         return read().getChildNodeCount();
     }
@@ -349,31 +373,36 @@ public class MemoryNodeBuilder implement
 
     @Override
     public NodeBuilder child(String name) {
-        NodeState state = read();
-
+        // look for a read-only child node
+        read();
         if (writeState == null) {
-            NodeState base = state.getChildNode(name);
-            if (base != null) {
-                return createChildBuilder(name, base); // shortcut
+            assert baseState != null; // guaranteed by read()
+            NodeState childBase = baseState.getChildNode(name);
+            if (childBase != null) { // read-only shortcut
+                return createChildBuilder(name, childBase);
             }
         }
 
-        NodeState cbase = NULL_STATE;
-        MutableNodeState mstate = write();
-        MutableNodeState cstate = mstate.nodes.get(name);
-        if (cstate != null) {
-            cbase = cstate.base;
-        } else if (mstate.nodes.containsKey(name)) {
-            // The child node was removed earlier and we're creating
-            // a new child with the same name. Remove the removal marker
-            // so that the new child builder won't try reconnecting with
-            // the previously removed node.
-            mstate.nodes.remove(name);
-        } else if (mstate.base.hasChildNode(name)) {
-            return createChildBuilder(name, mstate.base.getChildNode(name));
+        // no read-only child node found, switch to write mode
+        write();
+        assert writeState != null; // guaranteed by write()
+
+        NodeState childBase = null;
+        if (baseState != null) {
+            childBase = baseState.getChildNode(name);
         }
 
-        MemoryNodeBuilder builder = createChildBuilder(name, cbase);
+        if (writeState.nodes.get(name) == null) {
+            if (writeState.nodes.containsKey(name)) {
+                // The child node was removed earlier and we're creating
+                // a new child with the same name. Use the null state to
+                // prevent the previous child state from re-surfacing.
+                childBase = null;
+            }
+            writeState.nodes.put(name, new MutableNodeState(childBase));
+        }
+
+        MemoryNodeBuilder builder = createChildBuilder(name, childBase);
         builder.write();
         return builder;
     }
@@ -442,7 +471,11 @@ public class MemoryNodeBuilder implement
                 Maps.newHashMap();
 
         public MutableNodeState(NodeState base) {
-            this.base = checkNotNull(base);
+            if (base != null) {
+                this.base = base;
+            } else {
+                this.base = NULL_STATE;
+            }
         }
 
         private void reset(NodeState newBase) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java?rev=1401794&r1=1401793&r2=1401794&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java Wed Oct 24 17:38:38 2012
@@ -47,6 +47,23 @@ public interface NodeBuilder {
     NodeState getBaseState();
 
     /**
+     * Replaces the base state of this builder and throws away all changes.
+     * The effect of this method is equivalent to replacing this builder
+     * (and the connected subtree) with a new builder returned by
+     * {@code state.builder()}.
+     * <p>
+     * This method only works on builders acquired directly from a call
+     * to {@link NodeState#builder()}. Calling it on a builder returned
+     * by the {@link #child(String)} method will throw an
+     * {@link IllegalStateException}.
+     *
+     * @param state new base state
+     * @throws IllegalStateException if this is not a root builder
+     */
+    void reset(@Nonnull NodeState state)
+        throws IllegalStateException;
+
+    /**
      * Returns the current number of child nodes.
      *
      * @return number of child nodes

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java?rev=1401794&r1=1401793&r2=1401794&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java Wed Oct 24 17:38:38 2012
@@ -48,6 +48,11 @@ public class ReadOnlyBuilder implements 
     }
 
     @Override
+    public void reset(NodeState state) {
+        throw unsupported();
+    }
+
+    @Override
     public long getChildNodeCount() {
         return state.getChildNodeCount();
     }