diff options
author | Ted Tuckman <ted.tuckman@mongodb.com> | 2022-03-02 22:20:32 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-03-02 23:11:24 +0000 |
commit | f25675cc8ea9d89672ce063f49dbdaa39e63ce1b (patch) | |
tree | b1867e1b1e3db4dc5083da673bd62aa4cc218767 /src/mongo/db | |
parent | 27ce39ba637159ae0be6e7734b1d7f114af7141c (diff) | |
download | mongo-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.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/commands/run_aggregate.cpp | 38 | ||||
-rw-r--r-- | src/mongo/db/exec/sbe_cmd.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/pipeline/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/pipeline/pipeline.h | 27 | ||||
-rw-r--r-- | src/mongo/db/pipeline/plan_executor_pipeline.h | 5 | ||||
-rw-r--r-- | src/mongo/db/pipeline/search_helper.h | 16 | ||||
-rw-r--r-- | src/mongo/db/pipeline/sharded_agg_helpers.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/query/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/query/cursor_idl_validator.cpp | 44 | ||||
-rw-r--r-- | src/mongo/db/query/cursor_idl_validator.h | 40 | ||||
-rw-r--r-- | src/mongo/db/query/cursor_response.cpp | 15 | ||||
-rw-r--r-- | src/mongo/db/query/cursor_response.h | 12 | ||||
-rw-r--r-- | src/mongo/db/query/cursor_response.idl | 52 | ||||
-rw-r--r-- | src/mongo/db/query/cursor_response_test.cpp | 1 | ||||
-rw-r--r-- | src/mongo/db/query/plan_executor.h | 7 | ||||
-rw-r--r-- | src/mongo/db/query/query_request_test.cpp | 2 |
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) { |