diff options
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 { |