summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIan Boros <ian.boros@mongodb.com>2020-01-21 23:27:55 +0000
committerevergreen <evergreen@mongodb.com>2020-01-21 23:27:55 +0000
commit48cd578fa9c3ef317666ca475f9ee14c1fe0bc4f (patch)
tree06d2404c18339a300eb8441bbce195c71f52321e /src
parent896505a1ee961597277945fe63892d0bbb91f9ad (diff)
downloadmongo-48cd578fa9c3ef317666ca475f9ee14c1fe0bc4f.tar.gz
SERVER-45403 Don't recompute wildcard projection exhaustive paths
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/exec/add_fields_projection_executor.h4
-rw-r--r--src/mongo/db/exec/exclusion_projection_executor.h4
-rw-r--r--src/mongo/db/exec/inclusion_projection_executor.h15
-rw-r--r--src/mongo/db/exec/projection_executor.h6
-rw-r--r--src/mongo/db/exec/projection_executor_utils.cpp14
-rw-r--r--src/mongo/db/exec/projection_executor_utils.h7
-rw-r--r--src/mongo/db/exec/projection_executor_wildcard_access_test.cpp44
-rw-r--r--src/mongo/db/exec/wildcard_projection.h56
-rw-r--r--src/mongo/db/index/wildcard_access_method.h6
-rw-r--r--src/mongo/db/index/wildcard_key_generator.cpp12
-rw-r--r--src/mongo/db/index/wildcard_key_generator.h11
-rw-r--r--src/mongo/db/query/collection_query_info.cpp13
-rw-r--r--src/mongo/db/query/get_executor.cpp14
-rw-r--r--src/mongo/db/query/get_executor_test.cpp23
-rw-r--r--src/mongo/db/query/index_entry.h16
-rw-r--r--src/mongo/db/query/plan_cache_indexability.cpp2
-rw-r--r--src/mongo/db/query/plan_cache_indexability_test.cpp3
-rw-r--r--src/mongo/db/query/plan_cache_test.cpp21
-rw-r--r--src/mongo/db/query/planner_ixselect_test.cpp13
-rw-r--r--src/mongo/db/query/planner_wildcard_helpers.cpp10
-rw-r--r--src/mongo/db/query/query_planner_wildcard_index_test.cpp6
21 files changed, 185 insertions, 115 deletions
diff --git a/src/mongo/db/exec/add_fields_projection_executor.h b/src/mongo/db/exec/add_fields_projection_executor.h
index e17ce25e494..00ba580c2c7 100644
--- a/src/mongo/db/exec/add_fields_projection_executor.h
+++ b/src/mongo/db/exec/add_fields_projection_executor.h
@@ -117,6 +117,10 @@ public:
*/
Document applyProjection(const Document& inputDoc) const final;
+ boost::optional<std::set<FieldRef>> extractExhaustivePaths() const {
+ return boost::none;
+ }
+
private:
/**
* Attempts to parse 'objSpec' as an expression like {$add: [...]}. Adds a computed field to
diff --git a/src/mongo/db/exec/exclusion_projection_executor.h b/src/mongo/db/exec/exclusion_projection_executor.h
index d8cdab39e1d..cf21bf57126 100644
--- a/src/mongo/db/exec/exclusion_projection_executor.h
+++ b/src/mongo/db/exec/exclusion_projection_executor.h
@@ -136,6 +136,10 @@ public:
return {DocumentSource::GetModPathsReturn::Type::kFiniteSet, std::move(modifiedPaths), {}};
}
+ boost::optional<std::set<FieldRef>> extractExhaustivePaths() const {
+ return boost::none;
+ }
+
private:
// The ExclusionNode tree does most of the execution work once constructed.
std::unique_ptr<ExclusionNode> _root;
diff --git a/src/mongo/db/exec/inclusion_projection_executor.h b/src/mongo/db/exec/inclusion_projection_executor.h
index 2ce8d03623c..b095a423652 100644
--- a/src/mongo/db/exec/inclusion_projection_executor.h
+++ b/src/mongo/db/exec/inclusion_projection_executor.h
@@ -225,6 +225,21 @@ public:
return _root->applyToDocument(inputDoc);
}
+ /**
+ * Returns the exhaustive set of all paths that will be preserved by this projection, or
+ * boost::none if the exhaustive set cannot be determined.
+ */
+ boost::optional<std::set<FieldRef>> extractExhaustivePaths() const override {
+ std::set<FieldRef> exhaustivePaths;
+ DepsTracker depsTracker;
+ addDependencies(&depsTracker);
+ for (auto&& field : depsTracker.fields) {
+ exhaustivePaths.insert(FieldRef{field});
+ }
+
+ return exhaustivePaths;
+ }
+
private:
// The InclusionNode tree does most of the execution work once constructed.
std::unique_ptr<InclusionNode> _root;
diff --git a/src/mongo/db/exec/projection_executor.h b/src/mongo/db/exec/projection_executor.h
index 7921d4510e8..ca8e0d3990c 100644
--- a/src/mongo/db/exec/projection_executor.h
+++ b/src/mongo/db/exec/projection_executor.h
@@ -91,6 +91,12 @@ public:
_rootReplacementExpression = expr;
}
+ /**
+ * Returns the exhaustive set of all paths that will be preserved by this projection, or
+ * boost::none if the exhaustive set cannot be determined.
+ */
+ virtual boost::optional<std::set<FieldRef>> extractExhaustivePaths() const = 0;
+
protected:
ProjectionExecutor(const boost::intrusive_ptr<ExpressionContext>& expCtx,
ProjectionPolicies policies)
diff --git a/src/mongo/db/exec/projection_executor_utils.cpp b/src/mongo/db/exec/projection_executor_utils.cpp
index 0923e2e2fab..1cbc04531c9 100644
--- a/src/mongo/db/exec/projection_executor_utils.cpp
+++ b/src/mongo/db/exec/projection_executor_utils.cpp
@@ -54,20 +54,6 @@ stdx::unordered_set<std::string> applyProjectionToFields(
return out;
}
-std::set<FieldRef> extractExhaustivePaths(const projection_executor::ProjectionExecutor* executor) {
- std::set<FieldRef> exhaustivePaths;
-
- if (executor->getType() == TransformerInterface::TransformerType::kInclusionProjection) {
- DepsTracker depsTracker;
- executor->addDependencies(&depsTracker);
- for (auto&& field : depsTracker.fields) {
- exhaustivePaths.insert(FieldRef{field});
- }
- }
-
- return exhaustivePaths;
-}
-
namespace {
/**
* Holds various parameters required to apply a $slice projection. Populated from the arguments
diff --git a/src/mongo/db/exec/projection_executor_utils.h b/src/mongo/db/exec/projection_executor_utils.h
index 338d12d39d3..0b5558bc221 100644
--- a/src/mongo/db/exec/projection_executor_utils.h
+++ b/src/mongo/db/exec/projection_executor_utils.h
@@ -50,13 +50,6 @@ stdx::unordered_set<std::string> applyProjectionToFields(
const stdx::unordered_set<std::string>& fields);
/**
- * Returns the exhaustive set of all paths that will be preserved by this projection, or an
- * empty set if the exhaustive set cannot be determined. An inclusion will always produce an
- * exhaustive set; an exclusion will always produce an empty set.
- */
-std::set<FieldRef> extractExhaustivePaths(const projection_executor::ProjectionExecutor* executor);
-
-/**
* Applies a positional projection on the first array found in the 'path' on a projection
* 'preImage' document. The applied projection is merged with a projection 'postImage' document.
* The 'matchExpr' specifies a condition to locate the first matching element in the array and must
diff --git a/src/mongo/db/exec/projection_executor_wildcard_access_test.cpp b/src/mongo/db/exec/projection_executor_wildcard_access_test.cpp
index 672447b90d5..8edf7432fe4 100644
--- a/src/mongo/db/exec/projection_executor_wildcard_access_test.cpp
+++ b/src/mongo/db/exec/projection_executor_wildcard_access_test.cpp
@@ -211,11 +211,11 @@ TEST(ProjectionExecutorTests, InclusionFieldPathsWithImplicitIdInclusion) {
ASSERT(parsedProject->getType() == TransformerInterface::TransformerType::kInclusionProjection);
// Extract the exhaustive set of paths that will be preserved by the projection.
- auto exhaustivePaths = projection_executor_utils::extractExhaustivePaths(parsedProject.get());
+ auto exhaustivePaths = parsedProject->extractExhaustivePaths();
std::set<FieldRef> expectedPaths = toFieldRefs({"_id", "a.b.c", "d"});
// Verify that the exhaustive set of paths is as expected.
- ASSERT(exhaustivePaths == expectedPaths);
+ ASSERT(*exhaustivePaths == expectedPaths);
}
TEST(ProjectionExecutorTests, InclusionFieldPathsWithExplicitIdInclusion) {
@@ -224,11 +224,11 @@ TEST(ProjectionExecutorTests, InclusionFieldPathsWithExplicitIdInclusion) {
ASSERT(parsedProject->getType() == TransformerInterface::TransformerType::kInclusionProjection);
// Extract the exhaustive set of paths that will be preserved by the projection.
- auto exhaustivePaths = projection_executor_utils::extractExhaustivePaths(parsedProject.get());
+ auto exhaustivePaths = parsedProject->extractExhaustivePaths();
std::set<FieldRef> expectedPaths = toFieldRefs({"_id", "a.b.c", "d"});
// Verify that the exhaustive set of paths is as expected.
- ASSERT(exhaustivePaths == expectedPaths);
+ ASSERT(*exhaustivePaths == expectedPaths);
}
TEST(ProjectionExecutorTests, InclusionFieldPathsWithExplicitIdInclusionIdOnly) {
@@ -237,11 +237,11 @@ TEST(ProjectionExecutorTests, InclusionFieldPathsWithExplicitIdInclusionIdOnly)
ASSERT(parsedProject->getType() == TransformerInterface::TransformerType::kInclusionProjection);
// Extract the exhaustive set of paths that will be preserved by the projection.
- auto exhaustivePaths = projection_executor_utils::extractExhaustivePaths(parsedProject.get());
+ auto exhaustivePaths = parsedProject->extractExhaustivePaths();
std::set<FieldRef> expectedPaths = toFieldRefs({"_id"});
// Verify that the exhaustive set of paths is as expected.
- ASSERT(exhaustivePaths == expectedPaths);
+ ASSERT(*exhaustivePaths == expectedPaths);
}
TEST(ProjectionExecutorTests, InclusionFieldPathsWithImplicitIdExclusion) {
@@ -250,11 +250,11 @@ TEST(ProjectionExecutorTests, InclusionFieldPathsWithImplicitIdExclusion) {
ASSERT(parsedProject->getType() == TransformerInterface::TransformerType::kInclusionProjection);
// Extract the exhaustive set of paths that will be preserved by the projection.
- auto exhaustivePaths = projection_executor_utils::extractExhaustivePaths(parsedProject.get());
+ auto exhaustivePaths = parsedProject->extractExhaustivePaths();
std::set<FieldRef> expectedPaths = toFieldRefs({"a.b.c", "d"});
// Verify that the exhaustive set of paths is as expected.
- ASSERT(exhaustivePaths == expectedPaths);
+ ASSERT(*exhaustivePaths == expectedPaths);
}
TEST(ProjectionExecutorTests, InclusionFieldPathsWithExplicitIdExclusion) {
@@ -263,11 +263,11 @@ TEST(ProjectionExecutorTests, InclusionFieldPathsWithExplicitIdExclusion) {
ASSERT(parsedProject->getType() == TransformerInterface::TransformerType::kInclusionProjection);
// Extract the exhaustive set of paths that will be preserved by the projection.
- auto exhaustivePaths = projection_executor_utils::extractExhaustivePaths(parsedProject.get());
+ auto exhaustivePaths = parsedProject->extractExhaustivePaths();
std::set<FieldRef> expectedPaths = toFieldRefs({"a.b.c", "d"});
// Verify that the exhaustive set of paths is as expected.
- ASSERT(exhaustivePaths == expectedPaths);
+ ASSERT(*exhaustivePaths == expectedPaths);
}
TEST(ProjectionExecutorTests, ExclusionFieldPathsWithImplicitIdInclusion) {
@@ -276,10 +276,10 @@ TEST(ProjectionExecutorTests, ExclusionFieldPathsWithImplicitIdInclusion) {
ASSERT(parsedProject->getType() == TransformerInterface::TransformerType::kExclusionProjection);
// Extract the exhaustive set of paths that will be preserved by the projection.
- auto exhaustivePaths = projection_executor_utils::extractExhaustivePaths(parsedProject.get());
+ auto exhaustivePaths = parsedProject->extractExhaustivePaths();
- // Verify that the exhaustive set is empty, despite the implicit inclusion of _id.
- ASSERT(exhaustivePaths.empty());
+ // Verify that the exhaustive set is not available, despite the implicit inclusion of _id.
+ ASSERT(!exhaustivePaths);
}
TEST(ProjectionExecutorTests, ExclusionFieldPathsWithExplicitIdInclusion) {
@@ -288,10 +288,10 @@ TEST(ProjectionExecutorTests, ExclusionFieldPathsWithExplicitIdInclusion) {
ASSERT(parsedProject->getType() == TransformerInterface::TransformerType::kExclusionProjection);
// Extract the exhaustive set of paths that will be preserved by the projection.
- auto exhaustivePaths = projection_executor_utils::extractExhaustivePaths(parsedProject.get());
+ auto exhaustivePaths = parsedProject->extractExhaustivePaths();
- // Verify that the exhaustive set is empty, despite the explicit inclusion of _id.
- ASSERT(exhaustivePaths.empty());
+ // Verify that the exhaustive set is not available, despite the explicit inclusion of _id.
+ ASSERT(!exhaustivePaths);
}
TEST(ProjectionExecutorTests, ExclusionFieldPathsWithImplicitIdExclusion) {
@@ -300,10 +300,10 @@ TEST(ProjectionExecutorTests, ExclusionFieldPathsWithImplicitIdExclusion) {
ASSERT(parsedProject->getType() == TransformerInterface::TransformerType::kExclusionProjection);
// Extract the exhaustive set of paths that will be preserved by the projection.
- auto exhaustivePaths = projection_executor_utils::extractExhaustivePaths(parsedProject.get());
+ auto exhaustivePaths = parsedProject->extractExhaustivePaths();
// Verify that the exhaustive set is empty.
- ASSERT(exhaustivePaths.empty());
+ ASSERT(!exhaustivePaths);
}
TEST(ProjectionExecutorTests, ExclusionFieldPathsWithExplicitIdExclusion) {
@@ -312,10 +312,10 @@ TEST(ProjectionExecutorTests, ExclusionFieldPathsWithExplicitIdExclusion) {
ASSERT(parsedProject->getType() == TransformerInterface::TransformerType::kExclusionProjection);
// Extract the exhaustive set of paths that will be preserved by the projection.
- auto exhaustivePaths = projection_executor_utils::extractExhaustivePaths(parsedProject.get());
+ auto exhaustivePaths = parsedProject->extractExhaustivePaths();
// Verify that the exhaustive set is empty.
- ASSERT(exhaustivePaths.empty());
+ ASSERT(!exhaustivePaths);
}
TEST(ProjectionExecutorTests, ExclusionFieldPathsWithExplicitIdExclusionIdOnly) {
@@ -324,10 +324,10 @@ TEST(ProjectionExecutorTests, ExclusionFieldPathsWithExplicitIdExclusionIdOnly)
ASSERT(parsedProject->getType() == TransformerInterface::TransformerType::kExclusionProjection);
// Extract the exhaustive set of paths that will be preserved by the projection.
- auto exhaustivePaths = projection_executor_utils::extractExhaustivePaths(parsedProject.get());
+ auto exhaustivePaths = parsedProject->extractExhaustivePaths();
// Verify that the exhaustive set is empty.
- ASSERT(exhaustivePaths.empty());
+ ASSERT(!exhaustivePaths);
}
} // namespace
diff --git a/src/mongo/db/exec/wildcard_projection.h b/src/mongo/db/exec/wildcard_projection.h
new file mode 100644
index 00000000000..38005b5cf2c
--- /dev/null
+++ b/src/mongo/db/exec/wildcard_projection.h
@@ -0,0 +1,56 @@
+/**
+ * Copyright (C) 2020-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/db/exec/projection_executor.h"
+#include "mongo/db/field_ref.h"
+
+namespace mongo {
+
+class WildcardProjection {
+public:
+ WildcardProjection(std::unique_ptr<projection_executor::ProjectionExecutor> projExec)
+ : _exec(std::move(projExec)), _exhaustivePaths(_exec->extractExhaustivePaths()) {
+ invariant(_exec);
+ }
+
+ projection_executor::ProjectionExecutor* exec() const {
+ return _exec.get();
+ }
+
+ const boost::optional<std::set<FieldRef>>& exhaustivePaths() const {
+ return _exhaustivePaths;
+ }
+
+private:
+ // Guaranteed to be non-null.
+ std::unique_ptr<projection_executor::ProjectionExecutor> _exec;
+ // Store this here to avoid having to recompute it repeatedly, which is expensive.
+ boost::optional<std::set<FieldRef>> _exhaustivePaths;
+};
+} // namespace mongo
diff --git a/src/mongo/db/index/wildcard_access_method.h b/src/mongo/db/index/wildcard_access_method.h
index da03e69c9dc..0d87d6bbb99 100644
--- a/src/mongo/db/index/wildcard_access_method.h
+++ b/src/mongo/db/index/wildcard_access_method.h
@@ -71,10 +71,10 @@ public:
const MultikeyPaths& multikeyPaths) const final;
/**
- * Returns a pointer to the ProjectionExecutor owned by the underlying WildcardKeyGenerator.
+ * Returns a pointer to the WildcardProjection owned by the underlying WildcardKeyGenerator.
*/
- projection_executor::ProjectionExecutor* getProjectionExecutor() const {
- return _keyGen.getProjectionExecutor();
+ const WildcardProjection* getWildcardProjection() const {
+ return _keyGen.getWildcardProjection();
}
/**
diff --git a/src/mongo/db/index/wildcard_key_generator.cpp b/src/mongo/db/index/wildcard_key_generator.cpp
index 2766ff5e4fa..831cd776a15 100644
--- a/src/mongo/db/index/wildcard_key_generator.cpp
+++ b/src/mongo/db/index/wildcard_key_generator.cpp
@@ -65,8 +65,8 @@ void popPathComponent(BSONElement elem, bool enclosingObjIsArray, FieldRef* path
constexpr StringData WildcardKeyGenerator::kSubtreeSuffix;
-std::unique_ptr<projection_executor::ProjectionExecutor>
-WildcardKeyGenerator::createProjectionExecutor(BSONObj keyPattern, BSONObj pathProjection) {
+WildcardProjection WildcardKeyGenerator::createProjectionExecutor(BSONObj keyPattern,
+ BSONObj pathProjection) {
// We should never have a key pattern that contains more than a single element.
invariant(keyPattern.nFields() == 1);
@@ -91,8 +91,8 @@ WildcardKeyGenerator::createProjectionExecutor(BSONObj keyPattern, BSONObj pathP
auto expCtx = make_intrusive<ExpressionContext>(nullptr, nullptr);
auto policies = ProjectionPolicies::wildcardIndexSpecProjectionPolicies();
auto projection = projection_ast::parse(expCtx, projSpec, policies);
- return projection_executor::buildProjectionExecutor(
- expCtx, &projection, policies, projection_executor::kDefaultBuilderParams);
+ return WildcardProjection{projection_executor::buildProjectionExecutor(
+ expCtx, &projection, policies, projection_executor::kDefaultBuilderParams)};
}
WildcardKeyGenerator::WildcardKeyGenerator(BSONObj keyPattern,
@@ -100,7 +100,7 @@ WildcardKeyGenerator::WildcardKeyGenerator(BSONObj keyPattern,
const CollatorInterface* collator,
KeyString::Version keyStringVersion,
Ordering ordering)
- : _projExec(createProjectionExecutor(keyPattern, pathProjection)),
+ : _proj(createProjectionExecutor(keyPattern, pathProjection)),
_collator(collator),
_keyPattern(keyPattern),
_keyStringVersion(keyStringVersion),
@@ -111,7 +111,7 @@ void WildcardKeyGenerator::generateKeys(BSONObj inputDoc,
KeyStringSet* multikeyPaths,
boost::optional<RecordId> id) const {
FieldRef rootPath;
- _traverseWildcard(_projExec->applyTransformation(Document{inputDoc}).toBson(),
+ _traverseWildcard(_proj.exec()->applyTransformation(Document{inputDoc}).toBson(),
false,
&rootPath,
keys,
diff --git a/src/mongo/db/index/wildcard_key_generator.h b/src/mongo/db/index/wildcard_key_generator.h
index cf99187e35f..cd403939840 100644
--- a/src/mongo/db/index/wildcard_key_generator.h
+++ b/src/mongo/db/index/wildcard_key_generator.h
@@ -29,7 +29,7 @@
#pragma once
-#include "mongo/db/exec/projection_executor.h"
+#include "mongo/db/exec/wildcard_projection.h"
#include "mongo/db/field_ref.h"
#include "mongo/db/query/collation/collator_interface.h"
#include "mongo/db/storage/key_string.h"
@@ -51,8 +51,7 @@ public:
* internally when generating the keys for the $** index, as defined by the 'keyPattern' and
* 'pathProjection' arguments.
*/
- static std::unique_ptr<projection_executor::ProjectionExecutor> createProjectionExecutor(
- BSONObj keyPattern, BSONObj pathProjection);
+ static WildcardProjection createProjectionExecutor(BSONObj keyPattern, BSONObj pathProjection);
WildcardKeyGenerator(BSONObj keyPattern,
BSONObj pathProjection,
@@ -63,8 +62,8 @@ public:
/**
* Returns a pointer to the key generator's underlying ProjectionExecutor.
*/
- projection_executor::ProjectionExecutor* getProjectionExecutor() const {
- return _projExec.get();
+ const WildcardProjection* getWildcardProjection() const {
+ return &_proj;
}
/**
@@ -107,7 +106,7 @@ private:
KeyStringSet* keys,
boost::optional<RecordId> id) const;
- std::unique_ptr<projection_executor::ProjectionExecutor> _projExec;
+ WildcardProjection _proj;
const CollatorInterface* _collator;
const BSONObj _keyPattern;
const KeyString::Version _keyStringVersion;
diff --git a/src/mongo/db/query/collection_query_info.cpp b/src/mongo/db/query/collection_query_info.cpp
index d65773a230c..9d18d8175d9 100644
--- a/src/mongo/db/query/collection_query_info.cpp
+++ b/src/mongo/db/query/collection_query_info.cpp
@@ -61,9 +61,9 @@ CoreIndexInfo indexInfoFromIndexCatalogEntry(const IndexCatalogEntry& ice) {
auto accessMethod = ice.accessMethod();
invariant(accessMethod);
- projection_executor::ProjectionExecutor* projExec = nullptr;
+ const WildcardProjection* projExec = nullptr;
if (desc->getIndexType() == IndexType::INDEX_WILDCARD)
- projExec = static_cast<const WildcardAccessMethod*>(accessMethod)->getProjectionExecutor();
+ projExec = static_cast<const WildcardAccessMethod*>(accessMethod)->getWildcardProjection();
return {desc->keyPattern(),
desc->getIndexType(),
@@ -100,17 +100,18 @@ void CollectionQueryInfo::computeIndexKeys(OperationContext* opCtx) {
if (descriptor->getAccessMethodName() == IndexNames::WILDCARD) {
// Obtain the projection used by the $** index's key generator.
const auto* pathProj =
- static_cast<const WildcardAccessMethod*>(iam)->getProjectionExecutor();
+ static_cast<const WildcardAccessMethod*>(iam)->getWildcardProjection();
// If the projection is an exclusion, then we must check the new document's keys on all
// updates, since we do not exhaustively know the set of paths to be indexed.
- if (pathProj->getType() ==
+ if (pathProj->exec()->getType() ==
TransformerInterface::TransformerType::kExclusionProjection) {
_indexedPaths.allPathsIndexed();
} else {
// If a subtree was specified in the keyPattern, or if an inclusion projection is
// present, then we need only index the path(s) preserved by the projection.
- for (const auto& path :
- projection_executor_utils::extractExhaustivePaths(pathProj)) {
+ const auto& exhaustivePaths = pathProj->exhaustivePaths();
+ invariant(exhaustivePaths);
+ for (const auto& path : *exhaustivePaths) {
_indexedPaths.addPath(path);
}
}
diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp
index a8f215d0671..3dcd0e2aa40 100644
--- a/src/mongo/db/query/get_executor.cpp
+++ b/src/mongo/db/query/get_executor.cpp
@@ -166,18 +166,19 @@ IndexEntry indexEntryFromIndexCatalogEntry(OperationContext* opCtx,
const bool isMultikey = desc->isMultikey();
- projection_executor::ProjectionExecutor* projExec = nullptr;
+ const WildcardProjection* wildcardProjection = nullptr;
std::set<FieldRef> multikeyPathSet;
if (desc->getIndexType() == IndexType::INDEX_WILDCARD) {
- projExec = static_cast<const WildcardAccessMethod*>(accessMethod)->getProjectionExecutor();
+ wildcardProjection =
+ static_cast<const WildcardAccessMethod*>(accessMethod)->getWildcardProjection();
if (isMultikey) {
MultikeyMetadataAccessStats mkAccessStats;
if (canonicalQuery) {
stdx::unordered_set<std::string> fields;
QueryPlannerIXSelect::getFields(canonicalQuery->root(), &fields);
- const auto projectedFields =
- projection_executor_utils::applyProjectionToFields(projExec, fields);
+ const auto projectedFields = projection_executor_utils::applyProjectionToFields(
+ wildcardProjection->exec(), fields);
multikeyPathSet =
accessMethod->getMultikeyPathSet(opCtx, projectedFields, &mkAccessStats);
@@ -207,7 +208,7 @@ IndexEntry indexEntryFromIndexCatalogEntry(OperationContext* opCtx,
ice.getFilterExpression(),
desc->infoObj(),
ice.getCollator(),
- projExec};
+ wildcardProjection};
}
/**
@@ -1409,7 +1410,8 @@ QueryPlannerParams fillOutPlannerParamsForDistinct(OperationContext* opCtx,
} else if (desc->getIndexType() == IndexType::INDEX_WILDCARD && !query.isEmpty()) {
// Check whether the $** projection captures the field over which we are distinct-ing.
auto* proj = static_cast<const WildcardAccessMethod*>(ice->accessMethod())
- ->getProjectionExecutor();
+ ->getWildcardProjection()
+ ->exec();
if (projection_executor_utils::applyProjectionToOneField(proj,
parsedDistinct.getKey())) {
plannerParams.indices.push_back(
diff --git a/src/mongo/db/query/get_executor_test.cpp b/src/mongo/db/query/get_executor_test.cpp
index ec11139b37f..33f22f6ffed 100644
--- a/src/mongo/db/query/get_executor_test.cpp
+++ b/src/mongo/db/query/get_executor_test.cpp
@@ -39,6 +39,7 @@
#include "mongo/bson/simple_bsonobj_comparator.h"
#include "mongo/db/exec/projection_executor.h"
#include "mongo/db/exec/projection_executor_builder.h"
+#include "mongo/db/exec/wildcard_projection.h"
#include "mongo/db/json.h"
#include "mongo/db/pipeline/expression_context_for_test.h"
#include "mongo/db/query/projection_parser.h"
@@ -57,7 +58,7 @@ auto createProjectionExecutor(const BSONObj& spec, const ProjectionPolicies& pol
auto projection = projection_ast::parse(expCtx, spec, policies);
auto executor = projection_executor::buildProjectionExecutor(
expCtx, &projection, policies, projection_executor::kDefaultBuilderParams);
- return executor;
+ return WildcardProjection{std::move(executor)};
}
using std::unique_ptr;
@@ -150,7 +151,7 @@ IndexEntry buildSimpleIndexEntry(const BSONObj& kp, const std::string& indexName
* is neccesary for wildcard indicies.
*/
IndexEntry buildWildcardIndexEntry(const BSONObj& kp,
- projection_executor::ProjectionExecutor* projExec,
+ const WildcardProjection& wcProj,
const std::string& indexName) {
return {kp,
IndexNames::nameToType(IndexNames::findPluginName(kp)),
@@ -163,7 +164,7 @@ IndexEntry buildWildcardIndexEntry(const BSONObj& kp,
nullptr,
{},
nullptr,
- projExec};
+ &wcProj};
}
// Use of index filters to select compound index over single key index.
@@ -219,11 +220,11 @@ TEST(GetExecutorTest, GetAllowedIndicesMatchesMultipleIndexesByKey) {
}
TEST(GetExecutorTest, GetAllowedWildcardIndicesByKey) {
- auto projExec = createProjectionExecutor(
+ auto wcProj = createProjectionExecutor(
fromjson("{_id: 0}"),
{ProjectionPolicies::DefaultIdPolicy::kExcludeId,
ProjectionPolicies::ArrayRecursionPolicy::kDoNotRecurseNestedArrays});
- testAllowedIndices({buildWildcardIndexEntry(BSON("$**" << 1), projExec.get(), "$**_1"),
+ testAllowedIndices({buildWildcardIndexEntry(BSON("$**" << 1), wcProj, "$**_1"),
buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"),
buildSimpleIndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"),
buildSimpleIndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")},
@@ -233,11 +234,11 @@ TEST(GetExecutorTest, GetAllowedWildcardIndicesByKey) {
}
TEST(GetExecutorTest, GetAllowedWildcardIndicesByName) {
- auto projExec = createProjectionExecutor(
+ auto wcProj = createProjectionExecutor(
fromjson("{_id: 0}"),
{ProjectionPolicies::DefaultIdPolicy::kExcludeId,
ProjectionPolicies::ArrayRecursionPolicy::kDoNotRecurseNestedArrays});
- testAllowedIndices({buildWildcardIndexEntry(BSON("$**" << 1), projExec.get(), "$**_1"),
+ testAllowedIndices({buildWildcardIndexEntry(BSON("$**" << 1), wcProj, "$**_1"),
buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"),
buildSimpleIndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"),
buildSimpleIndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")},
@@ -247,11 +248,11 @@ TEST(GetExecutorTest, GetAllowedWildcardIndicesByName) {
}
TEST(GetExecutorTest, GetAllowedPathSpecifiedWildcardIndicesByKey) {
- auto projExec = createProjectionExecutor(
+ auto wcProj = createProjectionExecutor(
fromjson("{_id: 0}"),
{ProjectionPolicies::DefaultIdPolicy::kExcludeId,
ProjectionPolicies::ArrayRecursionPolicy::kDoNotRecurseNestedArrays});
- testAllowedIndices({buildWildcardIndexEntry(BSON("a.$**" << 1), projExec.get(), "a.$**_1"),
+ testAllowedIndices({buildWildcardIndexEntry(BSON("a.$**" << 1), wcProj, "a.$**_1"),
buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"),
buildSimpleIndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"),
buildSimpleIndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")},
@@ -261,11 +262,11 @@ TEST(GetExecutorTest, GetAllowedPathSpecifiedWildcardIndicesByKey) {
}
TEST(GetExecutorTest, GetAllowedPathSpecifiedWildcardIndicesByName) {
- auto projExec = createProjectionExecutor(
+ auto wcProj = createProjectionExecutor(
fromjson("{_id: 0}"),
{ProjectionPolicies::DefaultIdPolicy::kExcludeId,
ProjectionPolicies::ArrayRecursionPolicy::kDoNotRecurseNestedArrays});
- testAllowedIndices({buildWildcardIndexEntry(BSON("a.$**" << 1), projExec.get(), "a.$**_1"),
+ testAllowedIndices({buildWildcardIndexEntry(BSON("a.$**" << 1), wcProj, "a.$**_1"),
buildSimpleIndexEntry(fromjson("{a: 1}"), "a_1"),
buildSimpleIndexEntry(fromjson("{a: 1, b: 1}"), "a_1_b_1"),
buildSimpleIndexEntry(fromjson("{a: 1, c: 1}"), "a_1_c_1")},
diff --git a/src/mongo/db/query/index_entry.h b/src/mongo/db/query/index_entry.h
index d9eaf0ecdd7..487e8c6853d 100644
--- a/src/mongo/db/query/index_entry.h
+++ b/src/mongo/db/query/index_entry.h
@@ -42,9 +42,7 @@
namespace mongo {
class CollatorInterface;
class MatchExpression;
-namespace projection_executor {
-class ProjectionExecutor;
-}
+class WildcardProjection;
/**
* A CoreIndexInfo is a representation of an index in the catalog with parsed information which is
@@ -61,16 +59,16 @@ struct CoreIndexInfo {
Identifier ident,
const MatchExpression* fe = nullptr,
const CollatorInterface* ci = nullptr,
- projection_executor::ProjectionExecutor* projExec = nullptr)
+ const WildcardProjection* wildcardProj = nullptr)
: identifier(std::move(ident)),
keyPattern(kp),
filterExpr(fe),
type(type),
sparse(sp),
collator(ci),
- wildcardProjection(projExec) {
+ wildcardProjection(wildcardProj) {
// We always expect a projection executor for $** indexes, and none otherwise.
- invariant((type == IndexType::INDEX_WILDCARD) == (projExec != nullptr));
+ invariant((type == IndexType::INDEX_WILDCARD) == (wildcardProjection != nullptr));
}
virtual ~CoreIndexInfo() = default;
@@ -138,7 +136,7 @@ struct CoreIndexInfo {
// For $** indexes, a pointer to the projection executor owned by the index access method. Null
// unless this IndexEntry represents a wildcard index, in which case this is always non-null.
- projection_executor::ProjectionExecutor* wildcardProjection = nullptr;
+ const WildcardProjection* wildcardProjection = nullptr;
};
/**
@@ -160,8 +158,8 @@ struct IndexEntry : CoreIndexInfo {
const MatchExpression* fe,
const BSONObj& io,
const CollatorInterface* ci,
- projection_executor::ProjectionExecutor* projExec)
- : CoreIndexInfo(kp, type, sp, std::move(ident), fe, ci, projExec),
+ const WildcardProjection* wildcardProjection)
+ : CoreIndexInfo(kp, type, sp, std::move(ident), fe, ci, wildcardProjection),
multikey(mk),
multikeyPaths(mkp),
multikeyPathSet(std::move(multikeyPathSet)),
diff --git a/src/mongo/db/query/plan_cache_indexability.cpp b/src/mongo/db/query/plan_cache_indexability.cpp
index 96f7697e06c..4846cd85778 100644
--- a/src/mongo/db/query/plan_cache_indexability.cpp
+++ b/src/mongo/db/query/plan_cache_indexability.cpp
@@ -119,7 +119,7 @@ void PlanCacheIndexabilityState::processWildcardIndex(const CoreIndexInfo& cii)
invariant(cii.type == IndexType::INDEX_WILDCARD);
_wildcardIndexDiscriminators.emplace_back(
- cii.wildcardProjection, cii.identifier.catalogName, cii.filterExpr, cii.collator);
+ cii.wildcardProjection->exec(), cii.identifier.catalogName, cii.filterExpr, cii.collator);
}
void PlanCacheIndexabilityState::processIndexCollation(const std::string& indexName,
diff --git a/src/mongo/db/query/plan_cache_indexability_test.cpp b/src/mongo/db/query/plan_cache_indexability_test.cpp
index eb2978ef6db..471e57bfafb 100644
--- a/src/mongo/db/query/plan_cache_indexability_test.cpp
+++ b/src/mongo/db/query/plan_cache_indexability_test.cpp
@@ -58,7 +58,8 @@ std::unique_ptr<MatchExpression> parseMatchExpression(const BSONObj& obj,
// maintained by the $** index's IndexAccessMethod, and is required because the plan cache will
// obtain unowned pointers to it.
auto makeWildcardEntry(BSONObj keyPattern, const MatchExpression* filterExpr = nullptr) {
- auto projExec = WildcardKeyGenerator::createProjectionExecutor(keyPattern, {});
+ auto projExec = std::make_unique<WildcardProjection>(
+ WildcardKeyGenerator::createProjectionExecutor(keyPattern, {}));
return std::make_pair(IndexEntry(keyPattern,
IndexNames::nameToType(IndexNames::findPluginName(keyPattern)),
false, // multikey
diff --git a/src/mongo/db/query/plan_cache_test.cpp b/src/mongo/db/query/plan_cache_test.cpp
index ce580870ca9..30c52b82e39 100644
--- a/src/mongo/db/query/plan_cache_test.cpp
+++ b/src/mongo/db/query/plan_cache_test.cpp
@@ -243,9 +243,9 @@ void assertEquivalent(const char* queryStr,
// The latter simulates the ProjectionExecutor which, during normal operation, is owned and
// maintained by the $** index's IndexAccessMethod, and is required because the plan cache will
// obtain unowned pointers to it.
-std::pair<IndexEntry, std::unique_ptr<projection_executor::ProjectionExecutor>> makeWildcardEntry(
- BSONObj keyPattern) {
- auto projExec = WildcardKeyGenerator::createProjectionExecutor(keyPattern, {});
+std::pair<IndexEntry, std::unique_ptr<WildcardProjection>> makeWildcardEntry(BSONObj keyPattern) {
+ auto wcProj = std::make_unique<WildcardProjection>(
+ WildcardKeyGenerator::createProjectionExecutor(keyPattern, {}));
return {IndexEntry(keyPattern,
IndexNames::nameToType(IndexNames::findPluginName(keyPattern)),
false, // multikey
@@ -257,22 +257,23 @@ std::pair<IndexEntry, std::unique_ptr<projection_executor::ProjectionExecutor>>
nullptr,
BSONObj(),
nullptr,
- projExec.get()),
- std::move(projExec)};
+ wcProj.get()),
+ std::move(wcProj)};
}
// A version of the above for CoreIndexInfo, used for plan cache update tests.
-std::pair<CoreIndexInfo, std::unique_ptr<projection_executor::ProjectionExecutor>>
-makeWildcardUpdate(BSONObj keyPattern) {
- auto projExec = WildcardKeyGenerator::createProjectionExecutor(keyPattern, {});
+std::pair<CoreIndexInfo, std::unique_ptr<WildcardProjection>> makeWildcardUpdate(
+ BSONObj keyPattern) {
+ auto wcProj = std::make_unique<WildcardProjection>(
+ WildcardKeyGenerator::createProjectionExecutor(keyPattern, {}));
return {CoreIndexInfo(keyPattern,
IndexNames::nameToType(IndexNames::findPluginName(keyPattern)),
false, // sparse
IndexEntry::Identifier{"indexName"}, // name
nullptr, // filterExpr
nullptr, // collation
- projExec.get()), // wildcard
- std::move(projExec)};
+ wcProj.get()), // wildcard
+ std::move(wcProj)};
}
//
diff --git a/src/mongo/db/query/planner_ixselect_test.cpp b/src/mongo/db/query/planner_ixselect_test.cpp
index 406104b96b0..84ba3f704d0 100644
--- a/src/mongo/db/query/planner_ixselect_test.cpp
+++ b/src/mongo/db/query/planner_ixselect_test.cpp
@@ -1057,10 +1057,11 @@ auto makeIndexEntry(BSONObj keyPattern,
MultikeyPaths multiKeyPaths,
std::set<FieldRef> multiKeyPathSet = {},
BSONObj infoObj = BSONObj()) {
- auto projExec = (keyPattern.firstElement().fieldNameStringData().endsWith("$**"_sd)
- ? WildcardKeyGenerator::createProjectionExecutor(
- keyPattern, infoObj.getObjectField("wildcardProjection"))
- : nullptr);
+
+ auto wcProj = keyPattern.firstElement().fieldNameStringData().endsWith("$**"_sd)
+ ? std::make_unique<WildcardProjection>(WildcardKeyGenerator::createProjectionExecutor(
+ keyPattern, infoObj.getObjectField("wildcardProjection")))
+ : std::unique_ptr<WildcardProjection>(nullptr);
auto multiKey = !multiKeyPathSet.empty() ||
std::any_of(multiKeyPaths.cbegin(), multiKeyPaths.cend(), [](const auto& entry) {
@@ -1077,8 +1078,8 @@ auto makeIndexEntry(BSONObj keyPattern,
nullptr,
{},
nullptr,
- projExec.get()),
- std::move(projExec));
+ wcProj.get()),
+ std::move(wcProj));
}
TEST(QueryPlannerIXSelectTest, InternalExprEqCannotUseMultiKeyIndex) {
diff --git a/src/mongo/db/query/planner_wildcard_helpers.cpp b/src/mongo/db/query/planner_wildcard_helpers.cpp
index edf768c75a3..9681a69cd92 100644
--- a/src/mongo/db/query/planner_wildcard_helpers.cpp
+++ b/src/mongo/db/query/planner_wildcard_helpers.cpp
@@ -356,12 +356,14 @@ void expandWildcardIndexEntry(const IndexEntry& wildcardIndex,
invariant(wildcardIndex.multikeyPaths.empty());
// Obtain the projection executor from the parent wildcard IndexEntry.
- auto projExec = wildcardIndex.wildcardProjection;
- invariant(projExec);
+ auto* wildcardProjection = wildcardIndex.wildcardProjection;
+ invariant(wildcardProjection);
const auto projectedFields =
- projection_executor_utils::applyProjectionToFields(projExec, fields);
- const auto& includedPaths = projection_executor_utils::extractExhaustivePaths(projExec);
+ projection_executor_utils::applyProjectionToFields(wildcardProjection->exec(), fields);
+
+ std::set<FieldRef> includedPaths =
+ wildcardProjection->exhaustivePaths().value_or(std::set<FieldRef>{});
out->reserve(out->size() + projectedFields.size());
for (auto&& fieldName : projectedFields) {
// Convert string 'fieldName' into a FieldRef, to better facilitate the subsequent checks.
diff --git a/src/mongo/db/query/query_planner_wildcard_index_test.cpp b/src/mongo/db/query/query_planner_wildcard_index_test.cpp
index 58a217c941e..dde97c3c187 100644
--- a/src/mongo/db/query/query_planner_wildcard_index_test.cpp
+++ b/src/mongo/db/query/query_planner_wildcard_index_test.cpp
@@ -71,7 +71,7 @@ protected:
const bool isMultikey = !multikeyPathSet.empty();
BSONObj infoObj = BSON("wildcardProjection" << wildcardProjection);
- _projExec = WildcardKeyGenerator::createProjectionExecutor(keyPattern, wildcardProjection);
+ _proj = WildcardKeyGenerator::createProjectionExecutor(keyPattern, wildcardProjection);
params.indices.push_back({std::move(keyPattern),
IndexType::INDEX_WILDCARD,
@@ -84,10 +84,10 @@ protected:
partialFilterExpr,
std::move(infoObj),
collator,
- _projExec.get()});
+ _proj.get_ptr()});
}
- std::unique_ptr<projection_executor::ProjectionExecutor> _projExec;
+ boost::optional<WildcardProjection> _proj;
};
//