summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@mongodb.com>2014-08-27 18:34:27 -0400
committerAndy Schwerin <schwerin@mongodb.com>2014-08-28 14:22:56 -0400
commit86be883456bddff9ce3c283c9d740e70d62eb22f (patch)
tree7f27d99ee087c8ce16955afc945b806fbcaafd75
parentac6b4eac9d1fc33d357ee9264e4508f8a564d89d (diff)
downloadmongo-86be883456bddff9ce3c283c9d740e70d62eb22f.tar.gz
SERVER-14561 Parsing and accessor methods for ReplSetHeartbeatResponse.
-rw-r--r--src/mongo/db/repl/member_state.h4
-rw-r--r--src/mongo/db/repl/repl_coordinator_legacy.cpp2
-rw-r--r--src/mongo/db/repl/repl_set_heartbeat_response.cpp247
-rw-r--r--src/mongo/db/repl/repl_set_heartbeat_response.h57
-rw-r--r--src/mongo/db/repl/topology_coordinator_impl.cpp2
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) {