MySQL  8.0.20
Source Code Documentation
ut0stage.h
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 2014, 2019, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License, version 2.0, as published by the
7 Free Software Foundation.
8 
9 This program is also distributed with certain software (including but not
10 limited to OpenSSL) that is licensed under separate terms, as designated in a
11 particular file or component or in included license documentation. The authors
12 of MySQL hereby grant you an additional permission to link the program and
13 your derivative works with the separately licensed software that they have
14 included with MySQL.
15 
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19 for more details.
20 
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 
25 *****************************************************************************/
26 
27 /** @file include/ut0stage.h
28  Supplementary code to performance schema stage instrumentation.
29 
30  Created Nov 12, 2014 Vasil Dimov
31  *******************************************************/
32 
33 #ifndef ut0stage_h
34 #define ut0stage_h
35 
36 #include <math.h>
37 #include <algorithm>
38 
39 #include "dict0mem.h" /* dict_index_t */
40 #include "mysql/psi/mysql_stage.h" /* mysql_stage_inc_work_completed */
41 #include "row0log.h" /* row_log_estimate_work() */
42 #include "srv0srv.h" /* ut_stage_alter_t */
43 #include "univ.i"
44 
45 #ifdef HAVE_PSI_STAGE_INTERFACE
46 
47 /** Class used to report ALTER TABLE progress via performance_schema.
48 The only user of this class is the ALTER TABLE code and it calls the methods
49 in the following order
50 constructor
51 begin_phase_read_pk()
52  multiple times:
53  n_pk_recs_inc() // once per record read
54  inc() // once per page read
55 end_phase_read_pk()
56 if any new indexes are being added, for each one:
57  begin_phase_sort()
58  multiple times:
59  inc() // once per record sorted
60  begin_phase_insert()
61  multiple times:
62  inc() // once per record inserted
63  being_phase_log_index()
64  multiple times:
65  inc() // once per log-block applied
66 begin_phase_flush()
67  multiple times:
68  inc() // once per page flushed
69 begin_phase_log_table()
70  multiple times:
71  inc() // once per log-block applied
72 begin_phase_end()
73 destructor
74 
75 This class knows the specifics of each phase and tries to increment the
76 progress in an even manner across the entire ALTER TABLE lifetime. */
78  public:
79  /** Constructor.
80  @param[in] pk primary key of the old table */
81  explicit ut_stage_alter_t(const dict_index_t *pk)
83  m_pk(pk),
84  m_n_pk_recs(0),
85  m_n_pk_pages(0),
87  m_n_flush_pages(0),
89 
90  /** Destructor. */
92 
93  /** Flag an ALTER TABLE start (read primary key phase).
94  @param[in] n_sort_indexes number of indexes that will be sorted
95  during ALTER TABLE, used for estimating the total work to be done */
96  void begin_phase_read_pk(ulint n_sort_indexes);
97 
98  /** Increment the number of records in PK (table) with 1.
99  This is used to get more accurate estimate about the number of
100  records per page which is needed because some phases work on
101  per-page basis while some work on per-record basis and we want
102  to get the progress as even as possible. */
103  void n_pk_recs_inc();
104 
105  /** Flag either one record or one page processed, depending on the
106  current phase.
107  @param[in] inc_val flag this many units processed at once */
108  void inc(ulint inc_val = 1);
109 
110  /** Flag the end of reading of the primary key.
111  Here we know the exact number of pages and records and calculate
112  the number of records per page and refresh the estimate. */
113  void end_phase_read_pk();
114 
115  /** Flag the beginning of the sort phase.
116  @param[in] sort_multi_factor since merge sort processes
117  one page more than once we only update the estimate once per this
118  many pages processed. */
119  void begin_phase_sort(double sort_multi_factor);
120 
121  /** Flag the beginning of the insert phase. */
122  void begin_phase_insert();
123 
124  /** Flag the beginning of the flush phase.
125  @param[in] n_flush_pages this many pages are going to be
126  flushed */
127  void begin_phase_flush(ulint n_flush_pages);
128 
129  /** Flag the beginning of the log index phase. */
130  void begin_phase_log_index();
131 
132  /** Flag the beginning of the log table phase. */
133  void begin_phase_log_table();
134 
135  /** Flag the beginning of the end phase. */
136  void begin_phase_end();
137 
138  private:
139  /** Update the estimate of total work to be done. */
140  void reestimate();
141 
142  /** Change the current phase.
143  @param[in] new_stage pointer to the new stage to change to */
144  void change_phase(const PSI_stage_info *new_stage);
145 
146  /** Performance schema accounting object. */
148 
149  /** Old table PK. Used for calculating the estimate. */
151 
152  /** Number of records in the primary key (table), including delete
153  marked records. */
154  ulint m_n_pk_recs;
155 
156  /** Number of leaf pages in the primary key. */
158 
159  /** Estimated number of records per page in the primary key. */
161 
162  /** Number of indexes that are being added. */
164 
165  /** During the sort phase, increment the counter once per this
166  many pages processed. This is because sort processes one page more
167  than once. */
169 
170  /** Number of records processed during sort & insert phases. We
171  need to increment the counter only once page, or once per
172  recs-per-page records. */
174 
175  /** Number of pages to flush. */
177 
178  /** Current phase. */
179  enum {
181  READ_PK = 1,
182  SORT = 2,
183  INSERT = 3,
184  FLUSH = 4,
187  END = 7,
188  } m_cur_phase;
189 };
190 
191 /** Destructor. */
193  if (m_progress == nullptr) {
194  return;
195  }
196 
197  /* Set completed = estimated before we quit. */
200 
201  mysql_end_stage();
202 }
203 
204 /** Flag an ALTER TABLE start (read primary key phase).
205 @param[in] n_sort_indexes number of indexes that will be sorted
206 during ALTER TABLE, used for estimating the total work to be done */
207 inline void ut_stage_alter_t::begin_phase_read_pk(ulint n_sort_indexes) {
208  m_n_sort_indexes = n_sort_indexes;
209 
211 
212  m_progress =
214 
216 
217  reestimate();
218 }
219 
220 /** Increment the number of records in PK (table) with 1.
221 This is used to get more accurate estimate about the number of
222 records per page which is needed because some phases work on
223 per-page basis while some work on per-record basis and we want
224 to get the progress as even as possible. */
226 
227 /** Flag either one record or one page processed, depending on the
228 current phase.
229 @param[in] inc_val flag this many units processed at once */
230 inline void ut_stage_alter_t::inc(ulint inc_val /* = 1 */) {
231  if (m_progress == nullptr) {
232  return;
233  }
234 
235  ulint multi_factor = 1;
236  bool should_proceed = true;
237 
238  switch (m_cur_phase) {
239  case NOT_STARTED:
240  ut_error;
241  case READ_PK:
242  m_n_pk_pages++;
243  ut_ad(inc_val == 1);
244  /* Overall the read pk phase will read all the pages from the
245  PK and will do work, proportional to the number of added
246  indexes, thus when this is called once per read page we
247  increment with 1 + m_n_sort_indexes */
248  inc_val = 1 + m_n_sort_indexes;
249  break;
250  case SORT:
251  multi_factor = m_sort_multi_factor;
252  /* fall through */
253  case INSERT: {
254  /* Increment the progress every nth record. During
255  sort and insert phases, this method is called once per
256  record processed. We need fractional point numbers here
257  because "records per page" is such a number naturally and
258  to avoid rounding skew we want, for example: if there are
259  (double) N records per page, then the work_completed
260  should be incremented on the inc() calls round(k*N),
261  for k=1,2,3... */
262  const double every_nth = m_n_recs_per_page * multi_factor;
263 
264  const ulint k = static_cast<ulint>(round(m_n_recs_processed / every_nth));
265 
266  const ulint nth = static_cast<ulint>(round(k * every_nth));
267 
268  should_proceed = m_n_recs_processed == nth;
269 
271 
272  break;
273  }
274  case FLUSH:
275  break;
276  case LOG_INDEX:
277  break;
278  case LOG_TABLE:
279  break;
280  case END:
281  break;
282  }
283 
284  if (should_proceed) {
286  reestimate();
287  }
288 }
289 
290 /** Flag the end of reading of the primary key.
291 Here we know the exact number of pages and records and calculate
292 the number of records per page and refresh the estimate. */
294  reestimate();
295 
296  if (m_n_pk_pages == 0) {
297  /* The number of pages in the PK could be 0 if the tree is
298  empty. In this case we set m_n_recs_per_page to 1 to avoid
299  division by zero later. */
300  m_n_recs_per_page = 1.0;
301  } else {
303  std::max(static_cast<double>(m_n_pk_recs) / m_n_pk_pages, 1.0);
304  }
305 }
306 
307 /** Flag the beginning of the sort phase.
308 @param[in] sort_multi_factor since merge sort processes
309 one page more than once we only update the estimate once per this
310 many pages processed. */
311 inline void ut_stage_alter_t::begin_phase_sort(double sort_multi_factor) {
312  if (sort_multi_factor <= 1.0) {
314  } else {
315  m_sort_multi_factor = static_cast<ulint>(round(sort_multi_factor));
316  }
317 
319 }
320 
321 /** Flag the beginning of the insert phase. */
324 }
325 
326 /** Flag the beginning of the flush phase.
327 @param[in] n_flush_pages this many pages are going to be
328 flushed */
329 inline void ut_stage_alter_t::begin_phase_flush(ulint n_flush_pages) {
330  m_n_flush_pages = n_flush_pages;
331 
332  reestimate();
333 
335 }
336 
337 /** Flag the beginning of the log index phase. */
340 }
341 
342 /** Flag the beginning of the log table phase. */
345 }
346 
347 /** Flag the beginning of the end phase. */
350 }
351 
352 /** Update the estimate of total work to be done. */
354  if (m_progress == nullptr) {
355  return;
356  }
357 
358  /* During the log table phase we calculate the estimate as
359  work done so far + log size remaining. */
360  if (m_cur_phase == LOG_TABLE) {
364  return;
365  }
366 
367  /* During the other phases we use a formula, regardless of
368  how much work has been done so far. */
369 
370  /* For number of pages in the PK - if the PK has not been
371  read yet, use stat_n_leaf_pages (approximate), otherwise
372  use the exact number we gathered. */
373  const ulint n_pk_pages =
375 
376  /* If flush phase has not started yet and we do not know how
377  many pages are to be flushed, then use a wild guess - the
378  number of pages in the PK / 2. */
379  if (m_n_flush_pages == 0) {
380  m_n_flush_pages = n_pk_pages / 2;
381  }
382 
383  ulonglong estimate =
384  n_pk_pages *
385  (1 /* read PK */
386  + m_n_sort_indexes /* row_merge_buf_sort() inside the
387  read PK per created index */
388  + m_n_sort_indexes * 2 /* sort & insert per created index */) +
390 
391  /* Prevent estimate < completed */
392  estimate = std::max(estimate, mysql_stage_get_work_completed(m_progress));
393 
395 }
396 
397 /** Change the current phase.
398 @param[in] new_stage pointer to the new stage to change to */
399 inline void ut_stage_alter_t::change_phase(const PSI_stage_info *new_stage) {
400  if (m_progress == nullptr) {
401  return;
402  }
403 
406  } else if (new_stage == &srv_stage_alter_table_merge_sort) {
407  m_cur_phase = SORT;
408  } else if (new_stage == &srv_stage_alter_table_insert) {
410  } else if (new_stage == &srv_stage_alter_table_flush) {
411  m_cur_phase = FLUSH;
412  } else if (new_stage == &srv_stage_alter_table_log_index) {
414  } else if (new_stage == &srv_stage_alter_table_log_table) {
416  } else if (new_stage == &srv_stage_alter_table_end) {
417  m_cur_phase = END;
418  } else {
419  ut_error;
420  }
421 
424 
425  m_progress = mysql_set_stage(new_stage->m_key);
426 
429 }
430 
431 /* class to monitor the progress of 'ALTER TABLESPACE ENCRYPTION' in terms
432 of number of pages operated upon. */
434  public:
435  /** Constructor. */
437  : m_progress(nullptr),
438  m_work_estimated(0),
439  m_work_done(0),
441 
442  /** Destructor. */
444  if (m_progress == nullptr) {
445  return;
446  }
447  mysql_end_stage();
448  }
449 
450  void init(int key) {
451  ut_ad(key != -1);
453 
454  m_progress = nullptr;
455  m_work_estimated = 0;
456  m_work_done = 0;
457 
459  /* Change phase to INITIATED */
460  change_phase();
461  }
462 
463  void set_estimate(ulint units) {
464  if (m_progress == nullptr) {
465  return;
466  }
467 
468  ut_ad(m_cur_phase == INITIATED);
469  m_work_estimated = units;
470  mysql_stage_set_work_estimated(m_progress, m_work_estimated);
471  /* Change phase to WORK_ESTIMATED */
472  change_phase();
473  }
474 
475  void update_work(ulint units) {
476  if (m_progress == nullptr) {
477  return;
478  }
479 
480  ut_ad(m_cur_phase == WORK_ESTIMATED);
481 
482  m_work_done += units;
483  ut_ad(m_work_done <= m_work_estimated);
485 
486  if (m_work_done == m_work_estimated) {
487  /* Change phase to WORK_COMPLETED */
488  change_phase();
489  }
490  }
491 
492  void change_phase() {
493  if (m_progress == nullptr) {
495  return;
496  }
497 
498  switch (m_cur_phase) {
499  case NOT_STARTED:
500  m_cur_phase = INITIATED;
501  break;
502  case INITIATED:
503  m_cur_phase = WORK_ESTIMATED;
504  break;
505  case WORK_ESTIMATED:
506  m_cur_phase = WORK_COMPLETED;
507  break;
508  case WORK_COMPLETED:
509  default:
510  ut_error;
511  }
512  }
513 
514  bool is_completed() {
515  if (m_progress == nullptr) {
516  return true;
517  }
518 
519  return (m_cur_phase == WORK_COMPLETED);
520  }
521 
522  private:
523  /** Performance schema accounting object. */
525 
526  /** Number of pages to be (un)encrypted . */
528 
529  /** Number of pages already (un)encrypted . */
530  ulint m_work_done;
531 
532  /** Current phase. */
533  enum {
535  INITIATED = 1,
536  WORK_ESTIMATED = 2,
537  WORK_COMPLETED = 3,
538  } m_cur_phase;
539 };
540 
541 #else /* HAVE_PSI_STAGE_INTERFACE */
542 
543 class ut_stage_alter_t {
544  public:
545  explicit ut_stage_alter_t(const dict_index_t *pk) {}
546 
547  void begin_phase_read_pk(ulint n_sort_indexes) {}
548 
549  void n_pk_recs_inc() {}
550 
551  void inc(ulint inc_val = 1) {}
552 
553  void end_phase_read_pk() {}
554 
555  void begin_phase_sort(double sort_multi_factor) {}
556 
557  void begin_phase_insert() {}
558 
559  void begin_phase_flush(ulint n_flush_pages) {}
560 
561  void begin_phase_log_index() {}
562 
563  void begin_phase_log_table() {}
564 
565  void begin_phase_end() {}
566 };
567 
568 class ut_stage_alter_ts {
569  public:
570  /** Constructor. */
571  ut_stage_alter_ts() {}
572 
573  /** Destructor. */
574  inline ~ut_stage_alter_ts() {}
575 
576  void init(int key) {}
577 
578  void set_estimate(uint units) {}
579 
580  void update_work(uint units) {}
581 
582  void change_phase() {}
583 };
584 #endif /* HAVE_PSI_STAGE_INTERFACE */
585 
586 #endif /* ut0stage_h */
unsigned long long int ulonglong
Definition: my_inttypes.h:55
PSI_stage_info srv_stage_alter_table_log_table
Performance schema stage event for monitoring ALTER TABLE progress row_log_table_apply().
Definition: srv0srv.cc:779
Data dictionary memory object creation.
void begin_phase_insert()
Flag the beginning of the insert phase.
Definition: ut0stage.h:322
ulint m_n_pk_pages
Number of leaf pages in the primary key.
Definition: ut0stage.h:157
void change_phase(const PSI_stage_info *new_stage)
Change the current phase.
Definition: ut0stage.h:399
void change_phase()
Definition: ut0stage.h:492
Definition: ut0stage.h:184
Definition: ut0stage.h:433
~ut_stage_alter_ts()
Destructor.
Definition: ut0stage.h:443
void begin_phase_log_index()
Flag the beginning of the log index phase.
Definition: ut0stage.h:338
void inc(ulint inc_val=1)
Flag either one record or one page processed, depending on the current phase.
Definition: ut0stage.h:230
ulint m_n_pk_recs
Number of records in the primary key (table), including delete marked records.
Definition: ut0stage.h:154
#define mysql_set_stage(K)
Set the current stage.
Definition: mysql_stage.h:81
Definition: ut0stage.h:186
ulint m_n_recs_processed
Number of records processed during sort & insert phases.
Definition: ut0stage.h:173
double m_n_recs_per_page
Estimated number of records per page in the primary key.
Definition: ut0stage.h:160
enum ut_stage_alter_t::@137 m_cur_phase
Current phase.
void n_pk_recs_inc()
Increment the number of records in PK (table) with 1.
Definition: ut0stage.h:225
void update_work(ulint units)
Definition: ut0stage.h:475
#define mysql_stage_set_work_estimated(P1, P2)
Definition: mysql_stage.h:144
void begin_phase_read_pk(ulint n_sort_indexes)
Flag an ALTER TABLE start (read primary key phase).
Definition: ut0stage.h:207
Definition: ut0stage.h:180
PSI_stage_info srv_stage_alter_table_log_index
Performance schema stage event for monitoring ALTER TABLE progress row_log_apply().
Definition: srv0srv.cc:773
PSI_stage_progress * m_progress
Performance schema accounting object.
Definition: ut0stage.h:524
#define mysql_end_stage
End the last stage.
Definition: mysql_stage.h:91
Definition: ut0stage.h:182
void begin_phase_log_table()
Flag the beginning of the log table phase.
Definition: ut0stage.h:343
ulint m_work_estimated
Number of pages to be (un)encrypted .
Definition: ut0stage.h:527
#define mysql_stage_set_work_completed(P1, P2)
Definition: mysql_stage.h:119
static mysql_service_status_t init()
Component initialization.
Definition: audit_api_message_emit.cc:570
The server main program.
#define mysql_stage_get_work_completed(P1)
Definition: mysql_stage.h:122
void reestimate()
Update the estimate of total work to be done.
Definition: ut0stage.h:353
PSI_stage_info srv_stage_alter_table_insert
Performance schema stage event for monitoring ALTER TABLE progress row_merge_insert_index_tuples().
Definition: srv0srv.cc:768
void begin_phase_flush(ulint n_flush_pages)
Flag the beginning of the flush phase.
Definition: ut0stage.h:329
Definition: ut0stage.h:183
Stage instrument information.
Definition: psi_stage_bits.h:71
void end_phase_read_pk()
Flag the end of reading of the primary key.
Definition: ut0stage.h:293
PSI_stage_info srv_stage_alter_table_flush
Performance schema stage event for monitoring ALTER TABLE progress log_make_latest_checkpoint().
Definition: srv0srv.cc:763
void begin_phase_end()
Flag the beginning of the end phase.
Definition: ut0stage.h:348
const dict_index_t * m_pk
Old table PK.
Definition: ut0stage.h:150
ut_stage_alter_ts()
Constructor.
Definition: ut0stage.h:436
unsigned int uint
Definition: uca-dump.cc:29
PSI_stage_key m_key
The registered stage key.
Definition: psi_stage_bits.h:73
void init(int key)
Definition: ut0stage.h:450
ulint stat_n_leaf_pages
approximate number of leaf pages in the index tree
Definition: dict0mem.h:1010
Definition: ut0stage.h:187
PSI_stage_info srv_stage_alter_table_end
Performance schema stage event for monitoring ALTER TABLE progress everything after flush log_make_la...
Definition: srv0srv.cc:758
ulint row_log_estimate_work(const dict_index_t *index)
Estimate how much work is to be done by the log apply phase of an ALTER TABLE for this index...
Definition: row0log.cc:2635
static const char * key
Definition: suite_stubs.c:14
#define mysql_stage_get_work_estimated(P1)
Definition: mysql_stage.h:147
PSI_stage_info srv_stage_alter_table_merge_sort
Performance schema stage event for monitoring ALTER TABLE progress row_merge_sort().
Definition: srv0srv.cc:785
ulint m_sort_multi_factor
During the sort phase, increment the counter once per this many pages processed.
Definition: ut0stage.h:168
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:65
#define mysql_stage_inc_work_completed(P1, P2)
Definition: mysql_stage.h:135
#define ut_error
Abort execution.
Definition: ut0dbg.h:61
Interface for an instrumented stage progress.
Definition: psi_stage_bits.h:60
PSI_stage_progress * m_progress
Performance schema accounting object.
Definition: ut0stage.h:147
Class used to report ALTER TABLE progress via performance_schema.
Definition: ut0stage.h:77
PSI_stage_info srv_stage_alter_table_read_pk_internal_sort
Performance schema stage event for monitoring ALTER TABLE progress row_merge_read_clustered_index().
Definition: srv0srv.cc:790
Modification log for online index creation and online table rebuild.
~ut_stage_alter_t()
Destructor.
Definition: ut0stage.h:192
ut_stage_alter_t(const dict_index_t *pk)
Constructor.
Definition: ut0stage.h:81
Definition: ut0stage.h:185
Instrumentation helpers for stages.
bool is_completed()
Definition: ut0stage.h:514
void set_estimate(ulint units)
Definition: ut0stage.h:463
void begin_phase_sort(double sort_multi_factor)
Flag the beginning of the sort phase.
Definition: ut0stage.h:311
Definition: ut0stage.h:181
ulint m_n_sort_indexes
Number of indexes that are being added.
Definition: ut0stage.h:163
ulint m_work_done
Number of pages already (un)encrypted .
Definition: ut0stage.h:530
Dialog Client Authentication nullptr
Definition: dialog.cc:353
collation_unordered_map< std::string, Unit > units()
A function to obtaint the supported units for the gis module.
Definition: st_units_of_measure.cc:28
ulint m_n_flush_pages
Number of pages to flush.
Definition: ut0stage.h:176
Data structure for an index.
Definition: dict0mem.h:879