// This function starts a program. In its input array it accepts either all commandline tokens // which will be executed, or a single Object which must have a field named "args" which contains // an array with all commandline tokens. The Object may have a field named "env" which contains an // object of Key Value pairs which will be loaded into the environment of the spawned process. BSONObj StartMongoProgram(const BSONObj& a, void* data) { _nokillop = true; BSONObj args = a; BSONObj env{}; BSONElement firstElement = args.firstElement(); if (firstElement.ok() && firstElement.isABSONObj()) { BSONObj subobj = firstElement.Obj(); BSONElement argsElem = subobj["args"]; BSONElement envElem = subobj["env"]; uassert(40098, "If StartMongoProgram is called with a BSONObj, " "it must contain an 'args' subobject." + args.toString(), argsElem.ok() && argsElem.isABSONObj()); args = argsElem.Obj(); if (envElem.ok() && envElem.isABSONObj()) { env = envElem.Obj(); } } ProgramRunner r(args, env); r.start(); invariant(registry.isPidRegistered(r.pid())); stdx::thread t(r); registry.registerReaderThread(r.pid(), std::move(t)); return BSON(string("") << r.pid().asLongLong()); }
Status SetNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); _val = modExpr; return Status::OK(); }
Status AddToSetNode::init(BSONElement modExpr, const CollatorInterface* collator) { invariant(modExpr.ok()); bool isEach = false; // If the value of 'modExpr' is an object whose first field is '$each', treat it as an $each. if (modExpr.type() == BSONType::Object) { auto firstElement = modExpr.Obj().firstElement(); if (firstElement && firstElement.fieldNameStringData() == "$each") { isEach = true; if (firstElement.type() != BSONType::Array) { return Status( ErrorCodes::TypeMismatch, str::stream() << "The argument to $each in $addToSet must be an array but it was of type " << typeName(firstElement.type())); } if (modExpr.Obj().nFields() > 1) { return Status(ErrorCodes::BadValue, str::stream() << "Found unexpected fields after $each in $addToSet: " << modExpr.Obj()); } _elements = firstElement.Array(); } } // If the value of 'modExpr' was not an $each, we append the entire element. if (!isEach) { _elements.push_back(modExpr); } setCollator(collator); return Status::OK(); }
void report() const { const OpTime &maxOpTimeSynced = _player->maxOpTimeSynced(); LOG(0) << "synced up to " << fmtOpTime(maxOpTimeSynced); if (!_rconn) { LOG(0) << endl; return; } Query lastQuery; lastQuery.sort("$natural", -1); BSONObj lastFields = BSON("ts" << 1); BSONObj lastObj = _rconn->conn().findOne(_oplogns, lastQuery, &lastFields); BSONElement tsElt = lastObj["ts"]; if (!tsElt.ok()) { warning() << "couldn't find last oplog entry on remote host" << endl; LOG(0) << endl; return; } OpTime lastOpTime = OpTime(tsElt.date()); LOG(0) << ", source has up to " << fmtOpTime(lastOpTime); if (maxOpTimeSynced == lastOpTime) { LOG(0) << ", fully synced." << endl; } else { int diff = lastOpTime.getSecs() - maxOpTimeSynced.getSecs(); if (diff > 0) { LOG(0) << ", " << (lastOpTime.getSecs() - maxOpTimeSynced.getSecs()) << " seconds behind source." << endl; } else { LOG(0) << ", less than 1 second behind source." << endl; } } _reportingTimer.reset(); }
bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string ns = dbname + "." + cmdObj.firstElement().valuestrsafe(); const NamespaceDetails* nsd = nsdetails(ns.c_str()); if (!cmdLine.quiet) { tlog() << "CMD: indexStats " << ns << endl; } if (!nsd) { errmsg = "ns not found"; return false; } IndexStatsParams params; // { index: _index_name } BSONElement indexName = cmdObj["index"]; if (!indexName.ok() || indexName.type() != String) { errmsg = "an index name is required, use {index: \"indexname\"}"; return false; } params.indexName = indexName.String(); BSONElement expandNodes = cmdObj["expandNodes"]; if (expandNodes.ok()) { if (expandNodes.type() != mongo::Array) { errmsg = "expandNodes must be an array of numbers"; return false; } vector<BSONElement> arr = expandNodes.Array(); for (vector<BSONElement>::const_iterator it = arr.begin(); it != arr.end(); ++it) { if (!it->isNumber()) { errmsg = "expandNodes must be an array of numbers"; return false; } params.expandNodes.push_back(int(it->Number())); } } BSONObjBuilder resultBuilder; if (!runInternal(nsd, params, errmsg, resultBuilder)) return false; result.appendElements(resultBuilder.obj()); return true; }
Status BitNode::init(BSONElement modExpr, const CollatorInterface* collator) { invariant(modExpr.ok()); if (modExpr.type() != mongo::Object) { return Status(ErrorCodes::BadValue, str::stream() << "The $bit modifier is not compatible with a " << typeName(modExpr.type()) << ". You must pass in an embedded document: " "{$bit: {field: {and/or/xor: #}}"); } for (const auto& curOp : modExpr.embeddedObject()) { const StringData payloadFieldName = curOp.fieldNameStringData(); BitwiseOp parsedOp; if (payloadFieldName == "and") { parsedOp.bitOperator = &SafeNum::bitAnd; } else if (payloadFieldName == "or") { parsedOp.bitOperator = &SafeNum::bitOr; } else if (payloadFieldName == "xor") { parsedOp.bitOperator = &SafeNum::bitXor; } else { return Status(ErrorCodes::BadValue, str::stream() << "The $bit modifier only supports 'and', 'or', and 'xor', not '" << payloadFieldName << "' which is an unknown operator: {" << curOp << "}"); } if ((curOp.type() != mongo::NumberInt) && (curOp.type() != mongo::NumberLong)) { return Status(ErrorCodes::BadValue, str::stream() << "The $bit modifier field must be an Integer(32/64 bit); a '" << typeName(curOp.type()) << "' is not supported here: {" << curOp << "}"); } parsedOp.operand = SafeNum(curOp); _opList.push_back(parsedOp); } if (_opList.empty()) { return Status(ErrorCodes::BadValue, str::stream() << "You must pass in at least one bitwise operation. " << "The format is: " "{$bit: {field: {and/or/xor: #}}"); } return Status::OK(); }
Status RenameNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); invariant(BSONType::String == modExpr.type()); FieldRef fromFieldRef(modExpr.fieldName()); FieldRef toFieldRef(modExpr.String()); if (modExpr.valueStringData().find('\0') != std::string::npos) { return Status(ErrorCodes::BadValue, "The 'to' field for $rename cannot contain an embedded null byte"); } // Parsing {$rename: {'from': 'to'}} places nodes in the UpdateNode tree for both the "from" and // "to" paths via UpdateObjectNode::parseAndMerge(), which will enforce this isUpdatable // property. dassert(fieldchecker::isUpdatable(fromFieldRef).isOK()); dassert(fieldchecker::isUpdatable(toFieldRef).isOK()); // Though we could treat this as a no-op, it is illegal in the current implementation. if (fromFieldRef == toFieldRef) { return Status(ErrorCodes::BadValue, str::stream() << "The source and target field for $rename must differ: " << modExpr); } if (fromFieldRef.isPrefixOf(toFieldRef) || toFieldRef.isPrefixOf(fromFieldRef)) { return Status(ErrorCodes::BadValue, str::stream() << "The source and target field for $rename must " "not be on the same path: " << modExpr); } size_t dummyPos; if (fieldchecker::isPositional(fromFieldRef, &dummyPos) || fieldchecker::hasArrayFilter(fromFieldRef)) { return Status(ErrorCodes::BadValue, str::stream() << "The source field for $rename may not be dynamic: " << fromFieldRef.dottedField()); } else if (fieldchecker::isPositional(toFieldRef, &dummyPos) || fieldchecker::hasArrayFilter(toFieldRef)) { return Status(ErrorCodes::BadValue, str::stream() << "The destination field for $rename may not be dynamic: " << toFieldRef.dottedField()); } _val = modExpr; return Status::OK(); }
Status ArithmeticNode::init(BSONElement modExpr, const CollatorInterface* collator) { invariant(modExpr.ok()); if (!modExpr.isNumber()) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Cannot " << getNameForOp(_op) << " with non-numeric argument: {" << modExpr << "}"); } _val = modExpr; return Status::OK(); }
bool attemptQuery(int queryOptions) { BSONObj res; auto_ptr<DBClientCursor> cursor(_rconn->conn().query( _oplogns, QUERY("ts" << GTE << _player->maxOpTimeSynced()), 0, 0, &res, queryOptions)); if (!cursor->more()) { log() << "oplog query returned no results, sleeping 10 seconds..." << endl; sleepsecs(10); log() << "retrying" << endl; return true; } BSONObj firstObj = cursor->next(); { BSONElement tsElt = firstObj["ts"]; if (!tsElt.ok()) { log() << "oplog format error: " << firstObj << " missing 'ts' field." << endl; logPosition(); return false; } OpTime firstTime(tsElt.date()); if (firstTime != _player->maxOpTimeSynced()) { throw CantFindTimestamp(firstTime); } } report(); while (running && cursor->more()) { while (running && cursor->moreInCurrentBatch()) { BSONObj obj = cursor->next(); LOG(2) << obj << endl; bool ok = _player->processObj(obj); if (!ok) { logPosition(); return false; } } _player->flushInserts(); if (_reportingTimer.seconds() >= _reportingPeriod) { report(); } } return true; }
Status PullNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); try { if (modExpr.type() == mongo::Object && !MatchExpressionParser::parsePathAcceptingKeyword( modExpr.embeddedObject().firstElement())) { _matcher = stdx::make_unique<ObjectMatcher>(modExpr.embeddedObject(), expCtx); } else if (modExpr.type() == mongo::Object || modExpr.type() == mongo::RegEx) { _matcher = stdx::make_unique<WrappedObjectMatcher>(modExpr, expCtx); } else { _matcher = stdx::make_unique<EqualityMatcher>(modExpr, expCtx->getCollator()); } } catch (AssertionException& exception) { return exception.toStatus(); } return Status::OK(); }
Status CurrentDateNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) { invariant(modExpr.ok()); if (modExpr.type() == BSONType::Bool) { _typeIsDate = true; } else if (modExpr.type() == BSONType::Object) { auto foundValidType = false; for (auto&& elem : modExpr.Obj()) { if (elem.fieldNameStringData() == kType) { if (elem.type() == BSONType::String) { if (elem.valueStringData() == kDate) { _typeIsDate = true; foundValidType = true; } else if (elem.valueStringData() == kTimestamp) { _typeIsDate = false; foundValidType = true; } } } else { return Status(ErrorCodes::BadValue, str::stream() << "Unrecognized $currentDate option: " << elem.fieldNameStringData()); } } if (!foundValidType) { return Status(ErrorCodes::BadValue, "The '$type' string field is required " "to be 'date' or 'timestamp': " "{$currentDate: {field : {$type: 'date'}}}"); } } else { return Status(ErrorCodes::BadValue, str::stream() << typeName(modExpr.type()) << " is not valid type for $currentDate." " Please use a boolean ('true')" " or a $type expression ({$type: 'timestamp/date'})."); } return Status::OK(); }
Status ModifierSet::init(const BSONElement& modExpr, const Options& opts, bool* positional) { // // field name analysis // // Break down the field name into its 'dotted' components (aka parts) and check that // the field is fit for updates _fieldRef.parse(modExpr.fieldName()); Status status = fieldchecker::isUpdatable(_fieldRef); if (! status.isOK()) { return status; } // If a $-positional operator was used, get the index in which it occurred // and ensure only one occurrence. size_t foundCount; bool foundDollar = fieldchecker::isPositional(_fieldRef, &_posDollar, &foundCount); if (positional) *positional = foundDollar; if (foundDollar && foundCount > 1) { return Status(ErrorCodes::BadValue, str::stream() << "Too many positional (i.e. '$') elements found in path '" << _fieldRef.dottedField() << "'"); } // // value analysis // if (!modExpr.ok()) return Status(ErrorCodes::BadValue, "cannot $set an empty value"); _val = modExpr; _modOptions = opts; return Status::OK(); }
void Dictionary::open(const BSONObj &info, const mongo::Descriptor &descriptor, const bool may_create, const bool hot_index) { int readPageSize = 65536; int pageSize = 4 * 1024 * 1024; TOKU_COMPRESSION_METHOD compression = TOKU_ZLIB_WITHOUT_CHECKSUM_METHOD; BSONObj key_pattern = info["key"].Obj(); BSONElement e; e = info["readPageSize"]; if (e.ok() && !e.isNull()) { readPageSize = BytesQuantity<int>(e); uassert(16743, "readPageSize must be a number > 0.", readPageSize > 0); TOKULOG(1) << "db " << _dname << ", using read page size " << readPageSize << endl; } e = info["pageSize"]; if (e.ok() && !e.isNull()) { pageSize = BytesQuantity<int>(e); uassert(16445, "pageSize must be a number > 0.", pageSize > 0); TOKULOG(1) << "db " << _dname << ", using page size " << pageSize << endl; } e = info["compression"]; if (e.ok() && !e.isNull()) { std::string str = e.String(); if (str == "lzma") { compression = TOKU_LZMA_METHOD; } else if (str == "quicklz") { compression = TOKU_QUICKLZ_METHOD; } else if (str == "zlib") { compression = TOKU_ZLIB_WITHOUT_CHECKSUM_METHOD; } else if (str == "none") { compression = TOKU_NO_COMPRESSION; } else { uassert(16442, "compression must be one of: lzma, quicklz, zlib, none.", false); } TOKULOG(1) << "db " << _dname << ", using compression method \"" << str << "\"" << endl; } int r = _db->set_readpagesize(_db, readPageSize); if (r != 0) { handle_ydb_error(r); } r = _db->set_pagesize(_db, pageSize); if (r != 0) { handle_ydb_error(r); } r = _db->set_compression_method(_db, compression); if (r != 0) { handle_ydb_error(r); } // If this is a non-creating open for a read-only (or non-existent) // transaction, we can use an alternate stack since there's nothing // to roll back and no locktree locks to hold. const bool needAltTxn = !may_create && (!cc().hasTxn() || cc().txn().readOnly()); scoped_ptr<Client::AlternateTransactionStack> altStack(!needAltTxn ? NULL : new Client::AlternateTransactionStack()); scoped_ptr<Client::Transaction> altTxn(!needAltTxn ? NULL : new Client::Transaction(0)); const int db_flags = may_create ? DB_CREATE : 0; r = _db->open(_db, cc().txn().db_txn(), _dname.c_str(), NULL, DB_BTREE, db_flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); if (r == ENOENT && !may_create) { throw NeedsCreate(); } if (r != 0) { handle_ydb_error(r); } if (may_create) { set_db_descriptor(_db, descriptor, hot_index); } verify_or_upgrade_db_descriptor(_db, descriptor, hot_index); if (altTxn.get() != NULL) { altTxn->commit(); } }
/* called on a reconfig AND on initiate throws @param initial true when initiating */ void checkMembersUpForConfigChange(const ReplSetConfig& cfg, BSONObjBuilder& result, bool initial) { int failures = 0, allVotes = 0, allowableFailures = 0; int me = 0; stringstream selfs; for( vector<ReplSetConfig::MemberCfg>::const_iterator i = cfg.members.begin(); i != cfg.members.end(); i++ ) { if( i->h.isSelf() ) { me++; if( me > 1 ) selfs << ','; selfs << i->h.toString(); if( !i->potentiallyHot() ) { uasserted(13420, "initiation and reconfiguration of a replica set must be sent to a node that can become primary"); } } allVotes += i->votes; } allowableFailures = allVotes - (allVotes/2 + 1); uassert(13278, "bad config: isSelf is true for multiple hosts: " + selfs.str(), me <= 1); // dups? if( me != 1 ) { stringstream ss; ss << "can't find self in the replset config"; if( !cmdLine.isDefaultPort() ) ss << " my port: " << cmdLine.port; if( me != 0 ) ss << " found: " << me; uasserted(13279, ss.str()); } vector<string> down; for( vector<ReplSetConfig::MemberCfg>::const_iterator i = cfg.members.begin(); i != cfg.members.end(); i++ ) { // we know we're up if (i->h.isSelf()) { continue; } BSONObj res; { bool ok = false; try { ok = requestHeartbeat(cfg._id, "", i->h.toString(), res, -1, initial/*check if empty*/); if (ok) { BSONElement vElt = res["v"]; if (vElt.ok()) { int theirVersion = res["v"].Int(); if( theirVersion >= cfg.version ) { stringstream ss; ss << "replSet member " << i->h.toString() << " has too new a config version (" << theirVersion << ") to reconfigure"; uasserted(13259, ss.str()); } } } } catch(DBException& e) { log() << "replSet cmufcc requestHeartbeat " << i->h.toString() << " : " << e.toString() << rsLog; } catch(...) { log() << "replSet cmufcc error exception in requestHeartbeat?" << rsLog; } if (res.getBoolField("protocolVersionMismatch")) { uasserted(16817, "member " + i->h.toString() + " has a protocol version that is incompatible with ours: " + res.toString()); } if( res.getBoolField("mismatch") ) uasserted(13145, "set name does not match the set name host " + i->h.toString() + " expects"); if( *res.getStringField("set") ) { if( cfg.version <= 1 ) { // this was to be initiation, no one should be initiated already. uasserted(13256, "member " + i->h.toString() + " is already initiated"); } else { // Assure no one has a newer config. if( res["v"].Int() >= cfg.version ) { uasserted(13341, "member " + i->h.toString() + " has a config version >= to the new cfg version; cannot change config"); } } } if( !ok && !res["rs"].trueValue() ) { down.push_back(i->h.toString()); if( !res.isEmpty() ) { /* strange. got a response, but not "ok". log it. */ log() << "replSet warning " << i->h.toString() << " replied: " << res.toString() << rsLog; } bool allowFailure = false; failures += i->votes; if( !initial && failures <= allowableFailures ) { const Member* m = theReplSet->findById( i->_id ); if( m ) { verify( m->h().toString() == i->h.toString() ); } // it's okay if the down member isn't part of the config, // we might be adding a new member that isn't up yet allowFailure = true; } if( !allowFailure ) { string msg = string("need all members up to initiate, not ok : ") + i->h.toString(); if( !initial ) msg = string("need most members up to reconfigure, not ok : ") + i->h.toString(); uasserted(13144, msg); } } } if( initial ) { bool hasData = res["hasData"].Bool(); uassert(13311, "member " + i->h.toString() + " has data already, cannot initiate set. All members except initiator must be empty.", !hasData || i->h.isSelf()); } } if (down.size() > 0) { result.append("down", down); } }
Status UnsetNode::init(BSONElement modExpr, const boost::intrusive_ptr<ExpressionContext>& expCtx) { // Note that we don't need to store modExpr, because $unset does not do anything with its value. invariant(modExpr.ok()); return Status::OK(); }
Status ReplSetHeartbeatResponse::initialize(const BSONObj& doc) { // Old versions set this even though they returned not "ok" _mismatch = doc[kMismatchFieldName].trueValue(); if (_mismatch) return Status(ErrorCodes::InconsistentReplicaSetNames, "replica set name doesn't match."); // Old versions sometimes set the replica set name ("set") but ok:0 const BSONElement replSetNameElement = doc[kReplSetFieldName]; if (replSetNameElement.eoo()) { _setName.clear(); } else 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())); } else { _setName = replSetNameElement.String(); } if (_setName.empty() && !doc[kOkFieldName].trueValue()) { std::string errMsg = doc[kErrMsgFieldName].str(); BSONElement errCodeElem = doc[kErrorCodeFieldName]; if (errCodeElem.ok()) { if (!errCodeElem.isNumber()) return Status(ErrorCodes::BadValue, "Error code is not a number!"); int errorCode = errCodeElem.numberInt(); return Status(ErrorCodes::Error(errorCode), errMsg); } return Status(ErrorCodes::UnknownError, errMsg); } const BSONElement hasDataElement = doc[kHasDataFieldName]; _hasDataSet = !hasDataElement.eoo(); _hasData = hasDataElement.trueValue(); 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) { _electionTimeSet = 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 response 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(); } _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); } _stateSet = true; _state = MemberState(static_cast<int>(stateInt)); } _stateDisagreement = doc[kHasStateDisagreementFieldName].trueValue(); // Not required for the case of uninitialized members -- they have no config const BSONElement versionElement = doc[kConfigVersionFieldName]; // If we have an optime then we must have a version if (_opTimeSet && versionElement.eoo()) { return Status(ErrorCodes::NoSuchKey, str::stream() << "Response to replSetHeartbeat missing required \"" << kConfigVersionFieldName << "\" field even though initialized"); } // If there is a "v" (config version) then it must be an int. if (!versionElement.eoo() && 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 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())); } else { _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())); } else { _syncingTo = syncingToElement.String(); } const BSONElement rsConfigElement = doc[kConfigFieldName]; if (rsConfigElement.eoo()) { _configSet = false; _config = ReplicaSetConfig(); return Status::OK(); } 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()); }
Status ReplSetHeartbeatResponse::initialize(const BSONObj& doc, long long term) { // Old versions set this even though they returned not "ok" _mismatch = doc[kMismatchFieldName].trueValue(); if (_mismatch) return Status(ErrorCodes::InconsistentReplicaSetNames, "replica set name doesn't match."); // Old versions sometimes set the replica set name ("set") but ok:0 const BSONElement replSetNameElement = doc[kReplSetFieldName]; if (replSetNameElement.eoo()) { _setName.clear(); } else 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())); } else { _setName = replSetNameElement.String(); } if (_setName.empty() && !doc[kOkFieldName].trueValue()) { std::string errMsg = doc[kErrMsgFieldName].str(); BSONElement errCodeElem = doc[kErrorCodeFieldName]; if (errCodeElem.ok()) { if (!errCodeElem.isNumber()) return Status(ErrorCodes::BadValue, "Error code is not a number!"); int errorCode = errCodeElem.numberInt(); return Status(ErrorCodes::Error(errorCode), errMsg); } return Status(ErrorCodes::UnknownError, errMsg); } const BSONElement hasDataElement = doc[kHasDataFieldName]; _hasDataSet = !hasDataElement.eoo(); _hasData = hasDataElement.trueValue(); const BSONElement electionTimeElement = doc[kElectionTimeFieldName]; if (electionTimeElement.eoo()) { _electionTimeSet = false; } else if (electionTimeElement.type() == bsonTimestamp) { _electionTimeSet = true; _electionTime = electionTimeElement.timestamp(); } else if (electionTimeElement.type() == Date) { _electionTimeSet = true; _electionTime = Timestamp(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 response to replSetHeartbeat " "command to have a numeric type, but found type " << typeName(timeElement.type())); } _isReplSet = doc[kIsReplSetFieldName].trueValue(); Status termStatus = bsonExtractIntegerField(doc, kTermFieldName, &_term); if (!termStatus.isOK() && termStatus != ErrorCodes::NoSuchKey) { return termStatus; } // In order to support both the 3.0(V0) and 3.2(V1) heartbeats we must parse the OpTime // field based on its type. If it is a Date, we parse it as the timestamp and use // initialize's term argument to complete the OpTime type. If it is an Object, then it's // V1 and we construct an OpTime out of its nested fields. const BSONElement opTimeElement = doc[kOpTimeFieldName]; if (opTimeElement.eoo()) { _opTimeSet = false; } else if (opTimeElement.type() == bsonTimestamp) { _opTimeSet = true; _opTime = OpTime(opTimeElement.timestamp(), term); } else if (opTimeElement.type() == Date) { _opTimeSet = true; _opTime = OpTime(Timestamp(opTimeElement.date()), term); } else if (opTimeElement.type() == Object) { Status status = bsonExtractOpTimeField(doc, kOpTimeFieldName, &_opTime); _opTimeSet = true; // since a v1 OpTime was in the response, the member must be part of a replset _isReplSet = true; } 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(); } 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); } _stateSet = true; _state = MemberState(static_cast<int>(stateInt)); } _stateDisagreement = doc[kHasStateDisagreementFieldName].trueValue(); // Not required for the case of uninitialized members -- they have no config const BSONElement configVersionElement = doc[kConfigVersionFieldName]; // If we have an optime then we must have a configVersion if (_opTimeSet && configVersionElement.eoo()) { return Status(ErrorCodes::NoSuchKey, str::stream() << "Response to replSetHeartbeat missing required \"" << kConfigVersionFieldName << "\" field even though initialized"); } // If there is a "v" (config version) then it must be an int. if (!configVersionElement.eoo() && configVersionElement.type() != NumberInt) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kConfigVersionFieldName << "\" field in response to replSetHeartbeat to have " "type NumberInt, but found " << typeName(configVersionElement.type())); } _configVersion = configVersionElement.numberInt(); 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())); } else { _hbmsg = hbMsgElement.String(); } const BSONElement syncingToElement = doc[kSyncSourceFieldName]; if (syncingToElement.eoo()) { _syncingTo = HostAndPort(); } 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())); } else { _syncingTo = HostAndPort(syncingToElement.String()); } const BSONElement rsConfigElement = doc[kConfigFieldName]; if (rsConfigElement.eoo()) { _configSet = false; _config = ReplicaSetConfig(); return Status::OK(); } 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()); }
Status Collection::validate(OperationContext* txn, bool full, bool scanData, ValidateResults* results, BSONObjBuilder* output) { dassert(txn->lockState()->isCollectionLockedForMode(ns().toString(), MODE_IS)); MyValidateAdaptor adaptor; Status status = _recordStore->validate(txn, full, scanData, &adaptor, results, output); if (!status.isOK()) return status; { // indexes output->append("nIndexes", _indexCatalog.numIndexesReady(txn)); int idxn = 0; try { // Only applicable when 'full' validation is requested. std::unique_ptr<BSONObjBuilder> indexDetails(full ? new BSONObjBuilder() : NULL); BSONObjBuilder indexes; // not using subObjStart to be exception safe IndexCatalog::IndexIterator i = _indexCatalog.getIndexIterator(txn, false); while (i.more()) { const IndexDescriptor* descriptor = i.next(); log(LogComponent::kIndex) << "validating index " << descriptor->indexNamespace() << endl; IndexAccessMethod* iam = _indexCatalog.getIndex(descriptor); invariant(iam); std::unique_ptr<BSONObjBuilder> bob( indexDetails.get() ? new BSONObjBuilder(indexDetails->subobjStart( descriptor->indexNamespace())) : NULL); int64_t keys; iam->validate(txn, full, &keys, bob.get()); indexes.appendNumber(descriptor->indexNamespace(), static_cast<long long>(keys)); validateIndexKeyCount( txn, *descriptor, keys, _recordStore->numRecords(txn), results); if (bob) { BSONObj obj = bob->done(); BSONElement valid = obj["valid"]; if (valid.ok() && !valid.trueValue()) { results->valid = false; } } idxn++; } output->append("keysPerIndex", indexes.done()); if (indexDetails.get()) { output->append("indexDetails", indexDetails->done()); } } catch (DBException& exc) { string err = str::stream() << "exception during index validate idxn " << BSONObjBuilder::numStr(idxn) << ": " << exc.toString(); results->errors.push_back(err); results->valid = false; } } return Status::OK(); }
Status createCollectionForApplyOps(OperationContext* opCtx, const std::string& dbName, const BSONElement& ui, const BSONObj& cmdObj, const BSONObj& idIndex) { invariant(opCtx->lockState()->isDbLockedForMode(dbName, MODE_X)); auto db = dbHolder().get(opCtx, dbName); const NamespaceString newCollName(Command::parseNsCollectionRequired(dbName, cmdObj)); auto newCmd = cmdObj; // If a UUID is given, see if we need to rename a collection out of the way, and whether the // collection already exists under a different name. If so, rename it into place. As this is // done during replay of the oplog, the operations do not need to be atomic, just idempotent. // We need to do the renaming part in a separate transaction, as we cannot transactionally // create a database on MMAPv1, which could result in createCollection failing if the database // does not yet exist. if (ui.ok()) { // Return an optional, indicating whether we need to early return (if the collection already // exists, or in case of an error). using Result = boost::optional<Status>; auto result = writeConflictRetry(opCtx, "createCollectionForApplyOps", newCollName.ns(), [&] { WriteUnitOfWork wunit(opCtx); // Options need the field to be named "uuid", so parse/recreate. auto uuid = uassertStatusOK(UUID::parse(ui)); uassert(ErrorCodes::InvalidUUID, "Invalid UUID in applyOps create command: " + uuid.toString(), uuid.isRFC4122v4()); auto& catalog = UUIDCatalog::get(opCtx); auto currentName = catalog.lookupNSSByUUID(uuid); OpObserver* opObserver = getGlobalServiceContext()->getOpObserver(); if (currentName == newCollName) return Result(Status::OK()); // In the case of oplog replay, a future command may have created or renamed a // collection with that same name. In that case, renaming this future collection to // a random temporary name is correct: once all entries are replayed no temporary // names will remain. On MMAPv1 the rename can result in index names that are too // long. However this should only happen for initial sync and "resync collection" // for rollback, so we can let the error propagate resulting in an abort and restart // of the initial sync or result in rollback to fassert, requiring a resync of that // node. const bool stayTemp = true; if (auto futureColl = db ? db->getCollection(opCtx, newCollName) : nullptr) { auto tmpNameResult = db->makeUniqueCollectionNamespace(opCtx, "tmp%%%%%"); if (!tmpNameResult.isOK()) { return Result(Status(tmpNameResult.getStatus().code(), str::stream() << "Cannot generate temporary " "collection namespace for applyOps " "create command: collection: " << newCollName.ns() << ". error: " << tmpNameResult.getStatus().reason())); } const auto& tmpName = tmpNameResult.getValue(); Status status = db->renameCollection(opCtx, newCollName.ns(), tmpName.ns(), stayTemp); if (!status.isOK()) return Result(status); opObserver->onRenameCollection(opCtx, newCollName, tmpName, futureColl->uuid(), /*dropTarget*/ false, /*dropTargetUUID*/ {}, stayTemp); } // If the collection with the requested UUID already exists, but with a different // name, just rename it to 'newCollName'. if (catalog.lookupCollectionByUUID(uuid)) { Status status = db->renameCollection(opCtx, currentName.ns(), newCollName.ns(), stayTemp); if (!status.isOK()) return Result(status); opObserver->onRenameCollection(opCtx, currentName, newCollName, uuid, /*dropTarget*/ false, /*dropTargetUUID*/ {}, stayTemp); wunit.commit(); return Result(Status::OK()); } // A new collection with the specific UUID must be created, so add the UUID to the // creation options. Regular user collection creation commands cannot do this. auto uuidObj = uuid.toBSON(); newCmd = cmdObj.addField(uuidObj.firstElement()); wunit.commit(); return Result(boost::none); }); if (result) { return *result; } } return createCollection( opCtx, newCollName, newCmd, idIndex, CollectionOptions::parseForStorage); }
/** * This will verify that all updated fields are * 1.) Valid for storage (checking parent to make sure things like DBRefs are valid) * 2.) Compare updated immutable fields do not change values * * If updateFields is empty then it was replacement and/or we need to check all fields */ inline Status validate(const BSONObj& original, const FieldRefSet& updatedFields, const mb::Document& updated, const std::vector<FieldRef*>* immutableAndSingleValueFields, const ModifierInterface::Options& opts) { LOG(3) << "update validate options -- " << " updatedFields: " << updatedFields << " immutableAndSingleValueFields.size:" << (immutableAndSingleValueFields ? immutableAndSingleValueFields->size() : 0) << " validate:" << opts.enforceOkForStorage; // 1.) Loop through each updated field and validate for storage // and detect immutable field updates // The set of possibly changed immutable fields -- we will need to check their vals FieldRefSet changedImmutableFields; // Check to see if there were no fields specified or if we are not validating // The case if a range query, or query that didn't result in saved fields if (updatedFields.empty() || !opts.enforceOkForStorage) { if (opts.enforceOkForStorage) { // No specific fields were updated so the whole doc must be checked Status s = storageValid(updated, true); if (!s.isOK()) return s; } // Check all immutable fields if (immutableAndSingleValueFields) changedImmutableFields.fillFrom(*immutableAndSingleValueFields); } else { // TODO: Change impl so we don't need to create a new FieldRefSet // -- move all conflict logic into static function on FieldRefSet? FieldRefSet immutableFieldRef; if (immutableAndSingleValueFields) immutableFieldRef.fillFrom(*immutableAndSingleValueFields); FieldRefSet::const_iterator where = updatedFields.begin(); const FieldRefSet::const_iterator end = updatedFields.end(); for (; where != end; ++where) { const FieldRef& current = **where; // Find the updated field in the updated document. mutablebson::ConstElement newElem = updated.root(); size_t currentPart = 0; while (newElem.ok() && currentPart < current.numParts()) newElem = newElem[current.getPart(currentPart++)]; // newElem might be missing if $unset/$renamed-away if (newElem.ok()) { // Check element, and its children Status s = storageValid(newElem, true); if (!s.isOK()) return s; // Check parents to make sure they are valid as well. s = storageValidParents(newElem); if (!s.isOK()) return s; } // Check if the updated field conflicts with immutable fields immutableFieldRef.findConflicts(¤t, &changedImmutableFields); } } const bool checkIdField = (updatedFields.empty() && !original.isEmpty()) || updatedFields.findConflicts(&idFieldRef, NULL); // Add _id to fields to check since it too is immutable if (checkIdField) changedImmutableFields.keepShortest(&idFieldRef); else if (changedImmutableFields.empty()) { // Return early if nothing changed which is immutable return Status::OK(); } LOG(4) << "Changed immutable fields: " << changedImmutableFields; // 2.) Now compare values of the changed immutable fields (to make sure they haven't) const mutablebson::ConstElement newIdElem = updated.root()[idFieldName]; FieldRefSet::const_iterator where = changedImmutableFields.begin(); const FieldRefSet::const_iterator end = changedImmutableFields.end(); for (; where != end; ++where) { const FieldRef& current = **where; // Find the updated field in the updated document. mutablebson::ConstElement newElem = updated.root(); size_t currentPart = 0; while (newElem.ok() && currentPart < current.numParts()) newElem = newElem[current.getPart(currentPart++)]; if (!newElem.ok()) { if (original.isEmpty()) { // If the _id is missing and not required, then skip this check if (!(current.dottedField() == idFieldName)) return Status(ErrorCodes::NoSuchKey, mongoutils::str::stream() << "After applying the update, the new" << " document was missing the '" << current.dottedField() << "' (required and immutable) field."); } else { if (current.dottedField() != idFieldName) return Status(ErrorCodes::ImmutableField, mongoutils::str::stream() << "After applying the update to the document with " << newIdElem.toString() << ", the '" << current.dottedField() << "' (required and immutable) field was " "found to have been removed --" << original); } } else { // Find the potentially affected field in the original document. const BSONElement oldElem = dps::extractElementAtPath(original, current.dottedField()); const BSONElement oldIdElem = original.getField(idFieldName); // Ensure no arrays since neither _id nor shard keys can be in an array, or one. mb::ConstElement currElem = newElem; while (currElem.ok()) { if (currElem.getType() == Array) { return Status( ErrorCodes::NotSingleValueField, mongoutils::str::stream() << "After applying the update to the document {" << (oldIdElem.ok() ? oldIdElem.toString() : newIdElem.toString()) << " , ...}, the (immutable) field '" << current.dottedField() << "' was found to be an array or array descendant."); } currElem = currElem.parent(); } // If we have both (old and new), compare them. If we just have new we are good if (oldElem.ok() && newElem.compareWithBSONElement(oldElem, nullptr, false) != 0) { return Status(ErrorCodes::ImmutableField, mongoutils::str::stream() << "After applying the update to the document {" << oldElem.toString() << " , ...}, the (immutable) field '" << current.dottedField() << "' was found to have been altered to " << newElem.toString()); } } } return Status::OK(); }
int run() { if (!hasParam("from")) { log() << "need to specify --from" << endl; return -1; } _oplogns = getParam("oplogns"); Client::initThread( "mongo2toku" ); LOG(1) << "going to connect" << endl; _rconn.reset(ScopedDbConnection::getScopedDbConnection(getParam("from"))); LOG(1) << "connected" << endl; { string tsString; if (hasParam("ts")) { tsString = getParam("ts"); } else { try { ifstream tsFile; tsFile.exceptions(std::ifstream::badbit | std::ifstream::failbit); tsFile.open(_tsFilename); tsFile >> tsString; tsFile.close(); } catch (std::exception &e) { warning() << "Couldn't read OpTime from file " << _tsFilename << ": " << e.what() << endl; } } if (tsString.empty()) { warning() << "No starting OpTime provided. " << "Please find the right starting point and run again with --ts." << endl; return -1; } unsigned secs, i; OpTime maxOpTimeSynced; int r = sscanf(tsString.c_str(), "%u:%u", &secs, &i); if (r != 2) { warning() << "need to specify --ts as <secs>:<inc>" << endl; return -1; } maxOpTimeSynced = OpTime(secs, i); _player.reset(new VanillaOplogPlayer(conn(), _host, maxOpTimeSynced, running, _logAtExit)); } const int reportingPeriod = getParam("reportingPeriod", 10); try { while (running) { const int tailingQueryOptions = QueryOption_SlaveOk | QueryOption_CursorTailable | QueryOption_OplogReplay | QueryOption_AwaitData; BSONObjBuilder queryBuilder; BSONObjBuilder gteBuilder(queryBuilder.subobjStart("ts")); gteBuilder.appendTimestamp("$gte", _player->maxOpTimeSynced().asDate()); gteBuilder.doneFast(); BSONObj query = queryBuilder.done(); BSONObj res; auto_ptr<DBClientCursor> cursor(_rconn->conn().query(_oplogns, query, 0, 0, &res, tailingQueryOptions)); if (!cursor->more()) { log() << "oplog query returned no results, sleeping 10 seconds..." << endl; sleepsecs(10); log() << "retrying" << endl; continue; } BSONObj firstObj = cursor->next(); { BSONElement tsElt = firstObj["ts"]; if (!tsElt.ok()) { log() << "oplog format error: " << firstObj << " missing 'ts' field." << endl; logPosition(); _rconn->done(); _rconn.reset(); return -1; } OpTime firstTime(tsElt.date()); if (firstTime != _player->maxOpTimeSynced()) { warning() << "Tried to start at OpTime " << _player->maxOpTimeSyncedStr() << ", but didn't find anything before " << fmtOpTime(firstTime) << "!" << endl; warning() << "This may mean your oplog has been truncated past the point you are trying to resume from." << endl; warning() << "Either retry with a different value of --ts, or restart your migration procedure." << endl; _rconn->done(); _rconn.reset(); return -1; } } report(); while (running && cursor->more()) { while (running && cursor->moreInCurrentBatch()) { BSONObj obj = cursor->next(); LOG(2) << obj << endl; bool ok = _player->processObj(obj); if (!ok) { logPosition(); _rconn->done(); _rconn.reset(); return -1; } } _player->flushInserts(); if (_reportingTimer.seconds() >= reportingPeriod) { report(); } } } } catch (DBException &e) { warning() << "Caught exception " << e.what() << " while processing. Exiting..." << endl; logPosition(); _rconn->done(); _rconn.reset(); return -1; } catch (...) { warning() << "Caught unknown exception while processing. Exiting..." << endl; logPosition(); _rconn->done(); _rconn.reset(); return -1; } if (_logAtExit) { logPosition(); _rconn->done(); _rconn.reset(); return 0; } else { _rconn->done(); _rconn.reset(); return -1; } }
Status UpdateDriver::populateDocumentWithQueryFields(const CanonicalQuery* query, mutablebson::Document& doc) const { MatchExpression* root = query->root(); MatchExpression::MatchType rootType = root->matchType(); // These copies are needed until we apply the modifiers at the end. std::vector<BSONObj> copies; // We only care about equality and "and"ed equality fields, everything else is ignored if (rootType != MatchExpression::EQ && rootType != MatchExpression::AND) return Status::OK(); if (isDocReplacement()) { BSONElement idElem = query->getQueryObj().getField("_id"); // Replacement mods need the _id field copied explicitly. if (idElem.ok()) { mb::Element elem = doc.makeElement(idElem); return doc.root().pushFront(elem); } return Status::OK(); } // Create a new UpdateDriver to create the base doc from the query Options opts; opts.logOp = false; opts.multi = false; opts.upsert = true; opts.modOptions = modOptions(); UpdateDriver insertDriver(opts); insertDriver.setContext(ModifierInterface::ExecInfo::INSERT_CONTEXT); // If we are a single equality match query if (root->matchType() == MatchExpression::EQ) { EqualityMatchExpression* eqMatch = static_cast<EqualityMatchExpression*>(root); const BSONElement matchData = eqMatch->getData(); BSONElement childElem = matchData; // Make copy to new path if not the same field name (for cases like $all) if (!root->path().empty() && matchData.fieldNameStringData() != root->path()) { BSONObjBuilder copyBuilder; copyBuilder.appendAs(eqMatch->getData(), root->path()); const BSONObj copy = copyBuilder.obj(); copies.push_back(copy); childElem = copy[root->path()]; } // Add this element as a $set modifier Status s = insertDriver.addAndParse(modifiertable::MOD_SET, childElem); if (!s.isOK()) return s; } else { // parse query $set mods, including only equality stuff for (size_t i = 0; i < root->numChildren(); ++i) { MatchExpression* child = root->getChild(i); if (child->matchType() == MatchExpression::EQ) { EqualityMatchExpression* eqMatch = static_cast<EqualityMatchExpression*>(child); const BSONElement matchData = eqMatch->getData(); BSONElement childElem = matchData; // Make copy to new path if not the same field name (for cases like $all) if (!child->path().empty() && matchData.fieldNameStringData() != child->path()) { BSONObjBuilder copyBuilder; copyBuilder.appendAs(eqMatch->getData(), child->path()); const BSONObj copy = copyBuilder.obj(); copies.push_back(copy); childElem = copy[child->path()]; } // Add this element as a $set modifier Status s = insertDriver.addAndParse(modifiertable::MOD_SET, childElem); if (!s.isOK()) return s; } } } // update the document with base field Status s = insertDriver.update(StringData(), &doc); copies.clear(); if (!s.isOK()) { return Status(ErrorCodes::UnsupportedFormat, str::stream() << "Cannot create base during" " insert of update. Caused by :" << s.toString()); } return Status::OK(); }