You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by mr...@apache.org on 2016/01/06 08:28:39 UTC
svn commit: r1723241 -
/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MultiDocumentStoreTest.java
Author: mreutegg
Date: Wed Jan 6 07:28:39 2016
New Revision: 1723241
URL: http://svn.apache.org/viewvc?rev=1723241&view=rev
Log:
OAK-3634: RDB/MongoDocumentStore may return stale documents
Add (ignored) tests to reproduce the issue
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MultiDocumentStoreTest.java
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MultiDocumentStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MultiDocumentStoreTest.java?rev=1723241&r1=1723240&r2=1723241&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MultiDocumentStoreTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/MultiDocumentStoreTest.java Wed Jan 6 07:28:39 2016
@@ -24,7 +24,14 @@ import static org.junit.Assert.assertTru
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import org.apache.jackrabbit.oak.plugins.document.util.Utils;
+import org.junit.Ignore;
import org.junit.Test;
public class MultiDocumentStoreTest extends AbstractMultiDocumentStoreTest {
@@ -274,6 +281,159 @@ public class MultiDocumentStoreTest exte
}
}
+ @Ignore("OAK-3634")
+ @Test
+ public void testChangeVisibility() {
+ String id = this.getClass().getName() + ".testChangeVisibility";
+
+ super.ds1.remove(Collection.NODES, id);
+
+ UpdateOp up = new UpdateOp(id, true);
+ up.set("_id", id);
+ up.set("_foo", 0);
+ up.set("_bar", 0);
+ assertTrue(super.ds1.create(Collection.NODES, Collections.singletonList(up)));
+ removeMe.add(id);
+ NodeDocument orig = super.ds1.find(Collection.NODES, id);
+
+ // only run test if DS supports modcount
+ if (orig.getModCount() != null) {
+ long origMc = orig.getModCount().longValue();
+
+ UpdateOp up2 = new UpdateOp(id, false);
+ up2.set("_id", id);
+ up2.increment("_foo", 1L);
+ super.ds2.update(Collection.NODES, Collections.singletonList(id), up2);
+ NodeDocument ds2doc = super.ds2.find(Collection.NODES, id);
+ long ds2Mc = ds2doc.getModCount().longValue();
+ assertTrue("_modCount needs to be > " + origMc + " but was " + ds2Mc, ds2Mc > origMc);
+
+ UpdateOp up1 = new UpdateOp(id, false);
+ up1.set("_id", id);
+ up1.increment("_bar", 1L);
+ super.ds1.update(Collection.NODES, Collections.singletonList(id), up1);
+
+ NodeDocument ds1doc = super.ds1.find(Collection.NODES, id);
+ long ds1Mc = ds1doc.getModCount().longValue();
+ assertTrue("_modCount needs to be > " + ds2Mc + " but was " + ds1Mc, ds1Mc > ds2Mc);
+ }
+ }
+
+ @Ignore("OAK-3634")
+ @Test
+ public void concurrentUpdate() throws Exception {
+ String id = Utils.getIdFromPath("/foo");
+ ds1.remove(Collection.NODES, id);
+ ds2.invalidateCache();
+ removeMe.add(id);
+ UpdateOp op = new UpdateOp(id, true);
+ op.set(Document.ID, id);
+ ds1.create(Collection.NODES, Collections.singletonList(op));
+
+ List<Exception> exceptions = Collections.synchronizedList(new ArrayList<Exception>());
+ List<Thread> threads = Lists.newArrayList();
+ threads.add(new Thread(new Updater(ds1, id, exceptions)));
+ threads.add(new Thread(new Updater(ds2, id, exceptions)));
+ Reader r = new Reader(id, exceptions, ds1, ds2);
+ Thread reader = new Thread(r);
+ for (Thread t : threads) {
+ t.start();
+ }
+ reader.start();
+ for (Thread t : threads) {
+ t.join();
+ }
+ r.terminate();
+ reader.join();
+ for (Exception e : exceptions) {
+ throw e;
+ }
+ }
+
+ private static final class Reader implements Runnable {
+
+ private final String id;
+ private final List<Exception> exceptions;
+ private final List<DocumentStore> stores;
+ private volatile boolean terminate = false;
+ private final Map<Long, NodeDocument> docs = Maps.newHashMap();
+
+ public Reader(String id, List<Exception> exceptions, DocumentStore... stores) {
+ this.id = id;
+ this.exceptions = exceptions;
+ this.stores = Lists.newArrayList(stores);
+ }
+
+ void terminate() {
+ terminate = true;
+ }
+
+ @Override
+ public void run() {
+ Random random = new Random();
+ while (!terminate) {
+ try {
+ DocumentStore ds = stores.get(random.nextInt(stores.size()));
+ NodeDocument d = ds.find(Collection.NODES, id);
+ long modCount = d.getModCount().longValue();
+ NodeDocument seen = docs.get(modCount);
+ if (seen == null) {
+ docs.put(modCount, d);
+ } else {
+ Map<String, Object> expected = getPropertyValues(seen);
+ Map<String, Object> actual = getPropertyValues(d);
+ assertEquals(expected, actual);
+ }
+ Thread.sleep(random.nextInt(1));
+ } catch (AssertionError e) {
+ exceptions.add(new Exception(e.getMessage()));
+ break;
+ } catch (Exception e) {
+ exceptions.add(e);
+ break;
+ }
+ }
+ }
+
+ static Map<String, Object> getPropertyValues(NodeDocument doc) {
+ Map<String, Object> props = Maps.newHashMap();
+ for (String k : doc.keySet()) {
+ if (Utils.isPropertyName(k)) {
+ props.put(k, doc.get(k));
+ }
+ }
+ return props;
+ }
+ }
+
+ private static final class Updater implements Runnable {
+
+ private final DocumentStore ds;
+ private final String id;
+ private final List<Exception> exceptions;
+ private long counter = 0;
+
+ public Updater(DocumentStore ds, String id, List<Exception> exceptions) {
+ this.ds = ds;
+ this.id = id;
+ this.exceptions = exceptions;
+ }
+
+ @Override
+ public void run() {
+ String p = Thread.currentThread().getName();
+ try {
+ for (int i = 0; i < 1000; i++) {
+ UpdateOp op = new UpdateOp(id, false);
+ op.set(p, counter++);
+ ds.update(Collection.NODES, Collections.singletonList(id), op);
+ }
+ } catch (Exception e) {
+ exceptions.add(e);
+ }
+ }
+ }
+
private static long letTimeElapse() {
long ts = System.currentTimeMillis();
while (System.currentTimeMillis() == ts) {