diff options
Diffstat (limited to 'jstests')
48 files changed, 620 insertions, 194 deletions
diff --git a/jstests/auth/repl_auth.js b/jstests/auth/repl_auth.js index f2e6739be1e..a5bde8167c9 100644 --- a/jstests/auth/repl_auth.js +++ b/jstests/auth/repl_auth.js @@ -49,18 +49,18 @@ rsTest.getSecondaries().forEach(function(sec) { // pool if a different secondary is selected from the previous one so we have to iterate // a couple of times. for (var x = 0; x < 20; x++) { - var explain = fooDB0.user.find().readPref('secondary').explain(); + var explain = fooDB0.user.find().readPref('secondary').explain('executionStats'); assert.eq(1, explain.executionStats.nReturned); assert.throws(function() { - explain = barDB0.user.find().readPref('secondary').explain(); + explain = barDB0.user.find().readPref('secondary').explain('executionStats'); }); assert.throws(function() { - explain = fooDB1.user.find().readPref('secondary').explain(); + explain = fooDB1.user.find().readPref('secondary').explain('executionStats'); }); - explain = barDB1.user.find().readPref('secondary').explain(); + explain = barDB1.user.find().readPref('secondary').explain('executionStats'); assert.eq(1, explain.executionStats.nReturned); } diff --git a/jstests/core/and3.js b/jstests/core/and3.js index 3f223265522..a0a779937b1 100644 --- a/jstests/core/and3.js +++ b/jstests/core/and3.js @@ -9,7 +9,7 @@ t.save( {a:'foo'} ); t.ensureIndex( {a:1} ); function checkScanMatch( query, docsExamined, n ) { - var e = t.find( query ).hint( {a:1} ).explain(); + var e = t.find( query ).hint( {a:1} ).explain( "executionStats" ); assert.eq( docsExamined, e.executionStats.totalDocsExamined ); assert.eq( n, e.executionStats.nReturned ); } diff --git a/jstests/core/batch_size.js b/jstests/core/batch_size.js index 645ee0031ab..389c9903eba 100644 --- a/jstests/core/batch_size.js +++ b/jstests/core/batch_size.js @@ -63,15 +63,15 @@ assert.eq(15, t.find({a: {$gte: 85}}).sort({b: 1}).hint({b: 1}).batchSize(2).itc assert.eq(6, t.find({a: {$gte: 85}}).sort({b: 1}).hint({b: 1}).limit(6).itcount(), 'P'); // With explain. -var explain = t.find({a: {$gte: 85}}).sort({b: 1}).batchSize(2).explain(); +var explain = t.find({a: {$gte: 85}}).sort({b: 1}).batchSize(2).explain("executionStats"); assert.eq(15, explain.executionStats.nReturned, 'Q'); -explain = t.find({a: {$gte: 85}}).sort({b: 1}).limit(6).explain(); +explain = t.find({a: {$gte: 85}}).sort({b: 1}).limit(6).explain("executionStats"); assert.eq(6, explain.executionStats.nReturned, 'R'); // Double check that we're not scanning more stuff than we have to. // In order to get the sort using index 'a', we should need to scan // about 50 keys and 50 documents. -var explain = t.find({a: {$gte: 50}}).sort({b: 1}).hint({a: 1}).limit(6).explain(); +var explain = t.find({a: {$gte: 50}}).sort({b: 1}).hint({a: 1}).limit(6).explain("executionStats"); assert.lte(explain.executionStats.totalKeysExamined, 60, 'S'); assert.lte(explain.executionStats.totalDocsExamined, 60, 'T'); assert.eq(explain.executionStats.nReturned, 6, 'U'); diff --git a/jstests/core/covered_index_compound_1.js b/jstests/core/covered_index_compound_1.js index 632a2330b44..9090f3168cd 100644 --- a/jstests/core/covered_index_compound_1.js +++ b/jstests/core/covered_index_compound_1.js @@ -11,49 +11,61 @@ for (i=0;i<100;i++) { coll.ensureIndex({a:1,b:-1,c:1}) // Test equality - all indexed fields queried and projected -var plan = coll.find({a:10, b:"strvar_10", c:0}, {a:1, b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() +var plan = coll.find({a:10, b:"strvar_10", c:0}, {a:1, b:1, c:1, _id:0}) + .hint({a:1, b:-1, c:1}) + .explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "compound.1.1 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "compound.1.1 - nscannedObjects should be 0 for covered query") // Test query on subset of fields queried and project all -var plan = coll.find({a:26, b:"strvar_0"}, {a:1, b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() +var plan = coll.find({a:26, b:"strvar_0"}, {a:1, b:1, c:1, _id:0}) + .hint({a:1, b:-1, c:1}) + .explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "compound.1.2 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "compound.1.2 - nscannedObjects should be 0 for covered query") // Test query on all fields queried and project subset -var plan = coll.find({a:38, b:"strvar_12", c: 8}, {b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() +var plan = coll.find({a:38, b:"strvar_12", c: 8}, {b:1, c:1, _id:0}) + .hint({a:1, b:-1, c:1}) + .explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "compound.1.3 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "compound.1.3 - nscannedObjects should be 0 for covered query") // Test no query -var plan = coll.find({}, {b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() +var plan = coll.find({}, {b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "compound.1.4 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "compound.1.4 - nscannedObjects should be 0 for covered query") // Test range query -var plan = coll.find({a:{$gt:25,$lt:43}}, {b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() +var plan = coll.find({a:{$gt:25,$lt:43}}, {b:1, c:1, _id:0}) + .hint({a:1, b:-1, c:1}) + .explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "compound.1.5 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "compound.1.5 - nscannedObjects should be 0 for covered query") // Test in query -var plan = coll.find({a:38, b:"strvar_12", c:{$in:[5,8]}}, {b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() +var plan = coll.find({a:38, b:"strvar_12", c:{$in:[5,8]}}, {b:1, c:1, _id:0}) + .hint({a:1, b:-1, c:1}) + .explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "compound.1.6 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "compound.1.6 - nscannedObjects should be 0 for covered query") // Test no result -var plan = coll.find({a:38, b:"strvar_12", c:55},{a:1, b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() +var plan = coll.find({a:38, b:"strvar_12", c:55},{a:1, b:1, c:1, _id:0}) + .hint({a:1, b:-1, c:1}) + .explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "compound.1.7 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, diff --git a/jstests/core/covered_index_negative_1.js b/jstests/core/covered_index_negative_1.js index 4b538b7c275..b2ab81b37cc 100644 --- a/jstests/core/covered_index_negative_1.js +++ b/jstests/core/covered_index_negative_1.js @@ -18,28 +18,30 @@ coll.ensureIndex({d:1}) coll.ensureIndex({f:"hashed"}) // Test no projection -var plan = coll.find({a:10, b:"strvar_10", c:0}).hint({a:1, b:-1, c:1}).explain() +var plan = coll.find({a:10, b:"strvar_10", c:0}).hint({a:1, b:-1, c:1}).explain("executionStats"); assert(!isIndexOnly(plan.queryPlanner.winningPlan), "negative.1.1 - indexOnly should be false on a non covered query") assert.neq(0, plan.executionStats.totalDocsExamined, "negative.1.1 - docs examined should not be 0 for a non covered query") // Test projection and not excluding _id -var plan = coll.find({a:10, b:"strvar_10", c:0},{a:1, b:1, c:1}).hint({a:1, b:-1, c:1}).explain() +var plan = coll.find({a:10, b:"strvar_10", c:0},{a:1, b:1, c:1}) + .hint({a:1, b:-1, c:1}) + .explain("executionStats"); assert(!isIndexOnly(plan.queryPlanner.winningPlan), "negative.1.2 - indexOnly should be false on a non covered query") assert.neq(0, plan.executionStats.totalDocsExamined, "negative.1.2 - docs examined should not be 0 for a non covered query") // Test projection of non-indexed field -var plan = coll.find({d:100},{d:1, c:1, _id:0}).hint({d:1}).explain() +var plan = coll.find({d:100},{d:1, c:1, _id:0}).hint({d:1}).explain("executionStats"); assert(!isIndexOnly(plan.queryPlanner.winningPlan), "negative.1.3 - indexOnly should be false on a non covered query") assert.neq(0, plan.executionStats.totalDocsExamined, "negative.1.3 - docs examined should not be 0 for a non covered query") // Test query and projection on a multi-key index -var plan = coll.find({e:99},{e:1, _id:0}).hint({e:1}).explain() +var plan = coll.find({e:99},{e:1, _id:0}).hint({e:1}).explain("executionStats"); assert(!isIndexOnly(plan.queryPlanner.winningPlan), "negative.1.4 - indexOnly should be false on a non covered query") assert.neq(0, plan.executionStats.totalDocsExamined, @@ -59,14 +61,16 @@ assert.neq(0, plan.executionStats.totalDocsExamined, // assert.neq(0, plan.nscannedObjects, "negative.1.6 - nscannedObjects should not be 0 for a non covered query") // Test query on non-indexed field -var plan = coll.find({d:{$lt:1000}},{a:1, b:1, c:1, _id:0}).hint({a:1, b:-1, c:1}).explain() +var plan = coll.find({d:{$lt:1000}},{a:1, b:1, c:1, _id:0}) + .hint({a:1, b:-1, c:1}) + .explain("executionStats"); assert(!isIndexOnly(plan.queryPlanner.winningPlan), "negative.1.7 - indexOnly should be false on a non covered query") assert.neq(0, plan.executionStats.totalDocsExamined, "negative.1.7 - docs examined should not be 0 for a non covered query") // Test query on hashed indexed field -var plan = coll.find({f:10},{f:1, _id:0}).hint({f:"hashed"}).explain() +var plan = coll.find({f:10},{f:1, _id:0}).hint({f:"hashed"}).explain("executionStats"); assert(!isIndexOnly(plan.queryPlanner.winningPlan), "negative.1.8 - indexOnly should be false on a non covered query") assert.neq(0, plan.executionStats.totalDocsExamined, diff --git a/jstests/core/covered_index_simple_1.js b/jstests/core/covered_index_simple_1.js index 146f0751f1c..3edde455754 100644 --- a/jstests/core/covered_index_simple_1.js +++ b/jstests/core/covered_index_simple_1.js @@ -20,49 +20,49 @@ coll.insert({foo:null}) coll.ensureIndex({foo:1}) // Test equality with int value -var plan = coll.find({foo:1}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({foo:1}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.1.1 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.1.1 - docs examined should be 0 for covered query") // Test equality with string value -var plan = coll.find({foo:"string"}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({foo:"string"}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.1.2 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.1.2 - docs examined should be 0 for covered query") // Test equality with doc value -var plan = coll.find({foo:{bar:1}}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({foo:{bar:1}}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.1.3 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.1.3 - docs examined should be 0 for covered query") // Test no query -var plan = coll.find({}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.1.4 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.1.4 - docs examined should be 0 for covered query") // Test range query -var plan = coll.find({foo:{$gt:2,$lt:6}}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({foo:{$gt:2,$lt:6}}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.1.5 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.1.5 - docs examined should be 0 for covered query") // Test in query -var plan = coll.find({foo:{$in:[5,8]}}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({foo:{$in:[5,8]}}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.1.6 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.1.6 - docs examined should be 0 for covered query") // Test no return -var plan = coll.find({foo:"2"}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({foo:"2"}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.1.7 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, diff --git a/jstests/core/covered_index_simple_2.js b/jstests/core/covered_index_simple_2.js index 014f235b711..7ca05b3f461 100644 --- a/jstests/core/covered_index_simple_2.js +++ b/jstests/core/covered_index_simple_2.js @@ -14,42 +14,42 @@ coll.insert({foo:null}) coll.ensureIndex({foo:1},{unique:true}) // Test equality with int value -var plan = coll.find({foo:1}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({foo:1}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.2.1 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.2.1 - docs examined should be 0 for covered query") // Test equality with string value -var plan = coll.find({foo:"string"}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({foo:"string"}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.2.2 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.2.2 - docs examined should be 0 for covered query") // Test equality with int value on a dotted field -var plan = coll.find({foo:{bar:1}}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({foo:{bar:1}}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.2.3 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.2.3 - docs examined should be 0 for covered query"); // Test no query -var plan = coll.find({}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.2.4 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.2.4 - docs examined should be 0 for covered query"); // Test range query -var plan = coll.find({foo:{$gt:2,$lt:6}}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({foo:{$gt:2,$lt:6}}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.2.5 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.2.5 - docs examined should be 0 for covered query"); // Test in query -var plan = coll.find({foo:{$in:[5,8]}}, {foo:1, _id:0}).hint({foo:1}).explain() +var plan = coll.find({foo:{$in:[5,8]}}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.2.6 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, diff --git a/jstests/core/covered_index_simple_3.js b/jstests/core/covered_index_simple_3.js index 32f411798ec..88293fe68bd 100644 --- a/jstests/core/covered_index_simple_3.js +++ b/jstests/core/covered_index_simple_3.js @@ -17,49 +17,49 @@ coll.insert({foo:null}); coll.ensureIndex({foo:1}, {sparse:true, unique:true}); // Test equality with int value -var plan = coll.find({foo:1}, {foo:1, _id:0}).hint({foo:1}).explain(); +var plan = coll.find({foo:1}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.3.1 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.3.1 - docs examined should be 0 for covered query") // Test equality with string value -var plan = coll.find({foo:"string"}, {foo:1, _id:0}).hint({foo:1}).explain(); +var plan = coll.find({foo:"string"}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.3.2 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.3.2 - docs examined should be 0 for covered query") // Test equality with int value on a dotted field -var plan = coll.find({foo:{bar:1}}, {foo:1, _id:0}).hint({foo:1}).explain(); +var plan = coll.find({foo:{bar:1}}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.3.3 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.3.3 - docs examined should be 0 for covered query") // Test no query -var plan = coll.find({}, {foo:1, _id:0}).hint({foo:1}).explain(); +var plan = coll.find({}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.3.4 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.3.4 - docs examined should be 0 for covered query") // Test range query -var plan = coll.find({foo:{$gt:2,$lt:6}}, {foo:1, _id:0}).hint({foo:1}).explain(); +var plan = coll.find({foo:{$gt:2,$lt:6}}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.3.5 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.3.5 - docs examined should be 0 for covered query") // Test in query -var plan = coll.find({foo:{$in:[5,8]}}, {foo:1, _id:0}).hint({foo:1}).explain(); +var plan = coll.find({foo:{$in:[5,8]}}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.3.6 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.3.6 - docs examined should be 0 for covered query") // Test $exists true -var plan = coll.find({foo:{$exists:true}}, {foo:1, _id:0}).hint({foo:1}).explain(); +var plan = coll.find({foo:{$exists:true}}, {foo:1, _id:0}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.3.7 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, @@ -68,7 +68,7 @@ assert.eq(0, plan.executionStats.totalDocsExamined, // Check that $nin can be covered. coll.dropIndexes(); coll.ensureIndex({bar: 1}); -var plan = coll.find({bar:{$nin:[5,8]}}, {bar:1, _id:0}).hint({bar:1}).explain() +var plan = coll.find({bar:{$nin:[5,8]}}, {bar:1, _id:0}).hint({bar:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.3.8 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, diff --git a/jstests/core/covered_index_simple_id.js b/jstests/core/covered_index_simple_id.js index 8016854cb0a..3677e42056d 100644 --- a/jstests/core/covered_index_simple_id.js +++ b/jstests/core/covered_index_simple_id.js @@ -13,42 +13,42 @@ coll.insert({_id:{bar:1}}) coll.insert({_id:null}) // Test equality with int value -var plan = coll.find({_id:1}, {_id:1}).hint({_id:1}).explain() +var plan = coll.find({_id:1}, {_id:1}).hint({_id:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.id.1 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.id.1 - docs examined should be 0 for covered query") // Test equality with string value -var plan = coll.find({_id:"string"}, {_id:1}).hint({_id:1}).explain() +var plan = coll.find({_id:"string"}, {_id:1}).hint({_id:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.id.2 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.id.2 - docs examined should be 0 for covered query") // Test equality with int value on a dotted field -var plan = coll.find({_id:{bar:1}}, {_id:1}).hint({_id:1}).explain() +var plan = coll.find({_id:{bar:1}}, {_id:1}).hint({_id:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.id.3 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.id.3 - docs examined should be 0 for covered query") // Test no query -var plan = coll.find({}, {_id:1}).hint({_id:1}).explain() +var plan = coll.find({}, {_id:1}).hint({_id:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.id.4 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.id.4 - docs examined should be 0 for covered query") // Test range query -var plan = coll.find({_id:{$gt:2,$lt:6}}, {_id:1}).hint({_id:1}).explain() +var plan = coll.find({_id:{$gt:2,$lt:6}}, {_id:1}).hint({_id:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.id.5 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "simple.id.5 - docs examined should be 0 for covered query") // Test in query -var plan = coll.find({_id:{$in:[5,8]}}, {_id:1}).hint({_id:1}).explain() +var plan = coll.find({_id:{$in:[5,8]}}, {_id:1}).hint({_id:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "simple.id.6 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, diff --git a/jstests/core/covered_index_sort_1.js b/jstests/core/covered_index_sort_1.js index fd7d77d272e..d8b301ae3aa 100644 --- a/jstests/core/covered_index_sort_1.js +++ b/jstests/core/covered_index_sort_1.js @@ -20,21 +20,23 @@ coll.insert({foo:null}) coll.ensureIndex({foo:1}) // Test no query and sort ascending -var plan = coll.find({}, {foo:1, _id:0}).sort({foo:1}).hint({foo:1}).explain() +var plan = coll.find({}, {foo:1, _id:0}).sort({foo:1}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "sort.1.1 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "sort.1.1 - docs examined should be 0 for covered query") // Test no query and sort descending -var plan = coll.find({}, {foo:1, _id:0}).sort({foo:-1}).hint({foo:1}).explain() +var plan = coll.find({}, {foo:1, _id:0}).sort({foo:-1}).hint({foo:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "sort.1.2 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, "sort.1.2 - docs examined should be 0 for covered query") // Test range query with sort -var plan = coll.find({foo:{$gt:2}}, {foo:1, _id:0}).sort({foo:-1}).hint({foo:1}).explain() +var plan = coll.find({foo:{$gt:2}}, {foo:1, _id:0}).sort({foo:-1}) + .hint({foo:1}) + .explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "sort.1.3 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, diff --git a/jstests/core/covered_index_sort_2.js b/jstests/core/covered_index_sort_2.js index 4315bdc448a..fc438b21554 100644 --- a/jstests/core/covered_index_sort_2.js +++ b/jstests/core/covered_index_sort_2.js @@ -13,7 +13,7 @@ coll.insert({_id:{bar:1}}) coll.insert({_id:null}) // Test no query -var plan = coll.find({}, {_id:1}).sort({_id:-1}).hint({_id:1}).explain() +var plan = coll.find({}, {_id:1}).sort({_id:-1}).hint({_id:1}).explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "sort.2.1 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, diff --git a/jstests/core/covered_index_sort_3.js b/jstests/core/covered_index_sort_3.js index 6b5cae9def2..e87e6d0dff3 100644 --- a/jstests/core/covered_index_sort_3.js +++ b/jstests/core/covered_index_sort_3.js @@ -12,7 +12,9 @@ coll.insert coll.ensureIndex({a:1,b:-1,c:1}) // Test no query, sort on all fields in index order -var plan = coll.find({}, {b:1, c:1, _id:0}).sort({a:1,b:-1,c:1}).hint({a:1, b:-1, c:1}).explain() +var plan = coll.find({}, {b:1, c:1, _id:0}).sort({a:1,b:-1,c:1}) + .hint({a:1, b:-1, c:1}) + .explain("executionStats"); assert(isIndexOnly(plan.queryPlanner.winningPlan), "sort.3.1 - indexOnly should be true on covered query") assert.eq(0, plan.executionStats.totalDocsExamined, diff --git a/jstests/core/distinct_speed1.js b/jstests/core/distinct_speed1.js index 2e21f5463b9..dff1094f994 100644 --- a/jstests/core/distinct_speed1.js +++ b/jstests/core/distinct_speed1.js @@ -9,7 +9,7 @@ for ( var i=0; i<10000; i++ ){ assert.eq( 10 , t.distinct("x").length , "A1" ); function fast(){ - t.find().explain().executionStats.executionTimeMillis; + t.find().explain("executionStats").executionStats.executionTimeMillis; } function slow(){ diff --git a/jstests/core/explain1.js b/jstests/core/explain1.js index 59d29100507..2022a189a07 100644 --- a/jstests/core/explain1.js +++ b/jstests/core/explain1.js @@ -18,7 +18,7 @@ assert.eq( 49 , t.find( q ).count() , "D" ); assert.eq( 49 , t.find( q ).itcount() , "E" ); assert.eq( 20 , t.find( q ).limit(20).itcount() , "F" ); -assert.eq( 49 , t.find(q).explain().executionStats.nReturned , "G" ); -assert.eq( 20 , t.find(q).limit(20).explain().executionStats.nReturned , "H" ); -assert.eq( 20 , t.find(q).limit(-20).explain().executionStats.nReturned , "I" ); -assert.eq( 49 , t.find(q).batchSize(20).explain().executionStats.nReturned , "J" ); +assert.eq( 49 , t.find(q).explain("executionStats").executionStats.nReturned , "G" ); +assert.eq( 20 , t.find(q).limit(20).explain("executionStats").executionStats.nReturned , "H" ); +assert.eq( 20 , t.find(q).limit(-20).explain("executionStats").executionStats.nReturned , "I" ); +assert.eq( 49 , t.find(q).batchSize(20).explain("executionStats").executionStats.nReturned , "J" ); diff --git a/jstests/core/explain5.js b/jstests/core/explain5.js index 22f8ae9f184..eb8e5d9f4a2 100644 --- a/jstests/core/explain5.js +++ b/jstests/core/explain5.js @@ -11,7 +11,9 @@ for( i = 0; i < 1000; ++i ) { } // Query with an initial set of documents. -var explain1 = t.find( { a:{ $gte:0 }, b:2 } ).sort( { a:1 } ).hint( { a:1 } ).explain(); +var explain1 = t.find( { a:{ $gte:0 }, b:2 } ).sort( { a:1 } ) + .hint( { a:1 } ) + .explain("executionStats"); printjson(explain1); var stats1 = explain1.executionStats; assert.eq( 333, stats1.nReturned, 'wrong nReturned for explain1' ); @@ -22,7 +24,9 @@ for( i = 1000; i < 2000; ++i ) { } // Query with some additional documents. -var explain2 = t.find( { a:{ $gte:0 }, b:2 } ).sort( { a:1 } ).hint ( { a:1 } ).explain(); +var explain2 = t.find( { a:{ $gte:0 }, b:2 } ).sort( { a:1 } ) + .hint ( { a:1 } ) + .explain("executionStats"); printjson(explain2); var stats2 = explain2.executionStats; assert.eq( 666, stats2.nReturned, 'wrong nReturned for explain2' ); diff --git a/jstests/core/explain_batch_size.js b/jstests/core/explain_batch_size.js index 1722052c233..7528098107b 100644 --- a/jstests/core/explain_batch_size.js +++ b/jstests/core/explain_batch_size.js @@ -16,4 +16,4 @@ var q = {}; assert.eq( n , t.find( q ).count() , "A" ); assert.eq( n , t.find( q ).itcount() , "B" ); -assert.eq( n , t.find( q ).batchSize(1).explain().executionStats.nReturned , "C" ); +assert.eq( n , t.find( q ).batchSize(1).explain("executionStats").executionStats.nReturned , "C" ); diff --git a/jstests/core/explain_shell_helpers.js b/jstests/core/explain_shell_helpers.js new file mode 100644 index 00000000000..5cc0a4bbfd3 --- /dev/null +++ b/jstests/core/explain_shell_helpers.js @@ -0,0 +1,389 @@ +// Tests for the .explain() shell helper, which provides syntactic sugar for the explain command. + +var t = db.jstests_explain_helpers; +t.drop(); + +// Include helpers for analyzing explain output. +load("jstests/libs/analyze_plan.js"); + +var explain; +var stage; + +t.ensureIndex({a: 1}); +for (var i = 0; i < 10; i++) { + t.insert({_id: i, a: i, b: 1}); +} + +// +// Basic .find() +// + +// No verbosity specified means that we should use "queryPlanner" verbosity. +explain = t.explain().find().finish(); +assert.commandWorked(explain); +assert("queryPlanner" in explain); +assert(!("executionStats" in explain)); + +// .explain() can also come after .find(). +explain = t.find().explain(); +assert.commandWorked(explain); +assert("queryPlanner" in explain); +assert(!("executionStats" in explain)); + +// .explain(true) means get execution stats for all candidate plans. +explain = t.explain(true).find().finish(); +assert.commandWorked(explain); +assert("queryPlanner" in explain); +assert("executionStats" in explain); +assert("rejectedPlansExecution" in explain.executionStats); + +// .explain(true) after .find(). +explain = t.find().explain(true); +assert.commandWorked(explain); +assert("queryPlanner" in explain); +assert("executionStats" in explain); +assert("rejectedPlansExecution" in explain.executionStats); + +// +// Test verbosity specifiers. +// + +// "queryPlanner" +explain = t.explain("queryPlanner").find().finish(); +assert.commandWorked(explain); +assert("queryPlanner" in explain); +assert(!("executionStats" in explain)); +explain = t.find().explain("queryPlanner"); +assert.commandWorked(explain); +assert("queryPlanner" in explain); +assert(!("executionStats" in explain)); + +// "executionStats" +explain = t.explain("executionStats").find().finish(); +assert.commandWorked(explain); +assert("queryPlanner" in explain); +assert("executionStats" in explain); +assert(!("rejectedPlansExecution" in explain.executionStats)); +explain = t.find().explain("executionStats"); +assert.commandWorked(explain); +assert("queryPlanner" in explain); +assert("executionStats" in explain); +assert(!("rejectedPlansExecution" in explain.executionStats)); + +// "allPlansExecution" +explain = t.explain("allPlansExecution").find().finish(); +assert.commandWorked(explain); +assert("queryPlanner" in explain); +assert("executionStats" in explain); +assert("rejectedPlansExecution" in explain.executionStats); +explain = t.find().explain("allPlansExecution"); +assert.commandWorked(explain); +assert("queryPlanner" in explain); +assert("executionStats" in explain); +assert("rejectedPlansExecution" in explain.executionStats); + +// +// Tests for DBExplainQuery helpers. +// + +// .limit() +explain = t.explain().find().limit(3).finish(); +assert.commandWorked(explain); +explain = t.find().limit(3).explain(); +assert.commandWorked(explain); + +// .batchSize() +explain = t.explain().find().batchSize(3).finish(); +assert.commandWorked(explain); +explain = t.find().batchSize(3).explain(); +assert.commandWorked(explain); + +// .addOption() +explain = t.explain().find().addOption(DBQuery.Option.noTimeout).finish(); +assert.commandWorked(explain); +explain = t.find().batchSize(DBQuery.Option.noTimeout).explain(); +assert.commandWorked(explain); + +// .skip() +explain = t.explain().find().skip(3).finish(); +assert.commandWorked(explain); +explain = t.find().skip(3).explain(); +assert.commandWorked(explain); + +// .sort() +explain = t.explain().find().sort({b: -1}).finish(); +assert.commandWorked(explain); +assert(planHasStage(explain.queryPlanner.winningPlan, "SORT")); +explain = t.find().sort({b: -1}).explain(); +assert.commandWorked(explain); +assert(planHasStage(explain.queryPlanner.winningPlan, "SORT")); + +// .hint() +explain = t.explain().find().hint({a: 1}).finish(); +assert.commandWorked(explain); +assert(isIxscan(explain.queryPlanner.winningPlan)); +explain = t.find().hint({a: 1}).explain(); +assert.commandWorked(explain); +assert(isIxscan(explain.queryPlanner.winningPlan)); + +// .min() +explain = t.explain().find().min({a: 1}).finish(); +assert.commandWorked(explain); +assert(isIxscan(explain.queryPlanner.winningPlan)); +explain = t.find().min({a: 1}).explain(); +assert.commandWorked(explain); +assert(isIxscan(explain.queryPlanner.winningPlan)); + +// .max() +explain = t.explain().find().max({a: 1}).finish(); +assert.commandWorked(explain); +assert(isIxscan(explain.queryPlanner.winningPlan)); +explain = t.find().max({a: 1}).explain(); +assert.commandWorked(explain); +assert(isIxscan(explain.queryPlanner.winningPlan)); + +// .showDiskLoc() +explain = t.explain().find().showDiskLoc().finish(); +assert.commandWorked(explain); +explain = t.find().showDiskLoc().explain(); +assert.commandWorked(explain); + +// .maxTimeMS() +explain = t.explain().find().maxTimeMS(200).finish(); +assert.commandWorked(explain); +explain = t.find().maxTimeMS(200).explain(); +assert.commandWorked(explain); + +// .readPref() +explain = t.explain().find().readPref("secondary").finish(); +assert.commandWorked(explain); +explain = t.find().readPref("secondary").explain(); +assert.commandWorked(explain); + +// .comment() +explain = t.explain().find().comment("test .comment").finish(); +assert.commandWorked(explain); +explain = t.find().comment("test .comment").explain(); +assert.commandWorked(explain); + +// .snapshot() +explain = t.explain().find().snapshot().finish(); +assert.commandWorked(explain); +assert(isIxscan(explain.queryPlanner.winningPlan)); +explain = t.find().snapshot().explain(); +assert.commandWorked(explain); +assert(isIxscan(explain.queryPlanner.winningPlan)); + +// .next() +explain = t.explain().find().next(); +assert.commandWorked(explain); +assert("queryPlanner" in explain); + +// .hasNext() +var explainQuery = t.explain().find(); +assert(explainQuery.hasNext()); +assert.commandWorked(explainQuery.next()); +assert(!explainQuery.hasNext()); + +// .forEach() +var results = []; +t.explain().find().forEach(function (res) { + results.push(res); +}); +assert.eq(1, results.length); +assert.commandWorked(results[0]); + +// +// .aggregate() +// + +explain = t.explain().aggregate([{$match: {a: 3}}]); +assert.commandWorked(explain); +assert.eq(1, explain.stages.length); +assert("queryPlanner" in explain.stages[0].$cursor); + +// Legacy varargs format. +explain = t.explain().aggregate({$match: {a: 3}}); +assert.commandWorked(explain); +assert.eq(1, explain.stages.length); +assert("queryPlanner" in explain.stages[0].$cursor); + +explain = t.explain().aggregate({$match: {a: 3}}, {$project: {a: 1}}); +assert.commandWorked(explain); +assert.eq(2, explain.stages.length); +assert("queryPlanner" in explain.stages[0].$cursor); + +// Options already provided. +explain = t.explain().aggregate([{$match: {a: 3}}], {allowDiskUse: true}); +assert.commandWorked(explain); +assert.eq(1, explain.stages.length); +assert("queryPlanner" in explain.stages[0].$cursor); + +// +// .count() +// + +// Basic count. +explain = t.explain().count().finish(); +assert.commandWorked(explain); +assert(planHasStage(explain.queryPlanner.winningPlan, "COUNT")); + +// Tests for applySkipLimit argument to .count. When we don't apply the skip, we +// count one result. When we do apply the skip we count zero. +explain = t.explain("executionStats").find({a: 3}).skip(1).count(false).finish(); +stage = explain.executionStats.executionStages; +if ("SINGLE_SHARD" === stage.stage) { + stage = stage.shards[0].executionStages; +} +assert.eq(1, stage.nCounted); +explain = t.explain("executionStats").find({a: 3}).skip(1).count(true).finish(); +stage = explain.executionStats.executionStages; +if ("SINGLE_SHARD" === stage.stage) { + stage = stage.shards[0].executionStages; +} +assert.eq(0, stage.nCounted); + +// Count with hint. +explain = t.explain().count({a: 3}).hint({a: 1}).finish(); +assert.commandWorked(explain); +assert(planHasStage(explain.queryPlanner.winningPlan, "COUNT")); +assert(planHasStage(explain.queryPlanner.winningPlan, "COUNT_SCAN")); + +// Count with hint using .find().count() syntax. +explain = t.explain().find({a: 3}).count().hint({a: 1}).finish(); +assert.commandWorked(explain); +assert(planHasStage(explain.queryPlanner.winningPlan, "COUNT")); +assert(planHasStage(explain.queryPlanner.winningPlan, "COUNT_SCAN")); + +// +// .group() +// + +explain = t.explain().group({key: "a", initial: {}, reduce: function() { } }); +assert.commandWorked(explain); + +// +// .remove() +// + +// Check that there is one matching document. +assert.eq(1, t.find({a: 3}).itcount()); + +// Explain a single-document delete. +explain = t.explain("executionStats").remove({a: 3}, true); +assert.commandWorked(explain); +assert.eq(1, explain.executionStats.totalDocsExamined); + +// Document should not have been deleted. +assert.eq(1, t.find({a: 3}).itcount()); + +// Explain a single-document delete with the new syntax. +explain = t.explain("executionStats").remove({a: 3}, {justOne: true}); +assert.commandWorked(explain); +assert.eq(1, explain.executionStats.totalDocsExamined); + +// Document should not have been deleted. +assert.eq(1, t.find({a: 3}).itcount()); + +// Explain a multi-document delete. +explain = t.explain("executionStats").remove({a: {$lte: 2}}); +assert.commandWorked(explain); +assert.eq(3, explain.executionStats.totalDocsExamined); + +// All 10 docs in the collection should still be present. +assert.eq(10, t.count()); + +// +// .update() +// + +// Basic update. +explain = t.explain("executionStats").update({a: 3}, {$set: {b: 3}}); +assert.commandWorked(explain); +assert.eq(1, explain.executionStats.totalDocsExamined); + +// Document should not have been updated. +assert.eq(1, t.findOne({a: 3})["b"]); + +// Update with upsert flag set that should do an insert. +explain = t.explain("executionStats").update({a: 15}, {$set: {b: 3}}, true); +assert.commandWorked(explain); +stage = explain.executionStats.executionStages; +if ("SHARD_WRITE" === stage.stage) { + stage = stage.shards[0].executionStages; +} +assert.eq(stage.stage, "UPDATE"); +assert(stage.wouldInsert); + +// Make sure that the insert didn't actually happen. +assert.eq(10, t.count()); + +// Use the {upsert: true} syntax. +explain = t.explain("executionStats").update({a: 15}, {$set: {b: 3}}, {upsert: true}); +assert.commandWorked(explain); +var stage = explain.executionStats.executionStages; +if ("SHARD_WRITE" === stage.stage) { + stage = stage.shards[0].executionStages; +} +assert.eq(stage.stage, "UPDATE"); +assert(stage.wouldInsert); +assert.eq(0, stage.nMatched); + +// Make sure that the insert didn't actually happen. +assert.eq(10, t.count()); + +// Update with multi-update flag set. +explain = t.explain("executionStats").update({a: {$lte: 2}}, {$set: {b: 3}}, false, true); +assert.commandWorked(explain); +var stage = explain.executionStats.executionStages; +if ("SHARD_WRITE" === stage.stage) { + stage = stage.shards[0].executionStages; +} +assert.eq(stage.stage, "UPDATE"); +assert(!stage.wouldInsert); +assert.eq(3, stage.nMatched); +assert.eq(3, stage.nWouldModify); + +// Use the {multi: true} syntax. +explain = t.explain("executionStats").update({a: {$lte: 2}}, {$set: {b: 3}}, {multi: true}); +assert.commandWorked(explain); +var stage = explain.executionStats.executionStages; +if ("SHARD_WRITE" === stage.stage) { + stage = stage.shards[0].executionStages; +} +assert.eq(stage.stage, "UPDATE"); +assert(!stage.wouldInsert); +assert.eq(3, stage.nMatched); +assert.eq(3, stage.nWouldModify); + +// +// Error cases. +// + +// Invalid verbosity string. +assert.throws(function() { + t.explain("foobar").find().finish(); +}); +assert.throws(function() { + t.find().explain("foobar"); +}); + +// Can't explain an update without a query. +assert.throws(function() { + t.explain().update(); +}); + +// Can't explain an update without mods. +assert.throws(function() { + t.explain().update({a: 3}); +}); + +// Can't add fourth arg when using document-style specification of update options. +assert.throws(function() { + t.explain().update({a: 3}, {$set: {b: 4}}, {multi: true}, true); +}); + +// Missing "initial" for explaining a group. +assert.throws(function() { + t.explain().group({key: "a", reduce: function() { } }); +}); diff --git a/jstests/core/fts_explain.js b/jstests/core/fts_explain.js index 263e4b04b38..3ec8fc0315d 100644 --- a/jstests/core/fts_explain.js +++ b/jstests/core/fts_explain.js @@ -12,6 +12,9 @@ assert.writeOK(res); var explain = coll.find({$text:{$search: "\"a\" -b -\"c\""}}).explain(true); var stage = explain.executionStats.executionStages; +if ("SINGLE_SHARD" === stage.stage) { + stage = stage.shards[0].executionStages; +} assert.eq(stage.stage, "TEXT"); assert.eq(stage.parsedTextQuery.terms, ["a"]); assert.eq(stage.parsedTextQuery.negatedTerms, ["b"]); diff --git a/jstests/core/geo_2d_explain.js b/jstests/core/geo_2d_explain.js index f1a1e2887e4..3968c745748 100644 --- a/jstests/core/geo_2d_explain.js +++ b/jstests/core/geo_2d_explain.js @@ -20,7 +20,7 @@ for (var i = 0; i < n; i++) { t.save({_id: i, a: a, loc: loc}); } -var explain = t.find({loc: {$near: [40, 40]}, _id: {$lt: 50}}).explain(); +var explain = t.find({loc: {$near: [40, 40]}, _id: {$lt: 50}}).explain("executionStats"); print('explain = ' + tojson(explain)); diff --git a/jstests/core/geo_center_sphere1.js b/jstests/core/geo_center_sphere1.js index a0539965ccc..a5659391208 100644 --- a/jstests/core/geo_center_sphere1.js +++ b/jstests/core/geo_center_sphere1.js @@ -85,7 +85,7 @@ function test(index) { assert.eq( numExpected , t.find( q ).itcount() , "itcount : " + tojson( searches[i] ) ); assert.eq( numExpected , t.find( q ).count() , "count : " + tojson( searches[i] ) ); if (index == "2d") { - var explain = t.find( q ).explain(); + var explain = t.find( q ).explain("executionStats"); print( 'explain for ' + tojson( q , '' , true ) + ' = ' + tojson( explain ) ); // The index should be at least minimally effective in preventing the full collection // scan. diff --git a/jstests/core/geo_circle1.js b/jstests/core/geo_circle1.js index d74e6a1eea3..55cbbcc7e5c 100644 --- a/jstests/core/geo_circle1.js +++ b/jstests/core/geo_circle1.js @@ -37,7 +37,7 @@ for ( i=0; i<searches.length; i++ ){ assert.eq( correct[i].length , t.find( q ).itcount() , "itcount : " + tojson( searches[i] ) ); assert.eq( correct[i].length , t.find( q ).count() , "count : " + tojson( searches[i] ) ); - var explain = t.find( q ).explain(); + var explain = t.find( q ).explain("executionStats"); print( 'explain for ' + tojson( q , '' , true ) + ' = ' + tojson( explain ) ); // The index should be at least minimally effective in preventing the full collection // scan. diff --git a/jstests/core/geo_s2nearComplex.js b/jstests/core/geo_s2nearComplex.js index 9c6ac0098be..e6fa1f77bd7 100644 --- a/jstests/core/geo_s2nearComplex.js +++ b/jstests/core/geo_s2nearComplex.js @@ -164,7 +164,7 @@ uniformPoints(origin, 1000, 0.5, 1.5); validateOrdering({geo: {$geoNear: {$geometry: originGeo}}}) print("Millis for uniform:") -print(t.find(query).explain().executionStats.executionTimeMillis); +print(t.find(query).explain("executionStats").executionStats.executionTimeMillis); print("Total points:"); print(t.find(query).itcount()); @@ -176,7 +176,7 @@ uniformPointsWithGaps(origin, 1000, 1, 10.0, 5, 10); validateOrdering({geo: {$geoNear: {$geometry: originGeo}}}) print("Millis for uniform with gaps:") -print(t.find(query).explain().executionStats.executionTimeMillis); +print(t.find(query).explain("executionStats").executionStats.executionTimeMillis); print("Total points:"); print(t.find(query).itcount()); @@ -189,7 +189,7 @@ uniformPointsWithClusters(origin, 1000, 1, 10.0, 5, 10, 100); validateOrdering({geo: {$geoNear: {$geometry: originGeo}}}) print("Millis for uniform with clusters:"); -print(t.find(query).explain().executionStats.executionTimeMillis); +print(t.find(query).explain("executionStats").executionStats.executionTimeMillis); print("Total points:"); print(t.find(query).itcount()); @@ -210,7 +210,7 @@ validateOrdering({geo: {$geoNear: {$geometry: originGeo}}}) print("Millis for uniform near pole:") print(t.find({geo: {$geoNear: {$geometry: originGeo}}}) - .explain().executionStats.executionTimeMillis); + .explain("executionStats").executionStats.executionTimeMillis); assert.eq(t.find({geo: {$geoNear: {$geometry: originGeo}}}).itcount(), 50); t.drop() @@ -228,7 +228,7 @@ validateOrdering({geo: {$geoNear: {$geometry: originGeo}}}) print("Millis for uniform on meridian:") print(t.find({geo: {$geoNear: {$geometry: originGeo}}}) - .explain().executionStats.executionTimeMillis); + .explain("executionStats").executionStats.executionTimeMillis); assert.eq(t.find({geo: {$geoNear: {$geometry: originGeo}}}).itcount(), 50); t.drop() @@ -246,7 +246,7 @@ validateOrdering({geo: {$near: {$geometry: originGeo}}}) print("Millis for uniform on negative meridian:"); print(t.find({geo: {$geoNear: {$geometry: originGeo}}}) - .explain().executionStats.executionTimeMillis); + .explain("executionStats").executionStats.executionTimeMillis); assert.eq(t.find({geo: {$near: {$geometry: originGeo}}}).itcount(), 50); // Near search with points that are really far away. @@ -267,6 +267,6 @@ cur = t.find({geo: {$near: {$geometry: originGeo}}}) print("Near search on very distant points:"); print(t.find({geo: {$geoNear: {$geometry: originGeo}}}) - .explain().executionStats.executionTimeMillis); + .explain("executionStats").executionStats.executionTimeMillis); pt = cur.next(); assert(pt) diff --git a/jstests/core/geo_s2ordering.js b/jstests/core/geo_s2ordering.js index 3dd75ff5785..490d4068170 100644 --- a/jstests/core/geo_s2ordering.js +++ b/jstests/core/geo_s2ordering.js @@ -35,8 +35,8 @@ function runTest(index) { iterations = 10; for (var x = 0; x < iterations; ++x) { res = t.find({nongeo: needle, geo: {$within: {$centerSphere: [[0,0], Math.PI/180.0]}}}) - if (res.explain().executionStats.executionTimeMillis < mintime) { - mintime = res.explain().executionStats.executionTimeMillis; + if (res.explain("executionStats").executionStats.executionTimeMillis < mintime) { + mintime = res.explain("executionStats").executionStats.executionTimeMillis; resultcount = res.itcount() } } diff --git a/jstests/core/geo_s2twofields.js b/jstests/core/geo_s2twofields.js index 039223aadcf..7332c8e33e0 100644 --- a/jstests/core/geo_s2twofields.js +++ b/jstests/core/geo_s2twofields.js @@ -43,11 +43,11 @@ function semiRigorousTime(func) { function timeWithoutAndWithAnIndex(index, query) { t.dropIndex(index); var withoutTime = semiRigorousTime(function() { - return t.find(query).explain().executionStats.executionTimeMillis; + return t.find(query).explain("executionStats").executionStats.executionTimeMillis; }); t.ensureIndex(index); var withTime = semiRigorousTime(function() { - return t.find(query).explain().executionStats.executionTimeMillis; + return t.find(query).explain("executionStats").executionStats.executionTimeMillis; }); t.dropIndex(index); return [withoutTime, withTime]; diff --git a/jstests/core/index_check2.js b/jstests/core/index_check2.js index 9eade5a68fa..a4488dde229 100644 --- a/jstests/core/index_check2.js +++ b/jstests/core/index_check2.js @@ -32,9 +32,9 @@ assert( isIxscan(t.find(q1).explain().queryPlanner.winningPlan) , "e1" ); assert( isIxscan(t.find(q2).explain().queryPlanner.winningPlan) , "e2" ); assert( isIxscan(t.find(q3).explain().queryPlanner.winningPlan) , "e3" ); -scanned1 = t.find(q1).explain().executionStats.totalKeysExamined; -scanned2 = t.find(q2).explain().executionStats.totalKeysExamined; -scanned3 = t.find(q3).explain().executionStats.totalKeysExamined; +scanned1 = t.find(q1).explain("executionStats").executionStats.totalKeysExamined; +scanned2 = t.find(q2).explain("executionStats").executionStats.totalKeysExamined; +scanned3 = t.find(q3).explain("executionStats").executionStats.totalKeysExamined; //print( "scanned1: " + scanned1 + " scanned2: " + scanned2 + " scanned3: " + scanned3 ); diff --git a/jstests/core/index_check3.js b/jstests/core/index_check3.js index bef79fd650d..78135ff30ca 100644 --- a/jstests/core/index_check3.js +++ b/jstests/core/index_check3.js @@ -29,9 +29,9 @@ for ( var i=0; i<100; i++ ){ t.ensureIndex( { foo : 1 } ); -var explain = t.find( { foo : { $lt : 50 } } ).explain(); +var explain = t.find( { foo : { $lt : 50 } } ).explain("executionStats"); assert.gt( 30 , explain.executionStats.totalKeysExamined , "lt" ); -var explain = t.find( { foo : { $gt : 50 } } ).explain(); +var explain = t.find( { foo : { $gt : 50 } } ).explain("executionStats"); assert.gt( 30 , explain.executionStats.totalKeysExamined , "gt" ); @@ -43,11 +43,11 @@ for( var i=0; i < 10; ++i ) { t.ensureIndex( { i : 1 } ); -var explain = t.find( { i : { $lte : 'a' } } ).explain(); +var explain = t.find( { i : { $lte : 'a' } } ).explain("executionStats"); assert.gt( 3 , explain.executionStats.totalKeysExamined , "lte" ); //printjson( t.find( { i : { $gte : 'a' } } ).explain() ); // bug SERVER-99 -var explain = t.find( { i : { $gte : 'a' } } ).explain(); +var explain = t.find( { i : { $gte : 'a' } } ).explain("executionStats"); assert.gt( 3 , explain.executionStats.totalKeysExamined , "gte" ); assert.eq( 1 , t.find( { i : { $gte : 'a' } } ).count() , "gte a" ); assert.eq( 1 , t.find( { i : { $gte : 'a' } } ).itcount() , "gte b" ); @@ -56,7 +56,7 @@ assert.eq( 1 , t.find( { i : { $gte : 'a' } } ).sort( { i : 1 } ).itcount() , "g t.save( { i : "b" } ); -var explain = t.find( { i : { $gte : 'a' } } ).explain(); +var explain = t.find( { i : { $gte : 'a' } } ).explain("executionStats"); assert.gt( 3 , explain.executionStats.totalKeysExamined , "gte" ); assert.eq( 2 , t.find( { i : { $gte : 'a' } } ).count() , "gte a2" ); assert.eq( 2 , t.find( { i : { $gte : 'a' } } ).itcount() , "gte b2" ); diff --git a/jstests/core/index_check6.js b/jstests/core/index_check6.js index 090fd27d4c3..b1b624adbf6 100644 --- a/jstests/core/index_check6.js +++ b/jstests/core/index_check6.js @@ -3,7 +3,7 @@ t = db.index_check6; t.drop(); function keysExamined(query, hint) { - var explain = t.find(query).hint(hint).explain(); + var explain = t.find(query).hint(hint).explain("executionStats"); return explain.executionStats.totalKeysExamined; } @@ -29,8 +29,9 @@ assert.eq( 4 , keysExamined( { age : { $gte : 29 , $lte : 30 } , rating : 5 }, assert.eq( 6 , keysExamined( { age : { $gte : 29 , $lte : 30 } , rating : { $gte : 4 , $lte : 5 } }, {age:1,rating:1} ) , "D" ); // SERVER-371 -assert.eq.automsg( "2", "t.find( { age:30, rating:{ $gte:4, $lte:5} } ).explain()" + - ".executionStats.totalKeysExamined" ); +assert.eq.automsg( "2", "t.find( { age:30, rating:{ $gte:4, $lte:5} } )" + + ".explain('executionStats')" + + ".executionStats.totalKeysExamined" ); t.drop(); @@ -43,7 +44,7 @@ for ( var a=1; a<10; a++ ){ } function doQuery( count, query, sort, index ) { - var explain = t.find( query ).hint( index ).sort( sort ).explain(); + var explain = t.find( query ).hint( index ).sort( sort ).explain("executionStats"); var nscanned = explain.executionStats.totalKeysExamined; assert(Math.abs(count - nscanned) <= 2); } diff --git a/jstests/core/index_check7.js b/jstests/core/index_check7.js index c23ef4eda1e..01a369a5300 100644 --- a/jstests/core/index_check7.js +++ b/jstests/core/index_check7.js @@ -6,10 +6,10 @@ for ( var i=0; i<100; i++ ) t.save( { x : i } ) t.ensureIndex( { x : 1 } ) -assert.eq( 1 , t.find( { x : 27 } ).explain().executionStats.totalKeysExamined , "A" ) +assert.eq( 1 , t.find( { x : 27 } ).explain(true).executionStats.totalKeysExamined , "A" ) t.ensureIndex( { x : -1 } ) -assert.eq( 1 , t.find( { x : 27 } ).explain().executionStats.totalKeysExamined , "B" ) - -assert.eq( 40 , t.find( { x : { $gt : 59 } } ).explain().executionStats.totalKeysExamined , "C" ); +assert.eq( 1 , t.find( { x : 27 } ).explain(true).executionStats.totalKeysExamined , "B" ) +assert.eq( 40 , t.find( { x : { $gt : 59 } } ).explain(true) + .executionStats.totalKeysExamined , "C" ); diff --git a/jstests/core/index_elemmatch1.js b/jstests/core/index_elemmatch1.js index 99418e83839..9641bb6cf0d 100644 --- a/jstests/core/index_elemmatch1.js +++ b/jstests/core/index_elemmatch1.js @@ -34,7 +34,7 @@ function nscannedForCursor( explain, cursor ) { return -1; } -var explain = t.find(q).hint( { "arr.x" : 1 , a : 1 } ).explain(); +var explain = t.find(q).hint( { "arr.x" : 1 , a : 1 } ).explain("executionStats"); assert.eq( t.find(q).itcount(), explain.executionStats.totalKeysExamined ); printjson(t.find(q).explain()); diff --git a/jstests/core/indexj.js b/jstests/core/indexj.js index e58104d75c6..cde81e95ea2 100644 --- a/jstests/core/indexj.js +++ b/jstests/core/indexj.js @@ -10,7 +10,7 @@ function keysExamined(query, hint, sort) { if (!sort) { sort = {}; } - var explain = t.find(query).sort(sort).hint(hint).explain(); + var explain = t.find(query).sort(sort).hint(hint).explain("executionStats"); return explain.executionStats.totalKeysExamined; } diff --git a/jstests/core/indexv.js b/jstests/core/indexv.js index a30541de36c..95074da7333 100644 --- a/jstests/core/indexv.js +++ b/jstests/core/indexv.js @@ -6,13 +6,13 @@ t.drop(); t.ensureIndex( {'a.b':1} ); t.save( {a:[{},{b:1}]} ); -var e = t.find( {'a.b':null} ).explain(); +var e = t.find( {'a.b':null} ).explain("executionStats"); assert.eq( 1, e.executionStats.nReturned ); assert.eq( 1, e.executionStats.totalKeysExamined ); t.drop(); t.ensureIndex( {'a.b.c':1} ); t.save( {a:[{b:[]},{b:{c:1}}]} ); -var e = t.find( {'a.b.c':null} ).explain(); +var e = t.find( {'a.b.c':null} ).explain("executionStats"); assert.eq( 0, e.executionStats.nReturned ); assert.eq( 1, e.executionStats.totalKeysExamined ); diff --git a/jstests/core/mod1.js b/jstests/core/mod1.js index d578190737f..834084e9301 100644 --- a/jstests/core/mod1.js +++ b/jstests/core/mod1.js @@ -11,7 +11,7 @@ t.save( { a : "adasdas" } ); assert.eq( 2 , t.find( "this.a % 10 == 1" ).itcount() , "A1" ); assert.eq( 2 , t.find( { a : { $mod : [ 10 , 1 ] } } ).itcount() , "A2" ); -assert.eq( 0 , t.find( { a : { $mod : [ 10 , 1 ] } } ).explain() +assert.eq( 0 , t.find( { a : { $mod : [ 10 , 1 ] } } ).explain("executionStats") .executionStats.totalKeysExamined , "A3" ); t.ensureIndex( { a : 1 } ); @@ -21,7 +21,7 @@ assert.eq( 2 , t.find( { a : { $mod : [ 10 , 1 ] } } ).itcount() , "B2" ); assert.eq( 1 , t.find( "this.a % 10 == 0" ).itcount() , "B3" ); assert.eq( 1 , t.find( { a : { $mod : [ 10 , 0 ] } } ).itcount() , "B4" ); -assert.eq( 4 , t.find( { a : { $mod : [ 10 , 1 ] } } ).explain() +assert.eq( 4 , t.find( { a : { $mod : [ 10 , 1 ] } } ).explain("executionStats") .executionStats.totalKeysExamined, "B5" ); assert.eq( 1, t.find( { a: { $gt: 5, $mod : [ 10, 1 ] } } ).itcount() ); diff --git a/jstests/core/mr_index.js b/jstests/core/mr_index.js index 394ecc3f650..6c606cfa1dc 100644 --- a/jstests/core/mr_index.js +++ b/jstests/core/mr_index.js @@ -24,7 +24,7 @@ r = function( k , vs ){ } ex = function(){ - return out.find().sort( { value : 1 } ).explain() + return out.find().sort( { value : 1 } ).explain("executionStats") } res = t.mapReduce( m , r , { out : outName } ) diff --git a/jstests/core/ne2.js b/jstests/core/ne2.js index c34f482a389..b0960d69cfa 100644 --- a/jstests/core/ne2.js +++ b/jstests/core/ne2.js @@ -12,5 +12,5 @@ t.save( { a:0.5 } ); e = t.find( { a: { $ne: 0 } } ).explain( true ); assert.eq( 2, e.executionStats.nReturned, 'A' ); -e = t.find( { a: { $gt: -1, $lt: 1, $ne: 0 } } ).explain(); +e = t.find( { a: { $gt: -1, $lt: 1, $ne: 0 } } ).explain( true ); assert.eq( 2, e.executionStats.nReturned, 'B' ); diff --git a/jstests/core/regex3.js b/jstests/core/regex3.js index 418492ce7f5..747fbf4d8a8 100644 --- a/jstests/core/regex3.js +++ b/jstests/core/regex3.js @@ -8,11 +8,11 @@ t.save( { name : "bob" } ); t.save( { name : "aaron" } ); assert.eq( 2 , t.find( { name : /^e.*/ } ).itcount() , "no index count" ); -assert.eq( 4 , t.find( { name : /^e.*/ } ).explain().executionStats.totalDocsExamined , +assert.eq( 4 , t.find( { name : /^e.*/ } ).explain(true).executionStats.totalDocsExamined , "no index explain" ); t.ensureIndex( { name : 1 } ); assert.eq( 2 , t.find( { name : /^e.*/ } ).itcount() , "index count" ); -assert.eq( 2 , t.find( { name : /^e.*/ } ).explain().executionStats.totalKeysExamined , +assert.eq( 2 , t.find( { name : /^e.*/ } ).explain(true).executionStats.totalKeysExamined , "index explain" ); // SERVER-239 t.drop(); @@ -25,7 +25,7 @@ t.save( { name : "c" } ); assert.eq( 3 , t.find( { name : /^aa*/ } ).itcount() , "B ni" ); t.ensureIndex( { name : 1 } ); assert.eq( 3 , t.find( { name : /^aa*/ } ).itcount() , "B i 1" ); -assert.eq( 4 , t.find( { name : /^aa*/ } ).explain().executionStats.totalKeysExamined , +assert.eq( 4 , t.find( { name : /^aa*/ } ).explain(true).executionStats.totalKeysExamined , "B i 1 e" ); assert.eq( 2 , t.find( { name : /^a[ab]/ } ).itcount() , "B i 2" ); diff --git a/jstests/core/regex4.js b/jstests/core/regex4.js index e95daeafe7c..ed5e76331e0 100644 --- a/jstests/core/regex4.js +++ b/jstests/core/regex4.js @@ -8,13 +8,13 @@ t.save( { name : "bob" } ); t.save( { name : "aaron" } ); assert.eq( 2 , t.find( { name : /^e.*/ } ).count() , "no index count" ); -assert.eq( 4 , t.find( { name : /^e.*/ } ).explain().executionStats.totalDocsExamined , +assert.eq( 4 , t.find( { name : /^e.*/ } ).explain(true).executionStats.totalDocsExamined , "no index explain" ); //assert.eq( 2 , t.find( { name : { $ne : /^e.*/ } } ).count() , "no index count ne" ); // SERVER-251 t.ensureIndex( { name : 1 } ); assert.eq( 2 , t.find( { name : /^e.*/ } ).count() , "index count" ); -assert.eq( 2 , t.find( { name : /^e.*/ } ).explain().executionStats.totalKeysExamined , +assert.eq( 2 , t.find( { name : /^e.*/ } ).explain(true).executionStats.totalKeysExamined , "index explain" ); // SERVER-239 //assert.eq( 2 , t.find( { name : { $ne : /^e.*/ } } ).count() , "index count ne" ); // SERVER-251 diff --git a/jstests/core/regex6.js b/jstests/core/regex6.js index 9ffa7499deb..4380ab1ab6b 100644 --- a/jstests/core/regex6.js +++ b/jstests/core/regex6.js @@ -11,31 +11,31 @@ t.save( { name : "[with]some?symbols" } ); t.ensureIndex( { name : 1 } ); assert.eq( 0 , t.find( { name : /^\// } ).count() , "index count" ); -assert.eq( 1 , t.find( { name : /^\// } ).explain().executionStats.totalKeysExamined , +assert.eq( 1 , t.find( { name : /^\// } ).explain(true).executionStats.totalKeysExamined , "index explain 1" ); -assert.eq( 0 , t.find( { name : /^é/ } ).explain().executionStats.totalKeysExamined , +assert.eq( 0 , t.find( { name : /^é/ } ).explain(true).executionStats.totalKeysExamined , "index explain 2" ); -assert.eq( 0 , t.find( { name : /^\é/ } ).explain().executionStats.totalKeysExamined , +assert.eq( 0 , t.find( { name : /^\é/ } ).explain(true).executionStats.totalKeysExamined , "index explain 3" ); -assert.eq( 1 , t.find( { name : /^\./ } ).explain().executionStats.totalKeysExamined , +assert.eq( 1 , t.find( { name : /^\./ } ).explain(true).executionStats.totalKeysExamined , "index explain 4" ); -assert.eq( 5 , t.find( { name : /^./ } ).explain().executionStats.totalKeysExamined , +assert.eq( 5 , t.find( { name : /^./ } ).explain(true).executionStats.totalKeysExamined , "index explain 5" ); // SERVER-2862 assert.eq( 0 , t.find( { name : /^\Qblah\E/ } ).count() , "index explain 6" ); -assert.eq( 1 , t.find( { name : /^\Qblah\E/ } ).explain().executionStats.totalKeysExamined , +assert.eq( 1 , t.find( { name : /^\Qblah\E/ } ).explain(true).executionStats.totalKeysExamined , "index explain 6" ); -assert.eq( 1 , t.find( { name : /^blah/ } ).explain().executionStats.totalKeysExamined , +assert.eq( 1 , t.find( { name : /^blah/ } ).explain(true).executionStats.totalKeysExamined , "index explain 6" ); assert.eq( 1 , t.find( { name : /^\Q[\Ewi\Qth]some?s\Eym/ } ).count() , "index count 2" ); -assert.eq( 2 , t.find( { name : /^\Q[\Ewi\Qth]some?s\Eym/ } ).explain() +assert.eq( 2 , t.find( { name : /^\Q[\Ewi\Qth]some?s\Eym/ } ).explain(true) .executionStats.totalKeysExamined , "index explain 6" ); -assert.eq( 2 , t.find( { name : /^bob/ } ).explain().executionStats.totalKeysExamined , +assert.eq( 2 , t.find( { name : /^bob/ } ).explain(true).executionStats.totalKeysExamined , "index explain 6" ); // proof executionStats.totalKeysExamined == count+1 -assert.eq( 1, t.find( { name : { $regex : "^e", $gte: "emily" } } ).explain() +assert.eq( 1, t.find( { name : { $regex : "^e", $gte: "emily" } } ).explain(true) .executionStats.totalKeysExamined , "ie7" ); -assert.eq( 1, t.find( { name : { $gt : "a", $regex: "^emily" } } ).explain() +assert.eq( 1, t.find( { name : { $gt : "a", $regex: "^emily" } } ).explain(true) .executionStats.totalKeysExamined , "ie7" ); diff --git a/jstests/core/sortk.js b/jstests/core/sortk.js index 20ef08f7cca..da00fe80ba5 100644 --- a/jstests/core/sortk.js +++ b/jstests/core/sortk.js @@ -40,7 +40,7 @@ assert.eq( 1, simpleQueryWithLimit( -1 ).skip( 1 )[ 0 ].b ); // No limit is applied. assert.eq( 6, simpleQueryWithLimit( 0 ).itcount() ); -assert.eq( 6, simpleQueryWithLimit( 0 ).explain().executionStats.totalKeysExamined ); +assert.eq( 6, simpleQueryWithLimit( 0 ).explain( true ).executionStats.totalKeysExamined ); assert.eq( 5, simpleQueryWithLimit( 0 ).skip( 1 ).itcount() ); // The query has additional constriants, preventing limit optimization. diff --git a/jstests/libs/analyze_plan.js b/jstests/libs/analyze_plan.js index 9c2ebffd890..0fd8b3bc8fe 100644 --- a/jstests/libs/analyze_plan.js +++ b/jstests/libs/analyze_plan.js @@ -20,6 +20,13 @@ function planHasStage(root, stage) { } } } + else if ("shards" in root) { + for (var i = 0; i < root.shards.length; i++) { + if (planHasStage(root.shards[i].winningPlan, stage)) { + return true; + } + } + } return false; } diff --git a/jstests/noPassthrough/indexbg1.js b/jstests/noPassthrough/indexbg1.js index 640e703d1aa..666f80284b6 100644 --- a/jstests/noPassthrough/indexbg1.js +++ b/jstests/noPassthrough/indexbg1.js @@ -59,7 +59,7 @@ while( 1 ) { // if indexing finishes before we can run checks, try indexing w/ m q.next(); assert( q.hasNext(), "no next" ); } - var ex = t.find( {i:100} ).limit(-1).explain() + var ex = t.find( {i:100} ).limit(-1).explain("executionStats") printjson(ex) assert( ex.executionStats.totalKeysExamined < 1000 , "took too long to find 100: " + tojson( ex ) ); diff --git a/jstests/noPassthroughWithMongod/clonecollection.js b/jstests/noPassthroughWithMongod/clonecollection.js index e71b2bc3668..f06ae41bc4d 100644 --- a/jstests/noPassthroughWithMongod/clonecollection.js +++ b/jstests/noPassthroughWithMongod/clonecollection.js @@ -30,7 +30,7 @@ if ( t.a.getIndexes().length != 2 ) { } assert.eq( 2, t.a.getIndexes().length, "expected index missing" ); // Verify index works -x = t.a.find( { i: 50 } ).hint( { i: 1 } ).explain() +x = t.a.find( { i: 50 } ).hint( { i: 1 } ).explain("executionStats") printjson( x ) assert.eq( 1, x.executionStats.nReturned , "verify 1" ); assert.eq( 1, t.a.find( { i: 50 } ).hint( { i: 1 } ).toArray().length, "match length did not match expected" ); diff --git a/jstests/sharding/auth_slaveok_routing.js b/jstests/sharding/auth_slaveok_routing.js index a6552590351..96cc1cf6155 100644 --- a/jstests/sharding/auth_slaveok_routing.js +++ b/jstests/sharding/auth_slaveok_routing.js @@ -13,7 +13,9 @@ * @return {boolean} true if query was routed to a secondary node. */ function doesRouteToSec( coll, query ) { - var serverInfo = coll.find( query ).explain().serverInfo; + var explain = coll.find( query ).explain(); + assert.eq("SINGLE_SHARD", explain.queryPlanner.winningPlan.stage); + var serverInfo = explain.queryPlanner.winningPlan.shards[0].serverInfo; var conn = new Mongo( serverInfo.host + ":" + serverInfo.port.toString()); var cmdRes = conn.getDB( 'admin' ).runCommand({ isMaster: 1 }); diff --git a/jstests/sharding/covered_shard_key_indexes.js b/jstests/sharding/covered_shard_key_indexes.js index 22e3aebd984..6a4c0a7bb26 100644 --- a/jstests/sharding/covered_shard_key_indexes.js +++ b/jstests/sharding/covered_shard_key_indexes.js @@ -28,35 +28,31 @@ st.printShardingStatus(); // Insert some data assert.writeOK(coll.insert({ _id : true, a : true, b : true })); -var shardExplain = function(mongosExplainDoc) { - var explainDoc = mongosExplainDoc.shards[shards[0].host][0]; - printjson(explainDoc); - return explainDoc.executionStats; -}; - assert.commandWorked(st.shard0.adminCommand({ setParameter: 1, logComponentVerbosity: { query: { verbosity: 5 }}})); // // Index without shard key query - not covered assert.commandWorked(coll.ensureIndex({ a : 1 })); -assert.eq(1, shardExplain(coll.find({ a : true }).explain()).totalDocsExamined); -assert.eq(1, shardExplain(coll.find({ a : true }, { _id : 1, a : 1 }).explain()).totalDocsExamined); +assert.eq(1, coll.find({ a : true }).explain(true).executionStats.totalDocsExamined); +assert.eq(1, coll.find({ a : true }, { _id : 1, a : 1 }) + .explain(true).executionStats.totalDocsExamined); // // Index with shard key query - covered when projecting assert.commandWorked(coll.dropIndexes()); assert.commandWorked(coll.ensureIndex({ a : 1, _id : 1 })); -assert.eq(1, shardExplain(coll.find({ a : true }).explain()).totalDocsExamined); -assert.eq(0, shardExplain(coll.find({ a : true }, { _id : 1, a : 1 }).explain()).totalDocsExamined); +assert.eq(1, coll.find({ a : true }).explain(true).executionStats.totalDocsExamined); +assert.eq(0, coll.find({ a : true }, { _id : 1, a : 1 }) + .explain(true).executionStats.totalDocsExamined); // // Compound index with shard key query - covered when projecting assert.commandWorked(coll.dropIndexes()); assert.commandWorked(coll.ensureIndex({ a : 1, b : 1, _id : 1 })); -assert.eq(1, shardExplain(coll.find({ a : true, b : true }).explain()).totalDocsExamined); -assert.eq(0, shardExplain(coll.find({ a : true, b : true }, { _id : 1, a : 1 }) - .explain()).totalDocsExamined); +assert.eq(1, coll.find({ a : true, b : true }).explain(true).executionStats.totalDocsExamined); +assert.eq(0, coll.find({ a : true, b : true }, { _id : 1, a : 1 }) + .explain(true).executionStats.totalDocsExamined); // // @@ -71,14 +67,16 @@ assert.writeOK(coll.insert({ _id : true, a : true, b : true })); // // Index without shard key query - not covered assert.commandWorked(coll.ensureIndex({ a : 1 })); -assert.eq(1, shardExplain(coll.find({ a : true }).explain()).totalDocsExamined); -assert.eq(1, shardExplain(coll.find({ a : true }, { _id : 0, a : 1 }).explain()).totalDocsExamined); +assert.eq(1, coll.find({ a : true }).explain(true).executionStats.totalDocsExamined); +assert.eq(1, coll.find({ a : true }, { _id : 0, a : 1 }) + .explain(true).executionStats.totalDocsExamined); // // Index with shard key query - can't be covered since hashed index assert.commandWorked(coll.dropIndex({ a : 1 })); -assert.eq(1, shardExplain(coll.find({ _id : true }).explain()).totalDocsExamined); -assert.eq(1, shardExplain(coll.find({ _id : true }, { _id : 0 }).explain()).totalDocsExamined); +assert.eq(1, coll.find({ _id : true }).explain(true).executionStats.totalDocsExamined); +assert.eq(1, coll.find({ _id : true }, { _id : 0 }) + .explain(true).executionStats.totalDocsExamined); // // @@ -93,25 +91,25 @@ assert.writeOK(coll.insert({ _id : true, a : true, b : true, c : true, d : true // // Index without shard key query - not covered assert.commandWorked(coll.ensureIndex({ c : 1 })); -assert.eq(1, shardExplain(coll.find({ c : true }).explain()).totalDocsExamined); -assert.eq(1, shardExplain(coll.find({ c : true }, { _id : 0, a : 1, b : 1, c : 1 }) - .explain()).totalDocsExamined); +assert.eq(1, coll.find({ c : true }).explain(true).executionStats.totalDocsExamined); +assert.eq(1, coll.find({ c : true }, { _id : 0, a : 1, b : 1, c : 1 }) + .explain(true).executionStats.totalDocsExamined); // // Index with shard key query - covered when projecting assert.commandWorked(coll.dropIndex({ c : 1 })); assert.commandWorked(coll.ensureIndex({ c : 1, b : 1, a : 1 })); -assert.eq(1, shardExplain(coll.find({ c : true }).explain()).totalDocsExamined); -assert.eq(0, shardExplain(coll.find({ c : true }, { _id : 0, a : 1, b : 1, c : 1 }) - .explain()).totalDocsExamined); +assert.eq(1, coll.find({ c : true }).explain(true).executionStats.totalDocsExamined); +assert.eq(0, coll.find({ c : true }, { _id : 0, a : 1, b : 1, c : 1 }) + .explain(true).executionStats.totalDocsExamined); // // Compound index with shard key query - covered when projecting assert.commandWorked(coll.dropIndex({ c : 1, b : 1, a : 1 })); assert.commandWorked(coll.ensureIndex({ c : 1, d : 1, a : 1, b : 1, _id : 1 })); -assert.eq(1, shardExplain(coll.find({ c : true, d : true }).explain()).totalDocsExamined); -assert.eq(0, shardExplain(coll.find({ c : true, d : true }, { a : 1, b : 1, c : 1, d : 1 }) - .explain()).totalDocsExamined); +assert.eq(1, coll.find({ c : true, d : true }).explain(true).executionStats.totalDocsExamined); +assert.eq(0, coll.find({ c : true, d : true }, { a : 1, b : 1, c : 1, d : 1 }) + .explain(true).executionStats.totalDocsExamined); // // @@ -126,17 +124,17 @@ assert.writeOK(coll.insert({ _id : true, a : { b : true }, c : true })); // // Index without shard key query - not covered assert.commandWorked(coll.ensureIndex({ c : 1 })); -assert.eq(1, shardExplain(coll.find({ c : true }).explain()).totalDocsExamined); -assert.eq(1, shardExplain(coll.find({ c : true }, { _id : 0, 'a.b' : 1, c : 1 }) - .explain()).totalDocsExamined); +assert.eq(1, coll.find({ c : true }).explain(true).executionStats.totalDocsExamined); +assert.eq(1, coll.find({ c : true }, { _id : 0, 'a.b' : 1, c : 1 }) + .explain(true).executionStats.totalDocsExamined); // // Index with shard key query - nested query not covered even when projecting assert.commandWorked(coll.dropIndex({ c : 1 })); assert.commandWorked(coll.ensureIndex({ c : 1, 'a.b' : 1 })); -assert.eq(1, shardExplain(coll.find({ c : true }).explain()).totalDocsExamined); -assert.eq(1, shardExplain(coll.find({ c : true }, { _id : 0, 'a.b' : 1, c : 1 }) - .explain()).totalDocsExamined); +assert.eq(1, coll.find({ c : true }).explain(true).executionStats.totalDocsExamined); +assert.eq(1, coll.find({ c : true }, { _id : 0, 'a.b' : 1, c : 1 }) + .explain(true).executionStats.totalDocsExamined); // // @@ -151,10 +149,10 @@ assert.writeOK(st.shard0.getCollection(coll.toString()).insert({ _id : "bad data // // Index without shard key query - not covered but succeeds assert.commandWorked(coll.ensureIndex({ c : 1 })); -var explain = shardExplain(coll.find({ c : true }).explain()); +var explain = coll.find({ c : true }).explain(true).executionStats; assert.eq(0, explain.nReturned); assert.eq(1, explain.totalDocsExamined); -assert.eq(1, getChunkSkips(explain.executionStages)); +assert.eq(1, getChunkSkips(explain.executionStages.shards[0].executionStages)); // // Index with shard key query - covered and succeeds and returns result @@ -162,10 +160,10 @@ assert.eq(1, getChunkSkips(explain.executionStages)); // value for indexes assert.commandWorked(coll.ensureIndex({ c : 1, a : 1 })); jsTest.log(tojson(coll.find({ c : true }, { _id : 0, a : 1, c : 1 }).toArray())); -var explain = shardExplain(coll.find({ c : true }, { _id : 0, a : 1, c : 1 }).explain()); +var explain = coll.find({ c : true }, { _id : 0, a : 1, c : 1 }).explain(true).executionStats; assert.eq(1, explain.nReturned); assert.eq(0, explain.totalDocsExamined); -assert.eq(0, getChunkSkips(explain.executionStages)); +assert.eq(0, getChunkSkips(explain.executionStages.shards[0].executionStages)); jsTest.log("DONE!"); st.stop(); diff --git a/jstests/sharding/large_skip_one_shard.js b/jstests/sharding/large_skip_one_shard.js index ec8f250de03..49e6551dec0 100644 --- a/jstests/sharding/large_skip_one_shard.js +++ b/jstests/sharding/large_skip_one_shard.js @@ -26,22 +26,11 @@ function testSelectWithSkip(coll){ } // Run a query which only requires 5 results from a single shard - var explain = coll.find({ _id : { $gt : 1 }}).sort({ _id : 1 }).skip(90).limit(5).explain(); - printjson(explain); - - if (explain.shards) { - // We can't use Object.keys here, so a bit awkward to get the first key - var shardEntry = null; - var numEntries = 0; - for (shardEntry in explain.shards) numEntries++; - assert.eq(numEntries, 1); - - var shardExplain = explain.shards[shardEntry]; - assert.eq(shardExplain.length, 1); - explain = shardExplain[0]; - } + var explain = coll.find({ _id : { $gt : 1 }}).sort({ _id : 1 }) + .skip(90) + .limit(5) + .explain("executionStats"); - // What we're actually testing assert.lt(explain.executionStats.nReturned, 90); } @@ -50,4 +39,3 @@ testSelectWithSkip(collUnSharded); jsTest.log("DONE!"); st.stop(); - diff --git a/jstests/sharding/limit_push.js b/jstests/sharding/limit_push.js index d0bd259780b..ad9d8b9a383 100644 --- a/jstests/sharding/limit_push.js +++ b/jstests/sharding/limit_push.js @@ -35,17 +35,17 @@ assert.eq( 60 , db.limit_push.find( q ).count() , "Did not find 60 documents" ); // Now make sure that the explain shos that each shard is returning a single document as indicated // by the "n" element for each shard -exp = db.limit_push.find( q ).sort( { x:-1} ).limit(1).explain(); +exp = db.limit_push.find( q ).sort( { x:-1} ).limit(1).explain("executionStats"); printjson( exp ) -assert.eq("ParallelSort", exp.clusteredType, "Not a ParallelSort"); +var execStages = exp.executionStats.executionStages; +assert.eq("SHARD_MERGE_SORT", execStages.stage, "Expected SHARD_MERGE_SORT as root stage"); var k = 0; -for (var j in exp.shards) { - assert.eq( 1 , exp.shards[j][0].executionStats.nReturned, +for (var j in execStages.shards) { + assert.eq( 1 , execStages.shards[j].executionStages.nReturned, "'n' is not 1 from shard000" + k.toString()); k++ } s.stop(); - diff --git a/jstests/sharding/read_pref.js b/jstests/sharding/read_pref.js index 431fe0aa6d5..1d33866d432 100755 --- a/jstests/sharding/read_pref.js +++ b/jstests/sharding/read_pref.js @@ -108,27 +108,41 @@ var doTest = function(useDollarQuerySyntax) { $explain: true }).limit(-1).next(); } else { - return coll.find().readPref(readPrefMode, readPrefTags).explain(); + return coll.find().readPref(readPrefMode, readPrefTags).explain("executionStats"); } }; + var getExplainServer = function(explain) { + var serverInfo; + + if (useDollarQuerySyntax) { + serverInfo = explain.serverInfo; + } + else { + assert.eq("SINGLE_SHARD", explain.queryPlanner.winningPlan.stage); + serverInfo = explain.queryPlanner.winningPlan.shards[0].serverInfo; + } + + return serverInfo.host + ":" + serverInfo.port.toString(); + }; + // Read pref should work without slaveOk var explain = getExplain("secondary"); - var explainServer = explain.serverInfo.host + ":" + explain.serverInfo.port.toString(); + var explainServer = getExplainServer(explain); assert.neq( primaryNode.name, explainServer ); conn.setSlaveOk(); // It should also work with slaveOk explain = getExplain("secondary"); - explainServer = explain.serverInfo.host + ":" + explain.serverInfo.port.toString(); + explainServer = getExplainServer(explain); assert.neq( primaryNode.name, explainServer ); // Check that $readPreference does not influence the actual query assert.eq( 1, explain.executionStats.nReturned ); explain = getExplain("secondaryPreferred", [{ s: "2" }]); - explainServer = explain.serverInfo.host + ":" + explain.serverInfo.port.toString(); + explainServer = getExplainServer(explain); checkTag( explainServer, { s: "2" }); assert.eq( 1, explain.executionStats.nReturned ); @@ -138,23 +152,23 @@ var doTest = function(useDollarQuerySyntax) { }); // Ok to use empty tags on primaryOnly - explain = coll.find().readPref("primary", [{}]).explain(); - explainServer = explain.serverInfo.host + ":" + explain.serverInfo.port.toString(); + explain = getExplain("primary", [{}]); + explainServer = getExplainServer(explain); assert.eq(primaryNode.name, explainServer); - explain = coll.find().readPref("primary", []).explain(); - explainServer = explain.serverInfo.host + ":" + explain.serverInfo.port.toString(); + explain = getExplain("primary", []); + explainServer = getExplainServer(explain); assert.eq(primaryNode.name, explainServer); // Check that mongos will try the next tag if nothing matches the first explain = getExplain("secondary", [{ z: "3" }, { dc: "jp" }]); - explainServer = explain.serverInfo.host + ":" + explain.serverInfo.port.toString(); + explainServer = getExplainServer(explain); checkTag( explainServer, { dc: "jp" }); assert.eq( 1, explain.executionStats.nReturned ); // Check that mongos will fallback to primary if none of tags given matches explain = getExplain("secondaryPreferred", [{ z: "3" }, { dc: "ph" }]); - explainServer = explain.serverInfo.host + ":" + explain.serverInfo.port.toString(); + explainServer = getExplainServer(explain); // Call getPrimary again since the primary could have changed after the restart. assert.eq(replTest.getPrimary().name, explainServer); assert.eq( 1, explain.executionStats.nReturned ); @@ -178,7 +192,7 @@ var doTest = function(useDollarQuerySyntax) { // Test to make sure that connection is ok, in prep for priOnly test explain = getExplain("nearest"); - explainServer = explain.serverInfo.host + ":" + explain.serverInfo.port.toString(); + explainServer = getExplainServer(explain); assert.eq( explainServer, replTest.nodes[NODES - 1].name ); assert.eq( 1, explain.executionStats.nReturned ); @@ -192,4 +206,3 @@ var doTest = function(useDollarQuerySyntax) { doTest(false); doTest(true); - diff --git a/jstests/sharding/shard2.js b/jstests/sharding/shard2.js index a229c4dc4b1..41b46158167 100644 --- a/jstests/sharding/shard2.js +++ b/jstests/sharding/shard2.js @@ -140,12 +140,13 @@ placeCheck( 7 ); db.foo.find().sort( { _id : 1 } ).forEach( function(z){ print( z._id ); } ) -zzz = db.foo.find().explain(); +zzz = db.foo.find().explain("executionStats").executionStats; assert.eq( 0 , zzz.totalKeysExamined , "EX1a" ) assert.eq( 6 , zzz.nReturned , "EX1b" ) assert.eq( 6 , zzz.totalDocsExamined , "EX1c" ) -zzz = db.foo.find().hint( { _id : 1 } ).sort( { _id : 1 } ).explain(); +zzz = db.foo.find().hint( { _id : 1 } ).sort( { _id : 1 } ) + .explain("executionStats").executionStats; assert.eq( 6 , zzz.totalKeysExamined , "EX2a" ) assert.eq( 6 , zzz.nReturned , "EX2b" ) assert.eq( 6 , zzz.totalDocsExamined , "EX2c" ) diff --git a/jstests/sharding/shard3.js b/jstests/sharding/shard3.js index 5ecf1fb8140..290349aee58 100644 --- a/jstests/sharding/shard3.js +++ b/jstests/sharding/shard3.js @@ -66,15 +66,15 @@ function doCounts( name , total , onlyItCounts ){ var total = doCounts( "before wrong save" ) assert.writeOK(secondary.insert( { _id : 111 , num : -3 } )); doCounts( "after wrong save" , total , true ) -e = a.find().explain(); +e = a.find().explain("executionStats").executionStats; assert.eq( 3 , e.nReturned , "ex1" ) assert.eq( 0 , e.totalKeysExamined , "ex2" ) assert.eq( 4 , e.totalDocsExamined , "ex3" ) var chunkSkips = 0; -for (var shard in e.shards) { - var theShard = e.shards[shard][0]; - chunkSkips += getChunkSkips(theShard.executionStats.executionStages); +for (var shard in e.executionStages.shards) { + var theShard = e.executionStages.shards[shard]; + chunkSkips += getChunkSkips(theShard.executionStages); } assert.eq( 1 , chunkSkips , "ex4" ) |