summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJudah Schvimer <judah@mongodb.com>2020-04-09 10:28:22 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-04-24 02:01:46 +0000
commit924ac658e95463ea07e8f948c40b33e2ffcbcbe9 (patch)
tree2a89263c65a2c7d607f089dad63d3efc51f29c74
parent3064008dd3830bee2c18cea531fff565e26d47e5 (diff)
downloadmongo-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.cpp11
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_reconfig_test.cpp32
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"