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();


Reply via email to