diff options
author | Jason Zhang <jason.zhang@mongodb.com> | 2023-05-17 02:23:47 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-05-17 03:15:10 +0000 |
commit | 06797deec0c5806e56a70a7d156556e0b028da7f (patch) | |
tree | 07788fd471fdf4584b7b4b944c867d78932b88ec /src/mongo/s/write_ops | |
parent | b4b4b310cd5fe22d33a749eca4e43c42c2adf76c (diff) | |
download | mongo-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.cpp | 87 | ||||
-rw-r--r-- | src/mongo/s/write_ops/write_without_shard_key_util.h | 12 |
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 |