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/11/21 11:20:39 UTC

svn commit: r1544086 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/ oak-core/...

Author: mreutegg
Date: Thu Nov 21 10:20:38 2013
New Revision: 1544086

URL: http://svn.apache.org/r1544086
Log:
OAK-1203: Reset branch to previous commit

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKResetTest.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/NodeStoreKernel.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStoreBranch.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/LogWrapper.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/TimingWrapper.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreCacheTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKBranchMergeTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKTestBase.java
    jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java
    jackrabbit/oak/trunk/oak-mk-api/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java
    jackrabbit/oak/trunk/oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/client/Client.java
    jackrabbit/oak/trunk/oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/server/MicroKernelServlet.java
    jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/NodeStoreKernel.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/NodeStoreKernel.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/NodeStoreKernel.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/NodeStoreKernel.java Thu Nov 21 10:20:38 2013
@@ -519,6 +519,29 @@ public class NodeStoreKernel implements 
         throw new UnsupportedOperationException();
     }
 
+    @Nonnull
+    @Override
+    public synchronized String reset(@Nonnull String branchRevisionId,
+                                     @Nonnull String ancestorRevisionId)
+            throws MicroKernelException {
+        Revision revision = getRevision(branchRevisionId);
+        if (revision.branch == null) {
+            throw new MicroKernelException(
+                    "Branch not found: " + branchRevisionId);
+        }
+        Revision ancestor = getRevision(ancestorRevisionId);
+        while (!ancestor.id.equals(revision.id)) {
+            revision = revision.base;
+            if (revision.branch == null) {
+                throw new MicroKernelException(ancestorRevisionId + " is not " +
+                        "an ancestor revision of " + branchRevisionId);
+            }
+        }
+        Revision r = new Revision(ancestor);
+        revisions.put(r.id, r);
+        return r.id;
+    }
+
     @Override
     public long getLength(String blobId) throws MicroKernelException {
         Blob blob = blobs.get(blobId);

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMK.java Thu Nov 21 10:20:38 2013
@@ -449,6 +449,22 @@ public class MongoMK implements MicroKer
         return nodeStore.rebase(r, base).toString();
     }
 
+    @Nonnull
+    @Override
+    public String reset(@Nonnull String branchRevisionId,
+                        @Nonnull String ancestorRevisionId)
+            throws MicroKernelException {
+        Revision branch = Revision.fromString(branchRevisionId);
+        if (!branch.isBranch()) {
+            throw new MicroKernelException("Not a branch revision: " + branchRevisionId);
+        }
+        Revision ancestor = Revision.fromString(ancestorRevisionId);
+        if (!ancestor.isBranch()) {
+            throw new MicroKernelException("Not a branch revision: " + ancestorRevisionId);
+        }
+        return nodeStore.reset(branch, ancestor).toString();
+    }
+
     @Override
     public long getLength(String blobId) throws MicroKernelException {
         try {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java Thu Nov 21 10:20:38 2013
@@ -56,6 +56,7 @@ import org.apache.jackrabbit.oak.api.Blo
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.cache.CacheStats;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.kernel.BlobSerializer;
 import org.apache.jackrabbit.oak.plugins.mongomk.util.LoggingDocumentStoreWrapper;
 import org.apache.jackrabbit.oak.plugins.mongomk.util.TimingDocumentStoreWrapper;
 import org.apache.jackrabbit.oak.plugins.mongomk.util.Utils;
@@ -219,6 +220,25 @@ public final class MongoNodeStore
      */
     private final BlobStore blobStore;
 
+    /**
+     * The BlobSerializer.
+     */
+    private final BlobSerializer blobSerializer = new BlobSerializer() {
+        @Override
+        public String serialize(Blob blob) {
+            if (blob instanceof MongoBlob) {
+                return blob.toString();
+            }
+            String id;
+            try {
+                id = createBlob(blob.getNewStream()).toString();
+            } catch (IOException e) {
+                throw new IllegalStateException(e);
+            }
+            return id;
+        }
+    };
+
     public MongoNodeStore(MongoMK.Builder builder) {
         this.blobStore = builder.getBlobStore();
         if (builder.isUseSimpleRevision()) {
@@ -758,6 +778,46 @@ public final class MongoNodeStore
     }
 
     @Nonnull
+    Revision reset(@Nonnull Revision branchHead, @Nonnull Revision ancestor) {
+        checkNotNull(branchHead);
+        checkNotNull(ancestor);
+        Branch b = getBranches().getBranch(branchHead);
+        if (b == null) {
+            throw new MicroKernelException("Empty branch cannot be reset");
+        }
+        if (!b.containsCommit(ancestor)) {
+            throw new MicroKernelException(ancestor + " is not " +
+                    "an ancestor revision of " + branchHead);
+        }
+        Revision rev;
+        boolean success = false;
+        Commit commit = newCommit(branchHead);
+        try {
+            // apply reverse diff
+            getRoot(ancestor).compareAgainstBaseState(getRoot(branchHead),
+                    new CommitDiff(commit, getBlobSerializer()));
+            UpdateOp rootOp = commit.getUpdateOperationForNode("/");
+            // clear collisions
+            Iterator<Revision> it = b.getCommits().tailSet(ancestor).iterator();
+            // first revision is the ancestor
+            // do not clear collision for this revision
+            it.next();
+            while (it.hasNext()) {
+                NodeDocument.unsetCollision(rootOp, it.next());
+            }
+            rev = apply(commit);
+            success = true;
+        } finally {
+            if (!success) {
+                canceled(commit);
+            } else {
+                done(commit, true, null);
+            }
+        }
+        return rev;
+    }
+
+    @Nonnull
     Revision merge(@Nonnull Revision branchHead, @Nullable CommitInfo info) {
         Branch b = getBranches().getBranch(branchHead);
         Revision base = branchHead;
@@ -1194,5 +1254,9 @@ public final class MongoNodeStore
     public BlobStore getBlobStore() {
         return blobStore;
     }
+
+    BlobSerializer getBlobSerializer() {
+        return blobSerializer;
+    }
     
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStoreBranch.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStoreBranch.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStoreBranch.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStoreBranch.java Thu Nov 21 10:20:38 2013
@@ -16,15 +16,11 @@
  */
 package org.apache.jackrabbit.oak.plugins.mongomk;
 
-import java.io.IOException;
-
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 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.kernel.BlobSerializer;
 import org.apache.jackrabbit.oak.spi.commit.ChangeDispatcher;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
@@ -43,22 +39,6 @@ public class MongoNodeStoreBranch
      */
     private static final int MERGE_RETRIES = 10;
 
-    private final BlobSerializer blobs = new BlobSerializer() {
-        @Override
-        public String serialize(Blob blob) {
-            if (blob instanceof MongoBlob) {
-                return blob.toString();
-            }
-            String id;
-            try {
-                id = store.createBlob(blob.getNewStream()).toString();
-            } catch (IOException e) {
-                throw new IllegalStateException(e);
-            }
-            return id;
-        }
-    };
-
     public MongoNodeStoreBranch(MongoNodeStore store,
                                 MongoNodeState base) {
         super(store, new ChangeDispatcher(store.getRoot()), base);
@@ -92,7 +72,8 @@ public class MongoNodeStoreBranch
         MongoNodeState state = persist(new Changes() {
             @Override
             public void with(Commit c) {
-                toPersist.compareAgainstBaseState(base, new CommitDiff(c, blobs));
+                toPersist.compareAgainstBaseState(base,
+                        new CommitDiff(c, store.getBlobSerializer()));
             }
         }, base, info);
         if (base.isBranch()) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java Thu Nov 21 10:20:38 2013
@@ -843,6 +843,11 @@ public class NodeDocument extends Docume
         checkNotNull(op).unsetMapEntry(REVISIONS, checkNotNull(revision));
     }
 
+    public static void unsetCollision(@Nonnull UpdateOp op,
+                                      @Nonnull Revision revision) {
+        checkNotNull(op).unsetMapEntry(COLLISIONS, checkNotNull(revision));
+    }
+
     public static void setLastRev(@Nonnull UpdateOp op,
                                   @Nonnull Revision revision) {
         checkNotNull(op).setMapEntry(LAST_REV,

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/LogWrapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/LogWrapper.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/LogWrapper.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/LogWrapper.java Thu Nov 21 10:20:38 2013
@@ -261,6 +261,22 @@ public class LogWrapper<T extends MicroK
         }
     }
 
+    @Nonnull
+    @Override
+    public String reset(@Nonnull String branchRevisionId,
+                        @Nonnull String ancestorRevisionId)
+            throws MicroKernelException {
+        try {
+            logMethod("reset", branchRevisionId, ancestorRevisionId);
+            String result = mk.reset(branchRevisionId, ancestorRevisionId);
+            logResult(result);
+            return result;
+        } catch (Exception e) {
+            logException(e);
+            throw convert(e);
+        }
+    }
+
     private void logMethod(String methodName, Object... args) {
         StringBuilder buff = new StringBuilder("mk");
         buff.append(id).append('.').append(methodName).append('(');

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/TimingWrapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/TimingWrapper.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/TimingWrapper.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/util/TimingWrapper.java Thu Nov 21 10:20:38 2013
@@ -267,6 +267,21 @@ public class TimingWrapper implements Mi
         }
     }
 
+    @Nonnull
+    @Override
+    public String reset(@Nonnull String branchRevisionId,
+                        @Nonnull String ancestorRevisionId)
+            throws MicroKernelException {
+        try {
+            long start = now();
+            String result = mk.reset(branchRevisionId, ancestorRevisionId);
+            updateAndLogTimes("reset", start, 0, 0);
+            return result;
+        } catch (Exception e) {
+            throw convert(e);
+        }
+    }
+
     private static RuntimeException convert(Exception e) {
         if (e instanceof RuntimeException) {
             return (RuntimeException) e;

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreCacheTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreCacheTest.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreCacheTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/kernel/KernelNodeStoreCacheTest.java Thu Nov 21 10:20:38 2013
@@ -250,6 +250,14 @@ public class KernelNodeStoreCacheTest {
             return kernel.rebase(branchRevisionId, newBaseRevisionId);
         }
 
+        @Nonnull
+        @Override
+        public String reset(@Nonnull String branchRevisionId,
+                            @Nonnull String ancestorRevisionId)
+                throws MicroKernelException {
+            return kernel.reset(branchRevisionId, ancestorRevisionId);
+        }
+
         @Override
         public long getLength(String blobId) throws MicroKernelException {
             return kernel.getLength(blobId);

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKBranchMergeTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKBranchMergeTest.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKBranchMergeTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKBranchMergeTest.java Thu Nov 21 10:20:38 2013
@@ -457,13 +457,6 @@ public class MongoMKBranchMergeTest exte
 
     //--------------------------< internal >------------------------------------
 
-    private String addNodes(String rev, String...nodes) {
-        for (String node : nodes) {
-            rev = mk.commit("", "+\"" + node + "\":{}", rev, "");
-        }
-        return rev;
-    }
-
     private String removeNodes(String rev, String...nodes) {
         for (String node : nodes) {
             rev = mk.commit("", "-\"" + node + "\"", rev, "");

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKResetTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKResetTest.java?rev=1544086&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKResetTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKResetTest.java Thu Nov 21 10:20:38 2013
@@ -0,0 +1,68 @@
+/*
+ * 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.plugins.mongomk;
+
+import org.apache.jackrabbit.mk.api.MicroKernelException;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests MongoMKs implementation of MicroKernel.reset(String, String).
+ */
+public class MongoMKResetTest extends BaseMongoMKTest {
+
+    @Test
+    public void resetToCurrentBranchHead() {
+        String rev = mk.branch(null);
+        rev = addNodes(rev, "/foo");
+        String reset = mk.reset(rev, rev);
+        assertTrue(mk.diff(rev, reset, "/", 0).length() == 0);
+    }
+
+    @Test
+    public void resetTrunk() {
+        String rev = addNodes(null, "/foo");
+        try {
+            mk.reset(rev, rev);
+            fail("MicroKernelException expected");
+        } catch (MicroKernelException expected) {}
+    }
+
+    @Test
+    public void resetNonAncestor() {
+        String rev = mk.getHeadRevision();
+        addNodes(null, "/foo");
+        String branch = mk.branch(null);
+        branch = addNodes(branch, "/bar");
+        try {
+            mk.reset(branch, rev);
+            fail("MicroKernelException expected");
+        } catch (MicroKernelException expected) {}
+    }
+
+    @Test
+    public void resetBranch() {
+        String branch = mk.branch(null);
+        branch = addNodes(branch, "/foo");
+        String head = addNodes(branch, "/bar");
+        assertNodesExist(head, "/bar");
+        head = mk.reset(head, branch);
+        assertNodesNotExist(head, "/bar");
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKResetTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKResetTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKTestBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKTestBase.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKTestBase.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoMKTestBase.java Thu Nov 21 10:20:38 2013
@@ -182,4 +182,12 @@ public abstract class MongoMKTestBase {
         }
         return val;
     }
+
+    protected String addNodes(String rev, String...nodes) {
+        String newRev = rev;
+        for (String node : nodes) {
+            newRev = getMicroKernel().commit("", "+\"" + node + "\":{}", newRev, "");
+        }
+        return newRev;
+    }
 }

Modified: jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java (original)
+++ jackrabbit/oak/trunk/oak-it/mk/src/main/java/org/apache/jackrabbit/mk/test/MicroKernelIT.java Thu Nov 21 10:20:38 2013
@@ -1295,6 +1295,45 @@ public class MicroKernelIT extends Abstr
     }
 
     @Test
+    public void resetToCurrentBranchHead() {
+        String rev = mk.branch(null);
+        rev = addNodes(rev, "/foo");
+        String reset = mk.reset(rev, rev);
+        assertTrue(mk.diff(rev, reset, "/", -1).length() == 0);
+    }
+
+    @Test
+    public void resetTrunk() {
+        String rev = addNodes(null, "/foo");
+        try {
+            mk.reset(rev, rev);
+            fail("MicroKernelException expected");
+        } catch (MicroKernelException expected) {}
+    }
+
+    @Test
+    public void resetNonAncestor() {
+        String rev = mk.getHeadRevision();
+        addNodes(null, "/foo");
+        String branch = mk.branch(null);
+        branch = addNodes(branch, "/bar");
+        try {
+            mk.reset(branch, rev);
+            fail("MicroKernelException expected");
+        } catch (MicroKernelException expected) {}
+    }
+
+    @Test
+    public void resetBranch() {
+        String branch = mk.branch(null);
+        branch = addNodes(branch, "/foo");
+        String head = addNodes(branch, "/bar");
+        assertNodesExist(head, "/bar");
+        head = mk.reset(head, branch);
+        assertNodesNotExist(head, "/bar");
+    }
+
+    @Test
     public void testSmallBlob() {
         testBlobs(1024, 1024);
     }

Modified: jackrabbit/oak/trunk/oak-mk-api/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk-api/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk-api/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java (original)
+++ jackrabbit/oak/trunk/oak-mk-api/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java Thu Nov 21 10:20:38 2013
@@ -555,6 +555,24 @@ public interface MicroKernel {
     String /*revisionId */ rebase(@Nonnull String branchRevisionId, String newBaseRevisionId)
         throws MicroKernelException;
 
+    /**
+     * Resets the branch identified by {@code branchRevisionId} to an ancestor
+     * branch commit identified by {@code ancestorRevisionId}.
+     *
+     * @param branchRevisionId id of the private branch revision
+     * @param ancestorRevisionId id of the ancestor commit to reset the branch to.
+     * @return the id of the new head of the branch. This may not necessarily
+     *         be the same as {@code ancestorRevisionId}. An implementation is
+     *         free to create a new id for the reset branch.
+     * @throws MicroKernelException if {@code branchRevisionId} doesn't exist,
+     *                              if it's not a branch revision, if {@code ancestorRevisionId}
+     *                              is not a revision on that branch or if another error occurs.
+     */
+    @Nonnull
+    String /* revisionId */ reset(@Nonnull String branchRevisionId,
+                                  @Nonnull String ancestorRevisionId)
+            throws MicroKernelException;
+
     //--------------------------------------------------< BLOB READ/WRITE ops >
 
     /**

Modified: jackrabbit/oak/trunk/oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/client/Client.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/client/Client.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/client/Client.java (original)
+++ jackrabbit/oak/trunk/oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/client/Client.java Thu Nov 21 10:20:38 2013
@@ -321,6 +321,26 @@ public class Client implements MicroKern
         throw new UnsupportedOperationException();
     }
 
+    @Nonnull
+    @Override
+    public String reset(@Nonnull String branchRevisionId,
+                        @Nonnull String ancestorRevisionId)
+            throws MicroKernelException {
+
+        Request request = null;
+
+        try {
+            request = createRequest("reset");
+            request.addParameter("branch_revision_id", branchRevisionId);
+            request.addParameter("ancestor_revision_id", ancestorRevisionId);
+            return request.getString();
+        } catch (IOException e) {
+            throw toMicroKernelException(e);
+        } finally {
+            IOUtils.closeQuietly(request);
+        }
+    }
+
     @Override
     public long getLength(String blobId) throws MicroKernelException {
         Request request = null;

Modified: jackrabbit/oak/trunk/oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/server/MicroKernelServlet.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/server/MicroKernelServlet.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/server/MicroKernelServlet.java (original)
+++ jackrabbit/oak/trunk/oak-mk-remote/src/main/java/org/apache/jackrabbit/mk/server/MicroKernelServlet.java Thu Nov 21 10:20:38 2013
@@ -85,6 +85,7 @@ class MicroKernelServlet {
         COMMANDS.put("commit", new Commit());
         COMMANDS.put("branch", new Branch());
         COMMANDS.put("merge", new Merge());
+        COMMANDS.put("reset", new Reset());
         COMMANDS.put("getLength", new GetLength());
         COMMANDS.put("read", new Read());
         COMMANDS.put("write", new Write());
@@ -311,6 +312,21 @@ class MicroKernelServlet {
         }
     }
 
+    static class Reset implements Command {
+
+        @Override
+        public void execute(MicroKernel mk, Request request, Response response)
+                throws IOException, MicroKernelException {
+            String branchRevisionId = request.getParameter("branch_revision_id");
+            String ancestorRevisionId = request.getParameter("ancestor_revision_id");
+
+            String newRevision = mk.reset(branchRevisionId, ancestorRevisionId);
+
+            response.setContentType("test/plain");
+            response.write(newRevision);
+        }
+    }
+
     static class GetLength implements Command {
 
         @Override

Modified: jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java?rev=1544086&r1=1544085&r2=1544086&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java (original)
+++ jackrabbit/oak/trunk/oak-mk/src/main/java/org/apache/jackrabbit/mk/core/MicroKernelImpl.java Thu Nov 21 10:20:38 2013
@@ -22,6 +22,8 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import javax.annotation.Nonnull;
+
 import org.apache.jackrabbit.mk.api.MicroKernel;
 import org.apache.jackrabbit.mk.api.MicroKernelException;
 import org.apache.jackrabbit.mk.json.JsonObject;
@@ -579,6 +581,39 @@ public class MicroKernelImpl implements 
         }
     }
 
+    @Nonnull
+    @Override
+    public String reset(@Nonnull String branchRevisionId,
+                        @Nonnull String ancestorRevisionId)
+            throws MicroKernelException {
+        Id branchId = Id.fromString(branchRevisionId);
+        Id ancestorId = Id.fromString(ancestorRevisionId);
+        StoredCommit commit;
+        try {
+            commit = rep.getCommit(branchId);
+        } catch (Exception e) {
+            throw new MicroKernelException(e);
+        }
+        Id baseId = commit.getBranchRootId();
+        if (baseId == null) {
+            throw new MicroKernelException("Not a private branch: " + branchRevisionId);
+        }
+        // verify ancestorId is in fact an ancestor of branchId
+        while (!ancestorId.equals(branchId)) {
+            try {
+                commit = rep.getCommit(branchId);
+            } catch (Exception e) {
+                throw new MicroKernelException(e);
+            }
+            if (commit.getBranchRootId() == null) {
+                throw new MicroKernelException(ancestorRevisionId + " is not " +
+                        "an ancestor revision of " + branchRevisionId);
+            }
+            branchId = commit.getParentId();
+        }
+        return ancestorRevisionId;
+    }
+
     public long getLength(String blobId) throws MicroKernelException {
         if (rep == null) {
             throw new IllegalStateException("this instance has already been disposed");