summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorA. Jesse Jiryu Davis <jesse@mongodb.com>2020-02-11 22:03:34 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-02-24 02:09:50 +0000
commite433f91f86eb909d8de849798e1fdbd4c98147a5 (patch)
treea1f4610966b9402339c3e3643e58d36ab4b1092c
parente8f1d29de757d41f7d082d5ca1e667d1b8938741 (diff)
downloadmongo-e433f91f86eb909d8de849798e1fdbd4c98147a5.tar.gz
SERVER-46303 Omit configTerm -1 from heartbeats
-rw-r--r--src/mongo/db/repl/repl_set_heartbeat_args_v1.cpp14
-rw-r--r--src/mongo/db/repl/repl_set_heartbeat_args_v1.h4
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp5
-rw-r--r--src/mongo/db/repl/topology_coordinator.cpp5
-rw-r--r--src/mongo/db/repl/topology_coordinator_v1_test.cpp29
5 files changed, 44 insertions, 13 deletions
diff --git a/src/mongo/db/repl/repl_set_heartbeat_args_v1.cpp b/src/mongo/db/repl/repl_set_heartbeat_args_v1.cpp
index 57f85aa58f9..05423e1b538 100644
--- a/src/mongo/db/repl/repl_set_heartbeat_args_v1.cpp
+++ b/src/mongo/db/repl/repl_set_heartbeat_args_v1.cpp
@@ -159,25 +159,27 @@ void ReplSetHeartbeatArgsV1::setCheckEmpty() {
_checkEmpty = true;
}
-BSONObj ReplSetHeartbeatArgsV1::toBSON(bool omitConfigTerm) const {
+BSONObj ReplSetHeartbeatArgsV1::toBSON() const {
invariant(isInitialized());
BSONObjBuilder builder;
- addToBSON(&builder, omitConfigTerm);
+ addToBSON(&builder);
return builder.obj();
}
-void ReplSetHeartbeatArgsV1::addToBSON(BSONObjBuilder* builder, bool omitConfigTerm) const {
+void ReplSetHeartbeatArgsV1::addToBSON(BSONObjBuilder* builder) const {
builder->append(kSetNameFieldName, _setName);
if (_checkEmpty) {
builder->append(kCheckEmptyFieldName, _checkEmpty);
}
builder->appendIntOrLL(kConfigVersionFieldName, _configVersion);
- // Only attach the term field if we are fully upgraded to 4.4, since 4.2 nodes won't be able to
- // parse it.
+ // The configTerm field is new in 4.4 and cannot be parsed by MongoDB 4.2. Therefore omit it if
+ // we have a 4.2-style replica set config with no "term". This permits us to downgrade by first
+ // removing the replica set config's term, then downgrading to 4.2.
+ // TODO (SERVER-46288): Don't check FCV.
if (serverGlobalParams.featureCompatibility.isVersionInitialized() &&
serverGlobalParams.featureCompatibility.getVersion() ==
ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo44 &&
- !omitConfigTerm) {
+ _configTerm != OpTime::kUninitializedTerm) {
builder->appendIntOrLL(kConfigTermFieldName, _configTerm);
}
if (_hasHeartbeatVersion) {
diff --git a/src/mongo/db/repl/repl_set_heartbeat_args_v1.h b/src/mongo/db/repl/repl_set_heartbeat_args_v1.h
index f183a22072a..9b15f89750d 100644
--- a/src/mongo/db/repl/repl_set_heartbeat_args_v1.h
+++ b/src/mongo/db/repl/repl_set_heartbeat_args_v1.h
@@ -152,9 +152,9 @@ public:
* Should only be called if the mandatory fields have been set.
* Optional fields are only included if they have been set.
*/
- BSONObj toBSON(bool omitConfigTerm = false) const;
+ BSONObj toBSON() const;
- void addToBSON(BSONObjBuilder* builder, bool omitConfigTerm) const;
+ void addToBSON(BSONObjBuilder* builder) const;
private:
// look at the body of the isInitialized() function to see which fields are mandatory
diff --git a/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp b/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp
index 4a8c1ce7721..3961da51162 100644
--- a/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp
@@ -105,10 +105,7 @@ void ReplicationCoordinatorImpl::_doMemberHeartbeat(executor::TaskExecutor::Call
Milliseconds timeout(0);
const std::pair<ReplSetHeartbeatArgsV1, Milliseconds> hbRequest =
_topCoord->prepareHeartbeatRequestV1(now, _settings.ourSetName(), target);
- // Omit config term from all heartbeat requests sent by arbiter, since it cannot be parsed by
- // 4.2 nodes and arbiters do not respect FCV setting.
- bool omitConfigTerm = _getMemberState_inlock().arbiter();
- heartbeatObj = hbRequest.first.toBSON(omitConfigTerm);
+ heartbeatObj = hbRequest.first.toBSON();
timeout = hbRequest.second;
const RemoteCommandRequest request(
diff --git a/src/mongo/db/repl/topology_coordinator.cpp b/src/mongo/db/repl/topology_coordinator.cpp
index c48c7df9595..5e307efaaaa 100644
--- a/src/mongo/db/repl/topology_coordinator.cpp
+++ b/src/mongo/db/repl/topology_coordinator.cpp
@@ -754,7 +754,10 @@ std::pair<ReplSetHeartbeatArgsV1, Milliseconds> TopologyCoordinator::prepareHear
if (_rsConfig.isInitialized()) {
hbArgs.setSetName(_rsConfig.getReplSetName());
hbArgs.setConfigVersion(_rsConfig.getConfigVersion());
- hbArgs.setConfigTerm(_rsConfig.getConfigTerm());
+ if (_rsConfig.getConfigTerm() != OpTime::kUninitializedTerm) {
+ hbArgs.setConfigTerm(_rsConfig.getConfigTerm());
+ }
+
if (_selfIndex >= 0) {
const MemberConfig& me = _selfConfig();
hbArgs.setSenderId(me.getId().getData());
diff --git a/src/mongo/db/repl/topology_coordinator_v1_test.cpp b/src/mongo/db/repl/topology_coordinator_v1_test.cpp
index a578d50689d..a2fa3adcbd4 100644
--- a/src/mongo/db/repl/topology_coordinator_v1_test.cpp
+++ b/src/mongo/db/repl/topology_coordinator_v1_test.cpp
@@ -2246,6 +2246,35 @@ TEST_F(PrepareHeartbeatResponseV1Test,
ASSERT_EQUALS(HostAndPort("h2"), response.getSyncingTo());
}
+TEST_F(TopoCoordTest, OmitUninitializedConfigTermFromHeartbeat) {
+ // A MongoDB 4.2 replica set config with no term.
+ updateConfig(BSON("_id"
+ << "rs0"
+ << "version" << 1 << "members"
+ << BSON_ARRAY(BSON("_id" << 10 << "host"
+ << "hself")
+ << BSON("_id" << 20 << "host"
+ << "h2"))),
+ 0);
+
+ // A member with this config omits configTerm from heartbeat requests.
+ auto [request, timeout] =
+ getTopoCoord().prepareHeartbeatRequestV1(Date_t(), "rs0", HostAndPort("h2", 27017));
+ (void)timeout; // Unused.
+
+ ASSERT_EQUALS(request.getConfigTerm(), -1);
+ ASSERT_EQUALS(request.getConfigVersion(), 1);
+ ASSERT_FALSE(request.toBSON().hasField("configTerm"_sd));
+
+ // A member with this config omits configTerm from heartbeat responses.
+ ReplSetHeartbeatArgsV1 args;
+ args.setSetName("rs0");
+ args.setSenderId(20);
+ ReplSetHeartbeatResponse response;
+ ASSERT_OK(getTopoCoord().prepareHeartbeatResponseV1(now()++, args, "rs0", &response));
+ ASSERT_FALSE(response.toBSON().hasField("configTerm"_sd));
+}
+
TEST_F(TopoCoordTest, BecomeCandidateWhenBecomingSecondaryInSingleNodeSet) {
ASSERT_TRUE(TopologyCoordinator::Role::kFollower == getTopoCoord().getRole());
ASSERT_EQUALS(MemberState::RS_STARTUP, getTopoCoord().getMemberState().s);