diff options
Diffstat (limited to 'src/mongo/s/query/cluster_find.cpp')
| -rw-r--r-- | src/mongo/s/query/cluster_find.cpp | 78 |
1 files changed, 34 insertions, 44 deletions
diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp index 01c78f9c3c5..bd186639684 100644 --- a/src/mongo/s/query/cluster_find.cpp +++ b/src/mongo/s/query/cluster_find.cpp @@ -33,7 +33,6 @@ #include "mongo/s/query/cluster_find.h" -#include "mongo/db/query/query_stats/query_stats.h" #include <fmt/format.h> #include <memory> @@ -55,7 +54,6 @@ #include "mongo/db/query/find_common.h" #include "mongo/db/query/getmore_command_gen.h" #include "mongo/db/query/query_planner_common.h" -#include "mongo/db/query/query_stats/query_stats.h" #include "mongo/executor/task_executor_pool.h" #include "mongo/logv2/log.h" #include "mongo/platform/overflow_arithmetic.h" @@ -63,7 +61,6 @@ #include "mongo/s/client/num_hosts_targeted_metrics.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/cluster_commands_helpers.h" -#include "mongo/s/collection_uuid_mismatch.h" #include "mongo/s/grid.h" #include "mongo/s/query/async_results_merger.h" #include "mongo/s/query/cluster_client_cursor_impl.h" @@ -85,6 +82,11 @@ static const BSONObj kSortKeyMetaProjection = BSON("$meta" << "sortKey"); static const BSONObj kGeoNearDistanceMetaProjection = BSON("$meta" << "geoNearDistance"); +// We must allow some amount of overhead per result document, since when we make a cursor response +// the documents are elements of a BSONArray. The overhead is 1 byte/doc for the type + 1 byte/doc +// for the field name's null terminator + 1 byte per digit in the array index. The index can be no +// more than 8 decimal digits since the response is at most 16MB, and 16 * 1024 * 1024 < 1 * 10^8. +static const int kPerDocumentOverheadBytesUpperBound = 10; const char kFindCmdName[] = "find"; @@ -301,9 +303,12 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, if (ex.code() == ErrorCodes::CollectionUUIDMismatch && !ex.extraInfo<CollectionUUIDMismatchInfo>()->actualCollection() && !shardIds.count(cm.dbPrimary())) { - // We received CollectionUUIDMismatch but it does not contain the actual namespace, and - // we did not attempt to establish a cursor on the primary shard. - uassertStatusOK(populateCollectionUUIDMismatch(opCtx, ex.toStatus())); + // We received CollectionUUIDMismatchInfo but it does not contain the actual + // namespace, and we did not attempt to establish a cursor on the primary shard. + // Attempt to do so now in case the collection corresponding to the provided UUID is + // unsharded. This should throw CollectionUUIDMismatchInfo, StaleShardVersion, or + // StaleDbVersion. + establishCursorsOnShards({cm.dbPrimary()}); MONGO_UNREACHABLE; } @@ -336,7 +341,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, FindCommon::waitInFindBeforeMakingBatch(opCtx, query); auto cursorState = ClusterCursorManager::CursorState::NotExhausted; - FindCommon::BSONArrayResponseSizeTracker responseSizeTracker; + size_t bytesBuffered = 0; // 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 @@ -359,13 +364,14 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, // If adding this object will cause us to exceed the message size limit, then we stash it // for later. - if (!responseSizeTracker.haveSpaceForNext(nextObj)) { + if (!FindCommon::haveSpaceForNext(nextObj, results->size(), bytesBuffered)) { ccc->queueResult(nextObj); break; } - // Add doc to the batch. - responseSizeTracker.add(nextObj); + // Add doc to the batch. Account for the space overhead associated with returning this doc + // inside a BSON array. + bytesBuffered += (nextObj.objsize() + kPerDocumentOverheadBytesUpperBound); results->push_back(std::move(nextObj)); } @@ -375,26 +381,23 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, cursorState = ClusterCursorManager::CursorState::Exhausted; } - auto&& opDebug = CurOp::get(opCtx)->debug(); // Fill out query exec properties. - opDebug.nShards = ccc->getNumRemotes(); - opDebug.additiveMetrics.nBatches = 1; + CurOp::get(opCtx)->debug().nShards = ccc->getNumRemotes(); + CurOp::get(opCtx)->debug().nreturned = results->size(); // If the caller wants to know whether the cursor returned partial results, set it here. if (partialResultsReturned) { *partialResultsReturned = ccc->partialResultsReturned(); } - CurOp::get(opCtx)->setEndOfOpMetrics(results->size()); // If the cursor is exhausted, then there are no more results to return and we don't need to // allocate a cursor id. if (cursorState == ClusterCursorManager::CursorState::Exhausted) { - opDebug.cursorExhausted = true; + CurOp::get(opCtx)->debug().cursorExhausted = true; if (shardIds.size() > 0) { updateNumHostsTargetedMetrics(opCtx, cm, shardIds.size()); } - collectQueryStatsMongos(opCtx, ccc->takeKey()); return CursorId(0); } @@ -405,13 +408,13 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx, ? ClusterCursorManager::CursorLifetime::Immortal : ClusterCursorManager::CursorLifetime::Mortal; auto authUsers = AuthorizationSession::get(opCtx->getClient())->getAuthenticatedUserNames(); - collectQueryStatsMongos(opCtx, ccc); + ccc->incNBatches(); auto cursorId = uassertStatusOK(cursorManager->registerCursor( opCtx, ccc.releaseCursor(), query.nss(), cursorType, cursorLifetime, authUsers)); // Record the cursorID in CurOp. - opDebug.cursorid = cursorId; + CurOp::get(opCtx)->debug().cursorid = cursorId; if (shardIds.size() > 0) { updateNumHostsTargetedMetrics(opCtx, cm, shardIds.size()); @@ -471,19 +474,6 @@ Status setUpOperationContextStateForGetMore(OperationContext* opCtx, return Status::OK(); } -CursorId earlyExitWithNoResults(OperationContext* opCtx, - const CanonicalQuery& query, - const FindCommandRequest& findCommand) { - uassert(CollectionUUIDMismatchInfo(query.nss().db().toString(), - *findCommand.getCollectionUUID(), - query.nss().coll().toString(), - boost::none), - "Database does not exist", - !findCommand.getCollectionUUID()); - collectQueryStatsMongos(opCtx, std::move(CurOp::get(opCtx)->debug().queryStatsInfo.key)); - - return CursorId(0); -} } // namespace const size_t ClusterFind::kMaxRetries = 10; @@ -526,7 +516,7 @@ CursorId ClusterFind::runQuery(OperationContext* opCtx, if (swCM == ErrorCodes::NamespaceNotFound) { // If the database doesn't exist, we successfully return an empty result set without // creating a cursor. - return earlyExitWithNoResults(opCtx, query, findCommand); + return CursorId(0); } const auto cm = uassertStatusOK(std::move(swCM)); @@ -773,7 +763,7 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, } std::vector<BSONObj> batch; - FindCommon::BSONArrayResponseSizeTracker responseSizeTracker; + size_t bytesBuffered = 0; long long batchSize = cmd.getBatchSize().value_or(0); auto cursorState = ClusterCursorManager::CursorState::NotExhausted; BSONObj postBatchResumeToken; @@ -826,7 +816,8 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, break; } - if (!responseSizeTracker.haveSpaceForNext(*next.getValue().getResult())) { + if (!FindCommon::haveSpaceForNext( + *next.getValue().getResult(), batch.size(), bytesBuffered)) { pinnedCursor.getValue()->queueResult(*next.getValue().getResult()); stashedResult = true; break; @@ -835,8 +826,10 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, // As soon as we get a result, this operation no longer waits. awaitDataState(opCtx).shouldWaitForInserts = false; - // Add doc to the batch. - responseSizeTracker.add(*next.getValue().getResult()); + // Add doc to the batch. Account for the space overhead associated with returning this doc + // inside a BSON array. + bytesBuffered += + (next.getValue().getResult()->objsize() + kPerDocumentOverheadBytesUpperBound); batch.push_back(std::move(*next.getValue().getResult())); // Update the postBatchResumeToken. For non-$changeStream aggregations, this will be empty. @@ -853,20 +846,17 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, postBatchResumeToken = pinnedCursor.getValue()->getPostBatchResumeToken(); } - auto&& opDebug = CurOp::get(opCtx)->debug(); - // Set nReturned and whether the cursor has been exhausted. - opDebug.cursorExhausted = (idToReturn == 0); - opDebug.additiveMetrics.nBatches = 1; - CurOp::get(opCtx)->setEndOfOpMetrics(batch.size()); - const bool partialResultsReturned = pinnedCursor.getValue()->partialResultsReturned(); pinnedCursor.getValue()->setLeftoverMaxTimeMicros(opCtx->getRemainingMaxTimeMicros()); - collectQueryStatsMongos(opCtx, pinnedCursor.getValue()); - + pinnedCursor.getValue()->incNBatches(); // Upon successful completion, transfer ownership of the cursor back to the cursor manager. If // the cursor has been exhausted, the cursor manager will clean it up for us. pinnedCursor.getValue().returnCursor(cursorState); + // Set nReturned and whether the cursor has been exhausted. + CurOp::get(opCtx)->debug().cursorExhausted = (idToReturn == 0); + CurOp::get(opCtx)->debug().nreturned = batch.size(); + if (MONGO_unlikely(waitBeforeUnpinningOrDeletingCursorAfterGetMoreBatch.shouldFail())) { CurOpFailpointHelpers::waitWhileFailPointEnabled( &waitBeforeUnpinningOrDeletingCursorAfterGetMoreBatch, |
