diff options
author | James Wahlin <james@mongodb.com> | 2018-10-01 16:05:08 -0400 |
---|---|---|
committer | James Wahlin <james@mongodb.com> | 2018-10-02 09:56:37 -0400 |
commit | f7ddb89c8caf438781de9191d690d03f711b63fe (patch) | |
tree | 9244266869d8c17de23d5e0c817a2fddc2bc849a | |
parent | 5a6ee566f608c46654133de17a4e8bb3464d680d (diff) | |
download | mongo-f7ddb89c8caf438781de9191d690d03f711b63fe.tar.gz |
SERVER-37188 Rename "All Paths" index to "Wildcard" index
52 files changed, 673 insertions, 680 deletions
diff --git a/etc/perf.yml b/etc/perf.yml index 347521f33e2..9c31a142703 100644 --- a/etc/perf.yml +++ b/etc/perf.yml @@ -454,7 +454,7 @@ buildvariants: mongod_exec_wrapper: &exec_wrapper "numactl --physcpubind=4,5,6,7 -i 1" perf_exec_wrapper: &perf_wrapper "numactl --physcpubind=1,2,3 -i 0" # TODO SERVER-36198: Remove the `--setParameter internalQueryAllowAllPathsIndexes=true` line - # when all paths indexes are enabled by default. + # when wildcard indexes are enabled by default. mongod_flags: >- --auth --fork @@ -495,7 +495,7 @@ buildvariants: mongod_exec_wrapper: *exec_wrapper perf_exec_wrapper: *perf_wrapper # TODO SERVER-36198: Remove the `--setParameter internalQueryAllowAllPathsIndexes=true` line - # when all paths indexes are enabled by default. + # when wildcard indexes are enabled by default. mongod_flags: >- --auth --fork diff --git a/jstests/noPassthroughWithMongod/all_paths_and_text_indexes.js b/jstests/noPassthroughWithMongod/wildcard_and_text_indexes.js index 21f6a149aa9..58677209ddf 100644 --- a/jstests/noPassthroughWithMongod/all_paths_and_text_indexes.js +++ b/jstests/noPassthroughWithMongod/wildcard_and_text_indexes.js @@ -17,13 +17,13 @@ const assertArrayEq = (l, r) => assert(arrayEq(l, r), tojson(l) + " != " + tojson(r)); - const coll = db.all_paths_and_text_indexes; + const coll = db.wildcard_and_text_indexes; coll.drop(); - // Runs a single allPaths query test, confirming that an indexed solution exists, that the $** + // Runs a single wildcard query test, confirming that an indexed solution exists, that the $** // index on the given 'expectedPath' was used to answer the query, and that the results are // identical to those obtained via COLLSCAN. - function assertAllPathsQuery(query, expectedPath) { + function assertWildcardQuery(query, expectedPath) { // Explain the query, and determine whether an indexed solution is available. const explainOutput = coll.find(query).explain("executionStats"); const ixScans = getPlanStages(explainOutput.queryPlanner.winningPlan, "IXSCAN"); @@ -43,9 +43,9 @@ assert.commandWorked( db.adminCommand({setParameter: 1, internalQueryAllowAllPathsIndexes: true})); try { - // Build an allPaths index, and verify that it can be used to query for the field '_fts'. + // Build a wildcard index, and verify that it can be used to query for the field '_fts'. assert.commandWorked(coll.createIndex({"$**": 1})); - assertAllPathsQuery({_fts: {$gt: 0, $lt: 4}}, '_fts'); + assertWildcardQuery({_fts: {$gt: 0, $lt: 4}}, '_fts'); // Perform the tests below for simple and compound $text indexes. for (let textIndex of[{'$**': 'text'}, {a: 1, '$**': 'text'}]) { @@ -54,7 +54,7 @@ // Confirm that the $** index can still be used to query for the '_fts' field outside of // a $text query. - assertAllPathsQuery({_fts: {$gt: 0, $lt: 4}}, '_fts'); + assertWildcardQuery({_fts: {$gt: 0, $lt: 4}}, '_fts'); // Confirm that $** does not generate a candidate plan for $text search, including cases // when the query filter contains a compound field in the $text index. @@ -80,13 +80,13 @@ assert.eq(explainOut.queryPlanner.rejectedPlans.length, 0); assert.eq(explainOut.executionStats.nReturned, 3); - const textOrAllPaths = getPlanStages(explainOut.queryPlanner.winningPlan, "OR").shift(); - assert.eq(textOrAllPaths.inputStages.length, 2); - const textBranch = (textOrAllPaths.inputStages[0].stage === "TEXT" ? 0 : 1); - const allPathsBranch = (textBranch + 1) % 2; - assert.eq(textOrAllPaths.inputStages[textBranch].stage, "TEXT"); - assert.eq(textOrAllPaths.inputStages[allPathsBranch].stage, "IXSCAN"); - assert.eq(textOrAllPaths.inputStages[allPathsBranch].keyPattern, {$_path: 1, _fts: 1}); + const textOrWildcard = getPlanStages(explainOut.queryPlanner.winningPlan, "OR").shift(); + assert.eq(textOrWildcard.inputStages.length, 2); + const textBranch = (textOrWildcard.inputStages[0].stage === "TEXT" ? 0 : 1); + const wildcardBranch = (textBranch + 1) % 2; + assert.eq(textOrWildcard.inputStages[textBranch].stage, "TEXT"); + assert.eq(textOrWildcard.inputStages[wildcardBranch].stage, "IXSCAN"); + assert.eq(textOrWildcard.inputStages[wildcardBranch].keyPattern, {$_path: 1, _fts: 1}); // Drop the index so that a different text index can be created. assert.commandWorked(coll.dropIndex("textIndex")); diff --git a/jstests/noPassthroughWithMongod/all_paths_basic_index_bounds.js b/jstests/noPassthroughWithMongod/wildcard_index_basic_index_bounds.js index 9eef97a7da4..54fdcdfba58 100644 --- a/jstests/noPassthroughWithMongod/all_paths_basic_index_bounds.js +++ b/jstests/noPassthroughWithMongod/wildcard_index_basic_index_bounds.js @@ -17,7 +17,7 @@ const assertArrayEq = (l, r) => assert(arrayEq(l, r)); - const coll = db.all_paths_index_bounds; + const coll = db.wildcard_index_bounds; coll.drop(); // Template document which defines the 'schema' of the documents in the test collection. @@ -82,7 +82,7 @@ // been indexed based on the spec; this function will confirm that only the appropriate paths // are present in the $** index. Finally, for each match expression it will perform a rooted-$or // with one predicate on each expected path, and a rooted $and over all predicates and paths. - function runAllPathsIndexTest(keyPattern, pathProjection, expectedPaths) { + function runWildcardIndexTest(keyPattern, pathProjection, expectedPaths) { assert.commandWorked(coll.dropIndexes()); assert.commandWorked(coll.createIndex( keyPattern, pathProjection ? {wildcardProjection: pathProjection} : {})); @@ -202,24 +202,24 @@ try { // Test a $** index that indexes the entire document. - runAllPathsIndexTest({'$**': 1}, null, ['a', 'b.c', 'b.d.e', 'b.f']); + runWildcardIndexTest({'$**': 1}, null, ['a', 'b.c', 'b.d.e', 'b.f']); // Test a $** index on a single subtree. - runAllPathsIndexTest({'a.$**': 1}, null, ['a']); - runAllPathsIndexTest({'b.$**': 1}, null, ['b.c', 'b.d.e', 'b.f']); - runAllPathsIndexTest({'b.d.$**': 1}, null, ['b.d.e']); + runWildcardIndexTest({'a.$**': 1}, null, ['a']); + runWildcardIndexTest({'b.$**': 1}, null, ['b.c', 'b.d.e', 'b.f']); + runWildcardIndexTest({'b.d.$**': 1}, null, ['b.d.e']); // Test a $** index which includes a subset of paths. - runAllPathsIndexTest({'$**': 1}, {a: 1}, ['a']); - runAllPathsIndexTest({'$**': 1}, {b: 1}, ['b.c', 'b.d.e', 'b.f']); - runAllPathsIndexTest({'$**': 1}, {'b.d': 1}, ['b.d.e']); - runAllPathsIndexTest({'$**': 1}, {a: 1, 'b.d': 1}, ['a', 'b.d.e']); + runWildcardIndexTest({'$**': 1}, {a: 1}, ['a']); + runWildcardIndexTest({'$**': 1}, {b: 1}, ['b.c', 'b.d.e', 'b.f']); + runWildcardIndexTest({'$**': 1}, {'b.d': 1}, ['b.d.e']); + runWildcardIndexTest({'$**': 1}, {a: 1, 'b.d': 1}, ['a', 'b.d.e']); // Test a $** index which excludes a subset of paths. - runAllPathsIndexTest({'$**': 1}, {a: 0}, ['b.c', 'b.d.e', 'b.f']); - runAllPathsIndexTest({'$**': 1}, {b: 0}, ['a']); - runAllPathsIndexTest({'$**': 1}, {'b.d': 0}, ['a', 'b.c', 'b.f']); - runAllPathsIndexTest({'$**': 1}, {a: 0, 'b.d': 0}, ['b.c', 'b.f']); + runWildcardIndexTest({'$**': 1}, {a: 0}, ['b.c', 'b.d.e', 'b.f']); + runWildcardIndexTest({'$**': 1}, {b: 0}, ['a']); + runWildcardIndexTest({'$**': 1}, {'b.d': 0}, ['a', 'b.c', 'b.f']); + runWildcardIndexTest({'$**': 1}, {a: 0, 'b.d': 0}, ['b.c', 'b.f']); } finally { // Disable $** indexes once the tests have either completed or failed. assert.commandWorked( diff --git a/jstests/noPassthroughWithMongod/all_paths_cached_plans.js b/jstests/noPassthroughWithMongod/wildcard_index_cached_plans.js index bd54cba889f..dea4b0733d1 100644 --- a/jstests/noPassthroughWithMongod/all_paths_cached_plans.js +++ b/jstests/noPassthroughWithMongod/wildcard_index_cached_plans.js @@ -1,5 +1,5 @@ /** - * Test that cached plans which use allPaths indexes work. + * Test that cached plans which use wildcard indexes work. * TODO: SERVER-36198: Move this test back to jstests/core/ */ (function() { @@ -10,7 +10,7 @@ assert.commandWorked( db.adminCommand({setParameter: 1, internalQueryAllowAllPathsIndexes: true})); - const coll = db.all_paths_cached_plans; + const coll = db.wildcard_cached_plans; coll.drop(); assert.commandWorked(coll.createIndex({"b.$**": 1})); assert.commandWorked(coll.createIndex({"a": 1})); @@ -83,7 +83,7 @@ // Check that indexability discriminators work with collations. (function() { - // Create allPaths index with a collation. + // Create wildcard index with a collation. assert.eq(coll.drop(), true); assert.commandWorked( db.createCollection(coll.getName(), {collation: {locale: "en_US", strength: 1}})); @@ -110,7 +110,7 @@ queryWithStringExplain.queryPlanner.queryHash); })(); - // Check that indexability discriminators work with partial allPaths indexes. + // Check that indexability discriminators work with partial wildcard indexes. (function() { assert.eq(coll.drop(), true); assert.commandWorked(db.createCollection(coll.getName())); diff --git a/jstests/noPassthroughWithMongod/all_paths_collation.js b/jstests/noPassthroughWithMongod/wildcard_index_collation.js index d0fc07d3d97..92addd75de6 100644 --- a/jstests/noPassthroughWithMongod/all_paths_collation.js +++ b/jstests/noPassthroughWithMongod/wildcard_index_collation.js @@ -13,7 +13,7 @@ const assertArrayEq = (l, r) => assert(arrayEq(l, r)); - const coll = db.all_paths_collation; + const coll = db.wildcard_collation; coll.drop(); // Extracts the winning plan for the given query and projection from the explain output. @@ -22,7 +22,7 @@ // Runs the given query and confirms that: (1) the $** was used to answer the query, (2) the // results produced by the $** index match the given 'expectedResults', and (3) the same output // is produced by a COLLSCAN with the same collation. - function assertAllPathsIndexAnswersQuery(query, expectedResults, projection) { + function assertWildcardIndexAnswersQuery(query, expectedResults, projection) { // Verify that the $** index can answer this query. const ixScans = getPlanStages(winningPlan(query, (projection || {_id: 0})), "IXSCAN"); assert.gt(ixScans.length, 0, tojson(coll.find(query).explain())); @@ -30,9 +30,9 @@ // Assert that the $** index produces the expected results, and that these are the same // as those produced by a COLLSCAN with the same collation. - const allPathsResults = coll.find(query, (projection || {_id: 0})).toArray(); - assertArrayEq(allPathsResults, expectedResults); - assertArrayEq(allPathsResults, + const wildcardResults = coll.find(query, (projection || {_id: 0})).toArray(); + assertArrayEq(wildcardResults, expectedResults); + assertArrayEq(wildcardResults, coll.find(query, (projection || {_id: 0})) .collation({locale: "en_US", strength: 1}) .hint({$natural: 1}) @@ -82,11 +82,11 @@ // Confirm that only the document's values adhere to the case-insensitive collation. The // field paths, which are also present in the $** index keys, are evaluated using simple // binary comparison; so for instance, path "a.b" does *not* match path "A.B". - assertAllPathsIndexAnswersQuery({"a.b": "string"}, [ + assertWildcardIndexAnswersQuery({"a.b": "string"}, [ {a: {b: "string", c: "STRING"}, d: "sTrInG", e: 5}, {a: {b: "STRING", c: "string"}, d: "StRiNg", e: 5} ]); - assertAllPathsIndexAnswersQuery({"A.B": "string"}, [ + assertWildcardIndexAnswersQuery({"A.B": "string"}, [ {A: {B: "string", C: "STRING"}, d: "sTrInG", E: 5}, {A: {B: "STRING", C: "string"}, d: "StRiNg", E: 5} ]); @@ -94,16 +94,16 @@ // All documents in the collection are returned if we query over both upper- and lower-case // fieldnames, or when the fieldname has a consistent case across all documents. const allDocs = coll.find({}, {_id: 0}).toArray(); - assertAllPathsIndexAnswersQuery({$or: [{"a.c": "string"}, {"A.C": "string"}]}, allDocs); - assertAllPathsIndexAnswersQuery({d: "string"}, allDocs); + assertWildcardIndexAnswersQuery({$or: [{"a.c": "string"}, {"A.C": "string"}]}, allDocs); + assertWildcardIndexAnswersQuery({d: "string"}, allDocs); // Confirm that the $** index also differentiates between upper and lower fieldname case // when querying fields which do not contain string values. - assertAllPathsIndexAnswersQuery({e: 5}, [ + assertWildcardIndexAnswersQuery({e: 5}, [ {a: {b: "string", c: "STRING"}, d: "sTrInG", e: 5}, {a: {b: "STRING", c: "string"}, d: "StRiNg", e: 5} ]); - assertAllPathsIndexAnswersQuery({E: 5}, [ + assertWildcardIndexAnswersQuery({E: 5}, [ {A: {B: "string", C: "STRING"}, d: "sTrInG", E: 5}, {A: {B: "STRING", C: "string"}, d: "StRiNg", E: 5} ]); @@ -120,7 +120,7 @@ // Confirm that attempting to project the virtual $_path field which is present in $** index // keys produces a non-covered solution, which nonetheless returns the correct results. assert(!isIndexOnly(coll.getDB(), winningPlan({e: 5}, {_id: 0, e: 1, $_path: 1}))); - assertAllPathsIndexAnswersQuery({e: 5}, [{e: 5}, {e: 5}], {_id: 0, e: 1, $_path: 1}); + assertWildcardIndexAnswersQuery({e: 5}, [{e: 5}, {e: 5}], {_id: 0, e: 1, $_path: 1}); } finally { // Disable $** indexes once the tests have either completed or failed. db.adminCommand({setParameter: 1, internalQueryAllowAllPathsIndexes: false}); diff --git a/jstests/noPassthroughWithMongod/all_paths_covered_queries.js b/jstests/noPassthroughWithMongod/wildcard_index_covered_queries.js index 1855ab33fdb..ecb182d45af 100644 --- a/jstests/noPassthroughWithMongod/all_paths_covered_queries.js +++ b/jstests/noPassthroughWithMongod/wildcard_index_covered_queries.js @@ -16,14 +16,14 @@ const assertArrayEq = (l, r) => assert(arrayEq(l, r)); - const coll = db.all_paths_covered_query; + const coll = db.wildcard_covered_query; coll.drop(); // Confirms that the $** index can answer the given query and projection, that it produces a // covered solution, and that the results are identical to those obtained by a COLLSCAN. If // 'shouldFailToCover' is true, inverts the assertion and confirms that the given query and // projection do *not* produce a covered plan. - function assertAllPathsProvidesCoveredSolution(query, proj, shouldFailToCover = false) { + function assertWildcardProvidesCoveredSolution(query, proj, shouldFailToCover = false) { // Obtain the explain output for the given query and projection. We run the explain with // 'executionStats' so that we can subsequently validate the number of documents examined. const explainOut = assert.commandWorked(coll.find(query, proj).explain("executionStats")); @@ -58,34 +58,34 @@ assert.commandWorked(coll.createIndex({"$**": 1})); // Verify that the $** index can cover an exact match on an integer value. - assertAllPathsProvidesCoveredSolution({"a.b": 10}, {_id: 0, "a.b": 1}); + assertWildcardProvidesCoveredSolution({"a.b": 10}, {_id: 0, "a.b": 1}); // Verify that the $** index can cover an exact match on a string value. - assertAllPathsProvidesCoveredSolution({"a.c": "10"}, {_id: 0, "a.c": 1}); + assertWildcardProvidesCoveredSolution({"a.c": "10"}, {_id: 0, "a.c": 1}); // Verify that the $** index can cover a range query for integer values. - assertAllPathsProvidesCoveredSolution({"a.b": {$gt: 10, $lt: 99}}, {_id: 0, "a.b": 1}); + assertWildcardProvidesCoveredSolution({"a.b": {$gt: 10, $lt: 99}}, {_id: 0, "a.b": 1}); // Verify that the $** index can cover a range query for string values. - assertAllPathsProvidesCoveredSolution({"a.c": {$gt: "10", $lt: "99"}}, {_id: 0, "a.c": 1}); + assertWildcardProvidesCoveredSolution({"a.c": {$gt: "10", $lt: "99"}}, {_id: 0, "a.c": 1}); // Verify that the $** index can cover an $in query for integer values. - assertAllPathsProvidesCoveredSolution({"a.b": {$in: [0, 50, 100, 150]}}, + assertWildcardProvidesCoveredSolution({"a.b": {$in: [0, 50, 100, 150]}}, {_id: 0, "a.b": 1}); // Verify that the $** index can cover an $in query for string values. - assertAllPathsProvidesCoveredSolution({"a.c": {$in: ["0", "50", "100", "150"]}}, + assertWildcardProvidesCoveredSolution({"a.c": {$in: ["0", "50", "100", "150"]}}, {_id: 0, "a.c": 1}); // Verify that attempting to project the virtual $_path field from the $** keyPattern will // fail to do so and will instead produce a non-covered query. However, this query will // nonetheless output the correct results. const shouldFailToCover = true; - assertAllPathsProvidesCoveredSolution( + assertWildcardProvidesCoveredSolution( {d: {$in: [0, 25, 50, 75, 100]}}, {_id: 0, d: 1, $_path: 1}, shouldFailToCover); // Verify that predicates which produce inexact-fetch bounds are not covered by a $** index. - assertAllPathsProvidesCoveredSolution( + assertWildcardProvidesCoveredSolution( {d: {$elemMatch: {$eq: 50}}}, {_id: 0, d: 1}, shouldFailToCover); } finally { // Disable $** indexes once the tests have either completed or failed. diff --git a/jstests/noPassthroughWithMongod/all_paths_hint.js b/jstests/noPassthroughWithMongod/wildcard_index_hint.js index 052848c636e..f4a8d8fb878 100644 --- a/jstests/noPassthroughWithMongod/all_paths_hint.js +++ b/jstests/noPassthroughWithMongod/wildcard_index_hint.js @@ -8,7 +8,7 @@ load("jstests/aggregation/extras/utils.js"); // For arrayEq. load("jstests/libs/analyze_plan.js"); // For getPlanStages. - const coll = db.all_paths_hint; + const coll = db.wildcard_hint; coll.drop(); const assertArrayEq = (l, r) => assert(arrayEq(l, r), tojson(l) + " != " + tojson(r)); @@ -26,8 +26,8 @@ assert.gt(ixScans.length, 0, tojson(coll.find(query).hint(hint).explain())); ixScans.forEach((ixScan) => assert.eq(ixScan.indexName, expectedIndexName)); - const allPathsResults = coll.find(query, {_id: 0}).hint(hint).toArray(); - assertArrayEq(allPathsResults, expectedResults); + const wildcardResults = coll.find(query, {_id: 0}).hint(hint).toArray(); + assertArrayEq(wildcardResults, expectedResults); } assert.commandWorked( @@ -83,7 +83,7 @@ "$**_1", [{a: 1, b: 1, c: {d: 1, e: 1}}, {a: 2, b: 2, c: {d: 1, e: 2}}]); - // Adding another all paths index with a path specified. + // Adding another wildcard index with a path specified. assert.commandWorked(coll.createIndex({"c.$**": 1})); // Hint on path that is not in query argument. @@ -117,8 +117,5 @@ } finally { // Disable $** indexes once the tests have either completed or failed. db.adminCommand({setParameter: 1, internalQueryAllowAllPathsIndexes: false}); - - // TODO: SERVER-36444 remove calls to drop() once wildcard index validation works. - coll.drop(); } })();
\ No newline at end of file diff --git a/jstests/noPassthroughWithMongod/all_paths_index_multikey.js b/jstests/noPassthroughWithMongod/wildcard_index_multikey.js index 375bc704ef4..7c5e7c93fea 100644 --- a/jstests/noPassthroughWithMongod/all_paths_index_multikey.js +++ b/jstests/noPassthroughWithMongod/wildcard_index_multikey.js @@ -11,7 +11,7 @@ const assertArrayEq = (l, r) => assert(arrayEq(l, r), tojson(l) + " != " + tojson(r)); - const coll = db.all_paths_multikey_index; + const coll = db.wildcard_multikey_index; coll.drop(); // Template document which defines the 'schema' of the documents in the test collection. @@ -60,7 +60,7 @@ // field in turn. The 'expectedPaths' argument lists the set of paths which we expect to have // been indexed based on the spec; this function will confirm that only the appropriate paths // are present in the $** index. - function runAllPathsIndexTest(keyPattern, pathProjection, expectedPaths) { + function runWildcardIndexTest(keyPattern, pathProjection, expectedPaths) { assert.commandWorked(coll.dropIndexes()); assert.commandWorked(coll.createIndex( keyPattern, pathProjection ? {wildcardProjection: pathProjection} : {})); @@ -69,16 +69,16 @@ for (let op of operationList) { for (let path of pathList) { const query = {[path]: op.expression}; - assertAllPathsQuery(query, expectedPaths.includes(path) ? path : null); + assertWildcardQuery(query, expectedPaths.includes(path) ? path : null); } } } - // Runs a single allPaths query test. If 'expectedPath' is non-null, verifies that there is an + // Runs a single wildcard query test. If 'expectedPath' is non-null, verifies that there is an // indexed solution that uses the $** index with the given path string. If 'expectedPath' is // null, verifies that no indexed solution was found. If 'explainStats' is non-empty, verifies // that the query's explain output reflects the given stats. - function assertAllPathsQuery(query, expectedPath, explainStats = {}) { + function assertWildcardQuery(query, expectedPath, explainStats = {}) { // Explain the query, and determine whether an indexed solution is available. const explainOutput = coll.find(query).explain("executionStats"); const ixScans = getPlanStages(explainOutput.queryPlanner.winningPlan, "IXSCAN"); @@ -106,22 +106,22 @@ db.adminCommand({setParameter: 1, internalQueryAllowAllPathsIndexes: true})); try { // Test a $** index that indexes the entire document. - runAllPathsIndexTest({'$**': 1}, null, ['a', 'b.c', 'b.d.e']); + runWildcardIndexTest({'$**': 1}, null, ['a', 'b.c', 'b.d.e']); // Test a $** index on a single subtree. - runAllPathsIndexTest({'a.$**': 1}, null, ['a']); - runAllPathsIndexTest({'b.$**': 1}, null, ['b.c', 'b.d.e']); - runAllPathsIndexTest({'b.c.$**': 1}, null, ['b.c']); - runAllPathsIndexTest({'b.d.$**': 1}, null, ['b.d.e']); + runWildcardIndexTest({'a.$**': 1}, null, ['a']); + runWildcardIndexTest({'b.$**': 1}, null, ['b.c', 'b.d.e']); + runWildcardIndexTest({'b.c.$**': 1}, null, ['b.c']); + runWildcardIndexTest({'b.d.$**': 1}, null, ['b.d.e']); // Test a $** index which includes a subset of paths. - runAllPathsIndexTest({'$**': 1}, {a: 1}, ['a']); - runAllPathsIndexTest({'$**': 1}, {b: 1}, ['b.c', 'b.d.e']); - runAllPathsIndexTest({'$**': 1}, {'b.d': 1}, ['b.d.e']); - runAllPathsIndexTest({'$**': 1}, {a: 1, 'b.d': 1}, ['a', 'b.d.e']); + runWildcardIndexTest({'$**': 1}, {a: 1}, ['a']); + runWildcardIndexTest({'$**': 1}, {b: 1}, ['b.c', 'b.d.e']); + runWildcardIndexTest({'$**': 1}, {'b.d': 1}, ['b.d.e']); + runWildcardIndexTest({'$**': 1}, {a: 1, 'b.d': 1}, ['a', 'b.d.e']); // Test a $** index which excludes a subset of paths. - runAllPathsIndexTest({'$**': 1}, {a: 0}, ['b.c', 'b.d.e']); - runAllPathsIndexTest({'$**': 1}, {b: 0}, ['a']); - runAllPathsIndexTest({'$**': 1}, {'b.c': 0}, ['a', 'b.d.e']); - runAllPathsIndexTest({'$**': 1}, {a: 0, 'b.c': 0}, ['b.d.e']); + runWildcardIndexTest({'$**': 1}, {a: 0}, ['b.c', 'b.d.e']); + runWildcardIndexTest({'$**': 1}, {b: 0}, ['a']); + runWildcardIndexTest({'$**': 1}, {'b.c': 0}, ['a', 'b.d.e']); + runWildcardIndexTest({'$**': 1}, {a: 0, 'b.c': 0}, ['b.d.e']); // Sanity check that a few queries which need to be planned specially in the multikey case // return the correct results. @@ -186,17 +186,17 @@ // // We examine the solution's 'nReturned' versus 'totalDocsExamined' to confirm this. // totalDocsExamined: [_id:1, _id:2, _id:3, _id:4], nReturned: [_id:2, _id:3, _id:4] - assertAllPathsQuery({'a.0.b.1.c': 1}, + assertWildcardQuery({'a.0.b.1.c': 1}, 'a.0.b.1.c', {'executionStats.nReturned': 3, 'executionStats.totalDocsExamined': 4}); // Test that we can query a specific field of an array whose fieldname is itself numeric. - assertAllPathsQuery({'a.0.1.d': 1}, + assertWildcardQuery({'a.0.1.d': 1}, 'a.0.1.d', {'executionStats.nReturned': 1, 'executionStats.totalDocsExamined': 1}); // Test that we can query a primitive value at a specific array index. - assertAllPathsQuery({'a.0.b.1.c.2.d.3': 3}, + assertWildcardQuery({'a.0.b.1.c.2.d.3': 3}, 'a.0.b.1.c.2.d.3', {'executionStats.nReturned': 1, 'executionStats.totalDocsExamined': 1}); @@ -204,9 +204,9 @@ assert.commandWorked( coll.insert({_id: 6, a: [{b: [{c: [{d: [{e: [{f: [{g: [{h: [{i: [1]}]}]}]}]}]}]}]}]})); // We can query up to a depth of 8 arrays via specific indices, but not through 9 or more. - assertAllPathsQuery({'a.0.b.0.c.0.d.0.e.0.f.0.g.0.h.0.i': 1}, + assertWildcardQuery({'a.0.b.0.c.0.d.0.e.0.f.0.g.0.h.0.i': 1}, 'a.0.b.0.c.0.d.0.e.0.f.0.g.0.h.0.i'); - assertAllPathsQuery({'a.0.b.0.c.0.d.0.e.0.f.0.g.0.h.0.i.0': 1}, null); + assertWildcardQuery({'a.0.b.0.c.0.d.0.e.0.f.0.g.0.h.0.i.0': 1}, null); // Test that fieldname-or-array-index queries do not inappropriately trim predicates; that // is, all predicates on the field are added to a FETCH filter above the IXSCAN. @@ -220,10 +220,10 @@ assert.commandWorked(coll.insert({_id: 5, a: [4, 5, 6], b: [7, 8, 9], c: {'0': 10}})); assert.commandWorked(coll.insert({_id: 6, a: [5, 6, 7], b: [8, 9, 10], c: {'0': 11}})); - assertAllPathsQuery({"a.0": {$gt: 1, $lt: 4}}, 'a.0', {'executionStats.nReturned': 2}); - assertAllPathsQuery({"a.1": {$gte: 1, $lte: 4}}, 'a.1', {'executionStats.nReturned': 4}); - assertAllPathsQuery({"b.2": {$in: [5, 9]}}, 'b.2', {'executionStats.nReturned': 1}); - assertAllPathsQuery({"c.0": {$in: [10, 11]}}, 'c.0', {'executionStats.nReturned': 2}); + assertWildcardQuery({"a.0": {$gt: 1, $lt: 4}}, 'a.0', {'executionStats.nReturned': 2}); + assertWildcardQuery({"a.1": {$gte: 1, $lte: 4}}, 'a.1', {'executionStats.nReturned': 4}); + assertWildcardQuery({"b.2": {$in: [5, 9]}}, 'b.2', {'executionStats.nReturned': 1}); + assertWildcardQuery({"c.0": {$in: [10, 11]}}, 'c.0', {'executionStats.nReturned': 2}); // Test that the $** index doesn't trim predicates when planning across multiple nested // $and/$or expressions on various fieldname-or-array-index paths. diff --git a/jstests/noPassthroughWithMongod/all_paths_index_nonblocking_sort.js b/jstests/noPassthroughWithMongod/wildcard_index_nonblocking_sort.js index d27ee6b19e9..b9c7edb3921 100644 --- a/jstests/noPassthroughWithMongod/all_paths_index_nonblocking_sort.js +++ b/jstests/noPassthroughWithMongod/wildcard_index_nonblocking_sort.js @@ -4,7 +4,7 @@ load("jstests/aggregation/extras/utils.js"); // For arrayEq(). load("jstests/libs/analyze_plan.js"); // For getPlanStages(). - const coll = db.all_paths_nonblocking_sort; + const coll = db.wildcard_nonblocking_sort; // Required in order to build $** indexes. assert.commandWorked( @@ -64,8 +64,4 @@ checkQueryUsesBlockingSortAndGetsCorrectResults({}, {a: 1}); checkQueryUsesBlockingSortAndGetsCorrectResults({x: 123}, {a: 1}); checkQueryUsesBlockingSortAndGetsCorrectResults({excludedField: {$gte: 0}}, {excludedField: 1}); - - // TODO SERVER-36444: Remove drop once collection validation works with indexes that have - // multikey entries. - coll.drop(); })(); diff --git a/jstests/noPassthroughWithMongod/all_paths_partial_index.js b/jstests/noPassthroughWithMongod/wildcard_index_partial_index.js index 8cd6f80c9db..4e8d8ec090f 100644 --- a/jstests/noPassthroughWithMongod/all_paths_partial_index.js +++ b/jstests/noPassthroughWithMongod/wildcard_index_partial_index.js @@ -8,9 +8,9 @@ load("jstests/libs/analyze_plan.js"); // For isIxScan, isCollscan. - const coll = db.all_paths_partial_index; + const coll = db.wildcard_partial_index; - function testPartialAllPathsIndex(indexKeyPattern, indexOptions) { + function testPartialWildcardIndex(indexKeyPattern, indexOptions) { coll.drop(); assert.commandWorked(coll.createIndex(indexKeyPattern, indexOptions)); @@ -47,10 +47,10 @@ assert.commandWorked( db.adminCommand({setParameter: 1, internalQueryAllowAllPathsIndexes: true})); - testPartialAllPathsIndex({"$**": 1}, {partialFilterExpression: {a: {$lte: 1.5}}}); + testPartialWildcardIndex({"$**": 1}, {partialFilterExpression: {a: {$lte: 1.5}}}); // Case where the partial filter expression is on a field not included in the index. - testPartialAllPathsIndex({"x.$**": 1}, {partialFilterExpression: {a: {$lte: 1.5}}}); + testPartialWildcardIndex({"x.$**": 1}, {partialFilterExpression: {a: {$lte: 1.5}}}); } finally { // Disable $** indexes once the tests have either completed or failed. db.adminCommand({setParameter: 1, internalQueryAllowAllPathsIndexes: false}); diff --git a/jstests/noPassthroughWithMongod/all_paths_return_key.js b/jstests/noPassthroughWithMongod/wildcard_index_return_key.js index 75d503b320b..382aa9cfb98 100644 --- a/jstests/noPassthroughWithMongod/all_paths_return_key.js +++ b/jstests/noPassthroughWithMongod/wildcard_index_return_key.js @@ -7,7 +7,7 @@ load("jstests/aggregation/extras/utils.js"); - const coll = db.all_paths_return_key; + const coll = db.wildcard_return_key; coll.drop(); const assertArrayEq = (l, r) => assert(arrayEq(l, r), tojson(l) + " != " + tojson(r)); diff --git a/jstests/noPassthroughWithMongod/all_paths_validindex.js b/jstests/noPassthroughWithMongod/wildcard_index_validindex.js index 165b1fc6bc5..b73b21ae09f 100644 --- a/jstests/noPassthroughWithMongod/all_paths_validindex.js +++ b/jstests/noPassthroughWithMongod/wildcard_index_validindex.js @@ -1,5 +1,5 @@ /** - * Tests parsing and validation of allPaths indexes. + * Tests parsing and validation of wildcard indexes. * @tags: [ * # Uses index building in background * requires_background_index, @@ -9,10 +9,10 @@ (function() { "use strict"; - const kCollectionName = "all_paths_validindex"; + const kCollectionName = "wildcard_validindex"; const coll = db.getCollection(kCollectionName); - const kIndexName = "all_paths_validindex"; + const kIndexName = "wildcard_validindex"; const createIndexHelper = function(key, parameters) { return db.runCommand( @@ -33,27 +33,27 @@ assert.commandWorked( db.adminCommand({setParameter: 1, internalQueryAllowAllPathsIndexes: true})); try { - // Can create a valid allPaths index. + // Can create a valid wildcard index. createIndexAndVerifyWithDrop({"$**": 1}, {name: kIndexName}); - // Can create a valid allPaths index with subpaths. + // Can create a valid wildcard index with subpaths. createIndexAndVerifyWithDrop({"a.$**": 1}, {name: kIndexName}); - // Can create an allPaths index with partialFilterExpression. + // Can create a wildcard index with partialFilterExpression. createIndexAndVerifyWithDrop({"$**": 1}, {name: kIndexName, partialFilterExpression: {a: {"$gt": 0}}}); - // Can create an allPaths index with foreground & background construction. + // Can create a wildcard index with foreground & background construction. createIndexAndVerifyWithDrop({"$**": 1}, {background: false, name: kIndexName}); createIndexAndVerifyWithDrop({"$**": 1}, {background: true, name: kIndexName}); - // Can create an allPaths index with index level collation. + // Can create a wildcard index with index level collation. createIndexAndVerifyWithDrop({"$**": 1}, {collation: {locale: "fr"}, name: kIndexName}); - // Can create an allPaths index with an inclusion projection. + // Can create a wildcard index with an inclusion projection. createIndexAndVerifyWithDrop({"$**": 1}, {wildcardProjection: {a: 1, b: 1, c: 1}, name: kIndexName}); - // Can create an allPaths index with an exclusion projection. + // Can create a wildcard index with an exclusion projection. createIndexAndVerifyWithDrop({"$**": 1}, {wildcardProjection: {a: 0, b: 0, c: 0}, name: kIndexName}); // Can include _id in an exclusion. @@ -63,12 +63,12 @@ createIndexAndVerifyWithDrop( {"$**": 1}, {wildcardProjection: {_id: 0, a: 1, b: 1, c: 1}, name: kIndexName}); - // Cannot create an allPaths index with sparse option. + // Cannot create a wildcard index with sparse option. coll.dropIndexes(); assert.commandFailedWithCode(coll.createIndex({"$**": 1}, {sparse: true}), ErrorCodes.CannotCreateIndex); - // Cannot create an allPaths index with a v0 or v1 index. + // Cannot create a wildcard index with a v0 or v1 index. assert.commandFailedWithCode(coll.createIndex({"$**": 1}, {v: 0}), ErrorCodes.CannotCreateIndex); assert.commandFailedWithCode(coll.createIndex({"$**": 1}, {v: 1}), @@ -78,36 +78,36 @@ assert.commandFailedWithCode(coll.createIndex({"$**": 1}, {unique: true}), ErrorCodes.CannotCreateIndex); - // Cannot create a hashed all paths index. + // Cannot create a hashed wildcard index. assert.commandFailedWithCode(coll.createIndex({"$**": "hashed"}), ErrorCodes.CannotCreateIndex); - // Cannot create a TTL all paths index. + // Cannot create a TTL wildcard index. assert.commandFailedWithCode(coll.createIndex({"$**": 1}, {expireAfterSeconds: 3600}), ErrorCodes.CannotCreateIndex); - // Cannot create a geoSpatial all paths index. + // Cannot create a geoSpatial wildcard index. assert.commandFailedWithCode(coll.createIndex({"$**": "2dsphere"}), ErrorCodes.CannotCreateIndex); assert.commandFailedWithCode(coll.createIndex({"$**": "2d"}), ErrorCodes.CannotCreateIndex); - // Cannot create a text all paths index using single sub-path syntax. + // Cannot create a text wildcard index using single sub-path syntax. assert.commandFailedWithCode(coll.createIndex({"a.$**": "text"}), ErrorCodes.CannotCreateIndex); // Cannot specify plugin by string. - assert.commandFailedWithCode(coll.createIndex({"a": "allPaths"}), + assert.commandFailedWithCode(coll.createIndex({"a": "wildcard"}), ErrorCodes.CannotCreateIndex); - assert.commandFailedWithCode(coll.createIndex({"$**": "allPaths"}), + assert.commandFailedWithCode(coll.createIndex({"$**": "wildcard"}), ErrorCodes.CannotCreateIndex); - // Cannot create a compound all paths index. + // Cannot create a compound wildcard index. assert.commandFailedWithCode(coll.createIndex({"$**": 1, "a": 1}), ErrorCodes.CannotCreateIndex); assert.commandFailedWithCode(coll.createIndex({"a": 1, "$**": 1}), ErrorCodes.CannotCreateIndex); - // Cannot create an all paths index with an invalid spec. + // Cannot create an wildcard index with an invalid spec. assert.commandFailedWithCode(coll.createIndex({"a.$**.$**": 1}), ErrorCodes.CannotCreateIndex); assert.commandFailedWithCode(coll.createIndex({"$**.$**": 1}), @@ -115,16 +115,16 @@ assert.commandFailedWithCode(coll.createIndex({"$**": "hello"}), ErrorCodes.CannotCreateIndex); - // Cannot create an all paths index with mixed inclusion exclusion. + // Cannot create an wildcard index with mixed inclusion exclusion. assert.commandFailedWithCode( createIndexHelper({"$**": 1}, {name: kIndexName, wildcardProjection: {a: 1, b: 0}}), 40178); - // Cannot create an all paths index with computed fields. + // Cannot create an wildcard index with computed fields. assert.commandFailedWithCode( createIndexHelper({"$**": 1}, {name: kIndexName, wildcardProjection: {a: 1, b: "string"}}), ErrorCodes.FailedToParse); - // Cannot create an all paths index with an empty projection. + // Cannot create an wildcard index with an empty projection. assert.commandFailedWithCode( createIndexHelper({"$**": 1}, {name: kIndexName, wildcardProjection: {}}), ErrorCodes.FailedToParse); @@ -137,7 +137,7 @@ createIndexHelper({"$**": "text"}, {name: kIndexName, wildcardProjection: {a: 1, b: 1}}), ErrorCodes.BadValue); - // Cannot create an all paths index with a non-object "wildcardProjection" projection. + // Cannot create an wildcard index with a non-object "wildcardProjection" projection. assert.commandFailedWithCode( createIndexHelper({"a.$**": 1}, {name: kIndexName, wildcardProjection: "string"}), ErrorCodes.TypeMismatch); diff --git a/src/mongo/db/catalog/collection_info_cache_impl.cpp b/src/mongo/db/catalog/collection_info_cache_impl.cpp index 38adae1cf13..f653c68921e 100644 --- a/src/mongo/db/catalog/collection_info_cache_impl.cpp +++ b/src/mongo/db/catalog/collection_info_cache_impl.cpp @@ -37,8 +37,8 @@ #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/fts/fts_spec.h" -#include "mongo/db/index/all_paths_key_generator.h" #include "mongo/db/index/index_descriptor.h" +#include "mongo/db/index/wildcard_key_generator.h" #include "mongo/db/index_legacy.h" #include "mongo/db/query/get_executor.h" #include "mongo/db/query/plan_cache.h" @@ -90,9 +90,9 @@ void CollectionInfoCacheImpl::computeIndexKeys(OperationContext* opCtx) { while (i.more()) { IndexDescriptor* descriptor = i.next(); - if (descriptor->getAccessMethodName() == IndexNames::ALLPATHS) { + if (descriptor->getAccessMethodName() == IndexNames::WILDCARD) { // Obtain the projection used by the $** index's key generator. - auto pathProj = AllPathsKeyGenerator::createProjectionExec( + auto pathProj = WildcardKeyGenerator::createProjectionExec( descriptor->keyPattern(), descriptor->pathProjection()); // 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. diff --git a/src/mongo/db/catalog/index_catalog_impl.cpp b/src/mongo/db/catalog/index_catalog_impl.cpp index f6f9eea188c..f2a255efba5 100644 --- a/src/mongo/db/catalog/index_catalog_impl.cpp +++ b/src/mongo/db/catalog/index_catalog_impl.cpp @@ -595,7 +595,7 @@ Status IndexCatalogImpl::_isSpecOk(OperationContext* opCtx, const BSONObj& spec) } if ((pluginName != IndexNames::BTREE) && (pluginName != IndexNames::GEO_2DSPHERE) && - (pluginName != IndexNames::HASHED) && (pluginName != IndexNames::ALLPATHS)) { + (pluginName != IndexNames::HASHED) && (pluginName != IndexNames::WILDCARD)) { return Status(ErrorCodes::CannotCreateIndex, str::stream() << "Index type '" << pluginName << "' does not support collation: " @@ -605,7 +605,7 @@ Status IndexCatalogImpl::_isSpecOk(OperationContext* opCtx, const BSONObj& spec) const bool isSparse = spec["sparse"].trueValue(); - if (pluginName == IndexNames::ALLPATHS) { + if (pluginName == IndexNames::WILDCARD) { if (isSparse) { return Status(ErrorCodes::CannotCreateIndex, str::stream() << "Index type '" << pluginName diff --git a/src/mongo/db/catalog/index_key_validate.cpp b/src/mongo/db/catalog/index_key_validate.cpp index 8a0bcc191c1..ceca0d444c5 100644 --- a/src/mongo/db/catalog/index_key_validate.cpp +++ b/src/mongo/db/catalog/index_key_validate.cpp @@ -38,8 +38,8 @@ #include "mongo/base/status.h" #include "mongo/base/status_with.h" #include "mongo/db/field_ref.h" -#include "mongo/db/index/all_paths_key_generator.h" #include "mongo/db/index/index_descriptor.h" +#include "mongo/db/index/wildcard_key_generator.h" #include "mongo/db/index_names.h" #include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression_parser.h" @@ -121,11 +121,11 @@ Status validateKeyPattern(const BSONObj& key, IndexDescriptor::IndexVersion inde code, mongoutils::str::stream() << "Unknown index plugin '" << pluginName << '\''); } - if (pluginName == IndexNames::ALLPATHS && !internalQueryAllowAllPathsIndexes.load()) { - // TODO: SERVER-36198 remove this check once AllPaths indexes are complete. + if (pluginName == IndexNames::WILDCARD && !internalQueryAllowAllPathsIndexes.load()) { + // TODO: SERVER-36198 remove this check once wildcard indexes are complete. return Status( ErrorCodes::NotImplemented, - "Cannot use an allPaths index without enabling internalQueryAllowAllPathsIndexes"); + "Cannot use a wildcard index without enabling internalQueryAllowAllPathsIndexes"); } BSONObjIterator it(key); @@ -142,7 +142,7 @@ Status validateKeyPattern(const BSONObj& key, IndexDescriptor::IndexVersion inde << static_cast<int>(indexVersion)}; } - if (pluginName == IndexNames::ALLPATHS) { + if (pluginName == IndexNames::WILDCARD) { return {code, str::stream() << "'" << pluginName << "' index plugin is not allowed with index version v:" @@ -174,20 +174,20 @@ Status validateKeyPattern(const BSONObj& key, IndexDescriptor::IndexVersion inde if (keyElement.type() == String && pluginName != keyElement.str()) { return Status(code, "Can't use more than one index plugin for a single index."); - } else if (keyElement.type() == String && keyElement.str() == IndexNames::ALLPATHS) { + } else if (keyElement.type() == String && keyElement.str() == IndexNames::WILDCARD) { return Status(code, - str::stream() << "The key pattern value for an '" << IndexNames::ALLPATHS + str::stream() << "The key pattern value for an '" << IndexNames::WILDCARD << "' index must be a non-zero number, not a string."); } - // Check if the all paths index is compounded. If it is the key is invalid because - // compounded all paths indexes are disallowed. - if (pluginName == IndexNames::ALLPATHS && key.nFields() != 1) { - return Status(code, "all paths indexes do not allow compounding"); + // Check if the wildcard index is compounded. If it is the key is invalid because + // compounded wildcard indexes are disallowed. + if (pluginName == IndexNames::WILDCARD && key.nFields() != 1) { + return Status(code, "wildcard indexes do not allow compounding"); } // Ensure that the fields on which we are building the index are valid: a field must not - // begin with a '$' unless it is part of an allPaths, DBRef or text index, and a field path + // begin with a '$' unless it is part of a wildcard, DBRef or text index, and a field path // cannot contain an empty field. If a field cannot be created or updated, it should not be // indexable. @@ -198,7 +198,7 @@ Status validateKeyPattern(const BSONObj& key, IndexDescriptor::IndexVersion inde return Status(code, "Index keys cannot be an empty field."); } - // "$**" is acceptable for a text index or all paths index. + // "$**" is acceptable for a text index or wildcard index. if (mongoutils::str::equals(keyElement.fieldName(), "$**") && ((keyElement.isNumber()) || (keyElement.valuestrsafe() == IndexNames::TEXT))) continue; @@ -225,10 +225,10 @@ Status validateKeyPattern(const BSONObj& key, IndexDescriptor::IndexVersion inde const bool mightBePartOfDbRef = (i != 0) && (part == "$db" || part == "$id" || part == "$ref"); - const bool isPartOfAllPaths = - (i == numParts - 1) && (part == "$**") && (pluginName == IndexNames::ALLPATHS); + const bool isPartOfWildcard = + (i == numParts - 1) && (part == "$**") && (pluginName == IndexNames::WILDCARD); - if (!mightBePartOfDbRef && !isPartOfAllPaths) { + if (!mightBePartOfDbRef && !isPartOfWildcard) { return Status(code, "Index key contains an illegal field name: " "field name starts with '$'."); @@ -290,10 +290,10 @@ StatusWith<BSONObj> validateIndexSpec( if ((featureCompatibility.getVersion() < ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo42) && (IndexNames::findPluginName(indexSpec.getObjectField( - IndexDescriptor::kKeyPatternFieldName)) == IndexNames::ALLPATHS)) { + IndexDescriptor::kKeyPatternFieldName)) == IndexNames::WILDCARD)) { return {ErrorCodes::CannotCreateIndex, mongoutils::str::stream() << "Unknown index plugin '" - << IndexNames::ALLPATHS + << IndexNames::WILDCARD << "'"}; } hasKeyPatternField = true; @@ -404,11 +404,11 @@ StatusWith<BSONObj> validateIndexSpec( } } else if (IndexDescriptor::kPathProjectionFieldName == indexSpecElemFieldName) { const auto key = indexSpec.getObjectField(IndexDescriptor::kKeyPatternFieldName); - if (IndexNames::findPluginName(key) != IndexNames::ALLPATHS) { + if (IndexNames::findPluginName(key) != IndexNames::WILDCARD) { return {ErrorCodes::BadValue, str::stream() << "The field '" << IndexDescriptor::kPathProjectionFieldName << "' is only allowed in an '" - << IndexNames::ALLPATHS + << IndexNames::WILDCARD << "' index"}; } if (indexSpecElem.type() != BSONType::Object) { @@ -431,9 +431,9 @@ StatusWith<BSONObj> validateIndexSpec( << "' field can't be an empty object"}; } try { - // We use AllPathsKeyGenerator::createProjectionExec to parse and validate the path + // We use WildcardKeyGenerator::createProjectionExec to parse and validate the path // projection spec. - AllPathsKeyGenerator::createProjectionExec(key, indexSpecElem.embeddedObject()); + WildcardKeyGenerator::createProjectionExec(key, indexSpecElem.embeddedObject()); } catch (const DBException& ex) { return ex.toStatus(str::stream() << "Failed to parse: " << IndexDescriptor::kPathProjectionFieldName); diff --git a/src/mongo/db/catalog/index_key_validate_test.cpp b/src/mongo/db/catalog/index_key_validate_test.cpp index 9fbd4f345d4..06d81a0a2cb 100644 --- a/src/mongo/db/catalog/index_key_validate_test.cpp +++ b/src/mongo/db/catalog/index_key_validate_test.cpp @@ -248,59 +248,59 @@ TEST(IndexKeyValidateTest, KeyElementNameTextSucceedsOnTextIndex) { } } -TEST(IndexKeyValidateTest, KeyElementNameAllPathsSucceedsOnSubPath) { +TEST(IndexKeyValidateTest, KeyElementNameWildcardSucceedsOnSubPath) { TestCommandQueryKnobGuard guard; ASSERT_OK(validateKeyPattern(BSON("a.$**" << 1), IndexVersion::kV2)); } -TEST(IndexKeyValidateTest, KeyElementNameAllPathsSucceeds) { +TEST(IndexKeyValidateTest, KeyElementNameWildcardSucceeds) { TestCommandQueryKnobGuard guard; ASSERT_OK(validateKeyPattern(BSON("$**" << 1), IndexVersion::kV2)); } -TEST(IndexKeyValidateTest, KeyElementNameAllPathsFailsOnRepeat) { +TEST(IndexKeyValidateTest, KeyElementNameWildcardFailsOnRepeat) { TestCommandQueryKnobGuard guard; auto status = validateKeyPattern(BSON("$**.$**" << 1), IndexVersion::kV2); ASSERT_NOT_OK(status); ASSERT_EQ(status, ErrorCodes::CannotCreateIndex); } -TEST(IndexKeyValidateTest, KeyElementNameAllPathsFailsOnSubPathRepeat) { +TEST(IndexKeyValidateTest, KeyElementNameWildcardFailsOnSubPathRepeat) { TestCommandQueryKnobGuard guard; auto status = validateKeyPattern(BSON("a.$**.$**" << 1), IndexVersion::kV2); ASSERT_NOT_OK(status); ASSERT_EQ(status, ErrorCodes::CannotCreateIndex); } -TEST(IndexKeyValidateTest, KeyElementNameAllPathsFailsOnCompound) { +TEST(IndexKeyValidateTest, KeyElementNameWildcardFailsOnCompound) { TestCommandQueryKnobGuard guard; auto status = validateKeyPattern(BSON("$**" << 1 << "a" << 1), IndexVersion::kV2); ASSERT_NOT_OK(status); ASSERT_EQ(status, ErrorCodes::CannotCreateIndex); } -TEST(IndexKeyValidateTest, KeyElementNameAllPathsFailsOnIncorrectValue) { +TEST(IndexKeyValidateTest, KeyElementNameWildcardFailsOnIncorrectValue) { TestCommandQueryKnobGuard guard; auto status = validateKeyPattern(BSON("$**" << false), IndexVersion::kV2); ASSERT_NOT_OK(status); ASSERT_EQ(status, ErrorCodes::CannotCreateIndex); } -TEST(IndexKeyValidateTest, KeyElementNameAllPathsFailsWhenValueIsPluginNameWithInvalidKeyName) { +TEST(IndexKeyValidateTest, KeyElementNameWildcardFailsWhenValueIsPluginNameWithInvalidKeyName) { // TODO: Remove test command enabling/disabling in SERVER-36198 TestCommandQueryKnobGuard guard; auto status = validateKeyPattern(BSON("a" - << "allPaths"), + << "wildcard"), IndexVersion::kV2); ASSERT_NOT_OK(status); ASSERT_EQ(status, ErrorCodes::CannotCreateIndex); } -TEST(IndexKeyValidateTest, KeyElementNameAllPathsFailsWhenValueIsPluginNameWithValidKeyName) { +TEST(IndexKeyValidateTest, KeyElementNameWildcardFailsWhenValueIsPluginNameWithValidKeyName) { // TODO: Remove test command enabling/disabling in SERVER-36198 TestCommandQueryKnobGuard guard; auto status = validateKeyPattern(BSON("$**" - << "allPaths"), + << "wildcard"), IndexVersion::kV2); ASSERT_NOT_OK(status); ASSERT_EQ(status, ErrorCodes::CannotCreateIndex); diff --git a/src/mongo/db/catalog/index_spec_validate_test.cpp b/src/mongo/db/catalog/index_spec_validate_test.cpp index 4ad09b147d2..9481460593c 100644 --- a/src/mongo/db/catalog/index_spec_validate_test.cpp +++ b/src/mongo/db/catalog/index_spec_validate_test.cpp @@ -838,7 +838,7 @@ TEST(IndexSpecPartialFilterTest, AcceptsValidPartialFilterExpression) { ASSERT_OK(result.getStatus()); } -TEST(IndexSpecAllPaths, SucceedsWithInclusion) { +TEST(IndexSpecWildcard, SucceedsWithInclusion) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("$**" << 1) << "name" @@ -850,7 +850,7 @@ TEST(IndexSpecAllPaths, SucceedsWithInclusion) { ASSERT_OK(result.getStatus()); } -TEST(IndexSpecAllPaths, SucceedsWithExclusion) { +TEST(IndexSpecWildcard, SucceedsWithExclusion) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("$**" << 1) << "name" @@ -862,7 +862,7 @@ TEST(IndexSpecAllPaths, SucceedsWithExclusion) { ASSERT_OK(result.getStatus()); } -TEST(IndexSpecAllPaths, SucceedsWithExclusionIncludingId) { +TEST(IndexSpecWildcard, SucceedsWithExclusionIncludingId) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("$**" << 1) << "name" @@ -874,7 +874,7 @@ TEST(IndexSpecAllPaths, SucceedsWithExclusionIncludingId) { ASSERT_OK(result.getStatus()); } -TEST(IndexSpecAllPaths, SucceedsWithInclusionExcludingId) { +TEST(IndexSpecWildcard, SucceedsWithInclusionExcludingId) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("$**" << 1) << "name" @@ -886,7 +886,7 @@ TEST(IndexSpecAllPaths, SucceedsWithInclusionExcludingId) { ASSERT_OK(result.getStatus()); } -TEST(IndexSpecAllPaths, FailsWithInclusionExcludingIdSubfield) { +TEST(IndexSpecWildcard, FailsWithInclusionExcludingIdSubfield) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("$**" << 1) << "name" @@ -898,7 +898,7 @@ TEST(IndexSpecAllPaths, FailsWithInclusionExcludingIdSubfield) { ASSERT_EQ(result.getStatus().code(), 40179); } -TEST(IndexSpecAllPaths, FailsWithExclusionIncludingIdSubfield) { +TEST(IndexSpecWildcard, FailsWithExclusionIncludingIdSubfield) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("$**" << 1) << "name" @@ -910,7 +910,7 @@ TEST(IndexSpecAllPaths, FailsWithExclusionIncludingIdSubfield) { ASSERT_EQ(result.getStatus().code(), 40178); } -TEST(IndexSpecAllPaths, FailsWithImproperFeatureCompatabilityVersion) { +TEST(IndexSpecWildcard, FailsWithImproperFeatureCompatabilityVersion) { TestCommandFcvGuard guard; serverGlobalParams.featureCompatibility.setVersion( ServerGlobalParams::FeatureCompatibility::Version::kUpgradingTo42); @@ -922,7 +922,7 @@ TEST(IndexSpecAllPaths, FailsWithImproperFeatureCompatabilityVersion) { ASSERT_EQ(result.getStatus().code(), ErrorCodes::CannotCreateIndex); } -TEST(IndexSpecAllPaths, FailsWithMixedProjection) { +TEST(IndexSpecWildcard, FailsWithMixedProjection) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("$**" << 1) << "name" @@ -934,7 +934,7 @@ TEST(IndexSpecAllPaths, FailsWithMixedProjection) { ASSERT_EQ(result.getStatus().code(), 40178); } -TEST(IndexSpecAllPaths, FailsWithComputedFieldsInProjection) { +TEST(IndexSpecWildcard, FailsWithComputedFieldsInProjection) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("$**" << 1) << "name" @@ -947,7 +947,7 @@ TEST(IndexSpecAllPaths, FailsWithComputedFieldsInProjection) { ASSERT_EQ(result.getStatus().code(), ErrorCodes::FailedToParse); } -TEST(IndexSpecAllPaths, FailsWhenProjectionPluginNotAllPaths) { +TEST(IndexSpecWildcard, FailsWhenProjectionPluginNotWildcard) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("a" << 1) << "name" @@ -959,7 +959,7 @@ TEST(IndexSpecAllPaths, FailsWhenProjectionPluginNotAllPaths) { ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); } -TEST(IndexSpecAllPaths, FailsWhenProjectionIsNotAnObject) { +TEST(IndexSpecWildcard, FailsWhenProjectionIsNotAnObject) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("$**" << 1) << "name" @@ -971,7 +971,7 @@ TEST(IndexSpecAllPaths, FailsWhenProjectionIsNotAnObject) { ASSERT_EQ(result.getStatus().code(), ErrorCodes::TypeMismatch); } -TEST(IndexSpecAllPaths, FailsWithEmptyProjection) { +TEST(IndexSpecWildcard, FailsWithEmptyProjection) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("$**" << 1) << "name" @@ -983,7 +983,7 @@ TEST(IndexSpecAllPaths, FailsWithEmptyProjection) { ASSERT_EQ(result.getStatus().code(), ErrorCodes::FailedToParse); } -TEST(IndexSpecAllPaths, FailsWhenInclusionWithSubpath) { +TEST(IndexSpecWildcard, FailsWhenInclusionWithSubpath) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("a.$**" << 1) << "name" @@ -995,7 +995,7 @@ TEST(IndexSpecAllPaths, FailsWhenInclusionWithSubpath) { ASSERT_EQ(result.getStatus().code(), ErrorCodes::FailedToParse); } -TEST(IndexSpecAllPaths, FailsWhenExclusionWithSubpath) { +TEST(IndexSpecWildcard, FailsWhenExclusionWithSubpath) { TestCommandFcvGuard guard; auto result = validateIndexSpec(kDefaultOpCtx, BSON("key" << BSON("a.$**" << 1) << "name" diff --git a/src/mongo/db/catalog/private/record_store_validate_adaptor.cpp b/src/mongo/db/catalog/private/record_store_validate_adaptor.cpp index dc173706b4b..10ddaf281ef 100644 --- a/src/mongo/db/catalog/private/record_store_validate_adaptor.cpp +++ b/src/mongo/db/catalog/private/record_store_validate_adaptor.cpp @@ -35,9 +35,9 @@ #include "mongo/bson/bsonobj.h" #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/catalog/index_consistency.h" -#include "mongo/db/index/all_paths_access_method.h" #include "mongo/db/index/index_access_method.h" #include "mongo/db/index/index_descriptor.h" +#include "mongo/db/index/wildcard_access_method.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/operation_context.h" #include "mongo/db/storage/key_string.h" @@ -56,7 +56,7 @@ bool isLargeKeyDisallowed() { KeyString makeWildCardMultikeyMetadataKeyString(const BSONObj& indexKey) { const auto multikeyMetadataOrd = Ordering::make(BSON("" << 1 << "" << 1)); - const RecordId multikeyMetadataRecordId(RecordId::ReservedId::kAllPathsMultikeyMetadataId); + const RecordId multikeyMetadataRecordId(RecordId::ReservedId::kWildcardMultikeyMetadataId); return {KeyString::kLatestVersion, indexKey, multikeyMetadataOrd, multikeyMetadataRecordId}; } } @@ -171,10 +171,10 @@ void RecordStoreValidateAdaptor::traverseIndex(const IndexAccessMethod* iam, results->valid = false; } - const RecordId kAllPathsMultikeyMetadataRecordId{ - RecordId::ReservedId::kAllPathsMultikeyMetadataId}; - if (descriptor->getIndexType() == IndexType::INDEX_ALLPATHS && - indexEntry->loc == kAllPathsMultikeyMetadataRecordId) { + const RecordId kWildcardMultikeyMetadataRecordId{ + RecordId::ReservedId::kWildcardMultikeyMetadataId}; + if (descriptor->getIndexType() == IndexType::INDEX_WILDCARD && + indexEntry->loc == kWildcardMultikeyMetadataRecordId) { _indexConsistency->removeMultikeyMetadataPath( makeWildCardMultikeyMetadataKeyString(indexEntry->key), indexNumber); numKeys++; @@ -281,7 +281,7 @@ void RecordStoreValidateAdaptor::validateIndexKeyCount(IndexDescriptor* idx, // produce an index key per array entry) and not $** indexes which can produce index keys for // multiple paths within a single document. if (results.valid && !idx->isMultikey(_opCtx) && - idx->getIndexType() != IndexType::INDEX_ALLPATHS && totalKeys > numRecs) { + idx->getIndexType() != IndexType::INDEX_WILDCARD && totalKeys > numRecs) { std::string err = str::stream() << "index " << idx->indexName() << " is not multi-key, but has more entries (" << numIndexedKeys << ") than documents in the index (" << numRecs - numLongKeys << ")"; diff --git a/src/mongo/db/index/SConscript b/src/mongo/db/index/SConscript index 5fbf8868460..b98ff869f1f 100644 --- a/src/mongo/db/index/SConscript +++ b/src/mongo/db/index/SConscript @@ -19,10 +19,10 @@ env.Library( env.Library( target='key_generator', source=[ - 'all_paths_key_generator.cpp', 'btree_key_generator.cpp', 'expression_keys_private.cpp', 'sort_key_generator.cpp', + 'wildcard_key_generator.cpp', ], LIBDEPS=[ '$BUILD_DIR/mongo/base', @@ -59,12 +59,12 @@ env.Library( env.CppUnitTest( target='key_generator_test', source=[ - 'all_paths_key_generator_test.cpp', '2d_key_generator_test.cpp', 'btree_key_generator_test.cpp', 'hash_key_generator_test.cpp', 's2_key_generator_test.cpp', 'sort_key_generator_test.cpp', + 'wildcard_key_generator_test.cpp', ], LIBDEPS=[ 'key_generator', @@ -101,12 +101,12 @@ env.Library( target="index_access_methods", source=[ "2d_access_method.cpp", - "all_paths_access_method.cpp", "btree_access_method.cpp", "fts_access_method.cpp", "hash_access_method.cpp", "haystack_access_method.cpp", "s2_access_method.cpp", + "wildcard_access_method.cpp", ], LIBDEPS=[ '$BUILD_DIR/mongo/base', diff --git a/src/mongo/db/index/index_access_method.cpp b/src/mongo/db/index/index_access_method.cpp index 53591e09734..d2f12401f4a 100644 --- a/src/mongo/db/index/index_access_method.cpp +++ b/src/mongo/db/index/index_access_method.cpp @@ -68,7 +68,7 @@ namespace { // Reserved RecordId against which multikey metadata keys are indexed. static const RecordId kMultikeyMetadataKeyId = - RecordId{RecordId::ReservedId::kAllPathsMultikeyMetadataId}; + RecordId{RecordId::ReservedId::kWildcardMultikeyMetadataId}; /** * Returns true if at least one prefix of any of the indexed fields causes the index to be diff --git a/src/mongo/db/index/all_paths_access_method.cpp b/src/mongo/db/index/wildcard_access_method.cpp index b8b966d06d0..4816c29ac22 100644 --- a/src/mongo/db/index/all_paths_access_method.cpp +++ b/src/mongo/db/index/wildcard_access_method.cpp @@ -28,32 +28,32 @@ #include "mongo/platform/basic.h" -#include "mongo/db/index/all_paths_access_method.h" +#include "mongo/db/index/wildcard_access_method.h" #include "mongo/db/catalog/index_catalog_entry.h" namespace mongo { -AllPathsAccessMethod::AllPathsAccessMethod(IndexCatalogEntry* allPathsState, +WildcardAccessMethod::WildcardAccessMethod(IndexCatalogEntry* wildcardState, SortedDataInterface* btree) - : IndexAccessMethod(allPathsState, btree), + : IndexAccessMethod(wildcardState, btree), _keyGen( _descriptor->keyPattern(), _descriptor->pathProjection(), _btreeState->getCollator()) {} -bool AllPathsAccessMethod::shouldMarkIndexAsMultikey(const BSONObjSet& keys, +bool WildcardAccessMethod::shouldMarkIndexAsMultikey(const BSONObjSet& keys, const BSONObjSet& multikeyMetadataKeys, const MultikeyPaths& multikeyPaths) const { return !multikeyMetadataKeys.empty(); } -void AllPathsAccessMethod::doGetKeys(const BSONObj& obj, +void WildcardAccessMethod::doGetKeys(const BSONObj& obj, BSONObjSet* keys, BSONObjSet* multikeyMetadataKeys, MultikeyPaths* multikeyPaths) const { _keyGen.generateKeys(obj, keys, multikeyMetadataKeys); } -std::set<FieldRef> AllPathsAccessMethod::getMultikeyPathSet(OperationContext* opCtx) const { +std::set<FieldRef> WildcardAccessMethod::getMultikeyPathSet(OperationContext* opCtx) const { auto cursor = newCursor(opCtx); // All of the keys storing multikeyness metadata are prefixed by a value of 1. Establish an // index cursor which will scan this range. @@ -70,7 +70,7 @@ std::set<FieldRef> AllPathsAccessMethod::getMultikeyPathSet(OperationContext* op // Validate that the key contains the expected RecordId. invariant(entry->loc.isReserved()); invariant(entry->loc.repr() == - static_cast<int64_t>(RecordId::ReservedId::kAllPathsMultikeyMetadataId)); + static_cast<int64_t>(RecordId::ReservedId::kWildcardMultikeyMetadataId)); // Validate that the first piece of the key is the integer 1. BSONObjIterator iter(entry->key); diff --git a/src/mongo/db/index/all_paths_access_method.h b/src/mongo/db/index/wildcard_access_method.h index 2a771d8c3f4..e7c061f5134 100644 --- a/src/mongo/db/index/all_paths_access_method.h +++ b/src/mongo/db/index/wildcard_access_method.h @@ -28,22 +28,22 @@ #pragma once -#include "mongo/db/index/all_paths_key_generator.h" #include "mongo/db/index/index_access_method.h" +#include "mongo/db/index/wildcard_key_generator.h" #include "mongo/db/jsobj.h" namespace mongo { /** - * Class which is responsible for generating and providing access to AllPaths index keys. Any index + * Class which is responsible for generating and providing access to Wildcard index keys. Any index * created with { "$**": ±1 } or { "path.$**": ±1 } uses this class. * * $** indexes store a special metadata key for each path in the index that is multikey. This class * provides an interface to access the multikey metadata: see getMultikeyPathSet(). */ -class AllPathsAccessMethod final : public IndexAccessMethod { +class WildcardAccessMethod final : public IndexAccessMethod { public: - AllPathsAccessMethod(IndexCatalogEntry* allPathsState, SortedDataInterface* btree); + WildcardAccessMethod(IndexCatalogEntry* wildcardState, SortedDataInterface* btree); /** * Returns 'true' if the index should become multikey on the basis of the passed arguments. @@ -67,6 +67,6 @@ private: BSONObjSet* multikeyMetadataKeys, MultikeyPaths* multikeyPaths) const final; - const AllPathsKeyGenerator _keyGen; + const WildcardKeyGenerator _keyGen; }; } // namespace mongo diff --git a/src/mongo/db/index/all_paths_key_generator.cpp b/src/mongo/db/index/wildcard_key_generator.cpp index d0b786cd3c3..bec34025425 100644 --- a/src/mongo/db/index/all_paths_key_generator.cpp +++ b/src/mongo/db/index/wildcard_key_generator.cpp @@ -28,7 +28,7 @@ #include "mongo/platform/basic.h" -#include "mongo/db/index/all_paths_key_generator.h" +#include "mongo/db/index/wildcard_key_generator.h" #include "mongo/db/jsobj.h" #include "mongo/db/query/collation/collation_index_key.h" @@ -59,9 +59,9 @@ void popPathComponent(BSONElement elem, bool enclosingObjIsArray, FieldRef* path } } // namespace -constexpr StringData AllPathsKeyGenerator::kSubtreeSuffix; +constexpr StringData WildcardKeyGenerator::kSubtreeSuffix; -std::unique_ptr<ProjectionExecAgg> AllPathsKeyGenerator::createProjectionExec( +std::unique_ptr<ProjectionExecAgg> WildcardKeyGenerator::createProjectionExec( BSONObj keyPattern, BSONObj pathProjection) { // We should never have a key pattern that contains more than a single element. invariant(keyPattern.nFields() == 1); @@ -90,21 +90,21 @@ std::unique_ptr<ProjectionExecAgg> AllPathsKeyGenerator::createProjectionExec( ProjectionExecAgg::ArrayRecursionPolicy::kDoNotRecurseNestedArrays); } -AllPathsKeyGenerator::AllPathsKeyGenerator(BSONObj keyPattern, +WildcardKeyGenerator::WildcardKeyGenerator(BSONObj keyPattern, BSONObj pathProjection, const CollatorInterface* collator) : _collator(collator), _keyPattern(keyPattern) { _projExec = createProjectionExec(keyPattern, pathProjection); } -void AllPathsKeyGenerator::generateKeys(BSONObj inputDoc, +void WildcardKeyGenerator::generateKeys(BSONObj inputDoc, BSONObjSet* keys, BSONObjSet* multikeyPaths) const { FieldRef rootPath; - _traverseAllPaths(_projExec->applyProjection(inputDoc), false, &rootPath, keys, multikeyPaths); + _traverseWildcard(_projExec->applyProjection(inputDoc), false, &rootPath, keys, multikeyPaths); } -void AllPathsKeyGenerator::_traverseAllPaths(BSONObj obj, +void WildcardKeyGenerator::_traverseWildcard(BSONObj obj, bool objIsArray, FieldRef* path, BSONObjSet* keys, @@ -130,7 +130,7 @@ void AllPathsKeyGenerator::_traverseAllPaths(BSONObj obj, if (_addKeyForEmptyLeaf(elem, *path, keys)) break; - _traverseAllPaths( + _traverseWildcard( elem.Obj(), elem.type() == BSONType::Array, path, keys, multikeyPaths); break; @@ -143,7 +143,7 @@ void AllPathsKeyGenerator::_traverseAllPaths(BSONObj obj, } } -bool AllPathsKeyGenerator::_addKeyForNestedArray(BSONElement elem, +bool WildcardKeyGenerator::_addKeyForNestedArray(BSONElement elem, const FieldRef& fullPath, bool enclosingObjIsArray, BSONObjSet* keys) const { @@ -155,7 +155,7 @@ bool AllPathsKeyGenerator::_addKeyForNestedArray(BSONElement elem, return false; } -bool AllPathsKeyGenerator::_addKeyForEmptyLeaf(BSONElement elem, +bool WildcardKeyGenerator::_addKeyForEmptyLeaf(BSONElement elem, const FieldRef& fullPath, BSONObjSet* keys) const { invariant(elem.isABSONObj()); @@ -168,10 +168,10 @@ bool AllPathsKeyGenerator::_addKeyForEmptyLeaf(BSONElement elem, return false; } -void AllPathsKeyGenerator::_addKey(BSONElement elem, +void WildcardKeyGenerator::_addKey(BSONElement elem, const FieldRef& fullPath, BSONObjSet* keys) const { - // AllPaths keys are of the form { "": "path.to.field", "": <collation-aware value> }. + // Wildcard keys are of the form { "": "path.to.field", "": <collation-aware value> }. BSONObjBuilder bob; bob.append("", fullPath.dottedField()); if (elem) { @@ -182,7 +182,7 @@ void AllPathsKeyGenerator::_addKey(BSONElement elem, keys->insert(bob.obj()); } -void AllPathsKeyGenerator::_addMultiKey(const FieldRef& fullPath, BSONObjSet* multikeyPaths) const { +void WildcardKeyGenerator::_addMultiKey(const FieldRef& fullPath, BSONObjSet* multikeyPaths) const { // Multikey paths are denoted by a key of the form { "": 1, "": "path.to.array" }. The argument // 'multikeyPaths' may be nullptr if the access method is being used in an operation which does // not require multikey path generation. diff --git a/src/mongo/db/index/all_paths_key_generator.h b/src/mongo/db/index/wildcard_key_generator.h index cfbb5e7397a..a75bd6bfd23 100644 --- a/src/mongo/db/index/all_paths_key_generator.h +++ b/src/mongo/db/index/wildcard_key_generator.h @@ -39,24 +39,24 @@ namespace mongo { * pathProjection specs, and for subsequently extracting the set of all path-value pairs for each * document. */ -class AllPathsKeyGenerator { +class WildcardKeyGenerator { public: static constexpr StringData kSubtreeSuffix = ".$**"_sd; /** - * Returns an owned ProjectionExecAgg identical to the one that AllPathsKeyGenerator will use + * Returns an owned ProjectionExecAgg identical to the one that WildcardKeyGenerator will use * internally when generating the keys for the $** index, as defined by the 'keyPattern' and * 'pathProjection' arguments. */ static std::unique_ptr<ProjectionExecAgg> createProjectionExec(BSONObj keyPattern, BSONObj pathProjection); - AllPathsKeyGenerator(BSONObj keyPattern, + WildcardKeyGenerator(BSONObj keyPattern, BSONObj pathProjection, const CollatorInterface* collator); /** - * Applies the appropriate AllPaths projection to the input doc, and then adds one key-value + * Applies the appropriate Wildcard projection to the input doc, and then adds one key-value * pair to the BSONObjSet 'keys' for each leaf node in the post-projection document: * { '': 'path.to.field', '': <collation-aware-field-value> } * Also adds one entry to 'multikeyPaths' for each array encountered in the post-projection @@ -67,7 +67,7 @@ public: private: // Traverses every path of the post-projection document, adding keys to the set as it goes. - void _traverseAllPaths(BSONObj obj, + void _traverseWildcard(BSONObj obj, bool objIsArray, FieldRef* path, BSONObjSet* keys, diff --git a/src/mongo/db/index/all_paths_key_generator_test.cpp b/src/mongo/db/index/wildcard_key_generator_test.cpp index 9233ab39deb..cfc20048399 100644 --- a/src/mongo/db/index/all_paths_key_generator_test.cpp +++ b/src/mongo/db/index/wildcard_key_generator_test.cpp @@ -31,7 +31,7 @@ #include "mongo/platform/basic.h" #include "mongo/bson/json.h" -#include "mongo/db/index/all_paths_key_generator.h" +#include "mongo/db/index/wildcard_key_generator.h" #include "mongo/db/query/collation/collator_interface_mock.h" #include "mongo/unittest/unittest.h" #include "mongo/util/log.h" @@ -75,8 +75,8 @@ bool assertKeysetsEqual(const BSONObjSet& expectedKeys, const BSONObjSet& actual // Full-document tests with no projection. -TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractTopLevelKey) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorFullDocumentTest, ExtractTopLevelKey) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; auto inputDoc = fromjson("{a: 1}"); auto expectedKeys = makeKeySet({fromjson("{'': 'a', '': 1}")}); @@ -90,8 +90,8 @@ TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractTopLevelKey) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractKeysFromNestedObject) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorFullDocumentTest, ExtractKeysFromNestedObject) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; auto inputDoc = fromjson("{a: {b: 'one', c: 2}}"); auto expectedKeys = @@ -107,8 +107,8 @@ TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractKeysFromNestedObject) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorFullDocumentTest, ShouldIndexEmptyObject) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorFullDocumentTest, ShouldIndexEmptyObject) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; auto inputDoc = fromjson("{a: 1, b: {}}"); auto expectedKeys = makeKeySet({fromjson("{'': 'a', '': 1}"), fromjson("{'': 'b', '': {}}")}); @@ -122,8 +122,8 @@ TEST(AllPathsKeyGeneratorFullDocumentTest, ShouldIndexEmptyObject) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorFullDocumentTest, ShouldIndexNonNestedEmptyArrayAsUndefined) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorFullDocumentTest, ShouldIndexNonNestedEmptyArrayAsUndefined) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; auto inputDoc = fromjson("{ a: [], b: {c: []}, d: [[], {e: []}]}"); auto expectedKeys = makeKeySet({fromjson("{'': 'a', '': undefined}"), @@ -143,8 +143,8 @@ TEST(AllPathsKeyGeneratorFullDocumentTest, ShouldIndexNonNestedEmptyArrayAsUndef ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractMultikeyPath) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorFullDocumentTest, ExtractMultikeyPath) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; auto inputDoc = fromjson("{a: [1, 2, {b: 'one', c: 2}, {d: 3}]}"); auto expectedKeys = makeKeySet({fromjson("{'': 'a', '': 1}"), @@ -163,8 +163,8 @@ TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractMultikeyPath) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractMultikeyPathAndDedupKeys) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorFullDocumentTest, ExtractMultikeyPathAndDedupKeys) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; auto inputDoc = fromjson("{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {d: 3}]}"); auto expectedKeys = makeKeySet({fromjson("{'': 'a', '': 1}"), @@ -183,8 +183,8 @@ TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractMultikeyPathAndDedupKeys) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractZeroElementMultikeyPath) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorFullDocumentTest, ExtractZeroElementMultikeyPath) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; auto inputDoc = fromjson("{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {d: 3}], e: []}"); auto expectedKeys = makeKeySet({fromjson("{'': 'a', '': 1}"), @@ -205,8 +205,8 @@ TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractZeroElementMultikeyPath) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractNestedMultikeyPaths) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorFullDocumentTest, ExtractNestedMultikeyPaths) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; // Note: the 'e' array is nested within a subdocument in the enclosing 'a' array; it will // generate a separate multikey entry 'a.e' and index keys for each of its elements. The raw @@ -236,8 +236,8 @@ TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractNestedMultikeyPaths) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractMixedPathTypesAndAllSubpaths) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorFullDocumentTest, ExtractMixedPathTypesAndAllSubpaths) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; // Tests a mix of multikey paths, various duplicate-key scenarios, and deeply-nested paths. auto inputDoc = fromjson( @@ -275,8 +275,8 @@ TEST(AllPathsKeyGeneratorFullDocumentTest, ExtractMixedPathTypesAndAllSubpaths) // Single-subtree implicit projection. -TEST(AllPathsKeyGeneratorSingleSubtreeTest, ExtractSubtreeWithSinglePathComponent) { - AllPathsKeyGenerator keyGen{fromjson("{'g.$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractSubtreeWithSinglePathComponent) { + WildcardKeyGenerator keyGen{fromjson("{'g.$**': 1}"), {}, nullptr}; auto inputDoc = fromjson( "{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], " @@ -299,8 +299,8 @@ TEST(AllPathsKeyGeneratorSingleSubtreeTest, ExtractSubtreeWithSinglePathComponen ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorSingleSubtreeTest, ExtractSubtreeWithMultiplePathComponents) { - AllPathsKeyGenerator keyGen{fromjson("{'g.h.$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractSubtreeWithMultiplePathComponents) { + WildcardKeyGenerator keyGen{fromjson("{'g.h.$**': 1}"), {}, nullptr}; auto inputDoc = fromjson( "{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], " @@ -323,8 +323,8 @@ TEST(AllPathsKeyGeneratorSingleSubtreeTest, ExtractSubtreeWithMultiplePathCompon ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorSingleSubtreeTest, ExtractMultikeySubtree) { - AllPathsKeyGenerator keyGen{fromjson("{'g.h.j.$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractMultikeySubtree) { + WildcardKeyGenerator keyGen{fromjson("{'g.h.j.$**': 1}"), {}, nullptr}; auto inputDoc = fromjson( "{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], " @@ -345,8 +345,8 @@ TEST(AllPathsKeyGeneratorSingleSubtreeTest, ExtractMultikeySubtree) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorSingleSubtreeTest, ExtractNestedMultikeySubtree) { - AllPathsKeyGenerator keyGen{fromjson("{'a.e.$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorSingleSubtreeTest, ExtractNestedMultikeySubtree) { + WildcardKeyGenerator keyGen{fromjson("{'a.e.$**': 1}"), {}, nullptr}; auto inputDoc = fromjson( "{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], " @@ -371,8 +371,8 @@ TEST(AllPathsKeyGeneratorSingleSubtreeTest, ExtractNestedMultikeySubtree) { // Explicit inclusion tests. -TEST(AllPathsKeyGeneratorInclusionTest, InclusionProjectionSingleSubtree) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{g: 1}"), nullptr}; +TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionSingleSubtree) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{g: 1}"), nullptr}; auto inputDoc = fromjson( "{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], " @@ -395,8 +395,8 @@ TEST(AllPathsKeyGeneratorInclusionTest, InclusionProjectionSingleSubtree) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorInclusionTest, InclusionProjectionNestedSubtree) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'g.h': 1}"), nullptr}; +TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionNestedSubtree) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'g.h': 1}"), nullptr}; auto inputDoc = fromjson( "{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], " @@ -419,8 +419,8 @@ TEST(AllPathsKeyGeneratorInclusionTest, InclusionProjectionNestedSubtree) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorInclusionTest, InclusionProjectionMultikeySubtree) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'g.h.j': 1}"), nullptr}; +TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionMultikeySubtree) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'g.h.j': 1}"), nullptr}; auto inputDoc = fromjson( "{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], " @@ -441,8 +441,8 @@ TEST(AllPathsKeyGeneratorInclusionTest, InclusionProjectionMultikeySubtree) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorInclusionTest, InclusionProjectionNestedMultikeySubtree) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'a.e': 1}"), nullptr}; +TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionNestedMultikeySubtree) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'a.e': 1}"), nullptr}; auto inputDoc = fromjson( "{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], " @@ -463,8 +463,8 @@ TEST(AllPathsKeyGeneratorInclusionTest, InclusionProjectionNestedMultikeySubtree ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorInclusionTest, InclusionProjectionMultipleSubtrees) { - AllPathsKeyGenerator keyGen{ +TEST(WildcardKeyGeneratorInclusionTest, InclusionProjectionMultipleSubtrees) { + WildcardKeyGenerator keyGen{ fromjson("{'$**': 1}"), fromjson("{'a.b': 1, 'a.c': 1, 'a.e': 1, 'g.h.i': 1}"), nullptr}; auto inputDoc = fromjson( @@ -491,8 +491,8 @@ TEST(AllPathsKeyGeneratorInclusionTest, InclusionProjectionMultipleSubtrees) { // Explicit exclusion tests. -TEST(AllPathsKeyGeneratorExclusionTest, ExclusionProjectionSingleSubtree) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{g: 0}"), nullptr}; +TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionSingleSubtree) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{g: 0}"), nullptr}; auto inputDoc = fromjson( "{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], " @@ -520,8 +520,8 @@ TEST(AllPathsKeyGeneratorExclusionTest, ExclusionProjectionSingleSubtree) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorExclusionTest, ExclusionProjectionNestedSubtree) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'g.h': 0}"), nullptr}; +TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionNestedSubtree) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'g.h': 0}"), nullptr}; auto inputDoc = fromjson( "{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], " @@ -550,8 +550,8 @@ TEST(AllPathsKeyGeneratorExclusionTest, ExclusionProjectionNestedSubtree) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorExclusionTest, ExclusionProjectionMultikeySubtree) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'g.h.j': 0}"), nullptr}; +TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionMultikeySubtree) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'g.h.j': 0}"), nullptr}; auto inputDoc = fromjson( "{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], " @@ -581,8 +581,8 @@ TEST(AllPathsKeyGeneratorExclusionTest, ExclusionProjectionMultikeySubtree) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorExclusionTest, ExclusionProjectionNestedMultikeySubtree) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'a.e': 0}"), nullptr}; +TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionNestedMultikeySubtree) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'a.e': 0}"), nullptr}; auto inputDoc = fromjson( "{a: [1, 2, {b: 'one', c: 2}, {c: 2, d: 3}, {c: 'two', d: 3, e: [4, 5]}, [6, 7, {f: 8}]], " @@ -614,8 +614,8 @@ TEST(AllPathsKeyGeneratorExclusionTest, ExclusionProjectionNestedMultikeySubtree ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorExclusionTest, ExclusionProjectionMultipleSubtrees) { - AllPathsKeyGenerator keyGen{ +TEST(WildcardKeyGeneratorExclusionTest, ExclusionProjectionMultipleSubtrees) { + WildcardKeyGenerator keyGen{ fromjson("{'$**': 1}"), fromjson("{'a.b': 0, 'a.c': 0, 'a.e': 0, 'g.h.i': 0}"), nullptr}; auto inputDoc = fromjson( @@ -647,8 +647,8 @@ TEST(AllPathsKeyGeneratorExclusionTest, ExclusionProjectionMultipleSubtrees) { // Test _id inclusion and exclusion behaviour. -TEST(AllPathsKeyGeneratorIdTest, ExcludeIdFieldIfProjectionIsEmpty) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldIfProjectionIsEmpty) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, nullptr}; auto inputDoc = fromjson( "{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}"); @@ -671,8 +671,8 @@ TEST(AllPathsKeyGeneratorIdTest, ExcludeIdFieldIfProjectionIsEmpty) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorIdTest, ExcludeIdFieldForSingleSubtreeKeyPattern) { - AllPathsKeyGenerator keyGen{fromjson("{'a.$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldForSingleSubtreeKeyPattern) { + WildcardKeyGenerator keyGen{fromjson("{'a.$**': 1}"), {}, nullptr}; auto inputDoc = fromjson( "{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}"); @@ -693,8 +693,8 @@ TEST(AllPathsKeyGeneratorIdTest, ExcludeIdFieldForSingleSubtreeKeyPattern) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorIdTest, PermitIdFieldAsSingleSubtreeKeyPattern) { - AllPathsKeyGenerator keyGen{fromjson("{'_id.$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorIdTest, PermitIdFieldAsSingleSubtreeKeyPattern) { + WildcardKeyGenerator keyGen{fromjson("{'_id.$**': 1}"), {}, nullptr}; auto inputDoc = fromjson( "{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}"); @@ -712,8 +712,8 @@ TEST(AllPathsKeyGeneratorIdTest, PermitIdFieldAsSingleSubtreeKeyPattern) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorIdTest, PermitIdSubfieldAsSingleSubtreeKeyPattern) { - AllPathsKeyGenerator keyGen{fromjson("{'_id.id1.$**': 1}"), {}, nullptr}; +TEST(WildcardKeyGeneratorIdTest, PermitIdSubfieldAsSingleSubtreeKeyPattern) { + WildcardKeyGenerator keyGen{fromjson("{'_id.id1.$**': 1}"), {}, nullptr}; auto inputDoc = fromjson( "{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}"); @@ -730,8 +730,8 @@ TEST(AllPathsKeyGeneratorIdTest, PermitIdSubfieldAsSingleSubtreeKeyPattern) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorIdTest, ExcludeIdFieldByDefaultForInclusionProjection) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{a: 1}"), nullptr}; +TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldByDefaultForInclusionProjection) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{a: 1}"), nullptr}; auto inputDoc = fromjson( "{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}"); @@ -752,8 +752,8 @@ TEST(AllPathsKeyGeneratorIdTest, ExcludeIdFieldByDefaultForInclusionProjection) ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorIdTest, PermitIdSubfieldInclusionInExplicitProjection) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'_id.id1': 1}"), nullptr}; +TEST(WildcardKeyGeneratorIdTest, PermitIdSubfieldInclusionInExplicitProjection) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'_id.id1': 1}"), nullptr}; auto inputDoc = fromjson( "{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}"); @@ -770,8 +770,8 @@ TEST(AllPathsKeyGeneratorIdTest, PermitIdSubfieldInclusionInExplicitProjection) ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorIdTest, ExcludeIdFieldByDefaultForExclusionProjection) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{a: 0}"), nullptr}; +TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldByDefaultForExclusionProjection) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{a: 0}"), nullptr}; auto inputDoc = fromjson( "{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}"); @@ -789,8 +789,8 @@ TEST(AllPathsKeyGeneratorIdTest, ExcludeIdFieldByDefaultForExclusionProjection) ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorIdTest, PermitIdSubfieldExclusionInExplicitProjection) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'_id.id1': 0}"), nullptr}; +TEST(WildcardKeyGeneratorIdTest, PermitIdSubfieldExclusionInExplicitProjection) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{'_id.id1': 0}"), nullptr}; auto inputDoc = fromjson( "{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}"); @@ -814,8 +814,8 @@ TEST(AllPathsKeyGeneratorIdTest, PermitIdSubfieldExclusionInExplicitProjection) ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorIdTest, IncludeIdFieldIfExplicitlySpecifiedInProjection) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{_id: 1, a: 1}"), nullptr}; +TEST(WildcardKeyGeneratorIdTest, IncludeIdFieldIfExplicitlySpecifiedInProjection) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{_id: 1, a: 1}"), nullptr}; auto inputDoc = fromjson( "{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}"); @@ -838,8 +838,8 @@ TEST(AllPathsKeyGeneratorIdTest, IncludeIdFieldIfExplicitlySpecifiedInProjection ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorIdTest, ExcludeIdFieldIfExplicitlySpecifiedInProjection) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{_id: 0, a: 1}"), nullptr}; +TEST(WildcardKeyGeneratorIdTest, ExcludeIdFieldIfExplicitlySpecifiedInProjection) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{_id: 0, a: 1}"), nullptr}; auto inputDoc = fromjson( "{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}"); @@ -860,8 +860,8 @@ TEST(AllPathsKeyGeneratorIdTest, ExcludeIdFieldIfExplicitlySpecifiedInProjection ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorIdTest, IncludeIdFieldIfExplicitlySpecifiedInExclusionProjection) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{_id: 1, a: 0}"), nullptr}; +TEST(WildcardKeyGeneratorIdTest, IncludeIdFieldIfExplicitlySpecifiedInExclusionProjection) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), fromjson("{_id: 1, a: 0}"), nullptr}; auto inputDoc = fromjson( "{_id: {id1: 1, id2: 2}, a: [1, {b: 1, e: [4]}, [6, 7, {f: 8}]], g: {h: {i: 9, k: 12.0}}}"); @@ -883,9 +883,9 @@ TEST(AllPathsKeyGeneratorIdTest, IncludeIdFieldIfExplicitlySpecifiedInExclusionP // Collation tests. -TEST(AllPathsKeyGeneratorCollationTest, CollationMixedPathAndKeyTypes) { +TEST(WildcardKeyGeneratorCollationTest, CollationMixedPathAndKeyTypes) { CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString); - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, &collator}; + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, &collator}; // Verify that the collation is only applied to String values, but all types are indexed. auto dateVal = "{'$date': 1529453450288}"_sd; @@ -928,8 +928,8 @@ TEST(AllPathsKeyGeneratorCollationTest, CollationMixedPathAndKeyTypes) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorDottedFieldsTest, DoNotIndexDottedFields) { - AllPathsKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, {}}; +TEST(WildcardKeyGeneratorDottedFieldsTest, DoNotIndexDottedFields) { + WildcardKeyGenerator keyGen{fromjson("{'$**': 1}"), {}, {}}; auto inputDoc = fromjson( "{'a.b': 0, '.b': 1, 'b.': 2, a: {'.b': 3, 'b.': 4, 'b.c': 5, 'q': 6}, b: [{'d.e': 7}, {r: " @@ -950,8 +950,8 @@ TEST(AllPathsKeyGeneratorDottedFieldsTest, DoNotIndexDottedFields) { ASSERT(assertKeysetsEqual(expectedMultikeyPaths, multikeyMetadataKeys)); } -TEST(AllPathsKeyGeneratorDottedFieldsTest, DoNotIndexDottedFieldsWithSimilarSubpathInKey) { - AllPathsKeyGenerator keyGen{fromjson("{'a.b.$**': 1}"), {}, {}}; +TEST(WildcardKeyGeneratorDottedFieldsTest, DoNotIndexDottedFieldsWithSimilarSubpathInKey) { + WildcardKeyGenerator keyGen{fromjson("{'a.b.$**': 1}"), {}, {}}; auto inputDoc = fromjson("{'a.b': 0}"); diff --git a/src/mongo/db/index_names.cpp b/src/mongo/db/index_names.cpp index 8f5400e08d9..edff5c2feb5 100644 --- a/src/mongo/db/index_names.cpp +++ b/src/mongo/db/index_names.cpp @@ -41,7 +41,7 @@ const string IndexNames::GEO_2DSPHERE = "2dsphere"; const string IndexNames::TEXT = "text"; const string IndexNames::HASHED = "hashed"; const string IndexNames::BTREE = ""; -const string IndexNames::ALLPATHS = "allPaths"; +const string IndexNames::WILDCARD = "wildcard"; const StringMap<IndexType> kIndexNameToType = { {IndexNames::GEO_2D, INDEX_2D}, @@ -49,7 +49,7 @@ const StringMap<IndexType> kIndexNameToType = { {IndexNames::GEO_2DSPHERE, INDEX_2DSPHERE}, {IndexNames::TEXT, INDEX_TEXT}, {IndexNames::HASHED, INDEX_HASHED}, - {IndexNames::ALLPATHS, INDEX_ALLPATHS}, + {IndexNames::WILDCARD, INDEX_WILDCARD}, }; // static @@ -61,7 +61,7 @@ string IndexNames::findPluginName(const BSONObj& keyPattern) { if (String == e.type()) { return e.String(); } else if ((fieldName == "$**") || fieldName.endsWith(".$**")) { - return IndexNames::ALLPATHS; + return IndexNames::WILDCARD; } else continue; } @@ -74,7 +74,7 @@ bool IndexNames::isKnownName(const string& name) { return name == IndexNames::GEO_2D || name == IndexNames::GEO_2DSPHERE || name == IndexNames::GEO_HAYSTACK || name == IndexNames::TEXT || name == IndexNames::HASHED || name == IndexNames::BTREE || - (getTestCommandsEnabled() && name == IndexNames::ALLPATHS); + (getTestCommandsEnabled() && name == IndexNames::WILDCARD); } // static diff --git a/src/mongo/db/index_names.h b/src/mongo/db/index_names.h index fa97e0f5e22..97825574507 100644 --- a/src/mongo/db/index_names.h +++ b/src/mongo/db/index_names.h @@ -40,13 +40,13 @@ class BSONObj; * We need to know what 'type' an index is in order to plan correctly. */ enum IndexType { - INDEX_ALLPATHS, INDEX_BTREE, INDEX_2D, INDEX_HAYSTACK, INDEX_2DSPHERE, INDEX_TEXT, INDEX_HASHED, + INDEX_WILDCARD, }; /** @@ -55,13 +55,13 @@ enum IndexType { */ class IndexNames { public: - static const std::string ALLPATHS; static const std::string BTREE; static const std::string GEO_2D; static const std::string GEO_2DSPHERE; static const std::string GEO_HAYSTACK; static const std::string HASHED; static const std::string TEXT; + static const std::string WILDCARD; /** * Return the first std::string value in the provided object. For an index key pattern, diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript index 3ce7ee94e67..64018a41388 100644 --- a/src/mongo/db/query/SConscript +++ b/src/mongo/db/query/SConscript @@ -24,7 +24,7 @@ env.Library( "plan_cache_indexability.cpp", "plan_enumerator.cpp", "planner_access.cpp", - "planner_allpaths_helpers.cpp", + "planner_wildcard_helpers.cpp", "planner_analysis.cpp", "planner_ixselect.cpp", "query_planner.cpp", @@ -341,12 +341,12 @@ env.CppUnitTest( env.CppUnitTest( target="query_planner_test", source=[ - "query_planner_all_paths_index_test.cpp", "query_planner_array_test.cpp", "query_planner_collation_test.cpp", "query_planner_geo_test.cpp", "query_planner_partialidx_test.cpp", "query_planner_test.cpp", + "query_planner_wildcard_index_test.cpp", ], LIBDEPS=[ "collation/collator_interface_mock", diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index 958049fbdfd..161b73386dc 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -51,8 +51,8 @@ #include "mongo/db/exec/sort_key_generator.h" #include "mongo/db/exec/subplan.h" #include "mongo/db/exec/update.h" -#include "mongo/db/index/all_paths_access_method.h" #include "mongo/db/index/index_descriptor.h" +#include "mongo/db/index/wildcard_access_method.h" #include "mongo/db/index_names.h" #include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/matcher/extensions_callback_real.h" diff --git a/src/mongo/db/query/index_bounds_builder.cpp b/src/mongo/db/query/index_bounds_builder.cpp index 13d45890e72..fdfcfc2096c 100644 --- a/src/mongo/db/query/index_bounds_builder.cpp +++ b/src/mongo/db/query/index_bounds_builder.cpp @@ -45,8 +45,8 @@ #include "mongo/db/query/expression_index.h" #include "mongo/db/query/expression_index_knobs.h" #include "mongo/db/query/indexability.h" -#include "mongo/db/query/planner_allpaths_helpers.h" #include "mongo/db/query/planner_ixselect.h" +#include "mongo/db/query/planner_wildcard_helpers.h" #include "mongo/db/query/query_knobs.h" #include "mongo/util/log.h" #include "mongo/util/mongoutils/str.h" @@ -57,7 +57,7 @@ namespace mongo { namespace { -namespace app = ::mongo::all_paths_planning; +namespace app = ::mongo::wildcard_planning; // Helper for checking that an OIL "appears" to be ascending given one interval. void assertOILIsAscendingLocally(const vector<Interval>& intervals, size_t idx) { @@ -344,8 +344,8 @@ void IndexBoundsBuilder::translate(const MatchExpression* expr, // Under certain circumstances, queries on a $** index require that the bounds' tightness be // adjusted regardless of the predicate. Having filled out the initial bounds, we apply any // necessary changes to the tightness here. - if (index.type == IndexType::INDEX_ALLPATHS) { - *tightnessOut = app::applyAllPathsIndexScanBoundsTightness(index, *tightnessOut); + if (index.type == IndexType::INDEX_WILDCARD) { + *tightnessOut = app::applyWildcardIndexScanBoundsTightness(index, *tightnessOut); } } diff --git a/src/mongo/db/query/index_entry.h b/src/mongo/db/query/index_entry.h index c032b47d785..c028618394e 100644 --- a/src/mongo/db/query/index_entry.h +++ b/src/mongo/db/query/index_entry.h @@ -87,7 +87,7 @@ struct IndexEntry { std::string catalogName; // A string used for disambiguating multiple IndexEntries with the same catalogName (such - // as in the case with an allPaths index). + // as in the case with a wildcard index). std::string disambiguator; }; diff --git a/src/mongo/db/query/plan_cache.cpp b/src/mongo/db/query/plan_cache.cpp index 49020044448..4fccc01a648 100644 --- a/src/mongo/db/query/plan_cache.cpp +++ b/src/mongo/db/query/plan_cache.cpp @@ -326,16 +326,16 @@ void encodeIndexability(const MatchExpression* tree, const IndexToDiscriminatorMap& discriminators = indexabilityState.getDiscriminators(tree->path()); - IndexToDiscriminatorMap allPathsDiscriminators = - indexabilityState.buildAllPathsDiscriminators(tree->path()); - if (discriminators.empty() && allPathsDiscriminators.empty()) { + IndexToDiscriminatorMap wildcardDiscriminators = + indexabilityState.buildWildcardDiscriminators(tree->path()); + if (discriminators.empty() && wildcardDiscriminators.empty()) { return; } *keyBuilder << kEncodeDiscriminatorsBegin; // For each discriminator on this path, append the character '0' or '1'. encodeIndexabilityForDiscriminators(tree, discriminators, keyBuilder); - encodeIndexabilityForDiscriminators(tree, allPathsDiscriminators, keyBuilder); + encodeIndexabilityForDiscriminators(tree, wildcardDiscriminators, keyBuilder); *keyBuilder << kEncodeDiscriminatorsEnd; } diff --git a/src/mongo/db/query/plan_cache_indexability.cpp b/src/mongo/db/query/plan_cache_indexability.cpp index 353c5c87fe3..462b4ecedc1 100644 --- a/src/mongo/db/query/plan_cache_indexability.cpp +++ b/src/mongo/db/query/plan_cache_indexability.cpp @@ -32,7 +32,7 @@ #include "mongo/base/init.h" #include "mongo/base/owned_pointer_vector.h" -#include "mongo/db/index/all_paths_key_generator.h" +#include "mongo/db/index/wildcard_key_generator.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_algo.h" #include "mongo/db/matcher/expression_internal_expr_eq.h" @@ -112,11 +112,11 @@ void PlanCacheIndexabilityState::processPartialIndex(const std::string& indexNam } } -void PlanCacheIndexabilityState::processAllPathsIndex(const IndexEntry& ie) { - invariant(ie.type == IndexType::INDEX_ALLPATHS); +void PlanCacheIndexabilityState::processWildcardIndex(const IndexEntry& ie) { + invariant(ie.type == IndexType::INDEX_WILDCARD); - _allPathsIndexDiscriminators.emplace_back( - AllPathsKeyGenerator::createProjectionExec(ie.keyPattern, + _wildcardIndexDiscriminators.emplace_back( + WildcardKeyGenerator::createProjectionExec(ie.keyPattern, ie.infoObj.getObjectField("wildcardProjection")), ie.identifier.catalogName, ie.filterExpr, @@ -145,23 +145,23 @@ const IndexToDiscriminatorMap& PlanCacheIndexabilityState::getDiscriminators( return it->second; } -IndexToDiscriminatorMap PlanCacheIndexabilityState::buildAllPathsDiscriminators( +IndexToDiscriminatorMap PlanCacheIndexabilityState::buildWildcardDiscriminators( StringData path) const { IndexToDiscriminatorMap ret; - for (auto&& allPathsDiscriminator : _allPathsIndexDiscriminators) { - if (allPathsDiscriminator.projectionExec->applyProjectionToOneField(path)) { - CompositeIndexabilityDiscriminator& cid = ret[allPathsDiscriminator.catalogName]; + for (auto&& wildcardDiscriminator : _wildcardIndexDiscriminators) { + if (wildcardDiscriminator.projectionExec->applyProjectionToOneField(path)) { + CompositeIndexabilityDiscriminator& cid = ret[wildcardDiscriminator.catalogName]; // We can use these 'shallow' functions because the code building the plan cache key // will descend the match expression for us, and check the discriminator's return value // at each node. - cid.addDiscriminator(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex); + cid.addDiscriminator(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex); cid.addDiscriminator(nodeIsConservativelySupportedBySparseIndex); - cid.addDiscriminator(getCollatedIndexDiscriminator(allPathsDiscriminator.collator)); - if (allPathsDiscriminator.filterExpr) { + cid.addDiscriminator(getCollatedIndexDiscriminator(wildcardDiscriminator.collator)); + if (wildcardDiscriminator.filterExpr) { cid.addDiscriminator( - getPartialIndexDiscriminator(allPathsDiscriminator.filterExpr)); + getPartialIndexDiscriminator(wildcardDiscriminator.filterExpr)); } } } @@ -172,8 +172,8 @@ void PlanCacheIndexabilityState::updateDiscriminators(const std::vector<IndexEnt _pathDiscriminatorsMap = PathDiscriminatorsMap(); for (const IndexEntry& idx : indexEntries) { - if (idx.type == IndexType::INDEX_ALLPATHS) { - processAllPathsIndex(idx); + if (idx.type == IndexType::INDEX_WILDCARD) { + processWildcardIndex(idx); continue; } diff --git a/src/mongo/db/query/plan_cache_indexability.h b/src/mongo/db/query/plan_cache_indexability.h index 7f43a60cace..a79aceaef3d 100644 --- a/src/mongo/db/query/plan_cache_indexability.h +++ b/src/mongo/db/query/plan_cache_indexability.h @@ -96,10 +96,10 @@ public: const IndexToDiscriminatorMap& getDiscriminators(StringData path) const; /** - * Construct an IndexToDiscriminator map for the given path, only for the allPaths indexes + * Construct an IndexToDiscriminator map for the given path, only for the wildcard indexes * which have been included in the indexability state. */ - IndexToDiscriminatorMap buildAllPathsDiscriminators(StringData path) const; + IndexToDiscriminatorMap buildWildcardDiscriminators(StringData path) const; /** * Clears discriminators for all paths, and regenerate them from 'indexEntries'. @@ -114,8 +114,8 @@ private: * every possible field that it indexes, so we have to maintain some special context about the * index. */ - struct AllPathsIndexDiscriminatorContext { - AllPathsIndexDiscriminatorContext(std::unique_ptr<ProjectionExecAgg> proj, + struct WildcardIndexDiscriminatorContext { + WildcardIndexDiscriminatorContext(std::unique_ptr<ProjectionExecAgg> proj, std::string name, const MatchExpression* filter, const CollatorInterface* coll) @@ -169,15 +169,15 @@ private: /** * Adds special state for a $** index. When the discriminators are retrieved for a certain - * path, appropriate discriminators for the allPaths index will be included if it includes the + * path, appropriate discriminators for the wildcard index will be included if it includes the * given path. */ - void processAllPathsIndex(const IndexEntry& ie); + void processWildcardIndex(const IndexEntry& ie); // PathDiscriminatorsMap is a map from field path to index name to IndexabilityDiscriminator. PathDiscriminatorsMap _pathDiscriminatorsMap; - std::vector<AllPathsIndexDiscriminatorContext> _allPathsIndexDiscriminators; + std::vector<WildcardIndexDiscriminatorContext> _wildcardIndexDiscriminators; }; } // namespace mongo diff --git a/src/mongo/db/query/plan_cache_indexability_test.cpp b/src/mongo/db/query/plan_cache_indexability_test.cpp index 6531b5cae30..f0775219d26 100644 --- a/src/mongo/db/query/plan_cache_indexability_test.cpp +++ b/src/mongo/db/query/plan_cache_indexability_test.cpp @@ -409,7 +409,7 @@ TEST(PlanCacheIndexabilityTest, CompoundIndexCollationDiscriminator) { ASSERT(discriminatorsB.find("a_1_b_1") != discriminatorsB.end()); } -TEST(PlanCacheIndexabilityTest, AllPathsDiscriminator) { +TEST(PlanCacheIndexabilityTest, WildcardDiscriminator) { PlanCacheIndexabilityState state; state.updateDiscriminators({IndexEntry(BSON("a.$**" << 1), false, // multikey @@ -419,10 +419,10 @@ TEST(PlanCacheIndexabilityTest, AllPathsDiscriminator) { nullptr, BSONObj())}); - const auto unindexedPathDiscriminators = state.buildAllPathsDiscriminators("notIndexed"); + const auto unindexedPathDiscriminators = state.buildWildcardDiscriminators("notIndexed"); ASSERT_EQ(0U, unindexedPathDiscriminators.size()); - auto discriminatorsA = state.buildAllPathsDiscriminators("a"); + auto discriminatorsA = state.buildWildcardDiscriminators("a"); ASSERT_EQ(1U, discriminatorsA.size()); ASSERT(discriminatorsA.find("indexName") != discriminatorsA.end()); @@ -431,16 +431,16 @@ TEST(PlanCacheIndexabilityTest, AllPathsDiscriminator) { ASSERT_TRUE( disc.isMatchCompatibleWithIndex(parseMatchExpression(fromjson("{a: 'abc'}")).get())); - // Querying for object values isn't support by allPaths indexes. + // Querying for object values isn't support by wildcard indexes. ASSERT_FALSE( disc.isMatchCompatibleWithIndex(parseMatchExpression(fromjson("{a: {b: 1}}")).get())); ASSERT_FALSE(disc.isMatchCompatibleWithIndex(parseMatchExpression(fromjson("{a: {}}")).get())); ASSERT_FALSE( disc.isMatchCompatibleWithIndex(parseMatchExpression(fromjson("{a: {$lt: {}}}")).get())); - // Querying for array values isn't supported by allPaths indexes. + // Querying for array values isn't supported by wildcard indexes. ASSERT_FALSE( disc.isMatchCompatibleWithIndex(parseMatchExpression(fromjson("{a: [1, 2, 3]}")).get())); - // Querying for null isn't supported by allPaths indexes. + // Querying for null isn't supported by wildcard indexes. ASSERT_FALSE( disc.isMatchCompatibleWithIndex(parseMatchExpression(fromjson("{a: null}")).get())); @@ -470,7 +470,7 @@ TEST(PlanCacheIndexabilityTest, AllPathsDiscriminator) { parseMatchExpression(fromjson("{a: {$in: [1, 2, null]}}")).get())); } -TEST(PlanCacheIndexabilityTest, AllPathsWithCollationDiscriminator) { +TEST(PlanCacheIndexabilityTest, WildcardWithCollationDiscriminator) { PlanCacheIndexabilityState state; IndexEntry entry(BSON("a.$**" << 1), false, // multikey @@ -483,10 +483,10 @@ TEST(PlanCacheIndexabilityTest, AllPathsWithCollationDiscriminator) { entry.collator = &collator; state.updateDiscriminators({entry}); - const auto unindexedPathDiscriminators = state.buildAllPathsDiscriminators("notIndexed"); + const auto unindexedPathDiscriminators = state.buildWildcardDiscriminators("notIndexed"); ASSERT_EQ(0U, unindexedPathDiscriminators.size()); - auto discriminatorsA = state.buildAllPathsDiscriminators("a"); + auto discriminatorsA = state.buildWildcardDiscriminators("a"); ASSERT_EQ(1U, discriminatorsA.size()); ASSERT(discriminatorsA.find("indexName") != discriminatorsA.end()); @@ -500,7 +500,7 @@ TEST(PlanCacheIndexabilityTest, AllPathsWithCollationDiscriminator) { parseMatchExpression(fromjson("{a: \"hello world\"}"), &collator).get())); } -TEST(PlanCacheIndexabilityTest, AllPathsPartialIndexDiscriminator) { +TEST(PlanCacheIndexabilityTest, WildcardPartialIndexDiscriminator) { PlanCacheIndexabilityState state; // Need to keep the filter BSON object around for the duration of the test since the match @@ -516,7 +516,7 @@ TEST(PlanCacheIndexabilityTest, AllPathsPartialIndexDiscriminator) { BSONObj()); state.updateDiscriminators({entry}); - auto discriminatorsA = state.buildAllPathsDiscriminators("a"); + auto discriminatorsA = state.buildWildcardDiscriminators("a"); ASSERT_EQ(1U, discriminatorsA.size()); ASSERT(discriminatorsA.find("indexName") != discriminatorsA.end()); diff --git a/src/mongo/db/query/plan_cache_test.cpp b/src/mongo/db/query/plan_cache_test.cpp index f72c3ab15dc..f971200edbf 100644 --- a/src/mongo/db/query/plan_cache_test.cpp +++ b/src/mongo/db/query/plan_cache_test.cpp @@ -1271,9 +1271,9 @@ TEST_F(CachePlanSelectionTest, AndWithinPolygonWithinCenterSphere) { } // $** index -TEST_F(CachePlanSelectionTest, AllPathsIxScan) { +TEST_F(CachePlanSelectionTest, WildcardIxScan) { params.indices.push_back(IndexEntry(BSON("$**" << 1), - IndexType::INDEX_ALLPATHS, + IndexType::INDEX_WILDCARD, false, // multikey {}, // multikey paths {}, // multikeyPathSet @@ -1966,7 +1966,7 @@ TEST(PlanCacheTest, ComputeKeyCollationIndex) { planCache.computeKey(*inContainsStringHasCollation)); } -TEST(PlanCacheTest, ComputeKeyAllPathsIndex) { +TEST(PlanCacheTest, ComputeKeyWildcardIndex) { PlanCache planCache; IndexEntry entry(BSON("a.$**" << 1), false, // multikey @@ -2007,8 +2007,8 @@ TEST(PlanCacheTest, ComputeKeyAllPathsIndex) { ASSERT_EQ(planCache.computeKey(*usesPathWithObject), planCache.computeKey(*usesPathWithEmptyObject)); - // The query on 'b' should have a completely different plan cache key (both with and without an - // allPaths index). + // The query on 'b' should have a completely different plan cache key (both with and without a + // wildcard index). ASSERT_NE(planCacheWithNoIndexes.computeKey(*usesPathWithScalar), planCacheWithNoIndexes.computeKey(*doesNotUsePath)); ASSERT_NE(planCache.computeKey(*usesPathWithScalar), planCache.computeKey(*doesNotUsePath)); diff --git a/src/mongo/db/query/planner_access.cpp b/src/mongo/db/query/planner_access.cpp index 2be774dafcf..026e994b301 100644 --- a/src/mongo/db/query/planner_access.cpp +++ b/src/mongo/db/query/planner_access.cpp @@ -45,7 +45,7 @@ #include "mongo/db/query/index_bounds_builder.h" #include "mongo/db/query/index_tag.h" #include "mongo/db/query/indexability.h" -#include "mongo/db/query/planner_allpaths_helpers.h" +#include "mongo/db/query/planner_wildcard_helpers.h" #include "mongo/db/query/query_knobs.h" #include "mongo/db/query/query_planner.h" #include "mongo/db/query/query_planner_common.h" @@ -57,7 +57,7 @@ namespace { using namespace mongo; -namespace app = ::mongo::all_paths_planning; +namespace app = ::mongo::wildcard_planning; namespace dps = ::mongo::dotted_path_support; /** @@ -530,10 +530,10 @@ void QueryPlannerAccess::finishTextNode(QuerySolutionNode* node, const IndexEntr tn->indexPrefix = prefixBob.obj(); } -void QueryPlannerAccess::finishAllPathsIndexScanNode(QuerySolutionNode* node, +void QueryPlannerAccess::finishWildcardIndexScanNode(QuerySolutionNode* node, const IndexEntry& plannerIndex) { // We should only ever reach this point if we are an IndexScanNode for a $** index. - invariant(plannerIndex.type == IndexType::INDEX_ALLPATHS); + invariant(plannerIndex.type == IndexType::INDEX_WILDCARD); invariant(node && node->getType() == STAGE_IXSCAN); // Sanity check the QuerySolutionNode's copy of the IndexEntry. @@ -676,8 +676,8 @@ void QueryPlannerAccess::finishLeafNode(QuerySolutionNode* node, const IndexEntr } // If this is a $** index, update and populate the keyPattern, bounds, and multikeyPaths. - if (index.type == IndexType::INDEX_ALLPATHS) { - finishAllPathsIndexScanNode(node, index); + if (index.type == IndexType::INDEX_WILDCARD) { + finishWildcardIndexScanNode(node, index); } // Find the first field in the scan's bounds that was not filled out. @@ -1068,12 +1068,12 @@ std::unique_ptr<QuerySolutionNode> QueryPlannerAccess::buildIndexedAnd( andResult = std::move(ixscanNodes[0]); } else { // $** indexes are prohibited from participating in either AND_SORTED or AND_HASH. - const bool allPathsIndexInvolvedInIntersection = + const bool wildcardIndexInvolvedInIntersection = std::any_of(ixscanNodes.begin(), ixscanNodes.end(), [](const auto& ixScan) { return ixScan->getType() == StageType::STAGE_IXSCAN && - static_cast<IndexScanNode*>(ixScan.get())->index.type == INDEX_ALLPATHS; + static_cast<IndexScanNode*>(ixScan.get())->index.type == INDEX_WILDCARD; }); - if (allPathsIndexInvolvedInIntersection) { + if (wildcardIndexInvolvedInIntersection) { return nullptr; } diff --git a/src/mongo/db/query/planner_access.h b/src/mongo/db/query/planner_access.h index cf559315f2b..fec5ef6b793 100644 --- a/src/mongo/db/query/planner_access.h +++ b/src/mongo/db/query/planner_access.h @@ -388,7 +388,7 @@ private: static void finishTextNode(QuerySolutionNode* node, const IndexEntry& index); - static void finishAllPathsIndexScanNode(QuerySolutionNode* node, const IndexEntry& index); + static void finishWildcardIndexScanNode(QuerySolutionNode* node, const IndexEntry& index); /** * Add the filter 'match' to the query solution node 'node'. Takes diff --git a/src/mongo/db/query/planner_ixselect.cpp b/src/mongo/db/query/planner_ixselect.cpp index 8dd796ac18c..8a7f005d9c1 100644 --- a/src/mongo/db/query/planner_ixselect.cpp +++ b/src/mongo/db/query/planner_ixselect.cpp @@ -34,8 +34,8 @@ #include "mongo/base/simple_string_data_comparator.h" #include "mongo/db/geo/hash.h" -#include "mongo/db/index/all_paths_key_generator.h" #include "mongo/db/index/s2_common.h" +#include "mongo/db/index/wildcard_key_generator.h" #include "mongo/db/index_names.h" #include "mongo/db/matcher/expression_algo.h" #include "mongo/db/matcher/expression_geo.h" @@ -44,7 +44,7 @@ #include "mongo/db/query/collation/collator_interface.h" #include "mongo/db/query/index_tag.h" #include "mongo/db/query/indexability.h" -#include "mongo/db/query/planner_allpaths_helpers.h" +#include "mongo/db/query/planner_wildcard_helpers.h" #include "mongo/db/query/query_planner_common.h" #include "mongo/util/log.h" @@ -52,31 +52,31 @@ namespace mongo { namespace { -namespace app = ::mongo::all_paths_planning; +namespace app = ::mongo::wildcard_planning; std::size_t numPathComponents(StringData path) { return FieldRef{path}.numParts(); } /** - * Given a single allPaths index, and a set of fields which are being queried, create 'mock' + * Given a single wildcard index, and a set of fields which are being queried, create 'mock' * IndexEntry for each of the appropriate fields. */ -void expandIndex(const IndexEntry& allPathsIndex, +void expandIndex(const IndexEntry& wildcardIndex, const stdx::unordered_set<std::string>& fields, vector<IndexEntry>* out) { invariant(out); - invariant(allPathsIndex.type == INDEX_ALLPATHS); + invariant(wildcardIndex.type == INDEX_WILDCARD); // Should only have one field of the form {"path.$**" : 1}. - invariant(allPathsIndex.keyPattern.nFields() == 1); + invariant(wildcardIndex.keyPattern.nFields() == 1); // $** indexes do not keep the multikey metadata inside the index catalog entry, as the amount // of metadata is not bounded. We do not expect IndexEntry objects for $** indexes to have a // fixed-size vector of multikey metadata until after they are expanded. - invariant(allPathsIndex.multikeyPaths.empty()); + invariant(wildcardIndex.multikeyPaths.empty()); - const auto projExec = AllPathsKeyGenerator::createProjectionExec( - allPathsIndex.keyPattern, allPathsIndex.infoObj.getObjectField("wildcardProjection")); + const auto projExec = WildcardKeyGenerator::createProjectionExec( + wildcardIndex.keyPattern, wildcardIndex.infoObj.getObjectField("wildcardProjection")); const auto projectedFields = projExec->applyProjectionToFields(fields); @@ -91,8 +91,8 @@ void expandIndex(const IndexEntry& allPathsIndex, // in-memory. Here we convert this set of all multikey paths into a MultikeyPaths vector // which will indicate to the downstream planning code which components of 'fieldName' are // multikey. - auto multikeyPaths = app::buildMultiKeyPathsForExpandedAllPathsIndexEntry( - queryPath, allPathsIndex.multikeyPathSet); + auto multikeyPaths = app::buildMultiKeyPathsForExpandedWildcardIndexEntry( + queryPath, wildcardIndex.multikeyPathSet); // Check whether a query on the current fieldpath is answerable by the $** index, given any // numerical path components that may be present in the path string. @@ -109,8 +109,8 @@ void expandIndex(const IndexEntry& allPathsIndex, invariant(multikeyPaths.size() == 1u); const bool isMultikey = !multikeyPaths[0].empty(); - IndexEntry entry(BSON(fieldName << allPathsIndex.keyPattern.firstElement()), - IndexType::INDEX_ALLPATHS, + IndexEntry entry(BSON(fieldName << wildcardIndex.keyPattern.firstElement()), + IndexType::INDEX_WILDCARD, isMultikey, std::move(multikeyPaths), // Expanded index entries always use the fixed-size multikey paths @@ -118,17 +118,17 @@ void expandIndex(const IndexEntry& allPathsIndex, {}, true, // sparse false, // unique - {allPathsIndex.identifier.catalogName, fieldName}, - allPathsIndex.filterExpr, - allPathsIndex.infoObj, - allPathsIndex.collator); + {wildcardIndex.identifier.catalogName, fieldName}, + wildcardIndex.filterExpr, + wildcardIndex.infoObj, + wildcardIndex.collator); invariant("$_path"_sd != fieldName); out->push_back(std::move(entry)); } } -bool canUseAllPathsIndex(BSONElement elt, MatchExpression::MatchType matchType) { +bool canUseWildcardIndex(BSONElement elt, MatchExpression::MatchType matchType) { if (elt.type() == BSONType::Object) { return false; } @@ -370,7 +370,7 @@ std::vector<IndexEntry> QueryPlannerIXSelect::expandIndexes( const std::vector<IndexEntry>& relevantIndices) { std::vector<IndexEntry> out; for (auto&& entry : relevantIndices) { - if (entry.type == IndexType::INDEX_ALLPATHS) { + if (entry.type == IndexType::INDEX_WILDCARD) { expandIndex(entry, fields, &out); } else { out.push_back(entry); @@ -513,7 +513,7 @@ bool QueryPlannerIXSelect::_compatible(const BSONElement& keyPatternElt, } } - if (index.type == IndexType::INDEX_ALLPATHS && !nodeIsSupportedByAllPathsIndex(node)) { + if (index.type == IndexType::INDEX_WILDCARD && !nodeIsSupportedByWildcardIndex(node)) { return false; } @@ -652,8 +652,8 @@ bool QueryPlannerIXSelect::nodeIsSupportedBySparseIndex(const MatchExpression* q return true; } -bool QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex(const MatchExpression* queryExpr) { - // AllPaths indexes only store index keys for "leaf" nodes in an object. That is, they do not +bool QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex(const MatchExpression* queryExpr) { + // Wildcard indexes only store index keys for "leaf" nodes in an object. That is, they do not // store keys for nested objects, meaning that any kind of comparison to an object or array // cannot be answered by the index (including with a $in). @@ -661,14 +661,14 @@ bool QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex(const MatchExpression* const ComparisonMatchExpression* cmpExpr = static_cast<const ComparisonMatchExpression*>(queryExpr); - return canUseAllPathsIndex(cmpExpr->getData(), cmpExpr->matchType()); + return canUseWildcardIndex(cmpExpr->getData(), cmpExpr->matchType()); } else if (queryExpr->matchType() == MatchExpression::MATCH_IN) { const auto* queryExprIn = static_cast<const InMatchExpression*>(queryExpr); return std::all_of( queryExprIn->getEqualities().begin(), queryExprIn->getEqualities().end(), - [](const BSONElement& elt) { return canUseAllPathsIndex(elt, MatchExpression::EQ); }); + [](const BSONElement& elt) { return canUseWildcardIndex(elt, MatchExpression::EQ); }); } return true; @@ -766,7 +766,7 @@ void QueryPlannerIXSelect::_rateIndices(MatchExpression* node, // static void QueryPlannerIXSelect::stripInvalidAssignments(MatchExpression* node, const vector<IndexEntry>& indices) { - stripInvalidAssignmentsToAllPathsIndexes(node, indices); + stripInvalidAssignmentsToWildcardIndexes(node, indices); stripInvalidAssignmentsToTextIndexes(node, indices); if (MatchExpression::GEO != node->matchType() && @@ -955,13 +955,13 @@ void QueryPlannerIXSelect::stripInvalidAssignmentsToPartialIndices( } // -// AllPaths index invalid assignments. +// Wildcard index invalid assignments. // -void QueryPlannerIXSelect::stripInvalidAssignmentsToAllPathsIndexes( +void QueryPlannerIXSelect::stripInvalidAssignmentsToWildcardIndexes( MatchExpression* root, const vector<IndexEntry>& indices) { for (size_t idx = 0; idx < indices.size(); ++idx) { // Skip over all indexes except $**. - if (indices[idx].type != IndexType::INDEX_ALLPATHS) { + if (indices[idx].type != IndexType::INDEX_WILDCARD) { continue; } // If we have a $** index, check whether we have a TEXT node in the MatchExpression tree. diff --git a/src/mongo/db/query/planner_ixselect.h b/src/mongo/db/query/planner_ixselect.h index 01123e652b8..e2591ab3650 100644 --- a/src/mongo/db/query/planner_ixselect.h +++ b/src/mongo/db/query/planner_ixselect.h @@ -152,9 +152,9 @@ public: const std::vector<IndexEntry>& relevantIndices); /** - * Check if this match expression is a leaf and is supported by an allPaths index. + * Check if this match expression is a leaf and is supported by a wildcard index. */ - static bool nodeIsSupportedByAllPathsIndex(const MatchExpression* queryExpr); + static bool nodeIsSupportedByWildcardIndex(const MatchExpression* queryExpr); /* * Return true if the given match expression can use a sparse index, false otherwise. This will @@ -245,14 +245,14 @@ private: const std::vector<IndexEntry>& indices); /** - * This function strips RelevantTag assignments to expanded 'allPaths' indexes, in cases where + * This function strips RelevantTag assignments to expanded 'wildcard' indexes, in cases where * the assignment is incompatible with the query. * - * Specifically, if the query has a TEXT node with both 'text' and 'allPaths' indexes present, - * then the 'allPaths' index will mark itself as relevant to the '_fts' path reported by the - * TEXT node. We therefore remove any such misassigned 'allPaths' tags here. + * Specifically, if the query has a TEXT node with both 'text' and 'wildcard' indexes present, + * then the 'wildcard' index will mark itself as relevant to the '_fts' path reported by the + * TEXT node. We therefore remove any such misassigned 'wildcard' tags here. */ - static void stripInvalidAssignmentsToAllPathsIndexes(MatchExpression* root, + static void stripInvalidAssignmentsToWildcardIndexes(MatchExpression* root, const std::vector<IndexEntry>& indices); /** diff --git a/src/mongo/db/query/planner_ixselect_test.cpp b/src/mongo/db/query/planner_ixselect_test.cpp index 20bdf3f3d5a..bb51baa461a 100644 --- a/src/mongo/db/query/planner_ixselect_test.cpp +++ b/src/mongo/db/query/planner_ixselect_test.cpp @@ -1288,7 +1288,7 @@ bool indexEntryKeyPatternsMatch(vector<BSONObj>* keyPatterns, vector<IndexEntry> }); } -TEST(QueryPlannerIXSelectTest, ExpandAllPathsIndices) { +TEST(QueryPlannerIXSelectTest, ExpandWildcardIndices) { const auto indexEntry = makeIndexEntry(BSON("$**" << 1), {}); // Case where no fields are specified. @@ -1302,15 +1302,15 @@ TEST(QueryPlannerIXSelectTest, ExpandAllPathsIndices) { std::vector<BSONObj> expectedKeyPatterns = {BSON("fieldA" << 1), BSON("fieldB" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); - const auto allPathsIndexWithSubpath = makeIndexEntry(BSON("a.b.$**" << 1), {}); + const auto wildcardIndexWithSubpath = makeIndexEntry(BSON("a.b.$**" << 1), {}); fields = {"a.b", "a.b.c", "a.d"}; - result = QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexWithSubpath}); + result = QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexWithSubpath}); expectedKeyPatterns = {BSON("a.b" << 1), BSON("a.b.c" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, ExpandAllPathsIndicesInPresenceOfOtherIndices) { - auto allPathsIndexEntry = makeIndexEntry(BSON("$**" << 1), {}); +TEST(QueryPlannerIXSelectTest, ExpandWildcardIndicesInPresenceOfOtherIndices) { + auto wildcardIndexEntry = makeIndexEntry(BSON("$**" << 1), {}); auto aIndexEntry = makeIndexEntry(BSON("fieldA" << 1), {}); auto bIndexEntry = makeIndexEntry(BSON("fieldB" << 1), {}); auto abIndexEntry = makeIndexEntry(BSON("fieldA" << 1 << "fieldB" << 1), {}); @@ -1319,18 +1319,18 @@ TEST(QueryPlannerIXSelectTest, ExpandAllPathsIndicesInPresenceOfOtherIndices) { std::vector<BSONObj> expectedKeyPatterns = { BSON("fieldA" << 1), BSON("fieldA" << 1), BSON("fieldB" << 1), BSON("fieldC" << 1)}; - auto result = QueryPlannerIXSelect::expandIndexes(fields, {aIndexEntry, allPathsIndexEntry}); + auto result = QueryPlannerIXSelect::expandIndexes(fields, {aIndexEntry, wildcardIndexEntry}); ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); result.clear(); expectedKeyPatterns = { BSON("fieldB" << 1), BSON("fieldA" << 1), BSON("fieldB" << 1), BSON("fieldC" << 1)}; - result = QueryPlannerIXSelect::expandIndexes(fields, {bIndexEntry, allPathsIndexEntry}); + result = QueryPlannerIXSelect::expandIndexes(fields, {bIndexEntry, wildcardIndexEntry}); ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); result.clear(); result = - QueryPlannerIXSelect::expandIndexes(fields, {aIndexEntry, allPathsIndexEntry, bIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {aIndexEntry, wildcardIndexEntry, bIndexEntry}); expectedKeyPatterns = {BSON("fieldA" << 1), BSON("fieldA" << 1), BSON("fieldB" << 1), @@ -1339,7 +1339,7 @@ TEST(QueryPlannerIXSelectTest, ExpandAllPathsIndicesInPresenceOfOtherIndices) { ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); result.clear(); - result = QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry, abIndexEntry}); + result = QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry, abIndexEntry}); expectedKeyPatterns = {BSON("fieldA" << 1), BSON("fieldB" << 1), BSON("fieldC" << 1), @@ -1349,11 +1349,11 @@ TEST(QueryPlannerIXSelectTest, ExpandAllPathsIndicesInPresenceOfOtherIndices) { } TEST(QueryPlannerIXSelectTest, ExpandedIndexEntriesAreCorrectlyMarkedAsMultikeyOrNonMultikey) { - auto allPathsIndexEntry = makeIndexEntry(BSON("$**" << 1), {}, {FieldRef{"a"}}); + auto wildcardIndexEntry = makeIndexEntry(BSON("$**" << 1), {}, {FieldRef{"a"}}); const stdx::unordered_set<string> fields = {"a.b", "c.d"}; std::vector<BSONObj> expectedKeyPatterns = {BSON("a.b" << 1), BSON("c.d" << 1)}; - auto result = QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + auto result = QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); for (auto&& entry : result) { @@ -1371,7 +1371,7 @@ TEST(QueryPlannerIXSelectTest, ExpandedIndexEntriesAreCorrectlyMarkedAsMultikeyO } } -TEST(QueryPlannerIXSelectTest, AllPathsIndexExpansionExcludesIdField) { +TEST(QueryPlannerIXSelectTest, WildcardIndexExpansionExcludesIdField) { const auto indexEntry = makeIndexEntry(BSON("$**" << 1), {}); stdx::unordered_set<string> fields = {"_id", "abc", "def"}; @@ -1381,14 +1381,14 @@ TEST(QueryPlannerIXSelectTest, AllPathsIndexExpansionExcludesIdField) { ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesExpandedEntryHasCorrectProperties) { - auto allPathsIndexEntry = makeIndexEntry(BSON("$**" << 1), {}); - allPathsIndexEntry.identifier = IndexEntry::Identifier("someIndex"); +TEST(QueryPlannerIXSelectTest, WildcardIndicesExpandedEntryHasCorrectProperties) { + auto wildcardIndexEntry = makeIndexEntry(BSON("$**" << 1), {}); + wildcardIndexEntry.identifier = IndexEntry::Identifier("someIndex"); stdx::unordered_set<string> fields = {"abc", "def"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = {BSON("abc" << 1), BSON("def" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); @@ -1400,57 +1400,57 @@ TEST(QueryPlannerIXSelectTest, AllPathsIndicesExpandedEntryHasCorrectProperties) ASSERT_EQ(ie.multikeyPaths.size(), 1u); ASSERT_TRUE(ie.multikeyPaths[0].empty()); - // AllPaths indices are always sparse. + // Wildcard indices are always sparse. ASSERT_TRUE(ie.sparse); - // AllPaths indexes are never unique. + // Wildcard indexes are never unique. ASSERT_FALSE(ie.unique); ASSERT_EQ(ie.identifier, - IndexEntry::Identifier(allPathsIndexEntry.identifier.catalogName, + IndexEntry::Identifier(wildcardIndexEntry.identifier.catalogName, ie.keyPattern.firstElementFieldName())); } } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesExcludeNonMatchingKeySubpath) { - auto allPathsIndexEntry = makeIndexEntry(BSON("subpath.$**" << 1), {}); +TEST(QueryPlannerIXSelectTest, WildcardIndicesExcludeNonMatchingKeySubpath) { + auto wildcardIndexEntry = makeIndexEntry(BSON("subpath.$**" << 1), {}); stdx::unordered_set<string> fields = {"abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = { BSON("subpath.abc" << 1), BSON("subpath.def" << 1), BSON("subpath" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesExcludeNonMatchingPathsWithInclusionProjection) { - auto allPathsIndexEntry = makeIndexEntryWithInfoObj( +TEST(QueryPlannerIXSelectTest, WildcardIndicesExcludeNonMatchingPathsWithInclusionProjection) { + auto wildcardIndexEntry = makeIndexEntryWithInfoObj( BSON("$**" << 1), {}, BSON("wildcardProjection" << BSON("abc" << 1 << "subpath.abc" << 1))); stdx::unordered_set<string> fields = {"abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = {BSON("abc" << 1), BSON("subpath.abc" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesExcludeNonMatchingPathsWithExclusionProjection) { - auto allPathsIndexEntry = makeIndexEntryWithInfoObj( +TEST(QueryPlannerIXSelectTest, WildcardIndicesExcludeNonMatchingPathsWithExclusionProjection) { + auto wildcardIndexEntry = makeIndexEntryWithInfoObj( BSON("$**" << 1), {}, BSON("wildcardProjection" << BSON("abc" << 0 << "subpath.abc" << 0))); stdx::unordered_set<string> fields = {"abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = { BSON("def" << 1), BSON("subpath.def" << 1), BSON("subpath" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesWithInclusionProjectionAllowIdExclusion) { - auto allPathsIndexEntry = makeIndexEntryWithInfoObj( +TEST(QueryPlannerIXSelectTest, WildcardIndicesWithInclusionProjectionAllowIdExclusion) { + auto wildcardIndexEntry = makeIndexEntryWithInfoObj( BSON("$**" << 1), {}, BSON("wildcardProjection" << BSON("_id" << 0 << "abc" << 1 << "subpath.abc" << 1))); @@ -1459,13 +1459,13 @@ TEST(QueryPlannerIXSelectTest, AllPathsIndicesWithInclusionProjectionAllowIdExcl "_id", "abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = {BSON("abc" << 1), BSON("subpath.abc" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesWithInclusionProjectionAllowIdInclusion) { - auto allPathsIndexEntry = makeIndexEntryWithInfoObj( +TEST(QueryPlannerIXSelectTest, WildcardIndicesWithInclusionProjectionAllowIdInclusion) { + auto wildcardIndexEntry = makeIndexEntryWithInfoObj( BSON("$**" << 1), {}, BSON("wildcardProjection" << BSON("_id" << 1 << "abc" << 1 << "subpath.abc" << 1))); @@ -1474,14 +1474,14 @@ TEST(QueryPlannerIXSelectTest, AllPathsIndicesWithInclusionProjectionAllowIdIncl "_id", "abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = { BSON("_id" << 1), BSON("abc" << 1), BSON("subpath.abc" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesWithExclusionProjectionAllowIdInclusion) { - auto allPathsIndexEntry = makeIndexEntryWithInfoObj( +TEST(QueryPlannerIXSelectTest, WildcardIndicesWithExclusionProjectionAllowIdInclusion) { + auto wildcardIndexEntry = makeIndexEntryWithInfoObj( BSON("$**" << 1), {}, BSON("wildcardProjection" << BSON("_id" << 1 << "abc" << 0 << "subpath.abc" << 0))); @@ -1490,42 +1490,42 @@ TEST(QueryPlannerIXSelectTest, AllPathsIndicesWithExclusionProjectionAllowIdIncl "_id", "abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = { BSON("_id" << 1), BSON("def" << 1), BSON("subpath.def" << 1), BSON("subpath" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndicesIncludeMatchingInternalNodes) { - auto allPathsIndexEntry = makeIndexEntryWithInfoObj( +TEST(QueryPlannerIXSelectTest, WildcardIndicesIncludeMatchingInternalNodes) { + auto wildcardIndexEntry = makeIndexEntryWithInfoObj( BSON("$**" << 1), {}, BSON("wildcardProjection" << BSON("_id" << 1 << "subpath" << 1))); stdx::unordered_set<string> fields = { "_id", "abc", "def", "subpath.abc", "subpath.def", "subpath"}; std::vector<IndexEntry> result = - QueryPlannerIXSelect::expandIndexes(fields, {allPathsIndexEntry}); + QueryPlannerIXSelect::expandIndexes(fields, {wildcardIndexEntry}); std::vector<BSONObj> expectedKeyPatterns = { BSON("_id" << 1), BSON("subpath.abc" << 1), BSON("subpath.def" << 1), BSON("subpath" << 1)}; ASSERT_TRUE(indexEntryKeyPatternsMatch(&expectedKeyPatterns, &result)); } -TEST(QueryPlannerIXSelectTest, AllPathsIndexSupported) { - ASSERT_FALSE(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex( +TEST(QueryPlannerIXSelectTest, WildcardIndexSupported) { + ASSERT_FALSE(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex( parseMatchExpression(fromjson("{x: {abc: 1}}")).get())); - ASSERT_FALSE(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex( + ASSERT_FALSE(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex( parseMatchExpression(fromjson("{x: {$lt: {abc: 1}}}")).get())); - ASSERT_FALSE(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex( + ASSERT_FALSE(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex( parseMatchExpression(fromjson("{x: {$in: [1, 2, 3, {abc: 1}]}}")).get())); } -TEST(QueryPlannerIXSelectTest, AllPathsIndexSupportedDoesNotTraverse) { +TEST(QueryPlannerIXSelectTest, WildcardIndexSupportedDoesNotTraverse) { // The function will not traverse a node's children. - ASSERT_TRUE(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex( + ASSERT_TRUE(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex( parseMatchExpression(fromjson("{$or: [{z: {abc: 1}}]}")).get())); - ASSERT_TRUE(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex( + ASSERT_TRUE(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex( parseMatchExpression(fromjson("{x: 5, y: {abc: 1}}")).get())); - ASSERT_TRUE(QueryPlannerIXSelect::nodeIsSupportedByAllPathsIndex( + ASSERT_TRUE(QueryPlannerIXSelect::nodeIsSupportedByWildcardIndex( parseMatchExpression(fromjson("{x: {$ne: {abc: 1}}}")).get())); } diff --git a/src/mongo/db/query/planner_allpaths_helpers.cpp b/src/mongo/db/query/planner_wildcard_helpers.cpp index b56de29e577..6f44f0eb50c 100644 --- a/src/mongo/db/query/planner_allpaths_helpers.cpp +++ b/src/mongo/db/query/planner_wildcard_helpers.cpp @@ -30,7 +30,7 @@ #include "mongo/platform/basic.h" -#include "mongo/db/query/planner_allpaths_helpers.h" +#include "mongo/db/query/planner_wildcard_helpers.h" #include <vector> @@ -38,7 +38,7 @@ #include "mongo/util/log.h" namespace mongo { -namespace all_paths_planning { +namespace wildcard_planning { namespace { /** * Compares the path 'fieldNameOrArrayIndexPath' to 'staticComparisonPath', ignoring any array @@ -136,7 +136,7 @@ FieldRef pathWithoutSpecifiedComponents(const FieldRef& path, } } // namespace -MultikeyPaths buildMultiKeyPathsForExpandedAllPathsIndexEntry( +MultikeyPaths buildMultiKeyPathsForExpandedWildcardIndexEntry( const FieldRef& indexedPath, const std::set<FieldRef>& multikeyPathSet) { FieldRef pathToLookup; std::set<std::size_t> multikeyPaths; @@ -155,7 +155,7 @@ std::set<FieldRef> generateFieldNameOrArrayIndexPathSet(const std::set<std::size // The algorithm is unavoidably O(n2^n), but we enforce that 'n' is never more than single // digits during the planner's index selection phase. const auto potentialArrayIndices = findArrayIndexPathComponents(multikeyPaths, queryPath); - invariant(potentialArrayIndices.size() <= kAllPathsMaxArrayIndexTraversalDepth); + invariant(potentialArrayIndices.size() <= kWildcardMaxArrayIndexTraversalDepth); invariant(potentialArrayIndices.size() < sizeof(size_t) * 8u); // We iterate over every value [0..2^n), where 'n' is the size of 'potentialArrayIndices', // treating each value as a 'bitMask' of 'n' bits. Each bit in 'bitMask' represents the @@ -178,13 +178,13 @@ std::set<FieldRef> generateFieldNameOrArrayIndexPathSet(const std::set<std::size return paths; } -BoundsTightness applyAllPathsIndexScanBoundsTightness(const IndexEntry& index, +BoundsTightness applyWildcardIndexScanBoundsTightness(const IndexEntry& index, BoundsTightness tightnessIn) { // This method should only ever be called for a $** IndexEntry. We expect to be called during - // planning, *before* finishAllPathsIndexScanNode has been invoked. The IndexEntry should thus + // planning, *before* finishWildcardIndexScanNode has been invoked. The IndexEntry should thus // only have a single keyPattern field and multikeyPath entry, but this is sufficient to // determine whether it will be necessary to adjust the tightness. - invariant(index.type == IndexType::INDEX_ALLPATHS); + invariant(index.type == IndexType::INDEX_WILDCARD); invariant(index.keyPattern.nFields() == 1); invariant(index.multikeyPaths.size() == 1); @@ -217,10 +217,10 @@ bool validateNumericPathComponents(const MultikeyPaths& multikeyPaths, // To support $** fieldname-or-array-index semantics, the planner must generate the power set of // all paths with and without array indices. Because this is O(2^n), we decline to answer // queries that traverse more than 8 levels of array indices. - if (arrayIndices.size() > kAllPathsMaxArrayIndexTraversalDepth) { + if (arrayIndices.size() > kWildcardMaxArrayIndexTraversalDepth) { LOG(2) << "Declining to answer query on field '" << queryPath.dottedField() << "' with $** index, as it traverses through more than " - << kAllPathsMaxArrayIndexTraversalDepth << " nested array indices."; + << kWildcardMaxArrayIndexTraversalDepth << " nested array indices."; return false; } // If 'includedPaths' is empty, then either the $** projection is an exclusion, or no explicit @@ -245,5 +245,5 @@ bool validateNumericPathComponents(const MultikeyPaths& multikeyPaths, return arrayIndices[0] >= includePath->numParts(); } -} // namespace all_paths_planning +} // namespace wildcard_planning } // namespace mongo diff --git a/src/mongo/db/query/planner_allpaths_helpers.h b/src/mongo/db/query/planner_wildcard_helpers.h index 4bbb333dead..7e56adb1ba0 100644 --- a/src/mongo/db/query/planner_allpaths_helpers.h +++ b/src/mongo/db/query/planner_wildcard_helpers.h @@ -36,7 +36,7 @@ #include "mongo/db/query/query_solution.h" namespace mongo { -namespace all_paths_planning { +namespace wildcard_planning { using BoundsTightness = IndexBoundsBuilder::BoundsTightness; @@ -44,13 +44,13 @@ using BoundsTightness = IndexBoundsBuilder::BoundsTightness; * Specifies the maximum depth of nested array indices through which a query may traverse before a * $** declines to answer it, due to the exponential complexity of the bounds required. */ -static constexpr size_t kAllPathsMaxArrayIndexTraversalDepth = 8u; +static constexpr size_t kWildcardMaxArrayIndexTraversalDepth = 8u; /** * Returns a MultikeyPaths which indicates which components of 'indexedPath' are multikey, by * looking up multikeyness in 'multikeyPathSet'. */ -MultikeyPaths buildMultiKeyPathsForExpandedAllPathsIndexEntry( +MultikeyPaths buildMultiKeyPathsForExpandedWildcardIndexEntry( const FieldRef& indexedPath, const std::set<FieldRef>& multikeyPathSet); /** @@ -71,7 +71,7 @@ std::set<FieldRef> generateFieldNameOrArrayIndexPathSet(const std::set<std::size * predicate. Given an IndexEntry representing an expanded $** index, we apply any necessary changes * to the tightness here. */ -BoundsTightness applyAllPathsIndexScanBoundsTightness(const IndexEntry& index, +BoundsTightness applyWildcardIndexScanBoundsTightness(const IndexEntry& index, BoundsTightness tightnessIn); /** @@ -79,7 +79,7 @@ BoundsTightness applyAllPathsIndexScanBoundsTightness(const IndexEntry& index, * by the $** index, true otherwise. Specifically, the $** index cannot answer the query if either * of the following scenarios occur: * - * - The query path traverses through more than 'kAllPathsMaxArrayIndexTraversalDepth' nested arrays + * - The query path traverses through more than 'kWildcardMaxArrayIndexTraversalDepth' nested arrays * via explicit array indices. * - The query path lies along a $** projection through an array index. * @@ -97,5 +97,5 @@ bool validateNumericPathComponents(const MultikeyPaths& multikeyPaths, const std::set<FieldRef>& includedPaths, const FieldRef& queryPath); -} // namespace all_paths_planning +} // namespace wildcard_planning } // namespace mongo diff --git a/src/mongo/db/query/query_planner.cpp b/src/mongo/db/query/query_planner.cpp index c7492757b20..c32d0343a1c 100644 --- a/src/mongo/db/query/query_planner.cpp +++ b/src/mongo/db/query/query_planner.cpp @@ -38,7 +38,7 @@ #include "mongo/base/string_data.h" #include "mongo/bson/simple_bsonelement_comparator.h" #include "mongo/db/bson/dotted_path_support.h" -#include "mongo/db/index/all_paths_key_generator.h" +#include "mongo/db/index/wildcard_key_generator.h" #include "mongo/db/index_names.h" #include "mongo/db/matcher/expression_algo.h" #include "mongo/db/matcher/expression_geo.h" @@ -150,7 +150,7 @@ static BSONObj getKeyFromQuery(const BSONObj& keyPattern, const BSONObj& query) static bool indexCompatibleMaxMin(const BSONObj& obj, const CollatorInterface* queryCollator, const IndexEntry& indexEntry) { - if (indexEntry.type == IndexType::INDEX_ALLPATHS) { + if (indexEntry.type == IndexType::INDEX_WILDCARD) { return false; } @@ -634,7 +634,7 @@ StatusWith<std::vector<std::unique_ptr<QuerySolution>>> QueryPlanner::plan( // $** index. if (relevantIndices.size() > 1) { for (auto&& entry : relevantIndices) { - invariant(entry.type == IndexType::INDEX_ALLPATHS); + invariant(entry.type == IndexType::INDEX_WILDCARD); } } } @@ -856,7 +856,7 @@ StatusWith<std::vector<std::unique_ptr<QuerySolution>>> QueryPlanner::plan( // desired behavior when an index is hinted that is not relevant to the query. In the case that // $** index is hinted, we do not want this behavior. if (!hintedIndex.isEmpty() && relevantIndices.size() == 1) { - if (0 == out.size() && relevantIndices.front().type != IndexType::INDEX_ALLPATHS) { + if (0 == out.size() && relevantIndices.front().type != IndexType::INDEX_WILDCARD) { // Push hinted index solution to output list if found. It is possible to end up without // a solution in the case where a filtering QueryPlannerParams argument, such as // NO_BLOCKING_SORT, leads to its exclusion. diff --git a/src/mongo/db/query/query_planner_collation_test.cpp b/src/mongo/db/query/query_planner_collation_test.cpp index e30d0bf6b59..bf6020f4df4 100644 --- a/src/mongo/db/query/query_planner_collation_test.cpp +++ b/src/mongo/db/query/query_planner_collation_test.cpp @@ -559,7 +559,7 @@ TEST_F(QueryPlannerTest, NoSortStageWhenMinMaxIndexCollationDoesNotMatchButBound assertSolutionExists("{fetch: {node: {ixscan: {pattern: {a: 1, b: 1, c: 1}}}}}"); } -TEST_F(QueryPlannerTest, StringComparisonWithUnequalCollatorsAndAllPathsIndexResultsInCollscan) { +TEST_F(QueryPlannerTest, StringComparisonWithUnequalCollatorsAndWildcardIndexResultsInCollscan) { CollatorInterfaceMock alwaysEqualCollator(CollatorInterfaceMock::MockType::kAlwaysEqual); addIndex(fromjson("{'$**': 1}"), &alwaysEqualCollator); @@ -570,7 +570,7 @@ TEST_F(QueryPlannerTest, StringComparisonWithUnequalCollatorsAndAllPathsIndexRes assertSolutionExists("{cscan: {dir: 1}}"); } -TEST_F(QueryPlannerTest, StringComparisonWithEqualCollatorsAndAllPathsIndexUsesIndex) { +TEST_F(QueryPlannerTest, StringComparisonWithEqualCollatorsAndWildcardIndexUsesIndex) { params.options &= ~QueryPlannerParams::INCLUDE_COLLSCAN; CollatorInterfaceMock reverseStringCollator(CollatorInterfaceMock::MockType::kReverseString); diff --git a/src/mongo/db/query/query_planner_all_paths_index_test.cpp b/src/mongo/db/query/query_planner_wildcard_index_test.cpp index 9685d312b63..0ca171bd08e 100644 --- a/src/mongo/db/query/query_planner_all_paths_index_test.cpp +++ b/src/mongo/db/query/query_planner_wildcard_index_test.cpp @@ -38,7 +38,7 @@ const std::string kIndexName = "indexName"; * A specialization of the QueryPlannerTest fixture which makes it easy to present the planner with * a view of the available $** indexes. */ -class QueryPlannerAllPathsTest : public QueryPlannerTest { +class QueryPlannerWildcardTest : public QueryPlannerTest { protected: void setUp() final { QueryPlannerTest::setUp(); @@ -48,7 +48,7 @@ protected: params.options &= ~QueryPlannerParams::INCLUDE_COLLSCAN; } - void addAllPathsIndex(BSONObj keyPattern, + void addWildcardIndex(BSONObj keyPattern, const std::set<std::string>& multikeyPathSet = {}, BSONObj wildcardProjection = BSONObj{}, MatchExpression* partialFilterExpr = nullptr) { @@ -63,7 +63,7 @@ protected: BSONObj infoObj = BSON("wildcardProjection" << wildcardProjection); params.indices.push_back(IndexEntry{std::move(keyPattern), - IndexType::INDEX_ALLPATHS, + IndexType::INDEX_WILDCARD, isMultikey, {}, // multikeyPaths std::move(multikeyFieldRefs), @@ -80,7 +80,7 @@ protected: // Null comparison and existence tests. // -TEST_F(QueryPlannerAllPathsTest, ExistsTrueQueriesUseAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, ExistsTrueQueriesUseWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$exists: true}}")); @@ -89,7 +89,7 @@ TEST_F(QueryPlannerAllPathsTest, ExistsTrueQueriesUseAllPathsIndexes) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ExistsFalseQueriesDontUseAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, ExistsFalseQueriesDontUseWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$exists: false}}")); @@ -98,7 +98,7 @@ TEST_F(QueryPlannerAllPathsTest, ExistsFalseQueriesDontUseAllPathsIndexes) { assertSolutionExists("{cscan: {dir: 1}}"); } -TEST_F(QueryPlannerAllPathsTest, EqualsNullQueriesDontUseAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, EqualsNullQueriesDontUseWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$eq: null}}")); @@ -107,7 +107,7 @@ TEST_F(QueryPlannerAllPathsTest, EqualsNullQueriesDontUseAllPathsIndexes) { assertSolutionExists("{cscan: {dir: 1}}"); } -TEST_F(QueryPlannerAllPathsTest, NotEqualsNullQueriesDontUseAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, NotEqualsNullQueriesDontUseWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$ne: null}}")); @@ -116,7 +116,7 @@ TEST_F(QueryPlannerAllPathsTest, NotEqualsNullQueriesDontUseAllPathsIndexes) { assertSolutionExists("{cscan: {dir: 1}}"); } -TEST_F(QueryPlannerAllPathsTest, NotEqualsNullAndExistsQueriesUseAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, NotEqualsNullAndExistsQueriesUseWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$ne: null, $exists: true}}")); @@ -125,7 +125,7 @@ TEST_F(QueryPlannerAllPathsTest, NotEqualsNullAndExistsQueriesUseAllPathsIndexes assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, EqualsNullAndExistsQueriesUseAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, EqualsNullAndExistsQueriesUseWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$eq: null, $exists: true}}")); @@ -134,7 +134,7 @@ TEST_F(QueryPlannerAllPathsTest, EqualsNullAndExistsQueriesUseAllPathsIndexes) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, EmptyBoundsWithAllPathsIndexes) { +TEST_F(QueryPlannerWildcardTest, EmptyBoundsWithWildcardIndexes) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$lte: 5, $gte: 10}}")); @@ -147,8 +147,8 @@ TEST_F(QueryPlannerAllPathsTest, EmptyBoundsWithAllPathsIndexes) { // Multikey planning tests. // -TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverMultikeyFieldNoElemMatch) { - addAllPathsIndex(BSON("$**" << 1), {"a"}); +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverMultikeyFieldNoElemMatch) { + addWildcardIndex(BSON("$**" << 1), {"a"}); runQuery(fromjson("{a: {$gt: 0, $lt: 9}}")); assertNumSolutions(2U); @@ -162,8 +162,8 @@ TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverMultikeyFieldNoElemMatch) "bounds: {'$_path': [['a','a',true,true]], a: [[0,Infinity,false,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverMultikeyFieldWithElemMatch) { - addAllPathsIndex(BSON("$**" << 1), {"a"}); +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverMultikeyFieldWithElemMatch) { + addWildcardIndex(BSON("$**" << 1), {"a"}); runQuery(fromjson("{a: {$elemMatch: {$gt: 0, $lt: 9}}}")); assertNumSolutions(1U); @@ -173,8 +173,8 @@ TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverMultikeyFieldWithElemMatc "bounds: {'$_path': [['a','a',true,true]], a: [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNonMultikeyFieldWithMultikeyIndex) { - addAllPathsIndex(BSON("$**" << 1), {"b"}); +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverNonMultikeyFieldWithMultikeyIndex) { + addWildcardIndex(BSON("$**" << 1), {"b"}); runQuery(fromjson("{a: {$gt: 0, $lt: 9}}")); assertNumSolutions(1U); @@ -183,8 +183,8 @@ TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNonMultikeyFieldWithMulti "bounds: {'$_path': [['a','a',true,true]], a: [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNestedFieldWithFirstComponentMultikey) { - addAllPathsIndex(BSON("$**" << 1), {"a"}); +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverNestedFieldWithFirstComponentMultikey) { + addWildcardIndex(BSON("$**" << 1), {"a"}); runQuery(fromjson("{'a.b': {$gt: 0, $lt: 9}}")); assertNumSolutions(2U); @@ -198,8 +198,8 @@ TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNestedFieldWithFirstCompo "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[0,Infinity,false,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNestedFieldWithElemMatchObject) { - addAllPathsIndex(BSON("$**" << 1), {"a"}); +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverNestedFieldWithElemMatchObject) { + addWildcardIndex(BSON("$**" << 1), {"a"}); runQuery(fromjson("{a: {$elemMatch: {b: {$gt: 0, $lt: 9}}}}")); assertNumSolutions(1U); @@ -209,9 +209,9 @@ TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNestedFieldWithElemMatchO "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverNestedFieldWithElemMatchObjectBothComponentsMultikey) { - addAllPathsIndex(BSON("$**" << 1), {"a", "a.b"}); + addWildcardIndex(BSON("$**" << 1), {"a", "a.b"}); runQuery(fromjson("{a: {$elemMatch: {b: {$gt: 0, $lt: 9}}}}")); assertNumSolutions(2U); @@ -225,8 +225,8 @@ TEST_F(QueryPlannerAllPathsTest, "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[0,Infinity,false,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNestedFieldWithTwoElemMatches) { - addAllPathsIndex(BSON("$**" << 1), {"a", "a.b"}); +TEST_F(QueryPlannerWildcardTest, MultiplePredicatesOverNestedFieldWithTwoElemMatches) { + addWildcardIndex(BSON("$**" << 1), {"a", "a.b"}); runQuery(fromjson("{a: {$elemMatch: {b: {$elemMatch: {$gt: 0, $lt: 9}}}}}")); assertNumSolutions(1U); @@ -236,8 +236,8 @@ TEST_F(QueryPlannerAllPathsTest, MultiplePredicatesOverNestedFieldWithTwoElemMat "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ElemMatchOnInnermostMultikeyPathPermitsTightBounds) { - addAllPathsIndex(BSON("$**" << 1), {"a", "a.b", "a.b.c"}); +TEST_F(QueryPlannerWildcardTest, ElemMatchOnInnermostMultikeyPathPermitsTightBounds) { + addWildcardIndex(BSON("$**" << 1), {"a", "a.b", "a.b.c"}); runQuery(fromjson("{'a.b.c': {$elemMatch: {'d.e.f': {$gt: 0, $lt: 9}}}}")); assertNumSolutions(1U); @@ -248,8 +248,8 @@ TEST_F(QueryPlannerAllPathsTest, ElemMatchOnInnermostMultikeyPathPermitsTightBou "'a.b.c.d.e.f': [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPredsEligibleForIndexUseGenerateCandidatePlans) { - addAllPathsIndex(BSON("a.$**" << 1), {"a.b", "a.c"}); +TEST_F(QueryPlannerWildcardTest, AllPredsEligibleForIndexUseGenerateCandidatePlans) { + addWildcardIndex(BSON("a.$**" << 1), {"a.b", "a.c"}); runQuery( fromjson("{'a.b': {$gt: 0, $lt: 9}, 'a.c': {$gt: 11, $lt: 20}, d: {$gt: 31, $lt: 40}}")); @@ -272,8 +272,8 @@ TEST_F(QueryPlannerAllPathsTest, AllPredsEligibleForIndexUseGenerateCandidatePla "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[0,Infinity,false,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, RangeIndexScan) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, RangeIndexScan) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$gt: 0, $lt: 9}}")); assertNumSolutions(1U); @@ -283,8 +283,8 @@ TEST_F(QueryPlannerAllPathsTest, RangeIndexScan) { "bounds: {'$_path': [['a','a',true,true]], a: [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, RangeIndexScanEmptyRange) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, RangeIndexScanEmptyRange) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$gt: 9, $lt: 0}}")); assertNumSolutions(1U); @@ -294,8 +294,8 @@ TEST_F(QueryPlannerAllPathsTest, RangeIndexScanEmptyRange) { "bounds: {'$_path': [['a','a',true,true]], 'a': []}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, RangeIndexScanMinKeyMaxKey) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, RangeIndexScanMinKeyMaxKey) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$gt: {$minKey: 1}, $lt: {$maxKey: 1}}}")); assertNumSolutions(1U); @@ -306,8 +306,8 @@ TEST_F(QueryPlannerAllPathsTest, RangeIndexScanMinKeyMaxKey) { "'MaxKey', true, true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, RangeIndexScanNestedField) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, RangeIndexScanNestedField) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{'a.b': {$gt: 0, $lt: 9}}")); assertNumSolutions(1U); @@ -317,8 +317,8 @@ TEST_F(QueryPlannerAllPathsTest, RangeIndexScanNestedField) { "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[0,9,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, EqualityIndexScan) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, EqualityIndexScan) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$eq: 5}}")); assertNumSolutions(1U); @@ -328,8 +328,8 @@ TEST_F(QueryPlannerAllPathsTest, EqualityIndexScan) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,5,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, EqualityIndexScanOverNestedField) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, EqualityIndexScanOverNestedField) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{'a.b': {$eq: 5}}")); assertNumSolutions(1U); @@ -339,8 +339,8 @@ TEST_F(QueryPlannerAllPathsTest, EqualityIndexScanOverNestedField) { "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[5,5,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ExprEqCanUseIndex) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, ExprEqCanUseIndex) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$_internalExprEq: 1}}")); assertNumSolutions(1U); @@ -349,8 +349,8 @@ TEST_F(QueryPlannerAllPathsTest, ExprEqCanUseIndex) { "bounds: {'$_path': [['a','a',true,true]], a: [[1,1,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ExprEqCanUseSparseIndexForEqualityToNull) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, ExprEqCanUseSparseIndexForEqualityToNull) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$_internalExprEq: null}}")); assertNumSolutions(1U); @@ -360,7 +360,7 @@ TEST_F(QueryPlannerAllPathsTest, ExprEqCanUseSparseIndexForEqualityToNull) { "[null,null,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, PrefixRegex) { +TEST_F(QueryPlannerWildcardTest, PrefixRegex) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{a: /^foo/}")); @@ -371,7 +371,7 @@ TEST_F(QueryPlannerAllPathsTest, PrefixRegex) { "a: [['foo','fop',true,false], [/^foo/,/^foo/,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, NonPrefixRegex) { +TEST_F(QueryPlannerWildcardTest, NonPrefixRegex) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{a: /foo/}")); @@ -382,8 +382,8 @@ TEST_F(QueryPlannerAllPathsTest, NonPrefixRegex) { "a: [['',{},true,false], [/foo/,/foo/,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, GreaterThan) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, GreaterThan) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$gt: 5}}")); assertNumSolutions(1U); @@ -393,8 +393,8 @@ TEST_F(QueryPlannerAllPathsTest, GreaterThan) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,Infinity,false,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, GreaterThanEqualTo) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, GreaterThanEqualTo) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$gte: 5}}")); assertNumSolutions(1U); @@ -404,8 +404,8 @@ TEST_F(QueryPlannerAllPathsTest, GreaterThanEqualTo) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,Infinity,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, LessThan) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, LessThan) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$lt: 5}}")); assertNumSolutions(1U); @@ -415,8 +415,8 @@ TEST_F(QueryPlannerAllPathsTest, LessThan) { "bounds: {'$_path': [['a','a',true,true]], a: [[-Infinity,5,true,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, LessThanEqualTo) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, LessThanEqualTo) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$lte: 5}}")); assertNumSolutions(1U); @@ -426,8 +426,8 @@ TEST_F(QueryPlannerAllPathsTest, LessThanEqualTo) { "bounds: {'$_path': [['a','a',true,true]], a: [[-Infinity,5,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, Mod) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, Mod) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$mod: [2, 0]}}")); assertNumSolutions(1U); @@ -437,8 +437,8 @@ TEST_F(QueryPlannerAllPathsTest, Mod) { "bounds: {'$_path': [['a','a',true,true]], a: [[NaN,Infinity, true, true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ExistsTrue) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, ExistsTrue) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$exists: true}}")); assertNumSolutions(1U); @@ -449,16 +449,16 @@ TEST_F(QueryPlannerAllPathsTest, ExistsTrue) { "[['MinKey','MaxKey',true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ExistsFalseDoesNotUseIndex) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, ExistsFalseDoesNotUseIndex) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$exists: false}}")); assertNumSolutions(1U); assertSolutionExists("{cscan: {dir: 1}}"); } -TEST_F(QueryPlannerAllPathsTest, AndEqualityWithTwoPredicatesIndexesOnePath) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, AndEqualityWithTwoPredicatesIndexesOnePath) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: 5, b: 10}")); assertNumSolutions(2U); @@ -468,8 +468,8 @@ TEST_F(QueryPlannerAllPathsTest, AndEqualityWithTwoPredicatesIndexesOnePath) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,5,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, OrEqualityWithTwoPredicatesUsesTwoPaths) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, OrEqualityWithTwoPredicatesUsesTwoPaths) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{$or: [{a: 5}, {b: 10}]}")); assertNumSolutions(1U); @@ -482,8 +482,8 @@ TEST_F(QueryPlannerAllPathsTest, OrEqualityWithTwoPredicatesUsesTwoPaths) { ; } -TEST_F(QueryPlannerAllPathsTest, OrWithOneRegularAndOneAllPathsIndexPathUsesTwoIndexes) { - addAllPathsIndex(BSON("a.$**" << 1)); +TEST_F(QueryPlannerWildcardTest, OrWithOneRegularAndOneWildcardIndexPathUsesTwoIndexes) { + addWildcardIndex(BSON("a.$**" << 1)); addIndex(BSON("b" << 1)); runQuery(fromjson("{$or: [{a: 5}, {b: 10}]}")); @@ -497,8 +497,8 @@ TEST_F(QueryPlannerAllPathsTest, OrWithOneRegularAndOneAllPathsIndexPathUsesTwoI ; } -TEST_F(QueryPlannerAllPathsTest, BasicSkip) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, BasicSkip) { + addWildcardIndex(BSON("$**" << 1)); runQuerySkipNToReturn(BSON("a" << 5), 8, 0); assertNumSolutions(1U); @@ -508,8 +508,8 @@ TEST_F(QueryPlannerAllPathsTest, BasicSkip) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,5,true,true]]}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, CoveredSkip) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, CoveredSkip) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProjSkipNToReturn(fromjson("{a: 5}"), BSONObj(), fromjson("{_id: 0, a: 1}"), 8, 0); assertNumSolutions(1U); @@ -519,8 +519,8 @@ TEST_F(QueryPlannerAllPathsTest, CoveredSkip) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,5,true,true]]}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, BasicLimit) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, BasicLimit) { + addWildcardIndex(BSON("$**" << 1)); runQuerySkipNToReturn(BSON("a" << 5), 0, -5); assertNumSolutions(1U); @@ -530,8 +530,8 @@ TEST_F(QueryPlannerAllPathsTest, BasicLimit) { "bounds: {'$_path': [['a','a',true,true]], a: [[5,5,true,true]]}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, BasicCovering) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, BasicCovering) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{ x : {$gt: 1}}"), BSONObj(), fromjson("{_id: 0, x: 1}")); assertNumSolutions(1U); @@ -540,8 +540,8 @@ TEST_F(QueryPlannerAllPathsTest, BasicCovering) { "bounds: {'$_path': [['x','x',true,true]], x: [[1,Infinity,false,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, DottedFieldCovering) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, DottedFieldCovering) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{'a.b': 5}"), BSONObj(), fromjson("{_id: 0, 'a.b': 1}")); assertNumSolutions(1U); @@ -551,9 +551,9 @@ TEST_F(QueryPlannerAllPathsTest, DottedFieldCovering) { "bounds: {'$_path': [['a.b','a.b',true,true]], 'a.b': [[5,5,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, CoveredIxscanForCountOnIndexedPath) { +TEST_F(QueryPlannerWildcardTest, CoveredIxscanForCountOnIndexedPath) { params.options = QueryPlannerParams::IS_COUNT; - addAllPathsIndex(BSON("$**" << 1)); + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: 5}")); assertNumSolutions(1U); @@ -562,8 +562,8 @@ TEST_F(QueryPlannerAllPathsTest, CoveredIxscanForCountOnIndexedPath) { "bounds: {'$_path': [['a','a',true,true]], 'a': [[5,5,true,true]]}}}"); } -TEST_F(QueryPlannerAllPathsTest, InBasic) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, InBasic) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$in: [1, 2]}}")); assertNumSolutions(1U); @@ -573,8 +573,8 @@ TEST_F(QueryPlannerAllPathsTest, InBasic) { "bounds: {'$_path': [['a','a',true,true]], a: [[1,1,true,true],[2,2,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, EqualsEmptyArray) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, EqualsEmptyArray) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: []}")); assertNumSolutions(1U); @@ -584,29 +584,29 @@ TEST_F(QueryPlannerAllPathsTest, EqualsEmptyArray) { "[[undefined,undefined,true,true],[[],[],true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, EqualsNonEmptyArray) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, EqualsNonEmptyArray) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: [1]}")); assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, EqualsNestedEmptyArray) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, EqualsNestedEmptyArray) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: [[]]}")); assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, EqualsArrayWithValue) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, EqualsArrayWithValue) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: [[1]]}")); assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, InEmptyArray) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, InEmptyArray) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$in: [[]]}}")); assertNumSolutions(1U); @@ -616,22 +616,22 @@ TEST_F(QueryPlannerAllPathsTest, InEmptyArray) { "[[undefined,undefined,true,true],[[],[],true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, InNonEmptyArray) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, InNonEmptyArray) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$in: [[1]]}}")); assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, InNestedEmptyArray) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, InNestedEmptyArray) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$in: [[[]]]}}")); assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, InArrayWithValue) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, InArrayWithValue) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$in: [[[1]]]}}")); assertHasOnlyCollscan(); @@ -639,8 +639,8 @@ TEST_F(QueryPlannerAllPathsTest, InArrayWithValue) { // Logically equivalent to the preceding $in query. // Indexed solution should be the same. -TEST_F(QueryPlannerAllPathsTest, InBasicOrEquivalent) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, InBasicOrEquivalent) { + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{$or: [{a: 1}, {a: 2}]}")); assertNumSolutions(1U); @@ -650,10 +650,10 @@ TEST_F(QueryPlannerAllPathsTest, InBasicOrEquivalent) { "bounds: {'$_path': [['a','a',true,true]], a: [[1,1,true,true],[2,2,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, PartialIndexCanAnswerPredicateOnFilteredField) { +TEST_F(QueryPlannerWildcardTest, PartialIndexCanAnswerPredicateOnFilteredField) { auto filterObj = fromjson("{a: {$gt: 0}}"); auto filterExpr = QueryPlannerTest::parseMatchExpression(filterObj); - addAllPathsIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); + addWildcardIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); runQuery(fromjson("{a: {$gte: 5}}")); assertNumSolutions(1U); @@ -677,12 +677,12 @@ TEST_F(QueryPlannerAllPathsTest, PartialIndexCanAnswerPredicateOnFilteredField) "bounds: {'$_path': [['a','a',true,true]], a: [[1,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, PartialIndexDoesNotAnswerPredicatesExcludedByFilter) { +TEST_F(QueryPlannerWildcardTest, PartialIndexDoesNotAnswerPredicatesExcludedByFilter) { // Must keep 'filterObj' around since match expressions will store pointers into the BSON they // were parsed from. auto filterObj = fromjson("{a: {$gt: 0}}"); auto filterExpr = QueryPlannerTest::parseMatchExpression(filterObj); - addAllPathsIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); + addWildcardIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); runQuery(fromjson("{a: {$gte: -1}}")); assertHasOnlyCollscan(); @@ -694,10 +694,10 @@ TEST_F(QueryPlannerAllPathsTest, PartialIndexDoesNotAnswerPredicatesExcludedByFi assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, PartialIndexCanAnswerPredicateOnUnrelatedField) { +TEST_F(QueryPlannerWildcardTest, PartialIndexCanAnswerPredicateOnUnrelatedField) { auto filterObj = fromjson("{a: {$gt: 0}}"); auto filterExpr = QueryPlannerTest::parseMatchExpression(filterObj); - addAllPathsIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); + addWildcardIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); // Test when the field query is not included by the partial filter expression. runQuery(fromjson("{b: {$gte: -1}, a: {$gte: 5}}")); @@ -712,10 +712,10 @@ TEST_F(QueryPlannerAllPathsTest, PartialIndexCanAnswerPredicateOnUnrelatedField) "bounds: {'$_path': [['a','a',true,true]], a: [[5,Infinity,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, PartialIndexWithExistsTrueFilterCanAnswerExistenceQuery) { +TEST_F(QueryPlannerWildcardTest, PartialIndexWithExistsTrueFilterCanAnswerExistenceQuery) { auto filterObj = fromjson("{x: {$exists: true}}"); auto filterExpr = QueryPlannerTest::parseMatchExpression(filterObj); - addAllPathsIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); + addWildcardIndex(BSON("$**" << 1), {}, BSONObj{}, filterExpr.get()); runQuery(fromjson("{x: {$exists: true}}")); assertNumSolutions(1U); @@ -730,7 +730,7 @@ TEST_F(QueryPlannerAllPathsTest, PartialIndexWithExistsTrueFilterCanAnswerExiste // Index intersection tests. // -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexDoesNotParticipateInIndexIntersection) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexDoesNotParticipateInIndexIntersection) { // Enable both AND_SORTED and AND_HASH index intersection for this test. params.options |= QueryPlannerParams::INDEX_INTERSECTION; internalQueryPlannerEnableHashIntersection.store(true); @@ -764,7 +764,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexDoesNotParticipateInIndexIntersect "{filter: null, pattern: {a:1}}},{ixscan: {filter: null, pattern: {b:1}}}]}}}}"); // Now add a $** index and re-run the tests. - addAllPathsIndex(BSON("$**" << 1)); + addWildcardIndex(BSON("$**" << 1)); // First re-run the AND_SORTED test. runQuery(fromjson("{a:10, b:10}")); @@ -804,17 +804,17 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexDoesNotParticipateInIndexIntersect } // -// AllPaths and $text index tests. +// Wildcard and $text index tests. // -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexDoesNotSupplyCandidatePlanForTextSearch) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, WildcardIndexDoesNotSupplyCandidatePlanForTextSearch) { + addWildcardIndex(BSON("$**" << 1)); addIndex(BSON("a" << 1 << "_fts" << "text" << "_ftsx" << 1)); - // Confirm that the allPaths index generates candidate plans for queries which do not include a + // Confirm that the wildcard index generates candidate plans for queries which do not include a // $text predicate. runQuery(fromjson("{a: 10, b: 10}")); assertNumSolutions(2U); @@ -823,7 +823,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexDoesNotSupplyCandidatePlanForTextS assertSolutionExists( "{fetch: {filter: {a: 10}, node: {ixscan: {filter: null, pattern: {'$_path': 1, b: 1}}}}}"); - // Confirm that the allPaths index does not produce any candidate plans when a query includes a + // Confirm that the wildcard index does not produce any candidate plans when a query includes a // $text predicate, even for non-$text predicates which may be present in the query. runQuery(fromjson("{a: 10, b: 10, $text: {$search: 'banana'}}")); assertNumSolutions(1U); @@ -831,10 +831,10 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexDoesNotSupplyCandidatePlanForTextS "{fetch: {filter: {b: 10}, node: {text: {prefix: {a: 10}, search: 'banana'}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsDoesNotSupportNegationPredicate) { - // AllPaths indexes can't support negation queries because they are sparse, and {a: {$ne: 5}} +TEST_F(QueryPlannerWildcardTest, WildcardDoesNotSupportNegationPredicate) { + // Wildcard indexes can't support negation queries because they are sparse, and {a: {$ne: 5}} // will match documents which don't have an "a" field. - addAllPathsIndex(BSON("$**" << 1)); + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$ne: 5}}")); assertHasOnlyCollscan(); @@ -842,11 +842,11 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsDoesNotSupportNegationPredicate) { assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, - AllPathsDoesNotSupportNegationPredicateInsideElemMatchMultiKeyPath) { - // Logically, there's no reason a (sparse) allPaths index could not support a negation inside a +TEST_F(QueryPlannerWildcardTest, + WildcardDoesNotSupportNegationPredicateInsideElemMatchMultiKeyPath) { + // Logically, there's no reason a (sparse) wildcard index could not support a negation inside a // "$elemMatch value", but it is not something we've implemented. - addAllPathsIndex(BSON("$**" << 1), {"a"}); + addWildcardIndex(BSON("$**" << 1), {"a"}); runQuery(fromjson("{a: {$elemMatch: {$ne: 5}}}")); assertHasOnlyCollscan(); @@ -854,11 +854,11 @@ TEST_F(QueryPlannerAllPathsTest, assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, AllPathsDoesNotSupportNegationPredicateInsideElemMatch) { +TEST_F(QueryPlannerWildcardTest, WildcardDoesNotSupportNegationPredicateInsideElemMatch) { // Test the case where we use $elemMatch on a path which isn't even multikey. In this case, // we'd know up front that the results would be empty, but this is not an optimization we // support. - addAllPathsIndex(BSON("$**" << 1)); + addWildcardIndex(BSON("$**" << 1)); runQuery(fromjson("{a: {$elemMatch: {$ne: 5}}}")); assertHasOnlyCollscan(); @@ -870,7 +870,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsDoesNotSupportNegationPredicateInsideEl // Hinting with all paths index tests. // -TEST_F(QueryPlannerTest, ChooseAllPathsIndexHint) { +TEST_F(QueryPlannerTest, ChooseWildcardIndexHint) { addIndex(BSON("$**" << 1)); addIndex(BSON("x" << 1)); @@ -880,21 +880,21 @@ TEST_F(QueryPlannerTest, ChooseAllPathsIndexHint) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintByName) { - StringData allPaths = "allPaths"; +TEST_F(QueryPlannerTest, ChooseWildcardIndexHintByName) { + StringData wildcard = "wildcard"; CollatorInterface* nullCollator = nullptr; - addIndex(BSON("$**" << 1), nullCollator, allPaths); + addIndex(BSON("$**" << 1), nullCollator, wildcard); addIndex(BSON("x" << 1)); runQueryHint(fromjson("{x: {$eq: 1}}"), BSON("$hint" - << "allPaths")); + << "wildcard")); assertNumSolutions(1U); assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintWithPath) { +TEST_F(QueryPlannerTest, ChooseWildcardIndexHintWithPath) { addIndex(BSON("x.$**" << 1)); addIndex(BSON("x" << 1)); @@ -904,7 +904,7 @@ TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintWithPath) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintWithOr) { +TEST_F(QueryPlannerTest, ChooseWildcardIndexHintWithOr) { addIndex(BSON("$**" << 1)); addIndex(BSON("x" << 1 << "y" << 1)); @@ -916,7 +916,7 @@ TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintWithOr) { " {ixscan: {pattern: {$_path: 1, y: 1}}}]}}}}"); } -TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintWithCompoundIndex) { +TEST_F(QueryPlannerTest, ChooseWildcardIndexHintWithCompoundIndex) { addIndex(BSON("$**" << 1)); addIndex(BSON("x" << 1 << "y" << 1)); @@ -927,7 +927,7 @@ TEST_F(QueryPlannerTest, ChooseAllPathsIndexHintWithCompoundIndex) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, y: 1}}}}}"); } -TEST_F(QueryPlannerTest, QueryNotInAllPathsIndexHint) { +TEST_F(QueryPlannerTest, QueryNotInWildcardIndexHint) { addIndex(BSON("a.$**" << 1)); addIndex(BSON("x" << 1)); @@ -935,13 +935,13 @@ TEST_F(QueryPlannerTest, QueryNotInAllPathsIndexHint) { assertNumSolutions(0U); } -TEST_F(QueryPlannerTest, AllPathsIndexDoesNotExist) { +TEST_F(QueryPlannerTest, WildcardIndexDoesNotExist) { addIndex(BSON("x" << 1)); runInvalidQueryHint(fromjson("{x: {$eq: 1}}"), BSON("$**" << 1)); } -TEST_F(QueryPlannerTest, AllPathsIndexHintWithPartialFilter) { +TEST_F(QueryPlannerTest, WildcardIndexHintWithPartialFilter) { auto filterObj = fromjson("{a: {$gt: 100}}"); auto filterExpr = QueryPlannerTest::parseMatchExpression(filterObj); addIndex(BSON("$**" << 1), filterExpr.get()); @@ -950,7 +950,7 @@ TEST_F(QueryPlannerTest, AllPathsIndexHintWithPartialFilter) { assertNumSolutions(0U); } -TEST_F(QueryPlannerTest, MultipleAllPathsIndexesHintWithPartialFilter) { +TEST_F(QueryPlannerTest, MultipleWildcardIndexesHintWithPartialFilter) { auto filterObj = fromjson("{a: {$gt: 100}, b: {$gt: 100}}"); auto filterExpr = QueryPlannerTest::parseMatchExpression(filterObj); addIndex(BSON("$**" << 1), filterExpr.get()); @@ -959,7 +959,7 @@ TEST_F(QueryPlannerTest, MultipleAllPathsIndexesHintWithPartialFilter) { assertNumSolutions(0U); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportObjectEquality) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexesDoNotSupportObjectEquality) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {abc: 1}}")); @@ -974,7 +974,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportObjectEquality) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportObjectInequality) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexesDoNotSupportObjectInequality) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$lt: {abc: 1}}}")); @@ -1007,7 +1007,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportObjectInequality) { assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportInWithUnsupportedValues) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexesDoNotSupportInWithUnsupportedValues) { addIndex(BSON("$**" << 1)); runQuery(fromjson("{x: {$in: [1, 2, 3, {abc: 1}]}}")); @@ -1018,7 +1018,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportInWithUnsupportedVal assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesSupportElemMatchWithNull) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexesSupportElemMatchWithNull) { addIndex(BSON("$**" << 1)); // Simple case. @@ -1026,14 +1026,14 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesSupportElemMatchWithNull) { assertNumSolutions(1U); assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); - // null inside an $in inside an $elemMatch is supported by the allPaths index, since it means + // null inside an $in inside an $elemMatch is supported by the wildcard index, since it means // we're searching for an explicit null value. runQuery(fromjson("{x: {$elemMatch: {$in: [1, 2, 3, null]}}}")); assertNumSolutions(1U); assertSolutionExists("{fetch: {node: {ixscan: {pattern: {$_path: 1, x: 1}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportElemMatchWithUnsupportedValues) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexesDoNotSupportElemMatchWithUnsupportedValues) { runQuery(fromjson("{x: {$elemMatch: {$eq: ['a', 'b', 'c']}}}")); assertHasOnlyCollscan(); @@ -1045,13 +1045,13 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportElemMatchWithUnsuppo assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexesDoNotSupportElemMatchObject) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexesDoNotSupportElemMatchObject) { runQuery(fromjson("{x: {$elemMatch: {a: 1}}}")); assertHasOnlyCollscan(); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexCanProvideNonBlockingSort) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, WildcardIndexCanProvideNonBlockingSort) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{a: 1}"), BSON("a" << 1), BSONObj()); assertNumSolutions(1U); @@ -1060,9 +1060,9 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexCanProvideNonBlockingSort) { "bounds: {'$_path': [['a','a',true,true]], a: [[1,1,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, - AllPathsIndexCanProvideNonBlockingSortWhenFilterIncludesAdditionalFields) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, + WildcardIndexCanProvideNonBlockingSortWhenFilterIncludesAdditionalFields) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{a: {$gte: 3}, b: 1}"), BSON("a" << 1), BSONObj()); assertNumSolutions(2U); @@ -1079,8 +1079,8 @@ TEST_F(QueryPlannerAllPathsTest, "bounds: {'$_path': [['b','b',true,true]], b: [[1, 1, true, true]]}}}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWithElemMatch) { - addAllPathsIndex(BSON("$**" << 1), {"a"}); +TEST_F(QueryPlannerWildcardTest, WildcardIndexMustUseBlockingSortWithElemMatch) { + addWildcardIndex(BSON("$**" << 1), {"a"}); runQuerySortProj(fromjson("{a: {$elemMatch: {$eq: 1}}}"), BSON("a" << 1), BSONObj()); assertNumSolutions(1U); @@ -1091,8 +1091,8 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWithElemMatch) "bounds: {'$_path': [['a','a',true,true]], a: [[1, 1, true, true]]}}}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWithCompoundSort) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, WildcardIndexMustUseBlockingSortWithCompoundSort) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{a: {$lte: 3}}"), BSON("a" << 1 << "b" << 1), BSONObj()); assertNumSolutions(1U); @@ -1103,8 +1103,8 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWithCompoundSor "bounds: {'$_path': [['a','a',true,true]], a: [[-Infinity, 3, true, true]]}}}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWithExistsQueries) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, WildcardIndexMustUseBlockingSortWithExistsQueries) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{a: {$exists: true}}"), BSON("a" << 1), BSONObj()); assertNumSolutions(1U); @@ -1116,7 +1116,7 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWithExistsQueri "true]]}}}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWhenFilterNotPresent) { +TEST_F(QueryPlannerWildcardTest, WildcardIndexMustUseBlockingSortWhenFilterNotPresent) { // Since there's no filter on the field that we're sorting by, we cannot use an index scan to // answer the query as $** indexes are sparse. runQuerySortProj(BSONObj(), fromjson("{a: 1}"), BSONObj()); @@ -1125,8 +1125,8 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWhenFilterNotPr "{cscan: {dir: 1}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWhenFilterDoesNotIncludeSortKey) { - addAllPathsIndex(BSON("$**" << 1)); +TEST_F(QueryPlannerWildcardTest, WildcardIndexMustUseBlockingSortWhenFilterDoesNotIncludeSortKey) { + addWildcardIndex(BSON("$**" << 1)); runQuerySortProj(fromjson("{b: 1, c: 1}"), fromjson("{a: 1}"), BSONObj()); assertNumSolutions(2U); @@ -1142,8 +1142,8 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWhenFilterDoesN "bounds: {'$_path': [['c','c',true,true]], c: [[1, 1, true, true]]}}}}}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWhenFieldIsNotIncluded) { - addAllPathsIndex(BSON("$**" << 1), {}, BSON("b" << 0)); +TEST_F(QueryPlannerWildcardTest, WildcardIndexMustUseBlockingSortWhenFieldIsNotIncluded) { + addWildcardIndex(BSON("$**" << 1), {}, BSON("b" << 0)); runQuerySortProj(fromjson("{b: 1}"), fromjson("{b: 1}"), BSONObj()); assertNumSolutions(1U); @@ -1158,8 +1158,8 @@ TEST_F(QueryPlannerAllPathsTest, AllPathsIndexMustUseBlockingSortWhenFieldIsNotI // Field name or array index tests. // -TEST_F(QueryPlannerAllPathsTest, CannotAnswerQueryThroughArrayIndexProjection) { - addAllPathsIndex(BSON("$**" << 1), {"a"}, fromjson("{'a.0': 1, 'a.b': 1}")); +TEST_F(QueryPlannerWildcardTest, CannotAnswerQueryThroughArrayIndexProjection) { + addWildcardIndex(BSON("$**" << 1), {"a"}, fromjson("{'a.0': 1, 'a.b': 1}")); // Queries whose path lies along a projected array index cannot be answered. runQuery(fromjson("{'a.0': 10}")); @@ -1171,8 +1171,8 @@ TEST_F(QueryPlannerAllPathsTest, CannotAnswerQueryThroughArrayIndexProjection) { assertSolutionExists("{cscan: {dir: 1}}"); } -TEST_F(QueryPlannerAllPathsTest, CanAnswerQueryOnNonProjectedArrayIndex) { - addAllPathsIndex(BSON("$**" << 1), {"a", "c"}, fromjson("{'a.0': 1, b: 1, c: 1}")); +TEST_F(QueryPlannerWildcardTest, CanAnswerQueryOnNonProjectedArrayIndex) { + addWildcardIndex(BSON("$**" << 1), {"a", "c"}, fromjson("{'a.0': 1, b: 1, c: 1}")); // Queries on fields that are not projected array indices can be answered, even when such a // projection is present in the 'starPathsTempName' spec. @@ -1191,8 +1191,8 @@ TEST_F(QueryPlannerAllPathsTest, CanAnswerQueryOnNonProjectedArrayIndex) { "[[10,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldGenerateAllPotentialPathBoundsForArrayIndexQueries) { - addAllPathsIndex(BSON("a.$**" << 1), {"a", "a.b"}); +TEST_F(QueryPlannerWildcardTest, ShouldGenerateAllPotentialPathBoundsForArrayIndexQueries) { + addWildcardIndex(BSON("a.$**" << 1), {"a", "a.b"}); // A numeric path component immediately following a multikey path may represent an array index, // a fieldname, or both. The $** index does not record array indices explicitly, so for all such @@ -1221,8 +1221,8 @@ TEST_F(QueryPlannerAllPathsTest, ShouldGenerateAllPotentialPathBoundsForArrayInd "['a.b.c','a.b.c',true,true]], 'a.0.b.1.c': [[10,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldAddAllPredicatesToFetchFilterForArrayIndexQueries) { - addAllPathsIndex(BSON("$**" << 1), {"a", "a.b"}); +TEST_F(QueryPlannerWildcardTest, ShouldAddAllPredicatesToFetchFilterForArrayIndexQueries) { + addWildcardIndex(BSON("$**" << 1), {"a", "a.b"}); // Ordinarily, a query such as {'a': {$gt: 0, $lt: 5}} on a multikey field 'a' produces an EXACT // IXSCAN on one of the predicates and a FETCH filter on the other. For fieldname-or-array-index @@ -1302,8 +1302,8 @@ TEST_F(QueryPlannerAllPathsTest, ShouldAddAllPredicatesToFetchFilterForArrayInde "[[10,20,false,false]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldOnlyBuildSpecialBoundsForMultikeyPaths) { - addAllPathsIndex(BSON("a.$**" << 1), {"a.b", "a.b.c.d"}); +TEST_F(QueryPlannerWildcardTest, ShouldOnlyBuildSpecialBoundsForMultikeyPaths) { + addWildcardIndex(BSON("a.$**" << 1), {"a.b", "a.b.c.d"}); // 'a' is not multikey, so 'a.0' refers specifically to a fieldname rather than an array index, // and special bounds will not be generated. @@ -1350,8 +1350,8 @@ TEST_F(QueryPlannerAllPathsTest, ShouldOnlyBuildSpecialBoundsForMultikeyPaths) { "['a.b.c.d.e','a.b.c.d.e',true,true]], 'a.b.1.c.d.3.e':[[10,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldGenerateSpecialBoundsForNumericMultikeyPaths) { - addAllPathsIndex(BSON("a.$**" << 1), {"a.b", "a.b.0"}); +TEST_F(QueryPlannerWildcardTest, ShouldGenerateSpecialBoundsForNumericMultikeyPaths) { + addWildcardIndex(BSON("a.$**" << 1), {"a.b", "a.b.0"}); // 'a.b.0' is itself a multikey path, but since 'a.b' is multikey 'b.0' may refer to an array // element of 'b'. We generate special bounds for 'b.0'. @@ -1380,8 +1380,8 @@ TEST_F(QueryPlannerAllPathsTest, ShouldGenerateSpecialBoundsForNumericMultikeyPa "['a.b.1.c','a.b.1.c',true,true]], 'a.b.1.1.c': [[10,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldNotGenerateSpecialBoundsForFieldNamesWithLeadingZeroes) { - addAllPathsIndex(BSON("a.$**" << 1), {"a.b"}); +TEST_F(QueryPlannerWildcardTest, ShouldNotGenerateSpecialBoundsForFieldNamesWithLeadingZeroes) { + addWildcardIndex(BSON("a.$**" << 1), {"a.b"}); // 'a.b' is multikey, but '01' is not eligible for consideration as a numeric array index; it is // always strictly a field name. We therefore do not generate special bounds. @@ -1392,8 +1392,8 @@ TEST_F(QueryPlannerAllPathsTest, ShouldNotGenerateSpecialBoundsForFieldNamesWith "bounds: {'$_path': [['a.b.01','a.b.01',true,true]], 'a.b.01': [[10,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, InitialNumericPathComponentIsAlwaysFieldName) { - addAllPathsIndex(BSON("$**" << 1), {"0"}, fromjson("{'0': 1}")); +TEST_F(QueryPlannerWildcardTest, InitialNumericPathComponentIsAlwaysFieldName) { + addWildcardIndex(BSON("$**" << 1), {"0"}, fromjson("{'0': 1}")); // '0' is multikey, but the first component in a path can never be an array index since it must // always be a field name. We therefore do not generate special bounds for '0.b'. @@ -1412,8 +1412,8 @@ TEST_F(QueryPlannerAllPathsTest, InitialNumericPathComponentIsAlwaysFieldName) { "'0.1.b': [[10,10,true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldGenerateSpecialBoundsForNullAndExistenceQueries) { - addAllPathsIndex(BSON("a.$**" << 1), {"a", "a.b", "a.b.2", "a.b.2.3", "a.b.2.3.4"}); +TEST_F(QueryPlannerWildcardTest, ShouldGenerateSpecialBoundsForNullAndExistenceQueries) { + addWildcardIndex(BSON("a.$**" << 1), {"a", "a.b", "a.b.2", "a.b.2.3", "a.b.2.3.4"}); runQuery(fromjson("{'a.0.b': {$exists: true}}")); assertNumSolutions(1U); @@ -1453,8 +1453,8 @@ TEST_F(QueryPlannerAllPathsTest, ShouldGenerateSpecialBoundsForNullAndExistenceQ "'a.0.b.2.3.4': [[{$minKey: 1},{$maxKey: 1},true,true]]}}}}}"); } -TEST_F(QueryPlannerAllPathsTest, ShouldDeclineToAnswerQueriesThatTraverseTooManyArrays) { - addAllPathsIndex(BSON("$**" << 1), +TEST_F(QueryPlannerWildcardTest, ShouldDeclineToAnswerQueriesThatTraverseTooManyArrays) { + addWildcardIndex(BSON("$**" << 1), {"a", "a.b", "a.b.c", diff --git a/src/mongo/db/query/query_solution.cpp b/src/mongo/db/query/query_solution.cpp index 142e9a061fd..567cb958e0a 100644 --- a/src/mongo/db/query/query_solution.cpp +++ b/src/mongo/db/query/query_solution.cpp @@ -561,7 +561,7 @@ bool IndexScanNode::hasField(const string& field) const { for (auto&& elt : index.keyPattern) { // For $** indexes, the keyPattern is prefixed by a virtual field, '$_path'. We therefore // skip the first keyPattern field when deciding whether we can provide the requested field. - if (index.type == IndexType::INDEX_ALLPATHS && !keyPatternFieldIndex) { + if (index.type == IndexType::INDEX_WILDCARD && !keyPatternFieldIndex) { invariant(elt.fieldNameStringData() == "$_path"_sd); ++keyPatternFieldIndex; continue; diff --git a/src/mongo/db/record_id.h b/src/mongo/db/record_id.h index 1a903d1d39e..53450123325 100644 --- a/src/mongo/db/record_id.h +++ b/src/mongo/db/record_id.h @@ -54,7 +54,7 @@ public: /** * Enumerates all ids in the reserved range that have been allocated for a specific purpose. */ - enum class ReservedId : int64_t { kAllPathsMultikeyMetadataId = kMinReservedRepr }; + enum class ReservedId : int64_t { kWildcardMultikeyMetadataId = kMinReservedRepr }; /** * Constructs a Null RecordId. diff --git a/src/mongo/db/storage/kv/kv_database_catalog_entry.cpp b/src/mongo/db/storage/kv/kv_database_catalog_entry.cpp index 947acfc4104..2701dae77ce 100644 --- a/src/mongo/db/storage/kv/kv_database_catalog_entry.cpp +++ b/src/mongo/db/storage/kv/kv_database_catalog_entry.cpp @@ -32,7 +32,6 @@ #include "mongo/db/catalog/index_catalog_entry.h" #include "mongo/db/index/2d_access_method.h" -#include "mongo/db/index/all_paths_access_method.h" #include "mongo/db/index/btree_access_method.h" #include "mongo/db/index/fts_access_method.h" #include "mongo/db/index/hash_access_method.h" @@ -40,6 +39,7 @@ #include "mongo/db/index/index_access_method.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/index/s2_access_method.h" +#include "mongo/db/index/wildcard_access_method.h" #include "mongo/db/index_names.h" #include "mongo/db/storage/kv/kv_collection_catalog_entry.h" #include "mongo/db/storage/kv/kv_engine.h" @@ -85,8 +85,8 @@ IndexAccessMethod* KVDatabaseCatalogEntry::getIndex(OperationContext* opCtx, if (IndexNames::GEO_2D == type) return new TwoDAccessMethod(index, sdi); - if (IndexNames::ALLPATHS == type) - return new AllPathsAccessMethod(index, sdi); + if (IndexNames::WILDCARD == type) + return new WildcardAccessMethod(index, sdi); log() << "Can't find index for keyPattern " << desc->keyPattern(); MONGO_UNREACHABLE; diff --git a/src/mongo/dbtests/SConscript b/src/mongo/dbtests/SConscript index 8b5eb78c851..52b834e2e12 100644 --- a/src/mongo/dbtests/SConscript +++ b/src/mongo/dbtests/SConscript @@ -51,7 +51,6 @@ env.Library( dbtest = env.Program( target="dbtest", source=[ - 'all_paths_multikey_persistence_test.cpp', 'basictests.cpp', 'clienttests.cpp', 'commandtests.cpp', @@ -109,6 +108,7 @@ dbtest = env.Program( 'threadedtests.cpp', 'updatetests.cpp', 'validate_tests.cpp', + 'wildcard_multikey_persistence_test.cpp', ], LIBDEPS=[ "$BUILD_DIR/mongo/bson/mutable/mutable_bson_test_utils", diff --git a/src/mongo/dbtests/validate_tests.cpp b/src/mongo/dbtests/validate_tests.cpp index 8791185e1ba..5cc747e128f 100644 --- a/src/mongo/dbtests/validate_tests.cpp +++ b/src/mongo/dbtests/validate_tests.cpp @@ -66,7 +66,7 @@ public: _db(nullptr) { _client.createCollection(_ns); { - _origAllPathsKnob = internalQueryAllowAllPathsIndexes.load(); + _origWildcardKnob = internalQueryAllowAllPathsIndexes.load(); internalQueryAllowAllPathsIndexes.store(true); AutoGetCollection autoGetCollection(&_opCtx, _nss, MODE_X); @@ -78,7 +78,7 @@ public: ~ValidateBase() { _client.dropCollection(_ns); getGlobalServiceContext()->unsetKillAllOperations(); - internalQueryAllowAllPathsIndexes.store(_origAllPathsKnob); + internalQueryAllowAllPathsIndexes.store(_origWildcardKnob); } protected: @@ -140,7 +140,7 @@ protected: unique_ptr<AutoGetDb> _autoDb; Database* _db; bool _isInRecordIdOrder; - bool _origAllPathsKnob{false}; + bool _origWildcardKnob{false}; }; template <bool full, bool background> @@ -1019,7 +1019,7 @@ public: // Insert additional multikey path metadata index keys. lockDb(MODE_X); - const RecordId recordId(RecordId::ReservedId::kAllPathsMultikeyMetadataId); + const RecordId recordId(RecordId::ReservedId::kWildcardMultikeyMetadataId); IndexCatalog* indexCatalog = coll->getIndexCatalog(); IndexDescriptor* descriptor = indexCatalog->findIndexByName(&_opCtx, indexName); auto sortedDataInterface = @@ -1139,7 +1139,7 @@ public: WriteUnitOfWork wunit(&_opCtx); const BSONObj indexKey = BSON("" << 1 << "" << "a"); - RecordId recordId(RecordId::ReservedId::kAllPathsMultikeyMetadataId); + RecordId recordId(RecordId::ReservedId::kWildcardMultikeyMetadataId); sortedDataInterface->unindex(&_opCtx, indexKey, recordId, true /* dupsAllowed */); wunit.commit(); } diff --git a/src/mongo/dbtests/all_paths_multikey_persistence_test.cpp b/src/mongo/dbtests/wildcard_multikey_persistence_test.cpp index f438f1be820..6d31c903035 100644 --- a/src/mongo/dbtests/all_paths_multikey_persistence_test.cpp +++ b/src/mongo/dbtests/wildcard_multikey_persistence_test.cpp @@ -43,8 +43,8 @@ using namespace unittest; static const RecordId kMetadataId = RecordId::minReserved(); static const int kIndexVersion = static_cast<int>(IndexDescriptor::kLatestIndexVersion); -static const NamespaceString kDefaultNSS{"all_paths_multikey_persistence.test"}; -static const std::string kDefaultIndexName{"all_paths_multikey"}; +static const NamespaceString kDefaultNSS{"wildcard_multikey_persistence.test"}; +static const std::string kDefaultIndexName{"wildcard_multikey"}; static const BSONObj kDefaultIndexKey = fromjson("{'$**': 1}"); static const BSONObj kDefaultPathProjection; @@ -58,16 +58,16 @@ std::vector<InsertStatement> toInserts(std::vector<BSONObj> docs) { return inserts; } -class AllPathsMultikeyPersistenceTestFixture : public unittest::Test { +class WildcardMultikeyPersistenceTestFixture : public unittest::Test { public: - AllPathsMultikeyPersistenceTestFixture() { - _origAllPathsKnob = internalQueryAllowAllPathsIndexes.load(); + WildcardMultikeyPersistenceTestFixture() { + _origWildcardKnob = internalQueryAllowAllPathsIndexes.load(); internalQueryAllowAllPathsIndexes.store(true); _opCtx = cc().makeOperationContext(); } - virtual ~AllPathsMultikeyPersistenceTestFixture() { - internalQueryAllowAllPathsIndexes.store(_origAllPathsKnob); + virtual ~WildcardMultikeyPersistenceTestFixture() { + internalQueryAllowAllPathsIndexes.store(_origWildcardKnob); _opCtx.reset(); } @@ -235,11 +235,11 @@ protected: private: ServiceContext::UniqueOperationContext _opCtx; repl::StorageInterfaceImpl _storage; - bool _origAllPathsKnob{false}; + bool _origWildcardKnob{false}; int _id{1}; }; -TEST_F(AllPathsMultikeyPersistenceTestFixture, RecordMultikeyPathsInBulkIndexBuild) { +TEST_F(WildcardMultikeyPersistenceTestFixture, RecordMultikeyPathsInBulkIndexBuild) { // Create the test collection, add some initial documents, and build a foreground $** index. assertSetupEnvironment(false, makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}"})); @@ -254,7 +254,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, RecordMultikeyPathsInBulkIndexBui assertMultikeyPathSetEquals({"b", "b.d.e"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, RecordMultikeyPathsInBackgroundIndexBuild) { +TEST_F(WildcardMultikeyPersistenceTestFixture, RecordMultikeyPathsInBackgroundIndexBuild) { // Create the test collection, add some initial documents, and build a background $** index. assertSetupEnvironment(true, makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}"})); @@ -269,7 +269,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, RecordMultikeyPathsInBackgroundIn assertMultikeyPathSetEquals({"b", "b.d.e"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, DedupMultikeyPathsInBulkIndexBuild) { +TEST_F(WildcardMultikeyPersistenceTestFixture, DedupMultikeyPathsInBulkIndexBuild) { // Create the test collection, add some initial documents, and build a foreground $** index. const auto initialDocs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}"}); @@ -289,7 +289,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, DedupMultikeyPathsInBulkIndexBuil assertMultikeyPathSetEquals({"b", "b.d.e"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, DedupMultikeyPathsInBackgroundIndexBuild) { +TEST_F(WildcardMultikeyPersistenceTestFixture, DedupMultikeyPathsInBackgroundIndexBuild) { // Create the test collection, add some initial documents, and build a background $** index. const auto initialDocs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}"}); @@ -309,7 +309,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, DedupMultikeyPathsInBackgroundInd assertMultikeyPathSetEquals({"b", "b.d.e"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, AddAndDedupNewMultikeyPathsOnPostBuildInsertion) { +TEST_F(WildcardMultikeyPersistenceTestFixture, AddAndDedupNewMultikeyPathsOnPostBuildInsertion) { // Create the test collection, add some initial documents, and build a $** index. assertSetupEnvironment(false, makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}"})); @@ -332,7 +332,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, AddAndDedupNewMultikeyPathsOnPost assertMultikeyPathSetEquals({"b", "b.d.e", "d.e.f"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, AddAndDedupNewMultikeyPathsOnUpsert) { +TEST_F(WildcardMultikeyPersistenceTestFixture, AddAndDedupNewMultikeyPathsOnUpsert) { // Create the test collection, add some initial documents, and build a $** index. assertSetupEnvironment(false, makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}"})); @@ -355,7 +355,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, AddAndDedupNewMultikeyPathsOnUpse assertMultikeyPathSetEquals({"b", "b.d.e", "d.e.f"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, AddNewMultikeyPathsOnUpdate) { +TEST_F(WildcardMultikeyPersistenceTestFixture, AddNewMultikeyPathsOnUpdate) { // Create the test collection, add some initial documents, and build a $** index. assertSetupEnvironment(false, makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}"})); @@ -387,7 +387,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, AddNewMultikeyPathsOnUpdate) { assertMultikeyPathSetEquals({"b", "b.d.e", "b.d.f", "b.g"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, AddNewMultikeyPathsOnReplacement) { +TEST_F(WildcardMultikeyPersistenceTestFixture, AddNewMultikeyPathsOnReplacement) { // Create the test collection, add some initial documents, and build a $** index. assertSetupEnvironment(false, makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}"})); @@ -417,7 +417,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, AddNewMultikeyPathsOnReplacement) assertMultikeyPathSetEquals({"b", "b.d.e", "b.d.f"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, DoNotRemoveMultikeyPathsOnDocDeletion) { +TEST_F(WildcardMultikeyPersistenceTestFixture, DoNotRemoveMultikeyPathsOnDocDeletion) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}", @@ -449,7 +449,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, DoNotRemoveMultikeyPathsOnDocDele assertMultikeyPathSetEquals({"b", "b.d.e", "d.e.f"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, OnlyIndexKeyPatternSubTreeInBulkBuild) { +TEST_F(WildcardMultikeyPersistenceTestFixture, OnlyIndexKeyPatternSubTreeInBulkBuild) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}", @@ -470,7 +470,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, OnlyIndexKeyPatternSubTreeInBulkB assertMultikeyPathSetEquals({"b", "b.d.e"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, OnlyIndexKeyPatternSubTreeInBackgroundBuild) { +TEST_F(WildcardMultikeyPersistenceTestFixture, OnlyIndexKeyPatternSubTreeInBackgroundBuild) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}", @@ -489,7 +489,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, OnlyIndexKeyPatternSubTreeInBackg assertMultikeyPathSetEquals({"b", "b.d.e"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, OnlyIndexIncludedPathsInBulkBuild) { +TEST_F(WildcardMultikeyPersistenceTestFixture, OnlyIndexIncludedPathsInBulkBuild) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}", @@ -511,7 +511,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, OnlyIndexIncludedPathsInBulkBuild assertMultikeyPathSetEquals({"b", "b.d.e", "d.e.f"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, OnlyIndexIncludedPathsInBackgroundBuild) { +TEST_F(WildcardMultikeyPersistenceTestFixture, OnlyIndexIncludedPathsInBackgroundBuild) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}", @@ -533,7 +533,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, OnlyIndexIncludedPathsInBackgroun assertMultikeyPathSetEquals({"b", "b.d.e", "d.e.f"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, OnlyIndexIncludedPathsOnUpdate) { +TEST_F(WildcardMultikeyPersistenceTestFixture, OnlyIndexIncludedPathsOnUpdate) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}", @@ -572,7 +572,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, OnlyIndexIncludedPathsOnUpdate) { assertMultikeyPathSetEquals({"b", "b.d.e", "d.e.f"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, DoNotIndexExcludedPathsInBulkBuild) { +TEST_F(WildcardMultikeyPersistenceTestFixture, DoNotIndexExcludedPathsInBulkBuild) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}", @@ -596,7 +596,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, DoNotIndexExcludedPathsInBulkBuil assertMultikeyPathSetEquals({"b"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, DoNotIndexExcludedPathsInBackgroundBuild) { +TEST_F(WildcardMultikeyPersistenceTestFixture, DoNotIndexExcludedPathsInBackgroundBuild) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}", @@ -620,7 +620,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, DoNotIndexExcludedPathsInBackgrou assertMultikeyPathSetEquals({"b"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, DoNotIndexExcludedPathsOnUpdate) { +TEST_F(WildcardMultikeyPersistenceTestFixture, DoNotIndexExcludedPathsOnUpdate) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}", @@ -659,7 +659,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, DoNotIndexExcludedPathsOnUpdate) assertMultikeyPathSetEquals({"b"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, IndexIdFieldIfSpecifiedInInclusionProjection) { +TEST_F(WildcardMultikeyPersistenceTestFixture, IndexIdFieldIfSpecifiedInInclusionProjection) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}", @@ -684,7 +684,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, IndexIdFieldIfSpecifiedInInclusio assertMultikeyPathSetEquals({"b", "b.d.e", "d.e.f"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, IndexIdFieldIfSpecifiedInExclusionProjection) { +TEST_F(WildcardMultikeyPersistenceTestFixture, IndexIdFieldIfSpecifiedInExclusionProjection) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs({"{a: 1, b: [{c: 2}, {d: {e: [3]}}]}", "{a: 2, b: [{c: 3}, {d: {e: [4]}}]}", @@ -709,7 +709,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, IndexIdFieldIfSpecifiedInExclusio assertMultikeyPathSetEquals({"b"}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, DoNotMarkAsMultikeyIfNoArraysInBulkBuild) { +TEST_F(WildcardMultikeyPersistenceTestFixture, DoNotMarkAsMultikeyIfNoArraysInBulkBuild) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs( {"{a: 1, b: {c: 2, d: {e: 3}}}", "{a: 2, b: {c: 3, d: {e: 4}}}", "{d: {e: {f: 5}}}"}); @@ -729,7 +729,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, DoNotMarkAsMultikeyIfNoArraysInBu assertMultikeyPathSetEquals({}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, DoNotMarkAsMultikeyIfNoArraysInBackgroundBuild) { +TEST_F(WildcardMultikeyPersistenceTestFixture, DoNotMarkAsMultikeyIfNoArraysInBackgroundBuild) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs( {"{a: 1, b: {c: 2, d: {e: 3}}}", "{a: 2, b: {c: 3, d: {e: 4}}}", "{d: {e: {f: 5}}}"}); @@ -749,7 +749,7 @@ TEST_F(AllPathsMultikeyPersistenceTestFixture, DoNotMarkAsMultikeyIfNoArraysInBa assertMultikeyPathSetEquals({}); } -TEST_F(AllPathsMultikeyPersistenceTestFixture, IndexShouldBecomeMultikeyIfArrayIsCreatedByUpdate) { +TEST_F(WildcardMultikeyPersistenceTestFixture, IndexShouldBecomeMultikeyIfArrayIsCreatedByUpdate) { // Create the test collection, add some initial documents, and build a $** index. const auto docs = makeDocs( {"{a: 1, b: {c: 2, d: {e: 3}}}", "{a: 2, b: {c: 3, d: {e: 4}}}", "{d: {e: {f: 5}}}"}); |