Index: oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java (revision ) @@ -92,6 +92,17 @@ return exists() && builder.remove(); } + + @Override + public boolean moveTo(NodeBuilder newParent, String newName) { + return exists() && builder.moveTo(newParent, newName); + } + + @Override + public boolean copyTo(NodeBuilder newParent, String newName) { + return exists() && builder.copyTo(newParent, newName); + } + @Override @CheckForNull public PropertyState getProperty(String name) { PropertyState property = builder.getProperty(name); Index: oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingIndexTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingIndexTest.java (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingIndexTest.java (revision ) @@ -20,26 +20,28 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import org.apache.jackrabbit.mk.api.MicroKernel; import org.apache.jackrabbit.mk.core.MicroKernelImpl; import org.apache.jackrabbit.oak.kernel.KernelNodeState; +import org.apache.jackrabbit.oak.kernel.KernelNodeStore; import org.apache.jackrabbit.oak.spi.query.Cursor; import org.junit.Test; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; - /** * Tests the TraversingCursor. */ public class TraversingIndexTest { - private final MicroKernel mk = new MicroKernelImpl(); + private final KernelNodeStore store = new KernelNodeStore(mk); private final LoadingCache cache = CacheBuilder.newBuilder().build(new CacheLoader() { @@ -50,14 +52,10 @@ String path = key.substring(slash); // this method is strictly called _after_ the cache is initialized, // when the fields are set - return new KernelNodeState(getMicroKernel(), path, revision, getCache()); + return new KernelNodeState(store, path, revision, getCache()); } }); - + - MicroKernel getMicroKernel() { - return mk; - } - LoadingCache getCache() { return cache; } @@ -73,7 +71,7 @@ f.setPath("/"); List paths = new ArrayList(); - Cursor c = t.query(f, new KernelNodeState(mk, "/", head, cache)); + Cursor c = t.query(f, new KernelNodeState(store, "/", head, cache)); while (c.hasNext()) { paths.add(c.next().getPath()); } @@ -88,7 +86,7 @@ assertFalse(c.hasNext()); f.setPath("/nowhere"); - c = t.query(f, new KernelNodeState(mk, "/", head, cache)); + c = t.query(f, new KernelNodeState(store, "/", head, cache)); assertFalse(c.hasNext()); // endure it stays false assertFalse(c.hasNext()); Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStore.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStore.java (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeStore.java (revision ) @@ -23,6 +23,8 @@ import javax.annotation.Nonnull; import org.apache.jackrabbit.oak.api.Blob; +import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.spi.commit.CommitHook; /** * Storage abstraction for trees. At any given point in time the stored @@ -41,6 +43,8 @@ */ @Nonnull NodeState getRoot(); + + NodeState setRoot(@Nonnull NodeBuilder builder, @Nonnull CommitHook commitHook) throws CommitFailedException; /** * Creates a new branch of the tree to which transient changes can be applied. Index: oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java (revision ) @@ -24,9 +24,6 @@ import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.MISSING_NODE; import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; @@ -94,16 +91,10 @@ * path and revision. This object is only used internally and never leaves * this {@link KernelNodeState}. */ - private static final KernelNodeState NULL = new KernelNodeState( - (MicroKernel) Proxy.newProxyInstance(MicroKernel.class.getClassLoader(), - new Class[]{MicroKernel.class}, new InvocationHandler() { - @Override - public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable { - throw new UnsupportedOperationException(); - } - }), "null", "null", DUMMY_CACHE); + private static final KernelNodeState NULL = new KernelNodeState(); + private final KernelNodeStore store; + private final MicroKernel kernel; private final String path; @@ -127,20 +118,29 @@ * given {@code path} and {@code revision}. It is an error if the * underlying Microkernel does not contain such a node. * - * @param kernel the underlying MicroKernel + * @param store the underlying KernelNodeStore * @param path the path of this KernelNodeState * @param revision the revision of the node to read from the kernel. * @param cache the KernelNodeState cache */ public KernelNodeState( - MicroKernel kernel, String path, String revision, + KernelNodeStore store, String path, String revision, LoadingCache cache) { - this.kernel = checkNotNull(kernel); + this.store = store; + this.kernel = store.getKernel(); this.path = checkNotNull(path); this.revision = checkNotNull(revision); this.cache = checkNotNull(cache); } + private KernelNodeState() { + this.store = null; + this.kernel = null; + this.path = "null"; + this.revision = "null"; + this.cache = DUMMY_CACHE; + } + private void init() { boolean initialized = false; synchronized (this) { @@ -390,7 +390,13 @@ @Override public NodeBuilder builder() { + if ("/".equals(path)) { + // FIXME shouldn't we return a MemoryNodeBuilder in case we are + // on a branch already (i.e. NodeStoreBranch.getHead())? + return new KernelRootBuilder(this, store); + } else { - return new MemoryNodeBuilder(this); + return new MemoryNodeBuilder(this); + } } /** Index: oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeBuilder.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeBuilder.java (revision ) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeBuilder.java (revision ) @@ -0,0 +1,51 @@ +package org.apache.jackrabbit.oak.kernel; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.apache.jackrabbit.oak.commons.PathUtils; +import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder; +import org.apache.jackrabbit.oak.spi.state.NodeBuilder; + +public class KernelNodeBuilder extends MemoryNodeBuilder { + + private final KernelRootBuilder root; + + public KernelNodeBuilder(MemoryNodeBuilder parent, String name, KernelRootBuilder root) { + super(parent, name); + this.root = checkNotNull(root); + } + + //--------------------------------------------------< MemoryNodeBuilder >--- + + @Override + protected MemoryNodeBuilder createChildBuilder(String name) { + return new KernelNodeBuilder(this, name, root); + } + + @Override + protected void updated() { + root.updated(); + } + + @Override + public boolean moveTo(NodeBuilder newParent, String newName) { + if (newParent instanceof KernelNodeBuilder) { + String source = getPath(); + String target = PathUtils.concat(((KernelNodeBuilder) newParent).getPath(), newName); + return root.move(source, target); + } else { + return super.moveTo(newParent, newName); + } + } + + @Override + public boolean copyTo(NodeBuilder newParent, String newName) { + if (newParent instanceof KernelNodeBuilder) { + String source = getPath(); + String target = PathUtils.concat(((KernelNodeBuilder) newParent).getPath(), newName); + return root.copy(source, target); + } else { + return super.copyTo(newParent, newName); + } + } +} Index: oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeStore.java (revision ) @@ -16,6 +16,9 @@ */ package org.apache.jackrabbit.oak.kernel; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + import java.io.IOException; import java.io.InputStream; import java.util.concurrent.ExecutionException; @@ -29,18 +32,17 @@ import com.google.common.cache.Weigher; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; - 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.spi.commit.CommitHook; import org.apache.jackrabbit.oak.spi.commit.EmptyObserver; import org.apache.jackrabbit.oak.spi.commit.Observer; import org.apache.jackrabbit.oak.spi.state.AbstractNodeStore; +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 static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - /** * {@code NodeStore} implementations against {@link MicroKernel}. */ @@ -81,7 +83,7 @@ int slash = key.indexOf('/'); String revision = key.substring(0, slash); String path = key.substring(slash); - return new KernelNodeState(kernel, path, revision, cache); + return new KernelNodeState(KernelNodeStore.this, path, revision, cache); } @Override public ListenableFuture reload( @@ -126,6 +128,15 @@ observer.contentChanged(before, root); } return root; + } + + @Override + public NodeState setRoot(@Nonnull NodeBuilder builder, @Nonnull CommitHook commitHook) throws CommitFailedException { + if (builder instanceof KernelRootBuilder) { + return ((KernelRootBuilder) builder).save(commitHook); + } else { + return super.setRoot(builder, commitHook); + } } @Override Index: oak-parent/pom.xml IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-parent/pom.xml (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-parent/pom.xml (revision ) @@ -34,7 +34,7 @@ pom - -Xmx512m -XX:MaxPermSize=32m -Doak.root.purgeLimit=100 + -Xmx512m -XX:MaxPermSize=32m -Dupdate.limit=100 false Index: oak-core/src/test/java/org/apache/jackrabbit/oak/core/RootImplTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/core/RootImplTest.java (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/core/RootImplTest.java (revision ) @@ -158,8 +158,8 @@ root.move("/parent", "/moved"); - assertEquals(Status.EXISTING, parent.getStatus()); - assertEquals(Status.EXISTING, n.getStatus()); + assertEquals(Status.NEW, parent.getStatus()); + assertEquals(Status.NEW, n.getStatus()); assertEquals("/moved", parent.getPath()); assertEquals("/moved/new", n.getPath()); Index: oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRootBuilder.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRootBuilder.java (revision ) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelRootBuilder.java (revision ) @@ -0,0 +1,88 @@ +package org.apache.jackrabbit.oak.kernel; + +import static com.google.common.base.Preconditions.checkNotNull; + +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.NodeState; +import org.apache.jackrabbit.oak.spi.state.NodeStore; +import org.apache.jackrabbit.oak.spi.state.NodeStoreBranch; + +/** + * FIXME make package private + */ +public class KernelRootBuilder extends MemoryNodeBuilder { + + /** + * Number of content updates that need to happen before the updates + * are automatically committed to a branch in the MicroKernel. + */ + private static final int UPDATE_LIMIT = Integer.getInteger("update.limit", 1000); + + private final NodeStore store; + + private NodeStoreBranch branch; + + private int updates = 0; + + public KernelRootBuilder(NodeState base, NodeStore store) { + super(checkNotNull(base)); + this.store = store; + this.branch = store.branch(); + } + + //--------------------------------------------------< MemoryNodeBuilder >--- + + @Override + protected MemoryNodeBuilder createChildBuilder(String name) { + return new KernelNodeBuilder(this, name, this); + } + + @Override + protected void updated() { + if (updates++ > UPDATE_LIMIT) { + purge(); + } + } + + public NodeState rebase() { + purge(); + branch.rebase(); + NodeState head = branch.getHead(); + reset(head); + return head; + } + + public NodeState reset() { + branch = store.branch(); + NodeState head = branch.getHead(); + reset(head); + return head; + } + + NodeState save(CommitHook hook) throws CommitFailedException { + purge(); + return branch.merge(hook); + } + + void purge() { + branch.setRoot(getNodeState()); + reset(branch.getHead()); + updates = 0; + } + + boolean move(String source, String target) { + purge(); + boolean success = branch.move(source, target); + reset(branch.getHead()); + return success; + } + + public boolean copy(String source, String target) { + purge(); + boolean success = branch.copy(source, target); + reset(branch.getHead()); + return success; + } +} Index: oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryNodeBuilder.java (revision ) @@ -113,7 +113,7 @@ * @param parent parent builder * @param name name of this node */ - private MemoryNodeBuilder(MemoryNodeBuilder parent, String name) { + protected MemoryNodeBuilder(MemoryNodeBuilder parent, String name) { this.parent = parent; this.name = name; this.rootBuilder = parent.rootBuilder; @@ -279,6 +279,27 @@ } @Override + public boolean moveTo(NodeBuilder newParent, String newName) { + if (isRoot()) { + return false; + } else { + newParent.setChildNode(newName, getNodeState()); + remove(); + return true; + } + } + + @Override + public boolean copyTo(NodeBuilder newParent, String newName) { + if (isRoot()) { + return false; + } else { + newParent.setChildNode(newName, getNodeState()); + return true; + } + } + + @Override public long getPropertyCount() { return head().getCurrentNodeState().getPropertyCount(); } @@ -358,7 +379,7 @@ /** * @return path of this builder. For debugging purposes only */ - private String getPath() { + protected final String getPath() { return parent == null ? "/" : getPath(new StringBuilder()).toString(); } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/NodeBuilder.java (revision ) @@ -213,6 +213,10 @@ */ boolean remove(); + boolean moveTo(NodeBuilder newParent, String newName); + + boolean copyTo(NodeBuilder newParent, String newName); + /** * Returns the current number of properties. * Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeStore.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeStore.java (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/AbstractNodeStore.java (revision ) @@ -17,10 +17,22 @@ package org.apache.jackrabbit.oak.spi.state; +import javax.annotation.Nonnull; + +import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.spi.commit.CommitHook; + /** * Abstract base class for {@link NodeStore} implementations. */ public abstract class AbstractNodeStore implements NodeStore { + + @Override + public NodeState setRoot(@Nonnull NodeBuilder builder, @Nonnull CommitHook commitHook) throws CommitFailedException { + NodeStoreBranch branch = branch(); + branch.setRoot(builder.getNodeState()); + return branch.merge(commitHook); + } //------------------------------------------------------------< Object >-- Index: oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/core/RootImpl.java (revision ) @@ -21,6 +21,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static org.apache.jackrabbit.oak.commons.PathUtils.getName; import static org.apache.jackrabbit.oak.commons.PathUtils.getParentPath; +import static org.apache.jackrabbit.oak.commons.PathUtils.isAncestor; import java.io.IOException; import java.io.InputStream; @@ -41,6 +42,7 @@ import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.commons.PathUtils; +import org.apache.jackrabbit.oak.kernel.KernelRootBuilder; import org.apache.jackrabbit.oak.plugins.index.diffindex.UUIDDiffIndexProviderWrapper; import org.apache.jackrabbit.oak.query.QueryEngineImpl; import org.apache.jackrabbit.oak.security.authentication.SystemSubject; @@ -63,16 +65,10 @@ import org.apache.jackrabbit.oak.spi.state.NodeBuilder; import org.apache.jackrabbit.oak.spi.state.NodeState; import org.apache.jackrabbit.oak.spi.state.NodeStore; -import org.apache.jackrabbit.oak.spi.state.NodeStoreBranch; public class RootImpl implements Root { /** - * Number of {@link #updated} calls for which changes are kept in memory. - */ - private static final int PURGE_LIMIT = Integer.getInteger("oak.root.purgeLimit", 1000); - - /** * The underlying store to which this root belongs */ private final NodeStore store; @@ -95,15 +91,12 @@ private final TreeImpl rootTree; /** - * Current branch this root operates on - */ - private NodeStoreBranch branch; - - /** * Unsecured builder for the root tree */ - private NodeBuilder builder; + private final NodeBuilder builder; + private NodeState base; + /** Sentinel for the next move operation to take place on the this root */ private Move lastMove = new Move(); @@ -140,10 +133,9 @@ this.securityProvider = checkNotNull(securityProvider); this.indexProvider = indexProvider; - branch = this.store.branch(); - NodeState root = branch.getHead(); - builder = root.builder(); - NodeBuilder secureBuilder = new SecureNodeBuilder(builder, getRootContext(root)); + base = store.getRoot(); + builder = base.builder(); + NodeBuilder secureBuilder = new SecureNodeBuilder(builder, getRootContext(base)); rootTree = new TreeImpl(this, secureBuilder, lastMove); } @@ -178,22 +170,27 @@ @Override public boolean move(String sourcePath, String destPath) { - if (PathUtils.isAncestor(sourcePath, destPath)) { + if (isAncestor(sourcePath, destPath)) { return false; } checkLive(); - TreeImpl destParent = rootTree.getTree(getParentPath(destPath)); - if (!destParent.exists()) { + TreeImpl source = rootTree.getTree(sourcePath); + if (!source.exists()) { return false; } - purgePendingChanges(); - boolean success = branch.move(sourcePath, destPath); - reset(); + + String newName = getName(destPath); + TreeImpl newParent = rootTree.getTree(getParentPath(destPath)); + if (!newParent.exists() || newParent.hasChild(newName)) { + return false; + } + + boolean success = source.moveTo(newParent, newName); if (success) { getTree(getParentPath(sourcePath)).updateChildOrder(); getTree(getParentPath(destPath)).updateChildOrder(); - lastMove = lastMove.setMove(sourcePath, destParent, getName(destPath)); + lastMove = lastMove.setMove(sourcePath, newParent, newName); } return success; } @@ -201,9 +198,18 @@ @Override public boolean copy(String sourcePath, String destPath) { checkLive(); - purgePendingChanges(); - boolean success = branch.copy(sourcePath, destPath); - reset(); + TreeImpl source = rootTree.getTree(sourcePath); + if (!source.exists()) { + return false; + } + + String newName = getName(destPath); + TreeImpl newParent = rootTree.getTree(getParentPath(destPath)); + if (!newParent.exists() || newParent.hasChild(newName)) { + return false; + } + + boolean success = source.copyTo(newParent, newName); if (success) { getTree(getParentPath(destPath)).updateChildOrder(); } @@ -220,9 +226,8 @@ public void rebase() { checkLive(); if (!store.getRoot().equals(getBaseState())) { - purgePendingChanges(); - branch.rebase(); - reset(); + // FIXME don't cast. Doesn't work with MemoryNodeBuilder + base = ((KernelRootBuilder) builder).rebase(); if (permissionProvider != null) { permissionProvider.refresh(); } @@ -232,8 +237,8 @@ @Override public final void refresh() { checkLive(); - branch = store.branch(); - reset(); + // FIXME don't cast. Doesn't work with MemoryNodeBuilder + base = ((KernelRootBuilder) builder).reset(); modCount = 0; if (permissionProvider != null) { permissionProvider.refresh(); @@ -244,15 +249,14 @@ public void commit() throws CommitFailedException { checkLive(); rebase(); - purgePendingChanges(); CommitFailedException exception = Subject.doAs( getCommitSubject(), new PrivilegedAction() { @Override public CommitFailedException run() { try { - NodeState base = branch.getBase(); - NodeState newHead = branch.merge(getCommitHook()); - postHook.contentChanged(base, newHead); + NodeState oldBase = getBaseState(); + base = store.setRoot(builder, getCommitHook()); + postHook.contentChanged(oldBase, base); return null; } catch (CommitFailedException e) { return e; @@ -361,7 +365,7 @@ */ @Nonnull NodeState getBaseState() { - return branch.getBase(); + return base; } /** @@ -370,16 +374,12 @@ * @return secure base node state */ NodeState getSecureBase() { - NodeState root = branch.getBase(); - return new SecureNodeState(root, getRootContext(root)); + return new SecureNodeState(base, getRootContext(base)); } - // TODO better way to determine purge limit. See OAK-175 void updated() { - if (++modCount % PURGE_LIMIT == 0) { - purgePendingChanges(); + modCount++; - } + } - } //------------------------------------------------------------< private >--- @@ -418,22 +418,6 @@ return permissionProvider; } - /** - * Purge all pending changes to the underlying {@link NodeStoreBranch}. - */ - private void purgePendingChanges() { - branch.setRoot(getRootState()); - reset(); - } - - /** - * Reset the root builder to the branch's current root state - */ - private void reset() { - NodeState root = branch.getHead(); - builder.reset(root); - } - @Nonnull private PermissionProvider createPermissionProvider() { return getAcConfig().getPermissionProvider(this, subject.getPrincipals()); @@ -493,7 +477,7 @@ Move move = this; while (move.next != null) { if (move.source.equals(tree.getPathInternal())) { - tree.moveTo(move.destParent, move.destName); + tree.setParentAndName(move.destParent, move.destName); } move = move.next; } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/state/ReadOnlyBuilder.java (revision ) @@ -94,6 +94,16 @@ } @Override + public boolean moveTo(NodeBuilder newParent, String newName) { + throw unsupported(); + } + + @Override + public boolean copyTo(NodeBuilder newParent, String newName) { + throw unsupported(); + } + + @Override public long getPropertyCount() { return state.getPropertyCount(); } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java (revision 88d8104cecf177969b83e118f42e1e4d2b863091) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/core/TreeImpl.java (revision ) @@ -368,15 +368,25 @@ return nodeBuilder.getNodeState(); } + void setParentAndName(TreeImpl parent, String name) { + this.name = name; + this.parent = parent; + } + /** * Move this tree to the parent at {@code destParent} with the new name * {@code destName}. - * @param destParent new parent for this tree - * @param destName new name for this tree + * @param newParent new parent for this tree + * @param newName new name for this tree */ - void moveTo(TreeImpl destParent, String destName) { - name = destName; - parent = destParent; + boolean moveTo(TreeImpl newParent, String newName) { + name = newName; + parent = newParent; + return nodeBuilder.moveTo(newParent.nodeBuilder, newName); + } + + boolean copyTo(TreeImpl newParent, String newName) { + return nodeBuilder.copyTo(newParent.nodeBuilder, newName); } /**