summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorA. Jesse Jiryu Davis <jesse@mongodb.com>2020-03-26 21:46:52 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-03-27 03:27:51 +0000
commit0ebbedb45382c922d4873c2689d67fd80a735e5c (patch)
treec69445db7b17a3a1ea2ad58271c95a165d24a263
parentc60e8ce46af84d273648bc49c495e44f08ea1fb0 (diff)
downloadmongo-0ebbedb45382c922d4873c2689d67fd80a735e5c.tar.gz
SERVER-47097 Add ReplSetMetadata.isPrimary
-rw-r--r--src/mongo/db/repl/README.md1
-rw-r--r--src/mongo/db/repl/check_quorum_for_config_change_test.cpp3
-rw-r--r--src/mongo/db/repl/oplog_fetcher_test.cpp4
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_heartbeat_v1_test.cpp17
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_test.cpp92
-rw-r--r--src/mongo/db/repl/topology_coordinator.cpp3
-rw-r--r--src/mongo/db/repl/topology_coordinator_v1_test.cpp6
-rw-r--r--src/mongo/rpc/metadata/repl_set_metadata.cpp30
-rw-r--r--src/mongo/rpc/metadata/repl_set_metadata.h16
-rw-r--r--src/mongo/rpc/metadata/repl_set_metadata_test.cpp58
-rw-r--r--src/mongo/s/catalog/sharding_catalog_test.cpp12
11 files changed, 158 insertions, 84 deletions
diff --git a/src/mongo/db/repl/README.md b/src/mongo/db/repl/README.md
index 20085f7a6ae..a3ffc9afad9 100644
--- a/src/mongo/db/repl/README.md
+++ b/src/mongo/db/repl/README.md
@@ -320,6 +320,7 @@ It then creates a `ReplSetHeartbeatResponse` object. This includes:
7. The state of the receiving node
8. The receiving node's sync source
9. The receiving node's `ReplicaSetConfig` version
+10. Whether the receiving node is primary
When the sending node receives the response to the heartbeat, it first processes its
`ReplSetMetadata` like before.
diff --git a/src/mongo/db/repl/check_quorum_for_config_change_test.cpp b/src/mongo/db/repl/check_quorum_for_config_change_test.cpp
index d592d3fbfba..e84b1881961 100644
--- a/src/mongo/db/repl/check_quorum_for_config_change_test.cpp
+++ b/src/mongo/db/repl/check_quorum_for_config_change_test.cpp
@@ -449,7 +449,8 @@ TEST_F(CheckQuorumForInitiate, QuorumCheckFailedDueToSetIdMismatch) {
rsConfig.getConfigVersion(),
unexpectedId,
rpc::ReplSetMetadata::kNoPrimary,
- -1);
+ -1,
+ false);
BSONObjBuilder bob;
uassertStatusOK(metadata.writeToMetadata(&bob));
diff --git a/src/mongo/db/repl/oplog_fetcher_test.cpp b/src/mongo/db/repl/oplog_fetcher_test.cpp
index ab6db9e2358..0309db2f51a 100644
--- a/src/mongo/db/repl/oplog_fetcher_test.cpp
+++ b/src/mongo/db/repl/oplog_fetcher_test.cpp
@@ -335,8 +335,8 @@ const Date_t OplogFetcherTest::staleWallTime = Date_t() + Seconds(staleOpTime.ge
const rpc::OplogQueryMetadata OplogFetcherTest::staleOqMetadata = rpc::OplogQueryMetadata(
{staleOpTime, staleWallTime}, staleOpTime, rbid, primaryIndex, syncSourceIndex);
-const rpc::ReplSetMetadata OplogFetcherTest::replSetMetadata =
- rpc::ReplSetMetadata(1, OpTimeAndWallTime(), OpTime(), 1, OID(), primaryIndex, syncSourceIndex);
+const rpc::ReplSetMetadata OplogFetcherTest::replSetMetadata = rpc::ReplSetMetadata(
+ 1, OpTimeAndWallTime(), OpTime(), 1, OID(), primaryIndex, syncSourceIndex, false);
void OplogFetcherTest::setUp() {
executor::ThreadPoolExecutorTest::setUp();
diff --git a/src/mongo/db/repl/replication_coordinator_impl_heartbeat_v1_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_heartbeat_v1_test.cpp
index c8bb9b6c08c..b497d407730 100644
--- a/src/mongo/db/repl/replication_coordinator_impl_heartbeat_v1_test.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl_heartbeat_v1_test.cpp
@@ -786,7 +786,8 @@ TEST_F(ReplCoordHBV1Test, IgnoreTheContentsOfMetadataWhenItsReplicaSetIdDoesNotM
rsConfig.getConfigVersion(),
unexpectedId,
1,
- -1);
+ -1,
+ true);
uassertStatusOK(metadata.writeToMetadata(&responseBuilder));
heartbeatResponse = makeResponseStatus(responseBuilder.obj());
@@ -869,9 +870,10 @@ TEST_F(ReplCoordHBV1Test,
{commitPoint, Date_t() + Seconds(commitPoint.getSecs())}, // committed OpTime
commitPoint, // visibleOpTime
config.getConfigVersion(),
- {}, // replset id
- 1, // currentPrimaryIndex,
- 1); // currentSyncSourceIndex
+ {}, // replset id
+ 1, // currentPrimaryIndex,
+ 1, // currentSyncSourceIndex
+ true); // isPrimary
auto net = getNet();
BSONObjBuilder responseBuilder;
@@ -944,9 +946,10 @@ TEST_F(ReplCoordHBV1Test, LastCommittedOpTimeOnlyUpdatesFromHeartbeatIfNotInStar
{commitPoint, Date_t() + Seconds(commitPoint.getSecs())}, // committed OpTime
commitPoint, // visibleOpTime
config.getConfigVersion(),
- {}, // replset id
- 1, // currentPrimaryIndex,
- 1); // currentSyncSourceIndex
+ {}, // replset id
+ 1, // currentPrimaryIndex,
+ 1, // currentSyncSourceIndex
+ true); // isPrimary
auto net = getNet();
BSONObjBuilder responseBuilder;
diff --git a/src/mongo/db/repl/replication_coordinator_impl_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_test.cpp
index f2f79e2c07b..aff27217a52 100644
--- a/src/mongo/db/repl/replication_coordinator_impl_test.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl_test.cpp
@@ -5645,12 +5645,12 @@ TEST_F(ReplCoordTest, DoNotIgnoreTheContentsOfMetadataWhenItsConfigVersionDoesNo
// lower configVersion
auto lowerConfigVersion = 1;
StatusWith<rpc::ReplSetMetadata> metadata = rpc::ReplSetMetadata::readFromMetadata(BSON(
- rpc::kReplSetMetadataFieldName
- << BSON("lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 2)
- << "lastCommittedWall" << Date_t() + Seconds(100)
- << "lastOpVisible" << BSON("ts" << Timestamp(10, 0) << "t" << 2)
- << "configVersion" << lowerConfigVersion << "primaryIndex" << 2
- << "term" << 2 << "syncSourceIndex" << 1)));
+ rpc::kReplSetMetadataFieldName << BSON(
+ "lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 2) << "lastCommittedWall"
+ << Date_t() + Seconds(100) << "lastOpVisible"
+ << BSON("ts" << Timestamp(10, 0) << "t" << 2) << "configVersion"
+ << lowerConfigVersion << "primaryIndex" << 2 << "term" << 2
+ << "syncSourceIndex" << 1 << "isPrimary" << true)));
getReplCoord()->processReplSetMetadata(metadata.getValue());
// term should advance
ASSERT_EQUALS(2, getReplCoord()->getTerm());
@@ -5658,12 +5658,12 @@ TEST_F(ReplCoordTest, DoNotIgnoreTheContentsOfMetadataWhenItsConfigVersionDoesNo
// higher configVersion
auto higherConfigVersion = 100;
StatusWith<rpc::ReplSetMetadata> metadata2 = rpc::ReplSetMetadata::readFromMetadata(BSON(
- rpc::kReplSetMetadataFieldName
- << BSON("lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 2)
- << "lastCommittedWall" << Date_t() + Seconds(100)
- << "lastOpVisible" << BSON("ts" << Timestamp(10, 0) << "t" << 2)
- << "configVersion" << higherConfigVersion << "primaryIndex" << 2
- << "term" << 2 << "syncSourceIndex" << 1)));
+ rpc::kReplSetMetadataFieldName << BSON(
+ "lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 2) << "lastCommittedWall"
+ << Date_t() + Seconds(100) << "lastOpVisible"
+ << BSON("ts" << Timestamp(10, 0) << "t" << 2) << "configVersion"
+ << higherConfigVersion << "primaryIndex" << 2 << "term" << 2
+ << "syncSourceIndex" << 1 << "isPrimary" << true)));
getReplCoord()->processReplSetMetadata(metadata2.getValue());
// term should advance
ASSERT_EQUALS(2, getReplCoord()->getTerm());
@@ -5733,11 +5733,12 @@ TEST_F(ReplCoordTest, UpdateTermWhenTheTermFromMetadataIsNewerButNeverUpdateCurr
// higher term, should change
StatusWith<rpc::ReplSetMetadata> metadata = rpc::ReplSetMetadata::readFromMetadata(BSON(
- rpc::kReplSetMetadataFieldName << BSON(
- "lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 3) << "lastCommittedWall"
- << Date_t() + Seconds(100) << "lastOpVisible"
- << BSON("ts" << Timestamp(10, 0) << "t" << 3) << "configVersion" << 2
- << "primaryIndex" << 2 << "term" << 3 << "syncSourceIndex" << 1)));
+ rpc::kReplSetMetadataFieldName
+ << BSON("lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 3)
+ << "lastCommittedWall" << Date_t() + Seconds(100)
+ << "lastOpVisible" << BSON("ts" << Timestamp(10, 0) << "t" << 3)
+ << "configVersion" << 2 << "primaryIndex" << 2 << "term" << 3
+ << "syncSourceIndex" << 1 << "isPrimary" << true)));
getReplCoord()->processReplSetMetadata(metadata.getValue());
ASSERT_EQUALS(3, getReplCoord()->getTerm());
ASSERT_EQUALS(-1, getTopoCoord().getCurrentPrimaryIndex());
@@ -5745,11 +5746,12 @@ TEST_F(ReplCoordTest, UpdateTermWhenTheTermFromMetadataIsNewerButNeverUpdateCurr
// lower term, should not change
StatusWith<rpc::ReplSetMetadata> metadata2 = rpc::ReplSetMetadata::readFromMetadata(BSON(
- rpc::kReplSetMetadataFieldName << BSON(
- "lastOpCommitted" << BSON("ts" << Timestamp(11, 0) << "t" << 3) << "lastCommittedWall"
- << Date_t() + Seconds(100) << "lastOpVisible"
- << BSON("ts" << Timestamp(11, 0) << "t" << 3) << "configVersion" << 2
- << "primaryIndex" << 1 << "term" << 2 << "syncSourceIndex" << 1)));
+ rpc::kReplSetMetadataFieldName
+ << BSON("lastOpCommitted" << BSON("ts" << Timestamp(11, 0) << "t" << 3)
+ << "lastCommittedWall" << Date_t() + Seconds(100)
+ << "lastOpVisible" << BSON("ts" << Timestamp(11, 0) << "t" << 3)
+ << "configVersion" << 2 << "primaryIndex" << 1 << "term" << 2
+ << "syncSourceIndex" << 1 << "isPrimary" << true)));
getReplCoord()->processReplSetMetadata(metadata2.getValue());
ASSERT_EQUALS(3, getReplCoord()->getTerm());
ASSERT_EQUALS(-1, getTopoCoord().getCurrentPrimaryIndex());
@@ -5757,11 +5759,12 @@ TEST_F(ReplCoordTest, UpdateTermWhenTheTermFromMetadataIsNewerButNeverUpdateCurr
// same term, should not change
StatusWith<rpc::ReplSetMetadata> metadata3 = rpc::ReplSetMetadata::readFromMetadata(BSON(
- rpc::kReplSetMetadataFieldName << BSON(
- "lastOpCommitted" << BSON("ts" << Timestamp(11, 0) << "t" << 3) << "lastCommittedWall"
- << Date_t() + Seconds(100) << "lastOpVisible"
- << BSON("ts" << Timestamp(11, 0) << "t" << 3) << "configVersion" << 2
- << "primaryIndex" << 1 << "term" << 3 << "syncSourceIndex" << 1)));
+ rpc::kReplSetMetadataFieldName
+ << BSON("lastOpCommitted" << BSON("ts" << Timestamp(11, 0) << "t" << 3)
+ << "lastCommittedWall" << Date_t() + Seconds(100)
+ << "lastOpVisible" << BSON("ts" << Timestamp(11, 0) << "t" << 3)
+ << "configVersion" << 2 << "primaryIndex" << 1 << "term" << 3
+ << "syncSourceIndex" << 1 << "isPrimary" << true)));
getReplCoord()->processReplSetMetadata(metadata3.getValue());
ASSERT_EQUALS(3, getReplCoord()->getTerm());
ASSERT_EQUALS(-1, getTopoCoord().getCurrentPrimaryIndex());
@@ -5792,12 +5795,12 @@ TEST_F(ReplCoordTest,
// Higher term - should update term but not last committed optime.
StatusWith<rpc::ReplSetMetadata> metadata = rpc::ReplSetMetadata::readFromMetadata(BSON(
- rpc::kReplSetMetadataFieldName
- << BSON("lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 3)
- << "lastCommittedWall" << Date_t() + Seconds(100)
- << "lastOpVisible" << BSON("ts" << Timestamp(10, 0) << "t" << 3)
- << "configVersion" << config.getConfigVersion() << "primaryIndex"
- << 1 << "term" << 3 << "syncSourceIndex" << 1)));
+ rpc::kReplSetMetadataFieldName << BSON(
+ "lastOpCommitted" << BSON("ts" << Timestamp(10, 0) << "t" << 3) << "lastCommittedWall"
+ << Date_t() + Seconds(100) << "lastOpVisible"
+ << BSON("ts" << Timestamp(10, 0) << "t" << 3) << "configVersion"
+ << config.getConfigVersion() << "primaryIndex" << 1 << "term" << 3
+ << "syncSourceIndex" << 1 << "isPrimary" << true)));
BSONObjBuilder responseBuilder;
ASSERT_OK(metadata.getValue().writeToMetadata(&responseBuilder));
@@ -5904,6 +5907,7 @@ TEST_F(ReplCoordTest, PrepareOplogQueryMetadata) {
ASSERT_EQ(replMetadata.getValue().getTerm(), 0);
ASSERT_EQ(replMetadata.getValue().getSyncSourceIndex(), -1);
ASSERT_EQ(replMetadata.getValue().getPrimaryIndex(), -1);
+ ASSERT_EQ(replMetadata.getValue().getIsPrimary(), false);
}
TEST_F(ReplCoordTest, TermAndLastCommittedOpTimeUpdatedFromHeartbeatWhenArbiter) {
@@ -5930,12 +5934,12 @@ TEST_F(ReplCoordTest, TermAndLastCommittedOpTimeUpdatedFromHeartbeatWhenArbiter)
// Higher term - should update term and lastCommittedOpTime since arbiters learn of the
// commit point via heartbeats.
StatusWith<rpc::ReplSetMetadata> metadata = rpc::ReplSetMetadata::readFromMetadata(BSON(
- rpc::kReplSetMetadataFieldName
- << BSON("lastOpCommitted" << BSON("ts" << Timestamp(10, 1) << "t" << 3)
- << "lastCommittedWall" << Date_t() + Seconds(100)
- << "lastOpVisible" << BSON("ts" << Timestamp(10, 1) << "t" << 3)
- << "configVersion" << config.getConfigVersion() << "primaryIndex"
- << 1 << "term" << 3 << "syncSourceIndex" << 1)));
+ rpc::kReplSetMetadataFieldName << BSON(
+ "lastOpCommitted" << BSON("ts" << Timestamp(10, 1) << "t" << 3) << "lastCommittedWall"
+ << Date_t() + Seconds(100) << "lastOpVisible"
+ << BSON("ts" << Timestamp(10, 1) << "t" << 3) << "configVersion"
+ << config.getConfigVersion() << "primaryIndex" << 1 << "term" << 3
+ << "syncSourceIndex" << 1 << "isPrimary" << true)));
BSONObjBuilder responseBuilder;
ASSERT_OK(metadata.getValue().writeToMetadata(&responseBuilder));
@@ -6648,8 +6652,14 @@ TEST_F(ReplCoordTest, UpdatePositionCmdHasMetadata) {
// Set last committed optime via metadata. Pass dummy Date_t to avoid advanceCommitPoint
// invariant.
- rpc::ReplSetMetadata syncSourceMetadata(
- optime.getTerm(), {optime, Date_t() + Seconds(optime.getSecs())}, optime, 1, OID(), -1, 1);
+ rpc::ReplSetMetadata syncSourceMetadata(optime.getTerm(),
+ {optime, Date_t() + Seconds(optime.getSecs())},
+ optime,
+ 1,
+ OID(),
+ -1,
+ 1,
+ false);
getReplCoord()->processReplSetMetadata(syncSourceMetadata);
// Pass dummy Date_t to avoid advanceCommitPoint invariant.
getReplCoord()->advanceCommitPoint({optime, Date_t() + Seconds(optime.getSecs())}, true);
diff --git a/src/mongo/db/repl/topology_coordinator.cpp b/src/mongo/db/repl/topology_coordinator.cpp
index e1ffa9a6339..3116173a018 100644
--- a/src/mongo/db/repl/topology_coordinator.cpp
+++ b/src/mongo/db/repl/topology_coordinator.cpp
@@ -3022,7 +3022,8 @@ rpc::ReplSetMetadata TopologyCoordinator::prepareReplSetMetadata(
_rsConfig.getConfigVersion(),
_rsConfig.getReplicaSetId(),
_currentPrimaryIndex,
- _rsConfig.findMemberIndexByHostAndPort(getSyncSourceAddress()));
+ _rsConfig.findMemberIndexByHostAndPort(getSyncSourceAddress()),
+ _role == Role::kLeader /* isPrimary */);
}
rpc::OplogQueryMetadata TopologyCoordinator::prepareOplogQueryMetadata(int rbid) const {
diff --git a/src/mongo/db/repl/topology_coordinator_v1_test.cpp b/src/mongo/db/repl/topology_coordinator_v1_test.cpp
index 06c47afbfa0..01d658c6cb8 100644
--- a/src/mongo/db/repl/topology_coordinator_v1_test.cpp
+++ b/src/mongo/db/repl/topology_coordinator_v1_test.cpp
@@ -221,13 +221,15 @@ protected:
int syncSourceIndex = -1,
long long configVersion = -1) {
auto configIn = (configVersion != -1) ? configVersion : _currentConfig.getConfigVersion();
+ auto isPrimary = primaryIndex != -1 && _topo->getCurrentPrimaryIndex() == primaryIndex;
return ReplSetMetadata(_topo->getTerm(),
OpTimeAndWallTime(),
visibleOpTime,
configIn,
OID(),
primaryIndex,
- syncSourceIndex);
+ syncSourceIndex,
+ isPrimary);
}
// Make the OplogQueryMetadata coming from sync source.
@@ -4297,7 +4299,7 @@ TEST_F(HeartbeatResponseTestV1, ShouldNotChangeSyncSourceWhenMemberHasYetToHeart
TEST_F(HeartbeatResponseTestV1, ShouldNotChangeSyncSourceWhenMemberNotInConfig) {
// In this test, the TopologyCoordinator should tell us to change sync sources away from
// "host4" since "host4" is absent from the config of version 10.
- ReplSetMetadata replMetadata(0, {OpTime(), Date_t()}, OpTime(), 10, OID(), -1, -1);
+ ReplSetMetadata replMetadata(0, {OpTime(), Date_t()}, OpTime(), 10, OID(), -1, -1, false);
ASSERT_TRUE(getTopoCoord().shouldChangeSyncSource(
HostAndPort("host4"), replMetadata, makeOplogQueryMetadata(), now()));
}
diff --git a/src/mongo/rpc/metadata/repl_set_metadata.cpp b/src/mongo/rpc/metadata/repl_set_metadata.cpp
index 210412eb4c6..9698ded3eb5 100644
--- a/src/mongo/rpc/metadata/repl_set_metadata.cpp
+++ b/src/mongo/rpc/metadata/repl_set_metadata.cpp
@@ -53,6 +53,7 @@ const char kReplicaSetIdFieldName[] = "replicaSetId";
const char kPrimaryIndexFieldName[] = "primaryIndex";
const char kSyncSourceIndexFieldName[] = "syncSourceIndex";
const char kTermFieldName[] = "term";
+const char kIsPrimaryFieldName[] = "isPrimary";
} // unnamed namespace
@@ -64,14 +65,16 @@ ReplSetMetadata::ReplSetMetadata(long long term,
long long configVersion,
OID id,
int currentPrimaryIndex,
- int currentSyncSourceIndex)
+ int currentSyncSourceIndex,
+ boost::optional<bool> isPrimary)
: _lastOpCommitted(std::move(committedOpTime)),
_lastOpVisible(std::move(visibleOpTime)),
_currentTerm(term),
_configVersion(configVersion),
_replicaSetId(id),
_currentPrimaryIndex(currentPrimaryIndex),
- _currentSyncSourceIndex(currentSyncSourceIndex) {}
+ _currentSyncSourceIndex(currentSyncSourceIndex),
+ _isPrimary(isPrimary) {}
StatusWith<ReplSetMetadata> ReplSetMetadata::readFromMetadata(const BSONObj& metadataObj) {
BSONElement replMetadataElement;
@@ -105,6 +108,17 @@ StatusWith<ReplSetMetadata> ReplSetMetadata::readFromMetadata(const BSONObj& met
if (!status.isOK())
return status;
+ // TODO(SERVER-47125): require the isPrimary field.
+ boost::optional<bool> isPrimary;
+ if (replMetadataObj.hasField(kIsPrimaryFieldName)) {
+ bool isPrimaryBool;
+ status = bsonExtractBooleanField(replMetadataObj, kIsPrimaryFieldName, &isPrimaryBool);
+ if (!status.isOK())
+ return status;
+
+ isPrimary = isPrimaryBool;
+ }
+
long long term;
status = bsonExtractIntegerField(replMetadataObj, kTermFieldName, &term);
if (!status.isOK())
@@ -131,8 +145,14 @@ StatusWith<ReplSetMetadata> ReplSetMetadata::readFromMetadata(const BSONObj& met
}
lastOpCommitted.wallTime = wallClockTimeElement.Date();
- return ReplSetMetadata(
- term, lastOpCommitted, lastOpVisible, configVersion, id, primaryIndex, syncSourceIndex);
+ return ReplSetMetadata(term,
+ lastOpCommitted,
+ lastOpVisible,
+ configVersion,
+ id,
+ primaryIndex,
+ syncSourceIndex,
+ isPrimary);
}
Status ReplSetMetadata::writeToMetadata(BSONObjBuilder* builder) const {
@@ -145,6 +165,7 @@ Status ReplSetMetadata::writeToMetadata(BSONObjBuilder* builder) const {
replMetadataBuilder.append(kReplicaSetIdFieldName, _replicaSetId);
replMetadataBuilder.append(kPrimaryIndexFieldName, _currentPrimaryIndex);
replMetadataBuilder.append(kSyncSourceIndexFieldName, _currentSyncSourceIndex);
+ replMetadataBuilder.append(kIsPrimaryFieldName, _isPrimary.get());
replMetadataBuilder.doneFast();
return Status::OK();
@@ -158,6 +179,7 @@ std::string ReplSetMetadata::toString() const {
output << " Term: " << _currentTerm;
output << " Primary Index: " << _currentPrimaryIndex;
output << " Sync Source Index: " << _currentSyncSourceIndex;
+ output << " Is Primary: " << _isPrimary;
output << " Last Op Committed: " << _lastOpCommitted.toString();
output << " Last Op Visible: " << _lastOpVisible.toString();
return output;
diff --git a/src/mongo/rpc/metadata/repl_set_metadata.h b/src/mongo/rpc/metadata/repl_set_metadata.h
index 48b71f8cb69..df2e2ae96b2 100644
--- a/src/mongo/rpc/metadata/repl_set_metadata.h
+++ b/src/mongo/rpc/metadata/repl_set_metadata.h
@@ -59,7 +59,8 @@ public:
long long configVersion,
OID replicaSetId,
int currentPrimaryIndex,
- int currentSyncSourceIndex);
+ int currentSyncSourceIndex,
+ boost::optional<bool> isPrimary);
/**
* format:
@@ -70,7 +71,8 @@ public:
* configVersion: 0,
* replicaSetId: ObjectId("..."), // Only present in certain versions and above.
* primaryIndex: 0,
- * syncSourceIndex: 0
+ * syncSourceIndex: 0,
+ * isPrimary: false // 4.4 and later
* }
*/
static StatusWith<ReplSetMetadata> readFromMetadata(const BSONObj& doc);
@@ -128,6 +130,15 @@ public:
}
/**
+ * Returns true if the sender is primary, false if it isn't, and boost::none if this metadata
+ * is from a pre-4.4 node that doesn't send isPrimary.
+ */
+ // TODO(SERVER-47125): make this a regular bool post-4.4.
+ boost::optional<bool> getIsPrimary() const {
+ return _isPrimary;
+ }
+
+ /**
* Returns the current term from the perspective of the sender.
*/
long long getTerm() const {
@@ -147,6 +158,7 @@ private:
OID _replicaSetId;
int _currentPrimaryIndex = kNoPrimary;
int _currentSyncSourceIndex = -1;
+ boost::optional<bool> _isPrimary;
};
} // namespace rpc
diff --git a/src/mongo/rpc/metadata/repl_set_metadata_test.cpp b/src/mongo/rpc/metadata/repl_set_metadata_test.cpp
index 9775bbf3724..ca89b0f7e64 100644
--- a/src/mongo/rpc/metadata/repl_set_metadata_test.cpp
+++ b/src/mongo/rpc/metadata/repl_set_metadata_test.cpp
@@ -40,17 +40,18 @@ namespace {
using repl::OpTime;
using repl::OpTimeAndWallTime;
+static const OpTime opTime(Timestamp(1234, 100), 5);
+static const OpTime opTime2(Timestamp(7777, 100), 6);
+static const Date_t committedWallTime = Date_t() + Seconds(opTime.getSecs());
+static const ReplSetMetadata metadata(
+ 3, {opTime, committedWallTime}, opTime2, 6, OID("abcdefabcdefabcdefabcdef"), 12, -1, false);
+
TEST(ReplResponseMetadataTest, ReplicaSetIdNotSet) {
- ASSERT_FALSE(
- ReplSetMetadata(3, OpTimeAndWallTime(), OpTime(), 6, OID(), 12, -1).hasReplicaSetId());
+ ASSERT_FALSE(ReplSetMetadata(3, OpTimeAndWallTime(), OpTime(), 6, OID(), 12, -1, false)
+ .hasReplicaSetId());
}
TEST(ReplResponseMetadataTest, Roundtrip) {
- OpTime opTime(Timestamp(1234, 100), 5);
- OpTime opTime2(Timestamp(7777, 100), 6);
- Date_t committedWallTime = Date_t() + Seconds(opTime.getSecs());
- ReplSetMetadata metadata(3, {opTime, committedWallTime}, opTime2, 6, OID::gen(), 12, -1);
-
ASSERT_EQ(opTime, metadata.getLastOpCommitted().opTime);
ASSERT_EQ(committedWallTime, metadata.getLastOpCommitted().wallTime);
ASSERT_EQ(opTime2, metadata.getLastOpVisible());
@@ -59,14 +60,14 @@ TEST(ReplResponseMetadataTest, Roundtrip) {
BSONObjBuilder builder;
metadata.writeToMetadata(&builder).transitional_ignore();
- BSONObj expectedObj(
- BSON(kReplSetMetadataFieldName
- << BSON("term" << 3 << "lastOpCommitted"
- << BSON("ts" << opTime.getTimestamp() << "t" << opTime.getTerm())
- << "lastCommittedWall" << committedWallTime << "lastOpVisible"
- << BSON("ts" << opTime2.getTimestamp() << "t" << opTime2.getTerm())
- << "configVersion" << 6 << "replicaSetId" << metadata.getReplicaSetId()
- << "primaryIndex" << 12 << "syncSourceIndex" << -1)));
+ BSONObj expectedObj(BSON(
+ kReplSetMetadataFieldName << BSON(
+ "term" << 3 << "lastOpCommitted"
+ << BSON("ts" << opTime.getTimestamp() << "t" << opTime.getTerm())
+ << "lastCommittedWall" << committedWallTime << "lastOpVisible"
+ << BSON("ts" << opTime2.getTimestamp() << "t" << opTime2.getTerm())
+ << "configVersion" << 6 << "replicaSetId" << metadata.getReplicaSetId()
+ << "primaryIndex" << 12 << "syncSourceIndex" << -1 << "isPrimary" << false)));
BSONObj serializedObj = builder.obj();
ASSERT_BSONOBJ_EQ(expectedObj, serializedObj);
@@ -89,21 +90,38 @@ TEST(ReplResponseMetadataTest, Roundtrip) {
}
TEST(ReplResponseMetadataTest, MetadataCanBeConstructedWhenMissingOplogQueryMetadataFields) {
- auto id = OID::gen();
- Date_t committedWallTime = Date_t();
BSONObj obj(BSON(kReplSetMetadataFieldName
- << BSON("term" << 3 << "configVersion" << 6 << "replicaSetId" << id
- << "lastCommittedWall" << committedWallTime)));
+ << BSON("term" << 3 << "configVersion" << 6 << "replicaSetId"
+ << metadata.getReplicaSetId() << "lastCommittedWall"
+ << committedWallTime << "isPrimary" << false)));
auto status = ReplSetMetadata::readFromMetadata(obj);
ASSERT_OK(status.getStatus());
const auto& metadata = status.getValue();
ASSERT_EQ(metadata.getConfigVersion(), 6);
- ASSERT_EQ(metadata.getReplicaSetId(), id);
+ ASSERT_EQ(metadata.getReplicaSetId(), metadata.getReplicaSetId());
ASSERT_EQ(metadata.getTerm(), 3);
}
+TEST(ReplResponseMetadataTest, MetadataCanBeConstructedWhenMissingIsPrimary) {
+ // TODO(SERVER-47125): delete this test in 4.6 when we can rely on the isPrimary field.
+ BSONObj obj(
+ BSON(kReplSetMetadataFieldName
+ << BSON("term" << 3 << "lastOpCommitted"
+ << BSON("ts" << opTime.getTimestamp() << "t" << opTime.getTerm())
+ << "lastCommittedWall" << committedWallTime << "lastOpVisible"
+ << BSON("ts" << opTime2.getTimestamp() << "t" << opTime2.getTerm())
+ << "configVersion" << 6 << "replicaSetId" << metadata.getReplicaSetId()
+ << "primaryIndex" << 12 << "syncSourceIndex" << -1)));
+
+ auto status = ReplSetMetadata::readFromMetadata(obj);
+ ASSERT_OK(status.getStatus());
+
+ const auto& metadata = status.getValue();
+ ASSERT_FALSE(metadata.getIsPrimary().is_initialized());
+}
+
} // unnamed namespace
} // namespace rpc
} // namespace mongo
diff --git a/src/mongo/s/catalog/sharding_catalog_test.cpp b/src/mongo/s/catalog/sharding_catalog_test.cpp
index c0c019db581..6905cfa1e2f 100644
--- a/src/mongo/s/catalog/sharding_catalog_test.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_test.cpp
@@ -123,7 +123,8 @@ TEST_F(ShardingCatalogClientTest, GetCollectionExisting) {
100,
OID(),
30,
- -1);
+ -1,
+ true);
BSONObjBuilder builder;
metadata.writeToMetadata(&builder).transitional_ignore();
@@ -196,7 +197,8 @@ TEST_F(ShardingCatalogClientTest, GetDatabaseExisting) {
100,
OID(),
30,
- -1);
+ -1,
+ true);
BSONObjBuilder builder;
metadata.writeToMetadata(&builder).transitional_ignore();
@@ -423,7 +425,8 @@ TEST_F(ShardingCatalogClientTest, GetChunksForNSWithSortAndLimit) {
100,
OID(),
30,
- -1);
+ -1,
+ true);
BSONObjBuilder builder;
metadata.writeToMetadata(&builder).transitional_ignore();
@@ -824,7 +827,8 @@ TEST_F(ShardingCatalogClientTest, GetCollectionsValidResultsNoDb) {
100,
OID(),
30,
- -1);
+ -1,
+ true);
BSONObjBuilder builder;
metadata.writeToMetadata(&builder).transitional_ignore();