summaryrefslogtreecommitdiff
path: root/src/mongo/db/repl/member_config.cpp
diff options
context:
space:
mode:
authorADAM David Alan Martin <adam.martin@10gen.com>2019-05-17 15:41:29 -0400
committerADAM David Alan Martin <adam.martin@10gen.com>2019-05-17 15:41:29 -0400
commit6784f6568cc45fe25510e2d2393be57daffb5411 (patch)
tree1b3e93ce250ec2fbded3caea297e802b575c111f /src/mongo/db/repl/member_config.cpp
parent88efdbf5b5c3b2c30b5b971a9adcaaa0a9f51797 (diff)
downloadmongo-6784f6568cc45fe25510e2d2393be57daffb5411.tar.gz
SERVER-40156 Replica sets support Split Horizons
Replica sets can now respond to `isMaster` requests with different hostnames and ports, if contacted via alternate names using TLS. The `horizons` field in replica set member configurations can be used to control which `HostAndPort` to reply with for which "horizon view" of a replica set.
Diffstat (limited to 'src/mongo/db/repl/member_config.cpp')
-rw-r--r--src/mongo/db/repl/member_config.cpp111
1 files changed, 55 insertions, 56 deletions
diff --git a/src/mongo/db/repl/member_config.cpp b/src/mongo/db/repl/member_config.cpp
index 29907879a2e..6d5265a4b7f 100644
--- a/src/mongo/db/repl/member_config.cpp
+++ b/src/mongo/db/repl/member_config.cpp
@@ -50,6 +50,7 @@ const std::string MemberConfig::kSlaveDelayFieldName = "slaveDelay";
const std::string MemberConfig::kArbiterOnlyFieldName = "arbiterOnly";
const std::string MemberConfig::kBuildIndexesFieldName = "buildIndexes";
const std::string MemberConfig::kTagsFieldName = "tags";
+const std::string MemberConfig::kHorizonsFieldName = "horizons";
const std::string MemberConfig::kInternalVoterTagName = "$voter";
const std::string MemberConfig::kInternalElectableTagName = "$electable";
const std::string MemberConfig::kInternalAllTagName = "$all";
@@ -63,7 +64,8 @@ const std::string kLegalMemberConfigFieldNames[] = {MemberConfig::kIdFieldName,
MemberConfig::kSlaveDelayFieldName,
MemberConfig::kArbiterOnlyFieldName,
MemberConfig::kBuildIndexesFieldName,
- MemberConfig::kTagsFieldName};
+ MemberConfig::kTagsFieldName,
+ MemberConfig::kHorizonsFieldName};
const int kVotesFieldDefault = 1;
const double kPriorityFieldDefault = 1.0;
@@ -76,40 +78,34 @@ const Seconds kMaxSlaveDelay(3600 * 24 * 366);
} // namespace
-Status MemberConfig::initialize(const BSONObj& mcfg, ReplSetTagConfig* tagConfig) {
- Status status = bsonCheckOnlyHasFields(
- "replica set member configuration", mcfg, kLegalMemberConfigFieldNames);
- if (!status.isOK())
- return status;
+MemberConfig::MemberConfig(const BSONObj& mcfg, ReplSetTagConfig* tagConfig) {
+ uassertStatusOK(bsonCheckOnlyHasFields(
+ "replica set member configuration", mcfg, kLegalMemberConfigFieldNames));
//
// Parse _id field.
//
BSONElement idElement = mcfg[kIdFieldName];
- if (idElement.eoo()) {
- return Status(ErrorCodes::NoSuchKey, str::stream() << kIdFieldName << " field is missing");
- }
- if (!idElement.isNumber()) {
- return Status(ErrorCodes::TypeMismatch,
- str::stream() << kIdFieldName << " field has non-numeric type "
- << typeName(idElement.type()));
- }
+ if (idElement.eoo())
+ uasserted(ErrorCodes::NoSuchKey, str::stream() << kIdFieldName << " field is missing");
+
+ if (!idElement.isNumber())
+ uasserted(ErrorCodes::TypeMismatch,
+ str::stream() << kIdFieldName << " field has non-numeric type "
+ << typeName(idElement.type()));
_id = idElement.numberInt();
//
// Parse h field.
//
std::string hostAndPortString;
- status = bsonExtractStringField(mcfg, kHostFieldName, &hostAndPortString);
- if (!status.isOK())
- return status;
+ uassertStatusOK(bsonExtractStringField(mcfg, kHostFieldName, &hostAndPortString));
boost::trim(hostAndPortString);
- status = _host.initialize(hostAndPortString);
- if (!status.isOK())
- return status;
- if (!_host.hasPort()) {
+ HostAndPort host;
+ uassertStatusOK(host.initialize(hostAndPortString));
+ if (!host.hasPort()) {
// make port explicit even if default.
- _host = HostAndPort(_host.host(), _host.port());
+ host = HostAndPort(host.host(), host.port());
}
//
@@ -121,18 +117,16 @@ Status MemberConfig::initialize(const BSONObj& mcfg, ReplSetTagConfig* tagConfig
} else if (votesElement.isNumber()) {
_votes = votesElement.numberInt();
} else {
- return Status(ErrorCodes::TypeMismatch,
- str::stream() << kVotesFieldName << " field value has non-numeric type "
- << typeName(votesElement.type()));
+ uasserted(ErrorCodes::TypeMismatch,
+ str::stream() << kVotesFieldName << " field value has non-numeric type "
+ << typeName(votesElement.type()));
}
//
// Parse arbiterOnly field.
//
- status = bsonExtractBooleanFieldWithDefault(
- mcfg, kArbiterOnlyFieldName, kArbiterOnlyFieldDefault, &_arbiterOnly);
- if (!status.isOK())
- return status;
+ uassertStatusOK(bsonExtractBooleanFieldWithDefault(
+ mcfg, kArbiterOnlyFieldName, kArbiterOnlyFieldDefault, &_arbiterOnly));
//
// Parse priority field.
@@ -144,9 +138,9 @@ Status MemberConfig::initialize(const BSONObj& mcfg, ReplSetTagConfig* tagConfig
} else if (priorityElement.isNumber()) {
_priority = priorityElement.numberDouble();
} else {
- return Status(ErrorCodes::TypeMismatch,
- str::stream() << kPriorityFieldName << " field has non-numeric type "
- << typeName(priorityElement.type()));
+ uasserted(ErrorCodes::TypeMismatch,
+ str::stream() << kPriorityFieldName << " field has non-numeric type "
+ << typeName(priorityElement.type()));
}
//
@@ -158,47 +152,52 @@ Status MemberConfig::initialize(const BSONObj& mcfg, ReplSetTagConfig* tagConfig
} else if (slaveDelayElement.isNumber()) {
_slaveDelay = Seconds(slaveDelayElement.numberInt());
} else {
- return Status(ErrorCodes::TypeMismatch,
- str::stream() << kSlaveDelayFieldName << " field value has non-numeric type "
- << typeName(slaveDelayElement.type()));
+ uasserted(ErrorCodes::TypeMismatch,
+ str::stream() << kSlaveDelayFieldName << " field value has non-numeric type "
+ << typeName(slaveDelayElement.type()));
}
//
// Parse hidden field.
//
- status =
- bsonExtractBooleanFieldWithDefault(mcfg, kHiddenFieldName, kHiddenFieldDefault, &_hidden);
- if (!status.isOK())
- return status;
+ uassertStatusOK(
+ bsonExtractBooleanFieldWithDefault(mcfg, kHiddenFieldName, kHiddenFieldDefault, &_hidden));
//
// Parse buildIndexes field.
//
- status = bsonExtractBooleanFieldWithDefault(
- mcfg, kBuildIndexesFieldName, kBuildIndexesFieldDefault, &_buildIndexes);
- if (!status.isOK())
- return status;
+ uassertStatusOK(bsonExtractBooleanFieldWithDefault(
+ mcfg, kBuildIndexesFieldName, kBuildIndexesFieldDefault, &_buildIndexes));
//
// Parse "tags" field.
//
- _tags.clear();
- BSONElement tagsElement;
- status = bsonExtractTypedField(mcfg, kTagsFieldName, Object, &tagsElement);
- if (status.isOK()) {
+ try {
+ BSONElement tagsElement;
+ uassertStatusOK(bsonExtractTypedField(mcfg, kTagsFieldName, Object, &tagsElement));
for (auto&& tag : tagsElement.Obj()) {
if (tag.type() != String) {
- return Status(ErrorCodes::TypeMismatch,
- str::stream() << "tags." << tag.fieldName()
- << " field has non-string value of type "
- << typeName(tag.type()));
+ uasserted(ErrorCodes::TypeMismatch,
+ str::stream() << "tags." << tag.fieldName()
+ << " field has non-string value of type "
+ << typeName(tag.type()));
}
_tags.push_back(tagConfig->makeTag(tag.fieldNameStringData(), tag.valueStringData()));
}
- } else if (ErrorCodes::NoSuchKey != status) {
- return status;
+ } catch (const ExceptionFor<ErrorCodes::NoSuchKey>&) {
+ // No such key is okay in this case, everything else is a problem.
}
+ const auto horizonsElement = [&]() -> boost::optional<BSONElement> {
+ const BSONElement result = mcfg[kHorizonsFieldName];
+ if (result.eoo()) {
+ return boost::none;
+ }
+ return result;
+ }();
+
+ _splitHorizon = SplitHorizon(host, horizonsElement);
+
//
// Add internal tags based on other member properties.
//
@@ -218,8 +217,6 @@ Status MemberConfig::initialize(const BSONObj& mcfg, ReplSetTagConfig* tagConfig
if (!_arbiterOnly) {
_tags.push_back(tagConfig->makeTag(kInternalAllTagName, id));
}
-
- return Status::OK();
}
Status MemberConfig::validate() const {
@@ -286,7 +283,7 @@ bool MemberConfig::hasTags(const ReplSetTagConfig& tagConfig) const {
BSONObj MemberConfig::toBSON(const ReplSetTagConfig& tagConfig) const {
BSONObjBuilder configBuilder;
configBuilder.append("_id", _id);
- configBuilder.append("host", _host.toString());
+ configBuilder.append("host", _host().toString());
configBuilder.append("arbiterOnly", _arbiterOnly);
configBuilder.append("buildIndexes", _buildIndexes);
configBuilder.append("hidden", _hidden);
@@ -303,6 +300,8 @@ BSONObj MemberConfig::toBSON(const ReplSetTagConfig& tagConfig) const {
}
tags.done();
+ _splitHorizon.toBSON(configBuilder);
+
configBuilder.append("slaveDelay", durationCount<Seconds>(_slaveDelay));
configBuilder.append("votes", getNumVotes());
return configBuilder.obj();