summaryrefslogtreecommitdiff
path: root/src/mongo/db/explain.h
blob: 35414454abad060de6c872028d5954aa8bb8590a (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
// @file explain.h - Helper classes for generating query explain output.

/*    Copyright 2012 10gen Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#pragma once

#include "cursor.h"
#include "../util/timer.h"

namespace mongo {
    
    /**
     * Note: by default we filter out allPlans and oldPlan in the shell's
     * explain() function. If you add any recursive structures, make sure to
     * edit the JS to make sure everything gets filtered.
     */
    
    /** The timer starts on construction and provides the duration since then or until stopped. */
    class DurationTimer {
    public:
        DurationTimer() : _running( true ), _duration() {}
        void stop() { _running = false; _duration = _timer.millis(); }
        int duration() const { return _running ? _timer.millis() : _duration; }
    private:
        Timer _timer;
        bool _running;
        int _duration;
    };
    
    class ExplainClauseInfo;
    
    /** Data describing execution of a query plan. */
    class ExplainPlanInfo {
    public:
        ExplainPlanInfo();

        /** Note information about the plan. */
        void notePlan( const Cursor &cursor, bool scanAndOrder, bool indexOnly );
        /** Note an iteration of the plan. */
        void noteIterate( bool match, bool loadedRecord, const Cursor &cursor );
        /** Note that the plan yielded. */
        void noteYield();
        /** Note that the plan finished execution. */
        void noteDone( const Cursor &cursor );
        /** Note that the plan was chosen over others by the query optimizer. */
        void notePicked();

        /** BSON summary of the plan. */
        BSONObj bson() const;
        /** Combined details of both the plan and its clause. */
        BSONObj pickedPlanBson( const ExplainClauseInfo &clauseInfo ) const;

        bool picked() const { return _picked; }
        bool done() const { return _done; }
        long long n() const { return _n; }
        long long nscanned() const { return _nscanned; }

    private:
        void noteCursorUpdate( const Cursor &cursor );
        string _cursorName;
        bool _isMultiKey;
        long long _n;
        long long _nscannedObjects;
        long long _nscanned;
        bool _scanAndOrder;
        bool _indexOnly;
        int _nYields;
        BSONObj _indexBounds;
        bool _picked;
        bool _done;
        BSONObj _details;
    };
    
    /** Data describing execution of a query clause. */
    class ExplainClauseInfo {
    public:
        ExplainClauseInfo();

        /** Note an iteration of the clause. */
        void noteIterate( bool match, bool loadedRecord, bool chunkSkip );
        /** Revise the total number of documents returned to match an external count. */
        void reviseN( long long n );
        /** Stop the clauses's timer. */
        void stopTimer();

        /** Add information about a plan to this clause. */
        void addPlanInfo( const shared_ptr<ExplainPlanInfo> &info );
        BSONObj bson() const;

        long long n() const { return _n; }
        long long nscannedObjects() const { return _nscannedObjects; }
        long long nscanned() const;
        long long nChunkSkips() const { return _nChunkSkips; }
        int millis() const { return _timer.duration(); }

    private:
        const ExplainPlanInfo &virtualPickedPlan() const;
        list<shared_ptr<const ExplainPlanInfo> > _plans;
        long long _n;
        long long _nscannedObjects;
        long long _nChunkSkips;
        DurationTimer _timer;
    };
    
    /** Data describing execution of a query. */
    class ExplainQueryInfo {
    public:
        /** Note an iteration of the query's current clause. */
        void noteIterate( bool match, bool loadedRecord, bool chunkSkip );
        /** Revise the number of documents returned by the current clause. */
        void reviseN( long long n );

        /* Additional information describing the query. */
        struct AncillaryInfo {
            BSONObj _oldPlan;
        };
        void setAncillaryInfo( const AncillaryInfo &ancillaryInfo );
        
        /* Add information about a clause to this query. */
        void addClauseInfo( const shared_ptr<ExplainClauseInfo> &info );
        BSONObj bson() const;

    private:
        static string server();
        
        list<shared_ptr<ExplainClauseInfo> > _clauses;
        AncillaryInfo _ancillaryInfo;
        DurationTimer _timer;
    };
    
    /** Data describing execution of a query with a single clause and plan. */
    class ExplainSinglePlanQueryInfo {
    public:
        ExplainSinglePlanQueryInfo();

        /** Note information about the plan. */
        void notePlan( const Cursor &cursor, bool scanAndOrder, bool indexOnly ) {
            _planInfo->notePlan( cursor, scanAndOrder, indexOnly );
        }
        /** Note an iteration of the plan and the clause. */
        void noteIterate( bool match, bool loadedRecord, bool chunkSkip, const Cursor &cursor ) {
            _planInfo->noteIterate( match, loadedRecord, cursor );
            _queryInfo->noteIterate( match, loadedRecord, chunkSkip );
        }
        /** Note that the plan yielded. */
        void noteYield() {
            _planInfo->noteYield();
        }
        /** Note that the plan finished execution. */
        void noteDone( const Cursor &cursor ) {
            _planInfo->noteDone( cursor );
        }

        /** Return the corresponding ExplainQueryInfo for further use. */
        shared_ptr<ExplainQueryInfo> queryInfo() const {
            return _queryInfo;
        }

    private:
        shared_ptr<ExplainPlanInfo> _planInfo;
        shared_ptr<ExplainQueryInfo> _queryInfo;
    };

} // namespace mongo