File: opt_trace_context.h

package info (click to toggle)
mysql-8.0 8.0.43-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,273,924 kB
  • sloc: cpp: 4,684,605; ansic: 412,450; pascal: 108,398; java: 83,641; perl: 30,221; cs: 27,067; sql: 26,594; sh: 24,181; python: 21,816; yacc: 17,169; php: 11,522; xml: 7,388; javascript: 7,076; makefile: 2,194; lex: 1,075; awk: 670; asm: 520; objc: 183; ruby: 97; lisp: 86
file content (404 lines) | stat: -rw-r--r-- 16,437 bytes parent folder | download
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
/* Copyright (c) 2011, 2025, Oracle and/or its affiliates.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License, version 2.0,
   as published by the Free Software Foundation.

   This program is designed to work with certain software (including
   but not limited to OpenSSL) that is licensed under separate terms,
   as designated in a particular file or component or in included license
   documentation.  The authors of MySQL hereby grant you an additional
   permission to link the program and your derivative works with the
   separately licensed software that they have either included with
   the program or referenced in the documentation.

   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 General Public License, version 2.0, for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA  */

#ifndef OPT_TRACE_CONTEXT_INCLUDED
#define OPT_TRACE_CONTEXT_INCLUDED

#include <assert.h>

#include "my_inttypes.h"
#include "mysql/components/services/bits/psi_bits.h"
#include "prealloced_array.h"

/**
   @file
   This contains the declaration of class Opt_trace_context, which is needed
   to declare THD.
   It is recommend to read opt_trace.h first.
*/

class Opt_trace_stmt;  // implementation detail local to opt_trace.cc

typedef Prealloced_array<Opt_trace_stmt *, 16> Opt_trace_stmt_array;

/**
  @class Opt_trace_context

  A per-session context which is always available at any point of execution,
  because in practice it's accessible from THD which contains:
  @verbatim Opt_trace_context opt_trace; @endverbatim
  It maintains properties of the session's regarding tracing: enabled/disabled
  state, style (all trace on one line, or not, etc), a list of all remembered
  traces of previous and current SQL statement (as restricted by
  OFFSET/LIMIT), and a pointer to the current (being-generated) trace (which
  itself has a pointer to its current open object/array).

  Here is why the context needs to provide the current open object/array:

  @li When adding a value (scalar or array or object) to an array, or adding a
  key/value pair to an object, we need this outer object or array (from now
  on, we will use the term "structure" for "object or array", as both are
  structured types).

  @li The most natural way would be that the outer object would be passed in
  argument to the adder (the function which wants to add the value or
  key/value).

  @li But tracing is sometimes produced from deep down the stack trace, with
  many intermediate frames doing no tracing (writing nothing to the trace), so
  it would require passing the outer structure through many levels, thus
  modifying many function prototypes.
  Example (in gdb "backtrace" notation: inner frames first):
@verbatim
    #0  Item_in_subselect::single_value_transformer
        - opens an object for key "transformation"
    #1  Item_in_subselect::select_in_like_transformer - does no tracing
    #2  Item_allany_subselect::select_transformer - does no tracing
    #3  Query_block::prepare - opens an object for key "join_preparation"
@endverbatim
  So the object opened in #3 would have to be passed in argument to #2 and #1
  in order to finally reach #0 where object "transformation" would be added to
  it.

  @li So, as we cannot practically pass the object down, we rather maintain a
  "current object or array" accessible from the Opt_trace_context context;
  it's a pointer to an instance of Opt_trace_struct, and the function deep
  down (frame #0) grabs it from the context, where it was depositted by the
  function high up (frame #3 in the last example).
*/

class Opt_trace_context {
 public:
  Opt_trace_context() : pimpl(nullptr), I_S_disabled(0) {}
  ~Opt_trace_context();

  /**
     Starts a new trace.
     @param  support_I_S      Whether this statement should have its trace in
                              information_schema
     @param  support_dbug_or_missing_priv  'true' if this statement
                              should have its trace in the dbug log (--debug),
                              or if missing_privilege() may be called on this
                              trace
     @param  end_marker       For a key/(object|array) pair, should the key be
                              repeated in a comment when the object|array
                              closes? like
                              @verbatim
                              "key_foo": {
                                           multi-line blah
                                         } / * key_foo * /
                              @endverbatim
                              This is for human-readability only, not valid in
                              JSON. Note that YAML supports #-prefixed
                              comments (we would just need to put the next
                              item's "," before the current item's "#").
     @param  one_line         Should the trace be on a single line without
                              indentation? (More compact for network transfer
                              to programs, less human-readable.)
     @param  offset           Offset for restricting trace production.
     @param  limit            Limit for restricting trace production.
     @param  max_mem_size     Maximum allowed for cumulated size of all
                              remembered traces.
     @param  features         Only these optimizer features should be traced.

     @retval false            ok
     @retval true             error (OOM): instance is unusable, so only
                              destructor is permitted on it; any other
                              member function has undefined effects.
  */
  bool start(bool support_I_S, bool support_dbug_or_missing_priv,
             bool end_marker, bool one_line, long offset, long limit,
             ulong max_mem_size, ulonglong features);

  /**
    Ends the current (=open, unfinished, being-generated) trace.

    If @c missing_privilege() has been called between start() and end(),
    end() restores I_S support to what it was before the call to
    @c missing_privilege(). This is the key to ensure that missing_privilege()
    does not disable I_S support for the rest of the connection's life!
  */
  void end();

  /// Returns whether there is a current trace
  bool is_started() const {
    return unlikely(pimpl != nullptr) && pimpl->current_stmt_in_gen != nullptr;
  }

  /**
     @returns whether the current trace writes to I_S.
     This function should rarely be used. Don't you use this for some clever
     optimizations bypassing opt trace!
  */
  bool support_I_S() const;

  /**
     Set the "original" query (not transformed, as sent by client) for the
     current trace.
     @param   query    query
     @param   length   query's length
     @param   charset  charset which was used to encode this query
  */
  void set_query(const char *query, size_t length, const CHARSET_INFO *charset);

  /**
     Brainwash: deletes all remembered traces and resets counters regarding
     OFFSET/LIMIT (so that the next statement is considered as "at offset
     0"). Does not reset the @@@@optimizer_trace_offset/limit variables.
  */
  void reset();

  /// @sa parameters of Opt_trace_context::start()
  bool get_end_marker() const { return pimpl->end_marker; }
  /// @sa parameters of Opt_trace_context::start()
  bool get_one_line() const { return pimpl->one_line; }

  /**
     Names of flags for @@@@optimizer_trace variable of @c sys_vars.cc :
     @li "enabled" = tracing enabled
     @li "one_line"= see parameter of @ref Opt_trace_context::start
     @li "default".
  */
  static const char *flag_names[];

  /** Flags' numeric values for @@@@optimizer_trace variable */
  enum { FLAG_DEFAULT = 0, FLAG_ENABLED = 1 << 0, FLAG_ONE_LINE = 1 << 1 };

  /**
     Features' names for @@@@optimizer_trace_features variable of
     @c sys_vars.cc:
     @li "greedy_search" = the greedy search for a plan
     @li "range_optimizer" = the cost analysis of accessing data through
     ranges in indexes
     @li "dynamic_range" = the range optimization performed for each record
                           when access method is dynamic range
     @li "repeated_subselect" = the repeated execution of subselects
     @li "default".
  */
  static const char *feature_names[];

  /** Features' numeric values for @@@@optimizer_trace_features variable */
  enum feature_value {
    GREEDY_SEARCH = 1 << 0,
    RANGE_OPTIMIZER = 1 << 1,
    DYNAMIC_RANGE = 1 << 2,
    REPEATED_SUBSELECT = 1 << 3,
    /*
      If you add here, update feature_value of empty implementation
      and default_features!
    */
    /**
       Anything unclassified, including the top object (thus, by "inheritance
       from parent", disabling MISC makes an empty trace).
       This feature cannot be disabled by the user; for this it is important
       that it always has biggest flag; flag's value itself does not matter.
    */
    MISC = 1 << 7
  };

  /**
     User lacks privileges to see the current trace. Make the trace appear
     empty in Opt_trace_info, and disable I_S for all its upcoming children.

     Once a call to this function has been made, subsequent calls to it before
     @c end() have no effects.
  */
  void missing_privilege();

  /// Optimizer features which are traced by default.
  static const feature_value default_features;

  /**
     @returns whether an optimizer feature should be traced.
     @param  f  feature
  */
  bool feature_enabled(feature_value f) const {
    return unlikely(pimpl != nullptr) && (pimpl->features & f);
  }

  /**
     Opt_trace_struct is passed Opt_trace_context*, and needs to know
     to which statement's trace to attach, so Opt_trace_context must provide
     this information.
  */
  Opt_trace_stmt *get_current_stmt_in_gen() {
    return pimpl->current_stmt_in_gen;
  }

  /**
     @returns the next statement to show in I_S.
     @param[in,out]  got_so_far  How many statements the caller got so far
     (by previous calls to this function); function updates this count.
     @note traces are returned from oldest to newest.
   */
  const Opt_trace_stmt *get_next_stmt_for_I_S(long *got_so_far) const;

  /// Temporarily disables I_S for this trace and its children.
  void disable_I_S_for_this_and_children() {
    ++I_S_disabled;
    if (unlikely(pimpl != nullptr)) pimpl->disable_I_S_for_this_and_children();
  }

  /**
     Restores I_S support to what it was before the previous call to
     disable_I_S_for_this_and_children().
  */
  void restore_I_S() {
    --I_S_disabled;
    assert(I_S_disabled >= 0);
    if (unlikely(pimpl != nullptr)) pimpl->restore_I_S();
  }

 private:
  /**
     To have the smallest impact on THD's size, most of the implementation is
     moved to a separate class Opt_trace_context_impl which is instantiated on
     the heap when really needed. So if a connection never sets
     @@@@optimizer_trace to "enabled=on" and does not use --debug, this heap
     allocation never happens.
     This class is declared here so that frequently called functions like
     Opt_trace_context::is_started() can be inlined.
  */
  class Opt_trace_context_impl {
   public:
    Opt_trace_context_impl()
        : current_stmt_in_gen(nullptr),
          stack_of_current_stmts(PSI_INSTRUMENT_ME),
          all_stmts_for_I_S(PSI_INSTRUMENT_ME),
          all_stmts_to_del(PSI_INSTRUMENT_ME),
          features(feature_value(0)),
          offset(0),
          limit(0),
          since_offset_0(0) {}

    void disable_I_S_for_this_and_children();
    void restore_I_S();

    /**
       Trace which is currently being generated, where structures are being
       added. "in_gen" stands for "in generation", being-generated.

       In simple cases it is equal to the last element of array
       all_stmts_for_I_S. But it can be prior to it, for example when calling
       a stored routine:
@verbatim
       CALL statement starts executing
         create trace of CALL (call it "trace #1")
         add structure to trace #1
         add structure to trace #1
         First sub-statement executing
           create trace of sub-statement (call it "trace #2")
           add structure to trace #2
           add structure to trace #2
         First sub-statement ends
         add structure to trace #1
@endverbatim
       In the beginning, the CALL statement's trace is the newest and current;
       when the first sub-statement is executing, that sub-statement's trace
       is the newest and current; when the first sub-statement ends, it is
       still the newest but it's not the current anymore: the current is then
       again the CALL's one, where structures will be added, until a second
       sub-statement is executed.
       Another case is when the current statement sends only to DBUG:
       all_stmts_for_I_S lists only traces shown in OPTIMIZER_TRACE.
    */
    Opt_trace_stmt *current_stmt_in_gen;

    /**
       To keep track of what is the current statement, as execution goes into
       a sub-statement, and back to the upper statement, we have a stack of
       successive values of current_stmt_in_gen:
       when in a statement we enter a substatement (a new trace), we push the
       statement's trace on the stack and change current_stmt_in_gen to the
       substatement's trace; when leaving the substatement we pop from the
       stack and set current_stmt_in_gen to the popped value.
    */
    Opt_trace_stmt_array stack_of_current_stmts;

    /**
       List of remembered traces for putting into the OPTIMIZER_TRACE
       table. Element 0 is the one created first, will be first row of
       OPTIMIZER_TRACE table. The array structure fulfills those needs:
       - to output traces "oldest first" in OPTIMIZER_TRACE
       - to preserve traces "newest first" when @@@@optimizer_trace_offset<0
       - to delete a trace in the middle of the list when it is permanently
       out of the offset/limit showable window.
    */
    Opt_trace_stmt_array all_stmts_for_I_S;
    /**
       List of traces which are unneeded because of OFFSET/LIMIT, and
       scheduled for deletion from memory.
    */
    Opt_trace_stmt_array all_stmts_to_del;

    bool end_marker;  ///< copy of parameter of Opt_trace_context::start
    bool one_line;
    feature_value features;
    long offset;
    long limit;
    size_t max_mem_size;

    /**
       Number of statements traced so far since "offset 0", for comparison
       with OFFSET and LIMIT, when OFFSET >= 0.
    */
    long since_offset_0;
  };

  Opt_trace_context_impl *pimpl;  /// Dynamically allocated implementation.

  /**
    <>0 <=> any to-be-created statement's trace should not be in
    information_schema. This applies to next statements, their substatements,
    etc.
  */
  int I_S_disabled;

  /**
     Find and delete unneeded traces.
     For example if OFFSET=-1,LIMIT=1, only the last trace is needed. When a
     new trace is started, the previous traces becomes unneeded and this
     function deletes them which frees memory.
     @param  purge_all  if true, ignore OFFSET and thus delete everything
  */
  void purge_stmts(bool purge_all);

  /**
     Compute maximum allowed memory size for current trace. The current trace
     is the only one active. Other traces break down in two groups:
     - the finished ones (from previously executed statements),
     - the "started but not finished ones": they are not current, are not
     being updated at this moment: this must be the trace of a top
     statement calling a substatement which is the current trace now: trace's
     top statement is not being updated at this moment.
     So the current trace can grow in the room left by all traces above.
  */
  size_t allowed_mem_size_for_current_stmt() const;

  /// Not defined copy constructor, to disallow copy.
  Opt_trace_context(const Opt_trace_context &);
  /// Not defined assignment operator, to disallow assignment.
  Opt_trace_context &operator=(const Opt_trace_context &);
};

#endif /* OPT_TRACE_CONTEXT_INCLUDED */