-
Type:
Task
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
Query Integration
-
None
-
None
-
None
-
None
-
None
-
None
-
None
As outlined in the technical design, we will need to introduce an explicit desugaring step that will be called from the aggregation execution path immediately after query stats registration.
This requires that we implement specializations of DocumentSourceExtension, which each have distinct behaviour during expansion
As part of this ticket:
1. Add expand() to the DocumentSource base class:
virtual list<intrusive_ptr<DocumentSource>> DocumentSource::expand() { return list{}; // return an empty list }
2. Implement DocumentSourceExtensionExpandable:
class DocumentSourceExtensionExpandable : public DocumentSourceExtension { virtual list<intrusive_ptr<DocumentSource>> expand() { list<intrusive_ptr<DocumentSource>> expandedList; // call expand() on this object's parseNode, populating with a list of DocumentSources. auto nodes = parseNode->expand(); while (!nodes.empty()) { auto currentNode = nodes.pop_front(); if (currentNode.type == Ast) { // create a DocumentSourceExtensionOptimizable; expandedList.emplace_back(make_intrusive<DocumentSourceExtensionOptimizable>(currentNode.release()); } else if (currentNode.type == Parse) { if (currentNode.vtable == host::ParseNode::VTABLE) { // we have a host::ParseNode, we have to parse it!! expandedList.emplace_back(createFromBson(currentNode.getBson()); } else { // we have an extension provided ParseNode, recursively expand! // create a DocumentSourceExtensionExpandable; auto expandableNode = make_intrusive<DocumentSourceExtensionExpandable>(currentNode.release(); expandedList.emplace_back(expandableNode->expand()); } } } return expandedList; } }
3. Implement DocumentSourceExtensionOptimizable
DocumentSourceExtensionOptimizable does not override expand, since it does not itself expand (return empty list). However, DocumentSourceExtensionOptimizable must have a LogicalStage member, which DocumentSourceExtension does not.
4. Add unit tests for the above two classes.
Alternative: It's possible that we may not want to add expand() to the generic DocumentSource interface. Our long term place is to introduce expansion in the LiteParsedPipeline phase, so it might be better to avoid adding expand() as a virtual method of the DocumentSource base class.
Instead, we could leverage a visitor style Expansion/Desugarer class (note, if we go with this approach. don't implement this here, it should go in SERVER-109780)
class Desugarer {public: Desugarer(list<intrusive_ptr<DocumentSource>& pipelineSources) : m_sources(pipelineSources) {} void operator() { try { auto itr = m_sources.begin(); while (itr != m_sources.end()) \{ invariant(itr.get()); itr = _desugar(itr, *itr.get()); // This is like a visit() function. } } catch (...) \{ } } DocumentSourceContainer::iterator _desugar(DocumentSourceContainer::iterator, DocumentSource& stage) { invariant(itr->get() == &stage); // Non-Desugar stages just advance to the next stage in the pipeline. return std::next(itr); } // When we visit an Expandable stage, we can invoke the expand() function, which is only present on this class. DocumentSourceContainer::iterator _desugar(DocumentSourceContainer::iterator, DocumentSourceExtensionExpandable& stage) { invariant(itr->get() == &stage); auto desugaredPipeline = stage.expand(); // replace desugar stage with its desugared pipeline if (!desugaredPipeline.empty()) \{ auto desugarIterator = itr; m_sources.insert(itr, desugaredPipeline.begin(), desugaredPipeline.end()); itr = std::next(itr); m_sources.erase(desugarIterator); } return itr; }private: DocumentSourceContainer& m_sources; };
- depends on
-
SERVER-109564 Modify ParseNode::expand() to return ExtensionContainer instead of a serialized pipeline
-
- Backlog
-
- is depended on by
-
SERVER-109780 Implement explicit desugaring step for Pipelines with Desugar Stages
-
- Backlog
-