diff options
16 files changed, 83 insertions, 45 deletions
diff --git a/src/mongo/db/pipeline/document_source.h b/src/mongo/db/pipeline/document_source.h index 29b98369723..ee3977aed18 100644 --- a/src/mongo/db/pipeline/document_source.h +++ b/src/mongo/db/pipeline/document_source.h @@ -314,9 +314,13 @@ public: /** * Makes a deep clone of the DocumentSource by serializing and re-parsing it. DocumentSources - * that cannot be safely cloned this way should override this method. + * that cannot be safely cloned this way should override this method. Callers can optionally + * specify 'newExpCtx' to construct the deep clone with it instead of defaulting to the + * original's 'ExpressionContext'. */ - virtual boost::intrusive_ptr<DocumentSource> clone() const { + virtual boost::intrusive_ptr<DocumentSource> clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx = nullptr) const { + auto expCtx = newExpCtx ? newExpCtx : pExpCtx; std::vector<Value> serializedDoc; serializeToArray(serializedDoc); tassert(5757900, @@ -324,7 +328,7 @@ public: << " should have serialized to exactly one document. This stage may " "need a custom clone() implementation", serializedDoc.size() == 1 && serializedDoc[0].getType() == BSONType::Object); - auto dsList = parse(pExpCtx, Document(serializedDoc[0].getDocument()).toBson()); + auto dsList = parse(expCtx, Document(serializedDoc[0].getDocument()).toBson()); // Cloning should only happen once the pipeline has been fully built, after desugaring from // one stage to multiple stages has occurred. When cloning desugared stages we expect each // stage to re-parse to one stage. diff --git a/src/mongo/db/pipeline/document_source_change_stream_oplog_match.h b/src/mongo/db/pipeline/document_source_change_stream_oplog_match.h index 52b26a181a7..d6278a400c7 100644 --- a/src/mongo/db/pipeline/document_source_change_stream_oplog_match.h +++ b/src/mongo/db/pipeline/document_source_change_stream_oplog_match.h @@ -43,14 +43,16 @@ public: DocumentSourceChangeStreamOplogMatch(Timestamp clusterTime, const boost::intrusive_ptr<ExpressionContext>& expCtx); - DocumentSourceChangeStreamOplogMatch(const DocumentSourceChangeStreamOplogMatch& other) - : DocumentSourceMatch(other) { + DocumentSourceChangeStreamOplogMatch(const DocumentSourceChangeStreamOplogMatch& other, + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) + : DocumentSourceMatch(other, newExpCtx) { _clusterTime = other._clusterTime; _optimizedEndOfPipeline = other._optimizedEndOfPipeline; } - boost::intrusive_ptr<DocumentSource> clone() const final { - return new auto(*this); + boost::intrusive_ptr<DocumentSource> clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx = nullptr) const final { + return new DocumentSourceChangeStreamOplogMatch(*this, newExpCtx); } static boost::intrusive_ptr<DocumentSource> createFromBson( diff --git a/src/mongo/db/pipeline/document_source_graph_lookup.cpp b/src/mongo/db/pipeline/document_source_graph_lookup.cpp index 8634d4d86bd..417e92df4b0 100644 --- a/src/mongo/db/pipeline/document_source_graph_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_graph_lookup.cpp @@ -631,9 +631,13 @@ DocumentSourceGraphLookUp::DocumentSourceGraphLookUp( _fromPipeline.push_back(BSON("$match" << BSONObj())); } -DocumentSourceGraphLookUp::DocumentSourceGraphLookUp(const DocumentSourceGraphLookUp& original) - : DocumentSource(kStageName, - original.pExpCtx->copyWith(original.pExpCtx->ns, original.pExpCtx->uuid)), +DocumentSourceGraphLookUp::DocumentSourceGraphLookUp( + const DocumentSourceGraphLookUp& original, + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) + : DocumentSource( + kStageName, + newExpCtx ? newExpCtx + : original.pExpCtx->copyWith(original.pExpCtx->ns, original.pExpCtx->uuid)), _from(original._from), _as(original._as), _connectFromField(original._connectFromField), @@ -783,8 +787,9 @@ intrusive_ptr<DocumentSource> DocumentSourceGraphLookUp::createFromBson( return newSource; } -boost::intrusive_ptr<DocumentSource> DocumentSourceGraphLookUp::clone() const { - return make_intrusive<DocumentSourceGraphLookUp>(*this); +boost::intrusive_ptr<DocumentSource> DocumentSourceGraphLookUp::clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) const { + return make_intrusive<DocumentSourceGraphLookUp>(*this, newExpCtx); } void DocumentSourceGraphLookUp::addInvolvedCollections( diff --git a/src/mongo/db/pipeline/document_source_graph_lookup.h b/src/mongo/db/pipeline/document_source_graph_lookup.h index 30e63b5d64f..bc0146f1829 100644 --- a/src/mongo/db/pipeline/document_source_graph_lookup.h +++ b/src/mongo/db/pipeline/document_source_graph_lookup.h @@ -66,7 +66,8 @@ public: } }; - DocumentSourceGraphLookUp(const DocumentSourceGraphLookUp&); + DocumentSourceGraphLookUp(const DocumentSourceGraphLookUp&, + const boost::intrusive_ptr<ExpressionContext>&); const char* getSourceName() const final; @@ -155,7 +156,8 @@ public: static boost::intrusive_ptr<DocumentSource> createFromBson( BSONElement elem, const boost::intrusive_ptr<ExpressionContext>& pExpCtx); - boost::intrusive_ptr<DocumentSource> clone() const final; + boost::intrusive_ptr<DocumentSource> clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) const final; protected: GetNextResult doGetNext() final; diff --git a/src/mongo/db/pipeline/document_source_list_sessions.h b/src/mongo/db/pipeline/document_source_list_sessions.h index 629d565e244..9c3e4d10d68 100644 --- a/src/mongo/db/pipeline/document_source_list_sessions.h +++ b/src/mongo/db/pipeline/document_source_list_sessions.h @@ -50,11 +50,13 @@ namespace mongo { */ class DocumentSourceListSessions final : public DocumentSourceMatch { public: - DocumentSourceListSessions(const DocumentSourceListSessions& other) - : DocumentSourceMatch(other), _allUsers(other._allUsers), _users(other._users) {} + DocumentSourceListSessions(const DocumentSourceListSessions& other, + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) + : DocumentSourceMatch(other, newExpCtx), _allUsers(other._allUsers), _users(other._users) {} - virtual boost::intrusive_ptr<DocumentSource> clone() const { - return make_intrusive<std::decay_t<decltype(*this)>>(*this); + virtual boost::intrusive_ptr<DocumentSource> clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) const { + return make_intrusive<std::decay_t<decltype(*this)>>(*this, newExpCtx); } static constexpr StringData kStageName = "$listSessions"_sd; diff --git a/src/mongo/db/pipeline/document_source_lookup.cpp b/src/mongo/db/pipeline/document_source_lookup.cpp index f6f53594e7e..cfb885e94c5 100644 --- a/src/mongo/db/pipeline/document_source_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_lookup.cpp @@ -241,9 +241,12 @@ DocumentSourceLookUp::DocumentSourceLookUp( initializeResolvedIntrospectionPipeline(); } -DocumentSourceLookUp::DocumentSourceLookUp(const DocumentSourceLookUp& original) - : DocumentSource(kStageName, - original.pExpCtx->copyWith(original.pExpCtx->ns, original.pExpCtx->uuid)), +DocumentSourceLookUp::DocumentSourceLookUp(const DocumentSourceLookUp& original, + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) + : DocumentSource( + kStageName, + newExpCtx ? newExpCtx + : original.pExpCtx->copyWith(original.pExpCtx->ns, original.pExpCtx->uuid)), _fromNs(original._fromNs), _resolvedNs(original._resolvedNs), _as(original._as), @@ -270,8 +273,9 @@ DocumentSourceLookUp::DocumentSourceLookUp(const DocumentSourceLookUp& original) } } -boost::intrusive_ptr<DocumentSource> DocumentSourceLookUp::clone() const { - return make_intrusive<DocumentSourceLookUp>(*this); +boost::intrusive_ptr<DocumentSource> DocumentSourceLookUp::clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) const { + return make_intrusive<DocumentSourceLookUp>(*this, newExpCtx); } void validateLookupCollectionlessPipeline(const std::vector<BSONObj>& pipeline) { diff --git a/src/mongo/db/pipeline/document_source_lookup.h b/src/mongo/db/pipeline/document_source_lookup.h index eb28f357291..fef7cd0067f 100644 --- a/src/mongo/db/pipeline/document_source_lookup.h +++ b/src/mongo/db/pipeline/document_source_lookup.h @@ -121,7 +121,8 @@ public: /** * Copy constructor used for clone(). */ - DocumentSourceLookUp(const DocumentSourceLookUp&); + DocumentSourceLookUp(const DocumentSourceLookUp&, + const boost::intrusive_ptr<ExpressionContext>&); const char* getSourceName() const final; void serializeToArray( @@ -244,7 +245,8 @@ public: return buildPipeline(inputDoc); } - boost::intrusive_ptr<DocumentSource> clone() const final; + boost::intrusive_ptr<DocumentSource> clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) const final; bool sbeCompatible() const { return _sbeCompatible; diff --git a/src/mongo/db/pipeline/document_source_match.h b/src/mongo/db/pipeline/document_source_match.h index 241b0b265f3..5bf27ddfe5c 100644 --- a/src/mongo/db/pipeline/document_source_match.h +++ b/src/mongo/db/pipeline/document_source_match.h @@ -43,9 +43,10 @@ namespace mongo { class DocumentSourceMatch : public DocumentSource { public: - virtual boost::intrusive_ptr<DocumentSource> clone() const { + virtual boost::intrusive_ptr<DocumentSource> clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx = nullptr) const { // Raw new is needed to access non-public constructors. - return new auto(*this); + return new DocumentSourceMatch(*this, newExpCtx); } static constexpr StringData kStageName = "$match"_sd; @@ -205,10 +206,11 @@ public: } protected: - DocumentSourceMatch(const DocumentSourceMatch& other) + DocumentSourceMatch(const DocumentSourceMatch& other, + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) : DocumentSourceMatch( other.serialize().getDocument().toBson().firstElement().embeddedObject(), - other.pExpCtx) {} + newExpCtx ? newExpCtx : other.pExpCtx) {} GetNextResult doGetNext() override; DocumentSourceMatch(const BSONObj& query, diff --git a/src/mongo/db/pipeline/document_source_sequential_document_cache.h b/src/mongo/db/pipeline/document_source_sequential_document_cache.h index 792b3b56a53..4e81390d4ef 100644 --- a/src/mongo/db/pipeline/document_source_sequential_document_cache.h +++ b/src/mongo/db/pipeline/document_source_sequential_document_cache.h @@ -88,8 +88,9 @@ public: * that is being cloned. It is expected that only one of the DocumentSourceSequentialCache * copies will be used, and therefore only one will actively be using the cache. */ - boost::intrusive_ptr<DocumentSource> clone() const final { - auto newStage = create(pExpCtx, _cache); + boost::intrusive_ptr<DocumentSource> clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) const final { + auto newStage = create(newExpCtx ? newExpCtx : pExpCtx, _cache); // Keep the position flag so in case the containing pipeline is cloned post-optimization. newStage->_hasOptimizedPos = _hasOptimizedPos; newStage->_cacheIsEOF = _cacheIsEOF; diff --git a/src/mongo/db/pipeline/document_source_single_document_transformation.h b/src/mongo/db/pipeline/document_source_single_document_transformation.h index ca4855dfff2..db76f149213 100644 --- a/src/mongo/db/pipeline/document_source_single_document_transformation.h +++ b/src/mongo/db/pipeline/document_source_single_document_transformation.h @@ -44,8 +44,10 @@ namespace mongo { */ class DocumentSourceSingleDocumentTransformation final : public DocumentSource { public: - virtual boost::intrusive_ptr<DocumentSource> clone() const { - auto list = DocumentSource::parse(pExpCtx, serialize().getDocument().toBson()); + virtual boost::intrusive_ptr<DocumentSource> clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx = nullptr) const { + auto list = DocumentSource::parse(newExpCtx ? newExpCtx : pExpCtx, + serialize().getDocument().toBson()); invariant(list.size() == 1); return list.front(); } diff --git a/src/mongo/db/pipeline/document_source_sort.cpp b/src/mongo/db/pipeline/document_source_sort.cpp index 009b4e9defb..2c07c43c501 100644 --- a/src/mongo/db/pipeline/document_source_sort.cpp +++ b/src/mongo/db/pipeline/document_source_sort.cpp @@ -272,8 +272,9 @@ DocumentSource::GetNextResult DocumentSourceSort::doGetNext() { return GetNextResult{_sortExecutor->getNext().second}; } -boost::intrusive_ptr<DocumentSource> DocumentSourceSort::clone() const { - return create(pExpCtx, +boost::intrusive_ptr<DocumentSource> DocumentSourceSort::clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) const { + return create(newExpCtx ? newExpCtx : pExpCtx, getSortKeyPattern(), _sortExecutor->getLimit(), _sortExecutor->getMaxMemoryBytes()); diff --git a/src/mongo/db/pipeline/document_source_sort.h b/src/mongo/db/pipeline/document_source_sort.h index da554304a77..f0ab0c28a3c 100644 --- a/src/mongo/db/pipeline/document_source_sort.h +++ b/src/mongo/db/pipeline/document_source_sort.h @@ -74,7 +74,8 @@ public: std::vector<Value>& array, boost::optional<ExplainOptions::Verbosity> explain = boost::none) const final; - boost::intrusive_ptr<DocumentSource> clone() const final; + boost::intrusive_ptr<DocumentSource> clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) const final; GetModPathsReturn getModifiedPaths() const final { // A $sort does not modify any paths. diff --git a/src/mongo/db/pipeline/document_source_union_with.cpp b/src/mongo/db/pipeline/document_source_union_with.cpp index 6e69746dd98..62904bfb270 100644 --- a/src/mongo/db/pipeline/document_source_union_with.cpp +++ b/src/mongo/db/pipeline/document_source_union_with.cpp @@ -107,10 +107,11 @@ void validateUnionWithCollectionlessPipeline( ); } -boost::intrusive_ptr<DocumentSource> DocumentSourceUnionWith::clone() const { +boost::intrusive_ptr<DocumentSource> DocumentSourceUnionWith::clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) const { // At this point the ExpressionContext already has info about any resolved namespaces, so there // is no need to resolve them again when creating the clone. - return make_intrusive<DocumentSourceUnionWith>(*this); + return make_intrusive<DocumentSourceUnionWith>(*this, newExpCtx); } std::unique_ptr<DocumentSourceUnionWith::LiteParsed> DocumentSourceUnionWith::LiteParsed::parse( diff --git a/src/mongo/db/pipeline/document_source_union_with.h b/src/mongo/db/pipeline/document_source_union_with.h index e1b19c93049..0e2999a2bfc 100644 --- a/src/mongo/db/pipeline/document_source_union_with.h +++ b/src/mongo/db/pipeline/document_source_union_with.h @@ -70,8 +70,10 @@ public: } } - DocumentSourceUnionWith(const DocumentSourceUnionWith& original) - : DocumentSource(kStageName, original.pExpCtx->copyWith(original.pExpCtx->ns)), + DocumentSourceUnionWith(const DocumentSourceUnionWith& original, + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) + : DocumentSource(kStageName, + newExpCtx ? newExpCtx : original.pExpCtx->copyWith(original.pExpCtx->ns)), _pipeline(original._pipeline->clone()) {} ~DocumentSourceUnionWith(); @@ -138,7 +140,8 @@ public: return *_pipeline; } - boost::intrusive_ptr<DocumentSource> clone() const final; + boost::intrusive_ptr<DocumentSource> clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) const final; const Pipeline::SourceContainer* getSubPipeline() const final { if (_pipeline) { diff --git a/src/mongo/db/pipeline/pipeline.cpp b/src/mongo/db/pipeline/pipeline.cpp index d92a6fa3b29..97a896e5898 100644 --- a/src/mongo/db/pipeline/pipeline.cpp +++ b/src/mongo/db/pipeline/pipeline.cpp @@ -153,12 +153,13 @@ Pipeline::~Pipeline() { invariant(_disposed); } -std::unique_ptr<Pipeline, PipelineDeleter> Pipeline::clone() const { +std::unique_ptr<Pipeline, PipelineDeleter> Pipeline::clone( + const boost::intrusive_ptr<ExpressionContext>& newExpCtx) const { SourceContainer clonedStages; for (auto&& stage : _sources) { - clonedStages.push_back(stage->clone()); + clonedStages.push_back(stage->clone(newExpCtx)); } - return create(clonedStages, getContext()); + return create(clonedStages, newExpCtx ? newExpCtx : getContext()); } template <class T> diff --git a/src/mongo/db/pipeline/pipeline.h b/src/mongo/db/pipeline/pipeline.h index 8784ad262c3..96cf6426be3 100644 --- a/src/mongo/db/pipeline/pipeline.h +++ b/src/mongo/db/pipeline/pipeline.h @@ -177,7 +177,12 @@ public: std::vector<BSONObj> currentPipeline, MakePipelineOptions opts); - std::unique_ptr<Pipeline, PipelineDeleter> clone() const; + /** + * Callers can optionally specify 'newExpCtx' to construct the deep clone with it. This will be + * used to construct all the cloned DocumentSources as well. + */ + std::unique_ptr<Pipeline, PipelineDeleter> clone( + const boost::intrusive_ptr<ExpressionContext>& = nullptr) const; const boost::intrusive_ptr<ExpressionContext>& getContext() const { return pCtx; |