Index: src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java (revision 1536617) +++ src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java (working copy) @@ -248,8 +248,8 @@ } } - NodeStoreBranch createBranch(NodeState base) { - return new KernelNodeStoreBranch(this, mergeLock, (KernelNodeState) base); + NodeStoreBranch createBranch(KernelNodeState base) { + return new KernelNodeStoreBranch(this, changeDispatcher, mergeLock, base); } MicroKernel getKernel() { @@ -257,6 +257,10 @@ } KernelNodeState commit(String jsop, KernelNodeState base) { + if (jsop.isEmpty()) { + // nothing to commit + return base; + } KernelNodeState rootState = getRootState(kernel.commit("", jsop, base.getRevision(), null)); if (base.isBranch()) { rootState.setBranch(); @@ -272,20 +276,7 @@ return getRootState(kernel.rebase(branchHead.getRevision(), base.getRevision())).setBranch(); } - NodeState merge(KernelNodeState branchHead) { + KernelNodeState merge(KernelNodeState branchHead) { return getRootState(kernel.merge(branchHead.getRevision(), null)); } - - void beforeCommit(NodeState root) { - changeDispatcher.beforeCommit(root); - } - - void localCommit(NodeState root, CommitInfo info) { - changeDispatcher.localCommit(root, info); - } - - void afterCommit(NodeState root) { - changeDispatcher.afterCommit(root); - } - } Index: src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java (revision 1536363) +++ src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java (working copy) @@ -1,462 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jackrabbit.oak.kernel; - -import static com.google.common.base.Preconditions.checkNotNull; -import static org.apache.jackrabbit.oak.commons.PathUtils.elements; -import static org.apache.jackrabbit.oak.commons.PathUtils.getName; -import static org.apache.jackrabbit.oak.commons.PathUtils.getParentPath; - -import java.io.IOException; -import java.util.concurrent.locks.Lock; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import org.apache.jackrabbit.mk.api.MicroKernel; -import org.apache.jackrabbit.mk.api.MicroKernelException; -import org.apache.jackrabbit.oak.api.Blob; -import org.apache.jackrabbit.oak.api.CommitFailedException; -import org.apache.jackrabbit.oak.commons.PathUtils; -import org.apache.jackrabbit.oak.spi.commit.CommitHook; -import org.apache.jackrabbit.oak.spi.commit.CommitInfo; -import org.apache.jackrabbit.oak.spi.state.ConflictAnnotatingRebaseDiff; -import org.apache.jackrabbit.oak.spi.state.NodeBuilder; -import org.apache.jackrabbit.oak.spi.state.NodeState; -import org.apache.jackrabbit.oak.spi.state.NodeStoreBranch; - -/** - * {@code NodeStoreBranch} based on {@link MicroKernel} branching and merging. - * This implementation keeps changes in memory up to a certain limit and writes - * them back to the Microkernel branch when the limit is exceeded. - */ -class KernelNodeStoreBranch implements NodeStoreBranch { - - /** The underlying store to which this branch belongs */ - private final KernelNodeStore store; - - /** Lock for coordinating concurrent merge operations */ - private final Lock mergeLock; - - /** - * State of the this branch. Either {@link Unmodified}, {@link InMemory}, {@link Persisted} - * or {@link Merged}. - * @see BranchState - */ - private BranchState branchState; - - private final BlobSerializer blobs = new BlobSerializer() { - @Override - public String serialize(Blob blob) { - KernelBlob kernelBlob; - if (blob instanceof KernelBlob) { - kernelBlob = (KernelBlob) blob; - } else { - try { - kernelBlob = store.createBlob(blob.getNewStream()); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - return kernelBlob.getBinaryID(); - } - }; - - public KernelNodeStoreBranch(KernelNodeStore kernelNodeStore, Lock mergeLock, - KernelNodeState base) { - - this.store = checkNotNull(kernelNodeStore); - this.mergeLock = checkNotNull(mergeLock); - branchState = new Unmodified(checkNotNull(base)); - } - - @Override - public String toString() { - return branchState.toString(); - } - - @Nonnull - @Override - public NodeState getBase() { - return branchState.getBase(); - } - - @Nonnull - @Override - public NodeState getHead() { - return branchState.getHead(); - } - - @Override - public void setRoot(NodeState newRoot) { - branchState.setRoot(checkNotNull(newRoot)); - } - - @Override - public boolean move(String source, String target) { - if (PathUtils.isAncestor(checkNotNull(source), checkNotNull(target))) { - return false; - } else if (source.equals(target)) { - return true; - } - - if (!getNode(source).exists()) { - // source does not exist - return false; - } - NodeState destParent = getNode(getParentPath(target)); - if (!destParent.exists()) { - // parent of destination does not exist - return false; - } - if (destParent.getChildNode(getName(target)).exists()) { - // destination exists already - return false; - } - branchState.persist().commit(">\"" + source + "\":\"" + target + '"'); - return true; - } - - @Override - public boolean copy(String source, String target) { - if (!getNode(checkNotNull(source)).exists()) { - // source does not exist - return false; - } - NodeState destParent = getNode(getParentPath(checkNotNull(target))); - if (!destParent.exists()) { - // parent of destination does not exist - return false; - } - if (destParent.getChildNode(getName(target)).exists()) { - // destination exists already - return false; - } - branchState.persist().commit("*\"" + source + "\":\"" + target + '"'); - return true; - } - - @Nonnull - @Override - public NodeState merge(@Nonnull CommitHook hook, @Nullable CommitInfo info) - throws CommitFailedException { - return branchState.merge(checkNotNull(hook), info); - } - - @Override - public void rebase() { - branchState.rebase(); - } - - private NodeState getNode(String path) { - NodeState node = getHead(); - for (String name : elements(path)) { - node = node.getChildNode(name); - } - return node; - } - - /** - * Sub classes of this class represent a state a branch can be in. See the individual - * sub classes for permissible state transitions. - */ - private abstract class BranchState { - /** Root state of the base revision of this branch */ - protected KernelNodeState base; - - protected BranchState(KernelNodeState base) { - this.base = base; - } - - /** - * Persist this branch to an underlying branch in the {@code MicroKernel}. - */ - Persisted persist() { - branchState = new Persisted(base, getHead()); - return (Persisted) branchState; - } - - KernelNodeState getBase(){ - return base; - } - - @Nonnull - abstract NodeState getHead(); - - abstract void setRoot(NodeState root); - - abstract void rebase(); - - @Nonnull - abstract NodeState merge(@Nonnull CommitHook hook, @Nullable CommitInfo info) - throws CommitFailedException; - } - - /** - * Instances of this class represent a branch whose base and head are the same. - *

- * Transitions to: - *

- */ - private class Unmodified extends BranchState { - Unmodified(KernelNodeState base) { - super(base); - } - - @Override - public String toString() { - return "Unmodified[" + base + ']'; - } - - @Override - NodeState getHead() { - return base; - } - - @Override - void setRoot(NodeState root) { - if (!base.equals(root)) { - branchState = new InMemory(base, root); - } - } - - @Override - void rebase() { - base = store.getRoot(); - } - - @Override - NodeState merge(CommitHook hook, CommitInfo info) throws CommitFailedException { - branchState = new Merged(base); - return base; - } - } - - /** - * Instances of this class represent a branch whose base and head differ. - * All changes are kept in memory. - *

- * Transitions to: - *

- */ - private class InMemory extends BranchState { - /** Root state of the transient head. */ - private NodeState head; - - @Override - public String toString() { - return "InMemory[" + base + ", " + head + ']'; - } - - InMemory(KernelNodeState base, NodeState head) { - super(base); - this.head = head; - } - - @Override - NodeState getHead() { - return head; - } - - @Override - void setRoot(NodeState root) { - if (base.equals(root)) { - branchState = new Unmodified(base); - } else if (!head.equals(root)) { - head = root; - persist(); - } - } - - @Override - void rebase() { - KernelNodeState root = store.getRoot(); - NodeBuilder builder = root.builder(); - head.compareAgainstBaseState(base, new ConflictAnnotatingRebaseDiff(builder)); - head = builder.getNodeState(); - base = root; - } - - @Override - NodeState merge(CommitHook hook, CommitInfo info) throws CommitFailedException { - mergeLock.lock(); - try { - rebase(); - store.beforeCommit(base); - NodeState toCommit = checkNotNull(hook).processCommit(base, head); - JsopDiff diff = new JsopDiff(blobs); - toCommit.compareAgainstBaseState(base, diff); - NodeState newHead = store.commit(diff.toString(), base); - store.localCommit(newHead, info); - branchState = new Merged(base); - return newHead; - } catch (MicroKernelException e) { - throw new CommitFailedException( - "Kernel", 1, - "Failed to merge changes to the underlying MicroKernel", e); - } finally { - store.afterCommit(store.getRoot()); - mergeLock.unlock(); - } - } - } - - /** - * Instances of this class represent a branch whose base and head differ. - * All changes are persisted to an underlying branch in the {@code MicroKernel}. - *

- * Transitions to: - *

- */ - private class Persisted extends BranchState { - /** Root state of the transient head, top of persisted branch. */ - private KernelNodeState head; - - @Override - public String toString() { - return "Persisted[" + base + ", " + head + ']'; - } - - Persisted(KernelNodeState base, NodeState head) { - super(base); - this.head = store.branch(base); - persistTransientHead(head); - } - - void commit(String jsop) { - if (!jsop.isEmpty()) { - head = store.commit(jsop, head); - } - } - - @Override - NodeState getHead() { - return head; - } - - @Override - void setRoot(NodeState root) { - if (base.equals(root)) { - branchState = new Unmodified(base); - } else if (!head.equals(root)) { - persistTransientHead(root); - } - } - - @Override - void rebase() { - KernelNodeState root = store.getRoot(); - if (head.equals(root)) { - // Nothing was written to this branch: set new base revision - head = root; - base = root; - } else { - // perform rebase in kernel - head = store.rebase(head, root); - base = root; - } - } - - @Override - NodeState merge(CommitHook hook, CommitInfo info) throws CommitFailedException { - mergeLock.lock(); - try { - rebase(); - store.beforeCommit(base); - NodeState toCommit = checkNotNull(hook).processCommit(base, head); - if (toCommit.equals(base)) { - branchState = new Merged(base); - return base; - } else { - JsopDiff diff = new JsopDiff(blobs); - toCommit.compareAgainstBaseState(head, diff); - commit(diff.toString()); - NodeState newRoot = store.merge(head); - store.localCommit(newRoot, info); - branchState = new Merged(base); - return newRoot; - } - } catch (MicroKernelException e) { - throw new CommitFailedException( - "Kernel", 1, - "Failed to merge changes to the underlying MicroKernel", e); - } finally { - store.afterCommit(store.getRoot()); - mergeLock.unlock(); - } - } - - private void persistTransientHead(NodeState newHead) { - if (!newHead.equals(head)) { - JsopDiff diff = new JsopDiff(blobs); - newHead.compareAgainstBaseState(head, diff); - head = store.commit(diff.toString(), head); - } - } - } - - /** - * Instances of this class represent a branch that has already been merged. - * All methods throw an {@code IllegalStateException}. - *

- * Transitions to: none. - */ - private class Merged extends BranchState { - protected Merged(KernelNodeState base) { - super(base); - } - - @Override - public String toString() { - return "Merged[" + base + ']'; - } - - @Override - NodeState getHead() { - throw new IllegalStateException("Branch has already been merged"); - } - - @Override - void setRoot(NodeState root) { - throw new IllegalStateException("Branch has already been merged"); - } - - @Override - void rebase() { - throw new IllegalStateException("Branch has already been merged"); - } - - @Override - NodeState merge(CommitHook hook, CommitInfo info) throws CommitFailedException { - throw new IllegalStateException("Branch has already been merged"); - } - } - -} Index: src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java (revision 0) +++ src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreBranch.java (revision 1536363) @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jackrabbit.oak.kernel; + +import java.io.IOException; +import java.util.concurrent.locks.Lock; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.apache.jackrabbit.mk.api.MicroKernel; +import org.apache.jackrabbit.mk.api.MicroKernelException; +import org.apache.jackrabbit.oak.api.Blob; +import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.plugins.observation.ChangeDispatcher; +import org.apache.jackrabbit.oak.spi.commit.CommitHook; +import org.apache.jackrabbit.oak.spi.commit.CommitInfo; +import org.apache.jackrabbit.oak.spi.state.AbstractNodeStoreBranch; +import org.apache.jackrabbit.oak.spi.state.NodeState; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * {@code NodeStoreBranch} based on {@link MicroKernel} branching and merging. + * This implementation keeps changes in memory up to a certain limit and writes + * them back to the Microkernel branch when the limit is exceeded. + */ +public class KernelNodeStoreBranch extends + AbstractNodeStoreBranch { + + /** Lock for coordinating concurrent merge operations */ + private final Lock mergeLock; + + private final BlobSerializer blobs = new BlobSerializer() { + @Override + public String serialize(Blob blob) { + KernelBlob kernelBlob; + if (blob instanceof KernelBlob) { + kernelBlob = (KernelBlob) blob; + } else { + try { + kernelBlob = store.createBlob(blob.getNewStream()); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + return kernelBlob.getBinaryID(); + } + }; + + public KernelNodeStoreBranch(KernelNodeStore kernelNodeStore, + ChangeDispatcher dispatcher, + Lock mergeLock, + KernelNodeState base) { + super(kernelNodeStore, dispatcher, base); + this.mergeLock = checkNotNull(mergeLock); + } + + //----------------------< AbstractNodeStoreBranch >------------------------- + + @Override + public KernelNodeState createBranch(KernelNodeState state) { + return store.branch(state); + } + + @Override + public KernelNodeState getRoot() { + return store.getRoot(); + } + + @Override + protected KernelNodeState rebase(KernelNodeState branchHead, + KernelNodeState base) { + return store.rebase(branchHead, base); + } + + @Override + protected KernelNodeState merge(KernelNodeState branchHead) { + return store.merge(branchHead); + } + + @Override + protected KernelNodeState persist(NodeState toPersist, KernelNodeState base) { + JsopDiff diff = new JsopDiff(blobs); + toPersist.compareAgainstBaseState(base, diff); + return store.commit(diff.toString(), base); + } + + @Override + protected KernelNodeState copy(String source, + String target, + KernelNodeState base) { + return store.commit("*\"" + source + "\":\"" + target + '"', base); + } + + @Override + protected KernelNodeState move(String source, + String target, + KernelNodeState base) { + return store.commit(">\"" + source + "\":\"" + target + '"', base); + } + +//------------------------< NodeStoreBranch >------------------------------- + + @Nonnull + @Override + public NodeState merge(@Nonnull CommitHook hook, @Nullable CommitInfo info) + throws CommitFailedException { + mergeLock.lock(); + try { + return super.merge(hook, info); + } catch (MicroKernelException e) { + throw new CommitFailedException( + "Kernel", 1, + "Failed to merge changes to the underlying MicroKernel", e); + } finally { + mergeLock.unlock(); + } + } +} Property changes on: src\main\java\org\apache\jackrabbit\oak\kernel\KernelNodeStoreBranch.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision Rev URL Added: svn:eol-style + native Index: src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeStoreBranch.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeStoreBranch.java (revision 1536363) +++ src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeStoreBranch.java (working copy) @@ -14,76 +14,136 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.jackrabbit.oak.kernel; +package org.apache.jackrabbit.oak.spi.state; import static com.google.common.base.Preconditions.checkNotNull; import static org.apache.jackrabbit.oak.commons.PathUtils.elements; import static org.apache.jackrabbit.oak.commons.PathUtils.getName; import static org.apache.jackrabbit.oak.commons.PathUtils.getParentPath; -import java.io.IOException; -import java.util.concurrent.locks.Lock; - import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.apache.jackrabbit.mk.api.MicroKernel; -import org.apache.jackrabbit.mk.api.MicroKernelException; -import org.apache.jackrabbit.oak.api.Blob; import org.apache.jackrabbit.oak.api.CommitFailedException; import org.apache.jackrabbit.oak.commons.PathUtils; +import org.apache.jackrabbit.oak.plugins.observation.ChangeDispatcher; import org.apache.jackrabbit.oak.spi.commit.CommitHook; import org.apache.jackrabbit.oak.spi.commit.CommitInfo; -import org.apache.jackrabbit.oak.spi.state.ConflictAnnotatingRebaseDiff; -import org.apache.jackrabbit.oak.spi.state.NodeBuilder; -import org.apache.jackrabbit.oak.spi.state.NodeState; -import org.apache.jackrabbit.oak.spi.state.NodeStoreBranch; /** - * {@code NodeStoreBranch} based on {@link MicroKernel} branching and merging. + * A base implementation of a node store branch, which supports partially + * persisted branches. + *

* This implementation keeps changes in memory up to a certain limit and writes - * them back to the Microkernel branch when the limit is exceeded. + * them back to the underlying branch when the limit is exceeded. */ -class KernelNodeStoreBranch implements NodeStoreBranch { +public abstract class AbstractNodeStoreBranch + implements NodeStoreBranch { /** The underlying store to which this branch belongs */ - private final KernelNodeStore store; + protected final S store; - /** Lock for coordinating concurrent merge operations */ - private final Lock mergeLock; + /** The dispatcher to report changes */ + protected final ChangeDispatcher dispatcher; /** * State of the this branch. Either {@link Unmodified}, {@link InMemory}, {@link Persisted} * or {@link Merged}. * @see BranchState */ - private BranchState branchState; + protected BranchState branchState; - private final BlobSerializer blobs = new BlobSerializer() { - @Override - public String serialize(Blob blob) { - KernelBlob kernelBlob; - if (blob instanceof KernelBlob) { - kernelBlob = (KernelBlob) blob; - } else { - try { - kernelBlob = store.createBlob(blob.getNewStream()); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - return kernelBlob.getBinaryID(); - } - }; + public AbstractNodeStoreBranch(S kernelNodeStore, + ChangeDispatcher dispatcher, + N base) { - public KernelNodeStoreBranch(KernelNodeStore kernelNodeStore, Lock mergeLock, - KernelNodeState base) { - this.store = checkNotNull(kernelNodeStore); - this.mergeLock = checkNotNull(mergeLock); + this.dispatcher = dispatcher; branchState = new Unmodified(checkNotNull(base)); } + /** + * @return the current root of the underlying store. + */ + protected abstract N getRoot(); + + /** + * Create a new branch state from the given state. + * + * @param state the state from where to create a branch from. + * @return the branch state. + */ + protected abstract N createBranch(N state); + + /** + * Rebases the branch head to the given base. + * + * @param branchHead the head state of a branch. + * @param base the new base state for the branch. + * @return the rebased branch head. + */ + protected abstract N rebase(N branchHead, N base); + + /** + * Merges the branch head and returns the result state of the merge. + * + * @param branchHead the head of the branch to merge. + * @return the result state of the merge. + */ + protected abstract N merge(N branchHead); + + /** + * Persists the changes between toPersist and base + * to the underlying store. + *

+ * While this method does not declare any exceptions to be thrown, an + * implementation may still throw a runtime exception specific to the + * concrete implementation of this node store branch. + * + * @param toPersist the state with the changes on top of base. + * @param base the base state. + * @return the state with the persisted changes. + */ + protected abstract N persist(NodeState toPersist, N base); + + /** + * Perform a potentially optimized copy operation directly on the underlying + * store. + *

+ * This base class ensures that preconditions are met (e.g. the source + * exists), which means an implementation of this method just needs to + * perform the copy operation. + *

+ * While this method does not declare any exceptions to be thrown, an + * implementation may still throw a runtime exception specific to the + * concrete implementation of this node store branch. + * + * @param source the source of the copy operation. + * @param target the destination of the copy operation. + * @param base the base state. + * @return the result of the copy operation. + */ + protected abstract N copy(String source, String target, N base); + + /** + * Perform a potentially optimized move operation directly on the underlying + * store. + *

+ * This base class ensures that preconditions are met (e.g. the source + * exists), which means an implementation of this method just needs to + * perform the move operation. + *

+ * While this method does not declare any exceptions to be thrown, an + * implementation may still throw a runtime exception specific to the + * concrete implementation of this node store branch. + * + * @param source the source of the move operation. + * @param target the destination of the move operation. + * @param base the base state. + * @return the result of the move operation. + */ + protected abstract N move(String source, String target, N base); + @Override public String toString() { return branchState.toString(); @@ -127,7 +187,7 @@ // destination exists already return false; } - branchState.persist().commit(">\"" + source + "\":\"" + target + '"'); + branchState.persist().move(source, target); return true; } @@ -146,7 +206,7 @@ // destination exists already return false; } - branchState.persist().commit("*\"" + source + "\":\"" + target + '"'); + branchState.persist().copy(source, target); return true; } @@ -162,6 +222,8 @@ branchState.rebase(); } + //----------------------------< internal >---------------------------------- + private NodeState getNode(String path) { NodeState node = getHead(); for (String name : elements(path)) { @@ -176,9 +238,9 @@ */ private abstract class BranchState { /** Root state of the base revision of this branch */ - protected KernelNodeState base; + protected N base; - protected BranchState(KernelNodeState base) { + protected BranchState(N base) { this.base = base; } @@ -186,11 +248,12 @@ * Persist this branch to an underlying branch in the {@code MicroKernel}. */ Persisted persist() { - branchState = new Persisted(base, getHead()); - return (Persisted) branchState; + Persisted p = new Persisted(base, getHead()); + branchState = p; + return p; } - KernelNodeState getBase(){ + N getBase(){ return base; } @@ -201,6 +264,21 @@ abstract void rebase(); + /** + * Runs the commit hook on the changes tracked with this branch state + * merges the result. + *

+ * In addition to the {@link CommitFailedException}, an implementation + * may also throw an unchecked exception when an error occurs while + * persisting the changes. This exception is implementation specific + * and it is the responsibility of the caller to convert it into a + * {@link CommitFailedException}. + * + * @param hook the commit hook to run. + * @param info the associated commit info. + * @return the result of the merge. + * @throws CommitFailedException if a commit hook rejected the changes. + */ @Nonnull abstract NodeState merge(@Nonnull CommitHook hook, @Nullable CommitInfo info) throws CommitFailedException; @@ -217,7 +295,7 @@ * */ private class Unmodified extends BranchState { - Unmodified(KernelNodeState base) { + Unmodified(N base) { super(base); } @@ -227,6 +305,7 @@ } @Override + @Nonnull NodeState getHead() { return base; } @@ -240,11 +319,12 @@ @Override void rebase() { - base = store.getRoot(); + base = getRoot(); } @Override - NodeState merge(CommitHook hook, CommitInfo info) throws CommitFailedException { + @Nonnull + NodeState merge(@Nonnull CommitHook hook, CommitInfo info) { branchState = new Merged(base); return base; } @@ -271,12 +351,13 @@ return "InMemory[" + base + ", " + head + ']'; } - InMemory(KernelNodeState base, NodeState head) { + InMemory(N base, NodeState head) { super(base); this.head = head; } @Override + @Nonnull NodeState getHead() { return head; } @@ -293,7 +374,7 @@ @Override void rebase() { - KernelNodeState root = store.getRoot(); + N root = getRoot(); NodeBuilder builder = root.builder(); head.compareAgainstBaseState(base, new ConflictAnnotatingRebaseDiff(builder)); head = builder.getNodeState(); @@ -301,25 +382,19 @@ } @Override - NodeState merge(CommitHook hook, CommitInfo info) throws CommitFailedException { - mergeLock.lock(); + @Nonnull + NodeState merge(@Nonnull CommitHook hook, CommitInfo info) + throws CommitFailedException { try { rebase(); - store.beforeCommit(base); + dispatcher.beforeCommit(base); NodeState toCommit = checkNotNull(hook).processCommit(base, head); - JsopDiff diff = new JsopDiff(blobs); - toCommit.compareAgainstBaseState(base, diff); - NodeState newHead = store.commit(diff.toString(), base); - store.localCommit(newHead, info); + NodeState newHead = AbstractNodeStoreBranch.this.persist(toCommit, base); + dispatcher.localCommit(newHead, info); branchState = new Merged(base); return newHead; - } catch (MicroKernelException e) { - throw new CommitFailedException( - "Kernel", 1, - "Failed to merge changes to the underlying MicroKernel", e); } finally { - store.afterCommit(store.getRoot()); - mergeLock.unlock(); + dispatcher.afterCommit(getRoot()); } } } @@ -337,26 +412,29 @@ */ private class Persisted extends BranchState { /** Root state of the transient head, top of persisted branch. */ - private KernelNodeState head; + private N head; @Override public String toString() { return "Persisted[" + base + ", " + head + ']'; } - Persisted(KernelNodeState base, NodeState head) { + Persisted(N base, NodeState head) { super(base); - this.head = store.branch(base); + this.head = createBranch(base); persistTransientHead(head); } - void commit(String jsop) { - if (!jsop.isEmpty()) { - head = store.commit(jsop, head); - } + void move(String source, String target) { + head = AbstractNodeStoreBranch.this.move(source, target, head); } + void copy(String source, String target) { + head = AbstractNodeStoreBranch.this.copy(source, target, head); + } + @Override + @Nonnull NodeState getHead() { return head; } @@ -372,52 +450,43 @@ @Override void rebase() { - KernelNodeState root = store.getRoot(); + N root = getRoot(); if (head.equals(root)) { // Nothing was written to this branch: set new base revision head = root; base = root; } else { - // perform rebase in kernel - head = store.rebase(head, root); + // perform rebase in store + head = AbstractNodeStoreBranch.this.rebase(head, root); base = root; } } @Override - NodeState merge(CommitHook hook, CommitInfo info) throws CommitFailedException { - mergeLock.lock(); + @Nonnull + NodeState merge(@Nonnull CommitHook hook, CommitInfo info) throws CommitFailedException { try { rebase(); - store.beforeCommit(base); + dispatcher.beforeCommit(base); NodeState toCommit = checkNotNull(hook).processCommit(base, head); if (toCommit.equals(base)) { branchState = new Merged(base); return base; } else { - JsopDiff diff = new JsopDiff(blobs); - toCommit.compareAgainstBaseState(head, diff); - commit(diff.toString()); - NodeState newRoot = store.merge(head); - store.localCommit(newRoot, info); + head = AbstractNodeStoreBranch.this.persist(toCommit, head); + NodeState newRoot = AbstractNodeStoreBranch.this.merge(head); + dispatcher.localCommit(newRoot, info); branchState = new Merged(base); return newRoot; } - } catch (MicroKernelException e) { - throw new CommitFailedException( - "Kernel", 1, - "Failed to merge changes to the underlying MicroKernel", e); } finally { - store.afterCommit(store.getRoot()); - mergeLock.unlock(); + dispatcher.afterCommit(getRoot()); } } private void persistTransientHead(NodeState newHead) { if (!newHead.equals(head)) { - JsopDiff diff = new JsopDiff(blobs); - newHead.compareAgainstBaseState(head, diff); - head = store.commit(diff.toString(), head); + head = AbstractNodeStoreBranch.this.persist(newHead, head); } } } @@ -429,7 +498,7 @@ * Transitions to: none. */ private class Merged extends BranchState { - protected Merged(KernelNodeState base) { + protected Merged(N base) { super(base); } @@ -439,6 +508,7 @@ } @Override + @Nonnull NodeState getHead() { throw new IllegalStateException("Branch has already been merged"); } @@ -454,7 +524,8 @@ } @Override - NodeState merge(CommitHook hook, CommitInfo info) throws CommitFailedException { + @Nonnull + NodeState merge(@Nonnull CommitHook hook, CommitInfo info) { throw new IllegalStateException("Branch has already been merged"); } } Property changes on: src\main\java\org\apache\jackrabbit\oak\spi\state\AbstractNodeStoreBranch.java ___________________________________________________________________ Added: svn:eol-style + native