Author: mreutegg
Date: Mon May  6 13:14:06 2019
New Revision: 1858808

URL: http://svn.apache.org/viewvc?rev=1858808&view=rev
Log:
OAK-8300: Revision GC may remove previous document without removing reference

Add ignored test

Modified:
    
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java?rev=1858808&r1=1858807&r2=1858808&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
 Mon May  6 13:14:06 2019
@@ -26,6 +26,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
@@ -64,21 +65,25 @@ import com.google.common.collect.Iterato
 import com.google.common.collect.Lists;
 import com.google.common.collect.Queues;
 import com.google.common.collect.Sets;
+import com.google.common.io.Closer;
 import com.google.common.util.concurrent.Atomics;
 import com.mongodb.ReadPreference;
 
 import org.apache.jackrabbit.oak.api.CommitFailedException;
-import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.document.mongo.MongoTestUtils;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.stats.Clock;
 import org.jetbrains.annotations.NotNull;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -98,6 +103,8 @@ public class VersionGarbageCollectorIT {
 
     private ExecutorService execService;
 
+    private Closer closer = Closer.create();
+
     public VersionGarbageCollectorIT(DocumentStoreFixture fixture) {
         this.fixture = fixture;
     }
@@ -142,6 +149,7 @@ public class VersionGarbageCollectorIT {
 
     @After
     public void tearDown() throws Exception {
+        closer.close();
         store.dispose();
         Revision.resetClockToDefault();
         execService.shutdown();
@@ -872,6 +880,96 @@ public class VersionGarbageCollectorIT {
         assertEquals(value, 
store.getRoot().getChildNode("foo").getString("prop"));
     }
 
+    @Ignore("OAK-8300")
+    @Test
+    public void gcOnStaleDocument() throws Exception {
+        assumeTrue(fixture.hasSinglePersistence());
+
+        String nodeName = "foo";
+        Path path = new Path(Path.ROOT, nodeName);
+        String docId = Utils.getIdFromPath(path);
+
+        NodeBuilder builder = store.getRoot().builder();
+        builder.child(nodeName).setProperty("p", -1);
+        merge(store, builder);
+
+        store.runBackgroundOperations();
+
+        for (int i = 0; i < NUM_REVS_THRESHOLD - 1; i++) {
+            builder = store.getRoot().builder();
+            builder.child(nodeName).setProperty("p", i);
+            merge(store, builder);
+        }
+
+        DocumentStore ds2 = fixture.createDocumentStore(2);
+        DocumentNodeStore ns2 = new DocumentMK.Builder().setClusterId(2)
+                .setLeaseCheckMode(LeaseCheckMode.LENIENT)
+                
.clock(clock).setAsyncDelay(0).setDocumentStore(ds2).getNodeStore();
+        closer.register(ns2::dispose);
+
+        VersionGarbageCollector gc = ns2.getVersionGarbageCollector();
+        gc.gc(30, MINUTES);
+
+        CountDownLatch bgOperationsDone = new CountDownLatch(1);
+        // prepare commit that will trigger split
+        Commit c = store.newCommit(cb -> cb.updateProperty(path, "p", "0"),
+                store.getHeadRevision(), null);
+        try {
+            execService.submit(() -> {
+                store.runBackgroundOperations();
+                bgOperationsDone.countDown();
+            });
+            // give the background operations some time to progress
+            // past the check for split operations
+            Thread.sleep(50);
+            c.apply();
+        } finally {
+            store.done(c, false, CommitInfo.EMPTY);
+            store.addSplitCandidate(docId);
+        }
+
+        // pick up the changes performed by first store
+        bgOperationsDone.await();
+        ns2.runBackgroundOperations();
+
+        // read the node /foo from the store that will perform the
+        // revision garbage collection
+        NodeState state = ns2.getRoot().getChildNode(nodeName);
+        assertTrue(state.exists());
+        PropertyState prop = state.getProperty("p");
+        assertNotNull(prop);
+        assertEquals(0L, prop.getValue(Type.LONG).longValue());
+        // must have the corresponding document in the cache now
+        NodeDocument doc = ds2.getIfCached(NODES, docId);
+        assertNotNull(doc);
+        // must not yet have previous documents
+        assertTrue(doc.getPreviousRanges().isEmpty());
+
+        // write something else. this will ensure a journal entry is
+        // pushed on the next background update operation
+        builder = store.getRoot().builder();
+        builder.child("bar");
+        merge(store, builder);
+
+        // trigger the overdue split on 1:/foo
+        store.runBackgroundOperations();
+        ns2.runBackgroundOperations();
+
+        // wait some time and trigger RGC
+        clock.waitUntil(clock.getTime() + HOURS.toMillis(1));
+
+        gc = ns2.getVersionGarbageCollector();
+        VersionGCStats stats = gc.gc(30, MINUTES);
+        assertEquals(1, stats.splitDocGCCount);
+
+        // check how the document looks like, bypassing cache
+        doc = store.getDocumentStore().find(NODES, docId, 0);
+        assertNotNull(doc);
+        assertTrue(doc.getPreviousRanges().isEmpty());
+
+        ns2.dispose();
+    }
+
     private void createTestNode(String name) throws CommitFailedException {
         DocumentStore ds = store.getDocumentStore();
         NodeBuilder builder = store.getRoot().builder();


Reply via email to