Index: oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java (revision 1447709) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java (working copy) @@ -46,12 +46,15 @@ /** 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 +77,11 @@ public void setRoot(NodeState newRoot) { checkNotMerged(); if (!head.equals(newRoot)) { - JsopDiff diff = new JsopDiff(store.getKernel()); - newRoot.compareAgainstBaseState(head, diff); - commit(diff.toString()); + head = newRoot; + if (++updates > 1) { + // persist unless this is the first update + persistTransientHead(); + } } } @@ -127,28 +132,42 @@ checkNotMerged(); NodeState toCommit = checkNotNull(hook).processCommit(base, head); NodeState oldRoot = head; - setRoot(toCommit); + 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); } } @Override public void rebase() { + persistTransientHead(); KernelNodeState root = store.getRoot(); if (headRevision == null) { // Nothing was written to this branch: set new base revision @@ -189,7 +208,39 @@ headRevision = kernel.branch(baseRevision); } + // persist transient changes first + persistTransientHead(); + headRevision = kernel.commit("", jsop, headRevision, null); head = store.getRootState(headRevision); } + + private void persistTransientHead() { + MicroKernel kernel = store.getKernel(); + JsopDiff diff = new JsopDiff(store.getKernel()); + if (headRevision == null) { + // no persistent branch yet + if (head.equals(base)) { + // nothing to persist + 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); + } } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderImpl.java =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderImpl.java (revision 1447709) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderImpl.java (working copy) @@ -16,7 +16,9 @@ */ package org.apache.jackrabbit.oak.security; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; import javax.annotation.Nonnull; @@ -55,9 +57,9 @@ @Nonnull @Override public Iterable getSecurityConfigurations() { - Set scs = new HashSet(); + List scs = new ArrayList(); + scs.add(getUserConfiguration()); scs.add(getAccessControlConfiguration()); - scs.add(getUserConfiguration()); scs.add(getPrincipalConfiguration()); scs.add(getPrivilegeConfiguration()); return scs;