summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenety Goh <benety@mongodb.com>2015-10-22 19:04:33 -0400
committerBenety Goh <benety@mongodb.com>2015-10-23 10:55:58 -0400
commit7483d8652926ad277e7e74d145444fe7b3fe2088 (patch)
tree84cef9f2045005544c56cf810bec97c9c82b7bc3
parent3db9d1338c4d15b9b937516676645fd26d5f0a23 (diff)
downloadmongo-7483d8652926ad277e7e74d145444fe7b3fe2088.tar.gz
SERVER-20979 added test cases for current node having higher priority than primary
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.cpp8
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.h11
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_elect_test.cpp64
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp65
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp8
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();
}
}