summaryrefslogtreecommitdiff
path: root/src/mongo/db/repl/replication_coordinator_impl_test.cpp
diff options
context:
space:
mode:
authorSiyuan Zhou <siyuan.zhou@mongodb.com>2020-03-03 02:59:14 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-03-03 21:03:46 +0000
commit61865d1617e39506c9e0c9202ba2bb50217c7c1e (patch)
treea0b3be1b78ca0dab022d9faa4b04aa073a7599e5 /src/mongo/db/repl/replication_coordinator_impl_test.cpp
parente79b627b8d4e29b7732ad0229690a1e32e490110 (diff)
downloadmongo-61865d1617e39506c9e0c9202ba2bb50217c7c1e.tar.gz
SERVER-45081 Add a unit test case for awaitable isMaster after stepup and config term increment.
Diffstat (limited to 'src/mongo/db/repl/replication_coordinator_impl_test.cpp')
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_test.cpp108
1 files changed, 108 insertions, 0 deletions
diff --git a/src/mongo/db/repl/replication_coordinator_impl_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_test.cpp
index 5e0f6574ce9..3eed301094a 100644
--- a/src/mongo/db/repl/replication_coordinator_impl_test.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl_test.cpp
@@ -3877,6 +3877,114 @@ TEST_F(ReplCoordTest, AwaitIsMasterResponseReturnsOnElectionWin) {
getIsMasterThread.join();
}
+TEST_F(ReplCoordTest, AwaitIsMasterResponseReturnsOnElectionWinWithReconfig) {
+ // The config has a "term" field, so step-up will increment the config term
+ // via reconfig. As a result, step-up triggers three topology changes.
+ init();
+ assertStartSuccess(BSON("_id"
+ << "mySet"
+ << "version" << 2 << "term" << 0 << "members"
+ << BSON_ARRAY(BSON("host"
+ << "node1:12345"
+ << "_id" << 0)
+ << BSON("host"
+ << "node2:12345"
+ << "_id" << 1))),
+ HostAndPort("node1", 12345));
+
+ // Become secondary.
+ ASSERT_OK(getReplCoord()->setFollowerMode(MemberState::RS_SECONDARY));
+ replCoordSetMyLastAppliedOpTime(OpTimeWithTermOne(100, 1), Date_t() + Seconds(100));
+ replCoordSetMyLastDurableOpTime(OpTimeWithTermOne(100, 1), Date_t() + Seconds(100));
+ ASSERT(getReplCoord()->getMemberState().secondary());
+
+ auto maxAwaitTime = Milliseconds(50000);
+ auto deadline = getNet()->now() + maxAwaitTime;
+
+ auto currentTopologyVersion = getTopoCoord().getTopologyVersion();
+ auto expectedProcessId = currentTopologyVersion.getProcessId();
+ // A topology change should increment the TopologyVersion counter.
+ auto expectedCounter = currentTopologyVersion.getCounter() + 1;
+
+ auto opCtx = makeOperationContext();
+ // Calling isMaster without a TopologyVersion field should return immediately.
+ const auto response =
+ getReplCoord()->awaitIsMasterResponse(opCtx.get(), {}, boost::none, boost::none);
+ ASSERT_FALSE(response->isMaster());
+ ASSERT_TRUE(response->isSecondary());
+ ASSERT_FALSE(response->hasPrimary());
+
+ auto waitForIsMasterFailPoint = globalFailPointRegistry().find("waitForIsMasterResponse");
+ auto hangAfterReconfigFailPoint =
+ globalFailPointRegistry().find("hangAfterReconfigOnDrainComplete");
+
+ auto timesEnteredFailPoint = waitForIsMasterFailPoint->setMode(FailPoint::alwaysOn);
+
+ // awaitIsMasterResponse blocks and waits on a future when the request TopologyVersion equals
+ // the current TopologyVersion of the server.
+ stdx::thread getIsMasterThread([&] {
+ const auto responseAfterElection = getReplCoord()->awaitIsMasterResponse(
+ opCtx.get(), {}, currentTopologyVersion, deadline);
+
+ const auto topologyVersionAfterElection = responseAfterElection->getTopologyVersion();
+ ASSERT_EQUALS(topologyVersionAfterElection->getCounter(), expectedCounter);
+ ASSERT_EQUALS(topologyVersionAfterElection->getProcessId(), expectedProcessId);
+
+ // We expect the server to increment the TopologyVersion and respond to waiting IsMasters
+ // once an election is won even if we have yet to signal drain completion.
+ ASSERT_FALSE(responseAfterElection->isMaster());
+ ASSERT_TRUE(responseAfterElection->isSecondary());
+ ASSERT_TRUE(responseAfterElection->hasPrimary());
+ ASSERT_EQUALS(responseAfterElection->getPrimary().host(), "node1");
+ ASSERT(getReplCoord()->getMemberState().primary());
+
+ // The server TopologyVersion will increment once we finish reconfig.
+ expectedCounter = topologyVersionAfterElection->getCounter() + 1;
+ const auto responseAfterReconfig = getReplCoord()->awaitIsMasterResponse(
+ opCtx.get(), {}, topologyVersionAfterElection, deadline);
+ const auto topologyVersionAfterReconfig = responseAfterReconfig->getTopologyVersion();
+ ASSERT_EQUALS(topologyVersionAfterReconfig->getCounter(), expectedCounter);
+ ASSERT_EQUALS(topologyVersionAfterReconfig->getProcessId(), expectedProcessId);
+
+ ASSERT_FALSE(responseAfterReconfig->isMaster());
+ ASSERT_TRUE(responseAfterReconfig->isSecondary());
+ ASSERT_TRUE(responseAfterReconfig->hasPrimary());
+ ASSERT_EQUALS(responseAfterReconfig->getPrimary().host(), "node1");
+ ASSERT(getReplCoord()->getMemberState().primary());
+
+ hangAfterReconfigFailPoint->setMode(FailPoint::off);
+ // The server TopologyVersion will increment again once we exit drain mode.
+ expectedCounter = topologyVersionAfterReconfig->getCounter() + 1;
+ const auto responseAfterDrainComplete = getReplCoord()->awaitIsMasterResponse(
+ opCtx.get(), {}, topologyVersionAfterReconfig, deadline);
+ const auto topologyVersionAfterDrainComplete =
+ responseAfterDrainComplete->getTopologyVersion();
+ ASSERT_EQUALS(topologyVersionAfterDrainComplete->getCounter(), expectedCounter);
+ ASSERT_EQUALS(topologyVersionAfterDrainComplete->getProcessId(), expectedProcessId);
+
+ ASSERT_TRUE(responseAfterDrainComplete->isMaster());
+ ASSERT_FALSE(responseAfterDrainComplete->isSecondary());
+ ASSERT_TRUE(responseAfterDrainComplete->hasPrimary());
+ ASSERT_EQUALS(responseAfterDrainComplete->getPrimary().host(), "node1");
+ ASSERT(getReplCoord()->getMemberState().primary());
+ });
+
+ // Ensure that awaitIsMasterResponse() is called before finishing the election.
+ waitForIsMasterFailPoint->waitForTimesEntered(timesEnteredFailPoint + 1);
+ auto electionTimeoutWhen = getReplCoord()->getElectionTimeout_forTest();
+ ASSERT_NOT_EQUALS(Date_t(), electionTimeoutWhen);
+ LOGV2(4508104,
+ "Election timeout scheduled at {electionTimeoutWhen} (simulator time)",
+ "electionTimeoutWhen"_attr = electionTimeoutWhen);
+ simulateSuccessfulV1ElectionWithoutExitingDrainMode(electionTimeoutWhen, opCtx.get());
+
+ waitForIsMasterFailPoint->waitForTimesEntered(timesEnteredFailPoint + 2);
+ signalDrainComplete(opCtx.get());
+ ASSERT(getReplCoord()->getApplierState() == ReplicationCoordinator::ApplierState::Stopped);
+
+ getIsMasterThread.join();
+}
+
TEST_F(ReplCoordTest, IsMasterResponseMentionsLackOfReplicaSetConfig) {
start();