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