summaryrefslogtreecommitdiff
path: root/src/mongo/db/ops
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/ops')
-rw-r--r--src/mongo/db/ops/SConscript4
-rw-r--r--src/mongo/db/ops/insert.cpp18
-rw-r--r--src/mongo/db/ops/insert.h1
-rw-r--r--src/mongo/db/ops/parsed_delete.cpp8
-rw-r--r--src/mongo/db/ops/parsed_delete.h2
-rw-r--r--src/mongo/db/ops/parsed_update.cpp1
-rw-r--r--src/mongo/db/ops/update.cpp2
-rw-r--r--src/mongo/db/ops/update_request.h10
-rw-r--r--src/mongo/db/ops/write_ops.cpp303
-rw-r--r--src/mongo/db/ops/write_ops.h42
-rw-r--r--src/mongo/db/ops/write_ops.idl21
-rw-r--r--src/mongo/db/ops/write_ops_exec.cpp159
-rw-r--r--src/mongo/db/ops/write_ops_exec_test.cpp242
-rw-r--r--src/mongo/db/ops/write_ops_retryability.cpp8
-rw-r--r--src/mongo/db/ops/write_ops_retryability_test.cpp1
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