diff options
author | Siyuan Zhou <siyuan.zhou@mongodb.com> | 2020-03-03 02:59:14 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-03-03 21:03:46 +0000 |
commit | 61865d1617e39506c9e0c9202ba2bb50217c7c1e (patch) | |
tree | a0b3be1b78ca0dab022d9faa4b04aa073a7599e5 /src/mongo/db/repl/replication_coordinator_impl_test.cpp | |
parent | e79b627b8d4e29b7732ad0229690a1e32e490110 (diff) | |
download | mongo-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.cpp | 108 |
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(); |