summaryrefslogtreecommitdiff
path: root/src/mongo/s/query/cluster_find.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/s/query/cluster_find.cpp')
-rw-r--r--src/mongo/s/query/cluster_find.cpp78
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,