diff options
-rw-r--r-- | jstests/core/index_id_options.js | 26 | ||||
-rw-r--r-- | jstests/core/index_partial_create_drop.js | 22 | ||||
-rw-r--r-- | jstests/core/index_partial_read_ops.js | 77 | ||||
-rw-r--r-- | jstests/core/index_partial_write_ops.js | 5 | ||||
-rw-r--r-- | jstests/noPassthrough/index_partial_no_explain_cmds.js | 29 | ||||
-rw-r--r-- | jstests/noPassthrough/index_partial_no_hint_cmds.js | 59 |
6 files changed, 131 insertions, 87 deletions
diff --git a/jstests/core/index_id_options.js b/jstests/core/index_id_options.js index 91e57b73dc6..5333c12daa8 100644 --- a/jstests/core/index_id_options.js +++ b/jstests/core/index_id_options.js @@ -1,11 +1,12 @@ // Test creation of the _id index with various options: // - _id indexes must be unique. // - _id indexes can't be sparse. +// - _id indexes can't be partial indexes. var coll = db.index_id_options; // -// Uniqueness. +// Unique index. // // Creation of _id index with "non-zero" value for "unique" should succeed. @@ -31,7 +32,7 @@ assert.commandWorked(coll.runCommand("create", {autoIndexId: false})); assert.commandFailed(coll.ensureIndex({_id: 1}, {unique: NumberLong(0)})); // -// Sparseness. +// Sparse index. // // Creation of _id index with "non-zero" value for "sparse" should fail. @@ -55,3 +56,24 @@ assert.commandWorked(coll.ensureIndex({_id: 1}, {sparse: 0})); coll.drop(); assert.commandWorked(coll.runCommand("create", {autoIndexId: false})); assert.commandWorked(coll.ensureIndex({_id: 1}, {sparse: NumberLong(0)})); + +// +// Partial index. +// + +// Creation of _id index with any value for "partialFilterExpression" should fail. +coll.drop(); +assert.commandWorked(coll.runCommand("create", {autoIndexId: false})); +assert.commandFailed(coll.ensureIndex({_id: 1}, {partialFilterExpression: false})); +coll.drop(); +assert.commandWorked(coll.runCommand("create", {autoIndexId: false})); +assert.commandFailed(coll.ensureIndex({_id: 1}, {partialFilterExpression: null})); +coll.drop(); +assert.commandWorked(coll.runCommand("create", {autoIndexId: false})); +assert.commandFailed(coll.ensureIndex({_id: 1}, {partialFilterExpression: {}})); +coll.drop(); +assert.commandWorked(coll.runCommand("create", {autoIndexId: false})); +assert.commandFailed(coll.ensureIndex({_id: 1}, {partialFilterExpression: {a: 1}})); +coll.drop(); +assert.commandWorked(coll.runCommand("create", {autoIndexId: false})); +assert.commandFailed(coll.ensureIndex({_id: 1}, {partialFilterExpression: []})); diff --git a/jstests/core/index_partial_create_drop.js b/jstests/core/index_partial_create_drop.js index 4f9f9c514eb..d997f0fcfa3 100644 --- a/jstests/core/index_partial_create_drop.js +++ b/jstests/core/index_partial_create_drop.js @@ -5,7 +5,7 @@ var isMongos = (db.runCommand("isMaster").msg === "isdbgrid"); var coll = db.index_partial_create_drop; - var getNumKeys = function(idxName) { + var getNumKeys = function (idxName) { var res = assert.commandWorked(coll.validate(true)); var kpi; if (isMongos) { @@ -19,7 +19,7 @@ coll.drop(); - // Check bad partialFilterExpression spec on create. + // Check bad filter spec on create. assert.commandFailed(coll.ensureIndex({x: 1}, {partialFilterExpression: 5})); assert.commandFailed(coll.ensureIndex({x: 1}, {partialFilterExpression: {x: {$asdasd: 3}}})); assert.commandFailed(coll.ensureIndex({x: 1}, {partialFilterExpression: {$and: 5}})); @@ -40,7 +40,8 @@ assert.eq(1, coll.getIndexes().length); // Create partial index in background. - assert.commandWorked(coll.ensureIndex({x: 1}, {background: true, partialFilterExpression: {a: {$lt: 5}}})); + assert.commandWorked(coll.ensureIndex({x: 1}, {background: true, + partialFilterExpression: {a: {$lt: 5}}})); assert.eq(5, getNumKeys("x_1")); assert.commandWorked(coll.dropIndex({x: 1})); assert.eq(1, coll.getIndexes().length); @@ -54,15 +55,14 @@ // Partial indexes can't also be sparse indexes. assert.commandFailed(coll.ensureIndex({x: 1}, {partialFilterExpression: {a: 1}, sparse: true})); assert.commandFailed(coll.ensureIndex({x: 1}, {partialFilterExpression: {a: 1}, sparse: 1})); - assert.commandWorked(coll.ensureIndex({x: 1}, {partialFilterExpression: {a: 1}, sparse: false})); + assert.commandWorked(coll.ensureIndex({x: 1}, {partialFilterExpression: {a: 1}, + sparse: false})); assert.eq(2, coll.getIndexes().length); assert.commandWorked(coll.dropIndex({x: 1})); + assert.eq(1, coll.getIndexes().length); - // _id index can't be a partial index. SERVER-18170 - //coll.drop(); - //assert.commandWorked(db.createCollection("index_partial_basic", - // {autoIndexId: false})); - //assert.commandFailed(coll.ensureIndex({_id: 1}, {partialFilterExpression: {a: 1}})); - + // SERVER-18858: Verify that query compatible w/ partial index succeeds after index drop. + assert.commandWorked(coll.ensureIndex({x: 1}, {partialFilterExpression: {a: {$lt: 5}}})); + assert.commandWorked(coll.dropIndex({x: 1})); + assert.eq(1, coll.find({x: 0, a: 0}).itcount()); })(); - diff --git a/jstests/core/index_partial_read_ops.js b/jstests/core/index_partial_read_ops.js index 40005d510dc..ef5c30d25a6 100644 --- a/jstests/core/index_partial_read_ops.js +++ b/jstests/core/index_partial_read_ops.js @@ -1,25 +1,78 @@ // Read ops tests for partial indexes. +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + (function() { "use strict"; - var ret; + var explain; var coll = db.index_partial_read_ops; coll.drop(); - coll.ensureIndex({x: 1}, {partialFilterExpression: {a: 1}}); + assert.commandWorked(coll.ensureIndex({x: 1}, {partialFilterExpression: {a: {$lte: 1.5}}})); assert.writeOK(coll.insert({x: 5, a: 2})); // Not in index. assert.writeOK(coll.insert({x: 6, a: 1})); // In index. - // Verify index counts and basic functionality. - assert.eq(1, coll.find({x: 6}).itcount()); - assert.eq(1, coll.find({x: 6, a: 1}).hint({x: 1}).itcount()); - assert.eq(1, coll.find({x: {$gt: 1}, a: 1}).hint({x: 1}).itcount()); - // Hint is bad because a < 5 is not a subset of a = 1 - assert.throws(function() { - coll.find({x: 6, a: {$lt: 5}}).hint({x: 1}).itcount() - }); + // + // Verify basic functionality with find(). + // + + // find() operations that should use index. + explain = coll.explain('executionStats').find({x: 6, a: 1}).finish(); + assert.eq(1, explain.executionStats.nReturned); + assert(isIxscan(explain.queryPlanner.winningPlan)); + explain = coll.explain('executionStats').find({x: {$gt: 1}, a: 1}).finish(); + assert.eq(1, explain.executionStats.nReturned); + assert(isIxscan(explain.queryPlanner.winningPlan)); + explain = coll.explain('executionStats').find({x: 6, a: {$lte: 1}}).finish(); + assert.eq(1, explain.executionStats.nReturned); + assert(isIxscan(explain.queryPlanner.winningPlan)); + + // find() operations that should not use index. + explain = coll.explain('executionStats').find({x: 6, a: {$lt: 1.6}}).finish(); + assert.eq(1, explain.executionStats.nReturned); + assert(isCollscan(explain.queryPlanner.winningPlan)); + explain = coll.explain('executionStats').find({x: 6}).finish(); + assert.eq(1, explain.executionStats.nReturned); + assert(isCollscan(explain.queryPlanner.winningPlan)); + + // + // Verify basic functionality with the count command. + // + + // Count operation that should use index. + explain = coll.explain('executionStats').count({x: {$gt: 1}, a: 1}); + assert(isIxscan(explain.queryPlanner.winningPlan)); + + // Count operation that should not use index. + explain = coll.explain('executionStats').count({x: {$gt: 1}, a: 2}); + assert(isCollscan(explain.queryPlanner.winningPlan)); + + // + // Verify basic functionality with the aggregate command. + // + + // Aggregate operation that should use index. + explain = coll.aggregate([{$match: {x: {$gt: 1}, a: 1}}], {explain: true}).stages[0].$cursor; + assert(isIxscan(explain.queryPlanner.winningPlan)); + + // Aggregate operation that should not use index. + explain = coll.aggregate([{$match: {x: {$gt: 1}, a: 2}}], {explain: true}).stages[0].$cursor; + assert(isCollscan(explain.queryPlanner.winningPlan)); + + // + // Verify basic functionality with the findAndModify command. + // - // Count has special query path - assert.eq(1, coll.find({x: {$gt: 1}, a: 1}).hint({x: 1}).count()); + // findAndModify operation that should use index. + explain = coll.explain('executionStats').findAndModify({query: {x: {$gt: 1}, a: 1}, + update: {$inc: {x: 1}}}); + assert.eq(1, explain.executionStats.nReturned); + assert(isIxscan(explain.queryPlanner.winningPlan)); + // findAndModify operation that should not use index. + explain = coll.explain('executionStats').findAndModify({query: {x: {$gt: 1}, a: 2}, + update: {$inc: {x: 1}}}); + assert.eq(1, explain.executionStats.nReturned); + assert(isCollscan(explain.queryPlanner.winningPlan)); })(); diff --git a/jstests/core/index_partial_write_ops.js b/jstests/core/index_partial_write_ops.js index 6ddc4c9afa6..92d3720d07e 100644 --- a/jstests/core/index_partial_write_ops.js +++ b/jstests/core/index_partial_write_ops.js @@ -1,11 +1,11 @@ -// Write ops tests for partial indexes +// Write ops tests for partial indexes. (function() { "use strict"; var isMongos = (db.runCommand("isMaster").msg === "isdbgrid"); var coll = db.index_partial_write_ops; - var getNumKeys = function(idxName) { + var getNumKeys = function (idxName) { var res = assert.commandWorked(coll.validate(true)); var kpi; if (isMongos) { @@ -60,5 +60,4 @@ // Delete that does affect partial index. assert.writeOK(coll.remove({x: 6})); assert.eq(0, getNumKeys("x_1")); - })(); diff --git a/jstests/noPassthrough/index_partial_no_explain_cmds.js b/jstests/noPassthrough/index_partial_no_explain_cmds.js new file mode 100644 index 00000000000..9ea81569d4d --- /dev/null +++ b/jstests/noPassthrough/index_partial_no_explain_cmds.js @@ -0,0 +1,29 @@ +// Test partial indexes with commands that don't use explain. These commands are tested against +// mongod with the --notablescan flag set, so that they fail if the index is not used. +(function() { + "use strict"; + var runner = MongoRunner.runMongod({setParameter: "notablescan=1"}); + var coll = runner.getDB("test").index_partial_no_explain_cmds; + var ret; + + coll.drop(); + + assert.commandWorked(coll.ensureIndex({x: 1}, {partialFilterExpression: {a: 1}})); + + assert.writeOK(coll.insert({_id: 1, x: 5, a: 2})); // Not in index. + assert.writeOK(coll.insert({_id: 2, x: 6, a: 1})); // In index. + + // Verify we will throw if the partial index can't be used. + assert.throws(function() { coll.find({x: {$gt: 1}, a: 2}).itcount(); }); + + // Test mapReduce. + var mapFunc = function() { emit(this._id, 1); }; + var reduceFunc = function (keyId, countArray) { return Array.sum(countArray); }; + + ret = coll.mapReduce(mapFunc, reduceFunc, {out: "inline", query: {x: {$gt: 1}, a: 1}}); + assert.eq(1, ret.counts.input); + + // Test distinct. + ret = coll.distinct("a", {x: {$gt: 1}, a: 1}); + assert.eq(1, ret.length); +})(); diff --git a/jstests/noPassthrough/index_partial_no_hint_cmds.js b/jstests/noPassthrough/index_partial_no_hint_cmds.js deleted file mode 100644 index eb126432dd9..00000000000 --- a/jstests/noPassthrough/index_partial_no_hint_cmds.js +++ /dev/null @@ -1,59 +0,0 @@ -// Test partial indexes with commands that won't test well -// under sharding passthrough -(function () { - "use strict"; - // Launch mongod with notable scan, since these tests are - // centered around operations that can't take a hint. - var runner = MongoRunner.runMongod({setParameter: "notablescan=1"}); - var coll = runner.getDB("test").index_partial_no_hint_cmds; - var ret; - - var getNumKeys = function(idxName) { - var res = assert.commandWorked(coll.validate(true)); - return res.keysPerIndex[coll.getFullName() + ".$" + idxName]; - }; - - coll.drop(); - - assert.commandWorked(coll.ensureIndex({x: 1}, {partialFilterExpression: {a: 1}})); - - assert.writeOK(coll.insert({_id: 1, x: 5, a: 2})); // Not in index. - assert.writeOK(coll.insert({_id: 2, x: 6, a: 1})); // In index. - - // Verify we will throw if the partial index isn't used. Find won't - // necessarily assert in this case, but findAndModify does consistenly. - assert.throws(function() { - coll.findAndModify({query: {x: {$gt: 1}, a: 2}, update: {$inc: {x: 1}}, new: true}) - }); - - // Verify mapReduce is using the partial index. - var mapFunc = function () { emit(this._id, 1); }; - var reduceFunc = function (keyId, countArray) { return Array.sum(countArray); }; - - ret = coll.mapReduce(mapFunc, reduceFunc, {out: "inline", query: {x: {$gt: 1}, a: 1}}); - assert.eq(1, ret.counts.input); - - // Distinct and count have special query paths, but can't take hint. - ret = coll.distinct("a", {x: {$gt: 1}, a: 1}); - assert.eq(1, ret.length); - - ret = coll.count({x: {$gt: 1}, a: 1}); - assert.eq(1, ret); - - // Verify findAndModify uses the partial index. - ret = coll.findAndModify({query: {x: {$gt: 1}, a: 1}, - update: {$inc: {x: 1}}, new: true}); - assert.eq(2, ret._id); - assert.eq(1, getNumKeys("x_1")); - - - ret = coll.findAndModify({query:{x:{$gt:6}, a: 1}, - update: {$inc: {x: 1}}, new: true}); - assert.eq(2, ret._id); - assert.eq(1, getNumKeys("x_1")); - - // Check that aggregate is using the partial index. - ret = coll.aggregate([{$match: {x: {$gt: 1}, a: 1}}, - {$group: {_id:1, count: {$sum: 1}}}]).next(); - assert.eq(1, ret.count); -})(); |