1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 /** 32 * This is an internal header. 33 * This should only be included by replica_set_monitor.cpp and replica_set_monitor_test.cpp. 34 * This should never be included by any header. 35 */ 36 37 #pragma once 38 39 #include <cstdint> 40 #include <deque> 41 #include <set> 42 #include <string> 43 #include <vector> 44 45 #include "mongo/base/disallow_copying.h" 46 #include "mongo/client/read_preference.h" 47 #include "mongo/client/replica_set_monitor.h" 48 #include "mongo/db/jsobj.h" 49 #include "mongo/platform/random.h" 50 #include "mongo/stdx/condition_variable.h" 51 #include "mongo/stdx/mutex.h" 52 #include "mongo/util/net/hostandport.h" 53 54 namespace mongo { 55 56 struct ReplicaSetMonitor::IsMasterReply { IsMasterReplyIsMasterReply57 IsMasterReply() : ok(false) {} IsMasterReplyIsMasterReply58 IsMasterReply(const HostAndPort& host, int64_t latencyMicros, const BSONObj& reply) 59 : ok(false), host(host), latencyMicros(latencyMicros) { 60 parse(reply); 61 } 62 63 /** 64 * Never throws. If parsing fails for any reason, sets ok to false. 65 */ 66 void parse(const BSONObj& obj); 67 68 bool ok; // if false, ignore all other fields 69 BSONObj raw; // Always owned. Other fields are allowed to be a view into this. 70 std::string setName; 71 bool isMaster; 72 bool secondary; 73 bool hidden; 74 int configVersion{}; 75 OID electionId; // Set if this isMaster reply is from the primary 76 HostAndPort primary; // empty if not present 77 std::set<HostAndPort> normalHosts; // both "hosts" and "passives" 78 BSONObj tags; 79 int minWireVersion{}; 80 int maxWireVersion{}; 81 82 // remaining fields aren't in isMaster reply, but are known to caller. 83 HostAndPort host; 84 int64_t latencyMicros; // ignored if negative 85 Date_t lastWriteDate{}; 86 repl::OpTime opTime{}; 87 }; 88 89 struct ReplicaSetMonitor::SetState { 90 MONGO_DISALLOW_COPYING(SetState); 91 92 public: 93 /** 94 * Holds the state of a single node in the replicaSet 95 */ 96 struct Node { 97 explicit Node(const HostAndPort& host); 98 99 void markFailed(const Status& status); 100 101 bool matches(const ReadPreference pref) const; 102 103 /** 104 * Checks if the given tag matches the tag attached to this node. 105 * 106 * Example: 107 * 108 * Tag of this node: { "dc": "nyc", "region": "na", "rack": "4" } 109 * 110 * match: {} 111 * match: { "dc": "nyc", "rack": 4 } 112 * match: { "region": "na", "dc": "nyc" } 113 * not match: { "dc": "nyc", "rack": 2 } 114 * not match: { "dc": "sf" } 115 */ 116 bool matches(const BSONObj&) const; 117 118 /** 119 * Returns true if all of the tags in the tag set match node's tags 120 */ 121 bool matches(const TagSet&) const; 122 123 /** 124 * Updates this Node based on information in reply. The reply must be from this host. 125 */ 126 void update(const IsMasterReply& reply); 127 128 HostAndPort host; 129 bool isUp{false}; 130 bool isMaster{false}; 131 int64_t latencyMicros{}; 132 BSONObj tags; // owned 133 int minWireVersion{}; 134 int maxWireVersion{}; 135 Date_t lastWriteDate{}; // from isMasterReply 136 Date_t lastWriteDateUpdateTime{}; // set to the local system's time at the time of updating 137 // lastWriteDate 138 repl::OpTime opTime{}; // from isMasterReply 139 }; 140 141 typedef std::vector<Node> Nodes; 142 143 /** 144 * seedNodes must not be empty 145 */ 146 SetState(StringData name, const std::set<HostAndPort>& seedNodes); 147 148 SetState(const MongoURI& uri); 149 150 bool isUsable() const; 151 152 /** 153 * Returns a host matching criteria or an empty host if no known host matches. 154 * 155 * Note: Uses only local data and does not go over the network. 156 */ 157 HostAndPort getMatchingHost(const ReadPreferenceSetting& criteria) const; 158 159 /** 160 * Returns the Node with the given host, or NULL if no Node has that host. 161 */ 162 Node* findNode(const HostAndPort& host); 163 164 /** 165 * Returns the Node with the given host, or creates one if no Node has that host. 166 * Maintains the sorted order of nodes. 167 */ 168 Node* findOrCreateNode(const HostAndPort& host); 169 170 void updateNodeIfInNodes(const IsMasterReply& reply); 171 172 /** 173 * Returns the connection string of the nodes that are known the be in the set because we've 174 * seen them in the isMaster reply of a PRIMARY. 175 */ 176 std::string getConfirmedServerAddress() const; 177 178 /** 179 * Returns the connection string of the nodes that are believed to be in the set because we've 180 * seen them in the isMaster reply of non-PRIMARY nodes in our seed list. 181 */ 182 std::string getUnconfirmedServerAddress() const; 183 184 /** 185 * Before unlocking, do DEV checkInvariants(); 186 */ 187 void checkInvariants() const; 188 189 stdx::mutex mutex; // must hold this to access any other member or method (except name). 190 191 // If Refresher::getNextStep returns WAIT, you should wait on the condition_variable, 192 // releasing mutex. It will be notified when either getNextStep will return something other 193 // than WAIT, or a new host is available for consideration by getMatchingHost. Essentially, 194 // this will be hit whenever the _refreshUntilMatches loop has the potential to make 195 // progress. 196 // TODO consider splitting cv into two: one for when looking for a master, one for all other 197 // cases. 198 stdx::condition_variable cv; 199 200 const std::string name; // safe to read outside lock since it is const 201 int consecutiveFailedScans; 202 std::set<HostAndPort> seedNodes; // updated whenever a master reports set membership changes 203 OID maxElectionId; // largest election id observed by this ReplicaSetMonitor 204 int configVersion{0}; // version number of the replica set config. 205 HostAndPort lastSeenMaster; // empty if we have never seen a master. can be same as current 206 Nodes nodes; // maintained sorted and unique by host 207 ScanStatePtr currentScan; // NULL if no scan in progress 208 int64_t latencyThresholdMicros; 209 mutable PseudoRandom rand; // only used for host selection to balance load 210 mutable int roundRobin; // used when useDeterministicHostSelection is true 211 MongoURI setUri; // URI that may have constructed this 212 }; 213 214 struct ReplicaSetMonitor::ScanState { 215 MONGO_DISALLOW_COPYING(ScanState); 216 217 public: ScanStateScanState218 ScanState() : foundUpMaster(false), foundAnyUpNodes(false) {} 219 220 /** 221 * Adds all hosts in container that aren't in triedHosts to hostsToScan, then shuffles the 222 * queue. 223 */ 224 template <typename Container> 225 void enqueAllUntriedHosts(const Container& container, PseudoRandom& rand); 226 227 // Access to fields is guarded by associated SetState's mutex. 228 bool foundUpMaster; 229 bool foundAnyUpNodes; 230 std::deque<HostAndPort> hostsToScan; // Work queue. 231 std::set<HostAndPort> possibleNodes; // Nodes reported by non-primary hosts. 232 std::set<HostAndPort> waitingFor; // Hosts we have dispatched but haven't replied yet. 233 std::set<HostAndPort> triedHosts; // Hosts that have been returned from getNextStep. 234 235 // All responses go here until we find a master. 236 typedef std::vector<IsMasterReply> UnconfirmedReplies; 237 UnconfirmedReplies unconfirmedReplies; 238 }; 239 240 } // namespace mongo 241