void ReplicationCoordinatorImpl::_onFreshnessCheckComplete() { stdx::lock_guard<stdx::mutex> lk(_mutex); invariant(_freshnessChecker); invariant(!_electCmdRunner); LoseElectionGuard lossGuard(_topCoord.get(), _replExecutor.get(), &_freshnessChecker, &_electCmdRunner, &_electionFinishedEvent); if (_freshnessChecker->isCanceled()) { LOG(2) << "Election canceled during freshness check phase"; return; } const Date_t now(_replExecutor->now()); const FreshnessChecker::ElectionAbortReason abortReason = _freshnessChecker->shouldAbortElection(); // need to not sleep after last time sleeping, switch (abortReason) { case FreshnessChecker::None: break; case FreshnessChecker::FreshnessTie: if ((_selfIndex != 0) && !_sleptLastElection) { const auto ms = Milliseconds(_nextRandomInt64_inlock(1000) + 50); const Date_t nextCandidateTime = now + ms; log() << "possible election tie; sleeping " << ms << " until " << dateToISOStringLocal(nextCandidateTime); _topCoord->setElectionSleepUntil(nextCandidateTime); _scheduleWorkAt(nextCandidateTime, stdx::bind(&ReplicationCoordinatorImpl::_recoverFromElectionTie, this, stdx::placeholders::_1)); _sleptLastElection = true; return; } _sleptLastElection = false; break; case FreshnessChecker::FresherNodeFound: log() << "not electing self, we are not freshest"; return; case FreshnessChecker::QuorumUnreachable: log() << "not electing self, we could not contact enough voting members"; return; default: log() << "not electing self due to election abort message :" << static_cast<int>(abortReason); return; } log() << "running for election" << (abortReason == FreshnessChecker::FreshnessTie ? "; slept last election, so running regardless of possible tie" : ""); // Secure our vote for ourself first if (!_topCoord->voteForMyself(now)) { return; } _electCmdRunner.reset(new ElectCmdRunner); StatusWith<executor::TaskExecutor::EventHandle> nextPhaseEvh = _electCmdRunner->start( _replExecutor.get(), _rsConfig, _selfIndex, _topCoord->getMaybeUpHostAndPorts()); if (nextPhaseEvh.getStatus() == ErrorCodes::ShutdownInProgress) { return; } fassert(18685, nextPhaseEvh.getStatus()); _replExecutor ->onEvent(nextPhaseEvh.getValue(), stdx::bind(&ReplicationCoordinatorImpl::_onElectCmdRunnerComplete, this)) .status_with_transitional_ignore(); lossGuard.dismiss(); }
void BSONElement::jsonStringStream(JsonStringFormat format, bool includeFieldNames, int pretty, std::stringstream& s) const { if (includeFieldNames) s << '"' << escape(fieldName()) << "\" : "; switch (type()) { case mongo::String: case Symbol: s << '"' << escape(string(valuestr(), valuestrsize() - 1)) << '"'; break; case NumberLong: if (format == TenGen) { s << "NumberLong(" << _numberLong() << ")"; } else { s << "{ \"$numberLong\" : \"" << _numberLong() << "\" }"; } break; case NumberInt: if (format == TenGen) { s << "NumberInt(" << _numberInt() << ")"; break; } case NumberDouble: if (number() >= -std::numeric_limits<double>::max() && number() <= std::numeric_limits<double>::max()) { auto origPrecision = s.precision(); auto guard = MakeGuard([&s, origPrecision]() { s.precision(origPrecision); }); s.precision(16); s << number(); } // This is not valid JSON, but according to RFC-4627, "Numeric values that cannot be // represented as sequences of digits (such as Infinity and NaN) are not permitted." so // we are accepting the fact that if we have such values we cannot output valid JSON. else if (std::isnan(number())) { s << "NaN"; } else if (std::isinf(number())) { s << (number() > 0 ? "Infinity" : "-Infinity"); } else { StringBuilder ss; ss << "Number " << number() << " cannot be represented in JSON"; string message = ss.str(); massert(10311, message.c_str(), false); } break; case NumberDecimal: if (format == TenGen) s << "NumberDecimal(\""; else s << "{ \"$numberDecimal\" : \""; // Recognize again that this is not valid JSON according to RFC-4627. // Also, treat -NaN and +NaN as the same thing for MongoDB. if (numberDecimal().isNaN()) { s << "NaN"; } else if (numberDecimal().isInfinite()) { s << (numberDecimal().isNegative() ? "-Infinity" : "Infinity"); } else { s << numberDecimal().toString(); } if (format == TenGen) s << "\")"; else s << "\" }"; break; case mongo::Bool: s << (boolean() ? "true" : "false"); break; case jstNULL: s << "null"; break; case Undefined: if (format == Strict) { s << "{ \"$undefined\" : true }"; } else { s << "undefined"; } break; case Object: embeddedObject().jsonStringStream(format, pretty, false, s); break; case mongo::Array: { if (embeddedObject().isEmpty()) { s << "[]"; break; } s << "[ "; BSONObjIterator i(embeddedObject()); BSONElement e = i.next(); if (!e.eoo()) { int count = 0; while (1) { if (pretty) { s << '\n'; for (int x = 0; x < pretty; x++) s << " "; } if (strtol(e.fieldName(), 0, 10) > count) { s << "undefined"; } else { e.jsonStringStream(format, false, pretty ? pretty + 1 : 0, s); e = i.next(); } count++; if (e.eoo()) break; s << ", "; } } s << " ]"; break; } case DBRef: { if (format == TenGen) s << "Dbref( "; else s << "{ \"$ref\" : "; s << '"' << valuestr() << "\", "; if (format != TenGen) s << "\"$id\" : "; s << '"' << mongo::OID::from(valuestr() + valuestrsize()) << "\" "; if (format == TenGen) s << ')'; else s << '}'; break; } case jstOID: if (format == TenGen) { s << "ObjectId( "; } else { s << "{ \"$oid\" : "; } s << '"' << __oid() << '"'; if (format == TenGen) { s << " )"; } else { s << " }"; } break; case BinData: { ConstDataCursor reader(value()); const int len = reader.readAndAdvance<LittleEndian<int>>(); BinDataType type = static_cast<BinDataType>(reader.readAndAdvance<uint8_t>()); s << "{ \"$binary\" : \""; base64::encode(s, reader.view(), len); auto origFill = s.fill(); auto origFmtF = s.flags(); auto origWidth = s.width(); auto guard = MakeGuard([&s, origFill, origFmtF, origWidth] { s.fill(origFill); s.setf(origFmtF); s.width(origWidth); }); s.setf(std::ios_base::hex, std::ios_base::basefield); s << "\", \"$type\" : \""; s.width(2); s.fill('0'); s << type; s << "\" }"; break; } case mongo::Date: if (format == Strict) { Date_t d = date(); s << "{ \"$date\" : "; // The two cases in which we cannot convert Date_t::millis to an ISO Date string are // when the date is too large to format (SERVER-13760), and when the date is before // the epoch (SERVER-11273). Since Date_t internally stores millis as an unsigned // long long, despite the fact that it is logically signed (SERVER-8573), this check // handles both the case where Date_t::millis is too large, and the case where // Date_t::millis is negative (before the epoch). if (d.isFormattable()) { s << "\"" << dateToISOStringLocal(date()) << "\""; } else { s << "{ \"$numberLong\" : \"" << d.toMillisSinceEpoch() << "\" }"; } s << " }"; } else { s << "Date( "; if (pretty) { Date_t d = date(); // The two cases in which we cannot convert Date_t::millis to an ISO Date string // are when the date is too large to format (SERVER-13760), and when the date is // before the epoch (SERVER-11273). Since Date_t internally stores millis as an // unsigned long long, despite the fact that it is logically signed // (SERVER-8573), this check handles both the case where Date_t::millis is too // large, and the case where Date_t::millis is negative (before the epoch). if (d.isFormattable()) { s << "\"" << dateToISOStringLocal(date()) << "\""; } else { // FIXME: This is not parseable by the shell, since it may not fit in a // float s << d.toMillisSinceEpoch(); } } else { s << date().asInt64(); } s << " )"; } break; case RegEx: if (format == Strict) { s << "{ \"$regex\" : \"" << escape(regex()); s << "\", \"$options\" : \"" << regexFlags() << "\" }"; } else { s << "/" << escape(regex(), true) << "/"; // FIXME Worry about alpha order? for (const char* f = regexFlags(); *f; ++f) { switch (*f) { case 'g': case 'i': case 'm': s << *f; default: break; } } } break; case CodeWScope: { BSONObj scope = codeWScopeObject(); if (!scope.isEmpty()) { s << "{ \"$code\" : \"" << escape(_asCode()) << "\" , " << "\"$scope\" : " << scope.jsonString() << " }"; break; } } case Code: s << "\"" << escape(_asCode()) << "\""; break; case bsonTimestamp: if (format == TenGen) { s << "Timestamp( " << durationCount<Seconds>(timestampTime().toDurationSinceEpoch()) << ", " << timestampInc() << " )"; } else { s << "{ \"$timestamp\" : { \"t\" : " << durationCount<Seconds>(timestampTime().toDurationSinceEpoch()) << ", \"i\" : " << timestampInc() << " } }"; } break; case MinKey: s << "{ \"$minKey\" : 1 }"; break; case MaxKey: s << "{ \"$maxKey\" : 1 }"; break; default: StringBuilder ss; ss << "Cannot create a properly formatted JSON string with " << "element: " << toString() << " of type: " << type(); string message = ss.str(); massert(10312, message.c_str(), false); } }