diff options
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl.cpp | 21 | ||||
-rw-r--r-- | src/mongo/db/repl/topology_coordinator.h | 13 | ||||
-rw-r--r-- | src/mongo/db/repl/topology_coordinator_impl.cpp | 18 | ||||
-rw-r--r-- | src/mongo/db/repl/topology_coordinator_impl.h | 5 | ||||
-rw-r--r-- | src/mongo/db/repl/topology_coordinator_impl_test.cpp | 113 | ||||
-rw-r--r-- | src/mongo/db/repl/topology_coordinator_impl_v1_test.cpp | 113 |
6 files changed, 167 insertions, 116 deletions
diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index 5e31e9a77ee..a69feb88e26 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -1871,15 +1871,18 @@ bool ReplicationCoordinatorImpl::prepareOldReplSetUpdatePositionCommand( Status ReplicationCoordinatorImpl::processReplSetGetStatus(BSONObjBuilder* response) { Status result(ErrorCodes::InternalError, "didn't set status in prepareStatusResponse"); - _scheduleWorkAndWaitForCompletion(stdx::bind(&TopologyCoordinator::prepareStatusResponse, - _topCoord.get(), - stdx::placeholders::_1, - _replExecutor.now(), - time(0) - serverGlobalParams.started, - getMyLastAppliedOpTime(), - getLastCommittedOpTime(), - response, - &result)); + _scheduleWorkAndWaitForCompletion( + stdx::bind(&TopologyCoordinator::prepareStatusResponse, + _topCoord.get(), + stdx::placeholders::_1, + TopologyCoordinator::ReplSetStatusArgs{ + _replExecutor.now(), + static_cast<unsigned>(time(0) - serverGlobalParams.started), + getMyLastAppliedOpTime(), + getLastCommittedOpTime(), + getCurrentCommittedSnapshotOpTime()}, + response, + &result)); return result; } diff --git a/src/mongo/db/repl/topology_coordinator.h b/src/mongo/db/repl/topology_coordinator.h index c31ab4f3881..c68bb08eba0 100644 --- a/src/mongo/db/repl/topology_coordinator.h +++ b/src/mongo/db/repl/topology_coordinator.h @@ -244,12 +244,17 @@ public: const OpTime& lastOpDurable, ReplSetHeartbeatResponse* response) = 0; + struct ReplSetStatusArgs { + Date_t now; + unsigned selfUptime; + const OpTime& lastOpApplied; + const OpTime& lastCommittedOpTime; + const OpTime& readConcernMajorityOpTime; + }; + // produce a reply to a status request virtual void prepareStatusResponse(const ReplicationExecutor::CallbackArgs& data, - Date_t now, - unsigned uptime, - const OpTime& lastOpApplied, - const OpTime& lastCommittedOpTime, + const ReplSetStatusArgs& rsStatusArgs, BSONObjBuilder* response, Status* result) = 0; diff --git a/src/mongo/db/repl/topology_coordinator_impl.cpp b/src/mongo/db/repl/topology_coordinator_impl.cpp index ef73d338ef4..b67700251dc 100644 --- a/src/mongo/db/repl/topology_coordinator_impl.cpp +++ b/src/mongo/db/repl/topology_coordinator_impl.cpp @@ -1492,10 +1492,7 @@ const MemberConfig* TopologyCoordinatorImpl::_currentPrimaryMember() const { } void TopologyCoordinatorImpl::prepareStatusResponse(const ReplicationExecutor::CallbackArgs& data, - Date_t now, - unsigned selfUptime, - const OpTime& lastOpApplied, - const OpTime& lastCommittedOpTime, + const ReplSetStatusArgs& rsStatusArgs, BSONObjBuilder* response, Status* result) { if (data.status == ErrorCodes::CallbackCanceled) { @@ -1506,12 +1503,14 @@ void TopologyCoordinatorImpl::prepareStatusResponse(const ReplicationExecutor::C // output for each member vector<BSONObj> membersOut; const MemberState myState = getMemberState(); + const Date_t now = rsStatusArgs.now; + const OpTime& lastOpApplied = rsStatusArgs.lastOpApplied; if (_selfIndex == -1) { // We're REMOVED or have an invalid config response->append("state", static_cast<int>(myState.s)); response->append("stateStr", myState.toString()); - response->append("uptime", selfUptime); + response->append("uptime", rsStatusArgs.selfUptime); if (_rsConfig.getProtocolVersion() == 1) { BSONObjBuilder opTime(response->subobjStart("optime")); @@ -1546,7 +1545,7 @@ void TopologyCoordinatorImpl::prepareStatusResponse(const ReplicationExecutor::C bb.append("health", 1.0); bb.append("state", static_cast<int>(myState.s)); bb.append("stateStr", myState.toString()); - bb.append("uptime", selfUptime); + bb.append("uptime", rsStatusArgs.selfUptime); if (!_selfConfig().isArbiter()) { if (_rsConfig.getProtocolVersion() == 1) { BSONObjBuilder opTime(bb.subobjStart("optime")); @@ -1664,7 +1663,12 @@ void TopologyCoordinatorImpl::prepareStatusResponse(const ReplicationExecutor::C response->append("heartbeatIntervalMillis", durationCount<Milliseconds>(_rsConfig.getHeartbeatInterval())); - lastCommittedOpTime.append(response, "lastCommittedOpTime"); + BSONObjBuilder optimes; + rsStatusArgs.lastCommittedOpTime.append(&optimes, "lastCommittedOpTime"); + if (!rsStatusArgs.readConcernMajorityOpTime.isNull()) { + rsStatusArgs.readConcernMajorityOpTime.append(&optimes, "readConcernMajorityOpTime"); + } + response->append("OpTimes", optimes.obj()); response->append("members", membersOut); *result = Status::OK(); diff --git a/src/mongo/db/repl/topology_coordinator_impl.h b/src/mongo/db/repl/topology_coordinator_impl.h index 9cea2c7e0b6..6e192ae9425 100644 --- a/src/mongo/db/repl/topology_coordinator_impl.h +++ b/src/mongo/db/repl/topology_coordinator_impl.h @@ -192,10 +192,7 @@ public: const OpTime& lastOpDurable, ReplSetHeartbeatResponse* response); virtual void prepareStatusResponse(const ReplicationExecutor::CallbackArgs& data, - Date_t now, - unsigned uptime, - const OpTime& lastOpApplied, - const OpTime& lastCommittedOpTime, + const ReplSetStatusArgs& rsStatusArgs, BSONObjBuilder* response, Status* result); virtual void fillIsMasterForReplSet(IsMasterResponse* response); diff --git a/src/mongo/db/repl/topology_coordinator_impl_test.cpp b/src/mongo/db/repl/topology_coordinator_impl_test.cpp index 3cba188212c..c4888c697bb 100644 --- a/src/mongo/db/repl/topology_coordinator_impl_test.cpp +++ b/src/mongo/db/repl/topology_coordinator_impl_test.cpp @@ -1322,6 +1322,7 @@ TEST_F(TopoCoordTest, ReplSetGetStatus) { Timestamp electionTime(1, 2); OpTime oplogProgress(Timestamp(3, 4), 0); OpTime lastCommittedOpTime(Timestamp(2, 3), -1); + OpTime readConcernMajorityOpTime(Timestamp(4, 5), -1); std::string setName = "mySet"; ReplSetHeartbeatResponse hb; @@ -1369,20 +1370,25 @@ TEST_F(TopoCoordTest, ReplSetGetStatus) { // Now node 0 is down, node 1 is up, and for node 2 we have no heartbeat data yet. BSONObjBuilder statusBuilder; Status resultStatus(ErrorCodes::InternalError, "prepareStatusResponse didn't set result"); - getTopoCoord().prepareStatusResponse(cbData(), - curTime, - durationCount<Seconds>(uptimeSecs), - oplogProgress, - lastCommittedOpTime, - &statusBuilder, - &resultStatus); + getTopoCoord().prepareStatusResponse( + cbData(), + TopologyCoordinator::ReplSetStatusArgs{ + curTime, + static_cast<unsigned>(durationCount<Seconds>(uptimeSecs)), + oplogProgress, + lastCommittedOpTime, + readConcernMajorityOpTime}, + &statusBuilder, + &resultStatus); ASSERT_OK(resultStatus); BSONObj rsStatus = statusBuilder.obj(); // Test results for all non-self members ASSERT_EQUALS(setName, rsStatus["set"].String()); ASSERT_EQUALS(curTime.asInt64(), rsStatus["date"].Date().asInt64()); - ASSERT_EQUALS(lastCommittedOpTime.toBSON(), rsStatus["lastCommittedOpTime"].Obj()); + ASSERT_EQUALS(lastCommittedOpTime.toBSON(), rsStatus["OpTimes"]["lastCommittedOpTime"].Obj()); + ASSERT_EQUALS(readConcernMajorityOpTime.toBSON(), + rsStatus["OpTimes"]["readConcernMajorityOpTime"].Obj()); std::vector<BSONElement> memberArray = rsStatus["members"].Array(); ASSERT_EQUALS(4U, memberArray.size()); BSONObj member0Status = memberArray[0].Obj(); @@ -1474,13 +1480,16 @@ TEST_F(TopoCoordTest, NodeReturnsInvalidReplicaSetConfigInResponseToGetStatusWhe BSONObjBuilder statusBuilder; Status resultStatus(ErrorCodes::InternalError, "prepareStatusResponse didn't set result"); - getTopoCoord().prepareStatusResponse(cbData(), - curTime, - durationCount<Seconds>(uptimeSecs), - oplogProgress, - OpTime(), - &statusBuilder, - &resultStatus); + getTopoCoord().prepareStatusResponse( + cbData(), + TopologyCoordinator::ReplSetStatusArgs{ + curTime, + static_cast<unsigned>(durationCount<Seconds>(uptimeSecs)), + oplogProgress, + OpTime(), + OpTime()}, + &statusBuilder, + &resultStatus); ASSERT_NOT_OK(resultStatus); ASSERT_EQUALS(ErrorCodes::InvalidReplicaSetConfig, resultStatus); } @@ -2169,13 +2178,15 @@ public: // Ensure a single failed heartbeat did not cause the node to be marked down BSONObjBuilder statusBuilder; Status resultStatus(ErrorCodes::InternalError, "prepareStatusResponse didn't set result"); - getTopoCoord().prepareStatusResponse(cbData(), - _firstRequestDate + Milliseconds(4000), - 10, - OpTime(Timestamp(100, 0), 0), - OpTime(), - &statusBuilder, - &resultStatus); + getTopoCoord().prepareStatusResponse( + cbData(), + TopologyCoordinator::ReplSetStatusArgs{_firstRequestDate + Milliseconds(4000), + 10, + OpTime(Timestamp(100, 0), 0), + OpTime(), + OpTime()}, + &statusBuilder, + &resultStatus); ASSERT_OK(resultStatus); BSONObj rsStatus = statusBuilder.obj(); std::vector<BSONElement> memberArray = rsStatus["members"].Array(); @@ -2185,8 +2196,9 @@ public: ASSERT_EQUALS(1, member1Status["health"].Double()); ASSERT_EQUALS(Timestamp(0, 0), - Timestamp(rsStatus["lastCommittedOpTime"]["ts"].timestampValue())); - ASSERT_EQUALS(-1LL, rsStatus["lastCommittedOpTime"]["t"].numberLong()); + Timestamp(rsStatus["OpTimes"]["lastCommittedOpTime"]["ts"].timestampValue())); + ASSERT_EQUALS(-1LL, rsStatus["OpTimes"]["lastCommittedOpTime"]["t"].numberLong()); + ASSERT_FALSE(rsStatus["OpTimes"].Obj().hasField("readConcernMajorityOpTime")); } Date_t firstRequestDate() { @@ -2229,13 +2241,15 @@ public: // Ensure a second failed heartbeat did not cause the node to be marked down BSONObjBuilder statusBuilder; Status resultStatus(ErrorCodes::InternalError, "prepareStatusResponse didn't set result"); - getTopoCoord().prepareStatusResponse(cbData(), - firstRequestDate() + Seconds(4), - 10, - OpTime(Timestamp(100, 0), 0), - OpTime(), - &statusBuilder, - &resultStatus); + getTopoCoord().prepareStatusResponse( + cbData(), + TopologyCoordinator::ReplSetStatusArgs{firstRequestDate() + Seconds(4), + 10, + OpTime(Timestamp(100, 0), 0), + OpTime(), + OpTime()}, + &statusBuilder, + &resultStatus); ASSERT_OK(resultStatus); BSONObj rsStatus = statusBuilder.obj(); std::vector<BSONElement> memberArray = rsStatus["members"].Array(); @@ -2543,13 +2557,15 @@ TEST_F(HeartbeatResponseTestTwoRetries, NodeDoesNotRetryHeartbeatsAfterFailingTw // Ensure a third failed heartbeat caused the node to be marked down BSONObjBuilder statusBuilder; Status resultStatus(ErrorCodes::InternalError, "prepareStatusResponse didn't set result"); - getTopoCoord().prepareStatusResponse(cbData(), - firstRequestDate() + Milliseconds(4900), - 10, - OpTime(Timestamp(100, 0), 0), - OpTime(), - &statusBuilder, - &resultStatus); + getTopoCoord().prepareStatusResponse( + cbData(), + TopologyCoordinator::ReplSetStatusArgs{firstRequestDate() + Milliseconds(4900), + 10, + OpTime(Timestamp(100, 0), 0), + OpTime(), + OpTime()}, + &statusBuilder, + &resultStatus); ASSERT_OK(resultStatus); BSONObj rsStatus = statusBuilder.obj(); std::vector<BSONElement> memberArray = rsStatus["members"].Array(); @@ -2782,13 +2798,15 @@ TEST_F(HeartbeatResponseTestTwoRetries, // Ensure a third nonconsecutive heartbeat failure did not cause the node to be marked down BSONObjBuilder statusBuilder; Status resultStatus(ErrorCodes::InternalError, "prepareStatusResponse didn't set result"); - getTopoCoord().prepareStatusResponse(cbData(), - firstRequestDate() + Milliseconds(7000), - 600, - OpTime(Timestamp(100, 0), 0), - OpTime(), - &statusBuilder, - &resultStatus); + getTopoCoord().prepareStatusResponse( + cbData(), + TopologyCoordinator::ReplSetStatusArgs{firstRequestDate() + Milliseconds(7000), + 600, + OpTime(Timestamp(100, 0), 0), + OpTime(), + OpTime()}, + &statusBuilder, + &resultStatus); ASSERT_OK(resultStatus); BSONObj rsStatus = statusBuilder.obj(); std::vector<BSONElement> memberArray = rsStatus["members"].Array(); @@ -4236,7 +4254,10 @@ TEST_F(ShutdownInProgressTest, NodeReturnsShutDownInProgressWhenGetReplSetStatus Status result = Status::OK(); BSONObjBuilder response; getTopoCoord().prepareStatusResponse( - cbData(), Date_t(), 0, OpTime(), OpTime(), &response, &result); + cbData(), + TopologyCoordinator::ReplSetStatusArgs{Date_t(), 0, OpTime(), OpTime(), OpTime()}, + &response, + &result); ASSERT_EQUALS(ErrorCodes::ShutdownInProgress, result); ASSERT_TRUE(response.obj().isEmpty()); } diff --git a/src/mongo/db/repl/topology_coordinator_impl_v1_test.cpp b/src/mongo/db/repl/topology_coordinator_impl_v1_test.cpp index aa0ffeaaf2c..f8851a92950 100644 --- a/src/mongo/db/repl/topology_coordinator_impl_v1_test.cpp +++ b/src/mongo/db/repl/topology_coordinator_impl_v1_test.cpp @@ -1315,6 +1315,7 @@ TEST_F(TopoCoordTest, ReplSetGetStatus) { Timestamp electionTime(1, 2); OpTime oplogProgress(Timestamp(3, 4), 2); OpTime lastCommittedOpTime(Timestamp(2, 3), 6); + OpTime readConcernMajorityOpTime(Timestamp(4, 5), 7); std::string setName = "mySet"; ReplSetHeartbeatResponse hb; @@ -1362,20 +1363,25 @@ TEST_F(TopoCoordTest, ReplSetGetStatus) { // Now node 0 is down, node 1 is up, and for node 2 we have no heartbeat data yet. BSONObjBuilder statusBuilder; Status resultStatus(ErrorCodes::InternalError, "prepareStatusResponse didn't set result"); - getTopoCoord().prepareStatusResponse(cbData(), - curTime, - durationCount<Seconds>(uptimeSecs), - oplogProgress, - lastCommittedOpTime, - &statusBuilder, - &resultStatus); + getTopoCoord().prepareStatusResponse( + cbData(), + TopologyCoordinator::ReplSetStatusArgs{ + curTime, + static_cast<unsigned>(durationCount<Seconds>(uptimeSecs)), + oplogProgress, + lastCommittedOpTime, + readConcernMajorityOpTime}, + &statusBuilder, + &resultStatus); ASSERT_OK(resultStatus); BSONObj rsStatus = statusBuilder.obj(); // Test results for all non-self members ASSERT_EQUALS(setName, rsStatus["set"].String()); ASSERT_EQUALS(curTime.asInt64(), rsStatus["date"].Date().asInt64()); - ASSERT_EQUALS(lastCommittedOpTime.toBSON(), rsStatus["lastCommittedOpTime"].Obj()); + ASSERT_EQUALS(lastCommittedOpTime.toBSON(), rsStatus["OpTimes"]["lastCommittedOpTime"].Obj()); + ASSERT_EQUALS(readConcernMajorityOpTime.toBSON(), + rsStatus["OpTimes"]["readConcernMajorityOpTime"].Obj()); std::vector<BSONElement> memberArray = rsStatus["members"].Array(); ASSERT_EQUALS(4U, memberArray.size()); BSONObj member0Status = memberArray[0].Obj(); @@ -1467,13 +1473,16 @@ TEST_F(TopoCoordTest, NodeReturnsInvalidReplicaSetConfigInResponseToGetStatusWhe BSONObjBuilder statusBuilder; Status resultStatus(ErrorCodes::InternalError, "prepareStatusResponse didn't set result"); - getTopoCoord().prepareStatusResponse(cbData(), - curTime, - durationCount<Seconds>(uptimeSecs), - oplogProgress, - OpTime(), - &statusBuilder, - &resultStatus); + getTopoCoord().prepareStatusResponse( + cbData(), + TopologyCoordinator::ReplSetStatusArgs{ + curTime, + static_cast<unsigned>(durationCount<Seconds>(uptimeSecs)), + oplogProgress, + OpTime(), + OpTime()}, + &statusBuilder, + &resultStatus); ASSERT_NOT_OK(resultStatus); ASSERT_EQUALS(ErrorCodes::InvalidReplicaSetConfig, resultStatus); } @@ -1529,7 +1538,10 @@ TEST_F(ShutdownInProgressTest, NodeReturnsShutDownInProgressWhenGetReplSetStatus Status result = Status::OK(); BSONObjBuilder response; getTopoCoord().prepareStatusResponse( - cbData(), Date_t(), 0, OpTime(), OpTime(), &response, &result); + cbData(), + TopologyCoordinator::ReplSetStatusArgs{Date_t(), 0, OpTime(), OpTime(), OpTime()}, + &response, + &result); ASSERT_EQUALS(ErrorCodes::ShutdownInProgress, result); ASSERT_TRUE(response.obj().isEmpty()); } @@ -4032,13 +4044,15 @@ public: // Ensure a single failed heartbeat did not cause the node to be marked down BSONObjBuilder statusBuilder; Status resultStatus(ErrorCodes::InternalError, "prepareStatusResponse didn't set result"); - getTopoCoord().prepareStatusResponse(cbData(), - _firstRequestDate + Milliseconds(4000), - 10, - OpTime(Timestamp(100, 0), 0), - OpTime(), - &statusBuilder, - &resultStatus); + getTopoCoord().prepareStatusResponse( + cbData(), + TopologyCoordinator::ReplSetStatusArgs{_firstRequestDate + Milliseconds(4000), + 10, + OpTime(Timestamp(100, 0), 0), + OpTime(), + OpTime()}, + &statusBuilder, + &resultStatus); ASSERT_OK(resultStatus); BSONObj rsStatus = statusBuilder.obj(); std::vector<BSONElement> memberArray = rsStatus["members"].Array(); @@ -4048,8 +4062,9 @@ public: ASSERT_EQUALS(1, member1Status["health"].Double()); ASSERT_EQUALS(Timestamp(0, 0), - Timestamp(rsStatus["lastCommittedOpTime"]["ts"].timestampValue())); - ASSERT_EQUALS(-1LL, rsStatus["lastCommittedOpTime"]["t"].numberLong()); + Timestamp(rsStatus["OpTimes"]["lastCommittedOpTime"]["ts"].timestampValue())); + ASSERT_EQUALS(-1LL, rsStatus["OpTimes"]["lastCommittedOpTime"]["t"].numberLong()); + ASSERT_FALSE(rsStatus["OpTimes"].Obj().hasField("readConcernMajorityOpTime")); } Date_t firstRequestDate() { @@ -4112,13 +4127,15 @@ public: // Ensure a second failed heartbeat did not cause the node to be marked down BSONObjBuilder statusBuilder; Status resultStatus(ErrorCodes::InternalError, "prepareStatusResponse didn't set result"); - getTopoCoord().prepareStatusResponse(cbData(), - firstRequestDate() + Seconds(4), - 10, - OpTime(Timestamp(100, 0), 0), - OpTime(), - &statusBuilder, - &resultStatus); + getTopoCoord().prepareStatusResponse( + cbData(), + TopologyCoordinator::ReplSetStatusArgs{firstRequestDate() + Seconds(4), + 10, + OpTime(Timestamp(100, 0), 0), + OpTime(), + OpTime()}, + &statusBuilder, + &resultStatus); ASSERT_OK(resultStatus); BSONObj rsStatus = statusBuilder.obj(); std::vector<BSONElement> memberArray = rsStatus["members"].Array(); @@ -4158,13 +4175,15 @@ TEST_F(HeartbeatResponseTestTwoRetriesV1, NodeDoesNotRetryHeartbeatsAfterFailing // Ensure a third failed heartbeat caused the node to be marked down BSONObjBuilder statusBuilder; Status resultStatus(ErrorCodes::InternalError, "prepareStatusResponse didn't set result"); - getTopoCoord().prepareStatusResponse(cbData(), - firstRequestDate() + Milliseconds(4900), - 10, - OpTime(Timestamp(100, 0), 0), - OpTime(), - &statusBuilder, - &resultStatus); + getTopoCoord().prepareStatusResponse( + cbData(), + TopologyCoordinator::ReplSetStatusArgs{firstRequestDate() + Milliseconds(4900), + 10, + OpTime(Timestamp(100, 0), 0), + OpTime(), + OpTime()}, + &statusBuilder, + &resultStatus); ASSERT_OK(resultStatus); BSONObj rsStatus = statusBuilder.obj(); std::vector<BSONElement> memberArray = rsStatus["members"].Array(); @@ -4216,13 +4235,15 @@ TEST_F(HeartbeatResponseTestTwoRetriesV1, HeartbeatThreeNonconsecutiveFailures) // Ensure a third nonconsecutive heartbeat failure did not cause the node to be marked down BSONObjBuilder statusBuilder; Status resultStatus(ErrorCodes::InternalError, "prepareStatusResponse didn't set result"); - getTopoCoord().prepareStatusResponse(cbData(), - firstRequestDate() + Milliseconds(7000), - 600, - OpTime(Timestamp(100, 0), 0), - OpTime(), - &statusBuilder, - &resultStatus); + getTopoCoord().prepareStatusResponse( + cbData(), + TopologyCoordinator::ReplSetStatusArgs{firstRequestDate() + Milliseconds(7000), + 600, + OpTime(Timestamp(100, 0), 0), + OpTime(), + OpTime()}, + &statusBuilder, + &resultStatus); ASSERT_OK(resultStatus); BSONObj rsStatus = statusBuilder.obj(); std::vector<BSONElement> memberArray = rsStatus["members"].Array(); |