summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorTed Tuckman <ted.tuckman@mongodb.com>2022-03-02 22:20:32 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-03-02 23:11:24 +0000
commitf25675cc8ea9d89672ce063f49dbdaa39e63ce1b (patch)
treeb1867e1b1e3db4dc5083da673bd62aa4cc218767 /src/mongo/db
parent27ce39ba637159ae0be6e7734b1d7f114af7141c (diff)
downloadmongo-f25675cc8ea9d89672ce063f49dbdaa39e63ce1b.tar.gz
SERVER-62535 Allow sharded aggregation to return two cursors
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/commands/find_cmd.cpp3
-rw-r--r--src/mongo/db/commands/run_aggregate.cpp38
-rw-r--r--src/mongo/db/exec/sbe_cmd.cpp4
-rw-r--r--src/mongo/db/pipeline/SConscript1
-rw-r--r--src/mongo/db/pipeline/pipeline.h27
-rw-r--r--src/mongo/db/pipeline/plan_executor_pipeline.h5
-rw-r--r--src/mongo/db/pipeline/search_helper.h16
-rw-r--r--src/mongo/db/pipeline/sharded_agg_helpers.cpp10
-rw-r--r--src/mongo/db/query/SConscript1
-rw-r--r--src/mongo/db/query/cursor_idl_validator.cpp44
-rw-r--r--src/mongo/db/query/cursor_idl_validator.h40
-rw-r--r--src/mongo/db/query/cursor_response.cpp15
-rw-r--r--src/mongo/db/query/cursor_response.h12
-rw-r--r--src/mongo/db/query/cursor_response.idl52
-rw-r--r--src/mongo/db/query/cursor_response_test.cpp1
-rw-r--r--src/mongo/db/query/plan_executor.h7
-rw-r--r--src/mongo/db/query/query_request_test.cpp2
17 files changed, 268 insertions, 10 deletions
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index 732233dd194..2de5d93b52f 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -591,7 +591,8 @@ public:
const CursorId cursorId = 0;
endQueryOp(opCtx, collection, *exec, numResults, cursorId);
auto bodyBuilder = result->getBodyBuilder();
- appendCursorResponseObject(cursorId, nss.ns(), BSONArray(), &bodyBuilder);
+ appendCursorResponseObject(
+ cursorId, nss.ns(), BSONArray(), boost::none, &bodyBuilder);
return;
}
diff --git a/src/mongo/db/commands/run_aggregate.cpp b/src/mongo/db/commands/run_aggregate.cpp
index 813ad0e0a3e..64907d4d7d3 100644
--- a/src/mongo/db/commands/run_aggregate.cpp
+++ b/src/mongo/db/commands/run_aggregate.cpp
@@ -141,8 +141,11 @@ bool handleCursorCommand(OperationContext* opCtx,
invariant(cursors[idx]);
BSONObjBuilder cursorResult;
- appendCursorResponseObject(
- cursors[idx]->cursorid(), nsForCursor.ns(), BSONArray(), &cursorResult);
+ appendCursorResponseObject(cursors[idx]->cursorid(),
+ nsForCursor.ns(),
+ BSONArray(),
+ cursors[idx]->getExecutor()->getExecutorType(),
+ &cursorResult);
cursorResult.appendBool("ok", 1);
cursorsBuilder.append(cursorResult.obj());
@@ -514,6 +517,35 @@ std::vector<std::unique_ptr<Pipeline, PipelineDeleter>> createExchangePipelinesI
}
/**
+ * Creates additional pipelines if needed to serve the aggregation. This includes additional
+ * pipelines for exchange optimization and search commands that generate metadata. Returns
+ * a vector of all pipelines needed for the query, including the original one.
+ *
+ * Takes ownership of the original, passed in, pipeline.
+ */
+std::vector<std::unique_ptr<Pipeline, PipelineDeleter>> createAdditionalPipelinesIfNeeded(
+ OperationContext* opCtx,
+ boost::intrusive_ptr<ExpressionContext> expCtx,
+ const AggregateCommandRequest& request,
+ std::unique_ptr<Pipeline, PipelineDeleter> pipeline,
+ boost::optional<UUID> collUUID) {
+
+ std::vector<std::unique_ptr<Pipeline, PipelineDeleter>> pipelines;
+ // Exchange is not allowed to be specified if there is a $search stage.
+ if (auto metadataPipe = getSearchHelpers(opCtx->getServiceContext())
+ ->generateMetadataPipelineForSearch(
+ opCtx, expCtx, request, pipeline.get(), collUUID)) {
+ pipelines.push_back(std::move(pipeline));
+ pipelines.push_back(std::move(metadataPipe));
+ } else {
+ // Takes ownership of 'pipeline'.
+ pipelines =
+ createExchangePipelinesIfNeeded(opCtx, expCtx, request, std::move(pipeline), collUUID);
+ }
+ return pipelines;
+}
+
+/**
* Performs validations related to API versioning and time-series stages.
* Throws UserAssertion if any of the validations fails
* - validation of API versioning on each stage on the pipeline
@@ -574,7 +606,7 @@ std::vector<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> createLegacyEx
std::move(attachExecutorCallback.second),
pipeline.get());
- auto pipelines = createExchangePipelinesIfNeeded(
+ auto pipelines = createAdditionalPipelinesIfNeeded(
expCtx->opCtx, expCtx, request, std::move(pipeline), expCtx->uuid);
for (auto&& pipelineIt : pipelines) {
// There are separate ExpressionContexts for each exchange pipeline, so make sure to
diff --git a/src/mongo/db/exec/sbe_cmd.cpp b/src/mongo/db/exec/sbe_cmd.cpp
index bba9d728375..de2d5131932 100644
--- a/src/mongo/db/exec/sbe_cmd.cpp
+++ b/src/mongo/db/exec/sbe_cmd.cpp
@@ -148,7 +148,7 @@ public:
}
if (exec->isEOF()) {
- appendCursorResponseObject(0LL, nss.ns(), firstBatch.arr(), &result);
+ appendCursorResponseObject(0LL, nss.ns(), firstBatch.arr(), boost::none, &result);
return true;
}
@@ -167,7 +167,7 @@ public:
{}});
appendCursorResponseObject(
- pinnedCursor.getCursor()->cursorid(), nss.ns(), firstBatch.arr(), &result);
+ pinnedCursor.getCursor()->cursorid(), nss.ns(), firstBatch.arr(), boost::none, &result);
return true;
}
diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript
index aa47aef4bb0..c87ca855fd8 100644
--- a/src/mongo/db/pipeline/SConscript
+++ b/src/mongo/db/pipeline/SConscript
@@ -354,6 +354,7 @@ pipelineEnv.Library(
'$BUILD_DIR/mongo/db/pipeline/lite_parsed_document_source',
'$BUILD_DIR/mongo/db/query/collation/collator_factory_interface',
'$BUILD_DIR/mongo/db/query/collation/collator_interface',
+ '$BUILD_DIR/mongo/db/query/cursor_response_idl',
'$BUILD_DIR/mongo/db/query/datetime/date_time_support',
'$BUILD_DIR/mongo/db/query/query_knobs',
'$BUILD_DIR/mongo/db/query/sort_pattern',
diff --git a/src/mongo/db/pipeline/pipeline.h b/src/mongo/db/pipeline/pipeline.h
index e1ef7b6a0a4..6cdf67181b9 100644
--- a/src/mongo/db/pipeline/pipeline.h
+++ b/src/mongo/db/pipeline/pipeline.h
@@ -41,6 +41,7 @@
#include "mongo/db/namespace_string.h"
#include "mongo/db/pipeline/dependencies.h"
#include "mongo/db/pipeline/sharded_agg_helpers_targeting_policy.h"
+#include "mongo/db/query/cursor_response_gen.h"
#include "mongo/db/query/explain_options.h"
#include "mongo/db/query/query_knobs_gen.h"
#include "mongo/executor/task_executor.h"
@@ -382,6 +383,21 @@ public:
*/
friend class PipelineD;
+ /**
+ * For commands that return multiple pipelines, this value will contain the type of pipeline.
+ * This can be populated to the cursor so consumers do not have to depend on order or guess
+ * which pipeline is which. Default to a regular result pipeline.
+ */
+ CursorTypeEnum pipelineType = CursorTypeEnum::DocumentResult;
+
+ /**
+ * Get a string representation of the pipeline type.
+ */
+ auto getTypeString() {
+ return CursorType_serializer(pipelineType);
+ }
+
+
private:
friend class PipelineDeleter;
@@ -450,4 +466,15 @@ private:
bool _dismissed = false;
};
+/**
+ * A 'ServiceContext' decorator that by default does nothing but can be set to generate a
+ * complimentary, metadata pipeline to the one passed in.
+ */
+extern ServiceContext::Decoration<std::unique_ptr<Pipeline, PipelineDeleter> (*)(
+ OperationContext* opCtx,
+ boost::intrusive_ptr<ExpressionContext> expCtx,
+ const AggregateCommandRequest& request,
+ Pipeline* origPipeline,
+ boost::optional<UUID> uuid)>
+ generateMetadataPipelineFunc;
} // namespace mongo
diff --git a/src/mongo/db/pipeline/plan_executor_pipeline.h b/src/mongo/db/pipeline/plan_executor_pipeline.h
index efef0a7bb2d..d320a63062a 100644
--- a/src/mongo/db/pipeline/plan_executor_pipeline.h
+++ b/src/mongo/db/pipeline/plan_executor_pipeline.h
@@ -163,6 +163,11 @@ public:
return false;
}
+ boost::optional<StringData> getExecutorType() const override {
+ tassert(6253504, "Can't get type string without pipeline", _pipeline);
+ return _pipeline->getTypeString();
+ }
+
private:
/**
* Obtains the next document from the underlying Pipeline, and does change streams-related
diff --git a/src/mongo/db/pipeline/search_helper.h b/src/mongo/db/pipeline/search_helper.h
index fb38cd88690..25a224565a8 100644
--- a/src/mongo/db/pipeline/search_helper.h
+++ b/src/mongo/db/pipeline/search_helper.h
@@ -46,6 +46,22 @@ public:
// invoked for inner collection in $lookup, for instance, only when expanded pipeline is passed
// to the specific shard.
virtual void injectSearchShardFiltererIfNeeded(Pipeline* pipeline){};
+
+ /**
+ * Check to see if in the current environment an additional pipeline needs to be run by the
+ * aggregation command to generate metadata results. Either returns the additional pipeline
+ * or nullptr if no pipeline is necessary.
+ *
+ * This can modify the passed in pipeline but does not take ownership of it.
+ */
+ virtual std::unique_ptr<Pipeline, PipelineDeleter> generateMetadataPipelineForSearch(
+ OperationContext* opCtx,
+ boost::intrusive_ptr<ExpressionContext> expCtx,
+ const AggregateCommandRequest& request,
+ Pipeline* origPipeline,
+ boost::optional<UUID> uuid) {
+ return nullptr;
+ }
};
/**
diff --git a/src/mongo/db/pipeline/sharded_agg_helpers.cpp b/src/mongo/db/pipeline/sharded_agg_helpers.cpp
index f2b7073f5a3..a7ba134a672 100644
--- a/src/mongo/db/pipeline/sharded_agg_helpers.cpp
+++ b/src/mongo/db/pipeline/sharded_agg_helpers.cpp
@@ -963,7 +963,15 @@ DispatchShardPipelineResults dispatchShardPipeline(
"needsPrimaryShardMerge"_attr = needsPrimaryShardMerge);
splitPipelines = splitPipeline(std::move(pipeline));
- exchangeSpec = checkIfEligibleForExchange(opCtx, splitPipelines->mergePipeline.get());
+ // If the first stage of the pipeline is a $search stage, exchange optimization isn't
+ // possible.
+ // TODO SERVER-62537 Investigate relaxing this restriction.
+ if (!splitPipelines || !splitPipelines->shardsPipeline ||
+ !splitPipelines->shardsPipeline->peekFront() ||
+ splitPipelines->shardsPipeline->peekFront()->getSourceName() !=
+ "$_internalSearchMongotRemote"_sd) {
+ exchangeSpec = checkIfEligibleForExchange(opCtx, splitPipelines->mergePipeline.get());
+ }
}
// Generate the command object for the targeted shards.
diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript
index 7977f23f239..797009e9df7 100644
--- a/src/mongo/db/query/SConscript
+++ b/src/mongo/db/query/SConscript
@@ -183,6 +183,7 @@ env.Library(
env.Library(
target='cursor_response_idl',
source=[
+ 'cursor_idl_validator.cpp',
'cursor_response.idl',
],
LIBDEPS_PRIVATE=[
diff --git a/src/mongo/db/query/cursor_idl_validator.cpp b/src/mongo/db/query/cursor_idl_validator.cpp
new file mode 100644
index 00000000000..c66964a7e7e
--- /dev/null
+++ b/src/mongo/db/query/cursor_idl_validator.cpp
@@ -0,0 +1,44 @@
+/**
+ * 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/query/cursor_idl_validator.h"
+
+namespace mongo {
+
+/**
+ * Function used by the IDL parser to validate that a response has exactly one cursor type field.
+ */
+void validateIDLParsedCursorResponse(const CursorInitialReply* idlParsedObj) {
+ bool hasCursor = idlParsedObj->getCursor() != boost::none;
+ bool hasCursors = idlParsedObj->getCursors() != boost::none;
+ uassert(6253507,
+ "MultiResponseInitialCursor must have exactly one of 'cursor' or 'cursors' fields",
+ hasCursor != hasCursors);
+}
+} // namespace mongo
diff --git a/src/mongo/db/query/cursor_idl_validator.h b/src/mongo/db/query/cursor_idl_validator.h
new file mode 100644
index 00000000000..31617d7a428
--- /dev/null
+++ b/src/mongo/db/query/cursor_idl_validator.h
@@ -0,0 +1,40 @@
+/**
+ * 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.
+ */
+
+#pragma once
+#include "mongo/db/query/cursor_response_gen.h"
+
+namespace mongo {
+
+class CursorInitialReply;
+/**
+ * Function used by the IDL parser to validate that a response has exactly one cursor type field.
+ */
+void validateIDLParsedCursorResponse(const CursorInitialReply* idlParsedObj);
+} // namespace mongo
diff --git a/src/mongo/db/query/cursor_response.cpp b/src/mongo/db/query/cursor_response.cpp
index b4042f559b1..81bbe7ed1b9 100644
--- a/src/mongo/db/query/cursor_response.cpp
+++ b/src/mongo/db/query/cursor_response.cpp
@@ -45,6 +45,7 @@ const char kCursorField[] = "cursor";
const char kIdField[] = "id";
const char kNsField[] = "ns";
const char kVarsField[] = "vars";
+const char kTypeField[] = "type";
const char kAtClusterTimeField[] = "atClusterTime";
const char kBatchField[] = "nextBatch";
const char kBatchFieldInitial[] = "firstBatch";
@@ -104,11 +105,15 @@ void CursorResponseBuilder::abandon() {
void appendCursorResponseObject(long long cursorId,
StringData cursorNamespace,
BSONArray firstBatch,
+ boost::optional<StringData> cursorType,
BSONObjBuilder* builder) {
BSONObjBuilder cursorObj(builder->subobjStart(kCursorField));
cursorObj.append(kIdField, cursorId);
cursorObj.append(kNsField, cursorNamespace);
cursorObj.append(kBatchFieldInitial, firstBatch);
+ if (cursorType) {
+ cursorObj.append(kTypeField, cursorType.get());
+ }
cursorObj.done();
}
@@ -130,6 +135,7 @@ CursorResponse::CursorResponse(NamespaceString nss,
boost::optional<BSONObj> postBatchResumeToken,
boost::optional<BSONObj> writeConcernError,
boost::optional<BSONObj> varsField,
+ boost::optional<std::string> cursorType,
bool partialResultsReturned,
bool invalidated)
: _nss(std::move(nss)),
@@ -139,6 +145,7 @@ CursorResponse::CursorResponse(NamespaceString nss,
_postBatchResumeToken(std::move(postBatchResumeToken)),
_writeConcernError(std::move(writeConcernError)),
_varsField(std::move(varsField)),
+ _cursorType(std::move(cursorType)),
_partialResultsReturned(partialResultsReturned),
_invalidated(invalidated) {}
@@ -209,6 +216,13 @@ StatusWith<CursorResponse> CursorResponse::parseFromBSON(const BSONObj& cmdRespo
<< "' must be of type object in: " << cmdResponse};
}
+ BSONElement typeElt = cursorObj[kTypeField];
+ if (!typeElt.eoo() && typeElt.type() != BSONType::String) {
+ return {ErrorCodes::TypeMismatch,
+ str::stream() << "Field '" << kTypeField << "' must be of type string but got "
+ << typeElt.type() << " in: " << cmdResponse};
+ }
+
BSONElement batchElt = cursorObj[kBatchField];
if (batchElt.eoo()) {
batchElt = cursorObj[kBatchFieldInitial];
@@ -297,6 +311,7 @@ StatusWith<CursorResponse> CursorResponse::parseFromBSON(const BSONObj& cmdRespo
: boost::optional<BSONObj>{},
writeConcernError ? writeConcernError.Obj().getOwned() : boost::optional<BSONObj>{},
varsElt ? varsElt.Obj().getOwned() : boost::optional<BSONObj>{},
+ typeElt ? boost::make_optional<std::string>(typeElt.String()) : boost::none,
partialResultsReturned.trueValue(),
invalidatedElem.trueValue()}};
}
diff --git a/src/mongo/db/query/cursor_response.h b/src/mongo/db/query/cursor_response.h
index ca81974e78b..a8151d7709a 100644
--- a/src/mongo/db/query/cursor_response.h
+++ b/src/mongo/db/query/cursor_response.h
@@ -142,13 +142,17 @@ private:
* and appends the response object to the provided builder under the field name "cursor".
*
* The response object has the following format:
- * { id: <NumberLong>, ns: <String>, firstBatch: <Array> }.
+ * { id: <NumberLong>, ns: <String>, firstBatch: <Array> , type: <String>}.
+ *
+ * The type field is optional, but can be used to differentiate cursors if multiple are returned
+ * at once.
*
* This function is deprecated. Prefer CursorResponseBuilder or CursorResponse::toBSON() instead.
*/
void appendCursorResponseObject(long long cursorId,
StringData cursorNamespace,
BSONArray firstBatch,
+ boost::optional<StringData> cursorType,
BSONObjBuilder* builder);
/**
@@ -207,6 +211,7 @@ public:
boost::optional<BSONObj> postBatchResumeToken = boost::none,
boost::optional<BSONObj> writeConcernError = boost::none,
boost::optional<BSONObj> varsField = boost::none,
+ boost::optional<std::string> cursorType = boost::none,
bool partialResultsReturned = false,
bool invalidated = false);
@@ -249,6 +254,10 @@ public:
return _varsField;
}
+ auto getCursorType() const {
+ return _cursorType;
+ }
+
bool getPartialResultsReturned() const {
return _partialResultsReturned;
}
@@ -274,6 +283,7 @@ private:
boost::optional<BSONObj> _postBatchResumeToken;
boost::optional<BSONObj> _writeConcernError;
boost::optional<BSONObj> _varsField;
+ boost::optional<std::string> _cursorType;
bool _partialResultsReturned = false;
bool _invalidated = false;
};
diff --git a/src/mongo/db/query/cursor_response.idl b/src/mongo/db/query/cursor_response.idl
index 16f79c4be4d..8233f906c75 100644
--- a/src/mongo/db/query/cursor_response.idl
+++ b/src/mongo/db/query/cursor_response.idl
@@ -33,10 +33,19 @@ global:
cpp_includes:
- "mongo/db/namespace_string.h"
- "mongo/idl/basic_types.h"
+ - "mongo/db/query/cursor_idl_validator.h"
imports:
- "mongo/idl/basic_types.idl"
+enums:
+ CursorType:
+ description: "The type of a single cursor if a response has multiple cursors"
+ type: string
+ values:
+ SearchMetaResult: "meta"
+ DocumentResult: "results"
+
structs:
ResponseCursorBase:
description: "Common fields of initial and subsequent cursor responses."
@@ -80,18 +89,59 @@ structs:
type: array<object>
unstable: false
+ MultiResponseInitialResponseCursor:
+ description: "A struct representing an initial response cursor if multiple cursors are returned."
+ inline_chained_structs: true
+ chained_structs:
+ ResponseCursorBase: ResponseCursorBase
+ fields:
+ firstBatch:
+ description: "The first batch of the cursor."
+ type: array<object>
+ unstable: false
+ type:
+ description: "Optional disambiguation string of a cursor."
+ type: CursorType
+ cpp_name: cursorType
+ unstable: true
+ optional: true
+
+ MultiResponseCursor:
+ description: "A struct representing a cursor object inside an array of cursors"
+ fields:
+ cursor:
+ description: "The actual cursor object."
+ type: MultiResponseInitialResponseCursor
+ unstable: true
+ ok:
+ type: bool
+ unstable: true
+
CursorInitialReply:
description: "A struct representing a initial cursor reply."
+ cpp_validator_func: "validateIDLParsedCursorResponse"
fields:
cursor:
description: "A response cursor object."
type: InitialResponseCursor
unstable: false
+ optional: true
+ cursors:
+ description: "An array of cursor objects."
+ type: array<MultiResponseCursor>
+ unstable: true
+ optional: true
vars:
description: "An optional field containing additional response information for the query."
type: object
optional: true
- unstable: false
+ unstable: true
+ type:
+ description: "An optional field containing disambiguation information if a reply contains multiple cursors."
+ type: CursorType
+ cpp_name: cursorType
+ optional: true
+ unstable: true
GetMoreResponseCursor:
description: "A struct representing a subsequent response cursor."
diff --git a/src/mongo/db/query/cursor_response_test.cpp b/src/mongo/db/query/cursor_response_test.cpp
index 6cedc76ccb0..183c27e05d6 100644
--- a/src/mongo/db/query/cursor_response_test.cpp
+++ b/src/mongo/db/query/cursor_response_test.cpp
@@ -348,6 +348,7 @@ TEST(CursorResponseTest, toBSONPartialResultsReturned) {
boost::none,
boost::none,
boost::none,
+ boost::none,
true);
BSONObj responseObj = response.toBSON(CursorResponse::ResponseType::InitialResponse);
BSONObj expectedResponse = BSON(
diff --git a/src/mongo/db/query/plan_executor.h b/src/mongo/db/query/plan_executor.h
index 9748e3de303..80857984d3e 100644
--- a/src/mongo/db/query/plan_executor.h
+++ b/src/mongo/db/query/plan_executor.h
@@ -359,6 +359,13 @@ public:
*/
virtual void enableSaveRecoveryUnitAcrossCommandsIfSupported() = 0;
virtual bool isSaveRecoveryUnitAcrossCommandsEnabled() const = 0;
+
+ /**
+ * For queries that have multiple executors, this can be used to differentiate between them.
+ */
+ virtual boost::optional<StringData> getExecutorType() const {
+ return boost::none;
+ }
};
} // namespace mongo
diff --git a/src/mongo/db/query/query_request_test.cpp b/src/mongo/db/query/query_request_test.cpp
index 8c58484990a..20e618eff17 100644
--- a/src/mongo/db/query/query_request_test.cpp
+++ b/src/mongo/db/query/query_request_test.cpp
@@ -1551,7 +1551,7 @@ TEST(QueryRequestTest, ConvertToFindWithAllowDiskUseFalseSucceeds) {
TEST(QueryRequestHelperTest, ValidateResponseMissingFields) {
BSONObjBuilder builder;
ASSERT_THROWS_CODE(
- query_request_helper::validateCursorResponse(builder.asTempObj()), DBException, 40414);
+ query_request_helper::validateCursorResponse(builder.asTempObj()), DBException, 6253507);
}
TEST(QueryRequestHelperTest, ValidateResponseWrongDataType) {