diff options
author | Spencer T Brody <spencer@mongodb.com> | 2018-08-28 13:29:13 -0400 |
---|---|---|
committer | Spencer T Brody <spencer@mongodb.com> | 2018-08-30 17:08:03 -0400 |
commit | 0db56f8e29330894a7b24ee2b3f68f8f79e14848 (patch) | |
tree | 53ad5f2071ec08422901a5c245a3cd32e6fb082b /src/mongo/db/repl/replication_coordinator_impl_test.cpp | |
parent | 98fba86b404ddddb8d66f9751817e11a3d732ccd (diff) | |
download | mongo-0db56f8e29330894a7b24ee2b3f68f8f79e14848.tar.gz |
SERVER-36746 Don't erroneously skip drain mode if a stepdown attempt fails.
Diffstat (limited to 'src/mongo/db/repl/replication_coordinator_impl_test.cpp')
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl_test.cpp | 61 |
1 files changed, 61 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 1f12e006783..24202d1de02 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_test.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_test.cpp @@ -1668,6 +1668,67 @@ TEST_F(StepDownTest, StepDownCanCompleteBasedOnReplSetUpdatePositionAlone) { ASSERT_TRUE(repl->getMemberState().secondary()); } +TEST_F(StepDownTest, StepDownFailureRestoresDrainState) { + const auto repl = getReplCoord(); + + OpTimeWithTermOne opTime1(100, 1); + OpTimeWithTermOne opTime2(200, 1); + + repl->setMyLastAppliedOpTime(opTime2); + repl->setMyLastDurableOpTime(opTime2); + + // Secondaries not caught up yet. + ASSERT_OK(repl->setLastAppliedOptime_forTest(1, 1, opTime1)); + ASSERT_OK(repl->setLastAppliedOptime_forTest(1, 2, opTime1)); + + auto electionTimeoutWhen = getReplCoord()->getElectionTimeout_forTest(); + simulateSuccessfulV1ElectionWithoutExitingDrainMode(electionTimeoutWhen); + ASSERT_TRUE(repl->getMemberState().primary()); + ASSERT(repl->getApplierState() == ReplicationCoordinator::ApplierState::Draining); + + { + // We can't take writes yet since we're still in drain mode. + const auto opCtx = makeOperationContext(); + Lock::GlobalLock lock(opCtx.get(), MODE_IX); + ASSERT_FALSE(getReplCoord()->canAcceptWritesForDatabase(opCtx.get(), "admin")); + } + + // Step down where the secondary actually has to catch up before the stepDown can succeed. + auto result = stepDown_nonBlocking(false, Seconds(10), Seconds(60)); + + // Interrupt the ongoing stepdown command so that the stepdown attempt will fail. + { + stdx::lock_guard<Client> lk(*result.first.client.get()); + result.first.opCtx->markKilled(ErrorCodes::Interrupted); + } + + // Ensure that the stepdown command failed. + auto stepDownStatus = *result.second.get(); + ASSERT_NOT_OK(stepDownStatus); + // Which code is returned is racy. + ASSERT(stepDownStatus == ErrorCodes::PrimarySteppedDown || + stepDownStatus == ErrorCodes::Interrupted); + ASSERT_TRUE(getReplCoord()->getMemberState().primary()); + ASSERT(repl->getApplierState() == ReplicationCoordinator::ApplierState::Draining); + + // Ensure that the failed stepdown attempt didn't make us able to take writes since we're still + // in drain mode. + { + const auto opCtx = makeOperationContext(); + Lock::GlobalLock lock(opCtx.get(), MODE_IX); + ASSERT_FALSE(getReplCoord()->canAcceptWritesForDatabase(opCtx.get(), "admin")); + } + + // Now complete drain mode and ensure that we become capable of taking writes. + auto opCtx = makeOperationContext(); + signalDrainComplete(opCtx.get()); + ASSERT(repl->getApplierState() == ReplicationCoordinator::ApplierState::Stopped); + + ASSERT_TRUE(getReplCoord()->getMemberState().primary()); + Lock::GlobalLock lock(opCtx.get(), MODE_IX); + ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase(opCtx.get(), "admin")); +} + class StepDownTestWithUnelectableNode : public StepDownTest { private: void setUp() override { |