/** * Copyright (C) 2018-present MongoDB, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the Server Side Public License, version 1, * as published by MongoDB, Inc. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * Server Side Public License for more details. * * You should have received a copy of the Server Side Public License * along with this program. If not, see * . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the Server Side Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kReplication #include "mongo/platform/basic.h" #include #include "mongo/db/repl/member_data.h" #include "mongo/logv2/log.h" namespace mongo { namespace repl { MemberData::MemberData() : _health(-1), _authIssue(false), _configIndex(-1), _isSelf(false) { _lastResponse.setState(MemberState::RS_UNKNOWN); _lastResponse.setElectionTime(Timestamp()); _lastResponse.setAppliedOpTimeAndWallTime(OpTimeAndWallTime()); } bool MemberData::setUpValues(Date_t now, ReplSetHeartbeatResponse&& hbResponse) { _health = 1; if (_upSince == Date_t()) { _upSince = now; } _authIssue = false; _lastHeartbeat = now; _lastUpdate = now; _lastUpdateStale = false; _updatedSinceRestart = true; _lastHeartbeatMessage.clear(); if (!hbResponse.hasState()) { hbResponse.setState(MemberState::RS_UNKNOWN); } if (!hbResponse.hasElectionTime()) { hbResponse.setElectionTime(_lastResponse.getElectionTime()); } if (!hbResponse.hasAppliedOpTime()) { hbResponse.setAppliedOpTimeAndWallTime(_lastResponse.getAppliedOpTimeAndWallTime()); } // Log if the state changes if (_lastResponse.getState() != hbResponse.getState()) { LOGV2(21215, "Member {hostAndPort} is now in state {newState}", "Member is in new state", "hostAndPort"_attr = _hostAndPort.toString(), "newState"_attr = hbResponse.getState().toString()); } bool opTimeAdvanced = advanceLastAppliedOpTimeAndWallTime(hbResponse.getAppliedOpTimeAndWallTime(), now); auto durableOpTimeAndWallTime = hbResponse.hasDurableOpTime() ? hbResponse.getDurableOpTimeAndWallTime() : OpTimeAndWallTime(); opTimeAdvanced = advanceLastDurableOpTimeAndWallTime(durableOpTimeAndWallTime, now) || opTimeAdvanced; bool configChanged = (getConfigVersionAndTerm() < hbResponse.getConfigVersionAndTerm()); _configTerm = hbResponse.getConfigTerm(); _configVersion = hbResponse.getConfigVersion(); _lastResponse = std::move(hbResponse); return (opTimeAdvanced || configChanged); } void MemberData::setDownValues(Date_t now, const std::string& heartbeatMessage) { _health = 0; _upSince = Date_t(); _lastHeartbeat = now; _authIssue = false; _updatedSinceRestart = true; _lastHeartbeatMessage = heartbeatMessage; if (_lastResponse.getState() != MemberState::RS_DOWN) { LOGV2(21216, "Member {hostAndPort} is now in state RS_DOWN - {heartbeatMessage}", "Member is now in state RS_DOWN", "hostAndPort"_attr = _hostAndPort.toString(), "heartbeatMessage"_attr = redact(heartbeatMessage)); } _lastResponse = ReplSetHeartbeatResponse(); _lastResponse.setState(MemberState::RS_DOWN); _lastResponse.setElectionTime(Timestamp()); _lastResponse.setAppliedOpTimeAndWallTime(OpTimeAndWallTime()); _lastResponse.setSyncingTo(HostAndPort()); // The _lastAppliedOpTime/_lastDurableOpTime fields don't get cleared merely by missing a // heartbeat. } void MemberData::setAuthIssue(Date_t now) { _health = 0; // set health to 0 so that this doesn't count towards majority. _upSince = Date_t(); _lastHeartbeat = now; _authIssue = true; _updatedSinceRestart = true; _lastHeartbeatMessage.clear(); if (_lastResponse.getState() != MemberState::RS_UNKNOWN) { LOGV2(21217, "Member {hostAndPort} is now in state RS_UNKNOWN due to authentication issue.", "Member is now in state RS_UNKNOWN due to authentication issue", "hostAndPort"_attr = _hostAndPort.toString()); } _lastResponse = ReplSetHeartbeatResponse(); _lastResponse.setState(MemberState::RS_UNKNOWN); _lastResponse.setElectionTime(Timestamp()); _lastResponse.setAppliedOpTimeAndWallTime(OpTimeAndWallTime()); _lastResponse.setSyncingTo(HostAndPort()); } void MemberData::setLastAppliedOpTimeAndWallTime(OpTimeAndWallTime opTime, Date_t now) { invariant(opTime.opTime.isNull() || opTime.wallTime > Date_t()); _lastUpdate = now; _lastUpdateStale = false; _lastAppliedOpTime = opTime.opTime; _lastAppliedWallTime = opTime.wallTime; } void MemberData::setLastDurableOpTimeAndWallTime(OpTimeAndWallTime opTime, Date_t now) { invariant(opTime.opTime.isNull() || opTime.wallTime > Date_t()); _lastUpdate = now; _lastUpdateStale = false; // Since _lastDurableOpTime is set asynchronously from _lastAppliedOpTime, it is possible that // 'opTime' is ahead of _lastAppliedOpTime. if (_lastAppliedOpTime >= opTime.opTime) { _lastDurableOpTime = opTime.opTime; _lastDurableWallTime = opTime.wallTime; } } bool MemberData::advanceLastAppliedOpTimeAndWallTime(OpTimeAndWallTime opTime, Date_t now) { invariant(opTime.opTime.isNull() || opTime.wallTime > Date_t()); _lastUpdate = now; _lastUpdateStale = false; if (_lastAppliedOpTime < opTime.opTime) { setLastAppliedOpTimeAndWallTime(opTime, now); return true; } return false; } bool MemberData::advanceLastDurableOpTimeAndWallTime(OpTimeAndWallTime opTime, Date_t now) { invariant(opTime.opTime.isNull() || opTime.wallTime > Date_t()); _lastUpdate = now; _lastUpdateStale = false; if (_lastDurableOpTime < opTime.opTime) { _lastDurableOpTime = opTime.opTime; _lastDurableWallTime = opTime.wallTime; return true; } return false; } } // namespace repl } // namespace mongo