diff options
Diffstat (limited to 'src/mongo/db/ops/modifier_object_replace.cpp')
-rw-r--r-- | src/mongo/db/ops/modifier_object_replace.cpp | 240 |
1 files changed, 115 insertions, 125 deletions
diff --git a/src/mongo/db/ops/modifier_object_replace.cpp b/src/mongo/db/ops/modifier_object_replace.cpp index 5ebbb4bd342..700f111e5b3 100644 --- a/src/mongo/db/ops/modifier_object_replace.cpp +++ b/src/mongo/db/ops/modifier_object_replace.cpp @@ -36,161 +36,151 @@ namespace mongo { - namespace str = mongoutils::str; - - namespace { - const char idFieldName[] = "_id"; - - Status fixupTimestamps( const BSONObj& obj ) { - BSONObjIterator i(obj); - while (i.more()) { - BSONElement e = i.next(); - - // Skip _id field -- we do not replace it - if (e.type() == bsonTimestamp && e.fieldNameStringData() != idFieldName) { - // TODO(emilkie): This is not endian-safe. - unsigned long long ×tamp = - *(reinterpret_cast<unsigned long long*>( - const_cast<char *>(e.value()))); - if (timestamp == 0) { - // performance note, this locks a mutex: - Timestamp ts(getNextGlobalTimestamp()); - timestamp = ts.asULL(); - } - } +namespace str = mongoutils::str; + +namespace { +const char idFieldName[] = "_id"; + +Status fixupTimestamps(const BSONObj& obj) { + BSONObjIterator i(obj); + while (i.more()) { + BSONElement e = i.next(); + + // Skip _id field -- we do not replace it + if (e.type() == bsonTimestamp && e.fieldNameStringData() != idFieldName) { + // TODO(emilkie): This is not endian-safe. + unsigned long long& timestamp = + *(reinterpret_cast<unsigned long long*>(const_cast<char*>(e.value()))); + if (timestamp == 0) { + // performance note, this locks a mutex: + Timestamp ts(getNextGlobalTimestamp()); + timestamp = ts.asULL(); } - - return Status::OK(); } } - struct ModifierObjectReplace::PreparedState { + return Status::OK(); +} +} - PreparedState(mutablebson::Document* targetDoc) - : doc(*targetDoc) - , noOp(false) { - } +struct ModifierObjectReplace::PreparedState { + PreparedState(mutablebson::Document* targetDoc) : doc(*targetDoc), noOp(false) {} - // Document that is going to be changed - mutablebson::Document& doc; + // Document that is going to be changed + mutablebson::Document& doc; - // This is a no op - bool noOp; + // This is a no op + bool noOp; +}; - }; +ModifierObjectReplace::ModifierObjectReplace() : _val() {} - ModifierObjectReplace::ModifierObjectReplace() : _val() { - } +ModifierObjectReplace::~ModifierObjectReplace() {} - ModifierObjectReplace::~ModifierObjectReplace() { +Status ModifierObjectReplace::init(const BSONElement& modExpr, + const Options& opts, + bool* positional) { + if (modExpr.type() != Object) { + // Impossible, really since the caller check this already... + return Status(ErrorCodes::BadValue, + str::stream() << "Document replacement expects a complete document" + " but the type supplied was " << modExpr.type()); } - Status ModifierObjectReplace::init(const BSONElement& modExpr, const Options& opts, - bool* positional) { - - if (modExpr.type() != Object) { - // Impossible, really since the caller check this already... - return Status(ErrorCodes::BadValue, - str::stream() << "Document replacement expects a complete document" - " but the type supplied was " - << modExpr.type()); - } + // Object replacements never have positional operator. + if (positional) + *positional = false; + + // We make a copy of the object here because the update driver does not guarantees, in + // the case of object replacement, that the modExpr is going to outlive this mod. + _val = modExpr.embeddedObject().getOwned(); + return fixupTimestamps(_val); +} + +Status ModifierObjectReplace::prepare(mutablebson::Element root, + StringData matchedField, + ExecInfo* execInfo) { + _preparedState.reset(new PreparedState(&root.getDocument())); + + // objectSize checked by binaryEqual (optimization) + BSONObj objOld = root.getDocument().getObject(); + if (objOld.binaryEqual(_val)) { + _preparedState->noOp = true; + execInfo->noOp = true; + } - // Object replacements never have positional operator. - if (positional) - *positional = false; + return Status::OK(); +} - // We make a copy of the object here because the update driver does not guarantees, in - // the case of object replacement, that the modExpr is going to outlive this mod. - _val = modExpr.embeddedObject().getOwned(); - return fixupTimestamps(_val); - } +Status ModifierObjectReplace::apply() const { + dassert(!_preparedState->noOp); - Status ModifierObjectReplace::prepare(mutablebson::Element root, - StringData matchedField, - ExecInfo* execInfo) { - _preparedState.reset(new PreparedState(&root.getDocument())); + // Remove the contents of the provided doc. + mutablebson::Document& doc = _preparedState->doc; + mutablebson::Element current = doc.root().leftChild(); + mutablebson::Element srcIdElement = doc.end(); + while (current.ok()) { + mutablebson::Element toRemove = current; + current = current.rightSibling(); - // objectSize checked by binaryEqual (optimization) - BSONObj objOld = root.getDocument().getObject(); - if (objOld.binaryEqual(_val)) { - _preparedState->noOp = true; - execInfo->noOp = true; + // Skip _id field element -- it should not change + if (toRemove.getFieldName() == idFieldName) { + srcIdElement = toRemove; + continue; } - return Status::OK(); + Status status = toRemove.remove(); + if (!status.isOK()) { + return status; + } } - Status ModifierObjectReplace::apply() const { - dassert(!_preparedState->noOp); - - // Remove the contents of the provided doc. - mutablebson::Document& doc = _preparedState->doc; - mutablebson::Element current = doc.root().leftChild(); - mutablebson::Element srcIdElement = doc.end(); - while (current.ok()) { - mutablebson::Element toRemove = current; - current = current.rightSibling(); - - // Skip _id field element -- it should not change - if (toRemove.getFieldName() == idFieldName) { - srcIdElement = toRemove; + // Insert the provided contents instead. + BSONElement dstIdElement; + BSONObjIterator it(_val); + while (it.more()) { + BSONElement elem = it.next(); + if (elem.fieldNameStringData() == idFieldName) { + dstIdElement = elem; + + // Do not duplicate _id field + if (srcIdElement.ok()) { + if (srcIdElement.compareWithBSONElement(dstIdElement, true) != 0) { + return Status(ErrorCodes::ImmutableField, + str::stream() << "The _id field cannot be changed from {" + << srcIdElement.toString() << "} to {" + << dstIdElement.toString() << "}."); + } continue; } - - Status status = toRemove.remove(); - if (!status.isOK()) { - return status; - } } - // Insert the provided contents instead. - BSONElement dstIdElement; - BSONObjIterator it(_val); - while (it.more()) { - BSONElement elem = it.next(); - if (elem.fieldNameStringData() == idFieldName) { - dstIdElement = elem; - - // Do not duplicate _id field - if (srcIdElement.ok()) { - if (srcIdElement.compareWithBSONElement(dstIdElement, true) != 0) { - return Status(ErrorCodes::ImmutableField, - str::stream() << "The _id field cannot be changed from {" - << srcIdElement.toString() << "} to {" - << dstIdElement.toString() << "}."); - } - continue; - } - } - - Status status = doc.root().appendElement(elem); - if (!status.isOK()) { - return status; - } + Status status = doc.root().appendElement(elem); + if (!status.isOK()) { + return status; } - - return Status::OK(); } - Status ModifierObjectReplace::log(LogBuilder* logBuilder) const { + return Status::OK(); +} - mutablebson::Document& doc = logBuilder->getDocument(); +Status ModifierObjectReplace::log(LogBuilder* logBuilder) const { + mutablebson::Document& doc = logBuilder->getDocument(); - mutablebson::Element replacementObject = doc.end(); - Status status = logBuilder->getReplacementObject(&replacementObject); + mutablebson::Element replacementObject = doc.end(); + Status status = logBuilder->getReplacementObject(&replacementObject); - if (status.isOK()) { - mutablebson::Element current = _preparedState->doc.root().leftChild(); - while (current.ok()) { - status = replacementObject.appendElement(current.getValue()); - if (!status.isOK()) - return status; - current = current.rightSibling(); - } + if (status.isOK()) { + mutablebson::Element current = _preparedState->doc.root().leftChild(); + while (current.ok()) { + status = replacementObject.appendElement(current.getValue()); + if (!status.isOK()) + return status; + current = current.rightSibling(); } - - return status; } -} // namespace mongo + return status; +} + +} // namespace mongo |