diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-11 15:07:35 -0300 |
| commit | 4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch) | |
| tree | 1682a647d4463397c119183369ae6f750d5fdcff /src/mongo/db/pipeline/document_source.cpp | |
| parent | aa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff) | |
| parent | 8f0827553e09872941945a093b647a4211a9db7f (diff) | |
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0'
with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'src/mongo/db/pipeline/document_source.cpp')
| -rw-r--r-- | src/mongo/db/pipeline/document_source.cpp | 165 |
1 files changed, 49 insertions, 116 deletions
diff --git a/src/mongo/db/pipeline/document_source.cpp b/src/mongo/db/pipeline/document_source.cpp index ea1cf479480..3a5d5d0030c 100644 --- a/src/mongo/db/pipeline/document_source.cpp +++ b/src/mongo/db/pipeline/document_source.cpp @@ -36,13 +36,11 @@ #include "mongo/db/commands/feature_compatibility_version_documentation.h" #include "mongo/db/exec/document_value/value.h" #include "mongo/db/matcher/expression_algo.h" -#include "mongo/db/pipeline/change_stream_constants.h" #include "mongo/db/pipeline/document_source_add_fields.h" #include "mongo/db/pipeline/document_source_group.h" #include "mongo/db/pipeline/document_source_internal_shard_filter.h" #include "mongo/db/pipeline/document_source_match.h" #include "mongo/db/pipeline/document_source_project.h" -#include "mongo/db/pipeline/document_source_redact.h" #include "mongo/db/pipeline/document_source_replace_root.h" #include "mongo/db/pipeline/document_source_sample.h" #include "mongo/db/pipeline/document_source_sequential_document_cache.h" @@ -172,77 +170,45 @@ bool groupMatchSwapVerified(const DocumentSourceMatch& nextMatch, return !expression::hasExistencePredicateOnPath(*(nextMatch.getMatchExpression()), "_id"_sd); } -/** - * Returns 'true' if the given stage is an internal change stream stage that can appear in a router - * (mongoS) pipeline, or 'false' otherwise. - */ -bool isChangeStreamRouterPipelineStage(StringData stageName) { - return change_stream_constants::kChangeStreamRouterPipelineStages.contains(stageName); -} } // namespace bool DocumentSource::pushMatchBefore(Pipeline::SourceContainer::iterator itr, Pipeline::SourceContainer* container) { - if (!constraints().canSwapWithMatch) { - return false; - } - - auto nextStageAsMatch = dynamic_cast<DocumentSourceMatch*>((*std::next(itr)).get()); - if (!nextStageAsMatch || nextStageAsMatch->isTextQuery()) { - // We do not need to attempt this optimization if the $match contains a text search - // predicate because, in that scenario, $match is already required to be the first stage in - // the pipeline. - return false; - } - - // At this point: - // 1) The next stage after 'this' is $match. - // 2) The $match stage does not contain a text search predicate. - - // TODO SERVER-55492: Remove the following workaround when there are rename checks for 'other' - // match expressions. - if (isChangeStreamRouterPipelineStage(this->getSourceName())) { - // Always move the $match stage ahead of internal change stream stages appearing in the - // router (mongoS) pipeline, because they do not access or modify any paths in the input - // document. - container->splice(itr, *container, std::next(itr)); - return true; - } - - auto thisStageAsGroup = dynamic_cast<DocumentSourceGroup*>(this); - if (thisStageAsGroup && !groupMatchSwapVerified(*nextStageAsMatch, *thisStageAsGroup)) { - return false; - } - - auto [renameableMatchPart, nonRenameableMatchPart] = - DocumentSourceMatch::splitMatchByModifiedFields(nextStageAsMatch, getModifiedPaths()); - invariant(renameableMatchPart || nonRenameableMatchPart); - if (!renameableMatchPart) { - return false; - } - - LOGV2_DEBUG(5943503, + auto nextMatch = dynamic_cast<DocumentSourceMatch*>((*std::next(itr)).get()); + auto thisGroup = dynamic_cast<DocumentSourceGroup*>(this); + if (constraints().canSwapWithMatch && nextMatch && !nextMatch->isTextQuery() && + (!thisGroup || groupMatchSwapVerified(*nextMatch, *thisGroup))) { + // We're allowed to swap with a $match and the stage after us is a $match. Furthermore, the + // $match does not contain a text search predicate, which we do not attempt to optimize + // because such a $match must already be the first stage in the pipeline. We can attempt to + // swap the $match or part of the $match before ourselves. + auto splitMatch = + DocumentSourceMatch::splitMatchByModifiedFields(nextMatch, getModifiedPaths()); + invariant(splitMatch.first || splitMatch.second); + + if (splitMatch.first) { + // At least part of the $match can be moved before this stage. Erase the original $match + // and put the independent part before this stage. If splitMatch.second is not null, + // then there is a new $match stage to insert after ourselves which is dependent on the + // modified fields. + LOGV2_DEBUG( + 5943503, 5, "Swapping all or part of a $match stage in front of another stage: ", - "matchMovingBefore"_attr = redact(renameableMatchPart->serializeToBSONForDebug()), + "matchMovingBefore"_attr = redact(splitMatch.first->serializeToBSONForDebug()), "thisStage"_attr = redact(serializeToBSONForDebug()), "matchLeftAfter"_attr = redact( - nonRenameableMatchPart ? nonRenameableMatchPart->serializeToBSONForDebug() - : BSONObj())); - - // At this point we know that at least part of the $match expression can be moved ahead of - // 'this'. So, we erase the original $match and move that renameable part ahead of 'this' stage. - container->erase(std::next(itr)); - container->insert(itr, std::move(renameableMatchPart)); - - // If 'nonRenameableMatchPart' is not null, the 'renameableMatchPart' of the $match expression - // was only one component of the original $match. So, we need to create a new $match stage for - // the remaining 'nonRenameableMatchPart' and insert it after 'this' - effectively keeping it in - // its original position in the pipeline. - if (nonRenameableMatchPart) { - container->insert(std::next(itr), std::move(nonRenameableMatchPart)); + splitMatch.second ? splitMatch.second->serializeToBSONForDebug() : BSONObj())); + container->erase(std::next(itr)); + container->insert(itr, std::move(splitMatch.first)); + if (splitMatch.second) { + container->insert(std::next(itr), std::move(splitMatch.second)); + } + + return true; + } } - return true; + return false; } bool DocumentSource::pushSampleBefore(Pipeline::SourceContainer::iterator itr, @@ -260,9 +226,7 @@ bool DocumentSource::pushSampleBefore(Pipeline::SourceContainer::iterator itr, BSONObj DocumentSource::serializeToBSONForDebug() const { std::vector<Value> serialized; - auto opts = - SerializationOptions{boost::make_optional(ExplainOptions::Verbosity::kQueryPlanner)}; - serializeToArray(serialized, opts); + serializeToArray(serialized, ExplainOptions::Verbosity::kQueryPlanner); if (serialized.empty()) { LOGV2_DEBUG(5943501, 5, @@ -276,24 +240,21 @@ BSONObj DocumentSource::serializeToBSONForDebug() const { return serialized[0].getDocument().toBson(); } -bool DocumentSource::pushSingleDocumentTransformOrRedactBefore( - Pipeline::SourceContainer::iterator itr, Pipeline::SourceContainer* container) { - if (constraints().canSwapWithSingleDocTransformOrRedact) { - auto nextItr = std::next(itr); - if (dynamic_cast<DocumentSourceSingleDocumentTransformation*>(nextItr->get()) || - dynamic_cast<DocumentSourceRedact*>(nextItr->get())) { - LOGV2_DEBUG(5943500, - 5, - "Pushing a single document transform stage or a redact stage in ahead of " - "the current stage: ", - "singleDocTransformOrRedactStage"_attr = - redact((*nextItr)->serializeToBSONForDebug()), - "currentStage"_attr = redact(serializeToBSONForDebug())); - - // Swap 'itr' and 'nextItr' list nodes. - container->splice(itr, *container, nextItr); - return true; - } +bool DocumentSource::pushSingleDocumentTransformBefore(Pipeline::SourceContainer::iterator itr, + Pipeline::SourceContainer* container) { + auto singleDocTransform = + dynamic_cast<DocumentSourceSingleDocumentTransformation*>((*std::next(itr)).get()); + + if (constraints().canSwapWithSingleDocTransform && singleDocTransform) { + LOGV2_DEBUG(5943500, + 5, + "Swapping a single document transform stage in front of another stage: ", + "singleDocTransform"_attr = + redact(singleDocTransform->serializeToBSONForDebug()), + "thisStage"_attr = redact(serializeToBSONForDebug())); + container->insert(itr, std::move(singleDocTransform)); + container->erase(std::next(itr)); + return true; } return false; } @@ -313,43 +274,15 @@ Pipeline::SourceContainer::iterator DocumentSource::optimizeAt( } void DocumentSource::serializeToArray(vector<Value>& array, - const SerializationOptions& opts) const { - Value entry = serialize(opts); + boost::optional<ExplainOptions::Verbosity> explain) const { + Value entry = serialize(explain); if (!entry.missing()) { array.push_back(entry); } } -namespace { -std::list<boost::intrusive_ptr<DocumentSource>> throwOnParse( - BSONElement spec, const boost::intrusive_ptr<ExpressionContext>& expCtx) { - uasserted(6047400, spec.fieldNameStringData() + " stage is only allowed on MongoDB Atlas"); -} -std::unique_ptr<LiteParsedDocumentSource> throwOnParseLite(NamespaceString nss, - const BSONElement& spec) { - uasserted(6047401, spec.fieldNameStringData() + " stage is only allowed on MongoDB Atlas"); -} -} // namespace MONGO_INITIALIZER_GROUP(BeginDocumentSourceRegistration, ("default"), ("EndDocumentSourceRegistration")) -// Any remaining work on the parserMap should be done before finishing DocumentSource Registration. -MONGO_INITIALIZER_WITH_PREREQUISITES(EndDocumentSourceRegistration, - ("BeginDocumentSourceRegistration")) -(InitializerContext*) { - auto searchStageNames = { - "$vectorSearch"_sd, "$search"_sd, "$searchMeta"_sd, "$listSearchIndexes"_sd}; - for (auto stageName : searchStageNames) { - auto searchIt = parserMap.find(stageName); - // If the stage has not been registered at this point, register a parser that errors - // with a useful error message on parsing a search stage. - if (searchIt == parserMap.end()) { - LiteParsedDocumentSource::registerParser(stageName.toString(), - throwOnParseLite, - AllowedWithApiStrict::kAlways, - AllowedWithClientType::kAny); - DocumentSource::registerParser(stageName.toString(), throwOnParse, boost::none); - } - } -} +MONGO_INITIALIZER_GROUP(EndDocumentSourceRegistration, ("BeginDocumentSourceRegistration"), ()) } // namespace mongo |
