@@ -116,50 +116,139 @@ DBQuery.prototype.shellPrint = function(){
116
116
var paranoia = mongo_hacker_config . index_paranoia ;
117
117
118
118
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 } ) ;
132
130
} 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
+ }
134
136
}
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 ) ;
137
151
}
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 ) ;
151
207
}
152
208
}
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 } ) ;
158
224
}
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 } ) ;
159
229
}
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 ) ) ;
162
248
}
249
+
250
+ index_use += "]" ;
251
+ output . push ( index_use ) ;
163
252
}
164
253
}
165
254
0 commit comments