Author: mreutegg
Date: Tue Nov 17 12:49:02 2015
New Revision: 1714773
URL: http://svn.apache.org/viewvc?rev=1714773&view=rev
Log:
OAK-3646: Inconsistent read of hierarchy
Adding test (currently ignored)
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java?rev=1714773&r1=1714772&r2=1714773&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreTest.java
Tue Nov 17 12:49:02 2015
@@ -98,6 +98,7 @@ import org.apache.jackrabbit.oak.spi.sta
import org.apache.jackrabbit.oak.spi.state.NodeStore;
import org.apache.jackrabbit.oak.stats.Clock;
import org.junit.After;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
@@ -1654,6 +1655,76 @@ public class DocumentNodeStoreTest {
assertEquals(clusterId, ns.getClusterId());
}
+ // OAK-3646
+ @Ignore("OAK-3646")
+ @Test
+ public void concurrentChildOperations() throws Exception {
+ Clock clock = new Clock.Virtual();
+ Revision.setClock(clock);
+ MemoryDocumentStore store = new MemoryDocumentStore();
+ DocumentNodeStore ns1 = builderProvider.newBuilder()
+ .setAsyncDelay(0).clock(clock)
+ .setDocumentStore(store).getNodeStore();
+ DocumentNodeStore ns2 = builderProvider.newBuilder()
+ .setAsyncDelay(0).clock(clock)
+ .setDocumentStore(store).getNodeStore();
+
+ // create some children under /foo/bar
+ NodeBuilder b1 = ns1.getRoot().builder();
+ NodeBuilder node = b1.child("foo").child("bar");
+ node.child("child-0");
+ node.child("child-1");
+ node.child("child-2");
+ merge(ns1, b1);
+
+ // make changes visible on both cluster nodes
+ ns1.runBackgroundOperations();
+ ns2.runBackgroundOperations();
+
+ // remove child-0 on cluster node 1
+ b1 = ns1.getRoot().builder();
+ b1.child("foo").child("bar").getChildNode("child-0").remove();
+ merge(ns1, b1);
+
+ // push _lastRev updates to DocumentStore
+ ns1.runBackgroundOperations();
+
+ // remove child-1 on cluster node 2
+ NodeBuilder b2 = ns2.getRoot().builder();
+ b2.child("foo").child("bar").getChildNode("child-1").remove();
+ merge(ns2, b2);
+
+ // on cluster node 2, remove of child-0 is not yet visible
+ List<ChildNodeEntry> children =
Lists.newArrayList(ns2.getRoot().getChildNode("foo").getChildNode("bar").getChildNodeEntries());
+ assertEquals(2, Iterables.size(children));
+ Revision invalidate = null;
+ for (ChildNodeEntry entry : children) {
+ if (entry.getName().equals("child-0")) {
+ invalidate =
asDocumentNodeState(entry.getNodeState()).getRevision();
+ }
+ }
+ assertNotNull(invalidate);
+
+ // this will make changes from cluster node 1 visible
+ ns2.runBackgroundOperations();
+
+ // wait twice the time we remember revision order
+ clock.waitUntil(clock.getTime() + 2 * REMEMBER_REVISION_ORDER_MILLIS);
+ // collect everything older than one hour (time revision order is
remembered)
+ // this will remove child-0 and child-1 doc
+ ns1.getVersionGarbageCollector().gc(REMEMBER_REVISION_ORDER_MILLIS,
TimeUnit.MILLISECONDS);
+
+ // trigger purge of revisions older than one hour in RevisionComparator
+ // this is usually done by the background read operation, but we
+ // do it explicitly here to make sure it really happens in this test
+ ns2.getRevisionComparator().purge(clock.getTime() -
REMEMBER_REVISION_ORDER_MILLIS);
+ // forget cache entry for deleted node
+ ns2.invalidateNodeCache("/foo/bar/child-0", invalidate);
+
+ children =
Lists.newArrayList(ns2.getRoot().getChildNode("foo").getChildNode("bar").getChildNodeEntries());
+ assertEquals(1, Iterables.size(children));
+ }
+
private static boolean backgroundLeaseUpdateThreadRunning(int clusterId) {
String threadName = "DocumentNodeStore lease update thread (" +
clusterId + ")";
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();