You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by mr...@apache.org on 2014/09/15 12:35:23 UTC
svn commit: r1624993 - in
/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document:
Branch.java DocumentNodeStore.java LastRevTracker.java
UnmergedBranches.java UnsavedModifications.java
Author: mreutegg
Date: Mon Sep 15 10:35:23 2014
New Revision: 1624993
URL: http://svn.apache.org/r1624993
Log:
OAK-1768: DocumentNodeBuilder.setChildNode() runs OOM with large tree
Work in progress:
- Introduce different types of branch commits (regular and rebase commit) to reduce memory usage of a rebase
- Better hide UnsavedModifications as an implementation detail
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevTracker.java (with props)
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Branch.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Branch.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Branch.java?rev=1624993&r1=1624992&r2=1624993&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Branch.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Branch.java Mon Sep 15 10:35:23 2014
@@ -18,13 +18,21 @@ package org.apache.jackrabbit.oak.plugin
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.transform;
+import java.util.NavigableMap;
+import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentSkipListMap;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
/**
* Contains commit information about a branch and its base revision.
*/
@@ -54,7 +62,8 @@ class Branch {
this.base = base;
this.commits = new ConcurrentSkipListMap<Revision, BranchCommit>(commits.comparator());
for (Revision r : commits) {
- this.commits.put(r.asBranchRevision(), new BranchCommit(base));
+ this.commits.put(r.asBranchRevision(),
+ new BranchCommitImpl(base, r.asBranchRevision()));
}
}
@@ -97,12 +106,7 @@ class Branch {
checkArgument(!checkNotNull(base).isBranch(), "Not a trunk revision: %s", base);
Revision last = commits.lastKey();
checkArgument(commits.comparator().compare(head, last) > 0);
- BranchCommit bc = new BranchCommit(base);
- // set all previously touched paths as modified
- for (BranchCommit c : commits.values()) {
- c.getModifications().applyTo(bc.getModifications(), head);
- }
- commits.put(head, bc);
+ commits.put(head, new RebaseCommit(base, head, commits));
}
/**
@@ -115,7 +119,7 @@ class Branch {
checkArgument(checkNotNull(r).isBranch(), "Not a branch revision: %s", r);
Revision last = commits.lastKey();
checkArgument(commits.comparator().compare(r, last) > 0);
- commits.put(r, new BranchCommit(commits.get(last).getBase()));
+ commits.put(r, new BranchCommitImpl(commits.get(last).getBase(), r));
}
/**
@@ -145,6 +149,18 @@ class Branch {
}
/**
+ * Returns the branch commit with the given or {@code null} if it does not
+ * exist.
+ *
+ * @param r the revision of a commit.
+ * @return the branch commit or {@code null} if it doesn't exist.
+ */
+ @CheckForNull
+ BranchCommit getCommit(@Nonnull Revision r) {
+ return commits.get(checkNotNull(r).asBranchRevision());
+ }
+
+ /**
* Removes the commit with the given revision <code>r</code>. Does nothing
* if there is no such commit.
*
@@ -157,25 +173,6 @@ class Branch {
}
/**
- * Gets the unsaved modifications for the given branch commit revision.
- *
- * @param r a branch commit revision.
- * @return the unsaved modification for the given branch commit.
- * @throws IllegalArgumentException r is not a branch revision or if there
- * is no commit with the given revision.
- */
- @Nonnull
- public UnsavedModifications getModifications(@Nonnull Revision r) {
- checkArgument(checkNotNull(r).isBranch(), "Not a branch revision: %s", r);
- BranchCommit c = commits.get(r);
- if (c == null) {
- throw new IllegalArgumentException(
- "Revision " + r + " is not a commit in this branch");
- }
- return c.getModifications();
- }
-
- /**
* Applies all unsaved modification of this branch to the given collection
* of unsaved trunk modifications with the given merge commit revision.
*
@@ -186,7 +183,7 @@ class Branch {
@Nonnull Revision mergeCommit) {
checkNotNull(trunk);
for (BranchCommit c : commits.values()) {
- c.getModifications().applyTo(trunk, mergeCommit);
+ c.applyTo(trunk, mergeCommit);
}
}
@@ -208,9 +205,8 @@ class Branch {
continue;
}
BranchCommit c = commits.get(r);
- Revision modRevision = c.getModifications().get(path);
- if (modRevision != null) {
- return modRevision;
+ if (c.isModified(path)) {
+ return r;
}
}
return null;
@@ -230,21 +226,107 @@ class Branch {
/**
* Information about a commit within a branch.
*/
- private static final class BranchCommit {
+ abstract static class BranchCommit implements LastRevTracker {
- private final UnsavedModifications modifications = new UnsavedModifications();
- private final Revision base;
+ protected final Revision base;
+ protected final Revision commit;
- BranchCommit(Revision base) {
+ BranchCommit(Revision base, Revision commit) {
this.base = base;
+ this.commit = commit;
}
Revision getBase() {
return base;
}
- UnsavedModifications getModifications() {
+ abstract void applyTo(UnsavedModifications trunk, Revision commit);
+
+ abstract boolean isModified(String path);
+
+ abstract Iterable<String> getModifiedPaths();
+ }
+
+ /**
+ * Implements a regular branch commit.
+ */
+ private static class BranchCommitImpl extends BranchCommit {
+
+ private final Set<String> modifications = Sets.newHashSet();
+
+ BranchCommitImpl(Revision base, Revision commit) {
+ super(base, commit);
+ }
+
+ @Override
+ void applyTo(UnsavedModifications trunk, Revision commit) {
+ for (String p : modifications) {
+ trunk.put(p, commit);
+ }
+ }
+
+ @Override
+ boolean isModified(String path) { // TODO: rather pass NodeDocument?
+ return modifications.contains(path);
+ }
+
+ @Override
+ Iterable<String> getModifiedPaths() {
return modifications;
}
+
+ //------------------< LastRevTracker >----------------------------------
+
+ @Override
+ public void track(String path) {
+ modifications.add(path);
+ }
+ }
+
+ static class RebaseCommit extends BranchCommit {
+
+ private final NavigableMap<Revision, BranchCommit> previous;
+
+ RebaseCommit(Revision base, Revision commit,
+ NavigableMap<Revision, BranchCommit> previous) {
+ super(base, commit);
+ this.previous = Maps.newTreeMap(previous);
+ }
+
+ @Override
+ void applyTo(UnsavedModifications trunk, Revision commit) {
+ for (BranchCommit c : previous.values()) {
+ c.applyTo(trunk, commit);
+ }
+ }
+
+ @Override
+ boolean isModified(String path) {
+ for (BranchCommit c : previous.values()) {
+ if (c.isModified(path)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ Iterable<String> getModifiedPaths() {
+ Iterable<Iterable<String>> paths = transform(previous.values(),
+ new Function<BranchCommit, Iterable<String>>() {
+ @Override
+ public Iterable<String> apply(BranchCommit branchCommit) {
+ return branchCommit.getModifiedPaths();
+ }
+ });
+ return Iterables.concat(paths);
+ }
+
+ //------------------< LastRevTracker >----------------------------------
+
+ @Override
+ public void track(String path) {
+ throw new UnsupportedOperationException("RebaseCommit is read-only");
+ }
}
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1624993&r1=1624992&r2=1624993&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java Mon Sep 15 10:35:23 2014
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.plugin
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.jackrabbit.oak.api.CommitFailedException.MERGE;
+import static org.apache.jackrabbit.oak.plugins.document.Branch.BranchCommit;
import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES;
import static org.apache.jackrabbit.oak.plugins.document.DocumentMK.FAST_DIFF;
import static org.apache.jackrabbit.oak.plugins.document.DocumentMK.MANY_CHILDREN_THRESHOLD;
@@ -912,19 +913,19 @@ public final class DocumentNodeStore
boolean isBranchCommit, List<String> added,
List<String> removed, List<String> changed,
DiffCache.Entry cacheEntry) {
- UnsavedModifications unsaved = unsavedLastRevisions;
+ LastRevTracker tracker = createTracker(rev);
if (disableBranches) {
if (pendingLastRev) {
- unsaved.put(path, rev);
+ tracker.track(path);
}
} else {
if (isBranchCommit) {
Revision branchRev = rev.asBranchRevision();
- unsaved = branches.getBranch(branchRev).getModifications(branchRev);
+ tracker = branches.getBranchCommit(branchRev);
}
if (isBranchCommit || pendingLastRev) {
// write back _lastRev with background thread
- unsaved.put(path, rev);
+ tracker.track(path);
}
}
if (isNew) {
@@ -1497,6 +1498,21 @@ public final class DocumentNodeStore
//-----------------------------< internal >---------------------------------
+ /**
+ * Creates a tracker for the given commit revision.
+ *
+ * @param r a commit revision.
+ * @return a _lastRev tracker for the given commit revision.
+ */
+ private LastRevTracker createTracker(final @Nonnull Revision r) {
+ return new LastRevTracker() {
+ @Override
+ public void track(String path) {
+ unsavedLastRevisions.put(path, r);
+ }
+ };
+ }
+
private static void diffProperties(DocumentNodeState from,
DocumentNodeState to,
JsopWriter w) {
@@ -1561,12 +1577,12 @@ public final class DocumentNodeStore
}
// also consider nodes with not yet stored modifications (OAK-1107)
Revision minRev = new Revision(minTimestamp, 0, getClusterId());
- addPathsForDiff(path, paths, getPendingModifications(), minRev);
+ addPathsForDiff(path, paths, getPendingModifications().getPaths(minRev));
for (Revision r : new Revision[]{fromRev, toRev}) {
if (r.isBranch()) {
- Branch b = getBranches().getBranch(r);
- if (b != null) {
- addPathsForDiff(path, paths, b.getModifications(r), r);
+ BranchCommit c = getBranches().getBranchCommit(r);
+ if (c != null) {
+ addPathsForDiff(path, paths, c.getModifiedPaths());
}
}
}
@@ -1601,9 +1617,8 @@ public final class DocumentNodeStore
private static void addPathsForDiff(String path,
Set<String> paths,
- UnsavedModifications pending,
- Revision minRev) {
- for (String p : pending.getPaths(minRev)) {
+ Iterable<String> modified) {
+ for (String p : modified) {
if (PathUtils.denotesRoot(p)) {
continue;
}
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevTracker.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevTracker.java?rev=1624993&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevTracker.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevTracker.java Mon Sep 15 10:35:23 2014
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.document;
+
+/**
+ * An implementation of this interface receives callbacks about paths
+ * that need an update of the _lastRev field on documents.
+ */
+public interface LastRevTracker {
+
+ /**
+ * Called when a document needs an update of the _lastRev field.
+ *
+ * @param path the path of the document to update.
+ */
+ public void track(String path);
+}
Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevTracker.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java?rev=1624993&r1=1624992&r2=1624993&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java Mon Sep 15 10:35:23 2014
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.oak.plugin
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.jackrabbit.oak.plugins.document.Branch.BranchCommit;
import java.util.Comparator;
import java.util.List;
@@ -120,6 +121,24 @@ class UnmergedBranches {
}
/**
+ * Returns the branch commit with the given revision or {@code null} if
+ * it doesn't exists.
+ *
+ * @param r a revision.
+ * @return the branch commit or {@code null} if it doesn't exist.
+ */
+ @CheckForNull
+ BranchCommit getBranchCommit(@Nonnull Revision r) {
+ for (Branch b : branches) {
+ BranchCommit c = b.getCommit(r);
+ if (c != null) {
+ return c;
+ }
+ }
+ return null;
+ }
+
+ /**
* Removes the given branch.
* @param b the branch to remove.
*/
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java?rev=1624993&r1=1624992&r2=1624993&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java Mon Sep 15 10:35:23 2014
@@ -95,21 +95,6 @@ class UnsavedModifications {
}
/**
- * Applies all modifications from this instance to the <code>other</code>.
- * A modification is only applied if there is no modification in other
- * for a given path or if the other modification is earlier than the
- * {@code commit} revision.
- *
- * @param other the other <code>UnsavedModifications</code>.
- * @param commit the commit revision.
- */
- public void applyTo(UnsavedModifications other, Revision commit) {
- for (Map.Entry<String, Revision> entry : map.entrySet()) {
- other.put(entry.getKey(), commit);
- }
- }
-
- /**
* Returns all paths of nodes with modifications at the start revision
* (inclusive) or later.
*