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