1 /* Copyright (c) 2010, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software Foundation,
21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22
23 /**
24 @file storage/perfschema/table_events_stages.cc
25 Table EVENTS_STAGES_xxx (implementation).
26 */
27
28 #include "my_global.h"
29 #include "my_thread.h"
30 #include "table_events_stages.h"
31 #include "pfs_instr_class.h"
32 #include "pfs_instr.h"
33 #include "pfs_events_stages.h"
34 #include "pfs_timer.h"
35 #include "pfs_buffer_container.h"
36 #include "field.h"
37
38 THR_LOCK table_events_stages_current::m_table_lock;
39
40 static const TABLE_FIELD_TYPE field_types[]=
41 {
42 {
43 { C_STRING_WITH_LEN("THREAD_ID") },
44 { C_STRING_WITH_LEN("bigint(20)") },
45 { NULL, 0}
46 },
47 {
48 { C_STRING_WITH_LEN("EVENT_ID") },
49 { C_STRING_WITH_LEN("bigint(20)") },
50 { NULL, 0}
51 },
52 {
53 { C_STRING_WITH_LEN("END_EVENT_ID") },
54 { C_STRING_WITH_LEN("bigint(20)") },
55 { NULL, 0}
56 },
57 {
58 { C_STRING_WITH_LEN("EVENT_NAME") },
59 { C_STRING_WITH_LEN("varchar(128)") },
60 { NULL, 0}
61 },
62 {
63 { C_STRING_WITH_LEN("SOURCE") },
64 { C_STRING_WITH_LEN("varchar(64)") },
65 { NULL, 0}
66 },
67 {
68 { C_STRING_WITH_LEN("TIMER_START") },
69 { C_STRING_WITH_LEN("bigint(20)") },
70 { NULL, 0}
71 },
72 {
73 { C_STRING_WITH_LEN("TIMER_END") },
74 { C_STRING_WITH_LEN("bigint(20)") },
75 { NULL, 0}
76 },
77 {
78 { C_STRING_WITH_LEN("TIMER_WAIT") },
79 { C_STRING_WITH_LEN("bigint(20)") },
80 { NULL, 0}
81 },
82 {
83 { C_STRING_WITH_LEN("WORK_COMPLETED") },
84 { C_STRING_WITH_LEN("bigint(20)") },
85 { NULL, 0}
86 },
87 {
88 { C_STRING_WITH_LEN("WORK_ESTIMATED") },
89 { C_STRING_WITH_LEN("bigint(20)") },
90 { NULL, 0}
91 },
92 {
93 { C_STRING_WITH_LEN("NESTING_EVENT_ID") },
94 { C_STRING_WITH_LEN("bigint(20)") },
95 { NULL, 0}
96 },
97 {
98 { C_STRING_WITH_LEN("NESTING_EVENT_TYPE") },
99 { C_STRING_WITH_LEN("enum(\'TRANSACTION\',\'STATEMENT\',\'STAGE\',\'WAIT\'") },
100 { NULL, 0}
101 }
102 };
103
104 TABLE_FIELD_DEF
105 table_events_stages_current::m_field_def=
106 {12 , field_types };
107
108 PFS_engine_table_share
109 table_events_stages_current::m_share=
110 {
111 { C_STRING_WITH_LEN("events_stages_current") },
112 &pfs_truncatable_acl,
113 table_events_stages_current::create,
114 NULL, /* write_row */
115 table_events_stages_current::delete_all_rows,
116 table_events_stages_current::get_row_count,
117 sizeof(PFS_simple_index), /* ref length */
118 &m_table_lock,
119 &m_field_def,
120 false, /* checked */
121 false /* perpetual */
122 };
123
124 THR_LOCK table_events_stages_history::m_table_lock;
125
126 PFS_engine_table_share
127 table_events_stages_history::m_share=
128 {
129 { C_STRING_WITH_LEN("events_stages_history") },
130 &pfs_truncatable_acl,
131 table_events_stages_history::create,
132 NULL, /* write_row */
133 table_events_stages_history::delete_all_rows,
134 table_events_stages_history::get_row_count,
135 sizeof(pos_events_stages_history), /* ref length */
136 &m_table_lock,
137 &table_events_stages_current::m_field_def,
138 false, /* checked */
139 false /* perpetual */
140 };
141
142 THR_LOCK table_events_stages_history_long::m_table_lock;
143
144 PFS_engine_table_share
145 table_events_stages_history_long::m_share=
146 {
147 { C_STRING_WITH_LEN("events_stages_history_long") },
148 &pfs_truncatable_acl,
149 table_events_stages_history_long::create,
150 NULL, /* write_row */
151 table_events_stages_history_long::delete_all_rows,
152 table_events_stages_history_long::get_row_count,
153 sizeof(PFS_simple_index), /* ref length */
154 &m_table_lock,
155 &table_events_stages_current::m_field_def,
156 false, /* checked */
157 false /* perpetual */
158 };
159
table_events_stages_common(const PFS_engine_table_share * share,void * pos)160 table_events_stages_common::table_events_stages_common
161 (const PFS_engine_table_share *share, void *pos)
162 : PFS_engine_table(share, pos),
163 m_row_exists(false)
164 {}
165
166 /**
167 Build a row.
168 @param stage the stage the cursor is reading
169 */
make_row(PFS_events_stages * stage)170 void table_events_stages_common::make_row(PFS_events_stages *stage)
171 {
172 ulonglong timer_end;
173
174 m_row_exists= false;
175
176 PFS_stage_class *unsafe= (PFS_stage_class*) stage->m_class;
177 PFS_stage_class *klass= sanitize_stage_class(unsafe);
178 if (unlikely(klass == NULL))
179 return;
180
181 m_row.m_thread_internal_id= stage->m_thread_internal_id;
182 m_row.m_event_id= stage->m_event_id;
183 m_row.m_end_event_id= stage->m_end_event_id;
184 m_row.m_nesting_event_id= stage->m_nesting_event_id;
185 m_row.m_nesting_event_type= stage->m_nesting_event_type;
186
187 if (m_row.m_end_event_id == 0)
188 {
189 timer_end= get_timer_raw_value(stage_timer);
190 }
191 else
192 {
193 timer_end= stage->m_timer_end;
194 }
195
196 m_normalizer->to_pico(stage->m_timer_start, timer_end,
197 & m_row.m_timer_start, & m_row.m_timer_end, & m_row.m_timer_wait);
198
199 m_row.m_name= klass->m_name;
200 m_row.m_name_length= klass->m_name_length;
201
202 /* Disable source file and line to avoid stale __FILE__ pointers. */
203 m_row.m_source_length= 0;
204
205 if (klass->is_progress())
206 {
207 m_row.m_progress= true;
208 m_row.m_work_completed= stage->m_progress.m_work_completed;
209 m_row.m_work_estimated= stage->m_progress.m_work_estimated;
210 }
211 else
212 {
213 m_row.m_progress= false;
214 }
215
216 m_row_exists= true;
217 return;
218 }
219
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)220 int table_events_stages_common::read_row_values(TABLE *table,
221 unsigned char *buf,
222 Field **fields,
223 bool read_all)
224 {
225 Field *f;
226
227 if (unlikely(! m_row_exists))
228 return HA_ERR_RECORD_DELETED;
229
230 /* Set the null bits */
231 assert(table->s->null_bytes == 2);
232 buf[0]= 0;
233 buf[1]= 0;
234
235 for (; (f= *fields) ; fields++)
236 {
237 if (read_all || bitmap_is_set(table->read_set, f->field_index))
238 {
239 switch(f->field_index)
240 {
241 case 0: /* THREAD_ID */
242 set_field_ulonglong(f, m_row.m_thread_internal_id);
243 break;
244 case 1: /* EVENT_ID */
245 set_field_ulonglong(f, m_row.m_event_id);
246 break;
247 case 2: /* END_EVENT_ID */
248 if (m_row.m_end_event_id > 0)
249 set_field_ulonglong(f, m_row.m_end_event_id - 1);
250 else
251 f->set_null();
252 break;
253 case 3: /* EVENT_NAME */
254 set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
255 break;
256 case 4: /* SOURCE */
257 set_field_varchar_utf8(f, m_row.m_source, m_row.m_source_length);
258 break;
259 case 5: /* TIMER_START */
260 if (m_row.m_timer_start != 0)
261 set_field_ulonglong(f, m_row.m_timer_start);
262 else
263 f->set_null();
264 break;
265 case 6: /* TIMER_END */
266 if (m_row.m_timer_end != 0)
267 set_field_ulonglong(f, m_row.m_timer_end);
268 else
269 f->set_null();
270 break;
271 case 7: /* TIMER_WAIT */
272 if (m_row.m_timer_wait != 0)
273 set_field_ulonglong(f, m_row.m_timer_wait);
274 else
275 f->set_null();
276 break;
277 case 8: /* WORK_COMPLETED */
278 if (m_row.m_progress)
279 set_field_ulonglong(f, m_row.m_work_completed);
280 else
281 f->set_null();
282 break;
283 case 9: /* WORK_ESTIMATED */
284 if (m_row.m_progress)
285 set_field_ulonglong(f, m_row.m_work_estimated);
286 else
287 f->set_null();
288 break;
289 case 10: /* NESTING_EVENT_ID */
290 if (m_row.m_nesting_event_id != 0)
291 set_field_ulonglong(f, m_row.m_nesting_event_id);
292 else
293 f->set_null();
294 break;
295 case 11: /* NESTING_EVENT_TYPE */
296 if (m_row.m_nesting_event_id != 0)
297 set_field_enum(f, m_row.m_nesting_event_type);
298 else
299 f->set_null();
300 break;
301 default:
302 assert(false);
303 }
304 }
305 }
306 return 0;
307 }
308
create(void)309 PFS_engine_table* table_events_stages_current::create(void)
310 {
311 return new table_events_stages_current();
312 }
313
table_events_stages_current()314 table_events_stages_current::table_events_stages_current()
315 : table_events_stages_common(&m_share, &m_pos),
316 m_pos(0), m_next_pos(0)
317 {}
318
reset_position(void)319 void table_events_stages_current::reset_position(void)
320 {
321 m_pos.m_index= 0;
322 m_next_pos.m_index= 0;
323 }
324
rnd_init(bool scan)325 int table_events_stages_current::rnd_init(bool scan)
326 {
327 m_normalizer= time_normalizer::get(stage_timer);
328 return 0;
329 }
330
rnd_next(void)331 int table_events_stages_current::rnd_next(void)
332 {
333 PFS_thread *pfs_thread;
334 PFS_events_stages *stage;
335
336 m_pos.set_at(&m_next_pos);
337 PFS_thread_iterator it= global_thread_container.iterate(m_pos.m_index);
338 pfs_thread= it.scan_next(& m_pos.m_index);
339 if (pfs_thread != NULL)
340 {
341 stage= &pfs_thread->m_stage_current;
342 make_row(stage);
343 m_next_pos.set_after(&m_pos);
344 return 0;
345 }
346
347 return HA_ERR_END_OF_FILE;
348 }
349
rnd_pos(const void * pos)350 int table_events_stages_current::rnd_pos(const void *pos)
351 {
352 PFS_thread *pfs_thread;
353 PFS_events_stages *stage;
354
355 set_position(pos);
356
357 pfs_thread= global_thread_container.get(m_pos.m_index);
358 if (pfs_thread != NULL)
359 {
360 stage= &pfs_thread->m_stage_current;
361 make_row(stage);
362 return 0;
363 }
364
365 return HA_ERR_RECORD_DELETED;
366 }
367
delete_all_rows(void)368 int table_events_stages_current::delete_all_rows(void)
369 {
370 reset_events_stages_current();
371 return 0;
372 }
373
374 ha_rows
get_row_count(void)375 table_events_stages_current::get_row_count(void)
376 {
377 return global_thread_container.get_row_count();
378 }
379
create(void)380 PFS_engine_table* table_events_stages_history::create(void)
381 {
382 return new table_events_stages_history();
383 }
384
table_events_stages_history()385 table_events_stages_history::table_events_stages_history()
386 : table_events_stages_common(&m_share, &m_pos),
387 m_pos(), m_next_pos()
388 {}
389
reset_position(void)390 void table_events_stages_history::reset_position(void)
391 {
392 m_pos.reset();
393 m_next_pos.reset();
394 }
395
rnd_init(bool scan)396 int table_events_stages_history::rnd_init(bool scan)
397 {
398 m_normalizer= time_normalizer::get(stage_timer);
399 return 0;
400 }
401
rnd_next(void)402 int table_events_stages_history::rnd_next(void)
403 {
404 PFS_thread *pfs_thread;
405 PFS_events_stages *stage;
406 bool has_more_thread= true;
407
408 if (events_stages_history_per_thread == 0)
409 return HA_ERR_END_OF_FILE;
410
411 for (m_pos.set_at(&m_next_pos);
412 has_more_thread;
413 m_pos.next_thread())
414 {
415 pfs_thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread);
416 if (pfs_thread != NULL)
417 {
418 if (m_pos.m_index_2 >= events_stages_history_per_thread)
419 {
420 /* This thread does not have more (full) history */
421 continue;
422 }
423
424 if ( ! pfs_thread->m_stages_history_full &&
425 (m_pos.m_index_2 >= pfs_thread->m_stages_history_index))
426 {
427 /* This thread does not have more (not full) history */
428 continue;
429 }
430
431 stage= &pfs_thread->m_stages_history[m_pos.m_index_2];
432
433 if (stage->m_class != NULL)
434 {
435 make_row(stage);
436 /* Next iteration, look for the next history in this thread */
437 m_next_pos.set_after(&m_pos);
438 return 0;
439 }
440 }
441 }
442
443 return HA_ERR_END_OF_FILE;
444 }
445
rnd_pos(const void * pos)446 int table_events_stages_history::rnd_pos(const void *pos)
447 {
448 PFS_thread *pfs_thread;
449 PFS_events_stages *stage;
450
451 assert(events_stages_history_per_thread != 0);
452 set_position(pos);
453
454 assert(m_pos.m_index_2 < events_stages_history_per_thread);
455
456 pfs_thread= global_thread_container.get(m_pos.m_index_1);
457 if (pfs_thread != NULL)
458 {
459 if ( ! pfs_thread->m_stages_history_full &&
460 (m_pos.m_index_2 >= pfs_thread->m_stages_history_index))
461 return HA_ERR_RECORD_DELETED;
462
463 stage= &pfs_thread->m_stages_history[m_pos.m_index_2];
464
465 if (stage->m_class != NULL)
466 {
467 make_row(stage);
468 return 0;
469 }
470 }
471
472 return HA_ERR_RECORD_DELETED;
473 }
474
delete_all_rows(void)475 int table_events_stages_history::delete_all_rows(void)
476 {
477 reset_events_stages_history();
478 return 0;
479 }
480
481 ha_rows
get_row_count(void)482 table_events_stages_history::get_row_count(void)
483 {
484 return events_stages_history_per_thread * global_thread_container.get_row_count();
485 }
486
create(void)487 PFS_engine_table* table_events_stages_history_long::create(void)
488 {
489 return new table_events_stages_history_long();
490 }
491
table_events_stages_history_long()492 table_events_stages_history_long::table_events_stages_history_long()
493 : table_events_stages_common(&m_share, &m_pos),
494 m_pos(0), m_next_pos(0)
495 {}
496
reset_position(void)497 void table_events_stages_history_long::reset_position(void)
498 {
499 m_pos.m_index= 0;
500 m_next_pos.m_index= 0;
501 }
502
rnd_init(bool scan)503 int table_events_stages_history_long::rnd_init(bool scan)
504 {
505 m_normalizer= time_normalizer::get(stage_timer);
506 return 0;
507 }
508
rnd_next(void)509 int table_events_stages_history_long::rnd_next(void)
510 {
511 PFS_events_stages *stage;
512 uint limit;
513
514 if (events_stages_history_long_size == 0)
515 return HA_ERR_END_OF_FILE;
516
517 if (events_stages_history_long_full)
518 limit= events_stages_history_long_size;
519 else
520 limit= events_stages_history_long_index.m_u32 % events_stages_history_long_size;
521
522 for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next())
523 {
524 stage= &events_stages_history_long_array[m_pos.m_index];
525
526 if (stage->m_class != NULL)
527 {
528 make_row(stage);
529 /* Next iteration, look for the next entry */
530 m_next_pos.set_after(&m_pos);
531 return 0;
532 }
533 }
534
535 return HA_ERR_END_OF_FILE;
536 }
537
rnd_pos(const void * pos)538 int table_events_stages_history_long::rnd_pos(const void *pos)
539 {
540 PFS_events_stages *stage;
541 uint limit;
542
543 if (events_stages_history_long_size == 0)
544 return HA_ERR_RECORD_DELETED;
545
546 set_position(pos);
547
548 if (events_stages_history_long_full)
549 limit= events_stages_history_long_size;
550 else
551 limit= events_stages_history_long_index.m_u32 % events_stages_history_long_size;
552
553 if (m_pos.m_index > limit)
554 return HA_ERR_RECORD_DELETED;
555
556 stage= &events_stages_history_long_array[m_pos.m_index];
557
558 if (stage->m_class == NULL)
559 return HA_ERR_RECORD_DELETED;
560
561 make_row(stage);
562 return 0;
563 }
564
delete_all_rows(void)565 int table_events_stages_history_long::delete_all_rows(void)
566 {
567 reset_events_stages_history_long();
568 return 0;
569 }
570
571 ha_rows
get_row_count(void)572 table_events_stages_history_long::get_row_count(void)
573 {
574 return events_stages_history_long_size;
575 }
576
577