Status ReplSetConfig::checkIfWriteConcernCanBeSatisfied( const WriteConcernOptions& writeConcern) const { if (!writeConcern.wMode.empty() && writeConcern.wMode != WriteConcernOptions::kMajority && writeConcern.wMode != WriteConcernOptions::kInternalMajorityNoSnapshot) { StatusWith<ReplSetTagPattern> tagPatternStatus = findCustomWriteMode(writeConcern.wMode); if (!tagPatternStatus.isOK()) { return tagPatternStatus.getStatus(); } ReplSetTagMatch matcher(tagPatternStatus.getValue()); for (size_t j = 0; j < _members.size(); ++j) { const MemberConfig& memberConfig = _members[j]; for (MemberConfig::TagIterator it = memberConfig.tagsBegin(); it != memberConfig.tagsEnd(); ++it) { if (matcher.update(*it)) { return Status::OK(); } } } // Even if all the nodes in the set had a given write it still would not satisfy this // write concern mode. return Status(ErrorCodes::UnsatisfiableWriteConcern, str::stream() << "Not enough nodes match write concern mode \"" << writeConcern.wMode << "\""); } else { int nodesRemaining = writeConcern.wNumNodes; for (size_t j = 0; j < _members.size(); ++j) { if (!_members[j].isArbiter()) { // Only count data-bearing nodes --nodesRemaining; if (nodesRemaining <= 0) { return Status::OK(); } } } return Status(ErrorCodes::UnsatisfiableWriteConcern, "Not enough data-bearing nodes"); } }
Status ReplicaSetConfig::validate() const { if (_version <= 0 || _version > std::numeric_limits<int>::max()) { return Status(ErrorCodes::BadValue, str::stream() << kVersionFieldName << " field value of " << _version << " is out of range"); } if (_replSetName.empty()) { return Status(ErrorCodes::BadValue, str::stream() << "Replica set configuration must have non-empty " << kIdFieldName << " field"); } if (_heartbeatInterval < Milliseconds(0)) { return Status(ErrorCodes::BadValue, str::stream() << kSettingsFieldName << '.' << kHeartbeatIntervalFieldName << " field value must be non-negative, " "but found " << durationCount<Milliseconds>(_heartbeatInterval)); } if (_heartbeatTimeoutPeriod < Seconds(0)) { return Status(ErrorCodes::BadValue, str::stream() << kSettingsFieldName << '.' << kHeartbeatTimeoutFieldName << " field value must be non-negative, " "but found " << durationCount<Seconds>(_heartbeatTimeoutPeriod)); } if (_electionTimeoutPeriod < Milliseconds(0)) { return Status(ErrorCodes::BadValue, str::stream() << kSettingsFieldName << '.' << kElectionTimeoutFieldName << " field value must be non-negative, " "but found " << durationCount<Milliseconds>(_electionTimeoutPeriod)); } if (_members.size() > kMaxMembers || _members.empty()) { return Status(ErrorCodes::BadValue, str::stream() << "Replica set configuration contains " << _members.size() << " members, but must have at least 1 and no more than " << kMaxMembers); } size_t localhostCount = 0; size_t voterCount = 0; size_t arbiterCount = 0; size_t electableCount = 0; for (size_t i = 0; i < _members.size(); ++i) { const MemberConfig& memberI = _members[i]; Status status = memberI.validate(); if (!status.isOK()) return status; if (memberI.getHostAndPort().isLocalHost()) { ++localhostCount; } if (memberI.isVoter()) { ++voterCount; } // Nodes may be arbiters or electable, or neither, but never both. if (memberI.isArbiter()) { ++arbiterCount; } else if (memberI.getPriority() > 0) { ++electableCount; } for (size_t j = 0; j < _members.size(); ++j) { if (i == j) continue; const MemberConfig& memberJ = _members[j]; if (memberI.getId() == memberJ.getId()) { return Status(ErrorCodes::BadValue, str::stream() << "Found two member configurations with same " << MemberConfig::kIdFieldName << " field, " << kMembersFieldName << "." << i << "." << MemberConfig::kIdFieldName << " == " << kMembersFieldName << "." << j << "." << MemberConfig::kIdFieldName << " == " << memberI.getId()); } if (memberI.getHostAndPort() == memberJ.getHostAndPort()) { return Status(ErrorCodes::BadValue, str::stream() << "Found two member configurations with same " << MemberConfig::kHostFieldName << " field, " << kMembersFieldName << "." << i << "." << MemberConfig::kHostFieldName << " == " << kMembersFieldName << "." << j << "." << MemberConfig::kHostFieldName << " == " << memberI.getHostAndPort().toString()); } } } if (localhostCount != 0 && localhostCount != _members.size()) { return Status( ErrorCodes::BadValue, str::stream() << "Either all host names in a replica set configuration must be localhost " "references, or none must be; found " << localhostCount << " out of " << _members.size()); } if (voterCount > kMaxVotingMembers || voterCount == 0) { return Status(ErrorCodes::BadValue, str::stream() << "Replica set configuration contains " << voterCount << " voting members, but must be at least 1 and no more than " << kMaxVotingMembers); } if (electableCount == 0) { return Status(ErrorCodes::BadValue, "Replica set configuration must contain at least " "one non-arbiter member with priority > 0"); } // TODO(schwerin): Validate satisfiability of write modes? Omitting for backwards // compatibility. if (_defaultWriteConcern.wMode.empty()) { if (_defaultWriteConcern.wNumNodes == 0) { return Status(ErrorCodes::BadValue, "Default write concern mode must wait for at least 1 member"); } } else { if (WriteConcernOptions::kMajority != _defaultWriteConcern.wMode && !findCustomWriteMode(_defaultWriteConcern.wMode).isOK()) { return Status(ErrorCodes::BadValue, str::stream() << "Default write concern requires undefined write mode " << _defaultWriteConcern.wMode); } } if (_protocolVersion < 0 || _protocolVersion > std::numeric_limits<int>::max()) { return Status(ErrorCodes::BadValue, str::stream() << kProtocolVersionFieldName << " field value of " << _protocolVersion << " is out of range"); } if (_configServer) { if (arbiterCount > 0) { return Status(ErrorCodes::BadValue, "Arbiters are not allowed in replica set configurations being used for " "config servers"); } if (!serverGlobalParams.configsvr) { return Status(ErrorCodes::BadValue, "Nodes being used for config servers must be started with the " "--configsvr flag"); } } else if (serverGlobalParams.configsvr) { return Status(ErrorCodes::BadValue, "Nodes started with the --configsvr flag must have configsvr:true in " "their config"); } return Status::OK(); }
Status ReplSetConfig::validate() const { if (_version <= 0 || _version > std::numeric_limits<int>::max()) { return Status(ErrorCodes::BadValue, str::stream() << kVersionFieldName << " field value of " << _version << " is out of range"); } if (_replSetName.empty()) { return Status(ErrorCodes::BadValue, str::stream() << "Replica set configuration must have non-empty " << kIdFieldName << " field"); } if (_heartbeatInterval < Milliseconds(0)) { return Status(ErrorCodes::BadValue, str::stream() << kSettingsFieldName << '.' << kHeartbeatIntervalFieldName << " field value must be non-negative, " "but found " << durationCount<Milliseconds>(_heartbeatInterval)); } if (_members.size() > kMaxMembers || _members.empty()) { return Status(ErrorCodes::BadValue, str::stream() << "Replica set configuration contains " << _members.size() << " members, but must have at least 1 and no more than " << kMaxMembers); } size_t localhostCount = 0; size_t voterCount = 0; size_t arbiterCount = 0; size_t electableCount = 0; for (size_t i = 0; i < _members.size(); ++i) { const MemberConfig& memberI = _members[i]; Status status = memberI.validate(); if (!status.isOK()) return status; if (memberI.getHostAndPort().isLocalHost()) { ++localhostCount; } if (memberI.isVoter()) { ++voterCount; } // Nodes may be arbiters or electable, or neither, but never both. if (memberI.isArbiter()) { ++arbiterCount; } else if (memberI.getPriority() > 0) { ++electableCount; } for (size_t j = 0; j < _members.size(); ++j) { if (i == j) continue; const MemberConfig& memberJ = _members[j]; if (memberI.getId() == memberJ.getId()) { return Status(ErrorCodes::BadValue, str::stream() << "Found two member configurations with same " << MemberConfig::kIdFieldName << " field, " << kMembersFieldName << "." << i << "." << MemberConfig::kIdFieldName << " == " << kMembersFieldName << "." << j << "." << MemberConfig::kIdFieldName << " == " << memberI.getId()); } if (memberI.getHostAndPort() == memberJ.getHostAndPort()) { return Status(ErrorCodes::BadValue, str::stream() << "Found two member configurations with same " << MemberConfig::kHostFieldName << " field, " << kMembersFieldName << "." << i << "." << MemberConfig::kHostFieldName << " == " << kMembersFieldName << "." << j << "." << MemberConfig::kHostFieldName << " == " << memberI.getHostAndPort().toString()); } } } if (localhostCount != 0 && localhostCount != _members.size()) { return Status( ErrorCodes::BadValue, str::stream() << "Either all host names in a replica set configuration must be localhost " "references, or none must be; found " << localhostCount << " out of " << _members.size()); } if (voterCount > kMaxVotingMembers || voterCount == 0) { return Status(ErrorCodes::BadValue, str::stream() << "Replica set configuration contains " << voterCount << " voting members, but must be at least 1 and no more than " << kMaxVotingMembers); } if (electableCount == 0) { return Status(ErrorCodes::BadValue, "Replica set configuration must contain at least " "one non-arbiter member with priority > 0"); } if (_defaultWriteConcern.wMode.empty()) { if (_defaultWriteConcern.wNumNodes == 0) { return Status(ErrorCodes::BadValue, "Default write concern mode must wait for at least 1 member"); } } else { if (WriteConcernOptions::kMajority != _defaultWriteConcern.wMode && !findCustomWriteMode(_defaultWriteConcern.wMode).isOK()) { return Status(ErrorCodes::BadValue, str::stream() << "Default write concern requires undefined write mode " << _defaultWriteConcern.wMode); } } if (_protocolVersion != 0 && _protocolVersion != 1) { return Status(ErrorCodes::BadValue, str::stream() << kProtocolVersionFieldName << " field value of " << _protocolVersion << " is not 1 or 0"); } if (_configServer) { if (_protocolVersion == 0) { return Status(ErrorCodes::BadValue, "Config servers cannot run in protocolVersion 0"); } if (arbiterCount > 0) { return Status(ErrorCodes::BadValue, "Arbiters are not allowed in replica set configurations being used for " "config servers"); } for (MemberIterator mem = membersBegin(); mem != membersEnd(); mem++) { if (!mem->shouldBuildIndexes()) { return Status(ErrorCodes::BadValue, "Members in replica set configurations being used for config " "servers must build indexes"); } if (mem->getSlaveDelay() != Seconds(0)) { return Status(ErrorCodes::BadValue, "Members in replica set configurations being used for config " "servers cannot have a non-zero slaveDelay"); } } if (serverGlobalParams.clusterRole != ClusterRole::ConfigServer && !skipShardingConfigurationChecks) { return Status(ErrorCodes::BadValue, "Nodes being used for config servers must be started with the " "--configsvr flag"); } if (!_writeConcernMajorityJournalDefault) { return Status(ErrorCodes::BadValue, str::stream() << kWriteConcernMajorityJournalDefaultFieldName << " must be true in replica set configurations being " "used for config servers"); } } else if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer) { return Status(ErrorCodes::BadValue, "Nodes started with the --configsvr flag must have configsvr:true in " "their config"); } if (!_connectionString.isValid()) { return Status(ErrorCodes::BadValue, "ReplSetConfig represented an invalid replica set ConnectionString"); } return Status::OK(); }