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 2016/06/14 15:02:00 UTC
svn commit: r1748428 - in /jackrabbit/oak/branches/1.4: ./
oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/
oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/
oak-core/src/test/java/org/apache/jackrabbit/oak/plugi...
Author: mreutegg
Date: Tue Jun 14 15:02:00 2016
New Revision: 1748428
URL: http://svn.apache.org/viewvc?rev=1748428&view=rev
Log:
OAK-4358: Stale cluster ids can potentially lead to lots of previous docs traversal in NodeDocument.getNewestRevision
Merged revision 1746345 from trunk
Modified:
jackrabbit/oak/branches/1.4/ (props changed)
jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java
jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/Utils.java
jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentTest.java
Propchange: jackrabbit/oak/branches/1.4/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Jun 14 15:02:00 2016
@@ -1,3 +1,3 @@
/jackrabbit/oak/branches/1.0:1665962
-/jackrabbit/oak/trunk:1733615,1733875,1733913,1733929,1734230,1734254,1734279,1734941,1735052,1735405,1735484,1735549,1735564,1735588,1735622,1735638,1735919,1735983,1736176,1737309-1737310,1737334,1737349,1737998,1738004,1738775,1738795,1738833,1738950,1738957,1738963,1739894,1740116,1740625-1740626,1740971,1741032,1741339,1741343,1742520,1742888,1742916,1743097,1743172,1743343,1744265,1744959,1745038,1745197,1745368,1746086,1746117,1746342,1746696,1746981,1747492
+/jackrabbit/oak/trunk:1733615,1733875,1733913,1733929,1734230,1734254,1734279,1734941,1735052,1735405,1735484,1735549,1735564,1735588,1735622,1735638,1735919,1735983,1736176,1737309-1737310,1737334,1737349,1737998,1738004,1738775,1738795,1738833,1738950,1738957,1738963,1739894,1740116,1740625-1740626,1740971,1741032,1741339,1741343,1742520,1742888,1742916,1743097,1743172,1743343,1744265,1744959,1745038,1745197,1745368,1746086,1746117,1746342,1746345,1746696,1746981,1747492
/jackrabbit/trunk:1345480
Modified: jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java?rev=1748428&r1=1748427&r2=1748428&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java (original)
+++ jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java Tue Jun 14 15:02:00 2016
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.oak.plugin
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
@@ -39,6 +40,7 @@ import com.google.common.base.Predicate;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
import com.google.common.collect.Queues;
import org.apache.jackrabbit.oak.cache.CacheValue;
import org.apache.jackrabbit.oak.commons.PathUtils;
@@ -54,7 +56,6 @@ import org.slf4j.LoggerFactory;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-import com.google.common.primitives.Longs;
import static com.google.common.base.Objects.equal;
import static com.google.common.base.Preconditions.checkArgument;
@@ -65,6 +66,7 @@ import static org.apache.jackrabbit.oak.
import static org.apache.jackrabbit.oak.plugins.document.StableRevisionComparator.REVERSE;
import static org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
import static org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation;
+import static org.apache.jackrabbit.oak.plugins.document.util.Utils.abortingIterable;
import static org.apache.jackrabbit.oak.plugins.document.util.Utils.resolveCommitRevision;
/**
@@ -759,18 +761,24 @@ public final class NodeDocument extends
}
// if we don't have clusterIds, we can use the local changes only
boolean fullScan = true;
- Iterable<Revision> changes;
- if (clusterIds.isEmpty()) {
- // baseRev is newer than all previous documents
- changes = Iterables.mergeSorted(
- ImmutableList.of(
- getLocalRevisions().keySet(),
- getLocalCommitRoot().keySet()),
- getLocalRevisions().comparator());
- } else {
+ Iterable<Revision> changes = Iterables.mergeSorted(
+ ImmutableList.of(
+ getLocalRevisions().keySet(),
+ getLocalCommitRoot().keySet()),
+ getLocalRevisions().comparator()
+ );
+ if (!clusterIds.isEmpty()) {
+ // there are some previous documents that potentially
+ // contain changes after 'lower' revision vector
// include previous documents as well (only needed in rare cases)
fullScan = false;
- changes = getAllChanges();
+ changes = Iterables.mergeSorted(
+ ImmutableList.of(
+ changes,
+ getChanges(REVISIONS, lower),
+ getChanges(COMMIT_ROOT, lower)
+ ), getLocalRevisions().comparator()
+ );
if (LOG.isDebugEnabled()) {
LOG.debug("getNewestRevision() with changeRev {} on {}, " +
"_revisions {}, _commitRoot {}",
@@ -1448,90 +1456,18 @@ public final class NodeDocument extends
* @return revisions of all changes performed on this document.
*/
Iterable<Revision> getAllChanges() {
- final SortedSet<Revision> stack = Sets.newTreeSet(REVERSE);
- // initialize with local revisions and commitRoot entries
- stack.addAll(getLocalCommitRoot().keySet());
- stack.addAll(getLocalRevisions().keySet());
- if (getPreviousRanges().isEmpty()) {
- return stack;
- }
- return new Iterable<Revision>() {
- @Override
- public Iterator<Revision> iterator() {
- final Iterator<NodeDocument> previousDocs = getPreviousDocLeaves();
- return new AbstractIterator<Revision>() {
- private NodeDocument nextDoc;
- private Revision nextRevision;
- @Override
- protected Revision computeNext() {
- if (stack.isEmpty()) {
- return endOfData();
- }
- Revision next = stack.first();
- stack.remove(next);
- fillStackIfNeeded();
- return next;
- }
-
- private void fillStackIfNeeded() {
- for (;;) {
- fetchNextDoc();
-
- // no more changes to compare with
- if (nextDoc == null) {
- return;
- }
-
- // check if current top revision is still newer than
- // most recent revision of next document
- if (!stack.isEmpty()) {
- Revision top = stack.first();
- if (top.compareRevisionTimeThenClusterId(nextRevision) > 0) {
- return;
- }
- }
-
- // if we get here, we need to pull in changes
- // from nextDoc
- Iterables.addAll(stack, nextDoc.getAllChanges());
- nextDoc = null;
- nextRevision = null;
- }
- }
-
- /**
- * Fetch the next document if {@code nextDoc} is
- * {@code null} and there are more documents.
- */
- private void fetchNextDoc() {
- for (;;) {
- if (nextDoc != null) {
- break;
- }
- if (!previousDocs.hasNext()) {
- // no more previous docs
- break;
- }
- nextDoc = previousDocs.next();
- Iterator<Revision> changes = nextDoc.getAllChanges().iterator();
- if (changes.hasNext()) {
- nextRevision = changes.next();
- break;
- } else {
- // empty document, try next
- nextDoc = null;
- }
- }
- }
- };
- }
- };
+ RevisionVector empty = new RevisionVector();
+ return Iterables.mergeSorted(ImmutableList.of(
+ getChanges(REVISIONS, empty),
+ getChanges(COMMIT_ROOT, empty)
+ ), StableRevisionComparator.REVERSE);
}
/**
* Returns all changes for the given property back to {@code min} revision
* (exclusive). The revisions include committed as well as uncommitted
- * changes.
+ * changes. The returned revisions are sorted in reverse order (newest
+ * first).
*
* @param property the name of the property.
* @param min the lower bound revision (exclusive).
@@ -1540,43 +1476,27 @@ public final class NodeDocument extends
@Nonnull
Iterable<Revision> getChanges(@Nonnull final String property,
@Nonnull final RevisionVector min) {
- return new Iterable<Revision>() {
+ Predicate<Revision> p = new Predicate<Revision>() {
@Override
- public Iterator<Revision> iterator() {
- final Set<Revision> changes = getValueMap(property).keySet();
- final Set<Integer> clusterIds = Sets.newHashSet();
- for (Revision r : getLocalMap(property).keySet()) {
- clusterIds.add(r.getClusterId());
- }
- for (Range r : getPreviousRanges().values()) {
- if (min.isRevisionNewer(r.high)) {
- clusterIds.add(r.high.getClusterId());
- }
- }
- final Iterator<Revision> unfiltered = changes.iterator();
- return new AbstractIterator<Revision>() {
- @Override
- protected Revision computeNext() {
- while (unfiltered.hasNext()) {
- Revision next = unfiltered.next();
- if (min.isRevisionNewer(next)) {
- return next;
- } else {
- // further revisions with this clusterId
- // are older than min revision
- clusterIds.remove(next.getClusterId());
- // no more revisions to check
- if (clusterIds.isEmpty()) {
- return endOfData();
- }
- }
- }
- return endOfData();
- }
- };
+ public boolean apply(Revision input) {
+ return min.isRevisionNewer(input);
}
};
-
+ List<Iterable<Revision>> changes = Lists.newArrayList();
+ changes.add(abortingIterable(getLocalMap(property).keySet(), p));
+ for (Map.Entry<Revision, Range> e : getPreviousRanges().entrySet()) {
+ if (min.isRevisionNewer(e.getKey())) {
+ final NodeDocument prev = getPreviousDoc(e.getKey(), e.getValue());
+ if (prev != null) {
+ changes.add(abortingIterable(prev.getValueMap(property).keySet(), p));
+ }
+ }
+ }
+ if (changes.size() == 1) {
+ return changes.get(0);
+ } else {
+ return Iterables.mergeSorted(changes, StableRevisionComparator.REVERSE);
+ }
}
/**
Modified: jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/Utils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/Utils.java?rev=1748428&r1=1748427&r2=1748428&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/Utils.java (original)
+++ jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/Utils.java Tue Jun 14 15:02:00 2016
@@ -758,4 +758,36 @@ public class Utils {
}
return min;
}
+
+ /**
+ * Wraps the given iterable and aborts iteration over elements when the
+ * predicate on an element evaluates to {@code false}.
+ *
+ * @param iterable the iterable to wrap.
+ * @param p the predicate.
+ * @return the aborting iterable.
+ */
+ public static <T> Iterable<T> abortingIterable(final Iterable<T> iterable,
+ final Predicate<T> p) {
+ checkNotNull(iterable);
+ checkNotNull(p);
+ return new Iterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ final Iterator<T> it = iterable.iterator();
+ return new AbstractIterator<T>() {
+ @Override
+ protected T computeNext() {
+ if (it.hasNext()) {
+ T next = it.next();
+ if (p.apply(next)) {
+ return next;
+ }
+ }
+ return endOfData();
+ }
+ };
+ }
+ };
+ }
}
Modified: jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentTest.java?rev=1748428&r1=1748427&r2=1748428&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentTest.java (original)
+++ jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentTest.java Tue Jun 14 15:02:00 2016
@@ -36,7 +36,6 @@ import org.apache.jackrabbit.oak.spi.com
import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
-import org.junit.Ignore;
import org.junit.Test;
import static com.google.common.collect.Sets.newHashSet;
@@ -552,7 +551,6 @@ public class NodeDocumentTest {
}
// OAK-4358
- @Ignore
@Test
public void tooManyReadsOnGetNewestRevision() throws Exception {
final Set<String> prevDocCalls = newHashSet();