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