diff options
Diffstat (limited to 'src/mongo/db/ops')
| -rw-r--r-- | src/mongo/db/ops/SConscript | 4 | ||||
| -rw-r--r-- | src/mongo/db/ops/insert.cpp | 18 | ||||
| -rw-r--r-- | src/mongo/db/ops/insert.h | 1 | ||||
| -rw-r--r-- | src/mongo/db/ops/parsed_delete.cpp | 8 | ||||
| -rw-r--r-- | src/mongo/db/ops/parsed_delete.h | 2 | ||||
| -rw-r--r-- | src/mongo/db/ops/parsed_update.cpp | 1 | ||||
| -rw-r--r-- | src/mongo/db/ops/update.cpp | 2 | ||||
| -rw-r--r-- | src/mongo/db/ops/update_request.h | 10 | ||||
| -rw-r--r-- | src/mongo/db/ops/write_ops.cpp | 303 | ||||
| -rw-r--r-- | src/mongo/db/ops/write_ops.h | 42 | ||||
| -rw-r--r-- | src/mongo/db/ops/write_ops.idl | 21 | ||||
| -rw-r--r-- | src/mongo/db/ops/write_ops_exec.cpp | 159 | ||||
| -rw-r--r-- | src/mongo/db/ops/write_ops_exec_test.cpp | 242 | ||||
| -rw-r--r-- | src/mongo/db/ops/write_ops_retryability.cpp | 8 | ||||
| -rw-r--r-- | src/mongo/db/ops/write_ops_retryability_test.cpp | 1 |
15 files changed, 45 insertions, 777 deletions
diff --git a/src/mongo/db/ops/SConscript b/src/mongo/db/ops/SConscript index 9ac3c43f9fd..f24b532054f 100644 --- a/src/mongo/db/ops/SConscript +++ b/src/mongo/db/ops/SConscript @@ -14,10 +14,9 @@ env.Library( '$BUILD_DIR/mongo/db/catalog/catalog_helpers', '$BUILD_DIR/mongo/db/catalog/collection_options', '$BUILD_DIR/mongo/db/catalog_raii', - '$BUILD_DIR/mongo/db/concurrency/exception_util', + '$BUILD_DIR/mongo/db/curop', '$BUILD_DIR/mongo/db/curop_metrics', '$BUILD_DIR/mongo/db/dbhelpers', - '$BUILD_DIR/mongo/db/query/query_stats/query_stats', '$BUILD_DIR/mongo/db/record_id_helpers', '$BUILD_DIR/mongo/db/repl/oplog', '$BUILD_DIR/mongo/db/repl/repl_coordinator_interface', @@ -86,7 +85,6 @@ env.Library( env.CppUnitTest( target='db_ops_test', source=[ - 'write_ops_exec_test.cpp', 'write_ops_parsers_test.cpp', 'write_ops_retryability_test.cpp', ], diff --git a/src/mongo/db/ops/insert.cpp b/src/mongo/db/ops/insert.cpp index 8c949b333c7..8db1935b4b8 100644 --- a/src/mongo/db/ops/insert.cpp +++ b/src/mongo/db/ops/insert.cpp @@ -35,7 +35,6 @@ #include "mongo/bson/bson_depth.h" #include "mongo/db/catalog/document_validation.h" #include "mongo/db/commands/feature_compatibility_version_parser.h" -#include "mongo/db/mongod_options_storage_gen.h" #include "mongo/db/query/dbref.h" #include "mongo/db/query/query_feature_flags_gen.h" #include "mongo/db/repl/replication_coordinator.h" @@ -87,20 +86,11 @@ Status validateDepth(const BSONObj& obj) { StatusWith<BSONObj> fixDocumentForInsert(OperationContext* opCtx, const BSONObj& doc, - bool bypassEmptyTsReplacement, bool* containsDotsAndDollarsField) { bool validationDisabled = DocumentValidationSettings::get(opCtx).isInternalValidationDisabled(); if (!validationDisabled) { - // 'gAllowDocumentsGreaterThanMaxUserSize' should only ever be enabled when restoring a node - // from a backup. For some restores, we re-insert whole oplog entries from a - // source cluster to a destination cluster. Some generated oplog entries may exceed the user - // maximum due to entry metadata, and therefore we should skip BSON size validation for - // these inserts. Note that we should only skip the size check when inserting oplog entries - // into the oplog and not when inserting user documents. The oplog entries to insert have - // already been validated for size on the source cluster, and were successfully inserted - // into the source oplog. - if (doc.objsize() > BSONObjMaxUserSize && !gAllowDocumentsGreaterThanMaxUserSize) + if (doc.objsize() > BSONObjMaxUserSize) return StatusWith<BSONObj>(ErrorCodes::BadValue, str::stream() << "object to insert too large" << ". size in bytes: " << doc.objsize() @@ -140,8 +130,7 @@ StatusWith<BSONObj> fixDocumentForInsert(OperationContext* opCtx, } if (!validationDisabled) { - if (!bypassEmptyTsReplacement && e.type() == bsonTimestamp && - e.timestampValue() == 0) { + if (e.type() == bsonTimestamp && e.timestampValue() == 0) { // we replace Timestamp(0,0) at the top level with a correct value // in the fast pass, we just mark that we want to swap hasTimestampToFix = true; @@ -189,8 +178,7 @@ StatusWith<BSONObj> fixDocumentForInsert(OperationContext* opCtx, BSONElement e = i.next(); if (hadId && e.fieldNameStringData() == "_id") { // no-op - } else if (!bypassEmptyTsReplacement && e.type() == bsonTimestamp && - e.timestampValue() == 0) { + } else if (e.type() == bsonTimestamp && e.timestampValue() == 0) { auto nextTime = VectorClockMutable::get(opCtx)->tickClusterTime(1); b.append(e.fieldName(), nextTime.asTimestamp()); } else { diff --git a/src/mongo/db/ops/insert.h b/src/mongo/db/ops/insert.h index a523e499d02..faed6de5890 100644 --- a/src/mongo/db/ops/insert.h +++ b/src/mongo/db/ops/insert.h @@ -47,7 +47,6 @@ class OperationContext; */ StatusWith<BSONObj> fixDocumentForInsert(OperationContext* opCtx, const BSONObj& doc, - bool bypassEmptyTsReplacement = false, bool* containsDotsOrDollarsField = nullptr); /** diff --git a/src/mongo/db/ops/parsed_delete.cpp b/src/mongo/db/ops/parsed_delete.cpp index 0d84748c5be..22294b96e31 100644 --- a/src/mongo/db/ops/parsed_delete.cpp +++ b/src/mongo/db/ops/parsed_delete.cpp @@ -145,12 +145,4 @@ std::unique_ptr<CanonicalQuery> ParsedDelete::releaseParsedQuery() { return std::move(_canonicalQuery); } -void ParsedDelete::setCollator(std::unique_ptr<CollatorInterface> collator) { - if (_canonicalQuery) { - _canonicalQuery->setCollator(std::move(collator)); - } else { - _expCtx->setCollator(std::move(collator)); - } -} - } // namespace mongo diff --git a/src/mongo/db/ops/parsed_delete.h b/src/mongo/db/ops/parsed_delete.h index 6d6cb890681..ccf6b842884 100644 --- a/src/mongo/db/ops/parsed_delete.h +++ b/src/mongo/db/ops/parsed_delete.h @@ -115,8 +115,6 @@ public: return _expCtx; } - void setCollator(std::unique_ptr<CollatorInterface> collator); - private: // Transactional context. Not owned by us. OperationContext* _opCtx; diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp index a2badffa2aa..b9557e4b2fe 100644 --- a/src/mongo/db/ops/parsed_update.cpp +++ b/src/mongo/db/ops/parsed_update.cpp @@ -188,7 +188,6 @@ void ParsedUpdate::parseUpdate() { _driver.setCollator(_expCtx->getCollator()); _driver.setLogOp(true); _driver.setFromOplogApplication(_request->isFromOplogApplication()); - _driver.setBypassEmptyTsReplacement(static_cast<bool>(_request->getBypassEmptyTsReplacement())); // Time-series operations will not result in any documents with dots or dollars fields. if (auto source = _request->source(); source == OperationSource::kTimeseriesInsert || source == OperationSource::kTimeseriesUpdate) { diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp index 24f25c834d3..e63fef3a4d5 100644 --- a/src/mongo/db/ops/update.cpp +++ b/src/mongo/db/ops/update.cpp @@ -38,7 +38,7 @@ #include "mongo/db/catalog/database_holder.h" #include "mongo/db/client.h" #include "mongo/db/clientcursor.h" -#include "mongo/db/concurrency/exception_util.h" +#include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/exec/update_stage.h" #include "mongo/db/matcher/extensions_callback_real.h" #include "mongo/db/op_observer.h" diff --git a/src/mongo/db/ops/update_request.h b/src/mongo/db/ops/update_request.h index 2a086d8a4ab..3db331defa9 100644 --- a/src/mongo/db/ops/update_request.h +++ b/src/mongo/db/ops/update_request.h @@ -209,14 +209,6 @@ public: return _fromOplogApplication; } - void setBypassEmptyTsReplacement(OptionalBool bypassEmptyTsReplacement) { - _bypassEmptyTsReplacement = bypassEmptyTsReplacement; - } - - OptionalBool getBypassEmptyTsReplacement() const { - return _bypassEmptyTsReplacement; - } - void setExplain(boost::optional<ExplainOptions::Verbosity> verbosity) { _explain = verbosity; } @@ -322,8 +314,6 @@ private: // The statement ids of this request. std::vector<StmtId> _stmtIds = {kUninitializedStmtId}; - OptionalBool _bypassEmptyTsReplacement; - // Flags controlling the update. // God bypasses _id checking and index generation. It is only used on behalf of system diff --git a/src/mongo/db/ops/write_ops.cpp b/src/mongo/db/ops/write_ops.cpp index 14cf48fca37..54cef4d3d2a 100644 --- a/src/mongo/db/ops/write_ops.cpp +++ b/src/mongo/db/ops/write_ops.cpp @@ -54,18 +54,6 @@ using write_ops::WriteCommandRequestBase; namespace { -// This constant accounts for the null terminator in each field name and the BSONType byte for -// each element. -static constexpr int kPerElementOverhead = 2; - -// This constant accounts for the size of a bool. -static constexpr int kBoolSize = 1; - -// This constant tracks the overhead for serializing UUIDs. It includes 1 byte for the -// 'BinDataType', 4 bytes for serializing the integer size of the UUID, and finally, 16 bytes -// for the UUID itself. -static const int kUUIDSize = 21; - template <class T> void checkOpCountForCommand(const T& op, size_t numOps) { uassert(ErrorCodes::InvalidLength, @@ -90,56 +78,6 @@ void checkOpCountForCommand(const T& op, size_t numOps) { } } -// Utility which estimates the size of 'WriteCommandRequestBase' when serialized. -int getWriteCommandRequestBaseSize(const WriteCommandRequestBase& base) { - static const int kSizeOfOrderedField = - write_ops::WriteCommandRequestBase::kOrderedFieldName.size() + kBoolSize + - kPerElementOverhead; - static const int kSizeOfBypassDocumentValidationField = - write_ops::WriteCommandRequestBase::kBypassDocumentValidationFieldName.size() + kBoolSize + - kPerElementOverhead; - - auto estSize = static_cast<int>(BSONObj::kMinBSONLength) + kSizeOfOrderedField + - kSizeOfBypassDocumentValidationField; - - if (auto stmtId = base.getStmtId(); stmtId) { - estSize += write_ops::WriteCommandRequestBase::kStmtIdFieldName.size() + - sizeof(std::int32_t) + kPerElementOverhead; - } - - if (auto stmtIds = base.getStmtIds(); stmtIds) { - estSize += write_ops::WriteCommandRequestBase::kStmtIdsFieldName.size(); - estSize += static_cast<int>(BSONObj::kMinBSONLength); - estSize += - ((sizeof(std::int32_t) + write_ops::kWriteCommandBSONArrayPerElementOverheadBytes) * - stmtIds->size()); - estSize += kPerElementOverhead; - } - - if (auto isTimeseries = base.getIsTimeseriesNamespace(); isTimeseries.has_value()) { - estSize += write_ops::WriteCommandRequestBase::kIsTimeseriesNamespaceFieldName.size() + - kBoolSize + kPerElementOverhead; - } - - if (auto collUUID = base.getCollectionUUID(); collUUID) { - estSize += write_ops::WriteCommandRequestBase::kCollectionUUIDFieldName.size() + kUUIDSize + - kPerElementOverhead; - } - - if (auto encryptionInfo = base.getEncryptionInformation(); encryptionInfo) { - estSize += write_ops::WriteCommandRequestBase::kEncryptionInformationFieldName.size() + - encryptionInfo->toBSON().objsize() + kPerElementOverhead; - } - - if (auto bypassEmptyTsReplacement = base.getBypassEmptyTsReplacement(); - bypassEmptyTsReplacement.has_value()) { - estSize += write_ops::WriteCommandRequestBase::kBypassEmptyTsReplacementFieldName.size() + - kBoolSize + kPerElementOverhead; - } - - return estSize; -} - } // namespace namespace write_ops { @@ -199,247 +137,6 @@ int32_t getStmtIdForWriteAt(const WriteCommandRequestBase& writeCommandBase, siz return kFirstStmtId + writePos; } -int estimateRuntimeConstantsSize(const mongo::LegacyRuntimeConstants& constants) { - int size = write_ops::UpdateCommandRequest::kLegacyRuntimeConstantsFieldName.size() + - static_cast<int>(BSONObj::kMinBSONLength) + kPerElementOverhead; - - // $$NOW - size += - LegacyRuntimeConstants::kLocalNowFieldName.size() + sizeof(Date_t) + kPerElementOverhead; - - // $$CLUSTER_TIME - size += LegacyRuntimeConstants::kClusterTimeFieldName.size() + sizeof(Timestamp) + - kPerElementOverhead; - - // $$JS_SCOPE - if (const auto& scope = constants.getJsScope(); scope.has_value()) { - size += LegacyRuntimeConstants::kJsScopeFieldName.size() + scope->objsize() + - kPerElementOverhead; - } - - // $$IS_MR - if (const auto& isMR = constants.getIsMapReduce(); isMR.has_value()) { - size += - LegacyRuntimeConstants::kIsMapReduceFieldName.size() + kBoolSize + kPerElementOverhead; - } - - return size; -} - -int getUpdateSizeEstimate(const BSONObj& q, - const write_ops::UpdateModification& u, - const boost::optional<mongo::BSONObj>& c, - const bool includeUpsertSupplied, - const boost::optional<mongo::BSONObj>& collation, - const boost::optional<std::vector<mongo::BSONObj>>& arrayFilters, - const mongo::BSONObj& hint) { - using UpdateOpEntry = write_ops::UpdateOpEntry; - int estSize = static_cast<int>(BSONObj::kMinBSONLength); - - // Add the sizes of the 'multi' and 'upsert' fields. - estSize += UpdateOpEntry::kUpsertFieldName.size() + kBoolSize + kPerElementOverhead; - estSize += UpdateOpEntry::kMultiFieldName.size() + kBoolSize + kPerElementOverhead; - - // Add the size of 'upsertSupplied' field if present. - if (includeUpsertSupplied) { - estSize += UpdateOpEntry::kUpsertSuppliedFieldName.size() + kBoolSize + kPerElementOverhead; - } - - // Add the sizes of the 'q' and 'u' fields. - estSize += (UpdateOpEntry::kQFieldName.size() + q.objsize() + kPerElementOverhead + - UpdateOpEntry::kUFieldName.size() + u.objsize() + kPerElementOverhead); - - // Add the size of the 'c' field, if present. - if (c) { - estSize += (UpdateOpEntry::kCFieldName.size() + c->objsize() + kPerElementOverhead); - } - - // Add the size of the 'collation' field, if present. - if (collation) { - estSize += (UpdateOpEntry::kCollationFieldName.size() + collation->objsize() + - kPerElementOverhead); - } - - // Add the size of the 'arrayFilters' field, if present. - if (arrayFilters) { - estSize += ([&]() { - auto size = BSONObj::kMinBSONLength + UpdateOpEntry::kArrayFiltersFieldName.size() + - kPerElementOverhead; - for (auto&& filter : *arrayFilters) { - // For each filter, we not only need to account for the size of the filter itself, - // but also for the per array element overhead. - size += filter.objsize(); - size += write_ops::kWriteCommandBSONArrayPerElementOverheadBytes; - } - return size; - })(); - } - - // Add the size of 'hint' field if present. - if (!hint.isEmpty()) { - estSize += UpdateOpEntry::kHintFieldName.size() + hint.objsize() + kPerElementOverhead; - } - - return estSize; -} - -int getDeleteSizeEstimate(const BSONObj& q, - const boost::optional<mongo::BSONObj>& collation, - const mongo::BSONObj& hint) { - using DeleteOpEntry = write_ops::DeleteOpEntry; - - static const int kIntSize = 4; - int estSize = static_cast<int>(BSONObj::kMinBSONLength); - - // Add the size of the 'q' field. - estSize += DeleteOpEntry::kQFieldName.size() + q.objsize() + kPerElementOverhead; - - // Add the size of the 'collation' field, if present. - if (collation) { - estSize += - DeleteOpEntry::kCollationFieldName.size() + collation->objsize() + kPerElementOverhead; - } - - // Add the size of the 'limit' field. - estSize += DeleteOpEntry::kMultiFieldName.size() + kIntSize + kPerElementOverhead; - - // Add the size of the 'hint' field, if present. - if (!hint.isEmpty()) { - estSize += DeleteOpEntry::kHintFieldName.size() + hint.objsize() + kPerElementOverhead; - } - - return estSize; -} - -bool verifySizeEstimate(const write_ops::UpdateOpEntry& update) { - return write_ops::getUpdateSizeEstimate(update.getQ(), - update.getU(), - update.getC(), - update.getUpsertSupplied().has_value(), - update.getCollation(), - update.getArrayFilters(), - update.getHint()) >= update.toBSON().objsize(); -} - -bool verifySizeEstimate(const InsertCommandRequest& insertReq, - const OpMsgRequest* unparsedRequest) { - int size = getInsertHeaderSizeEstimate(insertReq); - for (auto&& docToInsert : insertReq.getDocuments()) { - size += docToInsert.objsize() + kWriteCommandBSONArrayPerElementOverheadBytes; - } - - // Return true if 'insertReq' originated from a document sequence and our size estimate exceeds - // the size limit. - if (unparsedRequest && !unparsedRequest->sequences.empty() && size > BSONObjMaxUserSize) { - return true; - } - return size >= insertReq.toBSON({} /* commandPassthroughFields */).objsize(); -} - -bool verifySizeEstimate(const UpdateCommandRequest& updateReq, - const OpMsgRequest* unparsedRequest) { - int size = getUpdateHeaderSizeEstimate(updateReq); - - for (auto&& update : updateReq.getUpdates()) { - size += getUpdateSizeEstimate(update.getQ(), - update.getU(), - update.getC(), - update.getUpsertSupplied().has_value(), - update.getCollation(), - update.getArrayFilters(), - update.getHint()) + - kWriteCommandBSONArrayPerElementOverheadBytes; - } - - // Return true if 'updateReq' originated from a document sequence and our size estimate exceeds - // the size limit. - if (unparsedRequest && !unparsedRequest->sequences.empty() && size > BSONObjMaxUserSize) { - return true; - } - return size >= updateReq.toBSON({} /* commandPassthroughFields */).objsize(); -} - -bool verifySizeEstimate(const DeleteCommandRequest& deleteReq, - const OpMsgRequest* unparsedRequest) { - int size = getDeleteHeaderSizeEstimate(deleteReq); - - for (auto&& deleteOp : deleteReq.getDeletes()) { - size += write_ops::getDeleteSizeEstimate( - deleteOp.getQ(), deleteOp.getCollation(), deleteOp.getHint()) + - kWriteCommandBSONArrayPerElementOverheadBytes; - } - - // Return true if 'deleteReq' originated from a document sequence and our size estimate exceeds - // the size limit. - if (unparsedRequest && !unparsedRequest->sequences.empty() && size > BSONObjMaxUserSize) { - return true; - } - return size >= deleteReq.toBSON({} /* commandPassthroughFields */).objsize(); -} - -int getInsertHeaderSizeEstimate(const InsertCommandRequest& insertReq) { - int size = getWriteCommandRequestBaseSize(insertReq.getWriteCommandRequestBase()) + - write_ops::InsertCommandRequest::kDocumentsFieldName.size() + kPerElementOverhead + - static_cast<int>(BSONObj::kMinBSONLength); - - size += InsertCommandRequest::kCommandName.size() + kPerElementOverhead + - insertReq.getNamespace().size() + 1 /* ns string null terminator */; - - return size; -} - -int getUpdateHeaderSizeEstimate(const UpdateCommandRequest& updateReq) { - int size = getWriteCommandRequestBaseSize(updateReq.getWriteCommandRequestBase()); - - size += UpdateCommandRequest::kCommandName.size() + kPerElementOverhead + - updateReq.getNamespace().size() + 1 /* ns string null terminator */; - - size += write_ops::UpdateCommandRequest::kUpdatesFieldName.size() + kPerElementOverhead + - static_cast<int>(BSONObj::kMinBSONLength); - - // Handle legacy runtime constants. - if (auto runtimeConstants = updateReq.getLegacyRuntimeConstants(); - runtimeConstants.has_value()) { - size += estimateRuntimeConstantsSize(*runtimeConstants); - } - - // Handle let parameters. - if (auto let = updateReq.getLet(); let.has_value()) { - size += write_ops::UpdateCommandRequest::kLetFieldName.size() + let->objsize() + - kPerElementOverhead; - } - return size; -} - -int getDeleteHeaderSizeEstimate(const DeleteCommandRequest& deleteReq) { - int size = getWriteCommandRequestBaseSize(deleteReq.getWriteCommandRequestBase()); - - size += DeleteCommandRequest::kCommandName.size() + kPerElementOverhead + - deleteReq.getNamespace().size() + 1 /* ns string null terminator */; - - size += write_ops::DeleteCommandRequest::kDeletesFieldName.size() + kPerElementOverhead + - static_cast<int>(BSONObj::kMinBSONLength); - - // Handle legacy runtime constants. - if (auto runtimeConstants = deleteReq.getLegacyRuntimeConstants(); - runtimeConstants.has_value()) { - size += estimateRuntimeConstantsSize(*runtimeConstants); - } - - // Handle let parameters. - if (auto let = deleteReq.getLet(); let.has_value()) { - size += write_ops::UpdateCommandRequest::kLetFieldName.size() + let->objsize() + - kPerElementOverhead; - } - return size; -} - -bool verifySizeEstimate(const write_ops::DeleteOpEntry& deleteOp) { - return write_ops::getDeleteSizeEstimate(deleteOp.getQ(), - deleteOp.getCollation(), - deleteOp.getHint()) >= deleteOp.toBSON().objsize(); -} - bool isClassicalUpdateReplacement(const BSONObj& update) { // An empty update object will be treated as replacement as firstElementFieldName() returns "". return update.firstElementFieldName()[0] != '$'; diff --git a/src/mongo/db/ops/write_ops.h b/src/mongo/db/ops/write_ops.h index 2e55f0054e5..d78791fdfdc 100644 --- a/src/mongo/db/ops/write_ops.h +++ b/src/mongo/db/ops/write_ops.h @@ -104,48 +104,6 @@ const std::vector<BSONObj>& arrayFiltersOf(const T& opEntry) { } /** - * Utility which estimates the size in bytes of an update statement with the given parameters, when - * serialized in the format used for the update command. - */ -int getUpdateSizeEstimate(const BSONObj& q, - const write_ops::UpdateModification& u, - const boost::optional<mongo::BSONObj>& c, - bool includeUpsertSupplied, - const boost::optional<mongo::BSONObj>& collation, - const boost::optional<std::vector<mongo::BSONObj>>& arrayFilters, - const mongo::BSONObj& hint); - -int getDeleteSizeEstimate(const BSONObj& q, - const boost::optional<mongo::BSONObj>& collation, - const mongo::BSONObj& hint); - -/** - * Set of utilities which return true if the estimated write size is greater than or equal to the - * actual write size, false otherwise. - * - * If the caller specifies 'unparsedRequest', these utilities will also return true if the request - * used document sequences and the size estimate is greater than the maximum size of a BSONObj. This - * indicates that 'unparsedRequest' cannot be serialized to a BSONObj because it exceeds the maximum - * BSONObj size. - */ -bool verifySizeEstimate(const write_ops::UpdateOpEntry& update); -bool verifySizeEstimate(const write_ops::DeleteOpEntry& deleteOp); -bool verifySizeEstimate(const InsertCommandRequest& insertReq, - const OpMsgRequest* unparsedRequest = nullptr); -bool verifySizeEstimate(const UpdateCommandRequest& updateReq, - const OpMsgRequest* unparsedRequest = nullptr); -bool verifySizeEstimate(const DeleteCommandRequest& deleteReq, - const OpMsgRequest* unparsedRequest = nullptr); - -/** - * Set of utilities which estimate the size of the headers (that is, all fields in a write command - * outside of the write statements themselves) of an insert/update/delete command, respectively. - */ -int getInsertHeaderSizeEstimate(const InsertCommandRequest& insertReq); -int getUpdateHeaderSizeEstimate(const UpdateCommandRequest& updateReq); -int getDeleteHeaderSizeEstimate(const DeleteCommandRequest& deleteReq); - -/** * If the response from a write command contains any write errors, it will throw the first one. All * the remaining errors will be disregarded. * diff --git a/src/mongo/db/ops/write_ops.idl b/src/mongo/db/ops/write_ops.idl index e41af05e808..83f9b43359b 100644 --- a/src/mongo/db/ops/write_ops.idl +++ b/src/mongo/db/ops/write_ops.idl @@ -149,8 +149,6 @@ structs: chained_structs: WriteCommandReplyBase: writeCommandReplyBase - # IMPORTANT: If any changes are made to the fields here, please update the corresponding size - # estimation functions in 'write_ops.cpp'. WriteCommandRequestBase: description: "Contains basic information included by all write commands" strict: false @@ -205,12 +203,6 @@ structs: type: EncryptionInformation optional: true unstable: true - bypassEmptyTsReplacement: - description: "Only applicable for inserts and replacement updates. If set to true, - any empty timestamps (Timestamp(0,0)) in 'documents' or 'u' will not - be replaced by the current time and instead will be preserved as-is." - type: optionalBool - unstable: true UpdateOpEntry: description: "Parser for the entries in the 'updates' array of an update command." @@ -334,8 +326,7 @@ structs: unstable: true commands: - # IMPORTANT: If any changes are made to the fields here, please update the corresponding insert - # size estimation functions in 'write_ops.cpp'. + insert: description: "Parser for the 'insert' command." command_name: insert @@ -358,8 +349,6 @@ commands: supports_doc_sequence: true unstable: false - # IMPORTANT: If any changes are made to the fields here, please update the corresponding update - # size estimation functions in 'write_ops.cpp'. update: description: "Parser for the 'update' command." command_name: update @@ -395,8 +384,6 @@ commands: optional: true unstable: false - # IMPORTANT: If any changes are made to the fields here, please update the corresponding delete - # size estimation functions in 'write_ops.cpp'. delete: description: "Parser for the 'delete' command." command_name: delete @@ -545,9 +532,3 @@ commands: type: EncryptionInformation optional: true unstable: true - bypassEmptyTsReplacement: - description: "Only applicable when 'update' is a replacement update. If set, any - empty timestamps (Timestamp(0, 0)) in the update will not be replaced - by the current time and instead will be preserved as-is." - type: optionalBool - unstable: true diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp index e58146ac5cd..f7fc2a84efd 100644 --- a/src/mongo/db/ops/write_ops_exec.cpp +++ b/src/mongo/db/ops/write_ops_exec.cpp @@ -44,7 +44,7 @@ #include "mongo/db/catalog/document_validation.h" #include "mongo/db/catalog_raii.h" #include "mongo/db/commands.h" -#include "mongo/db/concurrency/exception_util.h" +#include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/curop_failpoint_helpers.h" #include "mongo/db/curop_metrics.h" #include "mongo/db/dbhelpers.h" @@ -119,51 +119,6 @@ MONGO_FAIL_POINT_DEFINE(hangWithLockDuringBatchUpdate); MONGO_FAIL_POINT_DEFINE(hangWithLockDuringBatchRemove); MONGO_FAIL_POINT_DEFINE(failAtomicTimeseriesWrites); - -/** - * Metrics group for the `updateMany` and `deleteMany` operations. For each - * operation, the `duration` and `numDocs` will contribute to aggregated total - * and max metrics. - */ -class MultiUpdateDeleteMetrics { -public: - void operator()(Microseconds duration, size_t numDocs) { - _durationTotalMicroseconds.increment(durationCount<Microseconds>(duration)); - _durationTotalMs.set( - durationCount<Milliseconds>(Microseconds{_durationTotalMicroseconds.get()})); - _durationMaxMs.setIfMax(durationCount<Milliseconds>(duration)); - - _numDocsTotal.increment(numDocs); - _numDocsMax.setIfMax(numDocs); - } - -private: - /** - * To avoid rapid accumulation of roundoff error in the duration total, it - * is maintained precisely, and we arrange for the corresponding - * Millisecond metric to hold an exported low-res image of it. - */ - Counter64 _durationTotalMicroseconds; - - Atomic64Metric _durationTotalMs; - ServerStatusMetricField<Atomic64Metric> _displayDurationTotalMs{ - "query.updateDeleteManyDurationTotalMs", &_durationTotalMs}; - Atomic64Metric _durationMaxMs; - ServerStatusMetricField<Atomic64Metric> _displayDurationMaxMs{ - "query.updateDeleteManyDurationMaxMs", &_durationMaxMs}; - - Counter64 _numDocsTotal; - ServerStatusMetricField<Counter64> displayNumDocsTotal{ - "query.updateDeleteManyDocumentsTotalCount", &_numDocsTotal}; - - Atomic64Metric _numDocsMax; - ServerStatusMetricField<Atomic64Metric> _displayNumDocsMax{ - "query.updateDeleteManyDocumentsMaxCount", &_numDocsMax}; -}; - -MultiUpdateDeleteMetrics collectMultiUpdateDeleteMetrics; - - void updateRetryStats(OperationContext* opCtx, bool containsRetry) { if (containsRetry) { RetryableWritesStats::get(opCtx)->incrementRetriedCommandsCount(); @@ -174,7 +129,7 @@ void finishCurOp(OperationContext* opCtx, CurOp* curOp) { try { curOp->done(); auto executionTimeMicros = duration_cast<Microseconds>(curOp->elapsedTimeExcludingPauses()); - curOp->debug().additiveMetrics.executionTime = executionTimeMicros; + curOp->debug().executionTime = executionTimeMicros; recordCurOpMetrics(opCtx); Top::get(opCtx->getServiceContext()) @@ -338,20 +293,15 @@ bool handleError(OperationContext* opCtx, return false; } - if (ex.code() == ErrorCodes::StaleDbVersion || ErrorCodes::isStaleShardVersionError(ex) || - ex.code() == ErrorCodes::ShardCannotRefreshDueToLocksHeld) { + if (ex.code() == ErrorCodes::StaleDbVersion || ErrorCodes::isStaleShardVersionError(ex)) { if (!opCtx->getClient()->isInDirectClient()) { auto& oss = OperationShardingState::get(opCtx); oss.setShardingOperationFailedStatus(ex.toStatus()); } - // For routing errors, it is guaranteed that all subsequent operations will fail + // Since this is a routing error, it is guaranteed that all subsequent operations will fail // with the same cause, so don't try doing any more operations. The command reply serializer // will handle repeating this error for unordered writes. - // (On the other hand, ShardCannotRefreshDueToLocksHeld is caused by a temporary inability - // to access a stable version of the cache during the execution of the batch; the error is - // returned back to the router to leverage its capability of selectively retrying - // operations). out->results.emplace_back(ex.toStatus()); return false; } @@ -381,6 +331,10 @@ bool handleError(OperationContext* opCtx, return false; } + if (ex.code() == ErrorCodes::ShardCannotRefreshDueToLocksHeld) { + throw; + } + out->results.emplace_back(ex.toStatus()); return !wholeOp.getOrdered(); } @@ -496,13 +450,8 @@ bool insertBatchAndHandleErrors(OperationContext* opCtx, opCtx, wholeOp.getNamespace(), fixLockModeForSystemDotViewsChanges(wholeOp.getNamespace(), MODE_IX)); - checkCollectionUUIDMismatch(opCtx, - wholeOp.getNamespace(), - collection->getCollection(), - wholeOp.getCollectionUUID()); - if (*collection) { + if (*collection) break; - } if (source == OperationSource::kTimeseriesInsert) { assertTimeseriesBucketsCollectionNotFound(wholeOp.getNamespace()); @@ -548,6 +497,11 @@ bool insertBatchAndHandleErrors(OperationContext* opCtx, if (shouldProceedWithBatchInsert) { try { if (!collection->getCollection()->isCapped() && !inTxn && batch.size() > 1) { + checkCollectionUUIDMismatch(opCtx, + wholeOp.getNamespace(), + collection->getCollection(), + wholeOp.getCollectionUUID()); + // First try doing it all together. If all goes well, this is all we need to do. // See Collection::_insertDocuments for why we do all capped inserts one-at-a-time. lastOpFixer->startingOp(); @@ -590,6 +544,10 @@ bool insertBatchAndHandleErrors(OperationContext* opCtx, // Transactions are not allowed to operate on capped collections. uassertStatusOK( checkIfTransactionOnCappedColl(opCtx, collection->getCollection())); + checkCollectionUUIDMismatch(opCtx, + wholeOp.getNamespace(), + collection->getCollection(), + wholeOp.getCollectionUUID()); lastOpFixer->startingOp(); insertDocuments(opCtx, collection->getCollection(), @@ -673,6 +631,7 @@ bool getFleCrudProcessed(OperationContext* opCtx, WriteResult performInserts(OperationContext* opCtx, const write_ops::InsertCommandRequest& wholeOp, OperationSource source) { + // Insert performs its own retries, so we should only be within a WriteUnitOfWork when run in a // transaction. auto txnParticipant = TransactionParticipant::get(opCtx); @@ -731,20 +690,11 @@ WriteResult performInserts(OperationContext* opCtx, const size_t maxBatchBytes = write_ops::insertVectorMaxBytes; batch.reserve(std::min(wholeOp.getDocuments().size(), maxBatchSize)); - // If 'wholeOp.getBypassEmptyTsReplacement()' is true or if 'source' is 'kFromMigrate', set - // "bypassEmptyTsReplacement=true" for fixDocumentForInsert(). - const bool bypassEmptyTsReplacement = (source == OperationSource::kFromMigrate) || - static_cast<bool>(wholeOp.getBypassEmptyTsReplacement()); - for (auto&& doc : wholeOp.getDocuments()) { const bool isLastDoc = (&doc == &wholeOp.getDocuments().back()); bool containsDotsAndDollarsField = false; - - auto fixedDoc = fixDocumentForInsert( - opCtx, doc, bypassEmptyTsReplacement, &containsDotsAndDollarsField); - + auto fixedDoc = fixDocumentForInsert(opCtx, doc, &containsDotsAndDollarsField); const StmtId stmtId = getStmtIdForWriteOp(opCtx, wholeOp, stmtIdIndex++); - const bool wasAlreadyExecuted = opCtx->isRetryableWrite() && txnParticipant.checkStatementExecutedNoOplogEntryFetch(opCtx, stmtId); @@ -846,7 +796,6 @@ static SingleWriteResult performSingleUpdateOp(OperationContext* opCtx, boost::optional<AutoGetCollection> collection; while (true) { collection.emplace(opCtx, ns, fixLockModeForSystemDotViewsChanges(ns, MODE_IX)); - checkCollectionUUIDMismatch(opCtx, ns, collection->getCollection(), opCollectionUUID); if (*collection) { break; } @@ -911,6 +860,8 @@ static SingleWriteResult performSingleUpdateOp(OperationContext* opCtx, uassertStatusOK(checkIfTransactionOnCappedColl(opCtx, coll)); } + checkCollectionUUIDMismatch(opCtx, ns, collection->getCollection(), opCollectionUUID); + const ExtensionsCallbackReal extensionsCallback(opCtx, &updateRequest->getNamespaceString()); ParsedUpdate parsedUpdate(opCtx, updateRequest, extensionsCallback, forgoOpCounterIncrements); uassertStatusOK(parsedUpdate.parseRequest()); @@ -986,7 +937,6 @@ static SingleWriteResult performSingleUpdateOpWithDupKeyRetry( const write_ops::UpdateOpEntry& op, LegacyRuntimeConstants runtimeConstants, const boost::optional<BSONObj>& letParams, - const OptionalBool& bypassEmptyTsReplacement, OperationSource source, bool forgoOpCounterIncrements) { globalOpCounters.gotUpdate(); @@ -1015,9 +965,10 @@ static SingleWriteResult performSingleUpdateOpWithDupKeyRetry( if (letParams) { request.setLetParameters(std::move(letParams)); } - request.setBypassEmptyTsReplacement(bypassEmptyTsReplacement); request.setStmtIds(stmtIds); - request.setYieldPolicy(PlanYieldPolicy::YieldPolicy::YIELD_AUTO); + request.setYieldPolicy(opCtx->inMultiDocumentTransaction() + ? PlanYieldPolicy::YieldPolicy::INTERRUPT_ONLY + : PlanYieldPolicy::YieldPolicy::YIELD_AUTO); request.setSource(source); size_t numAttempts = 0; @@ -1144,12 +1095,7 @@ WriteResult performUpdates(OperationContext* opCtx, ? *wholeOp.getStmtIds() : std::vector<StmtId>{stmtId}; - boost::optional<Timer> timer; - if (singleOp.getMulti()) { - timer.emplace(); - } - - const SingleWriteResult&& reply = + out.results.emplace_back( performSingleUpdateOpWithDupKeyRetry(opCtx, ns, wholeOp.getCollectionUUID(), @@ -1157,27 +1103,11 @@ WriteResult performUpdates(OperationContext* opCtx, singleOp, runtimeConstants, wholeOp.getLet(), - wholeOp.getBypassEmptyTsReplacement(), source, - forgoOpCounterIncrements); - out.results.emplace_back(reply); + forgoOpCounterIncrements)); forgoOpCounterIncrements = true; lastOpFixer.finishedOpSuccessfully(); - - if (singleOp.getMulti()) { - updateManyCount.increment(1); - collectMultiUpdateDeleteMetrics(timer->elapsed(), reply.getNModified()); - } } catch (const DBException& ex) { - // Do not handle errors for time-series bucket compressions. They need to be transparent - // to users to not interfere with any decisions around operation retry. It is OK to - // leave bucket uncompressed in these edge cases. We just record the status to the - // result vector so we can keep track of statistics for failed bucket compressions. - if (source == OperationSource::kTimeseriesBucketCompression) { - out.results.emplace_back(ex.toStatus()); - break; - } - out.canContinue = handleError( opCtx, ex, ns, wholeOp.getWriteCommandRequestBase(), singleOp.getMulti(), &out); if (!out.canContinue) { @@ -1223,7 +1153,9 @@ static SingleWriteResult performSingleDeleteOp(OperationContext* opCtx, request.setQuery(op.getQ()); request.setCollation(write_ops::collationOf(op)); request.setMulti(op.getMulti()); - request.setYieldPolicy(PlanYieldPolicy::YieldPolicy::YIELD_AUTO); + request.setYieldPolicy(opCtx->inMultiDocumentTransaction() + ? PlanYieldPolicy::YieldPolicy::INTERRUPT_ONLY + : PlanYieldPolicy::YieldPolicy::YIELD_AUTO); request.setStmtId(stmtId); request.setHint(op.getHint()); @@ -1390,28 +1322,15 @@ WriteResult performDeletes(OperationContext* opCtx, }); try { lastOpFixer.startingOp(); - - boost::optional<Timer> timer; - if (singleOp.getMulti()) { - timer.emplace(); - } - - const SingleWriteResult&& reply = performSingleDeleteOp(opCtx, - ns, - wholeOp.getCollectionUUID(), - stmtId, - singleOp, - runtimeConstants, - wholeOp.getLet(), - source); - out.results.push_back(reply); + out.results.push_back(performSingleDeleteOp(opCtx, + ns, + wholeOp.getCollectionUUID(), + stmtId, + singleOp, + runtimeConstants, + wholeOp.getLet(), + source)); lastOpFixer.finishedOpSuccessfully(); - - // Collect metrics. - if (singleOp.getMulti()) { - deleteManyCount.increment(1); - collectMultiUpdateDeleteMetrics(timer->elapsed(), reply.getN()); - } } catch (const DBException& ex) { out.canContinue = handleError( opCtx, ex, ns, wholeOp.getWriteCommandRequestBase(), false /* multiUpdate */, &out); @@ -1508,7 +1427,7 @@ Status performAtomicTimeseriesWrites( doc_diff::applyDiff(original.value(), update.getU().getDiff(), &CollectionQueryInfo::get(*coll).getIndexKeys(opCtx), - update.getU().mustCheckExistenceForInsertOperations()); + static_cast<bool>(repl::tenantMigrationRecipientInfo(opCtx))); CollectionUpdateArgs args; if (const auto& stmtIds = op.getStmtIds()) { diff --git a/src/mongo/db/ops/write_ops_exec_test.cpp b/src/mongo/db/ops/write_ops_exec_test.cpp deleted file mode 100644 index 87393bf33a2..00000000000 --- a/src/mongo/db/ops/write_ops_exec_test.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/** - * Copyright (C) 2022-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/db/catalog/create_collection.h" -#include "mongo/db/catalog_raii.h" -#include "mongo/db/ops/write_ops_exec.h" -#include "mongo/unittest/unittest.h" - -namespace mongo { -namespace { - -TEST(WriteOpsExecTest, TestUpdateSizeEstimationLogic) { - // Basic test case. - OID id = OID::createFromString("629e1e680958e279dc29a989"_sd); - BSONObj updateStmt = fromjson("{$set: {a: 5}}"); - write_ops::UpdateModification mod(std::move(updateStmt), - write_ops::UpdateModification::ClassicTag{}, - false /* isReplacement */); - write_ops::UpdateOpEntry updateOpEntry(BSON("_id" << id), std::move(mod)); - ASSERT(write_ops::verifySizeEstimate(updateOpEntry)); - - // Add 'let' constants. - BSONObj constants = fromjson("{constOne: 'foo'}"); - updateOpEntry.setC(constants); - ASSERT(write_ops::verifySizeEstimate(updateOpEntry)); - - // Add 'upsertSupplied'. - updateOpEntry.setUpsertSupplied(OptionalBool(false)); - ASSERT(write_ops::verifySizeEstimate(updateOpEntry)); - - // Set 'upsertSupplied' to true. - updateOpEntry.setUpsertSupplied(OptionalBool(true)); - ASSERT(write_ops::verifySizeEstimate(updateOpEntry)); - - // Set 'upsertSupplied' to boost::none. - updateOpEntry.setUpsertSupplied(OptionalBool(boost::none)); - ASSERT(write_ops::verifySizeEstimate(updateOpEntry)); - - // Add a collation. - BSONObj collation = fromjson("{locale: 'simple'}"); - updateOpEntry.setCollation(collation); - ASSERT(write_ops::verifySizeEstimate(updateOpEntry)); - - // Add a hint. - BSONObj hint = fromjson("{_id: 1}"); - updateOpEntry.setHint(hint); - ASSERT(write_ops::verifySizeEstimate(updateOpEntry)); - - // Add arrayFilters. - auto arrayFilter = std::vector<BSONObj>{fromjson("{'x.a': {$gt: 85}}")}; - updateOpEntry.setArrayFilters(arrayFilter); - ASSERT(write_ops::verifySizeEstimate(updateOpEntry)); -} - -TEST(WriteOpsExecTest, TestDeleteSizeEstimationLogic) { - // Basic test case. - OID id = OID::createFromString("629e1e680958e279dc29a989"_sd); - write_ops::DeleteOpEntry deleteOpEntry(BSON("_id" << id), false /* multi */); - ASSERT(write_ops::verifySizeEstimate(deleteOpEntry)); - - // Add a collation. - BSONObj collation = fromjson("{locale: 'simple'}"); - deleteOpEntry.setCollation(collation); - ASSERT(write_ops::verifySizeEstimate(deleteOpEntry)); - - // Add a hint. - BSONObj hint = fromjson("{_id: 1}"); - deleteOpEntry.setHint(hint); - ASSERT(write_ops::verifySizeEstimate(deleteOpEntry)); -} - -TEST(WriteOpsExecTest, TestInsertRequestSizeEstimationLogic) { - NamespaceString ns("db_write_ops_exec_test", "insert_test"); - write_ops::InsertCommandRequest insert(ns); - BSONObj docToInsert(fromjson("{_id: 1, foo: 1}")); - insert.setDocuments({docToInsert}); - ASSERT(write_ops::verifySizeEstimate(insert)); - - // Configure different fields for 'wcb'. - write_ops::WriteCommandRequestBase wcb; - - // stmtId - wcb.setStmtId(2); - insert.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(insert)); - - // stmtIds - wcb.setStmtIds(std::vector<int32_t>{2, 3}); - insert.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(insert)); - - // isTimeseries - wcb.setIsTimeseriesNamespace(true); - insert.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(insert)); - - // collUUID - wcb.setCollectionUUID(UUID::gen()); - insert.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(insert)); - - // encryptionInfo - wcb.setEncryptionInformation( - EncryptionInformation(fromjson("{schema: 'I love encrypting and protecting my data'}"))); - insert.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(insert)); -} - -TEST(WriteOpsExecTest, TestUpdateRequestSizeEstimationLogic) { - NamespaceString ns("db_write_ops_exec_test", "update_test"); - write_ops::UpdateCommandRequest update(ns); - - const BSONObj updateStmt = fromjson("{$set: {a: 5}}"); - auto mod = write_ops::UpdateModification::parseFromClassicUpdate(updateStmt); - write_ops::UpdateOpEntry updateOpEntry(BSON("_id" << 1), std::move(mod)); - update.setUpdates({updateOpEntry}); - - ASSERT(write_ops::verifySizeEstimate(update)); - - // Configure different fields for 'wcb'. - write_ops::WriteCommandRequestBase wcb; - - // stmtId - wcb.setStmtId(2); - update.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(update)); - - // stmtIds - wcb.setStmtIds(std::vector<int32_t>{2, 3}); - update.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(update)); - - // isTimeseries - wcb.setIsTimeseriesNamespace(true); - update.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(update)); - - // collUUID - wcb.setCollectionUUID(UUID::gen()); - update.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(update)); - - // encryptionInfo - wcb.setEncryptionInformation( - EncryptionInformation(fromjson("{schema: 'I love encrypting and protecting my data'}"))); - update.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(update)); - - // Configure different fields specific to 'UpdateStatementRequest'. - LegacyRuntimeConstants legacyRuntimeConstants; - const auto now = Date_t::now(); - - // At a minimum, $$NOW and $$CLUSTER_TIME must be set. - legacyRuntimeConstants.setLocalNow(now); - legacyRuntimeConstants.setClusterTime(Timestamp(now)); - update.setLegacyRuntimeConstants(legacyRuntimeConstants); - ASSERT(write_ops::verifySizeEstimate(update)); - - // $$JS_SCOPE - BSONObj jsScope = fromjson("{constant: 'I love mapReduce and javascript :D'}"); - legacyRuntimeConstants.setJsScope(jsScope); - update.setLegacyRuntimeConstants(legacyRuntimeConstants); - ASSERT(write_ops::verifySizeEstimate(update)); - - // $$IS_MR - legacyRuntimeConstants.setIsMapReduce(true); - update.setLegacyRuntimeConstants(legacyRuntimeConstants); - ASSERT(write_ops::verifySizeEstimate(update)); - - const std::string kLargeString(100 * 1024, 'b'); - BSONObj letParams = BSON("largeStrParam" << kLargeString); - update.setLet(letParams); - ASSERT(write_ops::verifySizeEstimate(update)); -} - -TEST(WriteOpsExecTest, TestDeleteRequestSizeEstimationLogic) { - NamespaceString ns("db_write_ops_exec_test", "delete_test"); - write_ops::DeleteCommandRequest deleteReq(ns); - // Basic test case. - write_ops::DeleteOpEntry deleteOpEntry(BSON("_id" << 1), false /* multi */); - deleteReq.setDeletes({deleteOpEntry}); - - ASSERT(write_ops::verifySizeEstimate(deleteReq)); - - // Configure different fields for 'wcb'. - write_ops::WriteCommandRequestBase wcb; - - // stmtId - wcb.setStmtId(2); - deleteReq.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(deleteReq)); - - // stmtIds - wcb.setStmtIds(std::vector<int32_t>{2, 3}); - deleteReq.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(deleteReq)); - - // isTimeseries - wcb.setIsTimeseriesNamespace(true); - deleteReq.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(deleteReq)); - - // collUUID - wcb.setCollectionUUID(UUID::gen()); - deleteReq.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(deleteReq)); - - // encryptionInfo - wcb.setEncryptionInformation( - EncryptionInformation(fromjson("{schema: 'I love encrypting and protecting my data'}"))); - deleteReq.setWriteCommandRequestBase(wcb); - ASSERT(write_ops::verifySizeEstimate(deleteReq)); -} - -} // namespace -} // namespace mongo diff --git a/src/mongo/db/ops/write_ops_retryability.cpp b/src/mongo/db/ops/write_ops_retryability.cpp index 1f1c28cda28..41dcdd121f3 100644 --- a/src/mongo/db/ops/write_ops_retryability.cpp +++ b/src/mongo/db/ops/write_ops_retryability.cpp @@ -34,14 +34,12 @@ #include "mongo/db/ops/write_ops_retryability.h" #include "mongo/bson/util/bson_extract.h" -#include "mongo/db/curop.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/namespace_string.h" #include "mongo/db/ops/write_ops_gen.h" #include "mongo/db/repl/image_collection_entry_gen.h" #include "mongo/logv2/log.h" #include "mongo/logv2/redaction.h" -#include "mongo/stdx/mutex.h" namespace mongo { namespace { @@ -120,14 +118,8 @@ BSONObj extractPreOrPostImage(OperationContext* opCtx, const repl::OplogEntry& o LogicalSessionId sessionId = oplog.getSessionId().get(); TxnNumber txnNumber = oplog.getTxnNumber().get(); Timestamp ts = oplog.getTimestamp(); - auto curOp = CurOp::get(opCtx); - const std::string existingNS = curOp->getNS(); BSONObj imageDoc = client.findOne(NamespaceString::kConfigImagesNamespace, BSON("_id" << sessionId.toBSON())); - { - stdx::lock_guard<Client> clientLock(*opCtx->getClient()); - curOp->setNS_inlock(existingNS); - } if (imageDoc.isEmpty()) { LOGV2_WARNING(5676402, "Image lookup for a retryable findAndModify was not found", diff --git a/src/mongo/db/ops/write_ops_retryability_test.cpp b/src/mongo/db/ops/write_ops_retryability_test.cpp index 866d38de75d..1b31ab12ded 100644 --- a/src/mongo/db/ops/write_ops_retryability_test.cpp +++ b/src/mongo/db/ops/write_ops_retryability_test.cpp @@ -74,7 +74,6 @@ repl::OplogEntry makeOplogEntry(repl::OpTime opTime, nss, // namespace boost::none, // uuid boost::none, // fromMigrate - boost::none, // checkExistenceForDiffInsert repl::OplogEntry::kOplogVersion, // version oField, // o o2Field, // o2 |
