diff options
author | Benety Goh <benety@mongodb.com> | 2015-10-22 19:04:33 -0400 |
---|---|---|
committer | Benety Goh <benety@mongodb.com> | 2015-10-23 10:55:58 -0400 |
commit | 7483d8652926ad277e7e74d145444fe7b3fe2088 (patch) | |
tree | 84cef9f2045005544c56cf810bec97c9c82b7bc3 | |
parent | 3db9d1338c4d15b9b937516676645fd26d5f0a23 (diff) | |
download | mongo-7483d8652926ad277e7e74d145444fe7b3fe2088.tar.gz |
SERVER-20979 added test cases for current node having higher priority than primary
5 files changed, 149 insertions, 7 deletions
diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index 82617ff73c4..98f0e52d107 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -267,6 +267,14 @@ Date_t ReplicationCoordinatorImpl::getElectionTimeout_forTest() const { return _handleElectionTimeoutWhen; } +Date_t ReplicationCoordinatorImpl::getPriorityTakeover_forTest() const { + stdx::lock_guard<stdx::mutex> lk(_mutex); + if (!_priorityTakeoverCbh.isValid()) { + return Date_t(); + } + return _priorityTakeoverWhen; +} + OpTime ReplicationCoordinatorImpl::getCurrentCommittedSnapshotOpTime() { stdx::lock_guard<stdx::mutex> lk(_mutex); if (_currentCommittedSnapshot) { diff --git a/src/mongo/db/repl/replication_coordinator_impl.h b/src/mongo/db/repl/replication_coordinator_impl.h index 80757b7ba8e..a8b11b2a727 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.h +++ b/src/mongo/db/repl/replication_coordinator_impl.h @@ -324,6 +324,12 @@ public: Date_t getElectionTimeout_forTest() const; /** + * Returns scheduled time of priority takeover callback. + * Returns Date_t() if callback is not scheduled. + */ + Date_t getPriorityTakeover_forTest() const; + + /** * Simple wrapper around _setLastOptime_inlock to make it easier to test. */ Status setLastOptime_forTest(long long cfgVer, long long memberId, const OpTime& opTime); @@ -1346,6 +1352,11 @@ private: // Callback Handle used to cancel a scheduled PriorityTakover callback. ReplicationExecutor::CallbackHandle _priorityTakeoverCbh; // (M) + // Priority takeover callback will not run before this time. + // If this date is Date_t(), the callback is either unscheduled or canceled. + // Used for testing only. + Date_t _priorityTakeoverWhen; // (M) + // Callback handle used by waitForStartUpComplete() to block until configuration // is loaded and external state threads have been started (unless this node is an arbiter). // Used for testing only. diff --git a/src/mongo/db/repl/replication_coordinator_impl_elect_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_elect_test.cpp index 2414018aff1..a6788920ffd 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_elect_test.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_elect_test.cpp @@ -420,6 +420,66 @@ TEST_F(ReplCoordElectTest, NodeWillNotStandForElectionDuringHeartbeatReconfig) { "a configuration change")); getExternalState()->setStoreLocalConfigDocumentToHang(false); } + +TEST_F(ReplCoordElectTest, StepsDownRemoteIfNodeHasHigherPriorityThanCurrentPrimary) { + BSONObj configObj = BSON("_id" + << "mySet" + << "version" << 1 << "members" + << BSON_ARRAY(BSON("_id" << 1 << "host" + << "node1:12345" + << "priority" << 2) + << BSON("_id" << 2 << "host" + << "node2:12345") + << BSON("_id" << 3 << "host" + << "node3:12345"))); + assertStartSuccess(configObj, HostAndPort("node1", 12345)); + ReplicaSetConfig config = assertMakeRSConfig(configObj); + + auto replCoord = getReplCoord(); + + OperationContextNoop txn; + OpTime time1(Timestamp(100, 1), 0); + getReplCoord()->setMyLastOptime(time1); + ASSERT(getReplCoord()->setFollowerMode(MemberState::RS_SECONDARY)); + + auto net = getNet(); + net->enterNetwork(); + while (net->hasReadyRequests()) { + auto noi = net->getNextReadyRequest(); + auto&& request = noi->getRequest(); + log() << request.target << " processing " << request.cmdObj; + ASSERT_EQUALS("replSetHeartbeat", request.cmdObj.firstElement().fieldNameStringData()); + ReplSetHeartbeatArgs hbArgs; + if (hbArgs.initialize(request.cmdObj).isOK()) { + ReplSetHeartbeatResponse hbResp; + hbResp.setSetName(config.getReplSetName()); + if (request.target == HostAndPort("node2", 12345)) { + hbResp.setState(MemberState::RS_PRIMARY); + } else { + hbResp.setState(MemberState::RS_SECONDARY); + } + hbResp.setConfigVersion(config.getConfigVersion()); + auto response = makeResponseStatus(hbResp.toBSON(replCoord->isV1ElectionProtocol())); + net->scheduleResponse(noi, net->now(), response); + } else { + error() << "Black holing unexpected request to " << request.target << ": " + << request.cmdObj; + net->blackHole(noi); + } + } + net->runReadyNetworkOperations(); + net->exitNetwork(); + + net->enterNetwork(); + ASSERT_TRUE(net->hasReadyRequests()); + auto noi = net->getNextReadyRequest(); + auto&& request = noi->getRequest(); + log() << request.target << " processing " << request.cmdObj; + ASSERT_EQUALS("replSetStepDown", request.cmdObj.firstElement().fieldNameStringData()); + ASSERT_EQUALS(HostAndPort("node2", 12345), request.target); + net->exitNetwork(); } -} -} + +} // namespace +} // namespace repl +} // namespace mongo diff --git a/src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp index dd92722c201..b551b3a734f 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp @@ -750,6 +750,67 @@ TEST_F(ReplCoordElectV1Test, ElectionWillNotStartWhenNodeHasRecentlyLearnedAbout ASSERT(getReplCoord()->getMemberState().primary()) << getReplCoord()->getMemberState().toString(); } + +TEST_F(ReplCoordElectV1Test, SchedulesPriorityTakeoverIfNodeHasHigherPriorityThanCurrentPrimary) { + startCapturingLogMessages(); + BSONObj configObj = BSON("_id" + << "mySet" + << "version" << 1 << "members" + << BSON_ARRAY(BSON("_id" << 1 << "host" + << "node1:12345" + << "priority" << 2) + << BSON("_id" << 2 << "host" + << "node2:12345") + << BSON("_id" << 3 << "host" + << "node3:12345")) << "protocolVersion" + << 1); + assertStartSuccess(configObj, HostAndPort("node1", 12345)); + ReplicaSetConfig config = assertMakeRSConfig(configObj); + + auto replCoord = getReplCoord(); + + OperationContextNoop txn; + OpTime time1(Timestamp(100, 1), 0); + replCoord->setMyLastOptime(time1); + ASSERT(replCoord->setFollowerMode(MemberState::RS_SECONDARY)); + + ASSERT_EQUALS(Date_t(), replCoord->getPriorityTakeover_forTest()); + + auto net = getNet(); + net->enterNetwork(); + auto now = net->now(); + while (net->hasReadyRequests()) { + auto noi = net->getNextReadyRequest(); + auto&& request = noi->getRequest(); + log() << request.target << " processing " << request.cmdObj; + ASSERT_EQUALS("replSetHeartbeat", request.cmdObj.firstElement().fieldNameStringData()); + ReplSetHeartbeatArgsV1 hbArgs; + if (hbArgs.initialize(request.cmdObj).isOK()) { + ReplSetHeartbeatResponse hbResp; + hbResp.setSetName(config.getReplSetName()); + if (request.target == HostAndPort("node2", 12345)) { + hbResp.setState(MemberState::RS_PRIMARY); + } else { + hbResp.setState(MemberState::RS_SECONDARY); + } + hbResp.setConfigVersion(config.getConfigVersion()); + hbResp.setTerm(replCoord->getTerm()); + auto response = makeResponseStatus(hbResp.toBSON(replCoord->isV1ElectionProtocol())); + net->scheduleResponse(noi, net->now(), response); + } else { + error() << "Black holing unexpected request to " << request.target << ": " + << request.cmdObj; + net->blackHole(noi); + } + } + net->runReadyNetworkOperations(); + net->exitNetwork(); + + ASSERT_NOT_EQUALS(Date_t(), replCoord->getPriorityTakeover_forTest()); + ASSERT_EQUALS(now + config.getPriorityTakeoverDelay(0), + replCoord->getPriorityTakeover_forTest()); } -} -} + +} // namespace +} // namespace repl +} // namespace mongo diff --git a/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp b/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp index 10822e0f625..1e05e63a4c5 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp @@ -235,10 +235,11 @@ void ReplicationCoordinatorImpl::_handleHeartbeatResponseAction( case HeartbeatResponseAction::PriorityTakeover: { stdx::unique_lock<stdx::mutex> lk(_mutex); if (!_priorityTakeoverCbh.isValid()) { - auto when = _replExecutor.now() + _rsConfig.getPriorityTakeoverDelay(_selfIndex); - log() << "Scheduling priority takeover at " << when; + _priorityTakeoverWhen = + _replExecutor.now() + _rsConfig.getPriorityTakeoverDelay(_selfIndex); + log() << "Scheduling priority takeover at " << _priorityTakeoverWhen; _priorityTakeoverCbh = _scheduleWorkAt( - when, + _priorityTakeoverWhen, stdx::bind(&ReplicationCoordinatorImpl::_startElectSelfIfEligibleV1, this)); } break; @@ -663,6 +664,7 @@ void ReplicationCoordinatorImpl::_cancelPriorityTakeover_inlock() { log() << "Canceling priority takeover callback"; _replExecutor.cancel(_priorityTakeoverCbh); _priorityTakeoverCbh = CallbackHandle(); + _priorityTakeoverWhen = Date_t(); } } |