diff options
author | David Storch <david.storch@10gen.com> | 2014-05-21 10:07:07 -0400 |
---|---|---|
committer | David Storch <david.storch@10gen.com> | 2014-05-22 18:04:51 -0400 |
commit | 7dcbdc440a56fef19a561f513d8eddd1c2a2b27f (patch) | |
tree | ffa5a8853cad592b2e3b608181b1e792a98ffc17 /jstests/core/plan_cache_shell_helpers.js | |
parent | 3420a0121eaf0684b06a506d3758dd0d16af740f (diff) | |
download | mongo-7dcbdc440a56fef19a561f513d8eddd1c2a2b27f.tar.gz |
SERVER-13675 do not cache plans if there is a tie
Diffstat (limited to 'jstests/core/plan_cache_shell_helpers.js')
-rw-r--r-- | jstests/core/plan_cache_shell_helpers.js | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/jstests/core/plan_cache_shell_helpers.js b/jstests/core/plan_cache_shell_helpers.js new file mode 100644 index 00000000000..9ac9554ef00 --- /dev/null +++ b/jstests/core/plan_cache_shell_helpers.js @@ -0,0 +1,201 @@ +// Test the shell helpers which wrap the plan cache commands. + +var t = db.jstests_plan_cache_shell_helpers; +t.drop(); + +// Utility function to list query shapes in cache. +function getShapes(collection) { + if (collection == undefined) { + collection = t; + } + var res = collection.runCommand('planCacheListQueryShapes'); + print('planCacheListQueryShapes() = ' + tojson(res)); + assert.commandWorked(res, 'planCacheListQueryShapes failed'); + assert(res.hasOwnProperty('shapes'), 'shapes missing from planCacheListQueryShapes result'); + return res.shapes; +} +// Utility function to list plans for a query. +function getPlans(query, sort, projection) { + var key = {query: query, sort: sort, projection: projection}; + var res = t.runCommand('planCacheListPlans', key); + assert.commandWorked(res, 'planCacheListPlans(' + tojson(key, '', true) + ' failed'); + assert(res.hasOwnProperty('plans'), 'plans missing from planCacheListPlans(' + + tojson(key, '', true) + ') result'); + return res.plans; +} + +// Add data an indices. +var n = 200; +for (var i = 0; i < n; i++) { + t.save({a:i, b: -1, c: 1}); +} +t.ensureIndex({a: 1}); +t.ensureIndex({b: 1}); + +// Populate plan cache. +var queryB = {a: {$gte: 199}, b: -1}; +var projectionB = {_id: 0, b: 1}; +var sortC = {c: -1}; +assert.eq(1, t.find(queryB, projectionB).sort(sortC).itcount(), 'unexpected document count'); +assert.eq(1, t.find(queryB, projectionB).itcount(), 'unexpected document count'); +assert.eq(1, t.find(queryB).sort(sortC).itcount(), 'unexpected document count'); +assert.eq(1, t.find(queryB).itcount(), 'unexpected document count'); +assert.eq(4, getShapes().length, 'unexpected number of query shapes in plan cache'); + +// +// PlanCache.getName +// + +var planCache = t.getPlanCache(); +assert.eq(t.getName(), planCache.getName(), 'name of plan cache should match collection'); + +// +// PlanCache.help +// +planCache.help(); + +// +// shellPrint +// + +print('plan cache:'); +print(planCache); + +// +// collection.getPlanCache().listQueryShapes +// + +var missingCollection = db.jstests_plan_cache_missing; +missingCollection.drop(); +// should return empty array on non-existent collection. +assert.eq(0, missingCollection.getPlanCache().listQueryShapes().length, + 'collection.getPlanCache().listQueryShapes() should return empty results ' + + 'on non-existent collection'); +assert.eq(getShapes(), planCache.listQueryShapes(), + 'unexpected collection.getPlanCache().listQueryShapes() shell helper result'); + +// +// collection.getPlanCache().getPlansByQuery +// + +// should return empty array on non-existent query shape. +assert.eq(0, planCache.getPlansByQuery({unknownfield: 1}).length, + 'collection.getPlanCache().getPlansByQuery() should return empty results ' + + 'on non-existent collection'); +// should error on missing required field query. +assert.throws(function() { planCache.getPlansByQuery() }); + +// Invoke with various permutations of required (query) and optional (projection, sort) arguments. +assert.eq(getPlans(queryB, sortC, projectionB), planCache.getPlansByQuery(queryB, projectionB, + sortC), + 'plans from collection.getPlanCache().getPlansByQuery() different from command result'); +assert.eq(getPlans(queryB, {}, projectionB), planCache.getPlansByQuery(queryB, projectionB), + 'plans from collection.getPlanCache().getPlansByQuery() different from command result'); +assert.eq(getPlans(queryB, sortC, {}), planCache.getPlansByQuery(queryB, undefined, sortC), + 'plans from collection.getPlanCache().getPlansByQuery() different from command result'); +assert.eq(getPlans(queryB, {}, {}), planCache.getPlansByQuery(queryB), + 'plans from collection.getPlanCache().getPlansByQuery() different from command result'); + +// getPlansByQuery() will also accept a single argument with the query shape object +// as an alternative to specifying the query, sort and projection parameters separately. +// Format of query shape object: +// { +// query: <query>, +// projection: <projection>, +// sort: <sort> +// } +var shapeB = {query: queryB, projection: projectionB, sort: sortC}; +assert.eq(getPlans(queryB, sortC, projectionB), + planCache.getPlansByQuery(shapeB), + 'collection.getPlanCache().getPlansByQuery() did not accept query shape object'); + +// Should return empty array on missing or extra fields in query shape object. +// The entire invalid query shape object will be passed to the command +// as the 'query' component which will result in the server returning an empty +// array of plans. +assert.eq(0, planCache.getPlansByQuery({query: queryB}).length, + 'collection.getPlanCache.getPlansByQuery should return empty results on ' + + 'incomplete query shape'); +assert.eq(0, planCache.getPlansByQuery({query: queryB, sort: sortC, + projection: projectionB, + unknown_field: 1}).length, + 'collection.getPlanCache.getPlansByQuery should return empty results on ' + + 'invalid query shape'); + + + +// +// collection.getPlanCache().clearPlansByQuery +// + +// should not error on non-existent query shape. +planCache.clearPlansByQuery({unknownfield: 1}); +// should error on missing required field query. +assert.throws(function() { planCache.clearPlansByQuery() }); + +// Invoke with various permutations of required (query) and optional (projection, sort) arguments. +planCache.clearPlansByQuery(queryB, projectionB); +assert.eq(3, getShapes().length, + 'query shape not dropped after running collection.getPlanCache().clearPlansByQuery()'); + +planCache.clearPlansByQuery(queryB, undefined, sortC); +assert.eq(2, getShapes().length, + 'query shape not dropped after running collection.getPlanCache().clearPlansByQuery()'); + +planCache.clearPlansByQuery(queryB); +assert.eq(1, getShapes().length, + 'query shape not dropped after running collection.getPlanCache().clearPlansByQuery()'); + +planCache.clear(); +assert.eq(0, getShapes().length, 'plan cache not empty'); + +// clearPlansByQuery() will also accept a single argument with the query shape object +// as an alternative to specifying the query, sort and projection parameters separately. +// Format of query shape object: +// { +// query: <query>, +// projection: <projection>, +// sort: <sort> +// } + +// Repopulate cache +assert.eq(1, t.find(queryB).sort(sortC).itcount(), 'unexpected document count'); + +// Clear using query shape object. +planCache.clearPlansByQuery({query: queryB, projection: {}, sort: sortC}); +assert.eq(0, getShapes().length, + 'collection.getPlanCache().clearPlansByQuery() did not accept query shape object'); + +// Should not error on missing or extra fields in query shape object. +planCache.clearPlansByQuery({query: queryB}); +planCache.clearPlansByQuery({query: queryB, sort: sortC, projection: projectionB, + unknown_field: 1}); + + + +// +// collection.getPlanCache().clear +// + +// Should not error on non-existent collection. +missingCollection.getPlanCache().clear(); +// Re-populate plan cache with 1 query shape. +assert.eq(1, t.find(queryB, projectionB).sort(sortC).itcount(), 'unexpected document count'); +assert.eq(1, getShapes().length, 'plan cache should not be empty after running cacheable query'); +// Clear cache. +planCache.clear(); +assert.eq(0, getShapes().length, 'plan cache not empty after clearing'); + +// +// explain and plan cache +// Running explain should not mutate the plan cache. +// + +planCache.clear(); + +// MultiPlanRunner explain +var multiPlanRunnerExplain = t.find(queryB, projectionB).sort(sortC).explain(true); + +print('multi plan runner explain = ' + tojson(multiPlanRunnerExplain)); + +assert.eq(0, getShapes().length, 'explain should not mutate plan cache'); |