summaryrefslogtreecommitdiff
path: root/src/mongo/db/commands/find_cmd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/commands/find_cmd.cpp')
-rw-r--r--src/mongo/db/commands/find_cmd.cpp57
1 files changed, 38 insertions, 19 deletions
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index f7ac781404f..1fdb621add3 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -133,11 +133,17 @@ std::unique_ptr<FindCommandRequest> parseCmdObjectToFindCommandRequest(Operation
boost::intrusive_ptr<ExpressionContext> makeExpressionContext(
OperationContext* opCtx,
const FindCommandRequest& findCommand,
+ const CollectionPtr& collPtr,
boost::optional<ExplainOptions::Verbosity> verbosity) {
std::unique_ptr<CollatorInterface> collator;
if (!findCommand.getCollation().isEmpty()) {
collator = uassertStatusOK(CollatorFactoryInterface::get(opCtx->getServiceContext())
->makeFromBSON(findCommand.getCollation()));
+ } else if (collPtr && collPtr->getDefaultCollator()) {
+ // The 'collPtr' will be null for views, but we don't need to worry about views here. The
+ // views will get rewritten into aggregate command and will regenerate the
+ // ExpressionContext.
+ collator = collPtr->getDefaultCollator()->clone();
}
// Although both 'find' and 'aggregate' commands have an ExpressionContext, some of the data
@@ -320,7 +326,16 @@ public:
// Finish the parsing step by using the FindCommandRequest to create a CanonicalQuery.
const ExtensionsCallbackReal extensionsCallback(opCtx, &nss);
- auto expCtx = makeExpressionContext(opCtx, *findCommand, verbosity);
+
+ // The collection may be NULL. If so, getExecutor() should handle it by returning an
+ // execution tree with an EOFStage.
+ const auto& collection = ctx->getCollection();
+ if (!ctx->getView()) {
+ const bool isClusteredCollection = collection && collection->isClustered();
+ uassertStatusOK(query_request_helper::validateResumeAfter(
+ findCommand->getResumeAfter(), isClusteredCollection));
+ }
+ auto expCtx = makeExpressionContext(opCtx, *findCommand, collection, verbosity);
const bool isExplain = true;
auto cq = uassertStatusOK(
CanonicalQuery::canonicalize(opCtx,
@@ -370,10 +385,6 @@ public:
return;
}
- // The collection may be NULL. If so, getExecutor() should handle it by returning an
- // execution tree with an EOFStage.
- const auto& collection = ctx->getCollection();
-
// Get the execution plan for the query.
bool permitYield = true;
auto exec =
@@ -505,14 +516,16 @@ public:
}
// Tailing a replicated capped clustered collection requires majority read concern.
- const auto coll = ctx->getCollection().get();
- if (coll) {
+ const auto& collection = ctx->getCollection();
+
+ bool isClusteredCollection = false;
+ if (collection) {
const bool isTailable = findCommand->getTailable();
const bool isMajorityReadConcern = repl::ReadConcernArgs::get(opCtx).getLevel() ==
repl::ReadConcernLevel::kMajorityReadConcern;
- const bool isClusteredCollection = coll->isClustered();
- const bool isCapped = coll->isCapped();
- const bool isReplicated = coll->ns().isReplicated();
+ isClusteredCollection = collection->isClustered();
+ const bool isCapped = collection->isCapped();
+ const bool isReplicated = collection->ns().isReplicated();
if (isClusteredCollection && isCapped && isReplicated && isTailable) {
uassert(ErrorCodes::Error(6049203),
"A tailable cursor on a capped clustered collection requires majority "
@@ -521,12 +534,22 @@ public:
}
}
+ // Views use the aggregation system and the $_resumeAfter parameter is not allowed. A
+ // more descriptive error will be raised later, but we want to validate this parameter
+ // before beginning the operation.
+ if (!ctx->getView()) {
+ uassertStatusOK(query_request_helper::validateResumeAfter(
+ findCommand->getResumeAfter(), isClusteredCollection));
+ }
+
// Fill out curop information.
beginQueryOp(opCtx, nss, _request.body);
// Finish the parsing step by using the FindCommandRequest to create a CanonicalQuery.
const ExtensionsCallbackReal extensionsCallback(opCtx, &nss);
- auto expCtx = makeExpressionContext(opCtx, *findCommand, boost::none /* verbosity */);
+
+ auto expCtx =
+ makeExpressionContext(opCtx, *findCommand, collection, boost::none /* verbosity */);
auto cq = uassertStatusOK(
CanonicalQuery::canonicalize(opCtx,
std::move(findCommand),
@@ -570,8 +593,6 @@ public:
uassertStatusOK(replCoord->checkCanServeReadsFor(
opCtx, nss, ReadPreferenceSetting::get(opCtx).canRunOnSecondary()));
- const auto& collection = ctx->getCollection();
-
if (cq->getFindCommandRequest().getReadOnce()) {
// The readOnce option causes any storage-layer cursors created during plan
// execution to assume read data will not be needed again and need not be cached.
@@ -656,8 +677,6 @@ public:
auto&& [stats, _] =
explainer.getWinningPlanStats(ExplainOptions::Verbosity::kExecStats);
LOGV2_WARNING(23798,
- "Plan executor error during find command: {error}, "
- "stats: {stats}, cmd: {cmd}",
"Plan executor error during find command",
"error"_attr = exception.toStatus(),
"stats"_attr = redact(stats),
@@ -715,14 +734,14 @@ public:
if (stashResourcesForGetMore) {
// Collect storage stats now before we stash the recovery unit. These stats are
// normally collected in the service entry point layer just before a command
- // ends, but they must be collected before stashing the
- // RecoveryUnit. Otherwise, the service entry point layer will collect the
- // stats from the new RecoveryUnit, which wasn't actually used for the query.
+ // ends, but they must be collected before stashing the RecoveryUnit. Otherwise,
+ // the service entry point layer will collect the stats from the new
+ // RecoveryUnit, which wasn't actually used for the query.
//
// The stats collected here will not get overwritten, as the service entry
// point layer will only set these stats when they're not empty.
CurOp::get(opCtx)->debug().storageStats =
- opCtx->recoveryUnit()->getOperationStatistics();
+ opCtx->recoveryUnit()->computeOperationStatisticsSinceLastCall();
}
} else {
endQueryOp(opCtx, collection, *exec, numResults, cursorId);