diff options
Diffstat (limited to 'src/mongo/db/pipeline')
32 files changed, 259 insertions, 508 deletions
diff --git a/src/mongo/db/pipeline/dependencies.cpp b/src/mongo/db/pipeline/dependencies.cpp index c9482c9f0e1..7bc9532ed6f 100644 --- a/src/mongo/db/pipeline/dependencies.cpp +++ b/src/mongo/db/pipeline/dependencies.cpp @@ -29,6 +29,7 @@ #include "mongo/platform/basic.h" +#include "mongo/db/exec/document_value/document_metadata_fields.h" #include "mongo/db/jsobj.h" #include "mongo/db/pipeline/dependencies.h" #include "mongo/db/pipeline/field_path.h" @@ -36,50 +37,17 @@ namespace mongo { -constexpr DepsTracker::MetadataAvailable DepsTracker::kAllGeoNearDataAvailable; - -bool DepsTracker::_appendMetaProjections(BSONObjBuilder* projectionBuilder) const { - if (_needTextScore) { - projectionBuilder->append(Document::metaFieldTextScore, - BSON("$meta" - << "textScore")); - } - if (_needSortKey) { - projectionBuilder->append(Document::metaFieldSortKey, - BSON("$meta" - << "sortKey")); - } - if (_needGeoNearDistance) { - projectionBuilder->append(Document::metaFieldGeoNearDistance, - BSON("$meta" - << "geoNearDistance")); - } - if (_needGeoNearPoint) { - projectionBuilder->append(Document::metaFieldGeoNearPoint, - BSON("$meta" - << "geoNearPoint")); - } - return (_needTextScore || _needSortKey || _needGeoNearDistance || _needGeoNearPoint); -} - -BSONObj DepsTracker::toProjection() const { +BSONObj DepsTracker::toProjectionWithoutMetadata() const { BSONObjBuilder bb; - const bool needsMetadata = _appendMetaProjections(&bb); - if (needWholeDocument) { return bb.obj(); } if (fields.empty()) { - if (needsMetadata) { - // We only need metadata, but there is no easy way to express this in the query - // projection language. We use $noFieldsNeeded with a meta-projection since this is an - // inclusion projection which will exclude all existing fields but add the metadata. - bb.append("_id", 0); - bb.append("$__INTERNAL_QUERY_PROJECTION_RESERVED", 1); - } - // We either need nothing (as we would if this was logically a count), or only the metadata. + // We need no user-level fields (as we would if this was logically a count). Since there is + // no way of expressing a projection that indicates no depencies, we return an empty + // projection. return bb.obj(); } @@ -103,10 +71,11 @@ BSONObj DepsTracker::toProjection() const { last = field + '.'; - // We should only have dependencies on fields that are valid in aggregation. Create a - // FieldPath to check this. - FieldPath fieldPath(field); - + { + // Check that the field requested is a valid field name in the agg language. This + // constructor will throw if it isn't. + FieldPath fp(field); + } bb.append(field, 1); } @@ -118,173 +87,21 @@ BSONObj DepsTracker::toProjection() const { return bb.obj(); } -// ParsedDeps::_fields is a simple recursive look-up table. For each field: -// If the value has type==Bool, the whole field is needed -// If the value has type==Object, the fields in the subobject are needed -// All other fields should be missing which means not needed -boost::optional<ParsedDeps> DepsTracker::toParsedDeps() const { - MutableDocument md; +void DepsTracker::setNeedsMetadata(DocumentMetadataFields::MetaType type, bool required) { + // For everything but sortKey/randval metadata, check that it's available. A pipeline can + // generate those types of metadata. - if (needWholeDocument || _needTextScore) { - // can't use ParsedDeps in this case - return boost::none; + if (type != DocumentMetadataFields::MetaType::kSortKey && + type != DocumentMetadataFields::MetaType::kRandVal) { + uassert(40218, + str::stream() << "pipeline requires " << type + << " metadata, but it is not available", + !required || isMetadataAvailable(type)); } - std::string last; - for (const auto& field : fields) { - if (!last.empty() && str::startsWith(field, last)) { - // we are including a parent of *it so we don't need to include this field - // explicitly. In fact, if we included this field, the parent wouldn't be fully - // included. This logic relies on on set iterators going in lexicographic order so - // that a string is always directly before of all fields it prefixes. - continue; - } - last = field + '.'; - md.setNestedField(field, Value(true)); - } - - return ParsedDeps(md.freeze()); -} - -bool DepsTracker::getNeedsMetadata(MetadataType type) const { - switch (type) { - case MetadataType::TEXT_SCORE: - return _needTextScore; - case MetadataType::SORT_KEY: - return _needSortKey; - case MetadataType::GEO_NEAR_DISTANCE: - return _needGeoNearDistance; - case MetadataType::GEO_NEAR_POINT: - return _needGeoNearPoint; - } - MONGO_UNREACHABLE; -} - -bool DepsTracker::isMetadataAvailable(MetadataType type) const { - switch (type) { - case MetadataType::TEXT_SCORE: - return _metadataAvailable & MetadataAvailable::kTextScore; - case MetadataType::SORT_KEY: - MONGO_UNREACHABLE; - case MetadataType::GEO_NEAR_DISTANCE: - return _metadataAvailable & MetadataAvailable::kGeoNearDistance; - case MetadataType::GEO_NEAR_POINT: - return _metadataAvailable & MetadataAvailable::kGeoNearPoint; - } - MONGO_UNREACHABLE; -} - -void DepsTracker::setNeedsMetadata(MetadataType type, bool required) { - switch (type) { - case MetadataType::TEXT_SCORE: - uassert(40218, - "pipeline requires text score metadata, but there is no text score available", - !required || isMetadataAvailable(type)); - _needTextScore = required; - return; - case MetadataType::SORT_KEY: - invariant(required || !_needSortKey); - _needSortKey = required; - return; - case MetadataType::GEO_NEAR_DISTANCE: - uassert(50860, - "pipeline requires $geoNear distance metadata, but it is not available", - !required || isMetadataAvailable(type)); - invariant(required || !_needGeoNearDistance); - _needGeoNearDistance = required; - return; - case MetadataType::GEO_NEAR_POINT: - uassert(50859, - "pipeline requires $geoNear point metadata, but it is not available", - !required || isMetadataAvailable(type)); - invariant(required || !_needGeoNearPoint); - _needGeoNearPoint = required; - return; - } - MONGO_UNREACHABLE; -} - -std::vector<DepsTracker::MetadataType> DepsTracker::getAllRequiredMetadataTypes() const { - std::vector<MetadataType> reqs; - if (_needTextScore) { - reqs.push_back(MetadataType::TEXT_SCORE); - } - if (_needSortKey) { - reqs.push_back(MetadataType::SORT_KEY); - } - if (_needGeoNearDistance) { - reqs.push_back(MetadataType::GEO_NEAR_DISTANCE); - } - if (_needGeoNearPoint) { - reqs.push_back(MetadataType::GEO_NEAR_POINT); - } - return reqs; -} - -namespace { -// Mutually recursive with arrayHelper -Document documentHelper(const BSONObj& bson, const Document& neededFields, int nFieldsNeeded = -1); - -// Handles array-typed values for ParsedDeps::extractFields -Value arrayHelper(const BSONObj& bson, const Document& neededFields) { - BSONObjIterator it(bson); - - std::vector<Value> values; - while (it.more()) { - BSONElement bsonElement(it.next()); - if (bsonElement.type() == Object) { - Document sub = documentHelper(bsonElement.embeddedObject(), neededFields); - values.push_back(Value(sub)); - } - - if (bsonElement.type() == Array) { - values.push_back(arrayHelper(bsonElement.embeddedObject(), neededFields)); - } - } - - return Value(std::move(values)); -} - -// Handles object-typed values including the top-level for ParsedDeps::extractFields -Document documentHelper(const BSONObj& bson, const Document& neededFields, int nFieldsNeeded) { - // We cache the number of top level fields, so don't need to re-compute it every time. For - // sub-documents, just scan for the number of fields. - if (nFieldsNeeded == -1) { - nFieldsNeeded = neededFields.size(); - } - MutableDocument md(nFieldsNeeded); - - BSONObjIterator it(bson); - while (it.more() && nFieldsNeeded > 0) { - auto bsonElement = it.next(); - StringData fieldName = bsonElement.fieldNameStringData(); - Value isNeeded = neededFields[fieldName]; - - if (isNeeded.missing()) - continue; - - --nFieldsNeeded; // Found a needed field. - if (isNeeded.getType() == Bool) { - md.addField(fieldName, Value(bsonElement)); - } else { - dassert(isNeeded.getType() == Object); - - if (bsonElement.type() == BSONType::Object) { - md.addField( - fieldName, - Value(documentHelper(bsonElement.embeddedObject(), isNeeded.getDocument()))); - } else if (bsonElement.type() == BSONType::Array) { - md.addField(fieldName, - arrayHelper(bsonElement.embeddedObject(), isNeeded.getDocument())); - } - } - } - - return md.freeze(); -} -} // namespace - -Document ParsedDeps::extractFields(const BSONObj& input) const { - return documentHelper(input, _fields, _nFields); + // If the metadata type is not required, then it should not be recorded as a metadata + // dependency. + invariant(required || !_metadataDeps[type]); + _metadataDeps[type] = required; } } // namespace mongo diff --git a/src/mongo/db/pipeline/dependencies.h b/src/mongo/db/pipeline/dependencies.h index 27e2efc41fd..eff5610b089 100644 --- a/src/mongo/db/pipeline/dependencies.h +++ b/src/mongo/db/pipeline/dependencies.h @@ -37,7 +37,6 @@ #include "mongo/db/pipeline/variables.h" namespace mongo { -class ParsedDeps; /** * This struct allows components in an agg pipeline to report what they need from their input. @@ -69,56 +68,40 @@ struct DepsTracker { }; /** - * Represents the type of metadata a pipeline might request. + * Represents a state where all geo metadata is available. */ - enum class MetadataType { - // The score associated with a text match. - TEXT_SCORE, - - // The key to use for sorting. - SORT_KEY, - - // The computed distance for a near query. - GEO_NEAR_DISTANCE, - - // The point used in the computation of the GEO_NEAR_DISTANCE. - GEO_NEAR_POINT, - }; + static constexpr auto kAllGeoNearData = QueryMetadataBitSet( + (1 << DocumentMetadataFields::kGeoNearDist) | (1 << DocumentMetadataFields::kGeoNearPoint)); /** - * Represents what metadata is available on documents that are input to the pipeline. + * Represents a state where all metadata is available. */ - enum MetadataAvailable { - kNoMetadata = 0, - kTextScore = 1 << 1, - kGeoNearDistance = 1 << 2, - kGeoNearPoint = 1 << 3, - }; + static constexpr auto kAllMetadata = + QueryMetadataBitSet(~(1 << DocumentMetadataFields::kNumFields)); /** - * Represents a state where all geo metadata is available. + * Represents a state where only text score metadata is available. */ - static constexpr auto kAllGeoNearDataAvailable = - MetadataAvailable(MetadataAvailable::kGeoNearDistance | MetadataAvailable::kGeoNearPoint); + static constexpr auto kOnlyTextScore = + QueryMetadataBitSet(1 << DocumentMetadataFields::kTextScore); /** - * Represents a state where all metadata is available. + * Represents a state where no metadata is available. */ - static constexpr auto kAllMetadataAvailable = - MetadataAvailable(kTextScore | kGeoNearDistance | kGeoNearPoint); + static constexpr auto kNoMetadata = QueryMetadataBitSet(); + - DepsTracker(MetadataAvailable metadataAvailable = kNoMetadata) + DepsTracker(QueryMetadataBitSet metadataAvailable = kNoMetadata) : _metadataAvailable(metadataAvailable) {} /** - * Returns a projection object covering the dependencies tracked by this class. + * Returns a projection object covering the non-metadata dependencies tracked by this class, or + * empty BSONObj if the entire document is required. */ - BSONObj toProjection() const; - - boost::optional<ParsedDeps> toParsedDeps() const; + BSONObj toProjectionWithoutMetadata() const; bool hasNoRequirements() const { - return fields.empty() && !needWholeDocument && !_needTextScore; + return fields.empty() && !needWholeDocument && !_metadataDeps.any(); } /** @@ -134,7 +117,7 @@ struct DepsTracker { /** * Returns a value with bits set indicating the types of metadata available. */ - MetadataAvailable getMetadataAvailable() const { + QueryMetadataBitSet getMetadataAvailable() const { return _metadataAvailable; } @@ -143,7 +126,9 @@ struct DepsTracker { * illegal to call this with MetadataType::SORT_KEY, since the sort key will always be available * if needed. */ - bool isMetadataAvailable(MetadataType type) const; + bool isMetadataAvailable(DocumentMetadataFields::MetaType type) const { + return _metadataAvailable[type]; + } /** * Sets whether or not metadata 'type' is required. Throws if 'required' is true but that @@ -151,58 +136,49 @@ struct DepsTracker { * * Except for MetadataType::SORT_KEY, once 'type' is required, it cannot be unset. */ - void setNeedsMetadata(MetadataType type, bool required); + void setNeedsMetadata(DocumentMetadataFields::MetaType type, bool required); /** * Returns true if the DepsTracker requires that metadata of type 'type' is present. */ - bool getNeedsMetadata(MetadataType type) const; + bool getNeedsMetadata(DocumentMetadataFields::MetaType type) const { + return _metadataDeps[type]; + } /** * Returns true if there exists a type of metadata required by the DepsTracker. */ bool getNeedsAnyMetadata() const { - return _needTextScore || _needSortKey || _needGeoNearDistance || _needGeoNearPoint; + return _metadataDeps.any(); } /** - * Returns a vector containing all the types of metadata required by this DepsTracker. + * Return all of the metadata dependencies. */ - std::vector<MetadataType> getAllRequiredMetadataTypes() const; - - std::set<std::string> fields; // Names of needed fields in dotted notation. - std::set<Variables::Id> vars; // IDs of referenced variables. - bool needWholeDocument = false; // If true, ignore 'fields'; the whole document is needed. + QueryMetadataBitSet& metadataDeps() { + return _metadataDeps; + } + const QueryMetadataBitSet& metadataDeps() const { + return _metadataDeps; + } -private: /** - * Appends the meta projections for the sort key and/or text score to 'bb' if necessary. Returns - * true if either type of metadata was needed, and false otherwise. + * Request that all metadata in the given QueryMetadataBitSet be added as dependencies. */ - bool _appendMetaProjections(BSONObjBuilder* bb) const; - - MetadataAvailable _metadataAvailable; - - // Each member variable influences a different $meta projection. - bool _needTextScore = false; // {$meta: "textScore"} - bool _needSortKey = false; // {$meta: "sortKey"} - bool _needGeoNearDistance = false; // {$meta: "geoNearDistance"} - bool _needGeoNearPoint = false; // {$meta: "geoNearPoint"} -}; + void requestMetadata(const QueryMetadataBitSet& metadata) { + _metadataDeps |= metadata; + } -/** - * This class is designed to quickly extract the needed fields from a BSONObj into a Document. - * It should only be created by a call to DepsTracker::ParsedDeps - */ -class ParsedDeps { -public: - Document extractFields(const BSONObj& input) const; + std::set<std::string> fields; // Names of needed fields in dotted notation. + std::set<Variables::Id> vars; // IDs of referenced variables. + bool needWholeDocument = false; // If true, ignore 'fields'; the whole document is needed. private: - friend struct DepsTracker; // so it can call constructor - explicit ParsedDeps(Document&& fields) : _fields(std::move(fields)), _nFields(_fields.size()) {} + // Represents all metadata available to the pipeline. + QueryMetadataBitSet _metadataAvailable; - Document _fields; - int _nFields; // Cache the number of top-level fields needed. + // Represents which metadata is used by the pipeline. This is populated while performing + // dependency analysis. + QueryMetadataBitSet _metadataDeps; }; } // namespace mongo diff --git a/src/mongo/db/pipeline/dependencies_test.cpp b/src/mongo/db/pipeline/dependencies_test.cpp index de11708289d..f5b9c5a37a5 100644 --- a/src/mongo/db/pipeline/dependencies_test.cpp +++ b/src/mongo/db/pipeline/dependencies_test.cpp @@ -44,9 +44,6 @@ namespace { using std::set; using std::string; -static const BSONObj metaTextScore = BSON("$meta" - << "textScore"); - template <size_t ArrayLen> set<string> arrayToSet(const char* (&array)[ArrayLen]) { set<string> out; @@ -55,53 +52,64 @@ set<string> arrayToSet(const char* (&array)[ArrayLen]) { return out; } +TEST(DependenciesTest, CheckClassConstants) { + ASSERT_TRUE(DepsTracker::kAllGeoNearData[DocumentMetadataFields::kGeoNearPoint]); + ASSERT_TRUE(DepsTracker::kAllGeoNearData[DocumentMetadataFields::kGeoNearDist]); + ASSERT_EQ(DepsTracker::kAllGeoNearData.count(), 2); + ASSERT_TRUE(DepsTracker::kAllMetadata.all()); + ASSERT_EQ(DepsTracker::kOnlyTextScore.count(), 1); + ASSERT_TRUE(DepsTracker::kOnlyTextScore[DocumentMetadataFields::kTextScore]); +} + TEST(DependenciesToProjectionTest, ShouldIncludeAllFieldsAndExcludeIdIfNotSpecified) { const char* array[] = {"a", "b"}; DepsTracker deps; deps.fields = arrayToSet(array); - ASSERT_BSONOBJ_EQ(deps.toProjection(), BSON("a" << 1 << "b" << 1 << "_id" << 0)); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), BSON("a" << 1 << "b" << 1 << "_id" << 0)); } TEST(DependenciesToProjectionTest, ShouldIncludeFieldEvenIfSuffixOfAnotherIncludedField) { const char* array[] = {"a", "ab"}; DepsTracker deps; deps.fields = arrayToSet(array); - ASSERT_BSONOBJ_EQ(deps.toProjection(), BSON("a" << 1 << "ab" << 1 << "_id" << 0)); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), + BSON("a" << 1 << "ab" << 1 << "_id" << 0)); } TEST(DependenciesToProjectionTest, ShouldNotIncludeSubFieldIfTopLevelAlreadyIncluded) { const char* array[] = {"a", "b", "a.b"}; // a.b included by a DepsTracker deps; deps.fields = arrayToSet(array); - ASSERT_BSONOBJ_EQ(deps.toProjection(), BSON("a" << 1 << "b" << 1 << "_id" << 0)); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), BSON("a" << 1 << "b" << 1 << "_id" << 0)); } TEST(DependenciesToProjectionTest, ShouldIncludeIdIfNeeded) { const char* array[] = {"a", "_id"}; DepsTracker deps; deps.fields = arrayToSet(array); - ASSERT_BSONOBJ_EQ(deps.toProjection(), BSON("a" << 1 << "_id" << 1)); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), BSON("a" << 1 << "_id" << 1)); } TEST(DependenciesToProjectionTest, ShouldIncludeEntireIdEvenIfOnlyASubFieldIsNeeded) { const char* array[] = {"a", "_id.a"}; // still include whole _id (SERVER-7502) DepsTracker deps; deps.fields = arrayToSet(array); - ASSERT_BSONOBJ_EQ(deps.toProjection(), BSON("a" << 1 << "_id" << 1)); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), BSON("a" << 1 << "_id" << 1)); } TEST(DependenciesToProjectionTest, ShouldNotIncludeSubFieldOfIdIfIdIncluded) { const char* array[] = {"a", "_id", "_id.a"}; // handle both _id and subfield DepsTracker deps; deps.fields = arrayToSet(array); - ASSERT_BSONOBJ_EQ(deps.toProjection(), BSON("a" << 1 << "_id" << 1)); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), BSON("a" << 1 << "_id" << 1)); } TEST(DependenciesToProjectionTest, ShouldIncludeFieldPrefixedById) { const char* array[] = {"a", "_id", "_id_a"}; // _id prefixed but non-subfield DepsTracker deps; deps.fields = arrayToSet(array); - ASSERT_BSONOBJ_EQ(deps.toProjection(), BSON("_id_a" << 1 << "a" << 1 << "_id" << 1)); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), + BSON("_id_a" << 1 << "a" << 1 << "_id" << 1)); } TEST(DependenciesToProjectionTest, ShouldOutputEmptyObjectIfEntireDocumentNeeded) { @@ -109,55 +117,59 @@ TEST(DependenciesToProjectionTest, ShouldOutputEmptyObjectIfEntireDocumentNeeded DepsTracker deps; deps.fields = arrayToSet(array); deps.needWholeDocument = true; - ASSERT_BSONOBJ_EQ(deps.toProjection(), BSONObj()); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), BSONObj()); } TEST(DependenciesToProjectionTest, ShouldOnlyRequestTextScoreIfEntireDocumentAndTextScoreNeeded) { const char* array[] = {"a"}; // needTextScore with needWholeDocument - DepsTracker deps(DepsTracker::MetadataAvailable::kTextScore); + DepsTracker deps(DepsTracker::kOnlyTextScore); deps.fields = arrayToSet(array); deps.needWholeDocument = true; - deps.setNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE, true); - ASSERT_BSONOBJ_EQ(deps.toProjection(), BSON(Document::metaFieldTextScore << metaTextScore)); + deps.setNeedsMetadata(DocumentMetadataFields::kTextScore, true); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), BSONObj()); + ASSERT_EQ(deps.metadataDeps().count(), 1u); + ASSERT_TRUE(deps.metadataDeps()[DocumentMetadataFields::kTextScore]); } TEST(DependenciesToProjectionTest, ShouldRequireFieldsAndTextScoreIfTextScoreNeededWithoutWholeDocument) { const char* array[] = {"a"}; // needTextScore without needWholeDocument - DepsTracker deps(DepsTracker::MetadataAvailable::kTextScore); + DepsTracker deps(DepsTracker::kOnlyTextScore); deps.fields = arrayToSet(array); - deps.setNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE, true); - ASSERT_BSONOBJ_EQ( - deps.toProjection(), - BSON(Document::metaFieldTextScore << metaTextScore << "a" << 1 << "_id" << 0)); + deps.setNeedsMetadata(DocumentMetadataFields::kTextScore, true); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), BSON("a" << 1 << "_id" << 0)); + ASSERT_EQ(deps.metadataDeps().count(), 1u); + ASSERT_TRUE(deps.metadataDeps()[DocumentMetadataFields::kTextScore]); } TEST(DependenciesToProjectionTest, ShouldProduceEmptyObjectIfThereAreNoDependencies) { - DepsTracker deps(DepsTracker::MetadataAvailable::kTextScore); + DepsTracker deps(DepsTracker::kOnlyTextScore); deps.fields = {}; deps.needWholeDocument = false; - deps.setNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE, false); - ASSERT_BSONOBJ_EQ(deps.toProjection(), BSONObj()); + deps.setNeedsMetadata(DocumentMetadataFields::kTextScore, false); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), BSONObj()); } -TEST(DependenciesToProjectionTest, ShouldAttemptToExcludeOtherFieldsIfOnlyTextScoreIsNeeded) { - DepsTracker deps(DepsTracker::MetadataAvailable::kTextScore); +TEST(DependenciesToProjectionTest, ShouldReturnEmptyObjectIfOnlyTextScoreIsNeeded) { + DepsTracker deps(DepsTracker::kOnlyTextScore); deps.fields = {}; deps.needWholeDocument = false; - deps.setNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE, true); - ASSERT_BSONOBJ_EQ(deps.toProjection(), - BSON(Document::metaFieldTextScore << metaTextScore << "_id" << 0 - << "$__INTERNAL_QUERY_PROJECTION_RESERVED" - << 1)); + deps.setNeedsMetadata(DocumentMetadataFields::kTextScore, true); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), BSONObj()); + + ASSERT_EQ(deps.metadataDeps().count(), 1u); + ASSERT_TRUE(deps.metadataDeps()[DocumentMetadataFields::kTextScore]); } TEST(DependenciesToProjectionTest, ShouldRequireTextScoreIfNoFieldsPresentButWholeDocumentIsNeeded) { - DepsTracker deps(DepsTracker::MetadataAvailable::kTextScore); + DepsTracker deps(DepsTracker::kOnlyTextScore); deps.fields = {}; deps.needWholeDocument = true; - deps.setNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE, true); - ASSERT_BSONOBJ_EQ(deps.toProjection(), BSON(Document::metaFieldTextScore << metaTextScore)); + deps.setNeedsMetadata(DocumentMetadataFields::kTextScore, true); + ASSERT_BSONOBJ_EQ(deps.toProjectionWithoutMetadata(), BSONObj()); + ASSERT_EQ(deps.metadataDeps().count(), 1u); + ASSERT_TRUE(deps.metadataDeps()[DocumentMetadataFields::kTextScore]); } } // namespace diff --git a/src/mongo/db/pipeline/document_source_add_fields_test.cpp b/src/mongo/db/pipeline/document_source_add_fields_test.cpp index da57f5f7847..e20820feb0d 100644 --- a/src/mongo/db/pipeline/document_source_add_fields_test.cpp +++ b/src/mongo/db/pipeline/document_source_add_fields_test.cpp @@ -147,7 +147,7 @@ TEST_F(AddFieldsTest, ShouldAddReferencedFieldsToDependencies) { auto addFields = DocumentSourceAddFields::create( fromjson("{a: true, x: '$b', y: {$and: ['$c','$d']}, z: {$meta: 'textScore'}}"), getExpCtx()); - DepsTracker dependencies(DepsTracker::MetadataAvailable::kTextScore); + DepsTracker dependencies(DepsTracker::kOnlyTextScore); ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, addFields->getDependencies(&dependencies)); ASSERT_EQUALS(3U, dependencies.fields.size()); @@ -164,7 +164,7 @@ TEST_F(AddFieldsTest, ShouldAddReferencedFieldsToDependencies) { ASSERT_EQUALS(1U, dependencies.fields.count("c")); ASSERT_EQUALS(1U, dependencies.fields.count("d")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(true, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(true, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(AddFieldsTest, ShouldPropagatePauses) { diff --git a/src/mongo/db/pipeline/document_source_bucket_auto_test.cpp b/src/mongo/db/pipeline/document_source_bucket_auto_test.cpp index 5f450c1f792..9c68c05a50c 100644 --- a/src/mongo/db/pipeline/document_source_bucket_auto_test.cpp +++ b/src/mongo/db/pipeline/document_source_bucket_auto_test.cpp @@ -450,19 +450,19 @@ TEST_F(BucketAutoTests, ShouldAddDependenciesOfGroupByFieldAndComputedFields) { ASSERT_EQUALS(1U, dependencies.fields.count("b")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(BucketAutoTests, ShouldNeedTextScoreInDependenciesFromGroupByField) { auto bucketAuto = createBucketAuto(fromjson("{$bucketAuto : {groupBy : {$meta: 'textScore'}, buckets : 2}}")); - DepsTracker dependencies(DepsTracker::MetadataAvailable::kTextScore); + DepsTracker dependencies(DepsTracker::kOnlyTextScore); ASSERT_EQUALS(DepsTracker::State::EXHAUSTIVE_ALL, bucketAuto->getDependencies(&dependencies)); ASSERT_EQUALS(0U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(true, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(true, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(BucketAutoTests, ShouldNeedTextScoreInDependenciesFromOutputField) { @@ -470,7 +470,7 @@ TEST_F(BucketAutoTests, ShouldNeedTextScoreInDependenciesFromOutputField) { createBucketAuto(fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2, output: {avg : " "{$avg : {$meta : 'textScore'}}}}}")); - DepsTracker dependencies(DepsTracker::MetadataAvailable::kTextScore); + DepsTracker dependencies(DepsTracker::kOnlyTextScore); ASSERT_EQUALS(DepsTracker::State::EXHAUSTIVE_ALL, bucketAuto->getDependencies(&dependencies)); ASSERT_EQUALS(1U, dependencies.fields.size()); @@ -478,7 +478,7 @@ TEST_F(BucketAutoTests, ShouldNeedTextScoreInDependenciesFromOutputField) { ASSERT_EQUALS(1U, dependencies.fields.count("x")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(true, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(true, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(BucketAutoTests, SerializesDefaultAccumulatorIfOutputFieldIsNotSpecified) { diff --git a/src/mongo/db/pipeline/document_source_cursor.cpp b/src/mongo/db/pipeline/document_source_cursor.cpp index eb01db2a2ad..e1193e33cb8 100644 --- a/src/mongo/db/pipeline/document_source_cursor.cpp +++ b/src/mongo/db/pipeline/document_source_cursor.cpp @@ -73,13 +73,6 @@ DocumentSource::GetNextResult DocumentSourceCursor::doGetNext() { return std::move(out); } -Document DocumentSourceCursor::transformBSONObjToDocument(const BSONObj& obj) const { - // Aggregation assumes ownership of underlying BSON. - return _dependencies ? _dependencies->extractFields(obj) - : (_inputHasMetadata ? Document::fromBsonWithMetaData(obj.getOwned()) - : Document(obj.getOwned())); -} - void DocumentSourceCursor::loadBatch() { if (!_exec || _exec->isDisposed()) { // No more documents. @@ -92,7 +85,7 @@ void DocumentSourceCursor::loadBatch() { } PlanExecutor::ExecState state; - BSONObj resultObj; + Document resultObj; { AutoGetCollectionForRead autoColl(pExpCtx->opCtx, _exec->nss()); uassertStatusOK(repl::ReplicationCoordinator::get(pExpCtx->opCtx) @@ -108,7 +101,7 @@ void DocumentSourceCursor::loadBatch() { if (_shouldProduceEmptyDocs) { _currentBatch.push_back(Document()); } else { - _currentBatch.push_back(transformBSONObjToDocument(resultObj)); + _currentBatch.push_back(transformDoc(resultObj.getOwned())); } if (_limit) { @@ -228,9 +221,6 @@ Value DocumentSourceCursor::serialize(boost::optional<ExplainOptions::Verbosity> if (_limit) out["limit"] = Value(_limit->getLimit()); - if (!_projection.isEmpty()) - out["fields"] = Value(_projection); - BSONObjBuilder explainStatsBuilder; { diff --git a/src/mongo/db/pipeline/document_source_cursor.h b/src/mongo/db/pipeline/document_source_cursor.h index fa28dd114a0..60495193b93 100644 --- a/src/mongo/db/pipeline/document_source_cursor.h +++ b/src/mongo/db/pipeline/document_source_cursor.h @@ -115,21 +115,6 @@ public: } /** - * Informs this object of projection and dependency information. - * - * @param projection The projection that has been passed down to the query system. - * @param deps The output of DepsTracker::toParsedDeps. - * @param inputHasMetadata Indicates whether the input BSON object contains metadata fields. - */ - void setProjection(const BSONObj& projection, - const boost::optional<ParsedDeps>& deps, - bool inputHasMetadata) { - _projection = projection; - _dependencies = deps; - _inputHasMetadata = inputHasMetadata; - } - - /** * Returns the limit associated with this cursor, or -1 if there is no limit. */ long long getLimit() const { @@ -182,9 +167,11 @@ protected: * If '_shouldProduceEmptyDocs' is false, this function hook is called on each 'obj' returned by * '_exec' when loading a batch and returns a Document to be added to '_currentBatch'. * - * The default implementation is a dependency-aware BSONObj-to-Document transformation. + * The default implementation is the identity function. */ - virtual Document transformBSONObjToDocument(const BSONObj& obj) const; + virtual Document transformDoc(Document&& doc) const { + return std::move(doc); + } private: /** @@ -213,10 +200,7 @@ private: // BSONObj members must outlive _projection and cursor. BSONObj _query; BSONObj _sort; - BSONObj _projection; bool _shouldProduceEmptyDocs = false; - bool _inputHasMetadata = false; - boost::optional<ParsedDeps> _dependencies; boost::intrusive_ptr<DocumentSourceLimit> _limit; long long _docsAddedToBatches; // for _limit enforcement diff --git a/src/mongo/db/pipeline/document_source_facet.cpp b/src/mongo/db/pipeline/document_source_facet.cpp index 34bd1d9a4bd..71e9571f869 100644 --- a/src/mongo/db/pipeline/document_source_facet.cpp +++ b/src/mongo/db/pipeline/document_source_facet.cpp @@ -305,14 +305,14 @@ DepsTracker::State DocumentSourceFacet::getDependencies(DepsTracker* deps) const // The text score is the only type of metadata that could be needed by $facet. deps->setNeedsMetadata( - DepsTracker::MetadataType::TEXT_SCORE, - deps->getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE) || - subDepsTracker.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + DocumentMetadataFields::kTextScore, + deps->getNeedsMetadata(DocumentMetadataFields::kTextScore) || + subDepsTracker.getNeedsMetadata(DocumentMetadataFields::kTextScore)); // If there are variables defined at this stage's scope, there may be dependencies upon // them in subsequent pipelines. Keep enumerating. - if (deps->needWholeDocument && - deps->getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE) && !scopeHasVariables) { + if (deps->needWholeDocument && deps->getNeedsMetadata(DocumentMetadataFields::kTextScore) && + !scopeHasVariables) { break; } } diff --git a/src/mongo/db/pipeline/document_source_facet_test.cpp b/src/mongo/db/pipeline/document_source_facet_test.cpp index 5d094fe5bcf..980786689a8 100644 --- a/src/mongo/db/pipeline/document_source_facet_test.cpp +++ b/src/mongo/db/pipeline/document_source_facet_test.cpp @@ -618,8 +618,7 @@ TEST_F(DocumentSourceFacetTest, ShouldUnionDependenciesOfInnerPipelines) { auto needsA = DocumentSourceNeedsA::create(); auto firstPipeline = unittest::assertGet(Pipeline::createFacetPipeline({needsA}, ctx)); - auto firstPipelineDeps = - firstPipeline->getDependencies(DepsTracker::MetadataAvailable::kNoMetadata); + auto firstPipelineDeps = firstPipeline->getDependencies(DepsTracker::kNoMetadata); ASSERT_FALSE(firstPipelineDeps.needWholeDocument); ASSERT_EQ(firstPipelineDeps.fields.size(), 1UL); ASSERT_EQ(firstPipelineDeps.fields.count("a"), 1UL); @@ -627,8 +626,7 @@ TEST_F(DocumentSourceFacetTest, ShouldUnionDependenciesOfInnerPipelines) { auto needsB = DocumentSourceNeedsB::create(); auto secondPipeline = unittest::assertGet(Pipeline::createFacetPipeline({needsB}, ctx)); - auto secondPipelineDeps = - secondPipeline->getDependencies(DepsTracker::MetadataAvailable::kNoMetadata); + auto secondPipelineDeps = secondPipeline->getDependencies(DepsTracker::kNoMetadata); ASSERT_FALSE(secondPipelineDeps.needWholeDocument); ASSERT_EQ(secondPipelineDeps.fields.size(), 1UL); ASSERT_EQ(secondPipelineDeps.fields.count("b"), 1UL); @@ -638,10 +636,10 @@ TEST_F(DocumentSourceFacetTest, ShouldUnionDependenciesOfInnerPipelines) { facets.emplace_back("needsB", std::move(secondPipeline)); auto facetStage = DocumentSourceFacet::create(std::move(facets), ctx); - DepsTracker deps(DepsTracker::MetadataAvailable::kNoMetadata); + DepsTracker deps(DepsTracker::kNoMetadata); ASSERT_EQ(facetStage->getDependencies(&deps), DepsTracker::State::EXHAUSTIVE_ALL); ASSERT_FALSE(deps.needWholeDocument); - ASSERT_FALSE(deps.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_FALSE(deps.getNeedsMetadata(DocumentMetadataFields::kTextScore)); ASSERT_EQ(deps.fields.size(), 2UL); ASSERT_EQ(deps.fields.count("a"), 1UL); ASSERT_EQ(deps.fields.count("b"), 1UL); @@ -676,10 +674,10 @@ TEST_F(DocumentSourceFacetTest, ShouldRequireWholeDocumentIfAnyPipelineRequiresW facets.emplace_back("needsWholeDocument", std::move(secondPipeline)); auto facetStage = DocumentSourceFacet::create(std::move(facets), ctx); - DepsTracker deps(DepsTracker::MetadataAvailable::kNoMetadata); + DepsTracker deps(DepsTracker::kNoMetadata); ASSERT_EQ(facetStage->getDependencies(&deps), DepsTracker::State::EXHAUSTIVE_ALL); ASSERT_TRUE(deps.needWholeDocument); - ASSERT_FALSE(deps.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_FALSE(deps.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } /** @@ -688,7 +686,7 @@ TEST_F(DocumentSourceFacetTest, ShouldRequireWholeDocumentIfAnyPipelineRequiresW class DocumentSourceNeedsOnlyTextScore : public DocumentSourcePassthrough { public: DepsTracker::State getDependencies(DepsTracker* deps) const override { - deps->setNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE, true); + deps->setNeedsMetadata(DocumentMetadataFields::kTextScore, true); return DepsTracker::State::EXHAUSTIVE_ALL; } static boost::intrusive_ptr<DocumentSourceNeedsOnlyTextScore> create() { @@ -715,10 +713,10 @@ TEST_F(DocumentSourceFacetTest, ShouldRequireTextScoreIfAnyPipelineRequiresTextS facets.emplace_back("needsTextScore", std::move(thirdPipeline)); auto facetStage = DocumentSourceFacet::create(std::move(facets), ctx); - DepsTracker deps(DepsTracker::MetadataAvailable::kTextScore); + DepsTracker deps(DepsTracker::kOnlyTextScore); ASSERT_EQ(facetStage->getDependencies(&deps), DepsTracker::State::EXHAUSTIVE_ALL); ASSERT_TRUE(deps.needWholeDocument); - ASSERT_TRUE(deps.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_TRUE(deps.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceFacetTest, ShouldThrowIfAnyPipelineRequiresTextScoreButItIsNotAvailable) { @@ -735,7 +733,7 @@ TEST_F(DocumentSourceFacetTest, ShouldThrowIfAnyPipelineRequiresTextScoreButItIs facets.emplace_back("needsTextScore", std::move(secondPipeline)); auto facetStage = DocumentSourceFacet::create(std::move(facets), ctx); - DepsTracker deps(DepsTracker::MetadataAvailable::kNoMetadata); + DepsTracker deps(DepsTracker::kNoMetadata); ASSERT_THROWS(facetStage->getDependencies(&deps), AssertionException); } diff --git a/src/mongo/db/pipeline/document_source_geo_near.cpp b/src/mongo/db/pipeline/document_source_geo_near.cpp index 61f04889ffa..5081865eeba 100644 --- a/src/mongo/db/pipeline/document_source_geo_near.cpp +++ b/src/mongo/db/pipeline/document_source_geo_near.cpp @@ -225,8 +225,8 @@ DepsTracker::State DocumentSourceGeoNear::getDependencies(DepsTracker* deps) con // produced by this stage, and we could inform the query system that it need not include it in // its response. For now, assume that we require the entire document as well as the appropriate // geoNear metadata. - deps->setNeedsMetadata(DepsTracker::MetadataType::GEO_NEAR_DISTANCE, true); - deps->setNeedsMetadata(DepsTracker::MetadataType::GEO_NEAR_POINT, needsGeoNearPoint()); + deps->setNeedsMetadata(DocumentMetadataFields::kGeoNearDist, true); + deps->setNeedsMetadata(DocumentMetadataFields::kGeoNearPoint, needsGeoNearPoint()); deps->needWholeDocument = true; return DepsTracker::State::EXHAUSTIVE_FIELDS; diff --git a/src/mongo/db/pipeline/document_source_geo_near_cursor.cpp b/src/mongo/db/pipeline/document_source_geo_near_cursor.cpp index 306bc5f6d3e..0eb6fd5b04b 100644 --- a/src/mongo/db/pipeline/document_source_geo_near_cursor.cpp +++ b/src/mongo/db/pipeline/document_source_geo_near_cursor.cpp @@ -83,14 +83,14 @@ const char* DocumentSourceGeoNearCursor::getSourceName() const { return DocumentSourceGeoNearCursor::kStageName.rawData(); } -Document DocumentSourceGeoNearCursor::transformBSONObjToDocument(const BSONObj& obj) const { - MutableDocument output(Document::fromBsonWithMetaData(obj)); +Document DocumentSourceGeoNearCursor::transformDoc(Document&& objInput) const { + MutableDocument output(std::move(objInput)); // Scale the distance by the requested factor. invariant(output.peek().metadata().hasGeoNearDistance(), str::stream() << "Query returned a document that is unexpectedly missing the geoNear distance: " - << obj.jsonString()); + << output.peek().toString()); const auto distance = output.peek().metadata().getGeoNearDistance() * _distanceMultiplier; output.setNestedField(_distanceField, Value(distance)); @@ -99,7 +99,7 @@ Document DocumentSourceGeoNearCursor::transformBSONObjToDocument(const BSONObj& output.peek().metadata().hasGeoNearPoint(), str::stream() << "Query returned a document that is unexpectedly missing the geoNear point: " - << obj.jsonString()); + << output.peek().toString()); output.setNestedField(*_locationField, output.peek().metadata().getGeoNearPoint()); } diff --git a/src/mongo/db/pipeline/document_source_geo_near_cursor.h b/src/mongo/db/pipeline/document_source_geo_near_cursor.h index 5022c716d2e..084e8b76bbe 100644 --- a/src/mongo/db/pipeline/document_source_geo_near_cursor.h +++ b/src/mongo/db/pipeline/document_source_geo_near_cursor.h @@ -82,7 +82,7 @@ private: /** * Transforms 'obj' into a Document, calculating the distance. */ - Document transformBSONObjToDocument(const BSONObj& obj) const final; + Document transformDoc(Document&& obj) const override final; // The output field in which to store the computed distance. FieldPath _distanceField; diff --git a/src/mongo/db/pipeline/document_source_group_test.cpp b/src/mongo/db/pipeline/document_source_group_test.cpp index 5de0e26078a..e2fdfe4f107 100644 --- a/src/mongo/db/pipeline/document_source_group_test.cpp +++ b/src/mongo/db/pipeline/document_source_group_test.cpp @@ -813,7 +813,7 @@ public: ASSERT_EQUALS(1U, dependencies.fields.count("u")); ASSERT_EQUALS(1U, dependencies.fields.count("v")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } }; diff --git a/src/mongo/db/pipeline/document_source_limit_test.cpp b/src/mongo/db/pipeline/document_source_limit_test.cpp index 67d4954274c..85ccf9a811c 100644 --- a/src/mongo/db/pipeline/document_source_limit_test.cpp +++ b/src/mongo/db/pipeline/document_source_limit_test.cpp @@ -116,7 +116,7 @@ TEST_F(DocumentSourceLimitTest, ShouldNotIntroduceAnyDependencies) { ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, limit->getDependencies(&dependencies)); ASSERT_EQUALS(0U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceLimitTest, ShouldPropagatePauses) { diff --git a/src/mongo/db/pipeline/document_source_lookup.cpp b/src/mongo/db/pipeline/document_source_lookup.cpp index 575d3335ba4..e11a44fcf32 100644 --- a/src/mongo/db/pipeline/document_source_lookup.cpp +++ b/src/mongo/db/pipeline/document_source_lookup.cpp @@ -731,7 +731,7 @@ DepsTracker::State DocumentSourceLookUp::getDependencies(DepsTracker* deps) cons // subpipeline for the top-level pipeline. So without knowledge of what metadata is in fact // available, we "lie" and say that all metadata is available to avoid tripping any // assertions. - DepsTracker subDeps(DepsTracker::kAllMetadataAvailable); + DepsTracker subDeps(DepsTracker::kAllMetadata); // Get the subpipeline dependencies. Subpipeline stages may reference both 'let' variables // declared by this $lookup and variables declared externally. diff --git a/src/mongo/db/pipeline/document_source_match.cpp b/src/mongo/db/pipeline/document_source_match.cpp index 44697476cf1..494b3535879 100644 --- a/src/mongo/db/pipeline/document_source_match.cpp +++ b/src/mongo/db/pipeline/document_source_match.cpp @@ -486,7 +486,7 @@ DepsTracker::State DocumentSourceMatch::getDependencies(DepsTracker* deps) const // A $text aggregation field should return EXHAUSTIVE_FIELDS, since we don't necessarily // know what field it will be searching without examining indices. deps->needWholeDocument = true; - deps->setNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE, true); + deps->setNeedsMetadata(DocumentMetadataFields::kTextScore, true); return DepsTracker::State::EXHAUSTIVE_FIELDS; } @@ -504,8 +504,9 @@ void DocumentSourceMatch::rebuild(BSONObj filter) { _expression = uassertStatusOK(MatchExpressionParser::parse( _predicate, pExpCtx, ExtensionsCallbackNoop(), Pipeline::kAllowedMatcherFeatures)); _isTextQuery = isTextQuery(_predicate); - _dependencies = DepsTracker(_isTextQuery ? DepsTracker::MetadataAvailable::kTextScore - : DepsTracker::MetadataAvailable::kNoMetadata); + _dependencies = + DepsTracker(_isTextQuery ? QueryMetadataBitSet().set(DocumentMetadataFields::kTextScore) + : DepsTracker::kNoMetadata); getDependencies(&_dependencies); } diff --git a/src/mongo/db/pipeline/document_source_match_test.cpp b/src/mongo/db/pipeline/document_source_match_test.cpp index de5eb9cbc46..3d42a81f91d 100644 --- a/src/mongo/db/pipeline/document_source_match_test.cpp +++ b/src/mongo/db/pipeline/document_source_match_test.cpp @@ -220,15 +220,15 @@ TEST_F(DocumentSourceMatchTest, ShouldAddDependenciesOfAllBranchesOfOrClause) { ASSERT_EQUALS(1U, dependencies.fields.count("x.y")); ASSERT_EQUALS(2U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, TextSearchShouldRequireWholeDocumentAndTextScore) { auto match = DocumentSourceMatch::create(fromjson("{$text: {$search: 'hello'} }"), getExpCtx()); - DepsTracker dependencies(DepsTracker::MetadataAvailable::kTextScore); + DepsTracker dependencies(DepsTracker::kOnlyTextScore); ASSERT_EQUALS(DepsTracker::State::EXHAUSTIVE_FIELDS, match->getDependencies(&dependencies)); ASSERT_EQUALS(true, dependencies.needWholeDocument); - ASSERT_EQUALS(true, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(true, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, ShouldOnlyAddOuterFieldAsDependencyOfImplicitEqualityPredicate) { @@ -239,7 +239,7 @@ TEST_F(DocumentSourceMatchTest, ShouldOnlyAddOuterFieldAsDependencyOfImplicitEqu ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, ShouldOnlyAddOuterFieldAsDependencyOfClausesWithinElemMatch) { @@ -250,7 +250,7 @@ TEST_F(DocumentSourceMatchTest, ShouldOnlyAddOuterFieldAsDependencyOfClausesWith ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, @@ -267,7 +267,7 @@ TEST_F(DocumentSourceMatchTest, ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, @@ -278,7 +278,7 @@ TEST_F(DocumentSourceMatchTest, ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(0U, dependencies.fields.size()); ASSERT_EQUALS(true, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, @@ -289,7 +289,7 @@ TEST_F(DocumentSourceMatchTest, ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies1)); ASSERT_EQUALS(0U, dependencies1.fields.size()); ASSERT_EQUALS(true, dependencies1.needWholeDocument); - ASSERT_EQUALS(false, dependencies1.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies1.getNeedsMetadata(DocumentMetadataFields::kTextScore)); query = fromjson("{a: {$_internalSchemaObjectMatch: {$_internalSchemaMaxProperties: 1}}}"); match = DocumentSourceMatch::create(query, getExpCtx()); @@ -298,7 +298,7 @@ TEST_F(DocumentSourceMatchTest, ASSERT_EQUALS(1U, dependencies2.fields.size()); ASSERT_EQUALS(1U, dependencies2.fields.count("a")); ASSERT_EQUALS(false, dependencies2.needWholeDocument); - ASSERT_EQUALS(false, dependencies2.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies2.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, @@ -311,7 +311,7 @@ TEST_F(DocumentSourceMatchTest, ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(true, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, @@ -322,7 +322,7 @@ TEST_F(DocumentSourceMatchTest, ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(0U, dependencies.fields.size()); ASSERT_EQUALS(true, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForClausesWithInternalSchemaType) { @@ -333,7 +333,7 @@ TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForClausesWithIntern ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForClausesWithInternalSchemaCond) { @@ -346,7 +346,7 @@ TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForClausesWithIntern ASSERT_EQUALS(1U, dependencies.fields.count("b")); ASSERT_EQUALS(1U, dependencies.fields.count("c")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForClausesWithInternalSchemaXor) { @@ -359,7 +359,7 @@ TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForClausesWithIntern ASSERT_EQUALS(1U, dependencies.fields.count("b")); ASSERT_EQUALS(1U, dependencies.fields.count("c")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForClausesWithEmptyJSONSchema) { @@ -369,7 +369,7 @@ TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForClausesWithEmptyJ ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(0U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForClausesWithJSONSchemaProperties) { @@ -380,7 +380,7 @@ TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForClausesWithJSONSc ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForMultiplePredicatesWithJSONSchema) { @@ -392,7 +392,7 @@ TEST_F(DocumentSourceMatchTest, ShouldAddCorrectDependenciesForMultiplePredicate ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.count("b")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, ShouldAddOuterFieldToDependenciesIfElemMatchContainsNoFieldNames) { @@ -403,7 +403,7 @@ TEST_F(DocumentSourceMatchTest, ShouldAddOuterFieldToDependenciesIfElemMatchCont ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, ShouldAddNotClausesFieldAsDependency) { @@ -413,7 +413,7 @@ TEST_F(DocumentSourceMatchTest, ShouldAddNotClausesFieldAsDependency) { ASSERT_EQUALS(1U, dependencies.fields.count("b")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, ShouldAddDependenciesOfEachNorClause) { @@ -425,7 +425,7 @@ TEST_F(DocumentSourceMatchTest, ShouldAddDependenciesOfEachNorClause) { ASSERT_EQUALS(1U, dependencies.fields.count("b.c")); ASSERT_EQUALS(2U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, CommentShouldNotAddAnyDependencies) { @@ -434,7 +434,7 @@ TEST_F(DocumentSourceMatchTest, CommentShouldNotAddAnyDependencies) { ASSERT_EQUALS(DepsTracker::State::SEE_NEXT, match->getDependencies(&dependencies)); ASSERT_EQUALS(0U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, ClauseAndedWithCommentShouldAddDependencies) { @@ -445,7 +445,7 @@ TEST_F(DocumentSourceMatchTest, ClauseAndedWithCommentShouldAddDependencies) { ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceMatchTest, MultipleMatchStagesShouldCombineIntoOne) { diff --git a/src/mongo/db/pipeline/document_source_project_test.cpp b/src/mongo/db/pipeline/document_source_project_test.cpp index 9480c80602b..9c04482340e 100644 --- a/src/mongo/db/pipeline/document_source_project_test.cpp +++ b/src/mongo/db/pipeline/document_source_project_test.cpp @@ -171,7 +171,7 @@ TEST_F(ProjectStageTest, InclusionShouldAddDependenciesOfIncludedAndComputedFiel fromjson("{a: true, x: '$b', y: {$and: ['$c','$d']}, z: {$meta: 'textScore'}}"), getExpCtx(), "$project"_sd); - DepsTracker dependencies(DepsTracker::MetadataAvailable::kTextScore); + DepsTracker dependencies(DepsTracker::kOnlyTextScore); ASSERT_EQUALS(DepsTracker::State::EXHAUSTIVE_FIELDS, project->getDependencies(&dependencies)); ASSERT_EQUALS(5U, dependencies.fields.size()); @@ -188,7 +188,7 @@ TEST_F(ProjectStageTest, InclusionShouldAddDependenciesOfIncludedAndComputedFiel ASSERT_EQUALS(1U, dependencies.fields.count("c")); ASSERT_EQUALS(1U, dependencies.fields.count("d")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(true, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(true, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(ProjectStageTest, ExclusionShouldNotAddDependencies) { @@ -200,7 +200,7 @@ TEST_F(ProjectStageTest, ExclusionShouldNotAddDependencies) { ASSERT_EQUALS(0U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(ProjectStageTest, InclusionProjectionReportsIncludedPathsFromGetModifiedPaths) { @@ -446,7 +446,7 @@ TEST_F(UnsetTest, UnsetShouldNotAddDependencies) { ASSERT_EQUALS(0U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(UnsetTest, UnsetReportsExcludedPathsAsModifiedPaths) { diff --git a/src/mongo/db/pipeline/document_source_replace_root_test.cpp b/src/mongo/db/pipeline/document_source_replace_root_test.cpp index 227331d6897..7fac5040d32 100644 --- a/src/mongo/db/pipeline/document_source_replace_root_test.cpp +++ b/src/mongo/db/pipeline/document_source_replace_root_test.cpp @@ -272,7 +272,7 @@ TEST_F(ReplaceRootBasics, OnlyDependentFieldIsNewRoot) { // Should not need any other fields. ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(ReplaceRootBasics, ReplaceRootModifiesAllFields) { diff --git a/src/mongo/db/pipeline/document_source_sequential_document_cache.cpp b/src/mongo/db/pipeline/document_source_sequential_document_cache.cpp index 8cdfba006dd..971971ae19b 100644 --- a/src/mongo/db/pipeline/document_source_sequential_document_cache.cpp +++ b/src/mongo/db/pipeline/document_source_sequential_document_cache.cpp @@ -115,7 +115,7 @@ Pipeline::SourceContainer::iterator DocumentSourceSequentialDocumentCache::doOpt // elsewhere. So without knowledge of what metadata is in fact available, here // we "lie" and say that all metadata is available to avoid tripping any // assertions. - DepsTracker deps(DepsTracker::kAllMetadataAvailable); + DepsTracker deps(DepsTracker::kAllMetadata); // Iterate through the pipeline stages until we find one which references an external variable. for (; prefixSplit != container->end(); ++prefixSplit) { diff --git a/src/mongo/db/pipeline/document_source_sort.cpp b/src/mongo/db/pipeline/document_source_sort.cpp index 82b476c791f..d306c4e8248 100644 --- a/src/mongo/db/pipeline/document_source_sort.cpp +++ b/src/mongo/db/pipeline/document_source_sort.cpp @@ -158,7 +158,7 @@ DepsTracker::State DocumentSourceSort::getDependencies(DepsTracker* deps) const } if (pExpCtx->needsMerge) { // Include the sort key if we will merge several sorted streams later. - deps->setNeedsMetadata(DepsTracker::MetadataType::SORT_KEY, true); + deps->setNeedsMetadata(DocumentMetadataFields::kSortKey, true); } return DepsTracker::State::SEE_NEXT; diff --git a/src/mongo/db/pipeline/document_source_sort_test.cpp b/src/mongo/db/pipeline/document_source_sort_test.cpp index 67d909c54d2..88e909d326f 100644 --- a/src/mongo/db/pipeline/document_source_sort_test.cpp +++ b/src/mongo/db/pipeline/document_source_sort_test.cpp @@ -173,7 +173,7 @@ TEST_F(DocumentSourceSortTest, Dependencies) { ASSERT_EQUALS(1U, dependencies.fields.count("a")); ASSERT_EQUALS(1U, dependencies.fields.count("b.c")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(DocumentSourceSortTest, ReportsNoPathsModified) { diff --git a/src/mongo/db/pipeline/document_source_unwind_test.cpp b/src/mongo/db/pipeline/document_source_unwind_test.cpp index 00d0b3390b4..41d76c428b0 100644 --- a/src/mongo/db/pipeline/document_source_unwind_test.cpp +++ b/src/mongo/db/pipeline/document_source_unwind_test.cpp @@ -680,7 +680,7 @@ TEST_F(UnwindStageTest, AddsUnwoundPathToDependencies) { ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(1U, dependencies.fields.count("x.y.z")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(UnwindStageTest, ShouldPropagatePauses) { diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp index 61abc3f009b..6d307929e3e 100644 --- a/src/mongo/db/pipeline/expression.cpp +++ b/src/mongo/db/pipeline/expression.cpp @@ -2634,22 +2634,13 @@ Value ExpressionMeta::evaluate(const Document& root, Variables* variables) const } void ExpressionMeta::_doAddDependencies(DepsTracker* deps) const { - if (_metaType == MetaType::kTextScore) { - deps->setNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE, true); - + if (_metaType == MetaType::kSearchScore || _metaType == MetaType::kSearchHighlights) { // We do not add the dependencies for SEARCH_SCORE or SEARCH_HIGHLIGHTS because those values // are not stored in the collection (or in mongod at all). - } else if (_metaType == MetaType::kGeoNearDist) { - deps->setNeedsMetadata(DepsTracker::MetadataType::GEO_NEAR_DISTANCE, true); - } else if (_metaType == MetaType::kGeoNearPoint) { - deps->setNeedsMetadata(DepsTracker::MetadataType::GEO_NEAR_POINT, true); - } else if (_metaType == MetaType::kRecordId) { - // TODO: SERVER-42560 handle passing of metadata between PlanStage and DS layers. - } else if (_metaType == MetaType::kIndexKey) { - // TODO: SERVER-42560 handle passing of metadata between PlanStage and DS layers. - } else if (_metaType == MetaType::kSortKey) { - deps->setNeedsMetadata(DepsTracker::MetadataType::SORT_KEY, true); + return; } + + deps->setNeedsMetadata(_metaType, true); } /* ----------------------- ExpressionMod ---------------------------- */ diff --git a/src/mongo/db/pipeline/expression_test.cpp b/src/mongo/db/pipeline/expression_test.cpp index 0b3b8be1179..859ed6cc22e 100644 --- a/src/mongo/db/pipeline/expression_test.cpp +++ b/src/mongo/db/pipeline/expression_test.cpp @@ -262,7 +262,7 @@ protected: } ASSERT_BSONOBJ_EQ(expectedDependencies, dependenciesBson.arr()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsAnyMetadata()); } void assertContents(const intrusive_ptr<Testable>& expr, const BSONArray& expectedContents) { @@ -1985,7 +1985,7 @@ public: ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(1U, dependencies.fields.count("a.b")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsAnyMetadata()); } }; @@ -2491,7 +2491,7 @@ public: expression->addDependencies(&dependencies); ASSERT_EQUALS(0U, dependencies.fields.size()); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsAnyMetadata()); } }; @@ -3017,7 +3017,7 @@ public: ASSERT_EQUALS(1U, dependencies.fields.size()); ASSERT_EQUALS(1U, dependencies.fields.count("a.b")); ASSERT_EQUALS(false, dependencies.needWholeDocument); - ASSERT_EQUALS(false, dependencies.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_EQUALS(false, dependencies.getNeedsAnyMetadata()); } }; diff --git a/src/mongo/db/pipeline/field_path.cpp b/src/mongo/db/pipeline/field_path.cpp index 2d891ce7b10..6eb9fe46d0b 100644 --- a/src/mongo/db/pipeline/field_path.cpp +++ b/src/mongo/db/pipeline/field_path.cpp @@ -47,17 +47,12 @@ const StringDataSet kAllowedDollarPrefixedFields = { // Metadata fields. - // TODO SERVER-42560: It may be possible to eliminate some of these, if they're only used for - // creating the "dependency" projection. Some of them ($dis and $sortKey) may be used in - // sharded queries and are necessary. + // This is necessary for sharded query execution of find() commands. mongos may attach a + // $sortKey field to the projection sent to shards so that it can merge the results correctly. "$sortKey", - "$pt", - "$dis", - "$textScore", - "$recordId", - // Used internally for forcing projections to be of a certain type. - "$__INTERNAL_QUERY_PROJECTION_RESERVED"}; + // This is necessary for the "showRecordId" feature. + "$recordId"}; } // namespace diff --git a/src/mongo/db/pipeline/parsed_exclusion_projection_test.cpp b/src/mongo/db/pipeline/parsed_exclusion_projection_test.cpp index 1e1b4b4256e..cc7271be016 100644 --- a/src/mongo/db/pipeline/parsed_exclusion_projection_test.cpp +++ b/src/mongo/db/pipeline/parsed_exclusion_projection_test.cpp @@ -149,7 +149,7 @@ TEST(ExclusionProjectionExecutionTest, ShouldNotAddAnyDependencies) { ASSERT_EQ(deps.fields.size(), 0UL); ASSERT_FALSE(deps.needWholeDocument); - ASSERT_FALSE(deps.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_FALSE(deps.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST(ExclusionProjectionExecutionTest, ShouldReportExcludedFieldsAsModified) { diff --git a/src/mongo/db/pipeline/pipeline.cpp b/src/mongo/db/pipeline/pipeline.cpp index 7642b1ef49a..7e9fa39c66d 100644 --- a/src/mongo/db/pipeline/pipeline.cpp +++ b/src/mongo/db/pipeline/pipeline.cpp @@ -501,7 +501,7 @@ void Pipeline::addFinalSource(intrusive_ptr<DocumentSource> source) { _sources.push_back(source); } -DepsTracker Pipeline::getDependencies(DepsTracker::MetadataAvailable metadataAvailable) const { +DepsTracker Pipeline::getDependencies(QueryMetadataBitSet metadataAvailable) const { DepsTracker deps(metadataAvailable); const bool scopeHasVariables = pCtx->variablesParseState.hasDefinedVariables(); bool skipFieldsAndMetadataDeps = false; @@ -533,9 +533,7 @@ DepsTracker Pipeline::getDependencies(DepsTracker::MetadataAvailable metadataAva } if (!knowAllMeta) { - for (auto&& req : localDeps.getAllRequiredMetadataTypes()) { - deps.setNeedsMetadata(req, true); - } + deps.requestMetadata(localDeps.metadataDeps()); knowAllMeta = status & DepsTracker::State::EXHAUSTIVE_META; } @@ -549,15 +547,15 @@ DepsTracker Pipeline::getDependencies(DepsTracker::MetadataAvailable metadataAva if (!knowAllFields) deps.needWholeDocument = true; // don't know all fields we need - if (metadataAvailable & DepsTracker::MetadataAvailable::kTextScore) { + if (metadataAvailable[DocumentMetadataFields::kTextScore]) { // If there is a text score, assume we need to keep it if we can't prove we don't. If we are // the first half of a pipeline which has been split, future stages might need it. if (!knowAllMeta) { - deps.setNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE, true); + deps.setNeedsMetadata(DocumentMetadataFields::kTextScore, true); } } else { // If there is no text score available, then we don't need to ask for it. - deps.setNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE, false); + deps.setNeedsMetadata(DocumentMetadataFields::kTextScore, false); } return deps; diff --git a/src/mongo/db/pipeline/pipeline.h b/src/mongo/db/pipeline/pipeline.h index 1af188f4b15..39ba6372687 100644 --- a/src/mongo/db/pipeline/pipeline.h +++ b/src/mongo/db/pipeline/pipeline.h @@ -251,7 +251,7 @@ public: * Returns the dependencies needed by this pipeline. 'metadataAvailable' should reflect what * metadata is present on documents that are input to the front of the pipeline. */ - DepsTracker getDependencies(DepsTracker::MetadataAvailable metadataAvailable) const; + DepsTracker getDependencies(QueryMetadataBitSet metadataAvailable) const; const SourceContainer& getSources() const { return _sources; diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp index c327187ecd3..a523066d2a8 100644 --- a/src/mongo/db/pipeline/pipeline_d.cpp +++ b/src/mongo/db/pipeline/pipeline_d.cpp @@ -193,6 +193,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> attemptToGetExe const intrusive_ptr<ExpressionContext>& pExpCtx, BSONObj queryObj, BSONObj projectionObj, + const QueryMetadataBitSet& metadataRequested, BSONObj sortObj, boost::optional<std::string> groupIdForDistinctScan, const AggregationRequest* aggRequest, @@ -232,6 +233,9 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> attemptToGetExe return {cq.getStatus()}; } + // Mark the metadata that's requested by the pipeline on the CQ. + cq.getValue()->requestAdditionalMetadata(metadataRequested); + if (groupIdForDistinctScan) { // When the pipeline includes a $group that groups by a single field // (groupIdForDistinctScan), we use getExecutorDistinct() to attempt to get an executor that @@ -266,13 +270,6 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> attemptToGetExe return getExecutorFind(opCtx, collection, std::move(cq.getValue()), permitYield, plannerOpts); } -BSONObj removeSortKeyMetaProjection(BSONObj projectionObj) { - if (!projectionObj[Document::metaFieldSortKey]) { - return projectionObj; - } - return projectionObj.removeField(Document::metaFieldSortKey); -} - /** * Examines the indexes in 'collection' and returns the field name of a geo-indexed field suitable * for use in $geoNear. 2d indexes are given priority over 2dsphere indexes. @@ -366,7 +363,7 @@ PipelineD::buildInnerQueryExecutor(Collection* collection, // TODO SERVER-37453 this should no longer be necessary when we no don't need locks // to destroy a PlanExecutor. - auto deps = pipeline->getDependencies(DepsTracker::MetadataAvailable::kNoMetadata); + auto deps = pipeline->getDependencies(DepsTracker::kNoMetadata); auto attachExecutorCallback = [deps](Collection* collection, std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> exec, @@ -479,10 +476,10 @@ PipelineD::buildInnerQueryExecutorGeneric(Collection* collection, // Find the set of fields in the source documents depended on by this pipeline. DepsTracker deps = pipeline->getDependencies(DocumentSourceMatch::isTextQuery(queryObj) - ? DepsTracker::MetadataAvailable::kTextScore - : DepsTracker::MetadataAvailable::kNoMetadata); + ? DepsTracker::kOnlyTextScore + : DepsTracker::kNoMetadata); - BSONObj projForQuery = deps.toProjection(); + BSONObj projForQuery = deps.toProjectionWithoutMetadata(); boost::intrusive_ptr<DocumentSourceSort> sortStage; boost::intrusive_ptr<DocumentSourceGroup> groupStage; @@ -536,8 +533,7 @@ PipelineD::buildInnerQueryExecutorGeneric(Collection* collection, Pipeline* pipeline) { auto cursor = DocumentSourceCursor::create( collection, std::move(exec), pipeline->getContext(), trackOplogTS); - addCursorSource( - pipeline, std::move(cursor), std::move(deps), queryObj, sortObj, projForQuery); + addCursorSource(pipeline, std::move(cursor), std::move(deps), queryObj, sortObj); }; return std::make_pair(std::move(attachExecutorCallback), std::move(exec)); } @@ -557,7 +553,7 @@ PipelineD::buildInnerQueryExecutorGeoNear(Collection* collection, const auto geoNearStage = dynamic_cast<DocumentSourceGeoNear*>(sources.front().get()); invariant(geoNearStage); - auto deps = pipeline->getDependencies(DepsTracker::kAllGeoNearDataAvailable); + auto deps = pipeline->getDependencies(DepsTracker::kAllGeoNearData); // If the user specified a "key" field, use that field to satisfy the "near" query. Otherwise, // look for a geo-indexed field in 'collection' that can. @@ -569,7 +565,7 @@ PipelineD::buildInnerQueryExecutorGeoNear(Collection* collection, // Create a PlanExecutor whose query is the "near" predicate on 'nearFieldName' combined with // the optional "query" argument in the $geoNear stage. BSONObj fullQuery = geoNearStage->asNearQuery(nearFieldName); - BSONObj proj = deps.toProjection(); + BSONObj proj = deps.toProjectionWithoutMetadata(); BSONObj sortFromQuerySystem; auto exec = uassertStatusOK(prepareExecutor(expCtx->opCtx, collection, @@ -627,7 +623,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep // The query system has the potential to use an index to provide a non-blocking sort and/or to // use the projection to generate a covered plan. If this is possible, it is more efficient to // let the query system handle those parts of the pipeline. If not, it is more efficient to use - // a $sort and/or a ParsedDeps object. Thus, we will determine whether the query system can + // a $sort and/or a $project. Thus, we will determine whether the query system can // provide a non-blocking sort or a covered projection before we commit to a PlanExecutor. // // To determine if the query system can provide a non-blocking sort, we pass the @@ -674,6 +670,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep expCtx, queryObj, *projectionObj, + deps.metadataDeps(), sortObj ? *sortObj : emptySort, rewrittenGroupStage->groupId(), aggRequest, @@ -711,16 +708,17 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep const BSONObj metaSortProjection = BSON("$sortKey" << BSON("$meta" << "sortKey")); - // The only way to get meta information (e.g. the text score) is to let the query system handle - // the projection. In all other cases, unless the query system can do an index-covered - // projection and avoid going to the raw record at all, it is faster to have ParsedDeps filter - // the fields we need. + // TODO SERVER-42905: It should be possible to push down all eligible projections to the query + // layer. This code assumes that metadata is passed from the query layer to the DocumentSource + // layer via a projection, which is no longer true. if (!deps.getNeedsAnyMetadata()) { plannerOpts |= QueryPlannerParams::NO_UNCOVERED_PROJECTIONS; } SortPattern userSortPattern(*sortObj, expCtx); if (sortStage && canSortBePushedDown(userSortPattern)) { + QueryMetadataBitSet needsSortKey; + needsSortKey.set(DocumentMetadataFields::MetaType::kSortKey); // See if the query system can provide a non-blocking sort. auto swExecutorSort = attemptToGetExecutor(opCtx, @@ -728,7 +726,8 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep nss, expCtx, queryObj, - expCtx->needsMerge ? metaSortProjection : emptyProjection, + BSONObj(), // empty projection + expCtx->needsMerge ? needsSortKey : DepsTracker::kNoMetadata, *sortObj, boost::none, /* groupIdForDistinctScan */ aggRequest, @@ -744,6 +743,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep expCtx, queryObj, *projectionObj, + deps.metadataDeps(), *sortObj, boost::none, /* groupIdForDistinctScan */ aggRequest, @@ -780,13 +780,15 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep } } - // Either there's no sort or the query system can't provide a non-blocking sort. + // Either there was no $sort stage, or the query system could not provide a non-blocking + // sort. *sortObj = BSONObj(); - *projectionObj = removeSortKeyMetaProjection(*projectionObj); - const auto metadataRequired = deps.getAllRequiredMetadataTypes(); - if (metadataRequired.size() == 1 && - metadataRequired.front() == DepsTracker::MetadataType::SORT_KEY) { + // Since the DocumentSource layer will perform the sort, remove any dependencies we have on the + // query layer for a sort key. + QueryMetadataBitSet metadataDepsWithoutSortKey = deps.metadataDeps(); + metadataDepsWithoutSortKey[DocumentMetadataFields::kSortKey] = false; + if (!metadataDepsWithoutSortKey.any()) { // A sort key requirement would have prevented us from being able to add this parameter // before, but now we know the query system won't cover the sort, so we will be able to // compute the sort key ourselves during the $sort stage, and thus don't need a query @@ -801,6 +803,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep expCtx, queryObj, *projectionObj, + metadataDepsWithoutSortKey, *sortObj, boost::none, /* groupIdForDistinctScan */ aggRequest, @@ -814,7 +817,8 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep "Failed to determine whether query system can provide a covered projection"); } - // The query system couldn't provide a covered or simple uncovered projection. + // The query system couldn't provide a covered or simple uncovered projection. Do no projections + // and request no metadata from the query layer. *projectionObj = BSONObj(); // If this doesn't work, nothing will. return attemptToGetExecutor(opCtx, @@ -823,6 +827,7 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> PipelineD::prep expCtx, queryObj, *projectionObj, + DepsTracker::kNoMetadata, *sortObj, boost::none, /* groupIdForDistinctScan */ aggRequest, @@ -834,8 +839,7 @@ void PipelineD::addCursorSource(Pipeline* pipeline, boost::intrusive_ptr<DocumentSourceCursor> cursor, DepsTracker deps, const BSONObj& queryObj, - const BSONObj& sortObj, - const BSONObj& projectionObj) { + const BSONObj& sortObj) { // Add the cursor to the pipeline first so that it's correctly disposed of as part of the // pipeline if an exception is thrown during this method. pipeline->addInitialSource(cursor); @@ -845,19 +849,6 @@ void PipelineD::addCursorSource(Pipeline* pipeline, if (deps.hasNoRequirements()) { cursor->shouldProduceEmptyDocs(); } - - if (!projectionObj.isEmpty()) { - cursor->setProjection(projectionObj, boost::none, deps.getNeedsAnyMetadata()); - } else { - // There may be fewer dependencies now if the sort was covered. - if (!sortObj.isEmpty()) { - deps = pipeline->getDependencies(DocumentSourceMatch::isTextQuery(queryObj) - ? DepsTracker::MetadataAvailable::kTextScore - : DepsTracker::MetadataAvailable::kNoMetadata); - } - - cursor->setProjection(deps.toProjection(), deps.toParsedDeps(), deps.getNeedsAnyMetadata()); - } } Timestamp PipelineD::getLatestOplogTimestamp(const Pipeline* pipeline) { diff --git a/src/mongo/db/pipeline/pipeline_d.h b/src/mongo/db/pipeline/pipeline_d.h index 606c91a1067..9433198c4d9 100644 --- a/src/mongo/db/pipeline/pipeline_d.h +++ b/src/mongo/db/pipeline/pipeline_d.h @@ -202,8 +202,7 @@ private: boost::intrusive_ptr<DocumentSourceCursor> cursor, DepsTracker deps, const BSONObj& queryObj = BSONObj(), - const BSONObj& sortObj = BSONObj(), - const BSONObj& projectionObj = BSONObj()); + const BSONObj& sortObj = BSONObj()); }; } // namespace mongo diff --git a/src/mongo/db/pipeline/pipeline_test.cpp b/src/mongo/db/pipeline/pipeline_test.cpp index cc92f5958f2..3da457141dd 100644 --- a/src/mongo/db/pipeline/pipeline_test.cpp +++ b/src/mongo/db/pipeline/pipeline_test.cpp @@ -2793,13 +2793,13 @@ using PipelineDependenciesTest = AggregationContextFixture; TEST_F(PipelineDependenciesTest, EmptyPipelineShouldRequireWholeDocument) { auto pipeline = unittest::assertGet(Pipeline::create({}, getExpCtx())); - auto depsTracker = pipeline->getDependencies(DepsTracker::MetadataAvailable::kNoMetadata); + auto depsTracker = pipeline->getDependencies(DepsTracker::kNoMetadata); ASSERT_TRUE(depsTracker.needWholeDocument); - ASSERT_FALSE(depsTracker.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_FALSE(depsTracker.getNeedsMetadata(DocumentMetadataFields::kTextScore)); - depsTracker = pipeline->getDependencies(DepsTracker::MetadataAvailable::kTextScore); + depsTracker = pipeline->getDependencies(DepsTracker::kOnlyTextScore); ASSERT_TRUE(depsTracker.needWholeDocument); - ASSERT_TRUE(depsTracker.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_TRUE(depsTracker.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } // @@ -2861,7 +2861,7 @@ public: class DocumentSourceNeedsOnlyTextScore : public DocumentSourceDependencyDummy { public: DepsTracker::State getDependencies(DepsTracker* deps) const final { - deps->setNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE, true); + deps->setNeedsMetadata(DocumentMetadataFields::kTextScore, true); return DepsTracker::State::EXHAUSTIVE_META; } @@ -2887,15 +2887,15 @@ TEST_F(PipelineDependenciesTest, ShouldRequireWholeDocumentIfAnyStageDoesNotSupp auto notSupported = DocumentSourceDependenciesNotSupported::create(); auto pipeline = unittest::assertGet(Pipeline::create({needsASeeNext, notSupported}, ctx)); - auto depsTracker = pipeline->getDependencies(DepsTracker::MetadataAvailable::kNoMetadata); + auto depsTracker = pipeline->getDependencies(DepsTracker::kNoMetadata); ASSERT_TRUE(depsTracker.needWholeDocument); // The inputs did not have a text score available, so we should not require a text score. - ASSERT_FALSE(depsTracker.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_FALSE(depsTracker.getNeedsMetadata(DocumentMetadataFields::kTextScore)); // Now in the other order. pipeline = unittest::assertGet(Pipeline::create({notSupported, needsASeeNext}, ctx)); - depsTracker = pipeline->getDependencies(DepsTracker::MetadataAvailable::kNoMetadata); + depsTracker = pipeline->getDependencies(DepsTracker::kNoMetadata); ASSERT_TRUE(depsTracker.needWholeDocument); } @@ -2904,7 +2904,7 @@ TEST_F(PipelineDependenciesTest, ShouldRequireWholeDocumentIfNoStageReturnsExhau auto needsASeeNext = DocumentSourceNeedsASeeNext::create(); auto pipeline = unittest::assertGet(Pipeline::create({needsASeeNext}, ctx)); - auto depsTracker = pipeline->getDependencies(DepsTracker::MetadataAvailable::kNoMetadata); + auto depsTracker = pipeline->getDependencies(DepsTracker::kNoMetadata); ASSERT_TRUE(depsTracker.needWholeDocument); } @@ -2914,7 +2914,7 @@ TEST_F(PipelineDependenciesTest, ShouldNotRequireWholeDocumentIfAnyStageReturnsE auto needsOnlyB = DocumentSourceNeedsOnlyB::create(); auto pipeline = unittest::assertGet(Pipeline::create({needsASeeNext, needsOnlyB}, ctx)); - auto depsTracker = pipeline->getDependencies(DepsTracker::MetadataAvailable::kNoMetadata); + auto depsTracker = pipeline->getDependencies(DepsTracker::kNoMetadata); ASSERT_FALSE(depsTracker.needWholeDocument); ASSERT_EQ(depsTracker.fields.size(), 2UL); ASSERT_EQ(depsTracker.fields.count("a"), 1UL); @@ -2927,9 +2927,9 @@ TEST_F(PipelineDependenciesTest, ShouldNotAddAnyRequiredFieldsAfterFirstStageWit auto needsASeeNext = DocumentSourceNeedsASeeNext::create(); auto pipeline = unittest::assertGet(Pipeline::create({needsOnlyB, needsASeeNext}, ctx)); - auto depsTracker = pipeline->getDependencies(DepsTracker::MetadataAvailable::kNoMetadata); + auto depsTracker = pipeline->getDependencies(DepsTracker::kNoMetadata); ASSERT_FALSE(depsTracker.needWholeDocument); - ASSERT_FALSE(depsTracker.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_FALSE(depsTracker.getNeedsMetadata(DocumentMetadataFields::kTextScore)); // 'needsOnlyB' claims to know all its field dependencies, so we shouldn't add any from // 'needsASeeNext'. @@ -2941,8 +2941,8 @@ TEST_F(PipelineDependenciesTest, ShouldNotRequireTextScoreIfThereIsNoScoreAvaila auto ctx = getExpCtx(); auto pipeline = unittest::assertGet(Pipeline::create({}, ctx)); - auto depsTracker = pipeline->getDependencies(DepsTracker::MetadataAvailable::kNoMetadata); - ASSERT_FALSE(depsTracker.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + auto depsTracker = pipeline->getDependencies(DepsTracker::kNoMetadata); + ASSERT_FALSE(depsTracker.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(PipelineDependenciesTest, ShouldThrowIfTextScoreIsNeededButNotPresent) { @@ -2950,21 +2950,20 @@ TEST_F(PipelineDependenciesTest, ShouldThrowIfTextScoreIsNeededButNotPresent) { auto needsText = DocumentSourceNeedsOnlyTextScore::create(); auto pipeline = unittest::assertGet(Pipeline::create({needsText}, ctx)); - ASSERT_THROWS(pipeline->getDependencies(DepsTracker::MetadataAvailable::kNoMetadata), - AssertionException); + ASSERT_THROWS(pipeline->getDependencies(DepsTracker::kNoMetadata), AssertionException); } TEST_F(PipelineDependenciesTest, ShouldRequireTextScoreIfAvailableAndNoStageReturnsExhaustiveMeta) { auto ctx = getExpCtx(); auto pipeline = unittest::assertGet(Pipeline::create({}, ctx)); - auto depsTracker = pipeline->getDependencies(DepsTracker::MetadataAvailable::kTextScore); - ASSERT_TRUE(depsTracker.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + auto depsTracker = pipeline->getDependencies(DepsTracker::kOnlyTextScore); + ASSERT_TRUE(depsTracker.getNeedsMetadata(DocumentMetadataFields::kTextScore)); auto needsASeeNext = DocumentSourceNeedsASeeNext::create(); pipeline = unittest::assertGet(Pipeline::create({needsASeeNext}, ctx)); - depsTracker = pipeline->getDependencies(DepsTracker::MetadataAvailable::kTextScore); - ASSERT_TRUE(depsTracker.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + depsTracker = pipeline->getDependencies(DepsTracker::kOnlyTextScore); + ASSERT_TRUE(depsTracker.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } TEST_F(PipelineDependenciesTest, ShouldNotRequireTextScoreIfAvailableButDefinitelyNotNeeded) { @@ -2973,11 +2972,11 @@ TEST_F(PipelineDependenciesTest, ShouldNotRequireTextScoreIfAvailableButDefinite auto needsText = DocumentSourceNeedsOnlyTextScore::create(); auto pipeline = unittest::assertGet(Pipeline::create({stripsTextScore, needsText}, ctx)); - auto depsTracker = pipeline->getDependencies(DepsTracker::MetadataAvailable::kTextScore); + auto depsTracker = pipeline->getDependencies(DepsTracker::kOnlyTextScore); // 'stripsTextScore' claims that no further stage will need metadata information, so we // shouldn't have the text score as a dependency. - ASSERT_FALSE(depsTracker.getNeedsMetadata(DepsTracker::MetadataType::TEXT_SCORE)); + ASSERT_FALSE(depsTracker.getNeedsMetadata(DocumentMetadataFields::kTextScore)); } } // namespace Dependencies |