Interesting way for test case scenario construction Marcel ! Chetan Mehrotra
On Wed, Mar 18, 2015 at 10:38 PM, <[email protected]> wrote: > Author: mreutegg > Date: Wed Mar 18 17:08:59 2015 > New Revision: 1667590 > > URL: http://svn.apache.org/r1667590 > Log: > OAK-2420: DocumentNodeStore revision GC may lead to NPE > > Test to reproduce the problem > > Modified: > > jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCDeletionTest.java > > Modified: > jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCDeletionTest.java > URL: > http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCDeletionTest.java?rev=1667590&r1=1667589&r2=1667590&view=diff > > ============================================================================== > --- > jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCDeletionTest.java > (original) > +++ > jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCDeletionTest.java > Wed Mar 18 17:08:59 2015 > @@ -22,20 +22,31 @@ package org.apache.jackrabbit.oak.plugin > import java.util.Collections; > import java.util.Comparator; > import java.util.List; > +import java.util.concurrent.Callable; > +import java.util.concurrent.CountDownLatch; > +import java.util.concurrent.Future; > +import java.util.concurrent.Semaphore; > import java.util.concurrent.TimeUnit; > > import javax.annotation.Nonnull; > > +import org.apache.jackrabbit.oak.api.CommitFailedException; > +import > org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.VersionGCStats; > import > org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore; > 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.junit.After; > import org.junit.Before; > +import org.junit.Ignore; > import org.junit.Test; > > +import static java.util.concurrent.Executors.newSingleThreadExecutor; > import static java.util.concurrent.TimeUnit.HOURS; > +import static java.util.concurrent.TimeUnit.MINUTES; > import static org.junit.Assert.assertEquals; > import static org.junit.Assert.assertNull; > import static org.junit.Assert.fail; > @@ -140,7 +151,7 @@ public class VersionGCDeletionTest { > VersionGarbageCollector gc = store.getVersionGarbageCollector(); > gc.setOverflowToDiskThreshold(100); > > - VersionGarbageCollector.VersionGCStats stats = gc.gc(maxAge * 2, > HOURS); > + VersionGCStats stats = gc.gc(maxAge * 2, HOURS); > assertEquals(noOfDocsToDelete * 2 + 1, stats.deletedDocGCCount); > > > @@ -152,6 +163,88 @@ public class VersionGCDeletionTest { > } > } > > + // OAK-2420 > + @Ignore > + @Test > + public void queryWhileDocsAreRemoved() throws Exception { > + //Baseline the clock > + clock.waitUntil(Revision.getCurrentTimestamp()); > + > + final Thread currentThread = Thread.currentThread(); > + final Semaphore queries = new Semaphore(0); > + final CountDownLatch ready = new CountDownLatch(1); > + MemoryDocumentStore ms = new MemoryDocumentStore() { > + @Override > + public <T extends Document> T find(Collection<T> collection, > + String key) { > + if (Thread.currentThread() != currentThread) { > + ready.countDown(); > + queries.acquireUninterruptibly(); > + } > + return super.find(collection, key); > + } > + }; > + store = new DocumentMK.Builder().clock(clock) > + .setDocumentStore(ms).setAsyncDelay(0).getNodeStore(); > + > + // create nodes > + NodeBuilder builder = store.getRoot().builder(); > + NodeBuilder node = builder.child("node"); > + for (int i = 0; i < 100; i++) { > + node.child("c-" + i); > + } > + merge(store, builder); > + > + clock.waitUntil(clock.getTime() + HOURS.toMillis(1)); > + > + // remove nodes > + builder = store.getRoot().builder(); > + node = builder.child("node"); > + for (int i = 0; i < 90; i++) { > + node.getChildNode("c-" + i).remove(); > + } > + merge(store, builder); > + > + store.runBackgroundOperations(); > + > + clock.waitUntil(clock.getTime() + HOURS.toMillis(1)); > + > + // fill caches > + NodeState n = store.getRoot().getChildNode("node"); > + for (ChildNodeEntry entry : n.getChildNodeEntries()) { > + entry.getName(); > + } > + > + // invalidate the nodeChildren cache only > + store.invalidateNodeChildrenCache(); > + > + Future f = newSingleThreadExecutor().submit(new > Callable<Object>() { > + @Override > + public Object call() throws Exception { > + NodeState n = store.getRoot().getChildNode("node"); > + for (ChildNodeEntry entry : n.getChildNodeEntries()) { > + entry.getName(); > + } > + return null; > + } > + }); > + > + // run GC once the reader thread is collecting documents > + ready.await(); > + VersionGarbageCollector gc = store.getVersionGarbageCollector(); > + VersionGCStats stats = gc.gc(30, MINUTES); > + assertEquals(90, stats.deletedDocGCCount); > + > + queries.release(100); > + > + f.get(); > + } > + > + private void merge(DocumentNodeStore store, NodeBuilder builder) > + throws CommitFailedException { > + store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY); > + } > + > private static class TestDocumentStore extends MemoryDocumentStore { > boolean throwException; > @Override > > >
