diff options
Diffstat (limited to 'src/mongo/s/query')
-rw-r--r-- | src/mongo/s/query/async_results_merger_test.cpp | 2 | ||||
-rw-r--r-- | src/mongo/s/query/cluster_find.cpp | 110 | ||||
-rw-r--r-- | src/mongo/s/query/results_merger_test_fixture.h | 18 |
3 files changed, 68 insertions, 62 deletions
diff --git a/src/mongo/s/query/async_results_merger_test.cpp b/src/mongo/s/query/async_results_merger_test.cpp index 00112add13b..fd156343e2a 100644 --- a/src/mongo/s/query/async_results_merger_test.cpp +++ b/src/mongo/s/query/async_results_merger_test.cpp @@ -38,7 +38,7 @@ #include "mongo/db/pipeline/resume_token.h" #include "mongo/db/query/cursor_response.h" #include "mongo/db/query/getmore_request.h" -#include "mongo/db/query/query_request.h" +#include "mongo/db/query/query_request_helper.h" #include "mongo/executor/task_executor.h" #include "mongo/s/catalog/type_shard.h" #include "mongo/s/client/shard_registry.h" diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp index 7fac4105e93..02c4b570ac9 100644 --- a/src/mongo/s/query/cluster_find.cpp +++ b/src/mongo/s/query/cluster_find.cpp @@ -84,86 +84,94 @@ static const int kPerDocumentOverheadBytesUpperBound = 10; const char kFindCmdName[] = "find"; /** - * Given the QueryRequest 'qr' being executed by mongos, returns a copy of the query which is - * suitable for forwarding to the targeted hosts. + * Given the FindCommand 'findCommand' being executed by mongos, returns a copy of the query which + * is suitable for forwarding to the targeted hosts. */ -StatusWith<std::unique_ptr<QueryRequest>> transformQueryForShards( - const QueryRequest& qr, bool appendGeoNearDistanceProjection) { +StatusWith<std::unique_ptr<FindCommand>> transformQueryForShards( + const FindCommand& findCommand, bool appendGeoNearDistanceProjection) { // If there is a limit, we forward the sum of the limit and the skip. boost::optional<int64_t> newLimit; - if (qr.getLimit()) { + if (findCommand.getLimit()) { long long newLimitValue; - if (overflow::add(*qr.getLimit(), qr.getSkip().value_or(0), &newLimitValue)) { + if (overflow::add( + *findCommand.getLimit(), findCommand.getSkip().value_or(0), &newLimitValue)) { return Status( ErrorCodes::Overflow, str::stream() << "sum of limit and skip cannot be represented as a 64-bit integer, limit: " - << *qr.getLimit() << ", skip: " << qr.getSkip().value_or(0)); + << *findCommand.getLimit() << ", skip: " << findCommand.getSkip().value_or(0)); } newLimit = newLimitValue; } // Similarly, if nToReturn is set, we forward the sum of nToReturn and the skip. boost::optional<int64_t> newNToReturn; - if (qr.getNToReturn()) { + if (findCommand.getNtoreturn()) { // 'singleBatch' and ntoreturn mean the same as 'singleBatch' and limit, so perform the // conversion. - if (qr.isSingleBatch()) { + if (findCommand.getSingleBatch()) { int64_t newLimitValue; - if (overflow::add(*qr.getNToReturn(), qr.getSkip().value_or(0), &newLimitValue)) { + if (overflow::add(*findCommand.getNtoreturn(), + findCommand.getSkip().value_or(0), + &newLimitValue)) { return Status(ErrorCodes::Overflow, str::stream() << "sum of ntoreturn and skip cannot be represented as a 64-bit " "integer, ntoreturn: " - << *qr.getNToReturn() << ", skip: " << qr.getSkip().value_or(0)); + << *findCommand.getNtoreturn() + << ", skip: " << findCommand.getSkip().value_or(0)); } newLimit = newLimitValue; } else { int64_t newNToReturnValue; - if (overflow::add(*qr.getNToReturn(), qr.getSkip().value_or(0), &newNToReturnValue)) { + if (overflow::add(*findCommand.getNtoreturn(), + findCommand.getSkip().value_or(0), + &newNToReturnValue)) { return Status(ErrorCodes::Overflow, str::stream() << "sum of ntoreturn and skip cannot be represented as a 64-bit " "integer, ntoreturn: " - << *qr.getNToReturn() << ", skip: " << qr.getSkip().value_or(0)); + << *findCommand.getNtoreturn() + << ", skip: " << findCommand.getSkip().value_or(0)); } newNToReturn = newNToReturnValue; } } // If there is a sort other than $natural, we send a sortKey meta-projection to the remote node. - BSONObj newProjection = qr.getProj(); - if (!qr.getSort().isEmpty() && !qr.getSort()[QueryRequest::kNaturalSortField]) { + BSONObj newProjection = findCommand.getProjection(); + if (!findCommand.getSort().isEmpty() && + !findCommand.getSort()[query_request_helper::kNaturalSortField]) { BSONObjBuilder projectionBuilder; - projectionBuilder.appendElements(qr.getProj()); + projectionBuilder.appendElements(findCommand.getProjection()); projectionBuilder.append(AsyncResultsMerger::kSortKeyField, kSortKeyMetaProjection); newProjection = projectionBuilder.obj(); } if (appendGeoNearDistanceProjection) { - invariant(qr.getSort().isEmpty()); + invariant(findCommand.getSort().isEmpty()); BSONObjBuilder projectionBuilder; - projectionBuilder.appendElements(qr.getProj()); + projectionBuilder.appendElements(findCommand.getProjection()); projectionBuilder.append(AsyncResultsMerger::kSortKeyField, kGeoNearDistanceMetaProjection); newProjection = projectionBuilder.obj(); } - auto newQR = std::make_unique<QueryRequest>(qr); - newQR->setProj(newProjection); + auto newQR = std::make_unique<FindCommand>(findCommand); + newQR->setProjection(newProjection); newQR->setSkip(boost::none); newQR->setLimit(newLimit); - newQR->setNToReturn(newNToReturn); + newQR->setNtoreturn(newNToReturn); // Even if the client sends us singleBatch=true, we may need to retrieve // multiple batches from a shard in order to return the single requested batch to the client. // Therefore, we must always send singleBatch=false to the shards. - newQR->setSingleBatchField(false); + newQR->setSingleBatch(false); // Any expansion of the 'showRecordId' flag should have already happened on mongos. - if (newQR->showRecordId()) + if (newQR->getShowRecordId()) newQR->setShowRecordId(false); - invariant(newQR->validate()); + uassertStatusOK(query_request_helper::validateFindCommand(*newQR)); return std::move(newQR); } @@ -178,20 +186,20 @@ std::vector<std::pair<ShardId, BSONObj>> constructRequestsForShards( const CanonicalQuery& query, bool appendGeoNearDistanceProjection) { - std::unique_ptr<QueryRequest> qrToForward; + std::unique_ptr<FindCommand> findCommandToForward; if (shardIds.size() > 1) { - qrToForward = uassertStatusOK( - transformQueryForShards(query.getQueryRequest(), appendGeoNearDistanceProjection)); + findCommandToForward = uassertStatusOK( + transformQueryForShards(query.getFindCommand(), appendGeoNearDistanceProjection)); } else { - // Forwards the QueryRequest as is to a single shard so that limit and skip can + // Forwards the FindCommand as is to a single shard so that limit and skip can // be applied on mongod. - qrToForward = std::make_unique<QueryRequest>(query.getQueryRequest()); + findCommandToForward = std::make_unique<FindCommand>(query.getFindCommand()); } auto& readConcernArgs = repl::ReadConcernArgs::get(opCtx); if (readConcernArgs.wasAtClusterTimeSelected()) { // If mongos selected atClusterTime or received it from client, transmit it to shard. - qrToForward->setReadConcern(readConcernArgs.toBSONInner()); + findCommandToForward->setReadConcern(readConcernArgs.toBSONInner()); } auto shardRegistry = Grid::get(opCtx)->shardRegistry(); @@ -201,7 +209,7 @@ std::vector<std::pair<ShardId, BSONObj>> constructRequestsForShards( invariant(!shard->isConfig() || shard->getConnString()); BSONObjBuilder cmdBuilder; - qrToForward->asFindCommand(&cmdBuilder); + findCommandToForward->serialize(BSONObj(), &cmdBuilder); if (cm.isSharded()) { cm.getVersion(shardId).appendToCommand(&cmdBuilder); @@ -240,20 +248,20 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, const ChunkManager& cm, std::vector<BSONObj>* results, bool* partialResultsReturned) { + auto findCommand = query.getFindCommand(); // Get the set of shards on which we will run the query. - auto shardIds = getTargetedShardsForQuery(query.getExpCtx(), - cm, - query.getQueryRequest().getFilter(), - query.getQueryRequest().getCollation()); + auto shardIds = getTargetedShardsForQuery( + query.getExpCtx(), cm, findCommand.getFilter(), findCommand.getCollation()); // Construct the query and parameters. Defer setting skip and limit here until // we determine if the query is targeting multi-shards or a single shard below. ClusterClientCursorParams params( query.nss(), APIParameters::get(opCtx), readPref, ReadConcernArgs::get(opCtx)); params.originatingCommandObj = CurOp::get(opCtx)->opDescription().getOwned(); - params.batchSize = query.getQueryRequest().getEffectiveBatchSize(); - params.tailableMode = query.getQueryRequest().getTailableMode(); - params.isAllowPartialResults = query.getQueryRequest().isAllowPartialResults(); + params.batchSize = + findCommand.getBatchSize() ? findCommand.getBatchSize() : findCommand.getNtoreturn(); + params.tailableMode = query_request_helper::getTailableMode(findCommand); + params.isAllowPartialResults = findCommand.getAllowPartialResults(); params.lsid = opCtx->getLogicalSessionId(); params.txnNumber = opCtx->getTxnNumber(); params.originatingPrivileges = { @@ -274,8 +282,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, // sort on mongos. Including a $natural anywhere in the sort spec results in the whole sort // being considered a hint to use a collection scan. BSONObj sortComparatorObj; - if (query.getSortPattern() && - !query.getQueryRequest().getSort()[QueryRequest::kNaturalSortField]) { + if (query.getSortPattern() && !findCommand.getSort()[query_request_helper::kNaturalSortField]) { // We have already validated the input sort object. Serialize the raw sort spec into one // suitable for use as the ordering specification in BSONObj::woCompare(). In particular, we // want to eliminate sorts using expressions (like $meta) and replace them with a @@ -303,7 +310,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, // Tailable cursors can't have a sort, which should have already been validated. tassert(4457013, "tailable cursor unexpectedly has a sort", - sortComparatorObj.isEmpty() || !query.getQueryRequest().isTailable()); + sortComparatorObj.isEmpty() || !findCommand.getTailable()); // Construct the requests that we will use to establish cursors on the targeted shards, // attaching the shardVersion and txnNumber, if necessary. @@ -317,7 +324,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, query.nss(), readPref, requests, - query.getQueryRequest().isAllowPartialResults()); + findCommand.getAllowPartialResults()); // Determine whether the cursor we may eventually register will be single- or multi-target. @@ -328,9 +335,8 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, // Only set skip, limit and sort to be applied to on the router for the multi-shard case. For // the single-shard case skip/limit as well as sorts are appled on mongod. if (cursorType == ClusterCursorManager::CursorType::MultiTarget) { - const auto qr = query.getQueryRequest(); - params.skipToApplyOnRouter = qr.getSkip(); - params.limit = qr.getLimit(); + params.skipToApplyOnRouter = findCommand.getSkip(); + params.limit = findCommand.getLimit(); params.sortToApplyOnRouter = sortComparatorObj; params.compareWholeSortKeyOnRouter = compareWholeSortKeyOnRouter; } @@ -350,7 +356,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, // This loop will not result in actually calling getMore against shards, but just loading // results from the initial batches (that were obtained while establishing cursors) into // 'results'. - while (!FindCommon::enoughForFirstBatch(query.getQueryRequest(), results->size())) { + while (!FindCommon::enoughForFirstBatch(findCommand, results->size())) { auto next = uassertStatusOK(ccc->next(RouterExecStage::ExecContext::kInitialFind)); if (next.isEOF()) { @@ -381,7 +387,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, ccc->detachFromOperationContext(); - if (query.getQueryRequest().isSingleBatch() && !ccc->isTailable()) { + if (findCommand.getSingleBatch() && !ccc->isTailable()) { cursorState = ClusterCursorManager::CursorState::Exhausted; } @@ -408,7 +414,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, // Register the cursor with the cursor manager for subsequent getMore's. auto cursorManager = Grid::get(opCtx)->getCursorManager(); - const auto cursorLifetime = query.getQueryRequest().isNoCursorTimeout() + const auto cursorLifetime = findCommand.getNoCursorTimeout() ? ClusterCursorManager::CursorLifetime::Immortal : ClusterCursorManager::CursorLifetime::Mortal; auto authUsers = AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(); @@ -488,19 +494,19 @@ CursorId ClusterFind::runQuery(OperationContext* opCtx, // We must always have a BSONObj vector into which to output our results. invariant(results); + auto findCommand = query.getFindCommand(); // Projection on the reserved sort key field is illegal in mongos. - if (query.getQueryRequest().getProj().hasField(AsyncResultsMerger::kSortKeyField)) { + if (findCommand.getProjection().hasField(AsyncResultsMerger::kSortKeyField)) { uasserted(ErrorCodes::BadValue, str::stream() << "Projection contains illegal field '" << AsyncResultsMerger::kSortKeyField - << "': " << query.getQueryRequest().getProj()); + << "': " << findCommand.getProjection()); } // Attempting to establish a resumable query through mongoS is illegal. uassert(ErrorCodes::BadValue, "Queries on mongoS may not request or provide a resume token", - !query.getQueryRequest().getRequestResumeToken() && - query.getQueryRequest().getResumeAfter().isEmpty()); + !findCommand.getRequestResumeToken() && findCommand.getResumeAfter().isEmpty()); auto const catalogCache = Grid::get(opCtx)->catalogCache(); diff --git a/src/mongo/s/query/results_merger_test_fixture.h b/src/mongo/s/query/results_merger_test_fixture.h index d653bfe0bfa..10978c11cb7 100644 --- a/src/mongo/s/query/results_merger_test_fixture.h +++ b/src/mongo/s/query/results_merger_test_fixture.h @@ -72,22 +72,22 @@ protected: if (findCmd) { // If there is no '$db', append it. auto cmd = OpMsgRequest::fromDBAndBody(kTestNss.db(), *findCmd).body; - const auto qr = - QueryRequest::makeFromFindCommandForTests(cmd, false /* isExplain */, kTestNss); - if (!qr->getSort().isEmpty()) { - params.setSort(qr->getSort().getOwned()); + const auto findCommand = + query_request_helper::makeFromFindCommandForTests(cmd, kTestNss); + if (!findCommand->getSort().isEmpty()) { + params.setSort(findCommand->getSort().getOwned()); } if (getMoreBatchSize) { params.setBatchSize(getMoreBatchSize); } else { - params.setBatchSize(qr->getBatchSize() - ? boost::optional<std::int64_t>( - static_cast<std::int64_t>(*qr->getBatchSize())) + params.setBatchSize(findCommand->getBatchSize() + ? boost::optional<std::int64_t>(static_cast<std::int64_t>( + *findCommand->getBatchSize())) : boost::none); } - params.setTailableMode(qr->getTailableMode()); - params.setAllowPartialResults(qr->isAllowPartialResults()); + params.setTailableMode(query_request_helper::getTailableMode(*findCommand)); + params.setAllowPartialResults(findCommand->getAllowPartialResults()); } OperationSessionInfoFromClient sessionInfo; |