diff options
author | Judah Schvimer <judah@mongodb.com> | 2020-04-09 10:28:22 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-04-24 02:01:46 +0000 |
commit | 924ac658e95463ea07e8f948c40b33e2ffcbcbe9 (patch) | |
tree | 2a89263c65a2c7d607f089dad63d3efc51f29c74 | |
parent | 3064008dd3830bee2c18cea531fff565e26d47e5 (diff) | |
download | mongo-924ac658e95463ea07e8f948c40b33e2ffcbcbe9.tar.gz |
SERVER-47369 doReplSetReconfig should fail during primary drain mode
(cherry picked from commit 437b5f31521e39615553803324fae2b1ddb3b2b8)
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl.cpp | 11 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl_reconfig_test.cpp | 32 |
2 files changed, 38 insertions, 5 deletions
diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index 0da209a79e0..39ab56b224c 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -3253,11 +3253,12 @@ Status ReplicationCoordinatorImpl::doReplSetReconfig(OperationContext* opCtx, invariant(_rsConfig.isInitialized()); - if (!force && !_getMemberState_inlock().primary()) { - return Status(ErrorCodes::NotMaster, - str::stream() - << "replSetReconfig should only be run on PRIMARY, but my state is " - << _getMemberState_inlock().toString()); + if (!force && !_readWriteAbility->canAcceptNonLocalWrites(lk)) { + return Status( + ErrorCodes::NotMaster, + str::stream() + << "replSetReconfig should only be run on a writable PRIMARY. Current state is " + << _getMemberState_inlock().toString()); } auto topCoordTerm = _topCoord->getTerm(); diff --git a/src/mongo/db/repl/replication_coordinator_impl_reconfig_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_reconfig_test.cpp index 6cdc149686d..7df4b9b4d97 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_reconfig_test.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_reconfig_test.cpp @@ -93,6 +93,38 @@ TEST_F(ReplCoordTest, NodeReturnsNotMasterWhenReconfigReceivedWhileSecondary) { ASSERT_TRUE(result.obj().isEmpty()); } +TEST_F(ReplCoordTest, NodeReturnsNotMasterWhenReconfigReceivedWhileInDrainMode) { + init(); + + assertStartSuccess(BSON("_id" + << "mySet" + << "version" << 1 << "members" + << BSON_ARRAY(BSON("_id" << 0 << "host" + << "test1:1234") + << BSON("_id" << 1 << "host" + << "test2:1234")) + << "protocolVersion" << 1), + HostAndPort("test1", 1234)); + replCoordSetMyLastAppliedOpTime(OpTime(Timestamp(100, 1), 0), Date_t() + Seconds(100)); + replCoordSetMyLastDurableOpTime(OpTime(Timestamp(100, 1), 0), Date_t() + Seconds(100)); + ASSERT_OK(getReplCoord()->setFollowerMode(MemberState::RS_SECONDARY)); + ASSERT_TRUE(getReplCoord()->getMemberState().secondary()); + + const auto opCtx = makeOperationContext(); + simulateSuccessfulV1ElectionWithoutExitingDrainMode( + getReplCoord()->getElectionTimeout_forTest(), opCtx.get()); + + ASSERT_EQUALS(1, getReplCoord()->getTerm()); + ASSERT_TRUE(getReplCoord()->getMemberState().primary()); + + BSONObjBuilder result; + ReplSetReconfigArgs args; + args.force = false; + ASSERT_EQUALS(ErrorCodes::NotMaster, + getReplCoord()->processReplSetReconfig(opCtx.get(), args, &result)); + ASSERT_TRUE(result.obj().isEmpty()); +} + TEST_F(ReplCoordTest, NodeReturnsInvalidReplicaSetConfigWhenReconfigReceivedWithInvalidConfig) { // start up, become primary, receive uninitializable config assertStartSuccess(BSON("_id" |