Files
mongo/jstests/core/collation_plan_cache.js

244 lines
9.6 KiB
JavaScript

// Integration testing for the plan cache and index filter commands with collation.
//
// @tags: [
// # This test attempts to perform queries and introspect the server's plan cache entries. The
// # former operation may be routed to a secondary in the replica set, whereas the latter must be
// # routed to the primary.
// assumes_read_preference_unchanged,
// does_not_support_stepdowns,
// ]
(function() {
'use strict';
var coll = db.collation_plan_cache;
coll.drop();
assert.commandWorked(coll.insert({a: 'foo', b: 5}));
// We need two indexes that each query can use so that a plan cache entry is created.
assert.commandWorked(coll.createIndex({a: 1}, {collation: {locale: 'en_US'}}));
assert.commandWorked(coll.createIndex({a: 1, b: 1}, {collation: {locale: 'en_US'}}));
// We need an index with a different collation, so that string comparisons affect the query
// shape.
assert.commandWorked(coll.createIndex({b: 1}, {collation: {locale: 'fr_CA'}}));
// listQueryShapes().
// Run a query so that an entry is inserted into the cache.
assert.commandWorked(
coll.runCommand("find", {filter: {a: 'foo', b: 5}, collation: {locale: "en_US"}}),
'find command failed');
// The query shape should have been added.
var shapes = coll.getPlanCache().listQueryShapes();
assert.eq(1, shapes.length, 'unexpected cache size after running query');
let filteredShape0 = shapes[0];
delete filteredShape0.queryHash;
assert.eq(filteredShape0,
{
query: {a: 'foo', b: 5},
sort: {},
projection: {},
collation: {
locale: 'en_US',
caseLevel: false,
caseFirst: 'off',
strength: 3,
numericOrdering: false,
alternate: 'non-ignorable',
maxVariable: 'punct',
normalization: false,
backwards: false,
version: '57.1'
}
},
'unexpected query shape returned from listQueryShapes()');
coll.getPlanCache().clear();
// getPlansByQuery().
// Passing a query with an empty collation object should throw.
assert.throws(function() {
coll.getPlanCache().getPlansByQuery(
{query: {a: 'foo', b: 5}, sort: {}, projection: {}, collation: {}});
}, [], 'empty collation object should throw');
// Passing a query with an invalid collation object should throw.
assert.throws(function() {
coll.getPlanCache().getPlansByQuery(
{query: {a: 'foo', b: 5}, sort: {}, projection: {}, collation: {bad: "value"}});
}, [], 'invalid collation object should throw');
// Run a query so that an entry is inserted into the cache.
assert.commandWorked(
coll.runCommand("find", {filter: {a: 'foo', b: 5}, collation: {locale: "en_US"}}),
'find command failed');
// The query should have cached plans.
assert.lt(0,
coll.getPlanCache()
.getPlansByQuery(
{query: {a: 'foo', b: 5}, sort: {}, projection: {}, collation: {locale: 'en_US'}})
.plans.length,
'unexpected number of cached plans for query');
// Test passing the query, sort, projection, and collation to getPlansByQuery() as separate
// arguments.
assert.lt(
0,
coll.getPlanCache().getPlansByQuery({a: 'foo', b: 5}, {}, {}, {locale: 'en_US'}).plans.length,
'unexpected number of cached plans for query');
// Test passing the query, sort, projection, and collation to getPlansByQuery() as separate
// arguments.
assert.eq(0,
coll.getPlanCache().getPlansByQuery({a: 'foo', b: 5}).plans.length,
'unexpected number of cached plans for query');
// A query with a different collation should have no cached plans.
assert.eq(0,
coll.getPlanCache()
.getPlansByQuery(
{query: {a: 'foo', b: 5}, sort: {}, projection: {}, collation: {locale: 'fr_CA'}})
.plans.length,
'unexpected number of cached plans for query');
// A query with different string locations should have no cached plans.
assert.eq(
0,
coll.getPlanCache()
.getPlansByQuery(
{query: {a: 'foo', b: 'bar'}, sort: {}, projection: {}, collation: {locale: 'en_US'}})
.plans.length,
'unexpected number of cached plans for query');
coll.getPlanCache().clear();
// clearPlansByQuery().
// Passing a query with an empty collation object should throw.
assert.throws(function() {
coll.getPlanCache().clearPlansByQuery(
{query: {a: 'foo', b: 5}, sort: {}, projection: {}, collation: {}});
}, [], 'empty collation object should throw');
// Passing a query with an invalid collation object should throw.
assert.throws(function() {
coll.getPlanCache().clearPlansByQuery(
{query: {a: 'foo', b: 5}, sort: {}, projection: {}, collation: {bad: "value"}});
}, [], 'invalid collation object should throw');
// Run a query so that an entry is inserted into the cache.
assert.commandWorked(
coll.runCommand("find", {filter: {a: 'foo', b: 5}, collation: {locale: "en_US"}}),
'find command failed');
assert.eq(
1, coll.getPlanCache().listQueryShapes().length, 'unexpected cache size after running query');
// Dropping a query shape with a different collation should have no effect.
coll.getPlanCache().clearPlansByQuery(
{query: {a: 'foo', b: 5}, sort: {}, projection: {}, collation: {locale: 'fr_CA'}});
assert.eq(1,
coll.getPlanCache().listQueryShapes().length,
'unexpected cache size after dropping uncached query shape');
// Dropping a query shape with different string locations should have no effect.
coll.getPlanCache().clearPlansByQuery(
{query: {a: 'foo', b: 'bar'}, sort: {}, projection: {}, collation: {locale: 'en_US'}});
assert.eq(1,
coll.getPlanCache().listQueryShapes().length,
'unexpected cache size after dropping uncached query shape');
// Dropping query shape.
coll.getPlanCache().clearPlansByQuery(
{query: {a: 'foo', b: 5}, sort: {}, projection: {}, collation: {locale: 'en_US'}});
assert.eq(0,
coll.getPlanCache().listQueryShapes().length,
'unexpected cache size after dropping query shapes');
// Index filter commands.
// planCacheSetFilter should fail if 'collation' is an empty object.
assert.commandFailed(
coll.runCommand('planCacheSetFilter',
{query: {a: 'foo', b: 5}, collation: {}, indexes: [{a: 1, b: 1}]}),
'planCacheSetFilter should fail on empty collation object');
// planCacheSetFilter should fail if 'collation' is an invalid object.
assert.commandFailed(
coll.runCommand('planCacheSetFilter',
{query: {a: 'foo', b: 5}, collation: {bad: "value"}, indexes: [{a: 1, b: 1}]}),
'planCacheSetFilter should fail on invalid collation object');
// Set a plan cache filter.
assert.commandWorked(
coll.runCommand(
'planCacheSetFilter',
{query: {a: 'foo', b: 5}, collation: {locale: 'en_US'}, indexes: [{a: 1, b: 1}]}),
'planCacheSetFilter failed');
// Check the plan cache filter was added.
var res = coll.runCommand('planCacheListFilters');
assert.commandWorked(res, 'planCacheListFilters failed');
assert.eq(1, res.filters.length, 'unexpected number of plan cache filters');
assert.eq(res.filters[0],
{
query: {a: 'foo', b: 5},
sort: {},
projection: {},
collation: {
locale: 'en_US',
caseLevel: false,
caseFirst: 'off',
strength: 3,
numericOrdering: false,
alternate: 'non-ignorable',
maxVariable: 'punct',
normalization: false,
backwards: false,
version: '57.1'
},
indexes: [{a: 1, b: 1}]
},
'unexpected plan cache filter');
// planCacheClearFilters should fail if 'collation' is an empty object.
assert.commandFailed(
coll.runCommand('planCacheClearFilters', {query: {a: 'foo', b: 5}, collation: {}}),
'planCacheClearFilters should fail on empty collation object');
// planCacheSetFilter should fail if 'collation' is an invalid object.
assert.commandFailed(
coll.runCommand('planCacheClearFilters', {query: {a: 'foo', b: 5}, collation: {bad: 'value'}}),
'planCacheClearFilters should fail on invalid collation object');
// Clearing a plan cache filter with no collation should have no effect.
assert.commandWorked(coll.runCommand('planCacheClearFilters', {query: {a: 'foo', b: 5}}));
assert.eq(1,
coll.runCommand('planCacheListFilters').filters.length,
'unexpected number of plan cache filters');
// Clearing a plan cache filter with a different collation should have no effect.
assert.commandWorked(coll.runCommand('planCacheClearFilters',
{query: {a: 'foo', b: 5}, collation: {locale: 'fr_CA'}}));
assert.eq(1,
coll.runCommand('planCacheListFilters').filters.length,
'unexpected number of plan cache filters');
// Clearing a plan cache filter with different string locations should have no effect.
assert.commandWorked(coll.runCommand('planCacheClearFilters',
{query: {a: 'foo', b: 'bar', collation: {locale: 'en_US'}}}));
assert.eq(1,
coll.runCommand('planCacheListFilters').filters.length,
'unexpected number of plan cache filters');
// Clear plan cache filter.
assert.commandWorked(coll.runCommand('planCacheClearFilters',
{query: {a: 'foo', b: 5}, collation: {locale: 'en_US'}}));
assert.eq(0,
coll.runCommand('planCacheListFilters').filters.length,
'unexpected number of plan cache filters');
})();