summaryrefslogtreecommitdiff
path: root/src/mongo/s/write_ops
diff options
context:
space:
mode:
authorJason Zhang <jason.zhang@mongodb.com>2023-05-17 02:23:47 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-05-17 03:15:10 +0000
commit06797deec0c5806e56a70a7d156556e0b028da7f (patch)
tree07788fd471fdf4584b7b4b944c867d78932b88ec /src/mongo/s/write_ops
parentb4b4b310cd5fe22d33a749eca4e43c42c2adf76c (diff)
downloadmongo-06797deec0c5806e56a70a7d156556e0b028da7f.tar.gz
SERVER-69922 Implement explain for updateOne, deleteOne, and findAndModify
Diffstat (limited to 'src/mongo/s/write_ops')
-rw-r--r--src/mongo/s/write_ops/write_without_shard_key_util.cpp87
-rw-r--r--src/mongo/s/write_ops/write_without_shard_key_util.h12
2 files changed, 99 insertions, 0 deletions
diff --git a/src/mongo/s/write_ops/write_without_shard_key_util.cpp b/src/mongo/s/write_ops/write_without_shard_key_util.cpp
index f3d1ed0e4ab..ae0fb38587e 100644
--- a/src/mongo/s/write_ops/write_without_shard_key_util.cpp
+++ b/src/mongo/s/write_ops/write_without_shard_key_util.cpp
@@ -302,5 +302,92 @@ StatusWith<ClusterWriteWithoutShardKeyResponse> runTwoPhaseWriteProtocol(Operati
return StatusWith<ClusterWriteWithoutShardKeyResponse>(swResult.getStatus());
}
}
+
+BSONObj generateExplainResponseForTwoPhaseWriteProtocol(
+ const BSONObj& clusterQueryWithoutShardKeyExplainObj,
+ const BSONObj& clusterWriteWithoutShardKeyExplainObj) {
+ // To express the two phase nature of the two phase write protocol, we use the output of the
+ // 'Read Phase' explain as the 'inputStage' of the 'Write Phase' explain for both queryPlanner
+ // and executionStats sections.
+ //
+ // An example output would look like:
+
+ // "queryPlanner" : {
+ // "winningPlan" : {
+ // "stage" : "SHARD_WRITE",
+ // ...
+ // “inputStage”: {
+ // queryPlanner: {
+ // winningPlan: {
+ // stage: "SHARD_MERGE",
+ // ...
+ //
+ // }
+ // }
+ // }
+ // }
+ // }
+ //
+ // executionStats : {
+ // "executionStages" : {
+ // "stage" : "SHARD_WRITE",
+ // ...
+ // },
+ // "inputStage" : {
+ // "stage" : "SHARD_MERGE",
+ // ...
+ // }
+ //
+ // }
+ // ... other explain result fields ...
+
+ auto queryPlannerOutput = [&] {
+ auto clusterQueryWithoutShardKeyQueryPlannerObj =
+ clusterQueryWithoutShardKeyExplainObj.getObjectField("queryPlanner");
+ auto clusterWriteWithoutShardKeyQueryPlannerObj =
+ clusterWriteWithoutShardKeyExplainObj.getObjectField("queryPlanner");
+
+ auto winningPlan = clusterWriteWithoutShardKeyQueryPlannerObj.getObjectField("winningPlan");
+ BSONObjBuilder newWinningPlanBuilder(winningPlan);
+ newWinningPlanBuilder.appendObject("inputStage",
+ clusterQueryWithoutShardKeyQueryPlannerObj.objdata());
+ auto newWinningPlan = newWinningPlanBuilder.obj();
+
+ auto queryPlannerObjNoWinningPlan =
+ clusterWriteWithoutShardKeyQueryPlannerObj.removeField("winningPlan");
+ BSONObjBuilder newQueryPlannerBuilder(queryPlannerObjNoWinningPlan);
+ newQueryPlannerBuilder.appendObject("winningPlan", newWinningPlan.objdata());
+ return newQueryPlannerBuilder.obj();
+ }();
+
+ auto executionStatsOutput = [&] {
+ auto clusterQueryWithoutShardKeyExecutionStatsObj =
+ clusterQueryWithoutShardKeyExplainObj.getObjectField("executionStats");
+ auto clusterWriteWithoutShardKeyExecutionStatsObj =
+ clusterWriteWithoutShardKeyExplainObj.getObjectField("executionStats");
+
+ if (clusterQueryWithoutShardKeyExecutionStatsObj.isEmpty() &&
+ clusterWriteWithoutShardKeyExecutionStatsObj.isEmpty()) {
+ return BSONObj();
+ }
+
+ BSONObjBuilder newExecutionStatsBuilder(clusterWriteWithoutShardKeyExecutionStatsObj);
+ newExecutionStatsBuilder.appendObject(
+ "inputStage", clusterQueryWithoutShardKeyExecutionStatsObj.objdata());
+ return newExecutionStatsBuilder.obj();
+ }();
+
+ BSONObjBuilder explainOutputBuilder;
+ if (!queryPlannerOutput.isEmpty()) {
+ explainOutputBuilder.appendObject("queryPlanner", queryPlannerOutput.objdata());
+ }
+ if (!executionStatsOutput.isEmpty()) {
+ explainOutputBuilder.appendObject("executionStats", executionStatsOutput.objdata());
+ }
+ // This step is to get 'command', 'serverInfo', and 'serverParamter' fields to return in the
+ // final explain output.
+ explainOutputBuilder.appendElementsUnique(clusterWriteWithoutShardKeyExplainObj);
+ return explainOutputBuilder.obj();
+}
} // namespace write_without_shard_key
} // namespace mongo
diff --git a/src/mongo/s/write_ops/write_without_shard_key_util.h b/src/mongo/s/write_ops/write_without_shard_key_util.h
index bb7e4d0509b..5fb9bb35d68 100644
--- a/src/mongo/s/write_ops/write_without_shard_key_util.h
+++ b/src/mongo/s/write_ops/write_without_shard_key_util.h
@@ -38,6 +38,11 @@
namespace mongo {
namespace write_without_shard_key {
+// Used as a "dummy" target document for constructing explain responses for single writes without
+// shard key.
+const BSONObj targetDocForExplain = BSON("_id"
+ << "WriteWithoutShardKey");
+
/**
* Uses updateDriver to produce the document to insert. Only use when {upsert: true}.
*/
@@ -75,6 +80,13 @@ bool useTwoPhaseProtocol(OperationContext* opCtx,
StatusWith<ClusterWriteWithoutShardKeyResponse> runTwoPhaseWriteProtocol(OperationContext* opCtx,
NamespaceString nss,
BSONObj cmdObj);
+/**
+ * Return a formatted 'explain' response that describes the work done in the two phase write
+ * protocol.
+ **/
+BSONObj generateExplainResponseForTwoPhaseWriteProtocol(
+ const BSONObj& clusterQueryWithoutShardKeyExplainObj,
+ const BSONObj& clusterWriteWithoutShardKeyExplainObj);
} // namespace write_without_shard_key
} // namespace mongo