diff options
Diffstat (limited to 'src/mongo/db/pipeline')
7 files changed, 84 insertions, 4 deletions
diff --git a/src/mongo/db/pipeline/document_source_merge.h b/src/mongo/db/pipeline/document_source_merge.h index a3623fca678..05a87f1e340 100644 --- a/src/mongo/db/pipeline/document_source_merge.h +++ b/src/mongo/db/pipeline/document_source_merge.h @@ -90,11 +90,17 @@ public: ReadConcernSupportResult supportsReadConcern(repl::ReadConcernLevel level, bool isImplicitDefault) const final { - return { + ReadConcernSupportResult result = { {level == repl::ReadConcernLevel::kLinearizableReadConcern, {ErrorCodes::InvalidOptions, "{} cannot be used with a 'linearizable' read concern level"_format(kStageName)}}, Status::OK()}; + auto pipelineReadConcern = LiteParsedDocumentSourceNestedPipelines::supportsReadConcern( + level, isImplicitDefault); + // Merge the result from the sub-pipeline into the $merge specific read concern result + // to preserve the $merge errors over the internal pipeline errors. + result.merge(pipelineReadConcern); + return result; } PrivilegeVector requiredPrivileges(bool isMongos, diff --git a/src/mongo/db/pipeline/document_source_set_window_fields.cpp b/src/mongo/db/pipeline/document_source_set_window_fields.cpp index 0df6d6d5927..7a9fe901c8f 100644 --- a/src/mongo/db/pipeline/document_source_set_window_fields.cpp +++ b/src/mongo/db/pipeline/document_source_set_window_fields.cpp @@ -75,14 +75,14 @@ bool modifiedSortPaths(const SortPattern& pat, const DocumentSource::GetModPaths REGISTER_DOCUMENT_SOURCE_WITH_MIN_VERSION( setWindowFields, - LiteParsedDocumentSourceDefault::parse, + document_source_set_window_fields::LiteParsedSetWindowFields::parse, document_source_set_window_fields::createFromBson, AllowedWithApiStrict::kNeverInVersion1, multiversion::FeatureCompatibilityVersion::kFullyDowngradedTo_5_0); REGISTER_DOCUMENT_SOURCE_WITH_MIN_VERSION( _internalSetWindowFields, - LiteParsedDocumentSourceDefault::parse, + document_source_set_window_fields::LiteParsedSetWindowFields::parse, DocumentSourceInternalSetWindowFields::createFromBson, AllowedWithApiStrict::kNeverInVersion1, multiversion::FeatureCompatibilityVersion::kFullyDowngradedTo_5_0); diff --git a/src/mongo/db/pipeline/document_source_set_window_fields.h b/src/mongo/db/pipeline/document_source_set_window_fields.h index f854de92653..313961216c4 100644 --- a/src/mongo/db/pipeline/document_source_set_window_fields.h +++ b/src/mongo/db/pipeline/document_source_set_window_fields.h @@ -89,6 +89,39 @@ std::list<boost::intrusive_ptr<DocumentSource>> create( boost::optional<boost::intrusive_ptr<Expression>> partitionBy, const boost::optional<SortPattern>& sortBy, std::vector<WindowFunctionStatement> outputFields); + +class LiteParsedSetWindowFields : public LiteParsedDocumentSource { +public: + static std::unique_ptr<LiteParsedSetWindowFields> parse(const NamespaceString& nss, + const BSONElement& spec) { + return std::make_unique<LiteParsedSetWindowFields>(spec.fieldName()); + } + + explicit LiteParsedSetWindowFields(std::string parseTimeName) + : LiteParsedDocumentSource(std::move(parseTimeName)) {} + + ReadConcernSupportResult supportsReadConcern(repl::ReadConcernLevel level, + bool isImplicitDefault) const { + // $setWindowFields cannot spill to disk if read concern is set to "snapshot". + // TODO SERVER-59772 Enable $setWindowFields with read concern "snapshot". + return {{level == repl::ReadConcernLevel::kSnapshotReadConcern && !isImplicitDefault, + {ErrorCodes::InvalidOptions, + str::stream() << "Aggregation stage " << kStageName + << " cannot run with readConcern '" + << repl::readConcernLevels::toString( + repl::ReadConcernLevel::kSnapshotReadConcern)}}, + // The default read concern can't be snapshot. + boost::none}; + } + + stdx::unordered_set<NamespaceString> getInvolvedNamespaces() const final { + return stdx::unordered_set<NamespaceString>(); + } + + PrivilegeVector requiredPrivileges(bool isMongos, bool bypassDocumentValidation) const final { + return {}; + } +}; } // namespace document_source_set_window_fields class DocumentSourceInternalSetWindowFields final : public DocumentSource { @@ -131,7 +164,9 @@ public: HostTypeRequirement::kNone, DiskUseRequirement::kWritesTmpData, FacetRequirement::kAllowed, - TransactionRequirement::kAllowed, + // $setWindowFields does not work inside transactions. + // TODO SERVER-59772 Enable $setWindowFields inside transactions. + TransactionRequirement::kNotAllowed, LookupRequirement::kAllowed, UnionRequirement::kAllowed); } diff --git a/src/mongo/db/pipeline/lite_parsed_document_source.cpp b/src/mongo/db/pipeline/lite_parsed_document_source.cpp index 9b28609c9d7..121b916a389 100644 --- a/src/mongo/db/pipeline/lite_parsed_document_source.cpp +++ b/src/mongo/db/pipeline/lite_parsed_document_source.cpp @@ -132,4 +132,19 @@ bool LiteParsedDocumentSourceNestedPipelines::allowShardedForeignCollection( }); } +ReadConcernSupportResult LiteParsedDocumentSourceNestedPipelines::supportsReadConcern( + repl::ReadConcernLevel level, bool isImplicitDefault) const { + // Assume that the document source holding the pipeline has no constraints of its own, so + // return the strictest of the constraints on the sub-pipelines. + auto result = ReadConcernSupportResult::allSupportedAndDefaultPermitted(); + for (auto& pipeline : _pipelines) { + result.merge(pipeline.sourcesSupportReadConcern(level, isImplicitDefault)); + // If both result statuses are already not OK, stop checking. + if (!result.readConcernSupport.isOK() && !result.defaultReadConcernPermit.isOK()) { + break; + } + } + return result; +} + } // namespace mongo diff --git a/src/mongo/db/pipeline/lite_parsed_document_source.h b/src/mongo/db/pipeline/lite_parsed_document_source.h index ecc56c170ab..f5fc5fbcb06 100644 --- a/src/mongo/db/pipeline/lite_parsed_document_source.h +++ b/src/mongo/db/pipeline/lite_parsed_document_source.h @@ -295,6 +295,13 @@ public: return _pipelines; } + /** + * Check the read concern constraints of all sub-pipelines. If the stage that owns the + * sub-pipelines has its own constraints this should be overridden to take those into account. + */ + ReadConcernSupportResult supportsReadConcern(repl::ReadConcernLevel level, + bool isImplicitDefault) const override; + protected: boost::optional<NamespaceString> _foreignNss; std::vector<LiteParsedPipeline> _pipelines; diff --git a/src/mongo/db/pipeline/lite_parsed_pipeline.cpp b/src/mongo/db/pipeline/lite_parsed_pipeline.cpp index 94f29755d9b..ff8491c88b7 100644 --- a/src/mongo/db/pipeline/lite_parsed_pipeline.cpp +++ b/src/mongo/db/pipeline/lite_parsed_pipeline.cpp @@ -73,6 +73,16 @@ ReadConcernSupportResult LiteParsedPipeline::supportsReadConcern( // 3. If either the specified or default readConcern have not already been rejected, determine // whether the pipeline stages support them. If not, we record the first error we encounter. + result.merge(sourcesSupportReadConcern(level, isImplicitDefault)); + + return result; +} + +ReadConcernSupportResult LiteParsedPipeline::sourcesSupportReadConcern( + repl::ReadConcernLevel level, bool isImplicitDefault) const { + // Start by assuming that we will support both readConcern and cluster-wide default. + ReadConcernSupportResult result = ReadConcernSupportResult::allSupportedAndDefaultPermitted(); + for (auto&& spec : _stageSpecs) { // If both result statuses are already not OK, stop checking further stages. if (!result.readConcernSupport.isOK() && !result.defaultReadConcernPermit.isOK()) { diff --git a/src/mongo/db/pipeline/lite_parsed_pipeline.h b/src/mongo/db/pipeline/lite_parsed_pipeline.h index 0a7f24b83a5..eecaaa937e1 100644 --- a/src/mongo/db/pipeline/lite_parsed_pipeline.h +++ b/src/mongo/db/pipeline/lite_parsed_pipeline.h @@ -136,6 +136,13 @@ public: bool enableMajorityReadConcern) const; /** + * Checks that all of the stages in this pipeline are allowed to run with the specified read + * concern level. Does not do any pipeline global checks. + */ + ReadConcernSupportResult sourcesSupportReadConcern(repl::ReadConcernLevel level, + bool isImplicitDefault) const; + + /** * Verifies that this pipeline is allowed to run in a multi-document transaction. This ensures * that each stage is compatible, and throws a UserException if not. This should only be called * if the caller has determined the current operation is part of a transaction. |