Skip to content

Commit af2c505

Browse files
committed
Rework and fix index paranoia feature
1 parent d4e2293 commit af2c505

File tree

1 file changed

+125
-36
lines changed

1 file changed

+125
-36
lines changed

hacks/common.js

Lines changed: 125 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -116,50 +116,139 @@ DBQuery.prototype.shellPrint = function(){
116116
var paranoia = mongo_hacker_config.index_paranoia;
117117

118118
if (typeof paranoia !== 'undefined' && paranoia) {
119-
var explain = this.clone();
120-
explain._ensureSpecial();
121-
explain._query.$explain = true;
122-
explain._limit = Math.abs(n) * -1;
123-
var result = explain.next();
124-
125-
if (current_version < 3) {
126-
var type = result.cursor;
127-
128-
if (type !== undefined) {
129-
var index_use = "Index[";
130-
if (type == "BasicCursor") {
131-
index_use += colorize( "none", { color: "red", bright: true });
119+
var explanation = this.explain();
120+
var cursor = explanation.cursor;
121+
var clauses = explanation.clauses;
122+
var queryPlanner = explanation.queryPlanner;
123+
124+
if (cursor !== undefined || clauses !== undefined) {
125+
var index_use = "Index[";
126+
var parseClause = function(clause) {
127+
var indexInfo;
128+
if (clause.cursor === "BasicCursor") {
129+
indexInfo = colorize("none", {color: "red", bright: true});
132130
} else {
133-
index_use += colorize( result.cursor.substring(12), { color: "green", bright: true });
131+
var indexName = clause.cursor === "IDCursor" ? "_id_" : clause.cursor.split(" ")[1];
132+
indexInfo = colorize(indexName, {color: "green", bright: true});
133+
if (clause.indexOnly) {
134+
indexInfo += colorize("(covered)", {color: "green", bright: false});
135+
}
134136
}
135-
index_use += "]";
136-
output.push(index_use);
137+
return indexInfo;
138+
};
139+
if (clauses) {
140+
var clauseInfo = [];
141+
var singleClauseInfo;
142+
clauses.forEach(function(clause) {
143+
singleClauseInfo = parseClause(clause);
144+
if (clauseInfo.filter(function(info) { return info === singleClauseInfo; }).length === 0) {
145+
clauseInfo.push(singleClauseInfo);
146+
}
147+
});
148+
index_use += clauseInfo.join(', ');
149+
} else {
150+
index_use += parseClause(explanation);
137151
}
138-
} else {
139-
var winningPlan = result.queryPlanner.winningPlan;
140-
var winningInputStage = winningPlan.inputStage.inputStage;
141-
142-
if (winningPlan !== undefined) {
143-
var index_use = "Index[";
144-
if (winningPlan.inputStage.stage === "COLLSCAN" || (winningInputStage !== undefined && winningInputStage.stage !== "IXSCAN")) {
145-
index_use += colorize( "none", { color: "red", bright: true });
146-
} else {
147-
var fullScan = false;
148-
for (index in winningInputStage.keyPattern) {
149-
if (winningInputStage.indexBounds[index][0] == "[MinKey, MaxKey]") {
150-
fullScan = true;
152+
index_use += "]";
153+
output.push(index_use);
154+
} else if (queryPlanner !== undefined) {
155+
var collectionIndexes;
156+
var getIndexNameByKey = (function(query) {
157+
return function(key) {
158+
if (!collectionIndexes) {
159+
var nsParts = query._ns.split('.');
160+
var dbName = nsParts[0];
161+
var colName = nsParts[1];
162+
collectionIndexes = db.getSisterDB(dbName)[colName].getIndexes();
163+
}
164+
return collectionIndexes.filter(function (index) {
165+
return JSON.stringify(index.key) === JSON.stringify(key);
166+
})[0].name;
167+
}
168+
})(this);
169+
var traverseStageTree = function(currentStage, results) {
170+
results = results || {
171+
collscans: 0,
172+
eof: false,
173+
fetches: 0,
174+
idhacks: 0,
175+
indexes: [],
176+
ixscans: 0
177+
};
178+
switch(currentStage.stage) {
179+
case "EOF":
180+
results.eof = true;
181+
break;
182+
case "COLLSCAN":
183+
results.collscans++;
184+
break;
185+
case "IDHACK":
186+
results.idhacks++;
187+
break;
188+
case "IXSCAN":
189+
results.ixscans++;
190+
var currentIndexName = currentStage.indexName;
191+
if (!currentIndexName) {
192+
currentIndexName = getIndexNameByKey(currentStage.keyPattern);
193+
}
194+
if (results.indexes.filter(function(indexName) { return indexName === currentIndexName; }).length === 0) {
195+
results.indexes.push(currentIndexName);
196+
}
197+
break;
198+
case "FETCH":
199+
results.fetches++;
200+
// Fallthrough.
201+
default:
202+
if (currentStage.inputStage) {
203+
traverseStageTree(currentStage.inputStage, results);
204+
} else if (currentStage.inputStages) {
205+
for (var i = 0, length = currentStage.inputStages.length; i < length; i++) {
206+
traverseStageTree(currentStage.inputStages[i], results);
151207
}
152208
}
153-
154-
if (fullScan) {
155-
index_use += colorize( winningInputStage.indexName + " (full scan)", { color: "yellow", bright: true });
156-
} else {
157-
index_use += colorize( winningInputStage.indexName, { color: "green", bright: true });
209+
}
210+
return results;
211+
};
212+
var parseQueryResults = function(results) {
213+
var indexInfo;
214+
if (results.eof) {
215+
indexInfo = colorize("collection doesn't exist", { color: "red", bright: true });
216+
} else if (results.idhacks) {
217+
indexInfo = colorize("_id_", { color: "green", bright: true });
218+
} else if (results.ixscans) {
219+
indexInfo = results.indexes.map(function(index) {
220+
return colorize(index, { color: "green", bright: true });
221+
}).join(', ');
222+
if (!results.fetches) {
223+
indexInfo += colorize(" (covered)", { color: "green", bright: false });
158224
}
225+
} else if (results.collscans) {
226+
indexInfo = colorize("none", { color: "red", bright: true });
227+
} else {
228+
indexInfo = colorize( "CAN'T DETERMINE", { color: "red", bright: true });
159229
}
160-
index_use += "]";
161-
output.push(index_use);
230+
return indexInfo;
231+
};
232+
233+
var index_use = "Index[";
234+
if (queryPlanner.winningPlan.shards) {
235+
var shards = queryPlanner.winningPlan.shards;
236+
var shardIndexesInfo = [];
237+
shards.forEach(function(shard) {
238+
shardIndexesInfo.push(
239+
"shard " +
240+
colorize(shard.shardName, { color: "blue", bright: true }) +
241+
": " +
242+
parseQueryResults(traverseStageTree(shard.winningPlan))
243+
);
244+
});
245+
index_use += shardIndexesInfo.join('; ');
246+
} else {
247+
index_use += parseQueryResults(traverseStageTree(queryPlanner.winningPlan));
162248
}
249+
250+
index_use += "]";
251+
output.push(index_use);
163252
}
164253
}
165254

0 commit comments

Comments
 (0)