Author: mreutegg Date: Thu Dec 20 14:20:39 2012 New Revision: 1424481 URL: http://svn.apache.org/viewvc?rev=1424481&view=rev Log: OAK-534: Inefficient NodeState comparison with MongoMK
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/OneLevelDiffCommand.java (with props) Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/MongoNodeStore.java jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/MongoMKGetRevisionHistoryTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java?rev=1424481&r1=1424480&r2=1424481&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/KernelNodeState.java Thu Dec 20 14:20:39 2012 @@ -236,9 +236,11 @@ public final class KernelNodeState exten kbase.init(); if (hash != null && hash.equals(kbase.hash)) { return; // no differences - } else if (path.equals(kbase.path)) { - // TODO: Parse the JSON diff returned by the kernel - // kernel.diff(kbase.revision, revision, path); + } else if (path.equals(kbase.path) && !path.equals("/")) { + String jsonDiff = kernel.diff(kbase.getRevision(), revision, path, 0); + if (!hasChanges(jsonDiff)) { + return; // no differences + } } } } @@ -271,6 +273,9 @@ public final class KernelNodeState exten that.init(); if (hash != null && that.hash != null) { return hash.equals(that.hash); + } else if (path.equals(that.path) && !path.equals("/")) { + String jsonDiff = kernel.diff(that.getRevision(), revision, path, 0); + return !hasChanges(jsonDiff); } } } @@ -293,6 +298,10 @@ public final class KernelNodeState exten //------------------------------------------------------------< private >--- + private boolean hasChanges(String journal) { + return !journal.trim().isEmpty(); + } + private Iterable<ChildNodeEntry> getChildNodeEntries( final long offset, final int count) { return new Iterable<ChildNodeEntry>() { 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=1424481&r1=1424480&r2=1424481&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 Thu Dec 20 14:20:39 2012 @@ -36,6 +36,7 @@ import org.apache.jackrabbit.mongomk.imp import org.apache.jackrabbit.mongomk.impl.command.GetRevisionHistoryCommand; 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.WaitForCommitCommand; import org.apache.jackrabbit.mongomk.impl.model.MongoCommit; import org.apache.jackrabbit.mongomk.impl.model.MongoNode; @@ -91,7 +92,12 @@ public class MongoNodeStore implements N @Override public String diff(String fromRevision, String toRevision, String path, int depth) throws Exception { - Command<String> command = new DiffCommand(this, fromRevision, toRevision, path, depth); + Command<String> command; + if (depth == 0) { + command = new OneLevelDiffCommand(this, fromRevision, toRevision, path); + } else { + command = new DiffCommand(this, fromRevision, toRevision, path, depth); + } return commandExecutor.execute(command); } Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/OneLevelDiffCommand.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/OneLevelDiffCommand.java?rev=1424481&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/OneLevelDiffCommand.java (added) +++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/OneLevelDiffCommand.java Thu Dec 20 14:20:39 2012 @@ -0,0 +1,136 @@ +/* + * 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.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.jackrabbit.mk.json.JsopBuilder; +import org.apache.jackrabbit.mk.model.tree.DiffBuilder; +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.model.MongoCommit; +import org.apache.jackrabbit.mongomk.impl.model.MongoNode; +import org.apache.jackrabbit.mongomk.impl.model.NodeImpl; +import org.apache.jackrabbit.mongomk.impl.model.tree.SimpleMongoNodeStore; +import org.apache.jackrabbit.mongomk.util.MongoUtil; +import org.apache.jackrabbit.oak.commons.PathUtils; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * <code>OneLevelDiffCommand</code> implements a specialized {@link DiffCommand} + * with a fixed depth of 0. + */ +public class OneLevelDiffCommand extends BaseCommand<String> { + + private final long fromRevision; + private final long toRevision; + private final String path; + private final int pathDepth; + + public OneLevelDiffCommand(MongoNodeStore nodeStore, String fromRevision, + String toRevision, String path) throws Exception { + super(nodeStore); + this.fromRevision = MongoUtil.toMongoRepresentation(checkNotNull(fromRevision)); + this.toRevision = MongoUtil.toMongoRepresentation(checkNotNull(toRevision)); + this.path = MongoUtil.adjustPath(path); + this.pathDepth = PathUtils.getDepth(this.path); + } + + @Override + public String execute() throws Exception { + MongoCommit fromCommit = new FetchCommitAction( + nodeStore, fromRevision).execute(); + MongoCommit toCommit = new FetchCommitAction( + nodeStore, toRevision).execute(); + FetchNodesActionNew action = new FetchNodesActionNew( + nodeStore, path, 0, fromRevision); + action.setBranchId(fromCommit.getBranchId()); + NodeImpl fromNode = MongoNode.toNode(action.execute().get(path)); + action = new FetchNodesActionNew( + nodeStore, path, 0, toRevision); + action.setBranchId(toCommit.getBranchId()); + NodeImpl toNode = MongoNode.toNode(action.execute().get(path)); + + String diff = ""; + if (!fromNode.getRevisionId().equals(toNode.getRevisionId())) { + // diff of node at given path + DiffBuilder diffBuilder = new DiffBuilder(MongoUtil.wrap(fromNode), + MongoUtil.wrap(toNode), path, 0, new SimpleMongoNodeStore(), path); + diff = diffBuilder.build(); + } + + // find out what changed below path + List<MongoCommit> commits = getCommits(fromCommit, toCommit); + Set<String> affectedPaths = new HashSet<String>(); + for (MongoCommit mc : commits) { + for (String p : mc.getAffectedPaths()) { + if (p.startsWith(path)) { + int d = PathUtils.getDepth(p); + if (d > pathDepth) { + affectedPaths.add(PathUtils.getAncestorPath(p, d - pathDepth - 1)); + } + } + } + } + + JsopBuilder builder = new JsopBuilder(); + for (String p : affectedPaths) { + builder.tag('^'); + builder.key(p); + builder.object().endObject(); + builder.newline(); + } + + return diff + builder.toString(); + } + + /** + * Retrieves the commits within the range of <code>c1</code> and + * <code>c2</code>. The given bounding commits are included in the list as + * well. + * + * @param c1 a MongoCommit + * @param c2 a MongoCommit + * @return the commits from <code>c1</code> to <code>c2</code>. + * @throws Exception if an error occurs. + */ + private List<MongoCommit> getCommits(MongoCommit c1, MongoCommit c2) + throws Exception { + // this implementation does not use the multi commit fetch action + // FetchCommitsAction because that action does not leverage the + // commit cache in NodeStore. Retrieving each commit individually + // results in good cache hit ratios when the revision range is recent + // and not too big. + List<MongoCommit> commits = new ArrayList<MongoCommit>(); + MongoCommit fromCommit = c1.getRevisionId() < c2.getRevisionId() ? c1 : c2; + MongoCommit toCommit = c1.getRevisionId() < c2.getRevisionId() ? c2 : c1; + Long revision = toCommit.getBaseRevisionId(); + commits.add(toCommit); + while (revision != null && revision > fromCommit.getRevisionId()) { + MongoCommit c = new FetchCommitAction(nodeStore, revision).execute(); + commits.add(c); + revision = c.getBaseRevisionId(); + } + commits.add(fromCommit); + return commits; + } +} Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/OneLevelDiffCommand.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/impl/command/OneLevelDiffCommand.java ------------------------------------------------------------------------------ svn:keywords = Author Date Id Revision Rev URL Modified: jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/MongoMKGetRevisionHistoryTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/MongoMKGetRevisionHistoryTest.java?rev=1424481&r1=1424480&r2=1424481&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/MongoMKGetRevisionHistoryTest.java (original) +++ jackrabbit/oak/trunk/oak-mongomk/src/test/java/org/apache/jackrabbit/mongomk/impl/MongoMKGetRevisionHistoryTest.java Thu Dec 20 14:20:39 2012 @@ -72,6 +72,7 @@ public class MongoMKGetRevisionHistoryTe JSONArray array = parseJSONArray(mk.getRevisionHistory(since1, -1, "/")); assertEquals(count1, array.size()); + Thread.sleep(100); long since2 = System.currentTimeMillis(); int count2 = 4;