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 mr...@apache.org on 2013/02/25 13:50:20 UTC

svn commit: r1449687 - /jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java

Author: mreutegg
Date: Mon Feb 25 12:50:20 2013
New Revision: 1449687

URL: http://svn.apache.org/r1449687
Log:
OAK-638: Avoid branch/merge for small commits

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java?rev=1449687&r1=1449686&r2=1449687&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java Mon Feb 25 12:50:20 2013
@@ -19,9 +19,12 @@ package org.apache.jackrabbit.oak.kernel
 import org.apache.jackrabbit.mk.api.MicroKernel;
 import org.apache.jackrabbit.mk.api.MicroKernelException;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStoreBranch;
+import org.apache.jackrabbit.oak.spi.state.RebaseDiff;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -46,12 +49,15 @@ class KernelNodeStoreBranch implements N
     /** Revision of the base state of this branch*/
     private String baseRevision;
 
-    /** Root state of the head revision of this branch*/
+    /** Root state of the transient head revision on top of persisted branch, null if merged. */
     private NodeState head;
 
-    /** Head revision of this branch, null if not yet branched*/
+    /** Head revision of persisted branch, null if not yet branched*/
     private String headRevision;
 
+    /** Number of updates to this branch via {@link #setRoot(NodeState)} */
+    private int updates = 0;
+
     KernelNodeStoreBranch(KernelNodeStore store, KernelNodeState root) {
         this.store = store;
         this.base = root;
@@ -74,9 +80,20 @@ class KernelNodeStoreBranch implements N
     public void setRoot(NodeState newRoot) {
         checkNotMerged();
         if (!head.equals(newRoot)) {
-            JsopDiff diff = new JsopDiff(store.getKernel());
-            newRoot.compareAgainstBaseState(head, diff);
-            commit(diff.toString());
+            NodeState oldRoot = head;
+            head = newRoot;
+            if (++updates > 1) {
+                // persist unless this is the first update
+                boolean success = false;
+                try {
+                    persistTransientHead();
+                    success = true;
+                } finally {
+                    if (!success) {
+                        head = oldRoot;
+                    }
+                }
+            }
         }
     }
 
@@ -126,23 +143,36 @@ class KernelNodeStoreBranch implements N
     public NodeState merge(CommitHook hook) throws CommitFailedException {
         checkNotMerged();
         NodeState toCommit = checkNotNull(hook).processCommit(base, head);
-        NodeState oldRoot = head;
-        setRoot(toCommit);
+            NodeState oldRoot = head;
+        head = toCommit;
 
         try {
-            if (headRevision == null) {
+            if (head.equals(base)) {
                 // Nothing was written to this branch: return base state
                 head = null;  // Mark as merged
                 return base;
             } else {
                 MicroKernel kernel = store.getKernel();
-                String mergedRevision = kernel.merge(headRevision, null);
-                headRevision = null;
+                String newRevision;
+                JsopDiff diff = new JsopDiff(kernel);
+                if (headRevision == null) {
+                    // no branch created yet, commit directly
+                    head.compareAgainstBaseState(base, diff);
+                    newRevision = kernel.commit("", diff.toString(), baseRevision, null);
+                } else {
+                    // commit into branch and merge
+                    head.compareAgainstBaseState(store.getRootState(headRevision), diff);
+                    if (diff.toString().length() > 0) {
+                        headRevision = kernel.commit("", diff.toString(), headRevision, null);
+                    }
+                    newRevision = kernel.merge(headRevision, null);
+                    headRevision = null;
+                }
                 head = null;  // Mark as merged
-                return store.getRootState(mergedRevision);
+                return store.getRootState(newRevision);
             }
         } catch (MicroKernelException e) {
-            setRoot(oldRoot);
+            head = oldRoot;
             throw new CommitFailedException(e);
         }
     }
@@ -150,12 +180,22 @@ class KernelNodeStoreBranch implements N
     @Override
     public void rebase() {
         KernelNodeState root = store.getRoot();
-        if (headRevision == null) {
+        if (head.equals(root)) {
             // Nothing was written to this branch: set new base revision
             head = root;
             base = root;
             baseRevision = root.getRevision();
+        } else if (headRevision == null) {
+            // Nothing written to persistent branch yet
+            // perform rebase in memory
+            NodeBuilder builder = new MemoryNodeBuilder(root);
+            getRoot().compareAgainstBaseState(getBase(), new RebaseDiff(builder));
+            head = builder.getNodeState();
+            base = root;
+            baseRevision = root.getRevision();
         } else {
+            // perform rebase in kernel
+            persistTransientHead();
             headRevision = store.getKernel().rebase(headRevision, root.getRevision());
             head = store.getRootState(headRevision);
             base = root;
@@ -189,7 +229,56 @@ class KernelNodeStoreBranch implements N
             headRevision = kernel.branch(baseRevision);
         }
 
+        // persist transient changes first
+        persistTransientHead();
+
         headRevision = kernel.commit("", jsop, headRevision, null);
         head = store.getRootState(headRevision);
     }
+
+    private void persistTransientHead() {
+        NodeState oldBase = base;
+        String oldBaseRevision = baseRevision;
+        NodeState oldHead = head;
+        String oldHeadRevision = headRevision;
+        boolean success = false;
+        try {
+            MicroKernel kernel = store.getKernel();
+            JsopDiff diff = new JsopDiff(store.getKernel());
+            if (headRevision == null) {
+                // no persistent branch yet
+                if (head.equals(base)) {
+                    // nothing to persist
+                    success = true;
+                    return;
+                } else {
+                    // create branch
+                    headRevision = kernel.branch(baseRevision);
+                    head.compareAgainstBaseState(base, diff);
+                }
+            } else {
+                // compare against head of branch
+                NodeState branchHead = store.getRootState(headRevision);
+                if (head.equals(branchHead)) {
+                    // nothing to persist
+                    return;
+                } else {
+                    head.compareAgainstBaseState(branchHead, diff);
+                }
+            }
+            // if we get here we have something to persist
+            // and a branch exists
+            headRevision = kernel.commit("", diff.toString(), headRevision, null);
+            head = store.getRootState(headRevision);
+            success = true;
+        } finally {
+            // revert to old state if unsuccessful
+            if (!success) {
+                base = oldBase;
+                baseRevision = oldBaseRevision;
+                head = oldHead;
+                headRevision = oldHeadRevision;
+            }
+        }
+    }
 }