Author: thomasm
Date: Wed Dec 4 15:26:50 2013
New Revision: 1547822
URL: http://svn.apache.org/r1547822
Log:
OAK-1260 Using multiple cluster nodes can corrupt the data (test cases)
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/ClusterTest2.java
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/AbstractClusterTest.java
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/SimpleTestIT.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/NodeStoreFixture.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java?rev=1547822&r1=1547821&r2=1547822&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/MongoNodeStore.java
Wed Dec 4 15:26:50 2013
@@ -359,7 +359,7 @@ public final class MongoNodeStore
}
@Nonnull
- DocumentStore getDocumentStore() {
+ public DocumentStore getDocumentStore() {
return store;
}
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/ClusterTest2.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/ClusterTest2.java?rev=1547822&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/ClusterTest2.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/ClusterTest2.java
Wed Dec 4 15:26:50 2013
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.mongomk;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.jackrabbit.mk.blobs.MemoryBlobStore;
+import org.junit.Test;
+
+/**
+ * A set of simple cluster tests.
+ */
+public class ClusterTest2 {
+
+ @Test
+ public void twoNodes() throws Exception {
+ MemoryDocumentStore ds = new MemoryDocumentStore();
+ MemoryBlobStore bs = new MemoryBlobStore();
+ MongoMK.Builder builder;
+
+ builder = new MongoMK.Builder();
+ builder.setDocumentStore(ds).setBlobStore(bs);
+ MongoMK mk1 = builder.setClusterId(1).open();
+ builder = new MongoMK.Builder();
+ builder.setDocumentStore(ds).setBlobStore(bs);
+ MongoMK mk2 = builder.setClusterId(2).open();
+
+ mk1.commit("/", "+\"test\":{\"x\": 1}", null, null);
+ mk1.backgroundWrite();
+
+ mk2.backgroundRead();
+ String b1 = mk2.branch(mk2.getHeadRevision());
+ mk2.commit("/", "-\"test\"", b1, null);
+ String b2 = mk2.branch(mk2.getHeadRevision());
+ String b2b = mk2.commit("/", "-\"test\"", b2, null);
+ mk2.merge(b2b, null);
+ mk2.backgroundWrite();
+
+ mk1.backgroundRead();
+ mk1.commit("/", "+\"test\":{\"x\": 1}", null, null);
+ mk1.backgroundWrite();
+
+ mk2.backgroundRead();
+
+ String n1 = mk1.getNodes("/test", mk1.getHeadRevision(), 0, 0, 10,
null);
+ String n2 = mk2.getNodes("/test", mk2.getHeadRevision(), 0, 0, 10,
null);
+
+ // mk1 now sees both changes
+ assertEquals("{\"x\":1,\":childNodeCount\":0}", n1);
+ assertEquals("{\"x\":1,\":childNodeCount\":0}", n2);
+
+ mk1.dispose();
+ mk2.dispose();
+ }
+
+}
Modified:
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java?rev=1547822&r1=1547821&r2=1547822&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java
Wed Dec 4 15:26:50 2013
@@ -44,6 +44,15 @@ import org.junit.runners.Parameterized;
@Ignore("This abstract base class does not have any tests")
public abstract class AbstractRepositoryTest {
+ protected NodeStoreFixture fixture;
+ private NodeStore nodeStore;
+ private Repository repository;
+ private Session adminSession;
+
+ public AbstractRepositoryTest(NodeStoreFixture fixture) {
+ this.fixture = fixture;
+ }
+
@Parameterized.Parameters
public static Collection<Object[]> fixtures() {
Object[][] fixtures = new Object[][] {
@@ -55,17 +64,8 @@ public abstract class AbstractRepository
return Arrays.asList(fixtures);
}
- protected NodeStoreFixture fixture;
- private NodeStore nodeStore = null;
- private Repository repository = null;
- private Session adminSession = null;
-
- public AbstractRepositoryTest(NodeStoreFixture fixture) {
- this.fixture = fixture;
- }
-
@After
- public void logout() throws RepositoryException {
+ public void logout() {
// release session field
if (adminSession != null) {
adminSession.logout();
@@ -78,7 +78,7 @@ public abstract class AbstractRepository
}
}
- protected Repository getRepository() throws RepositoryException {
+ protected Repository getRepository() {
if (repository == null) {
nodeStore = fixture.createNodeStore();
repository = new Jcr(nodeStore).createRepository();
Modified:
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/NodeStoreFixture.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/NodeStoreFixture.java?rev=1547822&r1=1547821&r2=1547822&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/NodeStoreFixture.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/NodeStoreFixture.java
Wed Dec 4 15:26:50 2013
@@ -25,10 +25,13 @@ import org.apache.jackrabbit.mk.core.Mic
import org.apache.jackrabbit.oak.plugins.mongomk.MongoMK;
import org.apache.jackrabbit.oak.kernel.KernelNodeStore;
import org.apache.jackrabbit.oak.plugins.mongomk.MongoNodeStore;
+import org.apache.jackrabbit.oak.plugins.mongomk.util.MongoConnection;
import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore;
import org.apache.jackrabbit.oak.plugins.segment.memory.MemoryStore;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import com.mongodb.DB;
+
/**
* NodeStore fixture for parametrized tests.
*/
@@ -50,6 +53,23 @@ public abstract class NodeStoreFixture {
public NodeStore createNodeStore() {
return new CloseableNodeStore(new MongoMK.Builder().open());
}
+
+ @Override
+ public NodeStore createNodeStore(int clusterNodeId) {
+ String host = "localhost";
+ int port = 27017;
+ String db = "oak";
+ MongoConnection connection;
+ try {
+ connection = new MongoConnection(host, port, db);
+ DB mongoDB = connection.getDB();
+ MongoMK mk = new MongoMK.Builder()
+ .setMongoDB(mongoDB).open();
+ return new CloseableNodeStore(mk);
+ } catch (Exception e) {
+ return null;
+ }
+ }
@Override
public void dispose(NodeStore nodeStore) {
@@ -68,6 +88,22 @@ public abstract class NodeStoreFixture {
public NodeStore createNodeStore() {
return new MongoMK.Builder().getNodeStore();
}
+
+ @Override
+ public NodeStore createNodeStore(int clusterNodeId) {
+ String host = "localhost";
+ int port = 27017;
+ String db = "oak";
+ MongoConnection connection;
+ try {
+ connection = new MongoConnection(host, port, db);
+ DB mongoDB = connection.getDB();
+ return new MongoMK.Builder()
+ .setMongoDB(mongoDB).getNodeStore();
+ } catch (Exception e) {
+ return null;
+ }
+ }
@Override
public void dispose(NodeStore nodeStore) {
@@ -90,6 +126,16 @@ public abstract class NodeStoreFixture {
public abstract NodeStore createNodeStore();
+ /**
+ * Create a new cluster node that is attached to the same backend storage.
+ *
+ * @param clusterNodeId the cluster node id
+ * @return the node store, or null if clustering is not supported
+ */
+ public NodeStore createNodeStore(int clusterNodeId) {
+ return null;
+ }
+
public abstract void dispose(NodeStore nodeStore);
private static class CloseableNodeStore
Added:
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/AbstractClusterTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/AbstractClusterTest.java?rev=1547822&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/AbstractClusterTest.java
(added)
+++
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/AbstractClusterTest.java
Wed Dec 4 15:26:50 2013
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.jcr.cluster;
+
+import java.util.Iterator;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import junit.framework.Assert;
+
+import org.apache.jackrabbit.oak.jcr.Jcr;
+import org.apache.jackrabbit.oak.jcr.NodeStoreFixture;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.After;
+import org.junit.Before;
+
+/**
+ * A base class for MongoMK cluster tests.
+ */
+public class AbstractClusterTest {
+
+ protected NodeStoreFixture fixture = NodeStoreFixture.MONGO_MK;
+ protected NodeStore ns1, ns2;
+ protected Repository r1, r2;
+ protected Session s1, s2;
+
+ @After
+ public void logout() {
+ if (s1 != null) {
+ s1.logout();
+ s1 = null;
+ }
+ if (s2 != null) {
+ s2.logout();
+ s2 = null;
+ }
+ r1 = r2 = null;
+ if (ns1 != null) {
+ fixture.dispose(ns1);
+ }
+ if (ns2 != null) {
+ fixture.dispose(ns2);
+ }
+ }
+
+ @Before
+ public void login() throws RepositoryException {
+ ns1 = fixture.createNodeStore(1);
+ if (ns1 == null) {
+ return;
+ }
+ r1 = new Jcr(ns1).createRepository();
+ s1 = r1.login(new SimpleCredentials("admin", "admin".toCharArray()));
+ ns2 = fixture.createNodeStore(2);
+ r2 = new Jcr(ns2).createRepository();
+ s2 = r2.login(new SimpleCredentials("admin", "admin".toCharArray()));
+ }
+
+ static Iterable<Integer> seconds(final int max) {
+ return new Iterable<Integer>() {
+
+ @Override
+ public Iterator<Integer> iterator() {
+ return new Iterator<Integer>() {
+
+ long start = System.currentTimeMillis();
+ int x;
+
+ @Override
+ public boolean hasNext() {
+ long time = System.currentTimeMillis() - start;
+ if (x > 0 && time >= (max * 1000)) {
+ Assert.fail("Retry loop timed out after " + x +
+ " repetitions and " + time + "
milliseconds");
+ }
+ return true;
+ }
+
+ @Override
+ public Integer next() {
+ hasNext();
+ if (x > 0) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ return x++;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ };
+ }
+
+ };
+ }
+
+}
Added:
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/SimpleTestIT.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/SimpleTestIT.java?rev=1547822&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/SimpleTestIT.java
(added)
+++
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/cluster/SimpleTestIT.java
Wed Dec 4 15:26:50 2013
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.jcr.cluster;
+
+import org.junit.Test;
+
+/**
+ * A simple cluster test.
+ */
+public class SimpleTestIT extends AbstractClusterTest {
+
+ @SuppressWarnings("unused")
+ @Test
+ public void test() throws Exception {
+ if (s1 == null) {
+ return;
+ }
+ if (s1.getRootNode().hasNode("test")) {
+ s1.getRootNode().getNode("test").remove();
+ }
+ s1.getRootNode().addNode("test");
+ s1.save();
+ for (int x : seconds(5)) {
+ s2.refresh(false);
+ if (s2.getRootNode().hasNode("test")) {
+ break;
+ }
+ }
+ s2.getRootNode().getNode("test").remove();
+ s2.save();
+ for (int x : seconds(5)) {
+ s1.refresh(false);
+ if (!s1.getRootNode().hasNode("test")) {
+ break;
+ }
+ }
+ s1.getRootNode().addNode("test");
+ s1.save();
+ for (int x : seconds(5)) {
+ s2.refresh(false);
+ if (s2.getRootNode().hasNode("test")) {
+ break;
+ }
+ }
+ s2.getRootNode().getNode("test").remove();
+ s2.save();
+ }
+
+}