Files
mongo/jstests/core/index_stats.js
2016-05-28 17:55:12 -04:00

217 lines
6.0 KiB
JavaScript

(function() {
"use strict";
load("jstests/libs/analyze_plan.js");
var colName = "jstests_index_stats";
var col = db[colName];
col.drop();
var getUsageCount = function(indexName) {
var cursor = col.aggregate([{$indexStats: {}}]);
while (cursor.hasNext()) {
var doc = cursor.next();
if (doc.name === indexName) {
return doc.accesses.ops;
}
}
return undefined;
};
var getIndexKey = function(indexName) {
var cursor = col.aggregate([{$indexStats: {}}]);
while (cursor.hasNext()) {
var doc = cursor.next();
if (doc.name === indexName) {
return doc.key;
}
}
return undefined;
};
var getIndexNamesForWinningPlan = function(explain) {
var indexNameList = [];
var winningStages = getPlanStages(explain.queryPlanner.winningPlan, "IXSCAN");
for (var i = 0; i < winningStages.length; ++i) {
indexNameList.push(winningStages[i].indexName);
}
return indexNameList;
};
assert.writeOK(col.insert({a: 1, b: 1, c: 1}));
assert.writeOK(col.insert({a: 2, b: 2, c: 2}));
assert.writeOK(col.insert({a: 3, b: 3, c: 3}));
//
// Confirm no index stats object exists prior to index creation.
//
col.findOne({a: 1});
assert.eq(undefined, getUsageCount("a_1"));
//
// Create indexes.
//
assert.commandWorked(col.createIndex({a: 1}, {name: "a_1"}));
assert.commandWorked(col.createIndex({b: 1, c: 1}, {name: "b_1_c_1"}));
var countA = 0; // Tracks expected index access for "a_1".
var countB = 0; // Tracks expected index access for "b_1_c_1".
//
// Confirm a stats object exists post index creation (with 0 count).
//
assert.eq(countA, getUsageCount("a_1"));
assert.eq({a: 1}, getIndexKey("a_1"));
//
// Confirm index stats tick on find().
//
col.findOne({a: 1});
countA++;
assert.eq(countA, getUsageCount("a_1"));
//
// Confirm index stats tick on findAndModify() update.
//
var res =
db.runCommand({findAndModify: colName, query: {a: 1}, update: {$set: {d: 1}}, 'new': true});
assert.commandWorked(res);
countA++;
assert.eq(countA, getUsageCount("a_1"));
//
// Confirm index stats tick on findAndModify() delete.
//
res = db.runCommand({findAndModify: colName, query: {a: 2}, remove: true});
assert.commandWorked(res);
countA++;
assert.eq(countA, getUsageCount("a_1"));
assert.writeOK(col.insert(res.value));
//
// Confirm $and operation ticks indexes for winning plan, but not rejected plans.
//
// Run explain to determine which indexes would be used for this query. Note that index
// access counters are not incremented for explain execution.
var explain = col.find({a: 2, b: 2}).explain("queryPlanner");
var indexNameList = getIndexNamesForWinningPlan(explain);
assert.gte(indexNameList.length, 1);
for (var i = 0; i < indexNameList.length; ++i) {
// Increment the expected $indexStats count for each index used.
var name = indexNameList[i];
if (name === "a_1") {
countA++;
} else {
assert(name === "b_1_c_1");
countB++;
}
}
// Run the query again without explain to increment index access counters.
col.findOne({a: 2, b: 2});
// Check all indexes for proper count.
assert.eq(countA, getUsageCount("a_1"));
assert.eq(countB, getUsageCount("b_1_c_1"));
assert.eq(0, getUsageCount("_id_"));
//
// Confirm index stats tick on distinct().
//
res = db.runCommand({distinct: colName, key: "b", query: {b: 1}});
assert.commandWorked(res);
countB++;
assert.eq(countB, getUsageCount("b_1_c_1"));
//
// Confirm index stats tick on group().
//
res = db.runCommand({
group: {
ns: colName,
key: {b: 1, c: 1},
cond: {b: {$gt: 0}},
$reduce: function(curr, result) {},
initial: {}
}
});
assert.commandWorked(res);
countB++;
assert.eq(countB, getUsageCount("b_1_c_1"));
//
// Confirm index stats tick on aggregate w/ match.
//
res = db.runCommand({aggregate: colName, pipeline: [{$match: {b: 1}}]});
assert.commandWorked(res);
countB++;
assert.eq(countB, getUsageCount("b_1_c_1"));
//
// Confirm index stats tick on mapReduce with query.
//
res = db.runCommand({
mapReduce: colName,
map: function() {
emit(this.b, this.c);
},
reduce: function(key, val) {
return val;
},
query: {b: 2},
out: {inline: true}
});
assert.commandWorked(res);
countB++;
assert.eq(countB, getUsageCount("b_1_c_1"));
//
// Confirm index stats tick on update().
//
assert.writeOK(col.update({a: 2}, {$set: {d: 2}}));
countA++;
assert.eq(countA, getUsageCount("a_1"));
//
// Confirm index stats tick on remove().
//
assert.writeOK(col.remove({a: 2}));
countA++;
assert.eq(countA, getUsageCount("a_1"));
//
// Confirm multiple index $or operation ticks all involved indexes.
//
col.findOne({$or: [{a: 1}, {b: 1, c: 1}]});
countA++;
countB++;
assert.eq(countA, getUsageCount("a_1"));
assert.eq(countB, getUsageCount("b_1_c_1"));
//
// Confirm index stats object does not exist post index drop.
//
assert.commandWorked(col.dropIndex("b_1_c_1"));
countB = 0;
assert.eq(undefined, getUsageCount("b_1_c_1"));
//
// Confirm index stats object exists with count 0 once index is recreated.
//
assert.commandWorked(col.createIndex({b: 1, c: 1}, {name: "b_1_c_1"}));
assert.eq(countB, getUsageCount("b_1_c_1"));
//
// Confirm that retrieval fails if $indexStats is not in the first pipeline position.
//
assert.throws(function() {
col.aggregate([{$match: {}}, {$indexStats: {}}]);
});
})();