jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From meteata...@apache.org
Subject svn commit: r1416395 - in /jackrabbit/oak/trunk/oak-mongomk/src: main/java/org/apache/jackrabbit/mongomk/impl/ main/java/org/apache/jackrabbit/mongomk/impl/action/ main/java/org/apache/jackrabbit/mongomk/impl/command/ main/java/org/apache/jackrabbit/mo...
Date Mon, 03 Dec 2012 09:47:39 GMT
Author: meteatamel
Date: Mon Dec  3 09:47:36 2012
New Revision: 1416395

URL: http://svn.apache.org/viewvc?rev=1416395&view=rev
Log:
OAK-440 - Concurrency issue when 3 microkernels are writing in the same db

Added more optimized commands: FetchNodesActionNew, CommitCommandNew and GetNodesCommandNew. The main difference is that these commands do not fetch all commits upfront and this improves performance significantly. I'll keep the old commands for now until I'm sure they are not needed.

Added:
    jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesActionNew.java   (with props)
    jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/CommitCommandNew.java   (with props)
    jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetNodesCommandNew.java   (with props)
Modified:
    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/action/FetchNodesAction.java
    jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/DiffCommand.java
    jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetJournalCommand.java
    jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetRevisionHistoryCommand.java
    jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/MergeCommand.java
    jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/NodeExistsCommand.java
    jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/instruction/CommitCommandInstructionVisitor.java
    jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesActionTest.java
    jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/action/SimpleNodeScenario.java
    jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/CommitCommandTest.java
    jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/ConcurrentCommitCommandTest.java
    jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/ConcurrentConflictingCommitCommandTest.java

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=1416395&r1=1416394&r2=1416395&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 Mon Dec  3 09:47:36 2012
@@ -24,12 +24,12 @@ import org.apache.jackrabbit.mongomk.api
 import org.apache.jackrabbit.mongomk.api.model.Commit;
 import org.apache.jackrabbit.mongomk.api.model.Node;
 import org.apache.jackrabbit.mongomk.impl.action.FetchCommitAction;
-import org.apache.jackrabbit.mongomk.impl.command.CommitCommand;
+import org.apache.jackrabbit.mongomk.impl.command.CommitCommandNew;
 import org.apache.jackrabbit.mongomk.impl.command.DefaultCommandExecutor;
 import org.apache.jackrabbit.mongomk.impl.command.DiffCommand;
 import org.apache.jackrabbit.mongomk.impl.command.GetHeadRevisionCommand;
 import org.apache.jackrabbit.mongomk.impl.command.GetJournalCommand;
-import org.apache.jackrabbit.mongomk.impl.command.GetNodesCommand;
+import org.apache.jackrabbit.mongomk.impl.command.GetNodesCommandNew;
 import org.apache.jackrabbit.mongomk.impl.command.GetRevisionHistoryCommand;
 import org.apache.jackrabbit.mongomk.impl.command.MergeCommand;
 import org.apache.jackrabbit.mongomk.impl.command.NodeExistsCommand;
@@ -73,7 +73,7 @@ public class MongoNodeStore implements N
 
     @Override
     public String commit(Commit commit) throws Exception {
-        Command<Long> command = new CommitCommand(this, commit);
+        Command<Long> command = new CommitCommandNew(this, commit);
         Long revisionId = commandExecutor.execute(command);
         return MongoUtil.fromMongoRepresentation(revisionId);
     }
@@ -95,7 +95,7 @@ public class MongoNodeStore implements N
     @Override
     public Node getNodes(String path, String revisionId, int depth, long offset,
             int maxChildNodes, String filter) throws Exception {
-        GetNodesCommand command = new GetNodesCommand(this, path,
+        GetNodesCommandNew command = new GetNodesCommandNew(this, path,
                 MongoUtil.toMongoRepresentation(revisionId));
         command.setBranchId(getBranchId(revisionId));
         command.setDepth(depth);

Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesAction.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesAction.java?rev=1416395&r1=1416394&r2=1416395&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesAction.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesAction.java Mon Dec  3 09:47:36 2012
@@ -45,7 +45,7 @@ public class FetchNodesAction extends Ba
     private static final Logger LOG = LoggerFactory.getLogger(FetchNodesAction.class);
 
     private final Set<String> paths;
-    private final long revisionId;
+    private long revisionId = -1;
 
     private String branchId;
     private List<MongoCommit> validCommits;
@@ -127,7 +127,7 @@ public class FetchNodesAction extends Ba
             queryBuilder = queryBuilder.regex(pattern);
         }
 
-        if (revisionId > 0) {
+        if (revisionId > -1) {
             queryBuilder = queryBuilder.and(MongoNode.KEY_REVISION_ID).lessThanEquals(revisionId);
         }
 

Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesActionNew.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesActionNew.java?rev=1416395&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesActionNew.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesActionNew.java Mon Dec  3 09:47:36 2012
@@ -0,0 +1,228 @@
+/*
+ * 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.action;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.apache.jackrabbit.mongomk.impl.MongoNodeStore;
+import org.apache.jackrabbit.mongomk.impl.model.MongoCommit;
+import org.apache.jackrabbit.mongomk.impl.model.MongoNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBCursor;
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+
+/**
+ * FIXME - This is same as FetchNodesAction except that it does not require
+ * the list of all valid commits upfront. It also has some optimizations on how
+ * it fetches nodes. Consolidate the two.
+ *
+ * An action for fetching nodes.
+ */
+public class FetchNodesActionNew extends BaseAction<Map<String, MongoNode>> {
+
+    public static final int LIMITLESS_DEPTH = -1;
+    private static final Logger LOG = LoggerFactory.getLogger(FetchNodesActionNew.class);
+
+    private final Set<String> paths;
+    private long revisionId = -1;
+
+    private String branchId;
+    private int depth = LIMITLESS_DEPTH;
+
+    /**
+     * Constructs a new {@code FetchNodesAction} to fetch a node and optionally
+     * its descendants under the specified path.
+     *
+     * @param nodeStore Node store.
+     * @param path The path.
+     * @param revisionId The revision id.
+     */
+    public FetchNodesActionNew(MongoNodeStore nodeStore, String path, long revisionId) {
+        super(nodeStore);
+        paths = new HashSet<String>();
+        paths.add(path);
+        this.revisionId = revisionId;
+    }
+
+    /**
+     * Constructs a new {@code FetchNodesAction} to fetch nodes with the exact
+     * specified paths.
+     *
+     * @param nodeStore Node store.
+     * @param paths The exact paths to fetch nodes for.
+     * @param revisionId The revision id.
+     */
+    public FetchNodesActionNew(MongoNodeStore nodeStore,  Set<String> paths, long revisionId) {
+        super(nodeStore);
+        this.paths = paths;
+        this.revisionId = revisionId;
+    }
+
+    /**
+     * Sets the branchId for the query.
+     *
+     * @param branchId Branch id.
+     */
+    public void setBranchId(String branchId) {
+        this.branchId = branchId;
+    }
+
+    /**
+     * Sets the depth for the command. Only used when fetchDescendants is enabled.
+     *
+     * @param depth The depth for the command or -1 for limitless depth.
+     */
+    public void setDepth(int depth) {
+        this.depth = depth;
+    }
+
+    @Override
+    public Map<String, MongoNode> execute() {
+        if (paths.isEmpty()) {
+            return Collections.emptyMap();
+        }
+        DBCursor dbCursor = performQuery();
+        return getMostRecentValidNodes(dbCursor);
+    }
+
+    private DBCursor performQuery() {
+        QueryBuilder queryBuilder = QueryBuilder.start(MongoNode.KEY_PATH);
+        if (paths.size() > 1) {
+            queryBuilder = queryBuilder.in(paths);
+        } else {
+            String path = paths.toArray(new String[0])[0];
+            Pattern pattern = createPrefixRegExp(path);
+            queryBuilder = queryBuilder.regex(pattern);
+        }
+
+        // FIXME - This needs to be improved to not fetch all revisions of a path.
+        if (revisionId > -1) {
+            queryBuilder = queryBuilder.and(MongoNode.KEY_REVISION_ID).lessThanEquals(revisionId);
+        }
+
+        if (branchId == null) {
+            DBObject query = new BasicDBObject(MongoNode.KEY_BRANCH_ID, new BasicDBObject("$exists", false));
+            queryBuilder = queryBuilder.and(query);
+        } else {
+            // Not only return nodes in the branch but also nodes in the trunk
+            // before the branch was created.
+            long headBranchRevisionId = Long.parseLong(branchId.substring(0, branchId.indexOf("-")));
+
+            DBObject branchQuery = QueryBuilder.start().or(
+                    QueryBuilder.start(MongoNode.KEY_BRANCH_ID).is(branchId).get(),
+                    QueryBuilder.start(MongoNode.KEY_REVISION_ID).lessThanEquals(headBranchRevisionId).get()
+            ).get();
+            queryBuilder = queryBuilder.and(branchQuery);
+        }
+
+        DBObject orderBy = new BasicDBObject(MongoCommit.KEY_REVISION_ID, -1);
+        DBObject query = queryBuilder.get();
+        LOG.debug("Executing query: {}", query);
+
+        return nodeStore.getNodeCollection().find(query).sort(orderBy);
+    }
+
+    private Pattern createPrefixRegExp(String path) {
+        StringBuilder sb = new StringBuilder();
+        String quotedPath = Pattern.quote(path);
+
+        if (depth < 0) {
+            sb.append("^");
+            sb.append(quotedPath);
+        } else if (depth == 0) {
+            sb.append("^");
+            sb.append(quotedPath);
+            sb.append("$");
+        } else if (depth > 0) {
+            sb.append("^");
+            if (!"/".equals(path)) {
+                sb.append(quotedPath);
+            }
+            sb.append("(/[^/]*)");
+            sb.append("{0,");
+            sb.append(depth);
+            sb.append("}$");
+        }
+
+        return Pattern.compile(sb.toString());
+    }
+
+    private Map<String, MongoNode> getMostRecentValidNodes(DBCursor dbCursor) {
+        Map<String, MongoNode> nodeMongos = new HashMap<String, MongoNode>();
+        Map<Long, MongoCommit> commits = new HashMap<Long, MongoCommit>();
+
+        while (dbCursor.hasNext()) {
+            MongoNode nodeMongo = (MongoNode) dbCursor.next();
+            String path = nodeMongo.getPath();
+            // Assuming that revision ids are ordered and nodes are fetched in
+            // sorted order, first check if the path is already in the map.
+            if (nodeMongos.containsKey(path)) {
+                LOG.debug("Converted nodes @{} with path {} was not put into map"
+                        + " because a newer version is available", revisionId, path);
+                continue;
+            } else {
+                long revisionId = nodeMongo.getRevisionId();
+                LOG.debug("Converting node {} ({})", path, revisionId);
+
+                if (!commits.containsKey(revisionId)) {
+                    LOG.debug("Fetching commit @{}", revisionId);
+                    FetchCommitAction action = new FetchCommitAction(nodeStore, revisionId);
+                    try {
+                        MongoCommit commit = action.execute();
+                        commits.put(revisionId, commit);
+                    } catch (Exception e) {
+                        LOG.debug("Node will not be converted as it is not part of a valid commit {} ({})",
+                                path, revisionId);
+                        continue;
+                    }
+                }
+                nodeMongos.put(path, nodeMongo);
+                LOG.debug("Converted node @{} with path {} was put into map", revisionId, path);
+            }
+
+            // This is for unordered revision ids.
+            /*
+            MongoNode existingNodeMongo = nodeMongos.get(path);
+            if (existingNodeMongo != null) {
+                long existingRevId = existingNodeMongo.getRevisionId();
+
+                if (revisionId > existingRevId) {
+                    nodeMongos.put(path, nodeMongo);
+                    LOG.debug("Converted nodes was put into map and replaced {} ({})", path, revisionId);
+                } else {
+                    LOG.debug("Converted nodes was not put into map because a newer version"
+                            + " is available {} ({})", path, revisionId);
+                }
+            } else {
+                nodeMongos.put(path, nodeMongo);
+                LOG.debug("Converted node @{} with path {} was put into map", revisionId, path);
+            }
+            */
+        }
+        dbCursor.close();
+        return nodeMongos;
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesActionNew.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/CommitCommandNew.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/CommitCommandNew.java?rev=1416395&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/CommitCommandNew.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/CommitCommandNew.java Mon Dec  3 09:47:36 2012
@@ -0,0 +1,305 @@
+/*
+ * 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.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.jackrabbit.mongomk.api.instruction.Instruction;
+import org.apache.jackrabbit.mongomk.api.model.Commit;
+import org.apache.jackrabbit.mongomk.impl.MongoNodeStore;
+import org.apache.jackrabbit.mongomk.impl.action.FetchCommitAction;
+import org.apache.jackrabbit.mongomk.impl.action.FetchNodesActionNew;
+import org.apache.jackrabbit.mongomk.impl.action.ReadAndIncHeadRevisionAction;
+import org.apache.jackrabbit.mongomk.impl.action.SaveAndSetHeadRevisionAction;
+import org.apache.jackrabbit.mongomk.impl.action.SaveCommitAction;
+import org.apache.jackrabbit.mongomk.impl.action.SaveNodesAction;
+import org.apache.jackrabbit.mongomk.impl.command.exception.ConflictingCommitException;
+import org.apache.jackrabbit.mongomk.impl.instruction.CommitCommandInstructionVisitor;
+import org.apache.jackrabbit.mongomk.impl.model.MongoCommit;
+import org.apache.jackrabbit.mongomk.impl.model.MongoNode;
+import org.apache.jackrabbit.mongomk.impl.model.MongoSync;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBCollection;
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+import com.mongodb.WriteResult;
+
+/**
+ * FIXME - This is same as CommitCommand except that it does not fetch all valid
+ * commits upfront. Consolidate the two.
+ *
+ * {@code Command} for {@code MongoMicroKernel#commit(String, String, String, String)}
+ */
+public class CommitCommandNew extends BaseCommand<Long> {
+
+    private static final Logger logger = LoggerFactory.getLogger(CommitCommandNew.class);
+
+    private final MongoCommit commit;
+
+    private Set<String> affectedPaths;
+    private Map<String, MongoNode> existingNodes;
+    private MongoSync mongoSync;
+    private Set<MongoNode> nodes;
+    private Long revisionId;
+    private String branchId;
+
+    /**
+     * Constructs a new {@code CommitCommandMongo}.
+     *
+     * @param nodeStore Node store.
+     * @param commit {@link Commit}
+     */
+    public CommitCommandNew(MongoNodeStore nodeStore, Commit commit) {
+        super(nodeStore);
+        this.commit = (MongoCommit)commit;
+    }
+
+    @Override
+    public Long execute() throws Exception {
+        boolean success = false;
+        do {
+            mongoSync = new ReadAndIncHeadRevisionAction(nodeStore).execute();
+            revisionId = mongoSync.getNextRevisionId() - 1;
+            logger.info("Committing @{} with diff: {}", revisionId, commit.getDiff());
+            readBranchIdFromBaseCommit();
+            createMongoNodes();
+            prepareCommit();
+            readExistingNodes();
+            mergeNodes();
+            prepareMongoNodes();
+            new SaveNodesAction(nodeStore, nodes).execute();
+            new SaveCommitAction(nodeStore, commit).execute();
+            success = saveAndSetHeadRevision();
+        } while (!success);
+
+        logger.info("Commit @{}: success", revisionId);
+        return revisionId;
+    }
+
+    @Override
+    public int getNumOfRetries() {
+        return 100;
+    }
+
+    @Override
+    public boolean needsRetry(Exception e) {
+        return e instanceof ConflictingCommitException;
+    }
+
+    private void readBranchIdFromBaseCommit() throws Exception {
+        String commitBranchId = commit.getBranchId();
+        if (commitBranchId != null) {
+            // This is a newly created branch, so no need to check the base
+            // commit's branch id.
+            branchId = commitBranchId;
+            return;
+        }
+
+        Long baseRevisionId = commit.getBaseRevisionId();
+        if (baseRevisionId == null) {
+            return;
+        }
+
+        FetchCommitAction action = new FetchCommitAction(nodeStore, baseRevisionId);
+        MongoCommit commit = action.execute();
+        branchId = commit.getBranchId();
+    }
+
+    private void createMongoNodes() throws Exception {
+        CommitCommandInstructionVisitor visitor = new CommitCommandInstructionVisitor(
+                nodeStore, mongoSync.getHeadRevisionId(), null);
+        visitor.setBranchId(branchId);
+
+        for (Instruction instruction : commit.getInstructions()) {
+            instruction.accept(visitor);
+        }
+
+        Map<String, MongoNode> pathNodeMap = visitor.getPathNodeMap();
+        affectedPaths = pathNodeMap.keySet();
+        nodes = new HashSet<MongoNode>(pathNodeMap.values());
+    }
+
+    private void prepareCommit() throws Exception {
+        commit.setAffectedPaths(new LinkedList<String>(affectedPaths));
+        commit.setBaseRevisionId(mongoSync.getHeadRevisionId());
+        commit.setRevisionId(revisionId);
+        if (commit.getBranchId() == null && branchId != null) {
+            commit.setBranchId(branchId);
+        }
+        commit.removeField("_id"); // In case this is a retry.
+    }
+
+    private void readExistingNodes() {
+        FetchNodesActionNew action = new FetchNodesActionNew(nodeStore, affectedPaths,
+                mongoSync.getHeadRevisionId());
+        action.setBranchId(branchId);
+        existingNodes = action.execute();
+    }
+
+    private void mergeNodes() {
+        for (MongoNode existingNode : existingNodes.values()) {
+            for (MongoNode committingNode : nodes) {
+                if (existingNode.getPath().equals(committingNode.getPath())) {
+                    if(logger.isDebugEnabled()){
+                        logger.debug("Found existing node to merge: {}", existingNode.getPath());
+                        logger.debug("Existing node: {}", existingNode);
+                        logger.debug("Committing node: {}", committingNode);
+                    }
+                    Map<String, Object> existingProperties = existingNode.getProperties();
+                    if (!existingProperties.isEmpty()) {
+                        committingNode.setProperties(existingProperties);
+
+                        logger.debug("Merged properties for {}: {}", existingNode.getPath(),
+                                existingProperties);
+                    }
+
+                    List<String> existingChildren = existingNode.getChildren();
+                    if (existingChildren != null) {
+                        committingNode.setChildren(existingChildren);
+
+                        logger.debug("Merged children for {}: {}", existingNode.getPath(), existingChildren);
+                    }
+
+                    logger.debug("Merged node for {}: {}", existingNode.getPath(), committingNode);
+
+                    break;
+                }
+            }
+        }
+    }
+
+    private void prepareMongoNodes() {
+        for (MongoNode committingNode : nodes) {
+            logger.debug("Preparing children (added and removed) of {}", committingNode.getPath());
+            logger.debug("Committing node: {}", committingNode);
+
+            List<String> children = committingNode.getChildren();
+            if (children == null) {
+                children = new LinkedList<String>();
+            }
+
+            List<String> addedChildren = committingNode.getAddedChildren();
+            if (addedChildren != null) {
+                children.addAll(addedChildren);
+            }
+
+            List<String> removedChildren = committingNode.getRemovedChildren();
+            if (removedChildren != null) {
+                children.removeAll(removedChildren);
+            }
+
+            if (!children.isEmpty()) {
+                Set<String> temp = new HashSet<String>(children); // remove all duplicates
+                committingNode.setChildren(new LinkedList<String>(temp));
+            } else {
+                committingNode.setChildren(null);
+            }
+
+            Map<String, Object> properties = committingNode.getProperties();
+
+            Map<String, Object> addedProperties = committingNode.getAddedProps();
+            if (addedProperties != null) {
+                properties.putAll(addedProperties);
+            }
+
+            Map<String, Object> removedProperties = committingNode.getRemovedProps();
+            if (removedProperties != null) {
+                for (Map.Entry<String, Object> entry : removedProperties.entrySet()) {
+                    properties.remove(entry.getKey());
+                }
+            }
+
+            if (!properties.isEmpty()) {
+                committingNode.setProperties(properties);
+            } else {
+                committingNode.setProperties(null);
+            }
+
+            committingNode.setRevisionId(revisionId);
+            if (branchId != null) {
+                committingNode.setBranchId(branchId);
+            }
+
+            logger.debug("Prepared committing node: {}", committingNode);
+        }
+    }
+
+    /**
+     * Protected for testing purposed only.
+     *
+     * @return True if the operation was successful.
+     * @throws Exception If an exception happens.
+     */
+    protected boolean saveAndSetHeadRevision() throws Exception {
+        long assumedHeadRevision = this.mongoSync.getHeadRevisionId();
+        MongoSync mongoSync = new SaveAndSetHeadRevisionAction(nodeStore,
+                assumedHeadRevision, revisionId).execute();
+        if (mongoSync == null) {
+            // There have been commit(s) in the meantime. If it's a conflicting
+            // update, retry the whole operation and count against number of retries.
+            // If not, need to retry again (in order to write commits and nodes properly)
+            // but don't count these retries against number of retries.
+            if (conflictingCommitsExist(assumedHeadRevision)) {
+                String message = String.format("Commit @%s: failed due to a conflicting commit."
+                        + " Affected paths: %s", revisionId, commit.getAffectedPaths());
+                logger.warn(message);
+                markAsFailed();
+                throw new ConflictingCommitException(message);
+            } else {
+                logger.warn("Commit @{}: failed due to a conflicting commit."
+                        + " Affected paths: {}", revisionId, commit.getAffectedPaths());
+                markAsFailed();
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean conflictingCommitsExist(long baseRevisionId) {
+        QueryBuilder queryBuilder = QueryBuilder.start(MongoCommit.KEY_FAILED).notEquals(Boolean.TRUE)
+                .and(MongoCommit.KEY_BASE_REVISION_ID).is(baseRevisionId)
+                .and(MongoCommit.KEY_REVISION_ID).greaterThan(0L)
+                .and(MongoCommit.KEY_REVISION_ID).notEquals(revisionId);
+        DBObject query = queryBuilder.get();
+        DBCollection collection = nodeStore.getCommitCollection();
+        MongoCommit conflictingCommit = (MongoCommit)collection.findOne(query);
+        for (String affectedPath : conflictingCommit.getAffectedPaths()) {
+            if (affectedPaths.contains(affectedPath)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void markAsFailed() throws Exception {
+        DBCollection commitCollection = nodeStore.getCommitCollection();
+        DBObject query = QueryBuilder.start("_id").is(commit.getObjectId("_id")).get();
+        DBObject update = new BasicDBObject("$set", new BasicDBObject(MongoCommit.KEY_FAILED, Boolean.TRUE));
+        WriteResult writeResult = commitCollection.update(query, update);
+        if (writeResult.getError() != null) {
+            // FIXME This is potentially a bug that we need to handle.
+            throw new Exception(String.format("Update wasn't successful: %s", writeResult));
+        }
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/CommitCommandNew.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/DiffCommand.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/DiffCommand.java?rev=1416395&r1=1416394&r2=1416395&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/DiffCommand.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/DiffCommand.java Mon Dec  3 09:47:36 2012
@@ -81,7 +81,7 @@ public class DiffCommand extends BaseCom
     }
 
     private Node getNode(String path, long revisionId) throws Exception {
-        GetNodesCommand command = new GetNodesCommand(nodeStore, path, revisionId);
+        GetNodesCommandNew command = new GetNodesCommandNew(nodeStore, path, revisionId);
         return command.execute();
     }
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetJournalCommand.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetJournalCommand.java?rev=1416395&r1=1416394&r2=1416395&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetJournalCommand.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetJournalCommand.java Mon Dec  3 09:47:36 2012
@@ -114,6 +114,6 @@ public class GetJournalCommand extends B
     }
 
     private Node getNode(String path, long revisionId) throws Exception {
-        return new GetNodesCommand(nodeStore, path, revisionId).execute();
+        return new GetNodesCommandNew(nodeStore, path, revisionId).execute();
     }
 }
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetNodesCommandNew.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetNodesCommandNew.java?rev=1416395&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetNodesCommandNew.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetNodesCommandNew.java Mon Dec  3 09:47:36 2012
@@ -0,0 +1,179 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import org.apache.jackrabbit.mongomk.api.model.Node;
+import org.apache.jackrabbit.mongomk.impl.MongoNodeStore;
+import org.apache.jackrabbit.mongomk.impl.action.FetchNodesAction;
+import org.apache.jackrabbit.mongomk.impl.action.FetchNodesActionNew;
+import org.apache.jackrabbit.mongomk.impl.command.exception.InconsistentNodeHierarchyException;
+import org.apache.jackrabbit.mongomk.impl.model.MongoNode;
+import org.apache.jackrabbit.mongomk.impl.model.NodeImpl;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * FIXME - This is same as GetNodesCommand except that it does not fetch all valid
+ * commits upfront and it also does not check for stale slave reads. Consolidate the two.
+ *
+ * {@code Command} for {@code MongoMicroKernel#getNodes(String, String, int, long, int, String)}
+ */
+public class GetNodesCommandNew extends BaseCommand<Node> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GetNodesCommandNew.class);
+
+    private final String path;
+
+    private String branchId;
+    private int depth = FetchNodesAction.LIMITLESS_DEPTH;
+    private Long revisionId;
+
+    private Map<String, MongoNode> pathAndNodeMap;
+    private Node rootNode;
+
+    /**
+     * Constructs a new {@code GetNodesCommandMongo}.
+     *
+     * @param nodeStore Node store.
+     * @param path The root path of the nodes to get.
+     * @param revisionId The revision id or null for head revision.
+     */
+    public GetNodesCommandNew(MongoNodeStore nodeStore, String path,
+            Long revisionId) {
+        super(nodeStore);
+        this.path = path;
+        this.revisionId = revisionId;
+    }
+
+    /**
+     * Sets the branchId for the command.
+     *
+     * @param branchId Branch id.
+     */
+    public void setBranchId(String branchId) {
+        this.branchId = branchId;
+    }
+
+    /**
+     * Sets the depth for the command.
+     *
+     * @param depth The depth for the command or -1 for limitless depth.
+     */
+    public void setDepth(int depth) {
+        this.depth = depth;
+    }
+
+    @Override
+    public Node execute() throws Exception {
+        if (revisionId == null) {
+            revisionId = new GetHeadRevisionCommand(nodeStore).execute();
+        }
+        readRootNode();
+        return rootNode;
+    }
+
+    private void readRootNode() throws InconsistentNodeHierarchyException {
+        readNodesByPath();
+        boolean verified = verifyNodeHierarchy();
+        if (!verified) {
+            throw new InconsistentNodeHierarchyException();
+        }
+        buildNodeStructure();
+    }
+
+    @Override
+    public int getNumOfRetries() {
+        return 3;
+    }
+
+    @Override
+    public boolean needsRetry(Exception e) {
+        return e instanceof InconsistentNodeHierarchyException;
+    }
+
+    private void buildNodeStructure() {
+        MongoNode nodeMongoRootOfPath = pathAndNodeMap.get(path);
+        rootNode = buildNodeStructure(nodeMongoRootOfPath);
+    }
+
+    private NodeImpl buildNodeStructure(MongoNode nodeMongo) {
+        if (nodeMongo == null) {
+            return null;
+        }
+
+        NodeImpl node = MongoNode.toNode(nodeMongo);
+
+        for (Iterator<Node> it = node.getChildNodeEntries(0, -1); it.hasNext(); ) {
+            Node child = it.next();
+            MongoNode nodeMongoChild = pathAndNodeMap.get(child.getPath());
+            if (nodeMongoChild != null) {
+                NodeImpl nodeChild = buildNodeStructure(nodeMongoChild);
+                node.addChildNodeEntry(nodeChild);
+            }
+        }
+
+        return node;
+    }
+
+    private void readNodesByPath() {
+        FetchNodesActionNew query = new FetchNodesActionNew(nodeStore, path, revisionId);
+        query.setBranchId(branchId);
+        query.setDepth(depth);
+        pathAndNodeMap = query.execute();
+    }
+
+    private boolean verifyNodeHierarchy() {
+        boolean verified = verifyNodeHierarchyRec(path, 0);
+        if (!verified) {
+            LOG.error("Node hierarchy could not be verified because some nodes"
+                    + " were inconsistent: {}", path);
+        }
+        return verified;
+    }
+
+    private boolean verifyNodeHierarchyRec(String path, int currentDepth) {
+        boolean verified = false;
+
+        if (pathAndNodeMap.isEmpty()) {
+            return true;
+        }
+
+        MongoNode nodeMongo = pathAndNodeMap.get(path);
+        if (nodeMongo != null) {
+            verified = true;
+            if ((depth == -1) || (currentDepth < depth)) {
+                List<String> childNames = nodeMongo.getChildren();
+                if (childNames != null) {
+                    for (String childName : childNames) {
+                        String childPath = PathUtils.concat(path, childName);
+                        verified = verifyNodeHierarchyRec(childPath, ++currentDepth);
+                        if (!verified) {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        return verified;
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetNodesCommandNew.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetRevisionHistoryCommand.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetRevisionHistoryCommand.java?rev=1416395&r1=1416394&r2=1416395&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetRevisionHistoryCommand.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/GetRevisionHistoryCommand.java Mon Dec  3 09:47:36 2012
@@ -84,6 +84,6 @@ public class GetRevisionHistoryCommand e
     }
 
     private Node getNode(String path, long revisionId) throws Exception {
-        return new GetNodesCommand(nodeStore, path, revisionId).execute();
+        return new GetNodesCommandNew(nodeStore, path, revisionId).execute();
     }
 }
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/MergeCommand.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/MergeCommand.java?rev=1416395&r1=1416394&r2=1416395&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/MergeCommand.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/MergeCommand.java Mon Dec  3 09:47:36 2012
@@ -84,7 +84,7 @@ public class MergeCommand extends BaseCo
         Commit newCommit = CommitBuilder.build("", diff,
                 MongoUtil.fromMongoRepresentation(currentHead), message);
 
-        Command<Long> command = new CommitCommand(nodeStore, newCommit);
+        Command<Long> command = new CommitCommandNew(nodeStore, newCommit);
         long revision = command.execute();
         return MongoUtil.fromMongoRepresentation(revision);
     }
@@ -179,7 +179,7 @@ public class MergeCommand extends BaseCo
     }
 
     private Node getNode(String path, long revisionId, String branchId) throws Exception {
-        GetNodesCommand command = new GetNodesCommand(nodeStore, path, revisionId);
+        GetNodesCommandNew command = new GetNodesCommandNew(nodeStore, path, revisionId);
         command.setBranchId(branchId);
         return command.execute();
     }

Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/NodeExistsCommand.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/NodeExistsCommand.java?rev=1416395&r1=1416394&r2=1416395&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/NodeExistsCommand.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/NodeExistsCommand.java Mon Dec  3 09:47:36 2012
@@ -22,7 +22,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.jackrabbit.mongomk.impl.MongoNodeStore;
-import org.apache.jackrabbit.mongomk.impl.action.FetchNodesAction;
+import org.apache.jackrabbit.mongomk.impl.action.FetchNodesActionNew;
 import org.apache.jackrabbit.mongomk.impl.model.MongoCommit;
 import org.apache.jackrabbit.mongomk.impl.model.MongoNode;
 import org.apache.jackrabbit.oak.commons.PathUtils;
@@ -90,9 +90,9 @@ public class NodeExistsCommand extends B
             revisionId = new GetHeadRevisionCommand(nodeStore).execute();
         }
 
-        FetchNodesAction action = new FetchNodesAction(nodeStore, paths, revisionId);
+        FetchNodesActionNew action = new FetchNodesActionNew(nodeStore, paths, revisionId);
         action.setBranchId(branchId);
-        action.setValidCommits(validCommits);
+        //action.setValidCommits(validCommits);
 
         Map<String, MongoNode> pathAndNodeMap = action.execute();
         String currentPath = this.path;

Modified: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/instruction/CommitCommandInstructionVisitor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/instruction/CommitCommandInstructionVisitor.java?rev=1416395&r1=1416394&r2=1416395&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/instruction/CommitCommandInstructionVisitor.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/instruction/CommitCommandInstructionVisitor.java Mon Dec  3 09:47:36 2012
@@ -28,7 +28,7 @@ import org.apache.jackrabbit.mongomk.api
 import org.apache.jackrabbit.mongomk.api.instruction.Instruction.SetPropertyInstruction;
 import org.apache.jackrabbit.mongomk.api.instruction.InstructionVisitor;
 import org.apache.jackrabbit.mongomk.impl.MongoNodeStore;
-import org.apache.jackrabbit.mongomk.impl.action.FetchNodesAction;
+import org.apache.jackrabbit.mongomk.impl.action.FetchNodesActionNew;
 import org.apache.jackrabbit.mongomk.impl.command.NodeExistsCommand;
 import org.apache.jackrabbit.mongomk.impl.exception.NotFoundException;
 import org.apache.jackrabbit.mongomk.impl.model.MongoCommit;
@@ -155,7 +155,7 @@ public class CommitCommandInstructionVis
         }
 
         // First, copy the existing nodes.
-        Map<String, MongoNode> nodesToCopy = new FetchNodesAction(nodeStore,
+        Map<String, MongoNode> nodesToCopy = new FetchNodesActionNew(nodeStore,
                 srcPath, headRevisionId).execute();
         for (MongoNode nodeMongo : nodesToCopy.values()) {
             String oldPath = nodeMongo.getPath();
@@ -203,7 +203,7 @@ public class CommitCommandInstructionVis
         }
 
         // First, copy the existing nodes.
-        Map<String, MongoNode> nodesToCopy = new FetchNodesAction(nodeStore,
+        Map<String, MongoNode> nodesToCopy = new FetchNodesActionNew(nodeStore,
                 srcPath, headRevisionId).execute();
         for (MongoNode nodeMongo : nodesToCopy.values()) {
             String oldPath = nodeMongo.getPath();

Modified: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesActionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesActionTest.java?rev=1416395&r1=1416394&r2=1416395&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesActionTest.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/action/FetchNodesActionTest.java Mon Dec  3 09:47:36 2012
@@ -51,8 +51,7 @@ public class FetchNodesActionTest extend
         invalidateCommit(revisionId1);
         updateBaseRevisionId(revisionId2, 0L);
 
-        FetchNodesAction query = new FetchNodesAction(getNodeStore(), "/", revisionId3);
-        List<Node> actuals = toNode(query.execute());
+        List<Node> actuals = createAndExecuteQuery(revisionId3);
 
         String json = String.format("{\"/#%2$s\" : { \"b#%1$s\" : {}, \"c#%2$s\" : {} }}",
                 revisionId2, revisionId3);
@@ -163,18 +162,14 @@ public class FetchNodesActionTest extend
         SimpleNodeScenario scenario = new SimpleNodeScenario(getNodeStore());
         Long revisionId = scenario.create();
 
-        FetchNodesAction query = new FetchNodesAction(getNodeStore(),
-                getPathSet("/a", "/a/b", "/a/c", "not_existing"), revisionId);
-        List<Node> actuals = toNode(query.execute());
+        List<Node> actuals = createAndExecuteQuery(revisionId, getPathSet("/a", "/a/b", "/a/c", "not_existing"));
         String json = String.format("{ \"/#%1$s\" : { \"a#%1$s\" : { \"int\" : 1 , \"b#%1$s\" : { \"string\" : \"foo\" } , \"c#%1$s\" : { \"bool\" : true } } } }",
                 revisionId);
         Node expected = NodeBuilder.build(json);
         Iterator<Node> expecteds = expected.getChildNodeEntries(0, -1);
         NodeAssert.assertEquals(expecteds, actuals);
 
-        query = new FetchNodesAction(getNodeStore(),
-                getPathSet("/a", "not_existing"), revisionId);
-        actuals = toNode(query.execute());
+        actuals = createAndExecuteQuery(revisionId, getPathSet("/a", "not_existing"));
         json = String.format("{ \"/#%1$s\" : { \"a#%1$s\" : { \"int\" : 1 } } }",
                 revisionId);
         expected = NodeBuilder.build(json);
@@ -188,20 +183,14 @@ public class FetchNodesActionTest extend
         Long firstRevisionId = scenario.create();
         Long secondRevisionId = scenario.update_A_and_add_D_and_E();
 
-        FetchNodesAction query = new FetchNodesAction(getNodeStore(),
-                getPathSet("/a", "/a/b", "/a/c", "/a/d", "/a/b/e", "not_existing"),
-                firstRevisionId);
-        List<Node> actuals = toNode(query.execute());
+        List<Node> actuals = createAndExecuteQuery(firstRevisionId, getPathSet("/a", "/a/b", "/a/c", "/a/d", "/a/b/e", "not_existing"));
         String json = String.format("{ \"/#%1$s\" : { \"a#%1$s\" : { \"int\" : 1 , \"b#%1$s\" : { \"string\" : \"foo\" } , \"c#%1$s\" : { \"bool\" : true } } } }",
                 firstRevisionId);
         Node expected = NodeBuilder.build(json);
         Iterator<Node> expecteds = expected.getChildNodeEntries(0, -1);
         NodeAssert.assertEquals(expecteds, actuals);
 
-        query = new FetchNodesAction(getNodeStore(),
-                getPathSet("/a", "/a/b", "/a/c", "/a/d", "/a/b/e", "not_existing"),
-                secondRevisionId);
-        actuals = toNode(query.execute());
+        actuals = createAndExecuteQuery(secondRevisionId, getPathSet("/a", "/a/b", "/a/c", "/a/d", "/a/b/e", "not_existing"));
         json = String.format("{ \"/#%1$s\" : { \"a#%2$s\" : { \"int\" : 1 , \"double\" : 0.123 , \"b#%2$s\" : { \"string\" : \"foo\" , \"e#%2$s\" : { \"array\" : [ 123, null, 123.456, \"for:bar\", true ] } } , \"c#%1$s\" : { \"bool\" : true }, \"d#%2$s\" : { \"null\" : null } } } }",
                 firstRevisionId, secondRevisionId);
         expected = NodeBuilder.build(json);
@@ -209,12 +198,22 @@ public class FetchNodesActionTest extend
         NodeAssert.assertEquals(expecteds, actuals);
     }
 
-    private List<Node> createAndExecuteQuery(Long revisionId) {
+    private List<Node> createAndExecuteQuery(long revisionId) {
         return createAndExecuteQuery(revisionId, -1);
     }
 
-    private List<Node> createAndExecuteQuery(Long revisionId, int depth) {
-        FetchNodesAction query = new FetchNodesAction(getNodeStore(), "/", revisionId);
+    private List<Node> createAndExecuteQuery(long revisionId, int depth) {
+        Set<String> paths = new HashSet<String>();
+        paths.add("/");
+        return createAndExecuteQuery(revisionId, paths, depth);
+    }
+
+    private List<Node> createAndExecuteQuery(long revisionId, Set<String> paths) {
+        return createAndExecuteQuery(revisionId, paths, -1);
+    }
+
+    private List<Node> createAndExecuteQuery(long revisionId, Set<String> paths, int depth) {
+        FetchNodesActionNew query = new FetchNodesActionNew(getNodeStore(), paths, revisionId);
         if (depth > -1) {
             query.setDepth(depth);
         }

Modified: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/action/SimpleNodeScenario.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/action/SimpleNodeScenario.java?rev=1416395&r1=1416394&r2=1416395&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/action/SimpleNodeScenario.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/action/SimpleNodeScenario.java Mon Dec  3 09:47:36 2012
@@ -18,7 +18,7 @@ package org.apache.jackrabbit.mongomk.im
 
 import org.apache.jackrabbit.mongomk.api.model.Commit;
 import org.apache.jackrabbit.mongomk.impl.MongoNodeStore;
-import org.apache.jackrabbit.mongomk.impl.command.CommitCommand;
+import org.apache.jackrabbit.mongomk.impl.command.CommitCommandNew;
 import org.apache.jackrabbit.mongomk.impl.model.CommitBuilder;
 
 /**
@@ -51,26 +51,26 @@ public class SimpleNodeScenario {
         Commit commit = CommitBuilder.build("/",
                 "+\"a\" : { \"int\" : 1 , \"b\" : { \"string\" : \"foo\" } , \"c\" : { \"bool\" : true } }",
                 "This is the simple node scenario with nodes /, /a, /a/b, /a/c");
-        return new CommitCommand(nodeStore, commit).execute();
+        return new CommitCommandNew(nodeStore, commit).execute();
     }
 
     public Long addChildrenToA(int count) throws Exception {
         Long revisionId = null;
         for (int i = 1; i <= count; i++) {
             Commit commit = CommitBuilder.build("/a", "+\"child" + i + "\" : {}", "Add child" + i);
-            revisionId = new CommitCommand(nodeStore, commit).execute();
+            revisionId = new CommitCommandNew(nodeStore, commit).execute();
         }
         return revisionId;
     }
 
     public Long delete_A() throws Exception {
         Commit commit = CommitBuilder.build("/", "-\"a\"", "This is a commit with deleted /a");
-        return new CommitCommand(nodeStore, commit).execute();
+        return new CommitCommandNew(nodeStore, commit).execute();
     }
 
     public Long delete_B() throws Exception {
         Commit commit = CommitBuilder.build("/a", "-\"b\"", "This is a commit with deleted /a/b");
-        return new CommitCommand(nodeStore, commit).execute();
+        return new CommitCommandNew(nodeStore, commit).execute();
     }
 
     public Long update_A_and_add_D_and_E() throws Exception {
@@ -82,6 +82,6 @@ public class SimpleNodeScenario {
         diff.append("^\"a/b/e/array\" : [ 123, null, 123.456, \"for:bar\", true ]");
         Commit commit = CommitBuilder.build("/", diff.toString(),
                 "This is a commit with updated /a and added /a/d and /a/b/e");
-        return new CommitCommand(nodeStore, commit).execute();
+        return new CommitCommandNew(nodeStore, commit).execute();
     }
 }

Modified: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/CommitCommandTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/CommitCommandTest.java?rev=1416395&r1=1416394&r2=1416395&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/CommitCommandTest.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/CommitCommandTest.java Mon Dec  3 09:47:36 2012
@@ -34,7 +34,7 @@ public class CommitCommandTest extends B
     @Test
     public void initialCommit() throws Exception {
         Commit commit = CommitBuilder.build("/", "+\"a\" : { \"b\" : {} , \"c\" : {} }", null);
-        CommitCommand command = new CommitCommand(getNodeStore(), commit);
+        CommitCommandNew command = new CommitCommandNew(getNodeStore(), commit);
         Long revisionId = command.execute();
 
         Assert.assertNotNull(revisionId);

Modified: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/ConcurrentCommitCommandTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/ConcurrentCommitCommandTest.java?rev=1416395&r1=1416394&r2=1416395&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/ConcurrentCommitCommandTest.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/ConcurrentCommitCommandTest.java Mon Dec  3 09:47:36 2012
@@ -46,11 +46,11 @@ public class ConcurrentCommitCommandTest
         final Object waitLock = new Object();
 
         // create the commands
-        List<CommitCommand> commands = new ArrayList<CommitCommand>(numOfConcurrentThreads);
+        List<CommitCommandNew> commands = new ArrayList<CommitCommandNew>(numOfConcurrentThreads);
         for (int i = 0; i < numOfConcurrentThreads; ++i) {
             Commit commit = CommitBuilder.build("/", "+\"" + i + "\" : {}",
                     "This is a concurrent commit");
-            CommitCommand command = new CommitCommand(getNodeStore(), commit) {
+            CommitCommandNew command = new CommitCommandNew(getNodeStore(), commit) {
                 @Override
                 protected boolean saveAndSetHeadRevision() throws Exception {
                     try {
@@ -73,7 +73,7 @@ public class ConcurrentCommitCommandTest
         ExecutorService executorService = Executors.newFixedThreadPool(numOfConcurrentThreads);
         final List<Long> revisionIds = new LinkedList<Long>();
         for (int i = 0; i < numOfConcurrentThreads; ++i) {
-            final CommitCommand command = commands.get(i);
+            final CommitCommandNew command = commands.get(i);
             Runnable runnable = new Runnable() {
 
                 @Override
@@ -109,7 +109,7 @@ public class ConcurrentCommitCommandTest
         List<String> lastChildren = new LinkedList<String>();
         for (int i = 0; i < numOfConcurrentThreads; ++i) {
             Long revisionId = revisionIds.get(i);
-            GetNodesCommand command2 = new GetNodesCommand(getNodeStore(),
+            GetNodesCommandNew command2 = new GetNodesCommandNew(getNodeStore(),
                     "/", revisionId);
             Node root = command2.execute();
 

Modified: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/ConcurrentConflictingCommitCommandTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/ConcurrentConflictingCommitCommandTest.java?rev=1416395&r1=1416394&r2=1416395&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/ConcurrentConflictingCommitCommandTest.java (original)
+++ jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/command/ConcurrentConflictingCommitCommandTest.java Mon Dec  3 09:47:36 2012
@@ -42,9 +42,9 @@ public class ConcurrentConflictingCommit
     public void rootUpdate() throws Exception {
         int n = 2;
         CountDownLatch latch = new CountDownLatch(n - 1);
-        CommitCommand cmd1 = new WaitingCommitCommand(getNodeStore(),
+        CommitCommandNew cmd1 = new WaitingCommitCommand(getNodeStore(),
                 CommitBuilder.build("/", "+\"a1\" : {}", null), latch);
-        CommitCommand cmd2 = new NotifyingCommitCommand(getNodeStore(),
+        CommitCommandNew cmd2 = new NotifyingCommitCommand(getNodeStore(),
                 CommitBuilder.build("/", "+\"a2\" : {}", null), latch);
 
         ExecutorService executorService = Executors.newFixedThreadPool(n);
@@ -70,9 +70,9 @@ public class ConcurrentConflictingCommit
 
         int n = 2;
         CountDownLatch latch = new CountDownLatch(n - 1);
-        CommitCommand cmd1 = new WaitingCommitCommand(getNodeStore(),
+        CommitCommandNew cmd1 = new WaitingCommitCommand(getNodeStore(),
                 CommitBuilder.build("/", "+\"a1/b1\" : {}", null), latch);
-        CommitCommand cmd2 = new NotifyingCommitCommand(getNodeStore(),
+        CommitCommandNew cmd2 = new NotifyingCommitCommand(getNodeStore(),
                 CommitBuilder.build("/", "+\"a2/b1\" : {}", null), latch);
 
         ExecutorService executorService = Executors.newFixedThreadPool(n);
@@ -99,11 +99,11 @@ public class ConcurrentConflictingCommit
 
         int n = 3;
         CountDownLatch latch = new CountDownLatch(n - 1);
-        CommitCommand cmd1 = new WaitingCommitCommand(getNodeStore(),
+        CommitCommandNew cmd1 = new WaitingCommitCommand(getNodeStore(),
                 CommitBuilder.build("/", "+\"a1/b1\" : {}", null), latch);
-        CommitCommand cmd2 = new NotifyingCommitCommand(getNodeStore(),
+        CommitCommandNew cmd2 = new NotifyingCommitCommand(getNodeStore(),
                 CommitBuilder.build("/", "+\"a2/b1\" : {}", null), latch);
-        CommitCommand cmd3 = new NotifyingCommitCommand(getNodeStore(),
+        CommitCommandNew cmd3 = new NotifyingCommitCommand(getNodeStore(),
                 CommitBuilder.build("/", "+\"a3/b1\" : {}", null), latch);
 
 
@@ -132,11 +132,11 @@ public class ConcurrentConflictingCommit
 
         int n = 3;
         CountDownLatch latch = new CountDownLatch(n - 1);
-        CommitCommand cmd1 = new WaitingCommitCommand(getNodeStore(),
+        CommitCommandNew cmd1 = new WaitingCommitCommand(getNodeStore(),
                 CommitBuilder.build("/", "+\"a1/b1\" : {}", null), latch);
-        CommitCommand cmd2 = new NotifyingCommitCommand(getNodeStore(),
+        CommitCommandNew cmd2 = new NotifyingCommitCommand(getNodeStore(),
                 CommitBuilder.build("/", "+\"a2/b1\" : {}", null), latch);
-        CommitCommand cmd3 = new NotifyingCommitCommand(getNodeStore(),
+        CommitCommandNew cmd3 = new NotifyingCommitCommand(getNodeStore(),
                 CommitBuilder.build("/", "+\"a1/b2\" : {}", null), latch);
 
 
@@ -157,7 +157,7 @@ public class ConcurrentConflictingCommit
     /**
      * A CommitCommand that simply waits on the waitLock until notified.
      */
-    private static class WaitingCommitCommand extends CommitCommand {
+    private static class WaitingCommitCommand extends CommitCommandNew {
 
         private final CountDownLatch latch;
 
@@ -182,7 +182,7 @@ public class ConcurrentConflictingCommit
     /**
      * A CommitCommand that notifies on the waitLock.
      */
-    private static class NotifyingCommitCommand extends CommitCommand {
+    private static class NotifyingCommitCommand extends CommitCommandNew {
 
         private final CountDownLatch latch;
 
@@ -211,9 +211,9 @@ public class ConcurrentConflictingCommit
      */
     private static class CommitCallable implements Callable<Long> {
 
-        private final CommitCommand command;
+        private final CommitCommandNew command;
 
-        public CommitCallable(CommitCommand  command) {
+        public CommitCallable(CommitCommandNew  command) {
             this.command = command;
         }
 



Mime
View raw message