summaryrefslogtreecommitdiff
path: root/src/mongo/db/exec/plan_stats.h
blob: fa326b536d2fde42965cb62cbe6f94bdcfda92f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
/**
 *    Copyright (C) 2013-2014 MongoDB Inc.
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    As a special exception, the copyright holders give permission to link the
 *    code of portions of this program with the OpenSSL library under certain
 *    conditions as described in each individual source file and distribute
 *    linked combinations including the program with the OpenSSL library. You
 *    must comply with the GNU Affero General Public License in all respects for
 *    all of the code used other than as permitted herein. If you modify file(s)
 *    with this exception, you may extend this exception to your version of the
 *    file(s), but you are not obligated to do so. If you do not wish to do so,
 *    delete this exception statement from your version. If you delete this
 *    exception statement from all source files in the program, then also delete
 *    it in the license file.
 */

#pragma once

#include <boost/scoped_ptr.hpp>
#include <cstdlib>
#include <string>
#include <vector>

#include "mongo/base/disallow_copying.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/geo/hash.h"
#include "mongo/db/query/stage_types.h"
#include "mongo/platform/cstdint.h"

namespace mongo {

    /**
     * The interface all specific-to-stage stats provide.
     */
    struct SpecificStats {
        virtual ~SpecificStats() { }

        /**
         * Make a deep copy.
         */
        virtual SpecificStats* clone() const = 0;
    };

    // Every stage has CommonStats.
    struct CommonStats {
        CommonStats() : works(0),
                        yields(0),
                        unyields(0),
                        invalidates(0),
                        advanced(0),
                        needTime(0),
                        isEOF(false) { }

        // Count calls into the stage.
        size_t works;
        size_t yields;
        size_t unyields;
        size_t invalidates;

        // How many times was this state the return value of work(...)?
        size_t advanced;
        size_t needTime;

        // TODO: have some way of tracking WSM sizes (or really any series of #s).  We can measure
        // the size of our inputs and the size of our outputs.  We can do a lot with the WS here.

        // TODO: once we've picked a plan, collect different (or additional) stats for display to
        // the user, eg. time_t totalTimeSpent;

        bool isEOF;
    };

    // The universal container for a stage's stats.
    struct PlanStageStats {
        PlanStageStats(const CommonStats& c, StageType t) : stageType(t), common(c) { }

        ~PlanStageStats() {
            for (size_t i = 0; i < children.size(); ++i) {
                delete children[i];
            }
        }

        /**
         * Make a deep copy.
         */
        PlanStageStats* clone() const {
            PlanStageStats* stats = new PlanStageStats(common, stageType);
            if (specific.get()) {
                stats->specific.reset(specific->clone());
            }
            for (size_t i = 0; i < children.size(); ++i) {
                invariant(children[i]);
                stats->children.push_back(children[i]->clone());
            }
            return stats;
        }

        // See query/stage_type.h
        StageType stageType;

        // Stats exported by implementing the PlanStage interface.
        CommonStats common;

        // Per-stage place to stash additional information
        boost::scoped_ptr<SpecificStats> specific;

        // The stats of the node's children.
        std::vector<PlanStageStats*> children;

    private:
        MONGO_DISALLOW_COPYING(PlanStageStats);
    };

    struct AndHashStats : public SpecificStats {
        AndHashStats() : flaggedButPassed(0),
                         flaggedInProgress(0),
                         memUsage(0),
                         memLimit(0) { }

        virtual ~AndHashStats() { }

        virtual SpecificStats* clone() const {
            AndHashStats* specific = new AndHashStats(*this);
            return specific;
        }

        // Invalidation counters.
        // How many results had the AND fully evaluated but were invalidated?
        size_t flaggedButPassed;

        // How many results were mid-AND but got flagged?
        size_t flaggedInProgress;

        // How many entries are in the map after each child?
        // child 'i' produced children[i].common.advanced DiskLocs, of which mapAfterChild[i] were
        // intersections.
        std::vector<size_t> mapAfterChild;

        // mapAfterChild[mapAfterChild.size() - 1] WSMswere match tested.
        // commonstats.advanced is how many passed.

        // What's our current memory usage?
        size_t memUsage;

        // What's our memory limit?
        size_t memLimit;
    };

    struct AndSortedStats : public SpecificStats {
        AndSortedStats() : flagged(0),
                           matchTested(0) { }

        virtual ~AndSortedStats() { }

        virtual SpecificStats* clone() const {
            AndSortedStats* specific = new AndSortedStats(*this);
            return specific;
        }

        // How many results from each child did not pass the AND?
        std::vector<size_t> failedAnd;

        // How many results were flagged via invalidation?
        size_t flagged;

        // Fails == common.advanced - matchTested
        size_t matchTested;
    };

    struct CachedPlanStats : public SpecificStats {
        CachedPlanStats() { }

        virtual SpecificStats* clone() const {
            return new CachedPlanStats(*this);
        }
    };

    struct CollectionScanStats : public SpecificStats {
        CollectionScanStats() : docsTested(0) { }

        virtual SpecificStats* clone() const {
            CollectionScanStats* specific = new CollectionScanStats(*this);
            return specific;
        }

        // How many documents did we check against our filter?
        size_t docsTested;
    };

    struct DistinctScanStats : public SpecificStats {
        DistinctScanStats() : keysExamined(0) { }

        virtual SpecificStats* clone() const {
            return new DistinctScanStats(*this);
        }

        // How many keys did we look at while distinct-ing?
        size_t keysExamined;
    };

    struct FetchStats : public SpecificStats {
        FetchStats() : alreadyHasObj(0),
                       forcedFetches(0),
                       matchTested(0) { }

        virtual ~FetchStats() { }

        virtual SpecificStats* clone() const {
            FetchStats* specific = new FetchStats(*this);
            return specific;
        }

        // Have we seen anything that already had an object?
        size_t alreadyHasObj;

        // How many fetches weren't in memory?  it's common.needFetch.
        // How many total fetches did we do?  it's common.advanced.
        // So the number of fetches that were in memory are common.advanced - common.needFetch.

        // How many records were we forced to fetch as the result of an invalidation?
        size_t forcedFetches;

        // We know how many passed (it's the # of advanced) and therefore how many failed.
        size_t matchTested;
    };

    struct IndexScanStats : public SpecificStats {
        IndexScanStats() : isMultiKey(false),
                           yieldMovedCursor(0),
                           dupsTested(0),
                           dupsDropped(0),
                           seenInvalidated(0),
                           matchTested(0),
                           keysExamined(0) { }

        virtual ~IndexScanStats() { }

        virtual SpecificStats* clone() const {
            IndexScanStats* specific = new IndexScanStats(*this);
            // BSON objects have to be explicitly copied.
            specific->keyPattern = keyPattern.getOwned();
            specific->indexBounds = indexBounds.getOwned();
            return specific;
        }

        // Index type being used.
        std::string indexType;

        // name of the index being used
        std::string indexName;

        BSONObj keyPattern;

        // A BSON (opaque, ie. hands off other than toString() it) representation of the bounds
        // used.
        BSONObj indexBounds;

        // Contains same information as indexBounds with the addition of inclusivity of bounds.
        std::string indexBoundsVerbose;

        // >1 if we're traversing the index along with its order. <1 if we're traversing it
        // against the order.
        int direction;

        // Whether this index is over a field that contain array values.
        bool isMultiKey;

        size_t yieldMovedCursor;
        size_t dupsTested;
        size_t dupsDropped;

        size_t seenInvalidated;
        // TODO: we could track key sizes here.

        // We know how many passed (it's the # of advanced) and therefore how many failed.
        size_t matchTested;

        // Number of entries retrieved from the index during the scan.
        size_t keysExamined;

    };

    struct MultiPlanStats : public SpecificStats {
        MultiPlanStats() { }

        virtual SpecificStats* clone() const {
            return new MultiPlanStats(*this);
        }
    };

    struct OrStats : public SpecificStats {
        OrStats() : dupsTested(0),
                    dupsDropped(0),
                    locsForgotten(0) { }

        virtual ~OrStats() { }

        virtual SpecificStats* clone() const {
            OrStats* specific = new OrStats(*this);
            return specific;
        }

        size_t dupsTested;
        size_t dupsDropped;

        // How many calls to invalidate(...) actually removed a DiskLoc from our deduping map?
        size_t locsForgotten;

        // We know how many passed (it's the # of advanced) and therefore how many failed.
        std::vector<size_t> matchTested;
    };

    struct SortStats : public SpecificStats {
        SortStats() : forcedFetches(0), memUsage(0), memLimit(0) { }

        virtual ~SortStats() { }

        virtual SpecificStats* clone() const {
            SortStats* specific = new SortStats(*this);
            return specific;
        }

        // How many records were we forced to fetch as the result of an invalidation?
        size_t forcedFetches;

        // What's our current memory usage?
        size_t memUsage;

        // What's our memory limit?
        size_t memLimit;
    };

    struct MergeSortStats : public SpecificStats {
        MergeSortStats() : dupsTested(0),
                           dupsDropped(0),
                           forcedFetches(0) { }

        virtual ~MergeSortStats() { }

        virtual SpecificStats* clone() const {
            MergeSortStats* specific = new MergeSortStats(*this);
            return specific;
        }

        size_t dupsTested;
        size_t dupsDropped;

        // How many records were we forced to fetch as the result of an invalidation?
        size_t forcedFetches;
    };

    struct ShardingFilterStats : public SpecificStats {
        ShardingFilterStats() : chunkSkips(0) { }

        virtual SpecificStats* clone() const {
            ShardingFilterStats* specific = new ShardingFilterStats(*this);
            return specific;
        }

        size_t chunkSkips;
    };

    struct TwoDStats : public SpecificStats {
        TwoDStats() { }

        virtual SpecificStats* clone() const {
            TwoDStats* specific = new TwoDStats(*this);
            return specific;
        }

        // Type of GeoBrowse (box, circle, ...)
        std::string type;

        // Field name in 2d index.
        std::string field;

        // Geo hash converter parameters.
        // Used to construct a geo hash converter to generate
        // explain-style index bounds from geo hashes.
        GeoHashConverter::Parameters converterParams;

        // Geo hashes generated by GeoBrowse::fillStack.
        // Raw data for explain index bounds.
        std::vector<GeoHash> expPrefixes;
    };

    struct TwoDNearStats : public SpecificStats {
        TwoDNearStats() : objectsLoaded(0), nscanned(0) { }

        virtual SpecificStats* clone() const {
            TwoDNearStats* specific = new TwoDNearStats(*this);
            return specific;
        }

        size_t objectsLoaded;

        // Since 2d's near does all its work in one go we can't divine the real nscanned from
        // anything else.
        size_t nscanned;
    };

    struct TextStats : public SpecificStats {
        TextStats() : keysExamined(0), fetches(0), parsedTextQuery() { }

        virtual SpecificStats* clone() const {
            TextStats* specific = new TextStats(*this);
            return specific;
        }

        size_t keysExamined;

        size_t fetches;

        // Human-readable form of the FTSQuery associated with the text stage.
        BSONObj parsedTextQuery;
    };

}  // namespace mongo