Author: baedke Date: Tue Sep 27 13:34:26 2016 New Revision: 1762477 URL: http://svn.apache.org/viewvc?rev=1762477&view=rev Log: OAK-4528: diff calculation in DocumentNodeStore should try to re-use journal info on diff cache miss
Added: jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalDiffLoader.java - copied unchanged from r1752596, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalDiffLoader.java jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JsopNodeStateDiffer.java - copied unchanged from r1752596, jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JsopNodeStateDiffer.java jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalDiffLoaderTest.java - copied unchanged from r1752596, jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalDiffLoaderTest.java Modified: jackrabbit/oak/branches/1.4/ (props changed) jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalGarbageCollector.java jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalEntryTest.java jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalGCTest.java jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/SimpleTest.java Propchange: jackrabbit/oak/branches/1.4/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Tue Sep 27 13:34:26 2016 @@ -1,3 +1,3 @@ /jackrabbit/oak/branches/1.0:1665962 -/jackrabbit/oak/trunk:1733615,1733875,1733913,1733929,1734230,1734254,1734279,1734941,1735052,1735081,1735141,1735267,1735405,1735484,1735549,1735564,1735588,1735622,1735638,1735919,1735983,1736176,1737309-1737310,1737334,1737349,1737998,1738004,1738136,1738138,1738207,1738234,1738252,1738775,1738795,1738833,1738950,1738957,1738963,1739712,1739760,1739867,1739894,1739959-1739960,1740114,1740116,1740250,1740333,1740360,1740625-1740626,1740774,1740837,1740971,1741016,1741032,1741339,1741343,1742077,1742117,1742363,1742520,1742888,1742916,1743097,1743172,1743343,1743674,1744265,1744292,1744589,1744670,1744672,1744959,1745038,1745127,1745197,1745336,1745368,1746086,1746117,1746342,1746345,1746408,1746696,1746981,1747198,1747200,1747341-1747342,1747380,1747387,1747406,1747492,1747512,1747654,1748505,1748553,1748722,1748870,1749275,1749350,1749424,1749443,1749464,1749475,1749645,1749662,1749815,1749872,1749875,1749899,1750052,1750076-1750077,1750287,1750457,1750462,1750465,1750495,1750626 ,1750809,1750886,1751410,1751445-1751446,1751478,1751755,1751871,1752198,1752202,1752259,1752273-1752274,1752283,1752292,1752438,1752447-1752448,1752508,1752616,1752659,1752672,1753262,1753331-1753332,1753355,1753444,1754117,1754239,1755157,1756520,1756580,1757119,1757166,1759433,1760340,1760373,1760387,1760661-1760662,1761412,1761444,1761571,1761762,1761787 +/jackrabbit/oak/trunk:1733615,1733875,1733913,1733929,1734230,1734254,1734279,1734941,1735052,1735081,1735141,1735267,1735405,1735484,1735549,1735564,1735588,1735622,1735638,1735919,1735983,1736176,1737309-1737310,1737334,1737349,1737998,1738004,1738136,1738138,1738207,1738234,1738252,1738775,1738795,1738833,1738950,1738957,1738963,1739712,1739760,1739867,1739894,1739959-1739960,1740114,1740116,1740250,1740333,1740360,1740625-1740626,1740774,1740837,1740971,1741016,1741032,1741339,1741343,1742077,1742117,1742363,1742520,1742888,1742916,1743097,1743172,1743343,1743674,1744265,1744292,1744589,1744670,1744672,1744959,1745038,1745127,1745197,1745336,1745368,1746086,1746117,1746342,1746345,1746408,1746696,1746981,1747198,1747200,1747341-1747342,1747380,1747387,1747406,1747492,1747512,1747654,1748505,1748553,1748722,1748870,1749275,1749350,1749424,1749443,1749464,1749475,1749645,1749662,1749815,1749872,1749875,1749899,1750052,1750076-1750077,1750287,1750457,1750462,1750465,1750495,1750626 ,1750809,1750886,1751410,1751445-1751446,1751478,1751755,1751871,1752198,1752202,1752259,1752273-1752274,1752283,1752292,1752438,1752447-1752448,1752508,1752596,1752616,1752659,1752672,1753262,1753331-1753332,1753355,1753444,1754117,1754239,1755157,1756520,1756580,1757119,1757166,1759433,1760340,1760373,1760387,1760661-1760662,1761412,1761444,1761571,1761762,1761787 /jackrabbit/trunk:1345480 Modified: jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1762477&r1=1762476&r2=1762477&view=diff ============================================================================== --- jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (original) +++ jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java Tue Sep 27 13:34:26 2016 @@ -147,6 +147,12 @@ public final class DocumentNodeStore Boolean.parseBoolean(System.getProperty("oak.fairBackgroundOperationLock", "true")); /** + * Feature flag to disable the journal diff mechanism. See OAK-4528. + */ + private boolean disableJournalDiff = + Boolean.getBoolean("oak.disableJournalDiff"); + + /** * The document store (might be used by multiple node stores). */ protected final DocumentStore store; @@ -1454,22 +1460,22 @@ public final class DocumentNodeStore */ @Override public boolean compare(@Nonnull final AbstractDocumentNodeState node, - @Nonnull final AbstractDocumentNodeState base, - @Nonnull NodeStateDiff diff) { + @Nonnull final AbstractDocumentNodeState base, + @Nonnull NodeStateDiff diff) { if (!AbstractNodeState.comparePropertiesAgainstBaseState(node, base, diff)) { return false; } if (node.hasNoChildren() && base.hasNoChildren()) { return true; } - return dispatch(diffCache.getChanges(base.getRootRevision(), + return new JsopNodeStateDiffer(diffCache.getChanges(base.getRootRevision(), node.getRootRevision(), node.getPath(), new DiffCache.Loader() { @Override public String call() { return diffImpl(base, node); } - }), node, base, diff); + })).withoutPropertyChanges().compare(node, base, diff); } /** @@ -2165,47 +2171,6 @@ public final class DocumentNodeStore } } - private boolean dispatch(@Nonnull final String jsonDiff, - @Nonnull final AbstractDocumentNodeState node, - @Nonnull final AbstractDocumentNodeState base, - @Nonnull final NodeStateDiff diff) { - return DiffCache.parseJsopDiff(jsonDiff, new DiffCache.Diff() { - @Override - public boolean childNodeAdded(String name) { - return diff.childNodeAdded(name, - node.getChildNode(name)); - } - - @Override - public boolean childNodeChanged(String name) { - boolean continueComparison = true; - NodeState baseChild = base.getChildNode(name); - NodeState nodeChild = node.getChildNode(name); - if (baseChild.exists()) { - if (nodeChild.exists()) { - continueComparison = diff.childNodeChanged(name, - baseChild, nodeChild); - } else { - continueComparison = diff.childNodeDeleted(name, - baseChild); - } - } else { - if (nodeChild.exists()) { - continueComparison = diff.childNodeAdded(name, - nodeChild); - } - } - return continueComparison; - } - - @Override - public boolean childNodeDeleted(String name) { - return diff.childNodeDeleted(name, - base.getChildNode(name)); - } - }); - } - /** * Search for presence of child node as denoted by path in the children cache of parent * @@ -2248,44 +2213,54 @@ public final class DocumentNodeStore private String diffImpl(AbstractDocumentNodeState from, AbstractDocumentNodeState to) throws DocumentStoreException { - JsopWriter w = new JsopStream(); - // TODO this does not work well for large child node lists - // use a document store index instead int max = MANY_CHILDREN_THRESHOLD; final boolean debug = LOG.isDebugEnabled(); final long start = debug ? now() : 0; + long getChildrenDoneIn = start; - DocumentNodeState.Children fromChildren, toChildren; - fromChildren = getChildren(from, null, max); - toChildren = getChildren(to, null, max); - - final long getChildrenDoneIn = debug ? now() : 0; - + String diff; String diffAlgo; RevisionVector fromRev = from.getLastRevision(); RevisionVector toRev = to.getLastRevision(); - if (!fromChildren.hasMore && !toChildren.hasMore) { - diffAlgo = "diffFewChildren"; - diffFewChildren(w, from.getPath(), fromChildren, - fromRev, toChildren, toRev); + long minTimestamp = Utils.getMinTimestampForDiff( + fromRev, toRev, getMinExternalRevisions()); + + // use journal if possible + Revision tailRev = journalGarbageCollector.getTailRevision(); + if (!disableJournalDiff + && tailRev.getTimestamp() < minTimestamp) { + diffAlgo = "diffJournalChildren"; + diff = new JournalDiffLoader(from, to, this).call(); } else { - if (FAST_DIFF) { - diffAlgo = "diffManyChildren"; - fromRev = from.getRootRevision(); - toRev = to.getRootRevision(); - diffManyChildren(w, from.getPath(), fromRev, toRev); - } else { - diffAlgo = "diffAllChildren"; - max = Integer.MAX_VALUE; - fromChildren = getChildren(from, null, max); - toChildren = getChildren(to, null, max); + DocumentNodeState.Children fromChildren, toChildren; + fromChildren = getChildren(from, null, max); + toChildren = getChildren(to, null, max); + getChildrenDoneIn = debug ? now() : 0; + + JsopWriter w = new JsopStream(); + if (!fromChildren.hasMore && !toChildren.hasMore) { + diffAlgo = "diffFewChildren"; diffFewChildren(w, from.getPath(), fromChildren, fromRev, toChildren, toRev); + } else { + if (FAST_DIFF) { + diffAlgo = "diffManyChildren"; + fromRev = from.getRootRevision(); + toRev = to.getRootRevision(); + diffManyChildren(w, from.getPath(), fromRev, toRev); + } else { + diffAlgo = "diffAllChildren"; + max = Integer.MAX_VALUE; + fromChildren = getChildren(from, null, max); + toChildren = getChildren(to, null, max); + diffFewChildren(w, from.getPath(), fromChildren, + fromRev, toChildren, toRev); + } } + diff = w.toString(); } - String diff = w.toString(); if (debug) { long end = now(); LOG.debug("Diff performed via '{}' at [{}] between revisions [{}] => [{}] took {} ms ({} ms), diff '{}', external '{}", Modified: jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java?rev=1762477&r1=1762476&r2=1762477&view=diff ============================================================================== --- jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java (original) +++ jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java Tue Sep 27 13:34:26 2016 @@ -175,7 +175,9 @@ public final class JournalEntry extends /** * Reads all external changes between the two given revisions (with the same * clusterId) from the journal and appends the paths therein to the provided - * sorter. + * sorter. If there is no exact match of a journal entry for the given + * {@code to} revision, this method will fill external changes from the + * next higher journal entry that contains the revision. * * @param sorter the StringSort to which all externally changed paths * between the provided revisions will be added @@ -191,6 +193,10 @@ public final class JournalEntry extends throws IOException { checkArgument(checkNotNull(from).getClusterId() == checkNotNull(to).getClusterId()); + if (from.compareRevisionTime(to) >= 0) { + return; + } + // to is inclusive, but DocumentStore.query() toKey is exclusive final String inclusiveToId = asId(to); to = new Revision(to.getTimestamp(), to.getCounter() + 1, @@ -203,6 +209,8 @@ public final class JournalEntry extends // limit, then loop and do subsequent queries final String toId = asId(to); String fromId = asId(from); + int numEntries = 0; + JournalEntry lastEntry = null; while (true) { if (fromId.equals(inclusiveToId)) { // avoid query if from and to are off by just 1 counter (which @@ -212,6 +220,10 @@ public final class JournalEntry extends break; } List<JournalEntry> partialResult = store.query(JOURNAL, fromId, toId, READ_CHUNK_SIZE); + numEntries += partialResult.size(); + if (!partialResult.isEmpty()) { + lastEntry = partialResult.get(partialResult.size() - 1); + } for (JournalEntry d : partialResult) { d.addTo(sorter); @@ -224,6 +236,16 @@ public final class JournalEntry extends // include the from which we'd otherwise double-process) fromId = partialResult.get(partialResult.size() - 1).getId(); } + // check if last processed journal entry covers toId, otherwise + // read next document. also read next journal entry when none + // were read so far + if (numEntries == 0 + || (lastEntry != null && !lastEntry.getId().equals(inclusiveToId))) { + String maxId = asId(new Revision(Long.MAX_VALUE, 0, to.getClusterId())); + for (JournalEntry d : store.query(JOURNAL, inclusiveToId, maxId, 1)) { + d.addTo(sorter); + } + } } long getRevisionTimestamp() { Modified: jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalGarbageCollector.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalGarbageCollector.java?rev=1762477&r1=1762476&r2=1762477&view=diff ============================================================================== --- jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalGarbageCollector.java (original) +++ jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalGarbageCollector.java Tue Sep 27 13:34:26 2016 @@ -22,11 +22,14 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; +import org.apache.jackrabbit.oak.plugins.document.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Stopwatch; +import static org.apache.jackrabbit.oak.plugins.document.Collection.SETTINGS; + /** * The JournalGarbageCollector can clean up JournalEntries that are older than a * particular age. @@ -38,12 +41,27 @@ import com.google.common.base.Stopwatch; */ public class JournalGarbageCollector { + private static final Logger log = LoggerFactory.getLogger(JournalGarbageCollector.class); + + /** + * ID of the journalGC document in the settings collection. + */ + private static final String JOURNAL_GC_ID = "journalGC"; + + /** + * Key name of the entry that contains the timestamp of the journal tail. + */ + private static final String TAIL_TIMESTAMP = "tailTimestamp"; + private final DocumentNodeStore ns; - private static final Logger log = LoggerFactory.getLogger(JournalGarbageCollector.class); + private volatile long lastTailTimestampRefresh = Long.MIN_VALUE; + + private Revision tailRevision; public JournalGarbageCollector(DocumentNodeStore nodeStore) { this.ns = nodeStore; + this.tailRevision = new Revision(0, 0, ns.getClusterId()); } /** @@ -89,6 +107,10 @@ public class JournalGarbageCollector { // will compete at deletion, which is not optimal // due to performance, but does not harm. + // update the tail timestamp in the journalGC document + // of the settings collection + updateTailTimestamp(gcOlderThan); + // 1. get the list of cluster node ids final List<ClusterNodeInfoDocument> clusterNodeInfos = ClusterNodeInfoDocument.all(ds); int numDeleted = 0; @@ -139,6 +161,36 @@ public class JournalGarbageCollector { return numDeleted; } + private void updateTailTimestamp(long gcOlderThan) { + UpdateOp op = new UpdateOp(JOURNAL_GC_ID, true); + op.max(TAIL_TIMESTAMP, gcOlderThan); + ns.getDocumentStore().createOrUpdate(SETTINGS, op); + } + + public Revision getTailRevision() { + refreshTailRevisionIfNecessary(); + return tailRevision; + } + + private void refreshTailRevisionIfNecessary() { + // refresh once a minute + long now = ns.getClock().getTime(); + if (lastTailTimestampRefresh + TimeUnit.MINUTES.toMillis(1) > now) { + return; + } + lastTailTimestampRefresh = now; + + Document doc = ns.getDocumentStore().find(SETTINGS, JOURNAL_GC_ID); + if (doc == null) { + // no gc yet + return; + } + Long ts = Utils.asLong((Number) doc.get(TAIL_TIMESTAMP)); + if (ts != null) { + tailRevision = Utils.max(tailRevision, new Revision(ts, 0, ns.getClusterId())); + } + } + private List<String> asKeys(List<JournalEntry> deletionBatch) { final List<String> keys = new ArrayList<String>(deletionBatch.size()); for (JournalEntry e : deletionBatch) { Modified: jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java?rev=1762477&r1=1762476&r2=1762477&view=diff ============================================================================== --- jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java (original) +++ jackrabbit/oak/branches/1.4/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java Tue Sep 27 13:34:26 2016 @@ -138,6 +138,26 @@ class UnmergedBranches { } /** + * Returns {@code true} if the given revision is the base of an unmerged + * branch. + * + * @param r the base revision of a branch. + * @return {@code true} if such a branch exists, {@code false} otherwise. + */ + boolean isBranchBase(@Nonnull RevisionVector r) { + if (!r.isBranch()) { + return false; + } + RevisionVector base = r.asTrunkRevision(); + for (Branch b : branches) { + if (b.getBase().equals(base)) { + return true; + } + } + return false; + } + + /** * Returns the branch commit with the given revision or {@code null} if * it doesn't exists. * Modified: jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java?rev=1762477&r1=1762476&r2=1762477&view=diff ============================================================================== --- jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java (original) +++ jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java Tue Sep 27 13:34:26 2016 @@ -2173,6 +2173,10 @@ public class DocumentNodeStoreTest { // OAK-1970 @Test public void diffMany() throws Exception { + // make sure diffMany is used and not the new + // journal diff introduced with OAK-4528 + System.setProperty("oak.disableJournalDiff", "true"); + Clock clock = new Clock.Virtual(); clock.waitUntil(System.currentTimeMillis()); Revision.setClock(clock); @@ -2233,6 +2237,8 @@ public class DocumentNodeStoreTest { // startValue must be based on the revision of the before state // and not when '/test' was last modified assertEquals(beforeModified, (long) startValues.get(0)); + + System.clearProperty("oak.disableJournalDiff"); } // OAK-2620 Modified: jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalEntryTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalEntryTest.java?rev=1762477&r1=1762476&r2=1762477&view=diff ============================================================================== --- jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalEntryTest.java (original) +++ jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalEntryTest.java Tue Sep 27 13:34:26 2016 @@ -136,6 +136,76 @@ public class JournalEntryTest { } @Test + public void fillExternalChanges2() throws Exception { + Revision r1 = new Revision(1, 0, 1); + Revision r2 = new Revision(2, 0, 1); + Revision r3 = new Revision(3, 0, 1); + Revision r4 = new Revision(4, 0, 1); + DocumentStore store = new MemoryDocumentStore(); + JournalEntry entry = JOURNAL.newDocument(store); + entry.modified("/"); + entry.modified("/foo"); + UpdateOp op = entry.asUpdateOp(r2); + assertTrue(store.create(JOURNAL, Collections.singletonList(op))); + + entry = JOURNAL.newDocument(store); + entry.modified("/"); + entry.modified("/bar"); + op = entry.asUpdateOp(r4); + assertTrue(store.create(JOURNAL, Collections.singletonList(op))); + + StringSort sort = JournalEntry.newSorter(); + JournalEntry.fillExternalChanges(sort, r1, r1, store); + assertEquals(0, sort.getSize()); + sort.close(); + + sort = JournalEntry.newSorter(); + JournalEntry.fillExternalChanges(sort, r1, r2, store); + assertEquals(Sets.newHashSet("/", "/foo"), Sets.newHashSet(sort)); + sort.close(); + + sort = JournalEntry.newSorter(); + JournalEntry.fillExternalChanges(sort, r1, r3, store); + assertEquals(Sets.newHashSet("/", "/foo", "/bar"), Sets.newHashSet(sort)); + sort.close(); + + sort = JournalEntry.newSorter(); + JournalEntry.fillExternalChanges(sort, r1, r4, store); + assertEquals(Sets.newHashSet("/", "/foo", "/bar"), Sets.newHashSet(sort)); + sort.close(); + + sort = JournalEntry.newSorter(); + JournalEntry.fillExternalChanges(sort, r2, r2, store); + assertEquals(0, sort.getSize()); + sort.close(); + + sort = JournalEntry.newSorter(); + JournalEntry.fillExternalChanges(sort, r2, r3, store); + assertEquals(Sets.newHashSet("/", "/bar"), Sets.newHashSet(sort)); + sort.close(); + + sort = JournalEntry.newSorter(); + JournalEntry.fillExternalChanges(sort, r2, r4, store); + assertEquals(Sets.newHashSet("/", "/bar"), Sets.newHashSet(sort)); + sort.close(); + + sort = JournalEntry.newSorter(); + JournalEntry.fillExternalChanges(sort, r3, r3, store); + assertEquals(0, sort.getSize()); + sort.close(); + + sort = JournalEntry.newSorter(); + JournalEntry.fillExternalChanges(sort, r3, r4, store); + assertEquals(Sets.newHashSet("/", "/bar"), Sets.newHashSet(sort)); + sort.close(); + + sort = JournalEntry.newSorter(); + JournalEntry.fillExternalChanges(sort, r4, r4, store); + assertEquals(0, sort.getSize()); + sort.close(); + } + + @Test public void getRevisionTimestamp() throws Exception { DocumentStore store = new MemoryDocumentStore(); JournalEntry entry = JOURNAL.newDocument(store); Modified: jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalGCTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalGCTest.java?rev=1762477&r1=1762476&r2=1762477&view=diff ============================================================================== --- jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalGCTest.java (original) +++ jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/JournalGCTest.java Tue Sep 27 13:34:26 2016 @@ -28,6 +28,7 @@ import org.junit.Rule; import org.junit.Test; import static org.apache.jackrabbit.oak.plugins.document.Collection.JOURNAL; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -74,4 +75,41 @@ public class JournalGCTest { entry = ns.getDocumentStore().find(JOURNAL, JournalEntry.asId(head)); assertNull(entry); } + + @Test + public void getTailRevision() throws Exception { + Clock c = new Clock.Virtual(); + c.waitUntil(System.currentTimeMillis()); + DocumentNodeStore ns = builderProvider.newBuilder() + .clock(c).setAsyncDelay(0).getNodeStore(); + + JournalGarbageCollector jgc = ns.getJournalGarbageCollector(); + assertEquals(new Revision(0, 0, ns.getClusterId()), jgc.getTailRevision()); + + NodeBuilder builder = ns.getRoot().builder(); + builder.child("foo"); + ns.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY); + ns.runBackgroundOperations(); + + assertEquals(0, jgc.gc(1, 10, TimeUnit.HOURS)); + + // current time, but without the increment done by getTime() + long now = c.getTime() - 1; + Revision tail = new Revision(now - TimeUnit.HOURS.toMillis(1), 0, ns.getClusterId()); + + c.waitUntil(c.getTime() + TimeUnit.MINUTES.toMillis(1)); + assertEquals(tail, jgc.getTailRevision()); + + c.waitUntil(c.getTime() + TimeUnit.HOURS.toMillis(1)); + + // must collect all journal entries. the first created when + // DocumentNodeStore was initialized and the second created + // by the background update + assertEquals(2, jgc.gc(1, 10, TimeUnit.HOURS)); + + // current time, but without the increment done by getTime() + now = c.getTime() - 1; + tail = new Revision(now - TimeUnit.HOURS.toMillis(1), 0, ns.getClusterId()); + assertEquals(tail, jgc.getTailRevision()); + } } Modified: jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/SimpleTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/SimpleTest.java?rev=1762477&r1=1762476&r2=1762477&view=diff ============================================================================== --- jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/SimpleTest.java (original) +++ jackrabbit/oak/branches/1.4/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/SimpleTest.java Tue Sep 27 13:34:26 2016 @@ -16,10 +16,13 @@ */ package org.apache.jackrabbit.oak.plugins.document; +import static org.hamcrest.CoreMatchers.anyOf; +import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -162,7 +165,7 @@ public class SimpleTest { String diff23 = mk.diff(rev2, rev3, "/", 0).trim(); assertEquals("+\"/t3\":{}", diff23); String diff13 = mk.diff(rev1, rev3, "/", 0).trim(); - assertEquals("+\"/t2\":{}+\"/t3\":{}", diff13); + assertThat(diff13, anyOf(equalTo("+\"/t2\":{}+\"/t3\":{}"), equalTo("+\"/t3\":{}+\"/t2\":{}"))); String diff34 = mk.diff(rev3, rev4, "/", 0).trim(); assertEquals("^\"/t3\":{}", diff34); }