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 md...@apache.org on 2013/02/01 15:50:52 UTC
svn commit: r1441466 - in /jackrabbit/oak/trunk/oak-mongomk/src:
main/java/org/apache/jackrabbit/mongomk/api/
main/java/org/apache/jackrabbit/mongomk/impl/
main/java/org/apache/jackrabbit/mongomk/impl/command/
main/java/org/apache/jackrabbit/mongomk/im...
Author: mduerig
Date: Fri Feb 1 14:50:51 2013
New Revision: 1441466
URL: http://svn.apache.org/viewvc?rev=1441466&view=rev
Log:
OAK-536: Implement rebase for branches in Microkernel
implement rebase() for the Mongo Microkernel
Added:
jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/RebaseCommand.java (with props)
jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/MongoMKRebaseTest.java (with props)
Modified:
jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/api/NodeStore.java
jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/MongoMicroKernel.java
jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/MongoNodeStore.java
jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/model/tree/MongoNodeDelta.java
jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/util/MongoUtil.java
Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/api/NodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/api/NodeStore.java?rev=1441466&r1=1441465&r2=1441466&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/api/NodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/api/NodeStore.java Fri Feb 1 14:50:51 2013
@@ -125,6 +125,16 @@ public interface NodeStore {
String merge(String branchRevisionId, String message) throws Exception;
/**
+ * @see MicroKernel#rebase(String, String)
+ *
+ * @param branchRevisionId Branch revision id to rebase.
+ * @param newBaseRevisionId New base revision to rebase onto.
+ * @return The revision id of the rebased branch.
+ * @throws Exception If an error occurred while rebasing.
+ */
+ String rebase(String branchRevisionId, String newBaseRevisionId) throws Exception;
+
+ /**
* @see MicroKernel#nodeExists(String, String)
*
* @param path The path of the node to test.
Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/MongoMicroKernel.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/MongoMicroKernel.java?rev=1441466&r1=1441465&r2=1441466&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/MongoMicroKernel.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/MongoMicroKernel.java Fri Feb 1 14:50:51 2013
@@ -219,8 +219,13 @@ public class MongoMicroKernel implements
@Nonnull
@Override
- public String rebase(@Nonnull String branchRevisionId, String newBaseRevisionId) {
- throw new UnsupportedOperationException();
+ public String rebase(@Nonnull String branchRevisionId, String newBaseRevisionId)
+ throws MicroKernelException{
+ try {
+ return nodeStore.rebase(branchRevisionId, newBaseRevisionId);
+ } catch (Exception e) {
+ throw new MicroKernelException(e);
+ }
}
@Override
Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/MongoNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/MongoNodeStore.java?rev=1441466&r1=1441465&r2=1441466&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/MongoNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/MongoNodeStore.java Fri Feb 1 14:50:51 2013
@@ -19,6 +19,10 @@ package org.apache.jackrabbit.mongomk.im
import java.util.Collections;
import java.util.Map;
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import com.mongodb.DBObject;
import org.apache.jackrabbit.mk.util.SimpleLRUCache;
import org.apache.jackrabbit.mongomk.api.NodeStore;
import org.apache.jackrabbit.mongomk.api.command.Command;
@@ -36,6 +40,7 @@ import org.apache.jackrabbit.mongomk.imp
import org.apache.jackrabbit.mongomk.impl.command.MergeCommand;
import org.apache.jackrabbit.mongomk.impl.command.NodeExistsCommand;
import org.apache.jackrabbit.mongomk.impl.command.OneLevelDiffCommand;
+import org.apache.jackrabbit.mongomk.impl.command.RebaseCommand;
import org.apache.jackrabbit.mongomk.impl.command.WaitForCommitCommand;
import org.apache.jackrabbit.mongomk.impl.model.MongoCommit;
import org.apache.jackrabbit.mongomk.impl.model.MongoNode;
@@ -44,11 +49,6 @@ import org.apache.jackrabbit.mongomk.uti
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.mongodb.BasicDBObject;
-import com.mongodb.DB;
-import com.mongodb.DBCollection;
-import com.mongodb.DBObject;
-
/**
* Implementation of {@link NodeStore} for the {@code MongoDB}.
*/
@@ -146,6 +146,12 @@ public class MongoNodeStore implements N
}
@Override
+ public String rebase(String branchRevisionId, String newBaseRevisionId) throws Exception {
+ RebaseCommand command = new RebaseCommand(this, branchRevisionId, newBaseRevisionId);
+ return commandExecutor.execute(command);
+ }
+
+ @Override
public boolean nodeExists(String path, String revisionId) throws Exception {
NodeExistsCommand command = new NodeExistsCommand(this, path,
MongoUtil.toMongoRepresentation(revisionId));
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/RebaseCommand.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/RebaseCommand.java?rev=1441466&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/RebaseCommand.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/RebaseCommand.java Fri Feb 1 14:50:51 2013
@@ -0,0 +1,268 @@
+/*
+ * 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.mongomk.impl.command;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+
+import org.apache.jackrabbit.mk.model.tree.DiffBuilder;
+import org.apache.jackrabbit.mk.model.tree.NodeState;
+import org.apache.jackrabbit.mongomk.api.model.Node;
+import org.apache.jackrabbit.mongomk.impl.MongoNodeStore;
+import org.apache.jackrabbit.mongomk.impl.action.FetchCommitAction;
+import org.apache.jackrabbit.mongomk.impl.action.FetchHeadRevisionIdAction;
+import org.apache.jackrabbit.mongomk.impl.model.CommitBuilder;
+import org.apache.jackrabbit.mongomk.impl.model.MongoCommit;
+import org.apache.jackrabbit.mongomk.impl.model.NodeImpl;
+import org.apache.jackrabbit.mongomk.impl.model.tree.MongoNodeDelta;
+import org.apache.jackrabbit.mongomk.impl.model.tree.MongoNodeState;
+import org.apache.jackrabbit.mongomk.impl.model.tree.SimpleMongoNodeStore;
+import org.apache.jackrabbit.mongomk.util.MongoUtil;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.apache.jackrabbit.mongomk.util.MongoUtil.fromMongoRepresentation;
+import static org.apache.jackrabbit.mongomk.util.MongoUtil.getBaseRevision;
+import static org.apache.jackrabbit.mongomk.util.MongoUtil.toMongoRepresentation;
+
+/**
+ * A {@code Command} for {@link org.apache.jackrabbit.mongomk.impl.MongoMicroKernel#rebase(String, String)}
+ */
+public class RebaseCommand extends BaseCommand<String> {
+ private static final Logger LOG = LoggerFactory.getLogger(RebaseCommand.class);
+
+ private final String branchRevisionId;
+ private final String newBaseRevisionId;
+
+ public RebaseCommand(MongoNodeStore nodeStore, String branchRevisionId, String newBaseRevisionId) {
+ super(nodeStore);
+ this.branchRevisionId = branchRevisionId;
+ this.newBaseRevisionId = newBaseRevisionId;
+ }
+
+ private MongoCommit getCommit(String revisionId) throws Exception {
+ return new FetchCommitAction(nodeStore, toMongoRepresentation(revisionId)).execute();
+ }
+
+ @Override
+ public String execute() throws Exception {
+ MongoCommit branchCommit = getCommit(branchRevisionId);
+ String branchId = branchCommit.getBranchId();
+ checkArgument(branchId != null, "Can only rebase a private branch commit");
+
+ MongoCommit newBaseCommit;
+ if (newBaseRevisionId == null) {
+ Long headRevision = new FetchHeadRevisionIdAction(nodeStore).execute();
+ newBaseCommit = new FetchCommitAction(nodeStore, headRevision).execute();
+ }
+ else {
+ newBaseCommit = getCommit(newBaseRevisionId);
+ }
+ checkArgument(newBaseCommit.getBranchId() == null, "Cannot rebase onto private branch commit");
+
+ long branchHeadRev = branchCommit.getRevisionId();
+ long branchBaseRev = getBaseRevision(branchId);
+ long newBaseRev = newBaseCommit.getRevisionId();
+
+ if (newBaseRev == branchBaseRev) {
+ return branchRevisionId;
+ }
+
+ Node branchHeadRoot = getNode("/", branchHeadRev, branchId);
+ Node branchBaseRoot = getNode("/", branchBaseRev);
+ Node newBaseRoot = getNode("/", newBaseRev);
+ branchHeadRoot = rebaseNode(copy(newBaseRoot), branchBaseRoot, branchHeadRoot, "/");
+
+ String diff = new DiffBuilder(
+ MongoUtil.wrap(newBaseRoot),
+ MongoUtil.wrap(branchHeadRoot),
+ "/", -1, new SimpleMongoNodeStore(), "")
+ .build();
+
+ MongoCommit newBranchInitialCommit = (MongoCommit)CommitBuilder.build("", "",
+ fromMongoRepresentation(newBaseRev), MongoNodeStore.INITIAL_COMMIT_MESSAGE);
+ newBranchInitialCommit.setBranchId(fromMongoRepresentation(newBaseRev) + '-' + UUID.randomUUID().toString());
+ String newBranchRevId = nodeStore.commit(newBranchInitialCommit);
+
+ if (diff.isEmpty()) {
+ return newBranchRevId;
+ }
+
+ MongoCommit newCommit = (MongoCommit) CommitBuilder.build("", diff, newBranchRevId,
+ "rebased " + branchHeadRev + " onto " + newBaseRev);
+ newCommit.setBranchId(newBranchInitialCommit.getBranchId());
+ return nodeStore.commit(newCommit);
+ }
+
+ private static NodeImpl rebaseNode(Node baseNode, Node fromNode, Node toNode, String path) {
+ MongoNodeDelta theirDelta = new MongoNodeDelta(new SimpleMongoNodeStore(),
+ MongoUtil.wrap(fromNode), MongoUtil.wrap(baseNode));
+ MongoNodeDelta ourDelta = new MongoNodeDelta(new SimpleMongoNodeStore(),
+ MongoUtil.wrap(fromNode), MongoUtil.wrap(toNode));
+
+ NodeImpl stagedNode = (NodeImpl)baseNode;
+
+ // Apply our changes.
+ for (Entry<String, String> added : ourDelta.getAddedProperties().entrySet()) {
+ String name = added.getKey();
+ String ourValue = added.getValue();
+ String theirValue = theirDelta.getAddedProperties().get(name);
+
+ if (theirValue != null && !theirValue.equals(ourValue)) {
+ markConflict(stagedNode, "addExistingProperty", name, ourValue);
+ }
+ else {
+ stagedNode.getProperties().put(name, ourValue);
+ }
+ }
+
+ for (Entry<String, String> removed : ourDelta.getRemovedProperties().entrySet()) {
+ String name = removed.getKey();
+ String ourValue = removed.getValue();
+
+ if (theirDelta.getRemovedProperties().containsKey(name)) {
+ markConflict(stagedNode, "deleteDeletedProperty", name, ourValue);
+ }
+ else if (theirDelta.getChangedProperties().containsKey(name)) {
+ markConflict(stagedNode, "deleteChangedProperty", name, ourValue);
+ }
+ else {
+ stagedNode.getProperties().remove(name);
+ }
+ }
+
+ for (Entry<String, String> changed : ourDelta.getChangedProperties().entrySet()) {
+ String name = changed.getKey();
+ String ourValue = changed.getValue();
+ String theirValue = theirDelta.getChangedProperties().get(name);
+
+ if (theirDelta.getRemovedProperties().containsKey(name)) {
+ markConflict(stagedNode, "changeDeletedProperty", name, ourValue);
+ }
+ else if (theirValue != null && !theirValue.equals(ourValue)) {
+ markConflict(stagedNode, "changeChangedProperty", name, ourValue);
+ }
+ else {
+ stagedNode.getProperties().put(name, ourValue);
+ }
+ }
+
+ for (Entry<String, NodeState> added : ourDelta.getAddedChildNodes().entrySet()) {
+ String name = added.getKey();
+ NodeState ourState = added.getValue();
+ NodeState theirState = theirDelta.getAddedChildNodes().get(name);
+
+ if (theirState != null && !theirState.equals(ourState)) {
+ markConflict(stagedNode, "addExistingNode", name, ourState);
+ }
+ else {
+ stagedNode.addChildNodeEntry(unwrap(ourState));
+ }
+ }
+
+ for (Entry<String, NodeState> removed : ourDelta.getRemovedChildNodes().entrySet()) {
+ String name = removed.getKey();
+ NodeState ourState = removed.getValue();
+
+ if (theirDelta.getRemovedChildNodes().containsKey(name)) {
+ markConflict(stagedNode, "deleteDeletedNode", name, ourState);
+ }
+ else if (theirDelta.getChangedChildNodes().containsKey(name)) {
+ markConflict(stagedNode, "deleteChangedNode", name, ourState);
+ }
+ else {
+ stagedNode.removeChildNodeEntry(name);
+ }
+ }
+
+ for (Entry<String, NodeState> changed : ourDelta.getChangedChildNodes().entrySet()) {
+ String name = changed.getKey();
+ NodeState ourState = changed.getValue();
+
+ Node changedBase = baseNode.getChildNodeEntry(name);
+ if (changedBase == null) {
+ markConflict(stagedNode, "changeDeletedNode", name, ourState);
+ continue;
+ }
+
+ Node changedFrom = fromNode.getChildNodeEntry(name);
+ Node changedTo = toNode.getChildNodeEntry(name);
+ String changedPath = PathUtils.concat(path, name);
+ rebaseNode(changedBase, changedFrom, changedTo, changedPath);
+ }
+
+ return stagedNode;
+ }
+
+ private static Node unwrap(NodeState state) {
+ return ((MongoNodeState) state).unwrap();
+ }
+
+ private static void markConflict(NodeImpl parent, String conflictType, String name, String ourValue) {
+ NodeImpl marker = getOrAddConflictMarker(parent, conflictType);
+ marker.getProperties().put(name, ourValue);
+ }
+
+ private static void markConflict(NodeImpl parent, String conflictType, String name, NodeState ourState) {
+ NodeImpl marker = getOrAddConflictMarker(parent, conflictType);
+ marker.addChildNodeEntry(unwrap(ourState));
+ }
+
+ private static NodeImpl getOrAddConflictMarker(NodeImpl parent, String name) {
+ NodeImpl conflict = getOrAddNode(parent, ":conflict");
+ return getOrAddNode(conflict, name);
+ }
+
+ private static NodeImpl getOrAddNode(NodeImpl parent, String name) {
+ Node child = parent.getChildNodeEntry(name);
+ if (child == null) {
+ child = new NodeImpl(PathUtils.concat(parent.getPath(), name));
+ parent.addChildNodeEntry(child);
+ }
+ return (NodeImpl) child;
+ }
+
+ private Node getNode(String path, long revisionId) throws Exception {
+ return getNode(path, revisionId, null);
+ }
+
+ private Node getNode(String path, long revisionId, String branchId) throws Exception {
+ GetNodesCommand command = new GetNodesCommand(nodeStore, path, revisionId);
+ command.setBranchId(branchId);
+ return command.execute();
+ }
+
+ private static NodeImpl copy(Node node) {
+ NodeImpl copy = new NodeImpl(node.getPath());
+ copy.setRevisionId(node.getRevisionId());
+ for (Map.Entry<String, String> entry : node.getProperties().entrySet()) {
+ copy.addProperty(entry.getKey(), entry.getValue());
+ }
+ for (Iterator<Node> it = node.getChildNodeEntries(0, -1); it.hasNext(); ) {
+ Node child = it.next();
+ copy.addChildNodeEntry(copy(child));
+ }
+ return copy;
+ }
+
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/RebaseCommand.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/RebaseCommand.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev URL
Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/model/tree/MongoNodeDelta.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/model/tree/MongoNodeDelta.java?rev=1441466&r1=1441465&r2=1441466&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/model/tree/MongoNodeDelta.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/model/tree/MongoNodeDelta.java Fri Feb 1 14:50:51 2013
@@ -21,7 +21,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.apache.jackrabbit.mk.model.Id;
import org.apache.jackrabbit.mk.model.tree.NodeState;
import org.apache.jackrabbit.mk.model.tree.NodeStateDiff;
import org.apache.jackrabbit.mk.model.tree.NodeStore;
@@ -63,7 +62,7 @@ public class MongoNodeDelta {
Map<String, String> changedProperties = new HashMap<String, String>();
Map<String, NodeState> addedChildNodes = new HashMap<String, NodeState>();
- Map<String, Id> removedChildNodes = new HashMap<String, Id>();
+ Map<String, NodeState> removedChildNodes = new HashMap<String, NodeState>();
Map<String, NodeState> changedChildNodes = new HashMap<String, NodeState>();
public MongoNodeDelta(NodeStore provider, NodeState node1, NodeState node2) {
@@ -88,7 +87,7 @@ public class MongoNodeDelta {
return addedChildNodes;
}
- public Map<String, Id> getRemovedChildNodes() {
+ public Map<String, NodeState> getRemovedChildNodes() {
return removedChildNodes;
}
@@ -154,7 +153,7 @@ public class MongoNodeDelta {
//Map<String, Id> otherChangedChildNodes = other.getChangedChildNodes();
Map<String, NodeState> otherChangedChildNodes = other.getChangedChildNodes();
- Map<String, Id> otherRemovedChildNodes = other.getRemovedChildNodes();
+ Map<String, NodeState> otherRemovedChildNodes = other.getRemovedChildNodes();
for (Map.Entry<String, NodeState> changed : changedChildNodes.entrySet()) {
NodeState otherValue = otherChangedChildNodes.get(changed.getKey());
if (otherValue != null && !changed.getValue().equals(otherValue)) {
@@ -167,7 +166,7 @@ public class MongoNodeDelta {
}
}
- for (Map.Entry<String, Id> removed : removedChildNodes.entrySet()) {
+ for (Map.Entry<String, NodeState> removed : removedChildNodes.entrySet()) {
if (otherChangedChildNodes.containsKey(removed.getKey())) {
// removed child node entry has been changed
conflicts.add(new Conflict(ConflictType.REMOVED_DIRTY_NODE_CONFLICT, removed.getKey()));
@@ -209,7 +208,7 @@ public class MongoNodeDelta {
@Override
public void childNodeDeleted(String name, NodeState before) {
- removedChildNodes.put(name, null /*provider.getId(before)*/);
+ removedChildNodes.put(name, before /*provider.getId(before)*/);
}
}
Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/util/MongoUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/util/MongoUtil.java?rev=1441466&r1=1441465&r2=1441466&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/util/MongoUtil.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/util/MongoUtil.java Fri Feb 1 14:50:51 2013
@@ -20,6 +20,8 @@ import org.apache.jackrabbit.mk.model.tr
import org.apache.jackrabbit.mongomk.api.model.Node;
import org.apache.jackrabbit.mongomk.impl.model.tree.MongoNodeState;
+import static com.google.common.base.Preconditions.checkArgument;
+
/**
* MongoMK specific utility class.
*/
@@ -40,6 +42,12 @@ public class MongoUtil {
}
}
+ public static long getBaseRevision(String branchId) {
+ int i = branchId.indexOf('-');
+ checkArgument(i >= 0, "Not a branch id: " + branchId);
+ return Long.parseLong(branchId.substring(0, i));
+ }
+
public static NodeState wrap(Node node) {
return node != null? new MongoNodeState(node) : null;
}
Added: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/MongoMKRebaseTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/MongoMKRebaseTest.java?rev=1441466&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/MongoMKRebaseTest.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/MongoMKRebaseTest.java Fri Feb 1 14:50:51 2013
@@ -0,0 +1,347 @@
+/*
+ * 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.mongomk.impl;
+
+import org.apache.jackrabbit.mongomk.BaseMongoMicroKernelTest;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for {@code MicroKernel#rebase}
+ * FIXME: this is copied from MicroKernelImplTest. Factor out.
+ */
+public class MongoMKRebaseTest extends BaseMongoMicroKernelTest {
+
+ @Test
+ public void rebaseWithoutChanges() {
+ String branch = mk.branch(null);
+ String rebased = mk.rebase(branch, null);
+ assertEquals(branch, rebased);
+ }
+
+ @Test
+ public void fastForwardRebase() {
+ String branch = mk.branch(null);
+ branch = mk.commit("", "+\"/a\":{}", branch, null);
+ String rebased = mk.rebase(branch, null);
+ assertEquals(branch, rebased);
+ }
+
+ @Test
+ public void rebaseEmptyBranch() {
+ String branch = mk.branch(null);
+ String trunk = mk.commit("", "+\"/a\":{}", null, null);
+ String rebased = mk.rebase(branch, null);
+
+ assertEquals("{\":childNodeCount\":1,\"a\":{}}", mk.getNodes("/", rebased, 0, 0, -1, null));
+ assertEquals("{\":childNodeCount\":1,\"a\":{}}", mk.getNodes("/", null, 0, 0, -1, null));
+ assertEquals(trunk, mk.getHeadRevision());
+ assertFalse((trunk.equals(rebased)));
+ }
+
+ @Test
+ public void rebaseAddNode() {
+ mk.commit("", "+\"/x\":{}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "+\"/x/b\":{}", branch, null);
+ String trunk = mk.commit("", "+\"/x/a\":{}", null, null);
+ String rebased = mk.rebase(branch, null);
+
+ assertEquals(1, mk.getChildNodeCount("/x", null));
+ assertNotNull(mk.getNodes("/x/a", null, 0, 0, -1, null));
+
+ assertEquals(1, mk.getChildNodeCount("/x", branch));
+ assertNotNull(mk.getNodes("/x/b", branch, 0, 0, -1, null));
+
+ assertEquals(2, mk.getChildNodeCount("/x", rebased));
+ assertNotNull(mk.getNodes("/x/a", rebased, 0, 0, -1, null));
+ assertNotNull(mk.getNodes("/x/b", rebased, 0, 0, -1, null));
+ }
+
+ @Test
+ public void rebaseRemoveNode() {
+ mk.commit("", "+\"/x\":{\"y\":{}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "-\"/x/y\"", branch, null);
+ String trunk = mk.commit("", "+\"/x/a\":{}", null, null);
+ String rebased = mk.rebase(branch, null);
+
+ assertEquals(2, mk.getChildNodeCount("/x", null));
+ assertNotNull(mk.getNodes("/x/a", null, 0, 0, -1, null));
+ assertNotNull(mk.getNodes("/x/y", null, 0, 0, -1, null));
+
+ assertEquals(0, mk.getChildNodeCount("/x", branch));
+
+ assertEquals(1, mk.getChildNodeCount("/x", rebased));
+ assertNotNull(mk.getNodes("/x/a", rebased, 0, 0, -1, null));
+ }
+
+ @Test
+ public void rebaseAddProperty() {
+ mk.commit("", "+\"/x\":{\"y\":{}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "^\"/x/y/p\":42", branch, null);
+ String trunk = mk.commit("", "^\"/x/y/q\":99", null, null);
+ String rebased = mk.rebase(branch, null);
+
+ String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null);
+ assertTrue(branchNode.contains("\"p\":42"));
+ assertFalse(branchNode.contains("\"q\":99"));
+
+ String rebasedNode = mk.getNodes("/x/y", rebased, 0, 0, -1, null);
+ assertTrue(rebasedNode.contains("\"p\":42"));
+ assertTrue(rebasedNode.contains("\"q\":99"));
+
+ String trunkNode = mk.getNodes("/x/y", null, 0, 0, -1, null);
+ assertFalse(trunkNode.contains("\"p\":42"));
+ assertTrue(trunkNode.contains("\"q\":99"));
+ }
+
+ @Test
+ public void rebaseRemoveProperty() {
+ mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "^\"/x/y/p\":null", branch, null);
+ String trunk = mk.commit("", "^\"/x/y/q\":99", null, null);
+ String rebased = mk.rebase(branch, null);
+
+ String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null);
+ assertFalse(branchNode.contains("\"p\":42"));
+ assertFalse(branchNode.contains("\"q\":99"));
+
+ String rebasedNode = mk.getNodes("/x/y", rebased, 0, 0, -1, null);
+ assertFalse(rebasedNode.contains("\"p\":42"));
+ assertTrue(rebasedNode.contains("\"q\":99"));
+
+ String trunkNode = mk.getNodes("/x/y", null, 0, 0, -1, null);
+ assertTrue(trunkNode.contains("\"p\":42"));
+ assertTrue(trunkNode.contains("\"q\":99"));
+ }
+
+ @Test
+ public void rebaseChangeProperty() {
+ mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "^\"/x/y/p\":41", branch, null);
+ String trunk = mk.commit("", "^\"/x/y/q\":99", null, null);
+ String rebased = mk.rebase(branch, null);
+
+ String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null);
+ assertTrue(branchNode.contains("\"p\":41"));
+ assertFalse(branchNode.contains("\"q\":99"));
+
+ String rebasedNode = mk.getNodes("/x/y", rebased, 0, 0, -1, null);
+ assertTrue(rebasedNode.contains("\"p\":41"));
+ assertTrue(rebasedNode.contains("\"q\":99"));
+
+ String trunkNode = mk.getNodes("/x/y", null, 0, 0, -1, null);
+ assertTrue(trunkNode.contains("\"p\":42"));
+ assertTrue(trunkNode.contains("\"q\":99"));
+ }
+
+ @Test
+ public void rebaseChangePropertyWithSameValue() {
+ mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "^\"/x/y/p\":99", branch, null);
+ String trunk = mk.commit("", "^\"/x/y/p\":99", null, null);
+ String rebased = mk.rebase(branch, null);
+
+ String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null);
+ assertTrue(branchNode.contains("\"p\":99"));
+
+ String rebasedNode = mk.getNodes("/x/y", branch, 0, 0, -1, null);
+ assertTrue(rebasedNode.contains("\"p\":99"));
+
+ String trunkNode = mk.getNodes("/x/y", null, 0, 0, -1, null);
+ assertTrue(trunkNode.contains("\"p\":99"));
+ }
+
+ @Test
+ public void rebaseAddExistingNode() {
+ mk.commit("", "+\"/x\":{}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "+\"/x/a\":{}", branch, null);
+ mk.commit("", "+\"/x/a\":{\"b\":{}}", null, null);
+
+ branch = mk.rebase(branch, null);
+
+ assertTrue(mk.nodeExists("/x/a/b", branch));
+ String conflict = mk.getNodes("/x/:conflict", branch, 100, 0, -1, null);
+ assertEquals(
+ "{\":childNodeCount\":1,\"addExistingNode\":{\":childNodeCount\":1,\"a\":{\":childNodeCount\":0}}}",
+ conflict);
+ }
+
+ @Test
+ public void rebaseAddExistingProperty() {
+ mk.commit("", "+\"/x\":{\"y\":{}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "^\"/x/y/p\":42 ^\"/x/y/q\":42", branch, null);
+ mk.commit("", "^\"/x/y/p\":99 ^\"/x/y/q\":99", null, null);
+
+ branch = mk.rebase(branch, null);
+
+ String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null);
+ assertTrue(branchNode.contains("\"p\":99"));
+ String conflict = mk.getNodes("/x/y/:conflict", branch, 100, 0, -1, null);
+ assertEquals(
+ "{\":childNodeCount\":1,\"addExistingProperty\":{\"q\":42,\"p\":42,\":childNodeCount\":0}}",
+ conflict);
+ }
+
+ @Test
+ public void rebaseChangeRemovedProperty() {
+ mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "^\"/x/y/p\":99", branch, null);
+ mk.commit("", "^\"/x/y/p\":null", null, null);
+
+ branch = mk.rebase(branch, null);
+
+ String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null);
+ assertFalse(branchNode.contains("\"p\":99"));
+ String conflict = mk.getNodes("/x/y/:conflict", branch, 100, 0, -1, null);
+ assertEquals(
+ "{\":childNodeCount\":1,\"changeDeletedProperty\":{\"p\":99,\":childNodeCount\":0}}",
+ conflict);
+ }
+
+ @Test
+ public void rebaseRemoveChangedProperty() {
+ mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "^\"/x/y/p\":null", branch, null);
+ mk.commit("", "^\"/x/y/p\":99", null, null);
+
+ branch = mk.rebase(branch, null);
+
+ String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null);
+ assertTrue(branchNode.contains("\"p\":99"));
+ String conflict = mk.getNodes("/x/y/:conflict", branch, 100, 0, -1, null);
+ assertEquals(
+ "{\":childNodeCount\":1,\"deleteChangedProperty\":{\"p\":42,\":childNodeCount\":0}}",
+ conflict);
+ }
+
+ @Test
+ public void rebaseChangedChangedProperty() {
+ mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "^\"/x/y/p\":41", branch, null);
+ mk.commit("", "^\"/x/y/p\":99", null, null);
+
+ branch = mk.rebase(branch, null);
+
+ String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null);
+ assertTrue(branchNode.contains("\"p\":99"));
+ String conflict = mk.getNodes("/x/y/:conflict", branch, 100, 0, -1, null);
+ assertEquals(
+ "{\":childNodeCount\":1,\"changeChangedProperty\":{\"p\":41,\":childNodeCount\":0}}",
+ conflict);
+ }
+
+ @Test
+ public void rebaseRemoveChangedNode() {
+ mk.commit("", "+\"/x\":{\"y\":{}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "-\"/x/y\"", branch, null);
+ mk.commit("", "^\"/x/y/p\":42", null, null);
+
+ branch = mk.rebase(branch, null);
+
+ String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null);
+ assertTrue(branchNode.contains("\"p\":42"));
+ String conflict = mk.getNodes("/x/:conflict", branch, 100, 0, -1, null);
+ assertEquals(
+ "{\":childNodeCount\":1,\"deleteChangedNode\":{\":childNodeCount\":1,\"y\":{\":childNodeCount\":0}}}",
+ conflict);
+ }
+
+ @Test
+ public void rebaseChangeRemovedNode() {
+ mk.commit("", "+\"/x\":{\"y\":{}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "^\"/x/p\":42", branch, null);
+ mk.commit("", "-\"/x\"", null, null);
+
+ branch = mk.rebase(branch, null);
+
+ assertFalse(mk.nodeExists("/x", branch));
+ String conflict = mk.getNodes("/:conflict", branch, 100, 0, -1, null);
+ assertEquals(
+ "{\":childNodeCount\":1,\"changeDeletedNode\":{\":childNodeCount\":1,\"x\":{\"p\":42,\"" +
+ ":childNodeCount\":1,\"y\":{\":childNodeCount\":0}}}}",
+ conflict);
+ }
+
+ @Test
+ public void rebaseRemoveRemovedProperty() {
+ mk.commit("", "+\"/x\":{\"y\":{\"p\":42}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "^\"/x/y/p\":null", branch, null);
+ mk.commit("", "^\"/x/y/p\":null", null, null);
+
+ branch = mk.rebase(branch, null);
+
+ String branchNode = mk.getNodes("/x/y", branch, 0, 0, -1, null);
+ assertFalse(branchNode.contains("\"p\":42"));
+ String conflict = mk.getNodes("/x/y/:conflict", branch, 100, 0, -1, null);
+ assertEquals(
+ "{\":childNodeCount\":1,\"deleteDeletedProperty\":{\"p\":42,\":childNodeCount\":0}}",
+ conflict);
+ }
+
+ @Test
+ public void rebaseRemoveRemovedNode() {
+ mk.commit("", "+\"/x\":{\"y\":{}}", null, null);
+ String branch = mk.branch(null);
+ branch = mk.commit("", "-\"/x/y\"", branch, null);
+ mk.commit("", "-\"/x/y\"", null, null);
+
+ branch = mk.rebase(branch, null);
+
+ assertFalse(mk.nodeExists("/x/y", branch));
+ String conflict = mk.getNodes("/x/:conflict", branch, 100, 0, -1, null);
+ assertEquals(
+ "{\":childNodeCount\":1,\"deleteDeletedNode\":{\":childNodeCount\":1,\"y\":{\":childNodeCount\":0}}}",
+ conflict);
+ }
+
+ @Test
+ public void mergeRebased() {
+ mk.commit("", "+\"/x\":{\"y\":{}}", null, null);
+ String branch = mk.branch(null);
+ String trunk = mk.commit("", "^\"/x/p\":42", null, null);
+ branch = mk.commit("", "^\"/x/q\":43", branch, null);
+ branch = mk.rebase(branch, null);
+
+ String branchNode = mk.getNodes("/x", branch, 0, 0, -1, null);
+ assertTrue(branchNode.contains("\"p\":42"));
+ assertTrue(branchNode.contains("\"q\":43"));
+
+ mk.merge(branch, null);
+ String trunkNode = mk.getNodes("/x", branch, 0, 0, -1, null);
+ assertTrue(trunkNode.contains("\"p\":42"));
+ assertTrue(trunkNode.contains("\"q\":43"));
+ }
+
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/MongoMKRebaseTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/MongoMKRebaseTest.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev URL