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 to...@apache.org on 2016/07/05 11:11:13 UTC

svn commit: r1751441 [2/2] - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/document/ main/java/org/apache/jackrabbit/oak/plugins/document/mongo/ main/java/org/apache/jackrabbit/oak/plugins/document/mongo/replica/ ma...

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/replica/ReplicaSetInfoMock.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/replica/ReplicaSetInfoMock.java?rev=1751441&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/replica/ReplicaSetInfoMock.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/replica/ReplicaSetInfoMock.java Tue Jul  5 11:11:13 2016
@@ -0,0 +1,145 @@
+/*
+ * 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.mongo.replica;
+
+import com.google.common.base.Function;
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import org.apache.jackrabbit.oak.plugins.document.Revision;
+import org.apache.jackrabbit.oak.plugins.document.RevisionVector;
+import org.apache.jackrabbit.oak.stats.Clock;
+import org.bson.BasicBSONObject;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Maps.transformValues;
+import static java.util.Collections.emptyList;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ReplicaSetInfoMock extends ReplicaSetInfo {
+
+    private final Clock clock;
+
+    private Clock mongoClock;
+
+    private ReplicaSetMock replicationSet;
+
+    public static ReplicaSetInfoMock create(Clock clock) {
+        DB db = mock(DB.class);
+        when(db.getName()).thenReturn("oak-db");
+        when(db.getSisterDB(Mockito.anyString())).thenReturn(db);
+        return new ReplicaSetInfoMock(clock, db);
+    }
+
+    private ReplicaSetInfoMock(Clock clock, DB db) {
+        super(clock, db, null, 0, Long.MAX_VALUE, null);
+
+        this.clock = clock;
+        this.mongoClock = clock;
+        this.hiddenMembers = emptyList();
+    }
+
+    public void setMongoClock(Clock mongoClock) {
+        this.mongoClock = mongoClock;
+    }
+
+    public RevisionBuilder addInstance(MemberState state, String name) {
+        if (replicationSet == null) {
+            replicationSet = new ReplicaSetMock();
+        }
+        return replicationSet.addInstance(state, name);
+    }
+
+    public void updateRevisions() {
+        updateReplicaStatus();
+        for (ReplicaSetInfoListener listener : listeners) {
+            listener.gotRootRevisions(rootRevisions);
+        }
+    }
+
+    @Override
+    protected BasicDBObject getReplicaStatus() {
+        BasicDBObject obj = new BasicDBObject();
+        obj.put("date", mongoClock.getDate());
+        obj.put("members", replicationSet.members);
+        return obj;
+    }
+
+    @Override
+    protected Map<String, Timestamped<RevisionVector>> getRootRevisions(Iterable<String> hosts) {
+        return transformValues(replicationSet.memberRevisions,
+                new Function<RevisionBuilder, Timestamped<RevisionVector>>() {
+                    @Override
+                    public Timestamped<RevisionVector> apply(RevisionBuilder input) {
+                        return new Timestamped<RevisionVector>(input.revs, clock.getTime());
+                    }
+                });
+    }
+
+    private class ReplicaSetMock {
+
+        private List<BasicBSONObject> members = new ArrayList<BasicBSONObject>();
+
+        private Map<String, RevisionBuilder> memberRevisions = new HashMap<String, RevisionBuilder>();
+
+        private RevisionBuilder addInstance(MemberState state, String name) {
+            BasicBSONObject member = new BasicBSONObject();
+            member.put("stateStr", state.name());
+            member.put("name", name);
+            members.add(member);
+
+            RevisionBuilder builder = new RevisionBuilder();
+            memberRevisions.put(name, builder);
+            return builder;
+        }
+    }
+
+    public static class RevisionBuilder {
+
+        private RevisionVector revs = new RevisionVector();
+
+        public RevisionBuilder addRevisions(long... timestamps) {
+            for (int i = 0; i < timestamps.length; i++) {
+                addRevision(timestamps[i], 0, i, false);
+            }
+            return this;
+        }
+
+        public RevisionBuilder addRevision(long timestamp, int counter, int clusterId, boolean branch) {
+            Revision rev = new Revision(timestamp, counter, clusterId, branch);
+            revs = revs.update(rev);
+            return this;
+        }
+
+        public RevisionBuilder set(RevisionVector revs) {
+            this.revs = revs;
+            return this;
+        }
+
+        public RevisionVector build() {
+            return revs;
+        }
+    }
+
+}

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/replica/ReplicaSetInfoTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/replica/ReplicaSetInfoTest.java?rev=1751441&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/replica/ReplicaSetInfoTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/replica/ReplicaSetInfoTest.java Tue Jul  5 11:11:13 2016
@@ -0,0 +1,151 @@
+/*
+ * 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.mongo.replica;
+
+import static java.lang.Long.MAX_VALUE;
+import static org.apache.jackrabbit.oak.plugins.document.mongo.replica.ReplicaSetInfo.MemberState.PRIMARY;
+import static org.apache.jackrabbit.oak.plugins.document.mongo.replica.ReplicaSetInfo.MemberState.RECOVERING;
+import static org.apache.jackrabbit.oak.plugins.document.mongo.replica.ReplicaSetInfo.MemberState.SECONDARY;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.jackrabbit.oak.plugins.document.RevisionVector;
+import org.apache.jackrabbit.oak.stats.Clock;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ReplicaSetInfoTest {
+
+    private ReplicaSetInfoMock replica;
+
+    private Clock.Virtual clock;
+
+    @Before
+    public void resetEstimator() {
+        clock = new Clock.Virtual();
+        replica = ReplicaSetInfoMock.create(clock);
+    }
+
+    @Test
+    public void testMinimumRevision() {
+        replica.addInstance(PRIMARY, "mp").addRevisions(20, 18, 19);
+        replica.addInstance(SECONDARY, "m1").addRevisions(20, 18, 3);
+        replica.addInstance(SECONDARY, "m2").addRevisions(20, 1, 17);
+        replica.updateRevisions();
+
+        assertEquals(20, replica.getMinimumRootRevisions().getRevision(0).getTimestamp());
+        assertEquals( 1, replica.getMinimumRootRevisions().getRevision(1).getTimestamp());
+        assertEquals( 3, replica.getMinimumRootRevisions().getRevision(2).getTimestamp());
+
+        clock.waitUntil(38);
+        assertEquals(20, replica.getLag());
+    }
+
+    @Test
+    public void testIsMoreRecentThan() {
+        replica.addInstance(PRIMARY, "mp").addRevisions(15, 21, 22);
+        replica.addInstance(SECONDARY, "m1").addRevisions(10, 21, 11);
+        replica.addInstance(SECONDARY, "m2").addRevisions(15, 14, 13);
+        replica.addInstance(SECONDARY, "m3").addRevisions(14, 13, 22);
+        replica.updateRevisions();
+
+        assertTrue(replica.isMoreRecentThan(lastRev(9, 13, 10)));
+        assertFalse(replica.isMoreRecentThan(lastRev(11, 14, 10)));
+    }
+
+    @Test
+    public void testUnknownStateIsNotSafe() {
+        replica.addInstance(PRIMARY, "mp");
+        replica.addInstance(SECONDARY, "m1").addRevisions(10, 21, 11);
+        replica.addInstance(RECOVERING, "m2");
+        replica.updateRevisions();
+
+        assertNull(replica.getMinimumRootRevisions());
+        assertFalse(replica.isMoreRecentThan(lastRev(1, 1, 1)));
+        assertEquals(MAX_VALUE, replica.getLag());
+    }
+
+    @Test
+    public void testEmptyIsNotSafe() {
+        replica.addInstance(PRIMARY, "m1");
+        replica.updateRevisions();
+
+        assertNull(replica.getMinimumRootRevisions());
+        assertFalse(replica.isMoreRecentThan(lastRev(1, 1, 1)));
+        assertEquals(MAX_VALUE, replica.getLag());
+    }
+
+    @Test
+    public void testOldestNotReplicated() {
+        replica.addInstance(PRIMARY, "mp").addRevisions(10, 30, 30);
+        replica.addInstance(SECONDARY, "m1").addRevisions(10, 5, 30);
+        replica.addInstance(SECONDARY, "m2").addRevisions(2, 30, 30);
+        replica.updateRevisions();
+
+        assertEquals(10, replica.secondariesSafeTimestamp);
+
+        clock.waitUntil(40);
+        assertEquals(30, replica.getLag());
+        clock.waitUntil(50);
+        assertEquals(40, replica.getLag());
+    }
+
+    @Test
+    public void testAllSecondariesUpToDate() {
+        replica.addInstance(PRIMARY, "mp").addRevisions(10, 30, 30);
+        replica.addInstance(SECONDARY, "m1").addRevisions(10, 30, 30);
+        replica.addInstance(SECONDARY, "m2").addRevisions(10, 30, 30);
+
+        long before = clock.getTime();
+        replica.updateRevisions();
+        long after = clock.getTime();
+
+        assertBetween(before, after, replica.secondariesSafeTimestamp);
+    }
+
+    @Test
+    public void testAllSecondariesUpToDateWithTimediff() throws InterruptedException {
+        replica.addInstance(PRIMARY, "mp").addRevisions(10, 30, 30);
+        replica.addInstance(SECONDARY, "m1").addRevisions(10, 30, 30);
+        replica.addInstance(SECONDARY, "m2").addRevisions(10, 30, 30);
+
+        Clock mongoClock = new Clock.Virtual();
+        replica.setMongoClock(mongoClock);
+        mongoClock.waitUntil(100);
+
+        long before = clock.getTime();
+        replica.updateRevisions();
+        long after = clock.getTime();
+
+        assertBetween(before, after, replica.secondariesSafeTimestamp);
+    }
+
+    private static RevisionVector lastRev(long... timestamps) {
+        return new ReplicaSetInfoMock.RevisionBuilder().addRevisions(timestamps).build();
+    }
+
+    private static void assertBetween(long from, long to, long actual) {
+        final String msg = String.format("%d <= %d <= %d", from, actual, to);
+        assertTrue(msg, from <= actual);
+        assertTrue(msg, actual <= to);
+    }
+
+}
\ No newline at end of file