Author: mreutegg Date: Fri Sep 13 12:36:28 2019 New Revision: 1866900 URL: http://svn.apache.org/viewvc?rev=1866900&view=rev Log: OAK-8623: Improve collision handling performance
Ignored tests that verify the new expected behaviour Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CollisionTest.java Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CollisionTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CollisionTest.java?rev=1866900&r1=1866899&r2=1866900&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CollisionTest.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CollisionTest.java Fri Sep 13 12:36:28 2019 @@ -19,20 +19,26 @@ package org.apache.jackrabbit.oak.plugin import java.util.concurrent.atomic.AtomicInteger; import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore; 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.NodeBuilder; import org.jetbrains.annotations.NotNull; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES; import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.COLLISIONS; +import static org.apache.jackrabbit.oak.plugins.document.Path.ROOT; import static org.apache.jackrabbit.oak.plugins.document.util.Utils.getIdFromPath; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; public class CollisionTest { @@ -98,12 +104,12 @@ public class CollisionTest { Revision c = ns.newRevision(); UpdateOp op = new UpdateOp(id, true); NodeDocument.setDeleted(op, c, false); - Collision col = new Collision(doc, r1, op, c, ns); + Collision col = newCollision(doc, r1, op, c, ns); assertTrue(col.isConflicting()); // concurrent change op = new UpdateOp(id, false); op.setMapEntry("p", c, "b"); - col = new Collision(doc, r1, op, c, ns); + col = newCollision(doc, r1, op, c, ns); assertTrue(col.isConflicting()); b = ns.getRoot().builder(); @@ -118,17 +124,17 @@ public class CollisionTest { op = new UpdateOp(id, false); op.setDelete(true); NodeDocument.setDeleted(op, c, true); - col = new Collision(doc, r2, op, c, ns); + col = newCollision(doc, r2, op, c, ns); assertTrue(col.isConflicting()); // concurrent conflicting property set op = new UpdateOp(id, false); op.setMapEntry("p", c, "c"); - col = new Collision(doc, r2, op, c, ns); + col = newCollision(doc, r2, op, c, ns); assertTrue(col.isConflicting()); // concurrent non-conflicting property set op = new UpdateOp(id, false); op.setMapEntry("q", c, "a"); - col = new Collision(doc, r2, op, c, ns); + col = newCollision(doc, r2, op, c, ns); assertFalse(col.isConflicting()); b = ns.getRoot().builder(); @@ -143,15 +149,159 @@ public class CollisionTest { op = new UpdateOp(id, false); op.setDelete(true); NodeDocument.setDeleted(op, c, true); - col = new Collision(doc, r3, op, c, ns); + col = newCollision(doc, r3, op, c, ns); assertTrue(col.isConflicting()); // concurrent conflicting property set op = new UpdateOp(id, false); op.setMapEntry("p", c, "d"); - col = new Collision(doc, r3, op, c, ns); + col = newCollision(doc, r3, op, c, ns); assertTrue(col.isConflicting()); } + private static Collision newCollision(@NotNull NodeDocument document, + @NotNull Revision theirRev, + @NotNull UpdateOp ourOp, + @NotNull Revision ourRev, + @NotNull RevisionContext context) { + return new Collision(document, theirRev, ourOp, ourRev, context); + } + + @Ignore + @Test + public void collisionOnOrphanedBranch() throws Exception { + DocumentStore store = new MemoryDocumentStore(); + DocumentNodeStore ns = builderProvider.newBuilder() + .setDocumentStore(store).setAsyncDelay(0) + .setUpdateLimit(10).build(); + + NodeBuilder builder = ns.getRoot().builder(); + // force a branch commit + for (int i = 0; i < 20; i++) { + builder.child("n-" + i).setProperty("p", "v"); + } + ns.dispose(); + + NodeDocument root = store.find(NODES, Utils.getIdFromPath(ROOT)); + assertNotNull(root); + assertThat(root.getLocalBranchCommits(), not(empty())); + + // start it up again + ns = builderProvider.newBuilder() + .setDocumentStore(store).setAsyncDelay(0) + .setUpdateLimit(10).build(); + + root = store.find(NODES, Utils.getIdFromPath(ROOT)); + assertNotNull(root); + // on init the DocumentNodeStore removes orphaned + // branch commit entries on the root document + assertThat(root.getLocalBranchCommits(), empty()); + + // but some changes are still there + Path p = Path.fromString("/n-0"); + NodeDocument doc = store.find(NODES, Utils.getIdFromPath(p)); + assertNotNull(doc); + assertThat(doc.getLocalBranchCommits(), not(empty())); + + builder = ns.getRoot().builder(); + builder.child("n-0"); + merge(ns, builder); + + // must not create a collision marker for a branch commit + // that cannot be merged + assertNoCollisions(store, ROOT); + } + + @Ignore + @Test + public void collisionOnForeignOrphanedBranch() throws Exception { + DocumentStore store = new MemoryDocumentStore(); + DocumentNodeStore ns1 = builderProvider.newBuilder() + .setDocumentStore(store).setAsyncDelay(0) + .setUpdateLimit(10).setClusterId(1).build(); + DocumentNodeStore ns2 = builderProvider.newBuilder() + .setDocumentStore(store).setAsyncDelay(0) + .setUpdateLimit(10).setClusterId(2).build(); + + NodeBuilder builder = ns1.getRoot().builder(); + // force a branch commit + for (int i = 0; i < 20; i++) { + builder.child("n-" + i).setProperty("p", "v"); + } + ns1.dispose(); + + NodeDocument root = store.find(NODES, Utils.getIdFromPath(ROOT)); + assertNotNull(root); + assertThat(root.getLocalBranchCommits(), not(empty())); + + // but some changes are still there + Path p = Path.fromString("/n-0"); + NodeDocument doc = store.find(NODES, Utils.getIdFromPath(p)); + assertNotNull(doc); + assertThat(doc.getLocalBranchCommits(), not(empty())); + + builder = ns2.getRoot().builder(); + builder.child("n-0"); + merge(ns2, builder); + + // must not create a collision marker for a branch commit + // from a clusterId that is inactive + assertNoCollisions(store, ROOT); + } + + @Ignore + @Test + public void collisionOnForeignOrphanedBranchAfterRestart() throws Exception { + DocumentStore store = new MemoryDocumentStore(); + DocumentNodeStore ns1 = builderProvider.newBuilder() + .setDocumentStore(store).setAsyncDelay(0) + .setUpdateLimit(10).setClusterId(1).build(); + DocumentNodeStore ns2 = builderProvider.newBuilder() + .setDocumentStore(store).setAsyncDelay(0) + .setUpdateLimit(10).setClusterId(2).build(); + + NodeBuilder builder = ns1.getRoot().builder(); + // force a branch commit + for (int i = 0; i < 20; i++) { + builder.child("n-" + i).setProperty("p", "v"); + } + ns1.dispose(); + + NodeDocument root = store.find(NODES, Utils.getIdFromPath(ROOT)); + assertNotNull(root); + assertThat(root.getLocalBranchCommits(), not(empty())); + + // start it up again + ns1 = builderProvider.newBuilder() + .setDocumentStore(store).setAsyncDelay(0) + .setUpdateLimit(10).setClusterId(1).build(); + + root = store.find(NODES, Utils.getIdFromPath(ROOT)); + assertNotNull(root); + // on init the DocumentNodeStore removes orphaned + // branch commit entries on the root document + assertThat(root.getLocalBranchCommits(), empty()); + + // but some changes are still there + Path p = Path.fromString("/n-0"); + NodeDocument doc = store.find(NODES, Utils.getIdFromPath(p)); + assertNotNull(doc); + assertThat(doc.getLocalBranchCommits(), not(empty())); + + builder = ns2.getRoot().builder(); + builder.child("n-0"); + merge(ns2, builder); + + // must not create a collision marker for a branch commit + // from a clusterId that is inactive + assertNoCollisions(store, ROOT); + } + + private static void assertNoCollisions(DocumentStore store, Path p) { + NodeDocument doc = store.find(NODES, Utils.getIdFromPath(p)); + assertNotNull(doc); + assertThat(doc.getLocalMap(COLLISIONS).keySet(), empty()); + } + @NotNull private static RevisionVector merge(DocumentNodeStore ns, NodeBuilder nb) throws CommitFailedException {