1 /* Copyright (c) 2008, 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_waits.cc
25 Table EVENTS_WAITS_xxx (implementation).
26 */
27
28 #include "my_global.h"
29 #include "my_thread.h"
30 #include "table_events_waits.h"
31 #include "pfs_global.h"
32 #include "pfs_instr_class.h"
33 #include "pfs_instr.h"
34 #include "pfs_events_waits.h"
35 #include "pfs_timer.h"
36 #include "m_string.h"
37 #include "pfs_buffer_container.h"
38 #include "field.h"
39
40 THR_LOCK table_events_waits_current::m_table_lock;
41
42 static const TABLE_FIELD_TYPE field_types[]=
43 {
44 {
45 { C_STRING_WITH_LEN("THREAD_ID") },
46 { C_STRING_WITH_LEN("bigint(20)") },
47 { NULL, 0}
48 },
49 {
50 { C_STRING_WITH_LEN("EVENT_ID") },
51 { C_STRING_WITH_LEN("bigint(20)") },
52 { NULL, 0}
53 },
54 {
55 { C_STRING_WITH_LEN("END_EVENT_ID") },
56 { C_STRING_WITH_LEN("bigint(20)") },
57 { NULL, 0}
58 },
59 {
60 { C_STRING_WITH_LEN("EVENT_NAME") },
61 { C_STRING_WITH_LEN("varchar(128)") },
62 { NULL, 0}
63 },
64 {
65 { C_STRING_WITH_LEN("SOURCE") },
66 { C_STRING_WITH_LEN("varchar(64)") },
67 { NULL, 0}
68 },
69 {
70 { C_STRING_WITH_LEN("TIMER_START") },
71 { C_STRING_WITH_LEN("bigint(20)") },
72 { NULL, 0}
73 },
74 {
75 { C_STRING_WITH_LEN("TIMER_END") },
76 { C_STRING_WITH_LEN("bigint(20)") },
77 { NULL, 0}
78 },
79 {
80 { C_STRING_WITH_LEN("TIMER_WAIT") },
81 { C_STRING_WITH_LEN("bigint(20)") },
82 { NULL, 0}
83 },
84 {
85 { C_STRING_WITH_LEN("SPINS") },
86 { C_STRING_WITH_LEN("int(10)") },
87 { NULL, 0}
88 },
89 {
90 { C_STRING_WITH_LEN("OBJECT_SCHEMA") },
91 { C_STRING_WITH_LEN("varchar(64)") },
92 { NULL, 0}
93 },
94 {
95 { C_STRING_WITH_LEN("OBJECT_NAME") },
96 { C_STRING_WITH_LEN("varchar(512)") },
97 { NULL, 0}
98 },
99 {
100 { C_STRING_WITH_LEN("INDEX_NAME") },
101 { C_STRING_WITH_LEN("varchar(64)") },
102 { NULL, 0}
103 },
104 {
105 { C_STRING_WITH_LEN("OBJECT_TYPE") },
106 { C_STRING_WITH_LEN("varchar(64)") },
107 { NULL, 0}
108 },
109 {
110 { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") },
111 { C_STRING_WITH_LEN("bigint(20)") },
112 { NULL, 0}
113 },
114 {
115 { C_STRING_WITH_LEN("NESTING_EVENT_ID") },
116 { C_STRING_WITH_LEN("bigint(20)") },
117 { NULL, 0}
118 },
119 {
120 { C_STRING_WITH_LEN("NESTING_EVENT_TYPE") },
121 { C_STRING_WITH_LEN("enum(\'TRANSACTION\',\'STATEMENT\',\'STAGE\',\'WAIT\'") },
122 { NULL, 0}
123 },
124 {
125 { C_STRING_WITH_LEN("OPERATION") },
126 { C_STRING_WITH_LEN("varchar(32)") },
127 { NULL, 0}
128 },
129 {
130 { C_STRING_WITH_LEN("NUMBER_OF_BYTES") },
131 { C_STRING_WITH_LEN("bigint(20)") },
132 { NULL, 0}
133 },
134 {
135 { C_STRING_WITH_LEN("FLAGS") },
136 { C_STRING_WITH_LEN("int(10)") },
137 { NULL, 0}
138 }
139 };
140
141 TABLE_FIELD_DEF
142 table_events_waits_current::m_field_def=
143 { 19, field_types };
144
145 PFS_engine_table_share
146 table_events_waits_current::m_share=
147 {
148 { C_STRING_WITH_LEN("events_waits_current") },
149 &pfs_truncatable_acl,
150 table_events_waits_current::create,
151 NULL, /* write_row */
152 table_events_waits_current::delete_all_rows,
153 table_events_waits_current::get_row_count,
154 sizeof(pos_events_waits_current), /* ref length */
155 &m_table_lock,
156 &m_field_def,
157 false, /* checked */
158 false /* perpetual */
159 };
160
161 THR_LOCK table_events_waits_history::m_table_lock;
162
163 PFS_engine_table_share
164 table_events_waits_history::m_share=
165 {
166 { C_STRING_WITH_LEN("events_waits_history") },
167 &pfs_truncatable_acl,
168 table_events_waits_history::create,
169 NULL, /* write_row */
170 table_events_waits_history::delete_all_rows,
171 table_events_waits_history::get_row_count,
172 sizeof(pos_events_waits_history), /* ref length */
173 &m_table_lock,
174 &table_events_waits_current::m_field_def,
175 false, /* checked */
176 false /* perpetual */
177 };
178
179 THR_LOCK table_events_waits_history_long::m_table_lock;
180
181 PFS_engine_table_share
182 table_events_waits_history_long::m_share=
183 {
184 { C_STRING_WITH_LEN("events_waits_history_long") },
185 &pfs_truncatable_acl,
186 table_events_waits_history_long::create,
187 NULL, /* write_row */
188 table_events_waits_history_long::delete_all_rows,
189 table_events_waits_history_long::get_row_count,
190 sizeof(PFS_simple_index), /* ref length */
191 &m_table_lock,
192 &table_events_waits_current::m_field_def,
193 false, /* checked */
194 false /* perpetual */
195 };
196
table_events_waits_common(const PFS_engine_table_share * share,void * pos)197 table_events_waits_common::table_events_waits_common
198 (const PFS_engine_table_share *share, void *pos)
199 : PFS_engine_table(share, pos),
200 m_row_exists(false)
201 {}
202
clear_object_columns()203 void table_events_waits_common::clear_object_columns()
204 {
205 m_row.m_object_type_length= 0;
206 m_row.m_object_schema_length= 0;
207 m_row.m_object_name_length= 0;
208 m_row.m_index_name_length= 0;
209 }
210
make_table_object_columns(PFS_events_waits * wait)211 int table_events_waits_common::make_table_object_columns(PFS_events_waits *wait)
212 {
213 uint safe_index;
214 PFS_table_share *safe_table_share;
215
216 safe_table_share= sanitize_table_share(wait->m_weak_table_share);
217 if (unlikely(safe_table_share == NULL))
218 return 1;
219
220 if (wait->m_object_type == OBJECT_TYPE_TABLE)
221 {
222 m_row.m_object_type= "TABLE";
223 m_row.m_object_type_length= 5;
224 }
225 else
226 {
227 m_row.m_object_type= "TEMPORARY TABLE";
228 m_row.m_object_type_length= 15;
229 }
230
231 if (safe_table_share->get_version() == wait->m_weak_version)
232 {
233 /* OBJECT SCHEMA */
234 m_row.m_object_schema_length= safe_table_share->m_schema_name_length;
235 if (unlikely((m_row.m_object_schema_length == 0) ||
236 (m_row.m_object_schema_length > sizeof(m_row.m_object_schema))))
237 return 1;
238 memcpy(m_row.m_object_schema, safe_table_share->m_schema_name, m_row.m_object_schema_length);
239
240 /* OBJECT NAME */
241 m_row.m_object_name_length= safe_table_share->m_table_name_length;
242 if (unlikely((m_row.m_object_name_length == 0) ||
243 (m_row.m_object_name_length > sizeof(m_row.m_object_name))))
244 return 1;
245 memcpy(m_row.m_object_name, safe_table_share->m_table_name, m_row.m_object_name_length);
246
247 /* INDEX NAME */
248 safe_index= wait->m_index;
249 uint safe_key_count= sanitize_index_count(safe_table_share->m_key_count);
250 if (safe_index < safe_key_count)
251 {
252 PFS_table_share_index *index_stat;
253 index_stat= safe_table_share->find_index_stat(safe_index);
254
255 if (index_stat != NULL)
256 {
257 m_row.m_index_name_length= index_stat->m_key.m_name_length;
258
259 if (unlikely((m_row.m_index_name_length == 0) ||
260 (m_row.m_index_name_length > sizeof(m_row.m_index_name))))
261 return 1;
262
263 memcpy(m_row.m_index_name, index_stat->m_key.m_name, m_row.m_index_name_length);
264 }
265 else
266 {
267 m_row.m_index_name_length= 0;
268 }
269 }
270 else
271 {
272 m_row.m_index_name_length= 0;
273 }
274 }
275 else
276 {
277 m_row.m_object_schema_length= 0;
278 m_row.m_object_name_length= 0;
279 m_row.m_index_name_length= 0;
280 }
281
282 m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr;
283 return 0;
284 }
285
make_file_object_columns(PFS_events_waits * wait)286 int table_events_waits_common::make_file_object_columns(PFS_events_waits *wait)
287 {
288 PFS_file *safe_file;
289
290 safe_file= sanitize_file(wait->m_weak_file);
291 if (unlikely(safe_file == NULL))
292 return 1;
293
294 m_row.m_object_type= "FILE";
295 m_row.m_object_type_length= 4;
296 m_row.m_object_schema_length= 0;
297 m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr;
298
299 if (safe_file->get_version() == wait->m_weak_version)
300 {
301 /* OBJECT NAME */
302 m_row.m_object_name_length= safe_file->m_filename_length;
303 if (unlikely((m_row.m_object_name_length == 0) ||
304 (m_row.m_object_name_length > sizeof(m_row.m_object_name))))
305 return 1;
306 memcpy(m_row.m_object_name, safe_file->m_filename, m_row.m_object_name_length);
307 }
308 else
309 {
310 m_row.m_object_name_length= 0;
311 }
312
313 m_row.m_index_name_length= 0;
314
315 return 0;
316 }
317
make_socket_object_columns(PFS_events_waits * wait)318 int table_events_waits_common::make_socket_object_columns(PFS_events_waits *wait)
319 {
320 PFS_socket *safe_socket;
321
322 safe_socket= sanitize_socket(wait->m_weak_socket);
323 if (unlikely(safe_socket == NULL))
324 return 1;
325
326 m_row.m_object_type= "SOCKET";
327 m_row.m_object_type_length= 6;
328 m_row.m_object_schema_length= 0;
329 m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr;
330
331 if (safe_socket->get_version() == wait->m_weak_version)
332 {
333 /* Convert port number to string, include delimiter in port name length */
334
335 uint port;
336 char port_str[128];
337 char ip_str[INET6_ADDRSTRLEN+1];
338 uint ip_len= 0;
339 port_str[0]= ':';
340
341 /* Get the IP address and port number */
342 ip_len= pfs_get_socket_address(ip_str, sizeof(ip_str), &port,
343 &safe_socket->m_sock_addr,
344 safe_socket->m_addr_len);
345
346 /* Convert port number to a string (length includes ':') */
347 size_t port_len= int10_to_str(port, (port_str+1), 10) - port_str + 1;
348
349 /* OBJECT NAME */
350 m_row.m_object_name_length= ip_len + port_len;
351
352 if (unlikely((m_row.m_object_name_length == 0) ||
353 (m_row.m_object_name_length > sizeof(m_row.m_object_name))))
354 return 1;
355
356 char *name= m_row.m_object_name;
357 memcpy(name, ip_str, ip_len);
358 memcpy(name + ip_len, port_str, port_len);
359 }
360 else
361 {
362 m_row.m_object_name_length= 0;
363 }
364
365 m_row.m_index_name_length= 0;
366
367 return 0;
368 }
369
make_metadata_lock_object_columns(PFS_events_waits * wait)370 int table_events_waits_common::make_metadata_lock_object_columns(PFS_events_waits *wait)
371 {
372 PFS_metadata_lock *safe_metadata_lock;
373
374 safe_metadata_lock= sanitize_metadata_lock(wait->m_weak_metadata_lock);
375 if (unlikely(safe_metadata_lock == NULL))
376 return 1;
377
378 if (safe_metadata_lock->get_version() == wait->m_weak_version)
379 {
380 MDL_key *mdl= & safe_metadata_lock->m_mdl_key;
381
382 switch(mdl->mdl_namespace())
383 {
384 case MDL_key::GLOBAL:
385 m_row.m_object_type= "GLOBAL";
386 m_row.m_object_type_length= 6;
387 m_row.m_object_schema_length= 0;
388 m_row.m_object_name_length= 0;
389 break;
390 case MDL_key::SCHEMA:
391 m_row.m_object_type= "SCHEMA";
392 m_row.m_object_type_length= 6;
393 m_row.m_object_schema_length= mdl->db_name_length();
394 m_row.m_object_name_length= 0;
395 break;
396 case MDL_key::TABLE:
397 m_row.m_object_type= "TABLE";
398 m_row.m_object_type_length= 5;
399 m_row.m_object_schema_length= mdl->db_name_length();
400 m_row.m_object_name_length= mdl->name_length();
401 break;
402 case MDL_key::FUNCTION:
403 m_row.m_object_type= "FUNCTION";
404 m_row.m_object_type_length= 8;
405 m_row.m_object_schema_length= mdl->db_name_length();
406 m_row.m_object_name_length= mdl->name_length();
407 break;
408 case MDL_key::PROCEDURE:
409 m_row.m_object_type= "PROCEDURE";
410 m_row.m_object_type_length= 9;
411 m_row.m_object_schema_length= mdl->db_name_length();
412 m_row.m_object_name_length= mdl->name_length();
413 break;
414 case MDL_key::TRIGGER:
415 m_row.m_object_type= "TRIGGER";
416 m_row.m_object_type_length= 7;
417 m_row.m_object_schema_length= mdl->db_name_length();
418 m_row.m_object_name_length= mdl->name_length();
419 break;
420 case MDL_key::EVENT:
421 m_row.m_object_type= "EVENT";
422 m_row.m_object_type_length= 5;
423 m_row.m_object_schema_length= mdl->db_name_length();
424 m_row.m_object_name_length= mdl->name_length();
425 break;
426 case MDL_key::COMMIT:
427 m_row.m_object_type= "COMMIT";
428 m_row.m_object_type_length= 6;
429 m_row.m_object_schema_length= 0;
430 m_row.m_object_name_length= 0;
431 break;
432 case MDL_key::USER_LEVEL_LOCK:
433 m_row.m_object_type= "USER LEVEL LOCK";
434 m_row.m_object_type_length= 15;
435 m_row.m_object_schema_length= 0;
436 m_row.m_object_name_length= mdl->name_length();
437 break;
438 case MDL_key::TABLESPACE:
439 m_row.m_object_type= "TABLESPACE";
440 m_row.m_object_type_length= 10;
441 m_row.m_object_schema_length= 0;
442 m_row.m_object_name_length= mdl->name_length();
443 break;
444 case MDL_key::LOCKING_SERVICE:
445 m_row.m_object_type= "LOCKING SERVICE";
446 m_row.m_object_type_length= 15;
447 m_row.m_object_schema_length= mdl->db_name_length();
448 m_row.m_object_name_length= mdl->name_length();
449 break;
450 case MDL_key::NAMESPACE_END:
451 default:
452 m_row.m_object_type_length= 0;
453 m_row.m_object_schema_length= 0;
454 m_row.m_object_name_length= 0;
455 break;
456 }
457
458 if (m_row.m_object_schema_length > sizeof(m_row.m_object_schema))
459 return 1;
460 if (m_row.m_object_schema_length > 0)
461 memcpy(m_row.m_object_schema, mdl->db_name(), m_row.m_object_schema_length);
462
463 if (m_row.m_object_name_length > sizeof(m_row.m_object_name))
464 return 1;
465 if (m_row.m_object_name_length > 0)
466 memcpy(m_row.m_object_name, mdl->name(), m_row.m_object_name_length);
467
468 m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr;
469 }
470 else
471 {
472 m_row.m_object_type_length= 0;
473 m_row.m_object_schema_length= 0;
474 m_row.m_object_name_length= 0;
475 m_row.m_object_instance_addr= 0;
476 }
477
478 /* INDEX NAME */
479 m_row.m_index_name_length= 0;
480
481 return 0;
482 }
483
484 /**
485 Build a row.
486 @param wait the wait the cursor is reading
487 */
make_row(PFS_events_waits * wait)488 void table_events_waits_common::make_row(PFS_events_waits *wait)
489 {
490 PFS_instr_class *safe_class;
491 enum_timer_name timer_name= wait_timer;
492 ulonglong timer_end;
493
494 m_row_exists= false;
495
496 /*
497 Design choice:
498 We could have used a pfs_lock in PFS_events_waits here,
499 to protect the reader from concurrent event generation,
500 but this leads to too many pfs_lock atomic operations
501 each time an event is recorded:
502 - 1 dirty() + 1 allocated() per event start, for EVENTS_WAITS_CURRENT
503 - 1 dirty() + 1 allocated() per event end, for EVENTS_WAITS_CURRENT
504 - 1 dirty() + 1 allocated() per copy to EVENTS_WAITS_HISTORY
505 - 1 dirty() + 1 allocated() per copy to EVENTS_WAITS_HISTORY_LONG
506 or 8 atomics per recorded event.
507 The problem is that we record a *lot* of events ...
508
509 This code is prepared to accept *dirty* records,
510 and sanitizes all the data before returning a row.
511 */
512
513 /*
514 PFS_events_waits::m_class needs to be sanitized,
515 for race conditions when this code:
516 - reads a new value in m_wait_class,
517 - reads an old value in m_class.
518 */
519 switch (wait->m_wait_class)
520 {
521 case WAIT_CLASS_METADATA:
522 if (make_metadata_lock_object_columns(wait))
523 return;
524 safe_class= sanitize_metadata_class(wait->m_class);
525 break;
526 case WAIT_CLASS_IDLE:
527 clear_object_columns();
528 m_row.m_object_instance_addr= 0;
529 safe_class= sanitize_idle_class(wait->m_class);
530 timer_name= idle_timer;
531 break;
532 case WAIT_CLASS_MUTEX:
533 clear_object_columns();
534 m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr;
535 safe_class= sanitize_mutex_class((PFS_mutex_class*) wait->m_class);
536 break;
537 case WAIT_CLASS_RWLOCK:
538 clear_object_columns();
539 m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr;
540 safe_class= sanitize_rwlock_class((PFS_rwlock_class*) wait->m_class);
541 break;
542 case WAIT_CLASS_COND:
543 clear_object_columns();
544 m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr;
545 safe_class= sanitize_cond_class((PFS_cond_class*) wait->m_class);
546 break;
547 case WAIT_CLASS_TABLE:
548 if (make_table_object_columns(wait))
549 return;
550 safe_class= sanitize_table_class(wait->m_class);
551 break;
552 case WAIT_CLASS_FILE:
553 if (make_file_object_columns(wait))
554 return;
555 safe_class= sanitize_file_class((PFS_file_class*) wait->m_class);
556 break;
557 case WAIT_CLASS_SOCKET:
558 if (make_socket_object_columns(wait))
559 return;
560 safe_class= sanitize_socket_class((PFS_socket_class*) wait->m_class);
561 break;
562 case NO_WAIT_CLASS:
563 default:
564 return;
565 }
566
567 if (unlikely(safe_class == NULL))
568 return;
569
570 m_row.m_thread_internal_id= wait->m_thread_internal_id;
571 m_row.m_event_id= wait->m_event_id;
572 m_row.m_end_event_id= wait->m_end_event_id;
573 m_row.m_nesting_event_id= wait->m_nesting_event_id;
574 m_row.m_nesting_event_type= wait->m_nesting_event_type;
575
576 get_normalizer(safe_class);
577
578 if (m_row.m_end_event_id == 0)
579 {
580 timer_end= get_timer_raw_value(timer_name);
581 }
582 else
583 {
584 timer_end= wait->m_timer_end;
585 }
586
587 m_normalizer->to_pico(wait->m_timer_start, timer_end,
588 & m_row.m_timer_start, & m_row.m_timer_end, & m_row.m_timer_wait);
589
590 m_row.m_name= safe_class->m_name;
591 m_row.m_name_length= safe_class->m_name_length;
592
593 /* Disable source file and line to avoid stale __FILE__ pointers. */
594 m_row.m_source_length= 0;
595
596 m_row.m_operation= wait->m_operation;
597 m_row.m_number_of_bytes= wait->m_number_of_bytes;
598 m_row.m_flags= wait->m_flags;
599
600 m_row_exists= true;
601 }
602
603 /**
604 Operations names map, as displayed in the 'OPERATION' column.
605 Indexed by enum_operation_type - 1.
606 Note: enum_operation_type contains a more precise definition,
607 since more details are needed internally by the instrumentation.
608 Different similar operations (CLOSE vs STREAMCLOSE) are displayed
609 with the same name 'close'.
610 */
611 static const LEX_STRING operation_names_map[]=
612 {
613 /* Mutex operations */
614 { C_STRING_WITH_LEN("lock") },
615 { C_STRING_WITH_LEN("try_lock") },
616
617 /* RWLock operations (RW-lock) */
618 { C_STRING_WITH_LEN("read_lock") },
619 { C_STRING_WITH_LEN("write_lock") },
620 { C_STRING_WITH_LEN("try_read_lock") },
621 { C_STRING_WITH_LEN("try_write_lock") },
622
623 /* RWLock operations (SX-lock) */
624 { C_STRING_WITH_LEN("shared_lock") },
625 { C_STRING_WITH_LEN("shared_exclusive_lock") },
626 { C_STRING_WITH_LEN("exclusive_lock") },
627 { C_STRING_WITH_LEN("try_shared_lock") },
628 { C_STRING_WITH_LEN("try_shared_exclusive_lock") },
629 { C_STRING_WITH_LEN("try_exclusive_lock") },
630
631 /* Condition operations */
632 { C_STRING_WITH_LEN("wait") },
633 { C_STRING_WITH_LEN("timed_wait") },
634
635 /* File operations */
636 { C_STRING_WITH_LEN("create") },
637 { C_STRING_WITH_LEN("create") }, /* create tmp */
638 { C_STRING_WITH_LEN("open") },
639 { C_STRING_WITH_LEN("open") }, /* stream open */
640 { C_STRING_WITH_LEN("close") },
641 { C_STRING_WITH_LEN("close") }, /* stream close */
642 { C_STRING_WITH_LEN("read") },
643 { C_STRING_WITH_LEN("write") },
644 { C_STRING_WITH_LEN("seek") },
645 { C_STRING_WITH_LEN("tell") },
646 { C_STRING_WITH_LEN("flush") },
647 { C_STRING_WITH_LEN("stat") },
648 { C_STRING_WITH_LEN("stat") }, /* fstat */
649 { C_STRING_WITH_LEN("chsize") },
650 { C_STRING_WITH_LEN("delete") },
651 { C_STRING_WITH_LEN("rename") },
652 { C_STRING_WITH_LEN("sync") },
653
654 /* Table io operations */
655 { C_STRING_WITH_LEN("fetch") },
656 { C_STRING_WITH_LEN("insert") }, /* write row */
657 { C_STRING_WITH_LEN("update") }, /* update row */
658 { C_STRING_WITH_LEN("delete") }, /* delete row */
659
660 /* Table lock operations */
661 { C_STRING_WITH_LEN("read normal") },
662 { C_STRING_WITH_LEN("read with shared locks") },
663 { C_STRING_WITH_LEN("read high priority") },
664 { C_STRING_WITH_LEN("read no inserts") },
665 { C_STRING_WITH_LEN("write allow write") },
666 { C_STRING_WITH_LEN("write concurrent insert") },
667 { C_STRING_WITH_LEN("write low priority") },
668 { C_STRING_WITH_LEN("write normal") },
669 { C_STRING_WITH_LEN("read external") },
670 { C_STRING_WITH_LEN("write external") },
671
672 /* Socket operations */
673 { C_STRING_WITH_LEN("create") },
674 { C_STRING_WITH_LEN("connect") },
675 { C_STRING_WITH_LEN("bind") },
676 { C_STRING_WITH_LEN("close") },
677 { C_STRING_WITH_LEN("send") },
678 { C_STRING_WITH_LEN("recv") },
679 { C_STRING_WITH_LEN("sendto") },
680 { C_STRING_WITH_LEN("recvfrom") },
681 { C_STRING_WITH_LEN("sendmsg") },
682 { C_STRING_WITH_LEN("recvmsg") },
683 { C_STRING_WITH_LEN("seek") },
684 { C_STRING_WITH_LEN("opt") },
685 { C_STRING_WITH_LEN("stat") },
686 { C_STRING_WITH_LEN("shutdown") },
687 { C_STRING_WITH_LEN("select") },
688
689 /* Idle operations */
690 { C_STRING_WITH_LEN("idle") },
691
692 /* Medatada lock operations */
693 { C_STRING_WITH_LEN("metadata lock") }
694 };
695
696
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)697 int table_events_waits_common::read_row_values(TABLE *table,
698 unsigned char *buf,
699 Field **fields,
700 bool read_all)
701 {
702 Field *f;
703 const LEX_STRING *operation;
704
705 compile_time_assert(COUNT_OPERATION_TYPE ==
706 array_elements(operation_names_map));
707
708 if (unlikely(! m_row_exists))
709 return HA_ERR_RECORD_DELETED;
710
711 /* Set the null bits */
712 assert(table->s->null_bytes == 2);
713 buf[0]= 0;
714 buf[1]= 0;
715
716 /*
717 Some columns are unreliable, because they are joined with other buffers,
718 which could have changed and been reused for something else.
719 These columns are:
720 - THREAD_ID (m_thread joins with PFS_thread),
721 - SCHEMA_NAME (m_schema_name joins with PFS_table_share)
722 - OBJECT_NAME (m_object_name joins with PFS_table_share)
723 */
724 for (; (f= *fields) ; fields++)
725 {
726 if (read_all || bitmap_is_set(table->read_set, f->field_index))
727 {
728 switch(f->field_index)
729 {
730 case 0: /* THREAD_ID */
731 set_field_ulonglong(f, m_row.m_thread_internal_id);
732 break;
733 case 1: /* EVENT_ID */
734 set_field_ulonglong(f, m_row.m_event_id);
735 break;
736 case 2: /* END_EVENT_ID */
737 if (m_row.m_end_event_id > 0)
738 set_field_ulonglong(f, m_row.m_end_event_id - 1);
739 else
740 f->set_null();
741 break;
742 case 3: /* EVENT_NAME */
743 set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
744 break;
745 case 4: /* SOURCE */
746 set_field_varchar_utf8(f, m_row.m_source, m_row.m_source_length);
747 break;
748 case 5: /* TIMER_START */
749 if (m_row.m_timer_start != 0)
750 set_field_ulonglong(f, m_row.m_timer_start);
751 else
752 f->set_null();
753 break;
754 case 6: /* TIMER_END */
755 if (m_row.m_timer_end != 0)
756 set_field_ulonglong(f, m_row.m_timer_end);
757 else
758 f->set_null();
759 break;
760 case 7: /* TIMER_WAIT */
761 if (m_row.m_timer_wait != 0)
762 set_field_ulonglong(f, m_row.m_timer_wait);
763 else
764 f->set_null();
765 break;
766 case 8: /* SPINS */
767 f->set_null();
768 break;
769 case 9: /* OBJECT_SCHEMA */
770 if (m_row.m_object_schema_length > 0)
771 {
772 set_field_varchar_utf8(f, m_row.m_object_schema,
773 m_row.m_object_schema_length);
774 }
775 else
776 f->set_null();
777 break;
778 case 10: /* OBJECT_NAME */
779 if (m_row.m_object_name_length > 0)
780 {
781 set_field_varchar_utf8(f, m_row.m_object_name,
782 m_row.m_object_name_length);
783 }
784 else
785 f->set_null();
786 break;
787 case 11: /* INDEX_NAME */
788 if (m_row.m_index_name_length > 0)
789 {
790 set_field_varchar_utf8(f, m_row.m_index_name,
791 m_row.m_index_name_length);
792 }
793 else
794 f->set_null();
795 break;
796 case 12: /* OBJECT_TYPE */
797 if (m_row.m_object_type_length > 0)
798 {
799 set_field_varchar_utf8(f, m_row.m_object_type,
800 m_row.m_object_type_length);
801 }
802 else
803 f->set_null();
804 break;
805 case 13: /* OBJECT_INSTANCE */
806 set_field_ulonglong(f, m_row.m_object_instance_addr);
807 break;
808 case 14: /* NESTING_EVENT_ID */
809 if (m_row.m_nesting_event_id != 0)
810 set_field_ulonglong(f, m_row.m_nesting_event_id);
811 else
812 f->set_null();
813 break;
814 case 15: /* NESTING_EVENT_TYPE */
815 if (m_row.m_nesting_event_id != 0)
816 set_field_enum(f, m_row.m_nesting_event_type);
817 else
818 f->set_null();
819 break;
820 case 16: /* OPERATION */
821 operation= &operation_names_map[(int) m_row.m_operation - 1];
822 set_field_varchar_utf8(f, operation->str, operation->length);
823 break;
824 case 17: /* NUMBER_OF_BYTES (also used for ROWS) */
825 if ((m_row.m_operation == OPERATION_TYPE_FILEREAD) ||
826 (m_row.m_operation == OPERATION_TYPE_FILEWRITE) ||
827 (m_row.m_operation == OPERATION_TYPE_FILECHSIZE) ||
828 (m_row.m_operation == OPERATION_TYPE_SOCKETSEND) ||
829 (m_row.m_operation == OPERATION_TYPE_SOCKETRECV) ||
830 (m_row.m_operation == OPERATION_TYPE_SOCKETSENDTO) ||
831 (m_row.m_operation == OPERATION_TYPE_SOCKETRECVFROM) ||
832 (m_row.m_operation == OPERATION_TYPE_TABLE_FETCH) ||
833 (m_row.m_operation == OPERATION_TYPE_TABLE_WRITE_ROW) ||
834 (m_row.m_operation == OPERATION_TYPE_TABLE_UPDATE_ROW) ||
835 (m_row.m_operation == OPERATION_TYPE_TABLE_DELETE_ROW))
836 set_field_ulonglong(f, m_row.m_number_of_bytes);
837 else
838 f->set_null();
839 break;
840 case 18: /* FLAGS */
841 f->set_null();
842 break;
843 default:
844 assert(false);
845 }
846 }
847 }
848 return 0;
849 }
850
create(void)851 PFS_engine_table* table_events_waits_current::create(void)
852 {
853 return new table_events_waits_current();
854 }
855
table_events_waits_current()856 table_events_waits_current::table_events_waits_current()
857 : table_events_waits_common(&m_share, &m_pos),
858 m_pos(), m_next_pos()
859 {}
860
reset_position(void)861 void table_events_waits_current::reset_position(void)
862 {
863 m_pos.reset();
864 m_next_pos.reset();
865 }
866
rnd_next(void)867 int table_events_waits_current::rnd_next(void)
868 {
869 PFS_thread *pfs_thread;
870 PFS_events_waits *wait;
871 bool has_more_thread= true;
872
873 for (m_pos.set_at(&m_next_pos);
874 has_more_thread;
875 m_pos.next_thread())
876 {
877 pfs_thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread);
878 if (pfs_thread != NULL)
879 {
880 /*
881 We do not show nested events for now,
882 this will be revised with TABLE io
883 */
884 // #define ONLY_SHOW_ONE_WAIT
885
886 #ifdef ONLY_SHOW_ONE_WAIT
887 if (m_pos.m_index_2 >= 1)
888 continue;
889 #else
890 /* m_events_waits_stack[0] is a dummy record */
891 PFS_events_waits *top_wait = &pfs_thread->m_events_waits_stack[WAIT_STACK_BOTTOM];
892 wait= &pfs_thread->m_events_waits_stack[m_pos.m_index_2 + WAIT_STACK_BOTTOM];
893
894 PFS_events_waits *safe_current = pfs_thread->m_events_waits_current;
895
896 if (safe_current == top_wait)
897 {
898 /* Display the last top level wait, when completed */
899 if (m_pos.m_index_2 >= 1)
900 continue;
901 }
902 else
903 {
904 /* Display all pending waits, when in progress */
905 if (wait >= safe_current)
906 continue;
907 }
908 #endif
909
910 if (wait->m_wait_class == NO_WAIT_CLASS)
911 {
912 /*
913 This locker does not exist.
914 There can not be more lockers in the stack, skip to the next thread
915 */
916 continue;
917 }
918
919 make_row(pfs_thread, wait);
920 /* Next iteration, look for the next locker in this thread */
921 m_next_pos.set_after(&m_pos);
922 return 0;
923 }
924 }
925
926 return HA_ERR_END_OF_FILE;
927 }
928
rnd_pos(const void * pos)929 int table_events_waits_current::rnd_pos(const void *pos)
930 {
931 PFS_thread *pfs_thread;
932 PFS_events_waits *wait;
933
934 set_position(pos);
935
936 pfs_thread= global_thread_container.get(m_pos.m_index_1);
937 if (pfs_thread != NULL)
938 {
939 #ifdef ONLY_SHOW_ONE_WAIT
940 if (m_pos.m_index_2 >= 1)
941 return HA_ERR_RECORD_DELETED;
942 #else
943 /* m_events_waits_stack[0] is a dummy record */
944 PFS_events_waits *top_wait = &pfs_thread->m_events_waits_stack[WAIT_STACK_BOTTOM];
945 wait= &pfs_thread->m_events_waits_stack[m_pos.m_index_2 + WAIT_STACK_BOTTOM];
946
947 PFS_events_waits *safe_current = pfs_thread->m_events_waits_current;
948
949 if (safe_current == top_wait)
950 {
951 /* Display the last top level wait, when completed */
952 if (m_pos.m_index_2 >= 1)
953 return HA_ERR_RECORD_DELETED;
954 }
955 else
956 {
957 /* Display all pending waits, when in progress */
958 if (wait >= safe_current)
959 return HA_ERR_RECORD_DELETED;
960 }
961 #endif
962
963 assert(m_pos.m_index_2 < WAIT_STACK_LOGICAL_SIZE);
964
965 if (wait->m_wait_class != NO_WAIT_CLASS)
966 {
967 make_row(pfs_thread, wait);
968 return 0;
969 }
970 }
971
972 return HA_ERR_RECORD_DELETED;
973 }
974
make_row(PFS_thread * thread,PFS_events_waits * wait)975 void table_events_waits_current::make_row(PFS_thread *thread, PFS_events_waits *wait)
976 {
977 pfs_optimistic_state lock;
978
979 /* Protect this reader against a thread termination */
980 thread->m_lock.begin_optimistic_lock(&lock);
981
982 table_events_waits_common::make_row(wait);
983
984 if (! thread->m_lock.end_optimistic_lock(&lock))
985 m_row_exists= false;
986 }
987
delete_all_rows(void)988 int table_events_waits_current::delete_all_rows(void)
989 {
990 reset_events_waits_current();
991 return 0;
992 }
993
994 ha_rows
get_row_count(void)995 table_events_waits_current::get_row_count(void)
996 {
997 return WAIT_STACK_SIZE * global_thread_container.get_row_count();
998 }
999
create(void)1000 PFS_engine_table* table_events_waits_history::create(void)
1001 {
1002 return new table_events_waits_history();
1003 }
1004
table_events_waits_history()1005 table_events_waits_history::table_events_waits_history()
1006 : table_events_waits_common(&m_share, &m_pos),
1007 m_pos(), m_next_pos()
1008 {}
1009
reset_position(void)1010 void table_events_waits_history::reset_position(void)
1011 {
1012 m_pos.reset();
1013 m_next_pos.reset();
1014 }
1015
rnd_next(void)1016 int table_events_waits_history::rnd_next(void)
1017 {
1018 PFS_thread *pfs_thread;
1019 PFS_events_waits *wait;
1020 bool has_more_thread= true;
1021
1022 if (events_waits_history_per_thread == 0)
1023 return HA_ERR_END_OF_FILE;
1024
1025 for (m_pos.set_at(&m_next_pos);
1026 has_more_thread;
1027 m_pos.next_thread())
1028 {
1029 pfs_thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread);
1030 if (pfs_thread != NULL)
1031 {
1032 if (m_pos.m_index_2 >= events_waits_history_per_thread)
1033 {
1034 /* This thread does not have more (full) history */
1035 continue;
1036 }
1037
1038 if ( ! pfs_thread->m_waits_history_full &&
1039 (m_pos.m_index_2 >= pfs_thread->m_waits_history_index))
1040 {
1041 /* This thread does not have more (not full) history */
1042 continue;
1043 }
1044
1045 wait= &pfs_thread->m_waits_history[m_pos.m_index_2];
1046 if (wait->m_wait_class != NO_WAIT_CLASS)
1047 {
1048 make_row(pfs_thread, wait);
1049 /* Next iteration, look for the next history in this thread */
1050 m_next_pos.set_after(&m_pos);
1051 return 0;
1052 }
1053 }
1054 }
1055
1056 return HA_ERR_END_OF_FILE;
1057 }
1058
rnd_pos(const void * pos)1059 int table_events_waits_history::rnd_pos(const void *pos)
1060 {
1061 PFS_thread *pfs_thread;
1062 PFS_events_waits *wait;
1063
1064 assert(events_waits_history_per_thread != 0);
1065 set_position(pos);
1066
1067 pfs_thread= global_thread_container.get(m_pos.m_index_1);
1068 if (pfs_thread != NULL)
1069 {
1070 assert(m_pos.m_index_2 < events_waits_history_per_thread);
1071
1072 if ( ! pfs_thread->m_waits_history_full &&
1073 (m_pos.m_index_2 >= pfs_thread->m_waits_history_index))
1074 return HA_ERR_RECORD_DELETED;
1075
1076 wait= &pfs_thread->m_waits_history[m_pos.m_index_2];
1077
1078 if (wait->m_wait_class != NO_WAIT_CLASS)
1079 {
1080 make_row(pfs_thread, wait);
1081 return 0;
1082 }
1083 }
1084
1085 return HA_ERR_RECORD_DELETED;
1086 }
1087
make_row(PFS_thread * thread,PFS_events_waits * wait)1088 void table_events_waits_history::make_row(PFS_thread *thread, PFS_events_waits *wait)
1089 {
1090 pfs_optimistic_state lock;
1091
1092 /* Protect this reader against a thread termination */
1093 thread->m_lock.begin_optimistic_lock(&lock);
1094
1095 table_events_waits_common::make_row(wait);
1096
1097 if (! thread->m_lock.end_optimistic_lock(&lock))
1098 m_row_exists= false;
1099 }
1100
delete_all_rows(void)1101 int table_events_waits_history::delete_all_rows(void)
1102 {
1103 reset_events_waits_history();
1104 return 0;
1105 }
1106
1107 ha_rows
get_row_count(void)1108 table_events_waits_history::get_row_count(void)
1109 {
1110 return events_waits_history_per_thread * global_thread_container.get_row_count();
1111 }
1112
create(void)1113 PFS_engine_table* table_events_waits_history_long::create(void)
1114 {
1115 return new table_events_waits_history_long();
1116 }
1117
table_events_waits_history_long()1118 table_events_waits_history_long::table_events_waits_history_long()
1119 : table_events_waits_common(&m_share, &m_pos),
1120 m_pos(0), m_next_pos(0)
1121 {}
1122
reset_position(void)1123 void table_events_waits_history_long::reset_position(void)
1124 {
1125 m_pos.m_index= 0;
1126 m_next_pos.m_index= 0;
1127 }
1128
rnd_next(void)1129 int table_events_waits_history_long::rnd_next(void)
1130 {
1131 PFS_events_waits *wait;
1132 uint limit;
1133
1134 if (events_waits_history_long_size == 0)
1135 return HA_ERR_END_OF_FILE;
1136
1137 if (events_waits_history_long_full)
1138 limit= events_waits_history_long_size;
1139 else
1140 limit= events_waits_history_long_index.m_u32 % events_waits_history_long_size;
1141
1142 for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next())
1143 {
1144 wait= &events_waits_history_long_array[m_pos.m_index];
1145
1146 if (wait->m_wait_class != NO_WAIT_CLASS)
1147 {
1148 make_row(wait);
1149 /* Next iteration, look for the next entry */
1150 m_next_pos.set_after(&m_pos);
1151 return 0;
1152 }
1153 }
1154
1155 return HA_ERR_END_OF_FILE;
1156 }
1157
rnd_pos(const void * pos)1158 int table_events_waits_history_long::rnd_pos(const void *pos)
1159 {
1160 PFS_events_waits *wait;
1161 uint limit;
1162
1163 if (events_waits_history_long_size == 0)
1164 return HA_ERR_RECORD_DELETED;
1165
1166 set_position(pos);
1167
1168 if (events_waits_history_long_full)
1169 limit= events_waits_history_long_size;
1170 else
1171 limit= events_waits_history_long_index.m_u32 % events_waits_history_long_size;
1172
1173 if (m_pos.m_index >= limit)
1174 return HA_ERR_RECORD_DELETED;
1175
1176 wait= &events_waits_history_long_array[m_pos.m_index];
1177
1178 if (wait->m_wait_class == NO_WAIT_CLASS)
1179 return HA_ERR_RECORD_DELETED;
1180
1181 make_row(wait);
1182 return 0;
1183 }
1184
delete_all_rows(void)1185 int table_events_waits_history_long::delete_all_rows(void)
1186 {
1187 reset_events_waits_history_long();
1188 return 0;
1189 }
1190
1191 ha_rows
get_row_count(void)1192 table_events_waits_history_long::get_row_count(void)
1193 {
1194 return events_waits_history_long_size;
1195 }
1196
1197