summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/commands/find_and_modify.cpp14
-rw-r--r--src/mongo/db/ops/write_ops.idl38
-rw-r--r--src/mongo/db/ops/write_ops_exec.cpp26
-rw-r--r--src/mongo/s/commands/cluster_write_without_shard_key_cmd.cpp57
4 files changed, 122 insertions, 13 deletions
diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp
index bf0189073a5..2d0082285eb 100644
--- a/src/mongo/db/commands/find_and_modify.cpp
+++ b/src/mongo/db/commands/find_and_modify.cpp
@@ -684,8 +684,18 @@ write_ops::FindAndModifyCommandReply CmdFindAndModify::Invocation::typedRun(
}
if (analyze_shard_key::supportsPersistingSampledQueries() && req.getSampleId()) {
- analyze_shard_key::QueryAnalysisWriter::get(opCtx)->addFindAndModifyQuery(req).getAsync(
- [](auto) {});
+ auto findAndModifyOp = req;
+
+ // If the initial query was a write without shard key, the two phase write protocol
+ // modifies the query in the write phase. In order to get correct metrics, we need to
+ // reconstruct the original query prior to sampling.
+ if (req.getOriginalQuery()) {
+ findAndModifyOp.setQuery(*req.getOriginalQuery());
+ findAndModifyOp.setCollation(req.getOriginalCollation());
+ }
+ analyze_shard_key::QueryAnalysisWriter::get(opCtx)
+ ->addFindAndModifyQuery(findAndModifyOp)
+ .getAsync([](auto) {});
}
if (MONGO_unlikely(failAllFindAndModify.shouldFail())) {
diff --git a/src/mongo/db/ops/write_ops.idl b/src/mongo/db/ops/write_ops.idl
index 5f793cb9780..4fe3d0d7650 100644
--- a/src/mongo/db/ops/write_ops.idl
+++ b/src/mongo/db/ops/write_ops.idl
@@ -205,6 +205,25 @@ structs:
type: EncryptionInformation
optional: true
stability: unstable
+ $_originalQuery:
+ description: "The original write query. This is used for updateOne/deleteOne
+ without shard key during the write phase of the two phase protocol in
+ order to make sure the shard key query analysis stores the correct
+ client query."
+ type: object
+ optional: true
+ cpp_name: originalQuery
+ stability: internal
+ $_originalCollation:
+ description: "The original write query. This is used for updateOne/deleteOne
+ without shard key during the write phase of the two phase protocol in
+ order to make sure the shard key query analysis stores the correct
+ client collation."
+ type: object
+ optional: true
+ cpp_name: originalCollation
+ stability: internal
+
UpdateOpEntry:
description: "Parser for the entries in the 'updates' array of an update command."
@@ -550,3 +569,22 @@ commands:
type: uuid
optional: true
stability: unstable
+ $_originalQuery:
+ description: "The original write query. This is used for findAndModify without shard
+ key during the write phase of the two phase protocol in order to make
+ sure the shard key query analysis stores the correct client
+ query."
+ type: object
+ optional: true
+ cpp_name: originalQuery
+ stability: internal
+ $_originalCollation:
+ description: "The original collation. This is used for findAndModify without shard
+ key during the write phase of the two phase protocol in order to make
+ sure the shard key query analysis stores the correct client
+ collation."
+ type: object
+ optional: true
+ cpp_name: originalCollation
+ stability: internal
+
diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp
index dcb72a4ca93..71d6531de1a 100644
--- a/src/mongo/db/ops/write_ops_exec.cpp
+++ b/src/mongo/db/ops/write_ops_exec.cpp
@@ -1106,8 +1106,18 @@ WriteResult performUpdates(OperationContext* opCtx,
});
if (analyze_shard_key::supportsPersistingSampledQueries() && singleOp.getSampleId()) {
+ auto updateOp = wholeOp;
+
+ // If the initial query was a write without shard key, the two phase write protocol
+ // modifies the query in the write phase. In order to get correct metrics, we need to
+ // reconstruct the original query prior to sampling.
+ if (wholeOp.getOriginalQuery()) {
+ updateOp.getUpdates().front().setQ(*wholeOp.getOriginalQuery());
+ updateOp.getUpdates().front().setCollation(wholeOp.getOriginalCollation());
+ }
+
analyze_shard_key::QueryAnalysisWriter::get(opCtx)
- ->addUpdateQuery(wholeOp, currentOpIndex)
+ ->addUpdateQuery(updateOp, currentOpIndex)
.getAsync([](auto) {});
}
@@ -1354,8 +1364,18 @@ WriteResult performDeletes(OperationContext* opCtx,
});
if (analyze_shard_key::supportsPersistingSampledQueries() && singleOp.getSampleId()) {
+ auto deleteOp = wholeOp;
+
+ // If the initial query was a write without shard key, the two phase write protocol
+ // modifies the query in the write phase. In order to get correct metrics, we need to
+ // reconstruct the original query prior to sampling.
+ if (wholeOp.getOriginalQuery()) {
+ deleteOp.getDeletes().front().setQ(*wholeOp.getOriginalQuery());
+ deleteOp.getDeletes().front().setCollation(wholeOp.getOriginalCollation());
+ }
+
analyze_shard_key::QueryAnalysisWriter::get(opCtx)
- ->addDeleteQuery(wholeOp, currentOpIndex)
+ ->addDeleteQuery(deleteOp, currentOpIndex)
.getAsync([](auto) {});
}
@@ -1389,7 +1409,7 @@ WriteResult performDeletes(OperationContext* opCtx,
}
return out;
-}
+} // namespace mongo::write_ops_exec
Status performAtomicTimeseriesWrites(
OperationContext* opCtx,
diff --git a/src/mongo/s/commands/cluster_write_without_shard_key_cmd.cpp b/src/mongo/s/commands/cluster_write_without_shard_key_cmd.cpp
index 3250f90b0af..7d9a470dc4a 100644
--- a/src/mongo/s/commands/cluster_write_without_shard_key_cmd.cpp
+++ b/src/mongo/s/commands/cluster_write_without_shard_key_cmd.cpp
@@ -49,30 +49,71 @@ BSONObj _createCmdObj(const BSONObj& writeCmd,
const StringData& commandName,
const BSONObj& targetDocId,
const NamespaceString& nss) {
- // Drop collation and writeConcern as
- // targeting by _id uses default collation and writeConcern cannot be specified for
- // commands run in internal transactions. This object will be used to construct the command
- // request used by clusterWriteWithoutShardKey.
+
+ // Drop the writeConcern as it cannot be specified for commands run in internal transactions.
+ // This object will be used to construct the command request used by
+ // _clusterWriteWithoutShardKey.
BSONObjBuilder writeCmdObjBuilder(
- writeCmd.removeFields(std::set<std::string>{"collation", "writeConcern"}));
+ writeCmd.removeField(WriteConcernOptions::kWriteConcernField));
writeCmdObjBuilder.appendElementsUnique(BSON("$db" << nss.dbName().toString()));
auto writeCmdObj = writeCmdObjBuilder.obj();
// Parse original write command and set _id as query filter for new command object.
if (commandName == "update") {
auto parsedUpdateRequest = write_ops::UpdateCommandRequest::parse(
- IDLParserContext("_clusterWriteWithoutShardKey"), writeCmdObj);
+ IDLParserContext("_clusterWriteWithoutShardKeyForUpdate"), writeCmdObj);
+
+ // The original query and collation are sent along with the modified command for the
+ // purposes of query sampling.
+ if (parsedUpdateRequest.getUpdates().front().getSampleId()) {
+ auto writeCommandRequestBase = write_ops::WriteCommandRequestBase(
+ parsedUpdateRequest.getWriteCommandRequestBase());
+ writeCommandRequestBase.setOriginalQuery(
+ parsedUpdateRequest.getUpdates().front().getQ());
+ writeCommandRequestBase.setOriginalCollation(
+ parsedUpdateRequest.getUpdates().front().getCollation());
+ parsedUpdateRequest.setWriteCommandRequestBase(writeCommandRequestBase);
+ }
+
parsedUpdateRequest.getUpdates().front().setQ(targetDocId);
+ // Unset the collation because targeting by _id uses default collation.
+ parsedUpdateRequest.getUpdates().front().setCollation(boost::none);
return parsedUpdateRequest.toBSON(BSONObj());
} else if (commandName == "delete") {
auto parsedDeleteRequest = write_ops::DeleteCommandRequest::parse(
- IDLParserContext("_clusterWriteWithoutShardKey"), writeCmdObj);
+ IDLParserContext("_clusterWriteWithoutShardKeyForDelete"), writeCmdObj);
+
+ // The original query and collation are sent along with the modified command for the
+ // purposes of query sampling.
+ if (parsedDeleteRequest.getDeletes().front().getSampleId()) {
+ auto writeCommandRequestBase = write_ops::WriteCommandRequestBase(
+ parsedDeleteRequest.getWriteCommandRequestBase());
+ writeCommandRequestBase.setOriginalQuery(
+ parsedDeleteRequest.getDeletes().front().getQ());
+ writeCommandRequestBase.setOriginalCollation(
+ parsedDeleteRequest.getDeletes().front().getCollation());
+ parsedDeleteRequest.setWriteCommandRequestBase(writeCommandRequestBase);
+ }
+
parsedDeleteRequest.getDeletes().front().setQ(targetDocId);
+ // Unset the collation because targeting by _id uses default collation.
+ parsedDeleteRequest.getDeletes().front().setCollation(boost::none);
return parsedDeleteRequest.toBSON(BSONObj());
} else if (commandName == "findandmodify" || commandName == "findAndModify") {
auto parsedFindAndModifyRequest = write_ops::FindAndModifyCommandRequest::parse(
- IDLParserContext("_clusterWriteWithoutShardKey"), writeCmdObj);
+ IDLParserContext("_clusterWriteWithoutShardKeyForFindAndModify"), writeCmdObj);
+
+ // The original query and collation are sent along with the modified command for the
+ // purposes of query sampling.
+ if (parsedFindAndModifyRequest.getSampleId()) {
+ parsedFindAndModifyRequest.setOriginalQuery(parsedFindAndModifyRequest.getQuery());
+ parsedFindAndModifyRequest.setOriginalCollation(
+ parsedFindAndModifyRequest.getCollation());
+ }
+
parsedFindAndModifyRequest.setQuery(targetDocId);
+ // Unset the collation because targeting by _id uses default collation.
+ parsedFindAndModifyRequest.setCollation(boost::none);
return parsedFindAndModifyRequest.toBSON(BSONObj());
} else {
uasserted(ErrorCodes::InvalidOptions,