diff options
author | Andy Schwerin <schwerin@mongodb.com> | 2014-08-27 18:34:27 -0400 |
---|---|---|
committer | Andy Schwerin <schwerin@mongodb.com> | 2014-08-28 14:22:56 -0400 |
commit | 86be883456bddff9ce3c283c9d740e70d62eb22f (patch) | |
tree | 7f27d99ee087c8ce16955afc945b806fbcaafd75 | |
parent | ac6b4eac9d1fc33d357ee9264e4508f8a564d89d (diff) | |
download | mongo-86be883456bddff9ce3c283c9d740e70d62eb22f.tar.gz |
SERVER-14561 Parsing and accessor methods for ReplSetHeartbeatResponse.
-rw-r--r-- | src/mongo/db/repl/member_state.h | 4 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_coordinator_legacy.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_set_heartbeat_response.cpp | 247 | ||||
-rw-r--r-- | src/mongo/db/repl/repl_set_heartbeat_response.h | 57 | ||||
-rw-r--r-- | src/mongo/db/repl/topology_coordinator_impl.cpp | 2 |
5 files changed, 276 insertions, 36 deletions
diff --git a/src/mongo/db/repl/member_state.h b/src/mongo/db/repl/member_state.h index 00e088239c3..46d116c25cb 100644 --- a/src/mongo/db/repl/member_state.h +++ b/src/mongo/db/repl/member_state.h @@ -43,6 +43,9 @@ namespace repl { RS_RECOVERING recovering/resyncing; after recovery usually auto-transitions to secondary RS_FATAL something bad has occurred and server is not completely offline with regard to the replica set. fatal error. RS_STARTUP2 loaded config, still determining who is primary + + State -> integer mappings are reserved forever. Do not change them or delete them, except + to update RS_MAX when introducing new states. */ struct MemberState { enum MS { @@ -57,6 +60,7 @@ namespace repl { RS_DOWN = 8, /* node not reachable for a report */ RS_ROLLBACK = 9, RS_REMOVED = 10, /* node removed from replica set */ + RS_MAX = 10 } s; MemberState(MS ms = RS_UNKNOWN) : s(ms) { } diff --git a/src/mongo/db/repl/repl_coordinator_legacy.cpp b/src/mongo/db/repl/repl_coordinator_legacy.cpp index 510c615eb24..5276c39b0ce 100644 --- a/src/mongo/db/repl/repl_coordinator_legacy.cpp +++ b/src/mongo/db/repl/repl_coordinator_legacy.cpp @@ -554,7 +554,7 @@ namespace { response->setElectable(theReplSet->iAmElectable()); response->setHbMsg(theReplSet->hbmsg()); - response->setTime((long long) time(0)); + response->setTime(Seconds(time(0))); response->setOpTime(theReplSet->lastOpTimeWritten.asDate()); const Member *syncTarget = BackgroundSync::get()->getSyncTarget(); if (syncTarget) { diff --git a/src/mongo/db/repl/repl_set_heartbeat_response.cpp b/src/mongo/db/repl/repl_set_heartbeat_response.cpp index de54954e44d..ebfd25bf93b 100644 --- a/src/mongo/db/repl/repl_set_heartbeat_response.cpp +++ b/src/mongo/db/repl/repl_set_heartbeat_response.cpp @@ -26,74 +26,281 @@ * it in the license file. */ +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kReplication + +#include "mongo/platform/basic.h" + #include "mongo/db/repl/repl_set_heartbeat_response.h" +#include <string> + +#include "mongo/base/status.h" #include "mongo/db/jsobj.h" +#include "mongo/util/assert_util.h" +#include "mongo/util/mongoutils/str.h" namespace mongo { namespace repl { +namespace { + + const std::string kOpTimeFieldName = "opTime"; + const std::string kTimeFieldName = "time"; + const std::string kElectionTimeFieldName = "electionTime"; + const std::string kConfigFieldName = "config"; + const std::string kIsElectableFieldName = "e"; + const std::string kMismatchFieldName = "mismatch"; + const std::string kIsReplSetFieldName = "rs"; + const std::string kHasStateDisagreementFieldName = "stateDisagreement"; + const std::string kMemberStateFieldName = "state"; + const std::string kConfigVersionFieldName = "v"; + const std::string kHbMessageFieldName = "hbmsg"; + const std::string kReplSetFieldName = "set"; + const std::string kSyncSourceFieldName = "syncingTo"; + +} // namespace ReplSetHeartbeatResponse::ReplSetHeartbeatResponse() : _electionTimeSet(false), _timeSet(false), + _time(0), _opTimeSet(false), _electableSet(false), _electable(false), _mismatch(false), _isReplSet(false), _stateDisagreement(false), - _state(-1), + _stateSet(false), _version(-1), - _setName(""), - _hbmsg(""), - _syncingTo("") + _configSet(false) {} void ReplSetHeartbeatResponse::addToBSON(BSONObjBuilder* builder) const { if (_opTimeSet) { - builder->appendDate("opTime", _opTime); + builder->appendDate(kOpTimeFieldName, _opTime.asDate()); } if (_timeSet) { - long long millis = _time.asInt64(); - *builder << "time" << millis; + *builder << kTimeFieldName << _time.total_seconds(); } if (_electionTimeSet) { - builder->appendDate("electionTime", _electionTime); + builder->appendDate(kElectionTimeFieldName, _electionTime.asDate()); } - if (_config.isInitialized()) { - *builder << "config" << _config.toBSON(); + if (_configSet) { + *builder << kConfigFieldName << _config.toBSON(); } if (_electableSet) { - *builder << "e" << _electable; + *builder << kIsElectableFieldName << _electable; } if (_mismatch) { - *builder << "mismatch" << _mismatch; + *builder << kMismatchFieldName << _mismatch; } if (_isReplSet) { *builder << "rs" << _isReplSet; } if (_stateDisagreement) { - *builder << "stateDisagreement" << _stateDisagreement; + *builder << kHasStateDisagreementFieldName << _stateDisagreement; } - if (_state != -1) { - *builder << "state" << _state; + if (_stateSet) { + builder->appendIntOrLL(kMemberStateFieldName, _state.s); } if (_version != -1) { - *builder << "v" << _version; + *builder << kConfigVersionFieldName << _version; } - *builder << "hbmsg" << _hbmsg; + *builder << kHbMessageFieldName << _hbmsg; if (!_setName.empty()) { - *builder << "set" << _setName; + *builder << kReplSetFieldName << _setName; } if (!_syncingTo.empty()) { - *builder << "syncingTo" << _syncingTo; + *builder << kSyncSourceFieldName << _syncingTo; } } BSONObj ReplSetHeartbeatResponse::toBSON() const { BSONObjBuilder builder; addToBSON(&builder); - return builder.done(); + return builder.obj(); + } + + Status ReplSetHeartbeatResponse::initialize(const BSONObj& doc) { + const BSONElement electionTimeElement = doc[kElectionTimeFieldName]; + if (electionTimeElement.eoo()) { + _electionTimeSet = false; + } + else if (electionTimeElement.type() == Timestamp) { + _electionTimeSet = true; + _electionTime = electionTimeElement._opTime(); + } + else if (electionTimeElement.type() == Date) { + _electionTime = true; + _electionTime = OpTime(electionTimeElement.date()); + } + else { + return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << + kElectionTimeFieldName << "\" field in response to replSetHeartbeat " + "command to have type Date or Timestamp, but found type " << + typeName(electionTimeElement.type())); + } + + const BSONElement timeElement = doc[kTimeFieldName]; + if (timeElement.eoo()) { + _timeSet = false; + } + else if (timeElement.isNumber()) { + _timeSet = true; + _time = Seconds(timeElement.numberLong()); + } + else { + return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << + kTimeFieldName << "\" field in reponse to replSetHeartbeat " + "command to have a numeric type, but found type " << + typeName(timeElement.type())); + } + + const BSONElement opTimeElement = doc[kOpTimeFieldName]; + if (opTimeElement.eoo()) { + _opTimeSet = false; + } + else if (opTimeElement.type() == Timestamp) { + _opTimeSet = true; + _opTime = opTimeElement._opTime(); + } + else if (opTimeElement.type() == Date) { + _opTimeSet = true; + _opTime = OpTime(opTimeElement.date()); + } + else { + return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << + kOpTimeFieldName << "\" field in response to replSetHeartbeat " + "command to have type Date or Timestamp, but found type " << + typeName(opTimeElement.type())); + } + + const BSONElement electableElement = doc[kIsElectableFieldName]; + if (electableElement.eoo()) { + _electableSet = false; + } + else { + _electableSet = true; + _electable = electableElement.trueValue(); + } + + _mismatch = doc[kMismatchFieldName].trueValue(); + _isReplSet = doc[kIsReplSetFieldName].trueValue(); + + const BSONElement memberStateElement = doc[kMemberStateFieldName]; + if (memberStateElement.eoo()) { + _stateSet = false; + } + else if (memberStateElement.type() != NumberInt && + memberStateElement.type() != NumberLong) { + return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << + kMemberStateFieldName << "\" field in response to replSetHeartbeat " + " command to have type NumberInt or NumberLong, but found type " << + typeName(memberStateElement.type())); + } + else { + long long stateInt = memberStateElement.numberLong(); + if (stateInt < 0 || stateInt > MemberState::RS_MAX) { + return Status(ErrorCodes::BadValue, str::stream() << "Value for \"" << + kMemberStateFieldName << "\" in response to replSetHeartbeat is " + " out of range; legal values are non-negative and no more than " << + MemberState::RS_MAX); + } + _state = MemberState(static_cast<int>(stateInt)); + } + + _stateDisagreement = doc[kHasStateDisagreementFieldName].trueValue(); + + const BSONElement versionElement = doc[kConfigVersionFieldName]; + if (versionElement.eoo()) { + return Status(ErrorCodes::NoSuchKey, str::stream() << + "Response to replSetHeartbeat missing required \"" << + kConfigVersionFieldName << " field"); + } + if (versionElement.type() != NumberInt) { + return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << + kConfigVersionFieldName << + "\" field in response to replSetHeartbeat to have " + "type NumberInt, but found " << typeName(versionElement.type())); + } + _version = versionElement.numberInt(); + + const BSONElement replSetNameElement = doc[kReplSetFieldName]; + if (replSetNameElement.eoo()) { + return Status(ErrorCodes::NoSuchKey, str::stream() << + "Response to replSetHeartbeat missing required \"" << + kReplSetFieldName << "\" field"); + } + if (replSetNameElement.type() != String) { + return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << + kReplSetFieldName << "\" field in response to replSetHeartbeat to have " + "type String, but found " << typeName(replSetNameElement.type())); + } + _setName = replSetNameElement.String(); + + const BSONElement hbMsgElement = doc[kHbMessageFieldName]; + if (hbMsgElement.eoo()) { + _hbmsg.clear(); + } + else if (hbMsgElement.type() != String) { + return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << + kHbMessageFieldName << "\" field in response to replSetHeartbeat to have " + "type String, but found " << typeName(hbMsgElement.type())); + } + _hbmsg = hbMsgElement.String(); + + const BSONElement syncingToElement = doc[kSyncSourceFieldName]; + if (syncingToElement.eoo()) { + _syncingTo.clear(); + } + else if (syncingToElement.type() != String) { + return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << + kSyncSourceFieldName << "\" field in response to replSetHeartbeat to " + "have type String, but found " << typeName(syncingToElement.type())); + } + _syncingTo = syncingToElement.String(); + + const BSONElement rsConfigElement = doc[kConfigFieldName]; + if (rsConfigElement.eoo()) { + _configSet = false; + _config = ReplicaSetConfig(); + } + else if (rsConfigElement.type() != Object) { + return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << + kConfigFieldName << "\" in response to replSetHeartbeat to have type " + "Object, but found " << typeName(rsConfigElement.type())); + } + _configSet = true; + return _config.initialize(rsConfigElement.Obj()); + } + + MemberState ReplSetHeartbeatResponse::getState() const { + invariant(_stateSet); + return _state; + } + + OpTime ReplSetHeartbeatResponse::getElectionTime() const { + invariant(_electionTimeSet); + return _electionTime; + } + + bool ReplSetHeartbeatResponse::isElectable() const { + invariant(_electableSet); + return _electable; + } + + Seconds ReplSetHeartbeatResponse::getTime() const { + invariant(_timeSet); + return _time; + } + + OpTime ReplSetHeartbeatResponse::getOpTime() const { + invariant(_opTimeSet); + return _opTime; + } + + const ReplicaSetConfig& ReplSetHeartbeatResponse::getConfig() const { + invariant(_configSet); + return _config; } } // namespace repl diff --git a/src/mongo/db/repl/repl_set_heartbeat_response.h b/src/mongo/db/repl/repl_set_heartbeat_response.h index 21e890bd3cf..ef06bef4a94 100644 --- a/src/mongo/db/repl/repl_set_heartbeat_response.h +++ b/src/mongo/db/repl/repl_set_heartbeat_response.h @@ -30,6 +30,7 @@ #include <string> +#include "mongo/db/repl/member_state.h" #include "mongo/db/repl/replica_set_config.h" #include "mongo/util/time_support.h" @@ -59,9 +60,9 @@ namespace repl { ReplSetHeartbeatResponse(); /** - * Initializes this ReplSetHeartbeatArgs from the contents of args. + * Initializes this ReplSetHeartbeatResponse from the contents of "doc". */ - Status initialize(const BSONObj& argsObj); + Status initialize(const BSONObj& doc); /** * Appends all non-default values to "builder". @@ -73,6 +74,26 @@ namespace repl { */ BSONObj toBSON() const; + bool isMismatched() const { return _mismatch; } + bool isReplSet() const { return _isReplSet; } + bool isStateDisagreement() const { return _stateDisagreement; } + const std::string& getReplicaSetName() const { return _setName; } + bool hasState() const { return _stateSet; } + MemberState getState() const; + bool hasElectionTime() const { return _electionTimeSet; } + OpTime getElectionTime() const; + bool hasIsElectable() const { return _electableSet; } + bool isElectable() const; + const std::string& getHbMsg() const { return _hbmsg; } + bool hasTime() const { return _timeSet; } + Seconds getTime() const; + bool hasOpTime() const { return _opTimeSet; } + OpTime getOpTime() const; + const std::string& getSyncingTo() const { return _syncingTo; } + int getVersion() const { return _version; } + bool hasConfig() const { return _configSet; } + const ReplicaSetConfig& getConfig() const; + /** * Sets _mismatch to true. */ @@ -96,13 +117,12 @@ namespace repl { /** * Sets _state to "state". */ - void setState(int state) { _state = state; } + void setState(MemberState state) { _stateSet = true; _state = state; } /** - * Sets _electionTime to "time" and sets _electionTimeSet to true to indicate - * that the value of _electionTime has been modified. + * Sets the optional "electionTime" field to the given OpTime. */ - void setElectionTime(Date_t time) { _electionTimeSet = true; _electionTime = time; } + void setElectionTime(OpTime time) { _electionTimeSet = true; _electionTime = time; } /** * Sets _electable to "electable" and sets _electableSet to true to indicate @@ -116,10 +136,10 @@ namespace repl { void setHbMsg(std::string hbmsg) { _hbmsg = hbmsg; } /** - * Sets _time to "time" and sets _timeSet to true to indicate that the value - * of _time has been modified. + * Sets the optional "time" field of the response to "theTime", which is + * a count of seconds since the UNIX epoch. */ - void setTime(Date_t time) { _timeSet = true; _time = time; } + void setTime(Seconds theTime) { _timeSet = true; _time = theTime; } /** * Sets _opTime to "time" and sets _opTimeSet to true to indicate that the value @@ -140,25 +160,34 @@ namespace repl { /** * Initializes _config with "config". */ - void setConfig(const ReplicaSetConfig& config) { _config = config; } + void setConfig(const ReplicaSetConfig& config) { _configSet = true; _config = config; } private: - Date_t _electionTime; - Date_t _time; - Date_t _opTime; bool _electionTimeSet; + OpTime _electionTime; + bool _timeSet; + Seconds _time; // Seconds since UNIX epoch. + bool _opTimeSet; + OpTime _opTime; + bool _electableSet; bool _electable; + bool _mismatch; bool _isReplSet; bool _stateDisagreement; - int _state; + + bool _stateSet; + MemberState _state; + int _version; std::string _setName; std::string _hbmsg; std::string _syncingTo; + + bool _configSet; ReplicaSetConfig _config; }; diff --git a/src/mongo/db/repl/topology_coordinator_impl.cpp b/src/mongo/db/repl/topology_coordinator_impl.cpp index 108b156bfa9..7ae82f05ede 100644 --- a/src/mongo/db/repl/topology_coordinator_impl.cpp +++ b/src/mongo/db/repl/topology_coordinator_impl.cpp @@ -600,7 +600,7 @@ namespace repl { // Heartbeat status message response->setHbMsg(_getHbmsg()); - response->setTime(now); + response->setTime(Seconds(Milliseconds(now.asInt64()).total_seconds())); response->setOpTime(lastOpApplied.asDate()); if (_syncSourceIndex != -1) { |