void ReplCoordTest::simulateSuccessfulElection() { OperationContextReplMock txn; ReplicationCoordinatorImpl* replCoord = getReplCoord(); NetworkInterfaceMock* net = getNet(); ReplicaSetConfig rsConfig = replCoord->getReplicaSetConfig_forTest(); ASSERT(replCoord->getMemberState().secondary()) << replCoord->getMemberState().toString(); while (!replCoord->getMemberState().primary()) { log() << "Waiting on network in state " << replCoord->getMemberState(); getNet()->enterNetwork(); const NetworkInterfaceMock::NetworkOperationIterator noi = net->getNextReadyRequest(); const RemoteCommandRequest& request = noi->getRequest(); log() << request.target.toString() << " processing " << request.cmdObj; ReplSetHeartbeatArgs hbArgs; if (hbArgs.initialize(request.cmdObj).isOK()) { ReplSetHeartbeatResponse hbResp; hbResp.setSetName(rsConfig.getReplSetName()); hbResp.setState(MemberState::RS_SECONDARY); hbResp.setConfigVersion(rsConfig.getConfigVersion()); BSONObjBuilder respObj; respObj << "ok" << 1; hbResp.addToBSON(&respObj, false); net->scheduleResponse(noi, net->now(), makeResponseStatus(respObj.obj())); } else if (request.cmdObj.firstElement().fieldNameStringData() == "replSetFresh") { net->scheduleResponse( noi, net->now(), makeResponseStatus(BSON("ok" << 1 << "fresher" << false << "opTime" << Date_t() << "veto" << false))); } else if (request.cmdObj.firstElement().fieldNameStringData() == "replSetElect") { net->scheduleResponse(noi, net->now(), makeResponseStatus(BSON("ok" << 1 << "vote" << 1 << "round" << request.cmdObj["round"].OID()))); } else { error() << "Black holing unexpected request to " << request.target << ": " << request.cmdObj; net->blackHole(noi); } net->runReadyNetworkOperations(); getNet()->exitNetwork(); } ASSERT(replCoord->isWaitingForApplierToDrain()); ASSERT(replCoord->getMemberState().primary()) << replCoord->getMemberState().toString(); IsMasterResponse imResponse; replCoord->fillIsMasterForReplSet(&imResponse); ASSERT_FALSE(imResponse.isMaster()) << imResponse.toBSON().toString(); ASSERT_TRUE(imResponse.isSecondary()) << imResponse.toBSON().toString(); replCoord->signalDrainComplete(&txn); replCoord->fillIsMasterForReplSet(&imResponse); ASSERT_TRUE(imResponse.isMaster()) << imResponse.toBSON().toString(); ASSERT_FALSE(imResponse.isSecondary()) << imResponse.toBSON().toString(); ASSERT(replCoord->getMemberState().primary()) << replCoord->getMemberState().toString(); // Consume the notification of election win. for (int i = 0; i < rsConfig.getNumMembers() - 1; i++) { replyToReceivedHeartbeat(); } }
void ReplCoordTest::simulateStepDownOnIsolation() { ReplicationCoordinatorImpl* replCoord = getReplCoord(); NetworkInterfaceMock* net = getNet(); ReplicaSetConfig rsConfig = replCoord->getReplicaSetConfig_forTest(); ASSERT(replCoord->getMemberState().primary()) << replCoord->getMemberState().toString(); while (replCoord->getMemberState().primary()) { log() << "Waiting on network in state " << replCoord->getMemberState(); getNet()->enterNetwork(); net->runUntil(net->now() + Seconds(10)); const NetworkInterfaceMock::NetworkOperationIterator noi = net->getNextReadyRequest(); const RemoteCommandRequest& request = noi->getRequest(); log() << request.target.toString() << " processing " << request.cmdObj; ReplSetHeartbeatArgs hbArgs; if (hbArgs.initialize(request.cmdObj).isOK()) { net->scheduleResponse( noi, net->now(), ResponseStatus(ErrorCodes::NetworkTimeout, "Nobody's home")); } else { error() << "Black holing unexpected request to " << request.target << ": " << request.cmdObj; net->blackHole(noi); } net->runReadyNetworkOperations(); getNet()->exitNetwork(); } }
std::vector<RemoteCommandRequest> QuorumChecker::getRequests() const { const bool isInitialConfig = _rsConfig->getConfigVersion() == 1; const MemberConfig& myConfig = _rsConfig->getMemberAt(_myIndex); std::vector<RemoteCommandRequest> requests; if (hasReceivedSufficientResponses()) { return requests; } BSONObj hbRequest; if (_term == OpTime::kUninitializedTerm) { ReplSetHeartbeatArgs hbArgs; hbArgs.setSetName(_rsConfig->getReplSetName()); hbArgs.setProtocolVersion(1); hbArgs.setConfigVersion(_rsConfig->getConfigVersion()); hbArgs.setHeartbeatVersion(1); hbArgs.setCheckEmpty(isInitialConfig); hbArgs.setSenderHost(myConfig.getHostAndPort()); hbArgs.setSenderId(myConfig.getId()); hbRequest = hbArgs.toBSON(); } else { ReplSetHeartbeatArgsV1 hbArgs; hbArgs.setSetName(_rsConfig->getReplSetName()); hbArgs.setConfigVersion(_rsConfig->getConfigVersion()); hbArgs.setHeartbeatVersion(1); if (isInitialConfig) { hbArgs.setCheckEmpty(); } hbArgs.setSenderHost(myConfig.getHostAndPort()); hbArgs.setSenderId(myConfig.getId()); hbArgs.setTerm(_term); hbRequest = hbArgs.toBSON(); } // Send a bunch of heartbeat requests. // Schedule an operation when a "sufficient" number of them have completed, and use that // to compute the quorum check results. // Wait for the "completion" callback to finish, and then it's OK to return the results. for (int i = 0; i < _rsConfig->getNumMembers(); ++i) { if (_myIndex == i) { // No need to check self for liveness or unreadiness. continue; } requests.push_back(RemoteCommandRequest(_rsConfig->getMemberAt(i).getHostAndPort(), "admin", hbRequest, BSON(rpc::kReplSetMetadataFieldName << 1), nullptr, _rsConfig->getHeartbeatTimeoutPeriodMillis())); } return requests; }
Status LegacyReplicationCoordinator::processHeartbeat(const ReplSetHeartbeatArgs& args, ReplSetHeartbeatResponse* response) { if (args.getProtocolVersion() != 1) { return Status(ErrorCodes::BadValue, "incompatible replset protocol version"); } { if (_settings.ourSetName() != args.getSetName()) { log() << "replSet set names do not match, our cmdline: " << _settings.replSet << rsLog; log() << "replSet s: " << args.getSetName() << rsLog; response->noteMismatched(); return Status(ErrorCodes::BadValue, "repl set names do not match"); } } response->noteReplSet(); if( (theReplSet == 0) || (theReplSet->startupStatus == ReplSetImpl::LOADINGCONFIG) ) { if (!args.getSenderHost().empty()) { scoped_lock lck( _settings.discoveredSeeds_mx ); _settings.discoveredSeeds.insert(args.getSenderHost().toString()); } response->setHbMsg("still initializing"); return Status::OK(); } if (theReplSet->name() != args.getSetName()) { response->noteMismatched(); return Status(ErrorCodes::BadValue, "repl set names do not match (2)"); } response->setSetName(theReplSet->name()); MemberState currentState = theReplSet->state(); response->setState(currentState.s); if (currentState == MemberState::RS_PRIMARY) { response->setElectionTime(theReplSet->getElectionTime().asDate()); } response->setElectable(theReplSet->iAmElectable()); response->setHbMsg(theReplSet->hbmsg()); response->setTime((long long) time(0)); response->setOpTime(theReplSet->lastOpTimeWritten.asDate()); const Member *syncTarget = BackgroundSync::get()->getSyncTarget(); if (syncTarget) { response->setSyncingTo(syncTarget->fullName()); } int v = theReplSet->config().version; response->setVersion(v); if (v > args.getConfigVersion()) { ReplicaSetConfig config; fassert(18635, config.initialize(theReplSet->config().asBson())); response->setConfig(config); } Member* from = NULL; if (v == args.getConfigVersion() && args.getSenderId() != -1) { from = theReplSet->getMutableMember(args.getSenderId()); } if (!from) { from = theReplSet->findByName(args.getSenderHost().toString()); if (!from) { return Status::OK(); } } // if we thought that this node is down, let it know if (!from->hbinfo().up()) { response->noteStateDisagreement(); } // note that we got a heartbeat from this node theReplSet->mgr->send(stdx::bind(&ReplSet::msgUpdateHBRecv, theReplSet, from->hbinfo().id(), time(0))); return Status::OK(); }