summaryrefslogtreecommitdiff
path: root/src/mongo/db/repl/replication_coordinator_impl_test.cpp
diff options
context:
space:
mode:
authorSpencer T Brody <spencer@mongodb.com>2018-08-28 13:29:13 -0400
committerSpencer T Brody <spencer@mongodb.com>2018-08-30 17:08:03 -0400
commit0db56f8e29330894a7b24ee2b3f68f8f79e14848 (patch)
tree53ad5f2071ec08422901a5c245a3cd32e6fb082b /src/mongo/db/repl/replication_coordinator_impl_test.cpp
parent98fba86b404ddddb8d66f9751817e11a3d732ccd (diff)
downloadmongo-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.cpp61
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 {