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 2020/03/10 13:12:55 UTC

svn commit: r1875041 - /jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/RecoveryTest.java

Author: mreutegg
Date: Tue Mar 10 13:12:55 2020
New Revision: 1875041

URL: http://svn.apache.org/viewvc?rev=1875041&view=rev
Log:
OAK-8944: Missing journal entry on recovery

Add ignored test

Added:
    jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/RecoveryTest.java   (with props)

Added: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/RecoveryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/RecoveryTest.java?rev=1875041&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/RecoveryTest.java (added)
+++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/RecoveryTest.java Tue Mar 10 13:12:55 2020
@@ -0,0 +1,169 @@
+/*
+ * 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.document;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.plugins.migration.NodeStateTestUtils;
+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.spi.state.NodeStore;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.apache.jackrabbit.oak.plugins.document.TestUtils.disposeQuietly;
+import static org.apache.jackrabbit.oak.plugins.document.TestUtils.merge;
+import static org.apache.jackrabbit.oak.plugins.migration.NodeStateTestUtils.assertExists;
+import static org.apache.jackrabbit.oak.plugins.migration.NodeStateTestUtils.assertMissing;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class RecoveryTest extends AbstractTwoNodeTest {
+
+    private FailingDocumentStore fds1;
+
+    public RecoveryTest(DocumentStoreFixture fixture) {
+        super(fixture);
+    }
+
+    @Override
+    protected DocumentStore customize(DocumentStore store) {
+        // wrap the first store with a FailingDocumentStore
+        FailingDocumentStore fds = new FailingDocumentStore(store);
+        if (fds1 == null) {
+            fds1 = fds;
+        }
+        return fds;
+    }
+
+    @Ignore
+    @Test
+    public void recoverOther() throws Exception {
+        NodeBuilder builder = ds1.getRoot().builder();
+        builder.child("node");
+        builder.child("parent").child("test").child("c1");
+        builder.child("parent").child("other").child("c1");
+        merge(ds1, builder);
+        ds1.runBackgroundOperations();
+        ds2.runBackgroundOperations();
+        builder = ds2.getRoot().builder();
+        builder.child("node").setProperty("p", 1);
+        builder.child("parent").child("test").child("c2");
+        builder.child("parent").child("other").child("c2");
+        merge(ds2, builder);
+        ds2.runBackgroundOperations();
+        ds1.runBackgroundOperations();
+
+        waitOneMinute();
+        ds1.runBackgroundOperations();
+        ds2.runBackgroundOperations();
+        ds1.renewClusterIdLease();
+        ds2.renewClusterIdLease();
+
+        // apply several changes without background update
+        // and then simulate a killed process
+        builder = ds1.getRoot().builder();
+        builder.child("node").setProperty("p", 2);
+        builder.child("parent").child("test").child("c1").remove();
+        builder.child("parent").child("test").child("c3");
+        merge(ds1, builder);
+
+        builder = ds1.getRoot().builder();
+        builder.child("parent").child("other").child("c3");
+        merge(ds1, builder);
+
+        builder = ds1.getRoot().builder();
+        builder.child("node").setProperty("p", 3);
+        merge(ds1, builder);
+
+        builder = ds1.getRoot().builder();
+        builder.child("node").child("wont-make-it");
+
+        // simulate crashed process
+        fds1.fail().after(1).eternally();
+        try {
+            merge(ds1, builder);
+            fail("merge must fail");
+        } catch (CommitFailedException e) {
+            // expected
+        }
+        disposeQuietly(ds1);
+
+        waitOneMinute();
+        ds2.runBackgroundOperations();
+        ds2.renewClusterIdLease();
+        listChildren(ds2, "/");
+        listChildren(ds2, "/parent");
+        listChildren(ds2, "/parent/test");
+
+        builder = ds2.getRoot().builder();
+        builder.child("node").setProperty("q", 1);
+        merge(ds2, builder);
+
+        waitOneMinute();
+        ds2.runBackgroundOperations();
+        ds2.renewClusterIdLease();
+
+        waitOneMinute();
+        ds2.runBackgroundOperations();
+        ds2.renewClusterIdLease();
+
+        // before recovery, changes by ds1 are not visible
+        NodeState root = ds2.getRoot();
+        assertExists(root, "parent/test/c1");
+        assertMissing(root, "parent/test/c3");
+        assertMissing(root, "node/wont-make-it");
+
+        // clusterId 1 lease expired
+        assertTrue(ds2.getLastRevRecoveryAgent().isRecoveryNeeded());
+        int numDocs = ds2.getLastRevRecoveryAgent().recover(1);
+        assertThat(numDocs, equalTo(4));
+
+        // still not visible because background read did not yet happen
+        NodeState root1 = ds2.getRoot();
+        assertExists(root1, "parent/test/c1");
+        assertMissing(root1, "parent/test/c3");
+        assertMissing(root1, "node/wont-make-it");
+
+        ds2.runBackgroundOperations();
+        // now changes must be visible
+        NodeState root2 = ds2.getRoot();
+
+        assertMissing(root2, "parent/test/c1");
+        assertExists(root2, "parent/test/c3");
+        assertMissing(root2, "node/wont-make-it");
+
+        TrackingDiff diff = new TrackingDiff();
+        root2.compareAgainstBaseState(root1, diff);
+        assertThat(diff.modified, containsInAnyOrder("/parent", "/parent/other", "/parent/test", "/node"));
+        assertThat(diff.added, containsInAnyOrder("/parent/test/c3", "/parent/other/c3"));
+        assertThat(diff.deleted, containsInAnyOrder("/parent/test/c1"));
+    }
+
+    private void waitOneMinute() throws Exception {
+        clock.waitUntil(clock.getTime() + TimeUnit.MINUTES.toMillis(1));
+    }
+
+    private static void listChildren(NodeStore ns, String path) {
+        NodeStateTestUtils.getNodeState(ns.getRoot(), path).getChildNodeEntries().forEach(ChildNodeEntry::getNodeState);
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/RecoveryTest.java
------------------------------------------------------------------------------
    svn:eol-style = native