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 #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kReplication
32
33 #include "mongo/platform/basic.h"
34
35 #include "mongo/db/repl/is_master_response.h"
36
37 #include "mongo/base/status.h"
38 #include "mongo/bson/oid.h"
39 #include "mongo/bson/util/bson_extract.h"
40 #include "mongo/db/jsobj.h"
41 #include "mongo/util/mongoutils/str.h"
42
43 namespace mongo {
44 namespace repl {
45 namespace {
46
47 const std::string kIsMasterFieldName = "ismaster";
48 const std::string kSecondaryFieldName = "secondary";
49 const std::string kSetNameFieldName = "setName";
50 const std::string kSetVersionFieldName = "setVersion";
51 const std::string kHostsFieldName = "hosts";
52 const std::string kPassivesFieldName = "passives";
53 const std::string kArbitersFieldName = "arbiters";
54 const std::string kPrimaryFieldName = "primary";
55 const std::string kArbiterOnlyFieldName = "arbiterOnly";
56 const std::string kPassiveFieldName = "passive";
57 const std::string kHiddenFieldName = "hidden";
58 const std::string kBuildIndexesFieldName = "buildIndexes";
59 const std::string kSlaveDelayFieldName = "slaveDelay";
60 const std::string kTagsFieldName = "tags";
61 const std::string kMeFieldName = "me";
62 const std::string kElectionIdFieldName = "electionId";
63 const std::string kLastWriteOpTimeFieldName = "opTime";
64 const std::string kLastWriteDateFieldName = "lastWriteDate";
65 const std::string kLastMajorityWriteOpTimeFieldName = "majorityOpTime";
66 const std::string kLastMajorityWriteDateFieldName = "majorityWriteDate";
67 const std::string kLastWriteFieldName = "lastWrite";
68 const std::string kIsWritablePrimaryFieldName = "isWritablePrimary";
69 const std::string kSecondaryDelaySecsFieldName = "secondaryDelaySecs";
70
71 // field name constants that don't directly correspond to member variables
72 const std::string kInfoFieldName = "info";
73 const std::string kIsReplicaSetFieldName = "isreplicaset";
74 const std::string kErrmsgFieldName = "errmsg";
75 const std::string kCodeFieldName = "code";
76
77 } // namespace
78
IsMasterResponse()79 IsMasterResponse::IsMasterResponse()
80 : _isMaster(false),
81 _isMasterSet(false),
82 _secondary(false),
83 _isSecondarySet(false),
84 _setNameSet(false),
85 _setVersion(0),
86 _setVersionSet(false),
87 _hostsSet(false),
88 _passivesSet(false),
89 _arbitersSet(false),
90 _primarySet(false),
91 _arbiterOnly(false),
92 _arbiterOnlySet(false),
93 _passive(false),
94 _passiveSet(false),
95 _hidden(false),
96 _hiddenSet(false),
97 _buildIndexes(true),
98 _buildIndexesSet(false),
99 _slaveDelay(0),
100 _slaveDelaySet(false),
101 _tagsSet(false),
102 _meSet(false),
103 _electionId(OID()),
104 _configSet(true),
105 _shutdownInProgress(false) {}
106
addToBSON(BSONObjBuilder * builder,bool useLegacyResponseFields) const107 void IsMasterResponse::addToBSON(BSONObjBuilder* builder, bool useLegacyResponseFields) const {
108 if (_hostsSet) {
109 std::vector<std::string> hosts;
110 for (size_t i = 0; i < _hosts.size(); ++i) {
111 hosts.push_back(_hosts[i].toString());
112 }
113 builder->append(kHostsFieldName, hosts);
114 }
115 if (_passivesSet) {
116 std::vector<std::string> passives;
117 for (size_t i = 0; i < _passives.size(); ++i) {
118 passives.push_back(_passives[i].toString());
119 }
120 builder->append(kPassivesFieldName, passives);
121 }
122 if (_arbitersSet) {
123 std::vector<std::string> arbiters;
124 for (size_t i = 0; i < _arbiters.size(); ++i) {
125 arbiters.push_back(_arbiters[i].toString());
126 }
127 builder->append(kArbitersFieldName, arbiters);
128 }
129
130 if (_setNameSet) {
131 builder->append(kSetNameFieldName, _setName);
132 }
133
134 if (_shutdownInProgress) {
135 builder->append(kCodeFieldName, ErrorCodes::ShutdownInProgress);
136 builder->append(kErrmsgFieldName, "replication shutdown in progress");
137 return;
138 }
139
140 if (!_configSet) {
141 if (useLegacyResponseFields) {
142 builder->append(kIsMasterFieldName, false);
143 } else {
144 builder->append(kIsWritablePrimaryFieldName, false);
145 }
146 builder->append(kSecondaryFieldName, false);
147 builder->append(kInfoFieldName, "Does not have a valid replica set config");
148 builder->append(kIsReplicaSetFieldName, true);
149 return;
150 }
151
152 invariant(_setVersionSet);
153 builder->append(kSetVersionFieldName, static_cast<int>(_setVersion));
154 invariant(_isMasterSet);
155 if (useLegacyResponseFields) {
156 builder->append(kIsMasterFieldName, _isMaster);
157 } else {
158 builder->append(kIsWritablePrimaryFieldName, _isMaster);
159 }
160 invariant(_isSecondarySet);
161 builder->append(kSecondaryFieldName, _secondary);
162
163 if (_primarySet)
164 builder->append(kPrimaryFieldName, _primary.toString());
165 if (_arbiterOnlySet)
166 builder->append(kArbiterOnlyFieldName, _arbiterOnly);
167 if (_passiveSet)
168 builder->append(kPassiveFieldName, _passive);
169 if (_hiddenSet)
170 builder->append(kHiddenFieldName, _hidden);
171 if (_buildIndexesSet)
172 builder->append(kBuildIndexesFieldName, _buildIndexes);
173 if (_slaveDelaySet) {
174 if (useLegacyResponseFields) {
175 builder->appendIntOrLL(kSlaveDelayFieldName, durationCount<Seconds>(_slaveDelay));
176 } else {
177 builder->appendIntOrLL(kSecondaryDelaySecsFieldName,
178 durationCount<Seconds>(_slaveDelay));
179 }
180 }
181 if (_tagsSet) {
182 BSONObjBuilder tags(builder->subobjStart(kTagsFieldName));
183 for (unordered_map<std::string, std::string>::const_iterator it = _tags.begin();
184 it != _tags.end();
185 ++it) {
186 tags.append(it->first, it->second);
187 }
188 }
189 invariant(_meSet);
190 builder->append(kMeFieldName, _me.toString());
191 if (_electionId.isSet())
192 builder->append(kElectionIdFieldName, _electionId);
193 if (_lastWrite || _lastMajorityWrite) {
194 BSONObjBuilder lastWrite(builder->subobjStart(kLastWriteFieldName));
195 if (_lastWrite) {
196 lastWrite.append(kLastWriteOpTimeFieldName, _lastWrite->opTime.toBSON());
197 lastWrite.appendTimeT(kLastWriteDateFieldName, _lastWrite->value);
198 }
199 if (_lastMajorityWrite) {
200 lastWrite.append(kLastMajorityWriteOpTimeFieldName,
201 _lastMajorityWrite->opTime.toBSON());
202 lastWrite.appendTimeT(kLastMajorityWriteDateFieldName, _lastMajorityWrite->value);
203 }
204 }
205 }
206
toBSON(bool useLegacyResponseFields) const207 BSONObj IsMasterResponse::toBSON(bool useLegacyResponseFields) const {
208 BSONObjBuilder builder;
209 addToBSON(&builder, useLegacyResponseFields);
210 return builder.obj();
211 }
212
initialize(const BSONObj & doc)213 Status IsMasterResponse::initialize(const BSONObj& doc) {
214 Status status = bsonExtractBooleanField(doc, kIsMasterFieldName, &_isMaster);
215 if (!status.isOK()) {
216 return status;
217 }
218 _isMasterSet = true;
219 status = bsonExtractBooleanField(doc, kSecondaryFieldName, &_secondary);
220 if (!status.isOK()) {
221 return status;
222 }
223 _isSecondarySet = true;
224 if (doc.hasField(kInfoFieldName)) {
225 if (_isMaster || _secondary || !doc.hasField(kIsReplicaSetFieldName) ||
226 !doc[kIsReplicaSetFieldName].booleanSafe()) {
227 return Status(ErrorCodes::FailedToParse,
228 str::stream() << "Expected presence of \"" << kInfoFieldName
229 << "\" field to indicate no valid config loaded, but other "
230 "fields weren't as we expected");
231 }
232 _configSet = false;
233 return Status::OK();
234 } else {
235 if (doc.hasField(kIsReplicaSetFieldName)) {
236 return Status(ErrorCodes::FailedToParse,
237 str::stream() << "Found \"" << kIsReplicaSetFieldName
238 << "\" field which should indicate that no valid config "
239 "is loaded, but we didn't also have an \""
240 << kInfoFieldName
241 << "\" field as we expected");
242 }
243 }
244
245 status = bsonExtractStringField(doc, kSetNameFieldName, &_setName);
246 if (!status.isOK()) {
247 return status;
248 }
249 _setNameSet = true;
250 status = bsonExtractIntegerField(doc, kSetVersionFieldName, &_setVersion);
251 if (!status.isOK()) {
252 return status;
253 }
254 _setVersionSet = true;
255
256 if (doc.hasField(kHostsFieldName)) {
257 BSONElement hostsElement;
258 status = bsonExtractTypedField(doc, kHostsFieldName, Array, &hostsElement);
259 if (!status.isOK()) {
260 return status;
261 }
262 for (BSONObjIterator it(hostsElement.Obj()); it.more();) {
263 BSONElement hostElement = it.next();
264 if (hostElement.type() != String) {
265 return Status(ErrorCodes::TypeMismatch,
266 str::stream() << "Elements in \"" << kHostsFieldName
267 << "\" array of isMaster response must be of type "
268 << typeName(String)
269 << " but found type "
270 << typeName(hostElement.type()));
271 }
272 _hosts.push_back(HostAndPort(hostElement.String()));
273 }
274 _hostsSet = true;
275 }
276
277 if (doc.hasField(kPassivesFieldName)) {
278 BSONElement passivesElement;
279 status = bsonExtractTypedField(doc, kPassivesFieldName, Array, &passivesElement);
280 if (!status.isOK()) {
281 return status;
282 }
283 for (BSONObjIterator it(passivesElement.Obj()); it.more();) {
284 BSONElement passiveElement = it.next();
285 if (passiveElement.type() != String) {
286 return Status(ErrorCodes::TypeMismatch,
287 str::stream() << "Elements in \"" << kPassivesFieldName
288 << "\" array of isMaster response must be of type "
289 << typeName(String)
290 << " but found type "
291 << typeName(passiveElement.type()));
292 }
293 _passives.push_back(HostAndPort(passiveElement.String()));
294 }
295 _passivesSet = true;
296 }
297
298 if (doc.hasField(kArbitersFieldName)) {
299 BSONElement arbitersElement;
300 status = bsonExtractTypedField(doc, kArbitersFieldName, Array, &arbitersElement);
301 if (!status.isOK()) {
302 return status;
303 }
304 for (BSONObjIterator it(arbitersElement.Obj()); it.more();) {
305 BSONElement arbiterElement = it.next();
306 if (arbiterElement.type() != String) {
307 return Status(ErrorCodes::TypeMismatch,
308 str::stream() << "Elements in \"" << kArbitersFieldName
309 << "\" array of isMaster response must be of type "
310 << typeName(String)
311 << " but found type "
312 << typeName(arbiterElement.type()));
313 }
314 _arbiters.push_back(HostAndPort(arbiterElement.String()));
315 }
316 _arbitersSet = true;
317 }
318
319 if (doc.hasField(kPrimaryFieldName)) {
320 std::string primaryString;
321 status = bsonExtractStringField(doc, kPrimaryFieldName, &primaryString);
322 if (!status.isOK()) {
323 return status;
324 }
325 _primary = HostAndPort(primaryString);
326 _primarySet = true;
327 }
328
329 if (doc.hasField(kArbiterOnlyFieldName)) {
330 status = bsonExtractBooleanField(doc, kArbiterOnlyFieldName, &_arbiterOnly);
331 if (!status.isOK()) {
332 return status;
333 }
334 _arbiterOnlySet = true;
335 }
336
337 if (doc.hasField(kPassiveFieldName)) {
338 status = bsonExtractBooleanField(doc, kPassiveFieldName, &_passive);
339 if (!status.isOK()) {
340 return status;
341 }
342 _passiveSet = true;
343 }
344
345 if (doc.hasField(kHiddenFieldName)) {
346 status = bsonExtractBooleanField(doc, kHiddenFieldName, &_hidden);
347 if (!status.isOK()) {
348 return status;
349 }
350 _hiddenSet = true;
351 }
352
353 if (doc.hasField(kBuildIndexesFieldName)) {
354 status = bsonExtractBooleanField(doc, kBuildIndexesFieldName, &_buildIndexes);
355 if (!status.isOK()) {
356 return status;
357 }
358 _buildIndexesSet = true;
359 }
360
361 if (doc.hasField(kSlaveDelayFieldName)) {
362 long long slaveDelaySecs;
363 status = bsonExtractIntegerField(doc, kSlaveDelayFieldName, &slaveDelaySecs);
364 if (!status.isOK()) {
365 return status;
366 }
367 _slaveDelaySet = true;
368 _slaveDelay = Seconds(slaveDelaySecs);
369 }
370
371 if (doc.hasField(kTagsFieldName)) {
372 BSONElement tagsElement;
373 status = bsonExtractTypedField(doc, kTagsFieldName, Object, &tagsElement);
374 if (!status.isOK()) {
375 return status;
376 }
377 for (BSONObjIterator it(tagsElement.Obj()); it.more();) {
378 BSONElement tagElement = it.next();
379 if (tagElement.type() != String) {
380 return Status(ErrorCodes::TypeMismatch,
381 str::stream() << "Elements in \"" << kTagsFieldName
382 << "\" obj "
383 "of isMaster response must be of type "
384 << typeName(String)
385 << " but found type "
386 << typeName(tagsElement.type()));
387 }
388 _tags[tagElement.fieldNameStringData().toString()] = tagElement.String();
389 }
390 _tagsSet = true;
391 }
392
393 if (doc.hasField(kElectionIdFieldName)) {
394 BSONElement electionIdElem;
395 status = bsonExtractTypedField(doc, kElectionIdFieldName, jstOID, &electionIdElem);
396 if (!status.isOK()) {
397 return status;
398 }
399 _electionId = electionIdElem.OID();
400 }
401
402 if (doc.hasField(kLastWriteFieldName)) {
403 BSONElement lastWriteElement;
404 status = bsonExtractTypedField(doc, kLastWriteFieldName, Object, &lastWriteElement);
405 if (!status.isOK()) {
406 return status;
407 }
408 BSONObj lastWriteObj = lastWriteElement.Obj();
409 bool lastWriteOpTimeSet = false;
410 bool lastWriteDateSet = false;
411 if (auto lastWriteOpTimeElement = lastWriteObj[kLastWriteOpTimeFieldName]) {
412 if (lastWriteOpTimeElement.type() != Object) {
413 return Status(ErrorCodes::TypeMismatch,
414 str::stream() << "Elements in \"" << kLastWriteOpTimeFieldName
415 << "\" obj "
416 "of isMaster response must be of type "
417 << typeName(Object)
418 << " but found type "
419 << typeName(lastWriteOpTimeElement.type()));
420 }
421 auto lastWriteOpTime = OpTime::parseFromOplogEntry(lastWriteOpTimeElement.Obj());
422 if (!lastWriteOpTime.isOK()) {
423 return lastWriteOpTime.getStatus();
424 }
425 if (_lastWrite) {
426 _lastWrite->opTime = lastWriteOpTime.getValue();
427 } else {
428 _lastWrite = OpTimeWith<time_t>(0, lastWriteOpTime.getValue());
429 }
430 lastWriteOpTimeSet = true;
431 }
432 if (auto lastWriteDateElement = lastWriteObj[kLastWriteDateFieldName]) {
433 if (lastWriteDateElement.type() != Date) {
434 return Status(ErrorCodes::TypeMismatch,
435 str::stream() << "Elements in \"" << kLastWriteDateFieldName
436 << "\" obj "
437 "of isMaster response must be of type "
438 << typeName(Date)
439 << " but found type "
440 << typeName(lastWriteDateElement.type()));
441 }
442 if (_lastWrite) {
443 _lastWrite->value = lastWriteDateElement.Date().toTimeT();
444 } else {
445 _lastWrite = OpTimeWith<time_t>(lastWriteDateElement.Date().toTimeT(), OpTime());
446 }
447 lastWriteDateSet = true;
448 }
449 invariant(lastWriteOpTimeSet == lastWriteDateSet);
450
451 bool lastMajorityWriteOpTimeSet = false;
452 bool lastMajorityWriteDateSet = false;
453 if (auto lastMajorityWriteOpTimeElement = lastWriteObj[kLastMajorityWriteOpTimeFieldName]) {
454 if (lastMajorityWriteOpTimeElement.type() != Object) {
455 return Status(ErrorCodes::TypeMismatch,
456 str::stream() << "Elements in \"" << kLastMajorityWriteOpTimeFieldName
457 << "\" obj "
458 "of isMaster response must be of type "
459 << typeName(Object)
460 << " but found type "
461 << typeName(lastMajorityWriteOpTimeElement.type()));
462 }
463 auto lastMajorityWriteOpTime =
464 OpTime::parseFromOplogEntry(lastMajorityWriteOpTimeElement.Obj());
465 if (!lastMajorityWriteOpTime.isOK()) {
466 return lastMajorityWriteOpTime.getStatus();
467 }
468 if (_lastMajorityWrite) {
469 _lastMajorityWrite->opTime = lastMajorityWriteOpTime.getValue();
470 } else {
471 _lastMajorityWrite = OpTimeWith<time_t>(0, lastMajorityWriteOpTime.getValue());
472 }
473 lastMajorityWriteOpTimeSet = true;
474 }
475 if (auto lastMajorityWriteDateElement = lastWriteObj[kLastMajorityWriteDateFieldName]) {
476 if (lastMajorityWriteDateElement.type() != Date) {
477 return Status(ErrorCodes::TypeMismatch,
478 str::stream() << "Elements in \"" << kLastMajorityWriteDateFieldName
479 << "\" obj "
480 "of isMaster response must be of type "
481 << typeName(Date)
482 << " but found type "
483 << typeName(lastMajorityWriteDateElement.type()));
484 }
485 if (_lastMajorityWrite) {
486 _lastMajorityWrite->value = lastMajorityWriteDateElement.Date().toTimeT();
487 } else {
488 _lastMajorityWrite =
489 OpTimeWith<time_t>(lastMajorityWriteDateElement.Date().toTimeT(), OpTime());
490 }
491 lastMajorityWriteDateSet = true;
492 }
493 invariant(lastMajorityWriteOpTimeSet == lastMajorityWriteDateSet);
494 }
495
496 std::string meString;
497 status = bsonExtractStringField(doc, kMeFieldName, &meString);
498 if (!status.isOK()) {
499 return status;
500 }
501 _me = HostAndPort(meString);
502 _meSet = true;
503
504 return Status::OK();
505 }
506
setIsMaster(bool isMaster)507 void IsMasterResponse::setIsMaster(bool isMaster) {
508 _isMasterSet = true;
509 _isMaster = isMaster;
510 }
511
setIsSecondary(bool secondary)512 void IsMasterResponse::setIsSecondary(bool secondary) {
513 _isSecondarySet = true;
514 _secondary = secondary;
515 }
516
setReplSetName(const std::string & setName)517 void IsMasterResponse::setReplSetName(const std::string& setName) {
518 _setNameSet = true;
519 _setName = setName;
520 }
521
setReplSetVersion(long long version)522 void IsMasterResponse::setReplSetVersion(long long version) {
523 _setVersionSet = true;
524 _setVersion = version;
525 }
526
addHost(const HostAndPort & host)527 void IsMasterResponse::addHost(const HostAndPort& host) {
528 _hostsSet = true;
529 _hosts.push_back(host);
530 }
531
addPassive(const HostAndPort & passive)532 void IsMasterResponse::addPassive(const HostAndPort& passive) {
533 _passivesSet = true;
534 _passives.push_back(passive);
535 }
536
addArbiter(const HostAndPort & arbiter)537 void IsMasterResponse::addArbiter(const HostAndPort& arbiter) {
538 _arbitersSet = true;
539 _arbiters.push_back(arbiter);
540 }
541
setPrimary(const HostAndPort & primary)542 void IsMasterResponse::setPrimary(const HostAndPort& primary) {
543 _primarySet = true;
544 _primary = primary;
545 }
546
setIsArbiterOnly(bool arbiterOnly)547 void IsMasterResponse::setIsArbiterOnly(bool arbiterOnly) {
548 _arbiterOnlySet = true;
549 _arbiterOnly = arbiterOnly;
550 }
551
setIsPassive(bool passive)552 void IsMasterResponse::setIsPassive(bool passive) {
553 _passiveSet = true;
554 _passive = passive;
555 }
556
setIsHidden(bool hidden)557 void IsMasterResponse::setIsHidden(bool hidden) {
558 _hiddenSet = true;
559 _hidden = hidden;
560 }
561
setShouldBuildIndexes(bool buildIndexes)562 void IsMasterResponse::setShouldBuildIndexes(bool buildIndexes) {
563 _buildIndexesSet = true;
564 _buildIndexes = buildIndexes;
565 }
566
setSlaveDelay(Seconds slaveDelay)567 void IsMasterResponse::setSlaveDelay(Seconds slaveDelay) {
568 _slaveDelaySet = true;
569 _slaveDelay = slaveDelay;
570 }
571
addTag(const std::string & tagKey,const std::string & tagValue)572 void IsMasterResponse::addTag(const std::string& tagKey, const std::string& tagValue) {
573 _tagsSet = true;
574 _tags[tagKey] = tagValue;
575 }
576
setMe(const HostAndPort & me)577 void IsMasterResponse::setMe(const HostAndPort& me) {
578 _meSet = true;
579 _me = me;
580 }
581
setElectionId(const OID & electionId)582 void IsMasterResponse::setElectionId(const OID& electionId) {
583 _electionId = electionId;
584 }
585
setLastWrite(const OpTime & lastWriteOpTime,const time_t lastWriteDate)586 void IsMasterResponse::setLastWrite(const OpTime& lastWriteOpTime, const time_t lastWriteDate) {
587 _lastWrite = OpTimeWith<time_t>(lastWriteDate, lastWriteOpTime);
588 }
589
setLastMajorityWrite(const OpTime & lastMajorityWriteOpTime,const time_t lastMajorityWriteDate)590 void IsMasterResponse::setLastMajorityWrite(const OpTime& lastMajorityWriteOpTime,
591 const time_t lastMajorityWriteDate) {
592 _lastMajorityWrite = OpTimeWith<time_t>(lastMajorityWriteDate, lastMajorityWriteOpTime);
593 }
594
markAsNoConfig()595 void IsMasterResponse::markAsNoConfig() {
596 _configSet = false;
597 }
598
markAsShutdownInProgress()599 void IsMasterResponse::markAsShutdownInProgress() {
600 _shutdownInProgress = true;
601 }
602
603 } // namespace repl
604 } // namespace mongo
605