1 /* Copyright (c) 2008, 2021, Oracle and/or its affiliates.
2 Copyright (c) 2020, MariaDB Corporation.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation,
22 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
23
24 /**
25 @file storage/perfschema/pfs_instr_class.cc
26 Performance schema instruments meta data (implementation).
27 */
28
29 #include "my_global.h"
30 #include "my_sys.h"
31 #include "table.h"
32 #include "pfs_instr_class.h"
33 #include "pfs_builtin_memory.h"
34 #include "pfs_instr.h"
35 #include "pfs_global.h"
36 #include "pfs_timer.h"
37 #include "pfs_events_waits.h"
38 #include "pfs_setup_object.h"
39 #include "pfs_atomic.h"
40 #include "pfs_program.h"
41 #include "pfs_buffer_container.h"
42 #include "mysql/psi/mysql_thread.h"
43 #include "lf.h"
44
45 #include <string.h>
46
47 /**
48 @defgroup Performance_schema_buffers Performance Schema Buffers
49 @ingroup Performance_schema_implementation
50 @{
51 */
52
53 /**
54 Global performance schema flag.
55 Indicate if the performance schema is enabled.
56 This flag is set at startup, and never changes.
57 */
58 my_bool pfs_enabled= TRUE;
59
60 /**
61 PFS_INSTRUMENT option settings array
62 */
63 Pfs_instr_config_array *pfs_instr_config_array= NULL;
64
65 static void configure_instr_class(PFS_instr_class *entry);
66
67 static void init_instr_class(PFS_instr_class *klass,
68 const char *name,
69 uint name_length,
70 int flags,
71 PFS_class_type class_type);
72
73 /**
74 Current number of elements in mutex_class_array.
75 This global variable is written to during:
76 - the performance schema initialization
77 - a plugin initialization
78 */
79 static uint32 mutex_class_dirty_count= 0;
80 static uint32 mutex_class_allocated_count= 0;
81 static uint32 rwlock_class_dirty_count= 0;
82 static uint32 rwlock_class_allocated_count= 0;
83 static uint32 cond_class_dirty_count= 0;
84 static uint32 cond_class_allocated_count= 0;
85
86 /** Size of the mutex class array. @sa mutex_class_array */
87 ulong mutex_class_max= 0;
88 /** Number of mutex class lost. @sa mutex_class_array */
89 ulong mutex_class_lost= 0;
90 /** Size of the rwlock class array. @sa rwlock_class_array */
91 ulong rwlock_class_max= 0;
92 /** Number of rwlock class lost. @sa rwlock_class_array */
93 ulong rwlock_class_lost= 0;
94 /** Size of the condition class array. @sa cond_class_array */
95 ulong cond_class_max= 0;
96 /** Number of condition class lost. @sa cond_class_array */
97 ulong cond_class_lost= 0;
98 /** Size of the thread class array. @sa thread_class_array */
99 ulong thread_class_max= 0;
100 /** Number of thread class lost. @sa thread_class_array */
101 ulong thread_class_lost= 0;
102 /** Size of the file class array. @sa file_class_array */
103 ulong file_class_max= 0;
104 /** Number of file class lost. @sa file_class_array */
105 ulong file_class_lost= 0;
106 /** Size of the stage class array. @sa stage_class_array */
107 ulong stage_class_max= 0;
108 /** Number of stage class lost. @sa stage_class_array */
109 ulong stage_class_lost= 0;
110 /** Size of the statement class array. @sa statement_class_array */
111 ulong statement_class_max= 0;
112 /** Number of statement class lost. @sa statement_class_array */
113 ulong statement_class_lost= 0;
114 /** Size of the socket class array. @sa socket_class_array */
115 ulong socket_class_max= 0;
116 /** Number of socket class lost. @sa socket_class_array */
117 ulong socket_class_lost= 0;
118 /** Size of the memory class array. @sa memory_class_array */
119 ulong memory_class_max= 0;
120 /** Number of memory class lost. @sa memory_class_array */
121 ulong memory_class_lost= 0;
122
123 /**
124 Number of transaction classes. Although there is only one transaction class,
125 this is used for sizing by other event classes.
126 @sa global_transaction_class
127 */
128 ulong transaction_class_max= 0;
129
130 PFS_mutex_class *mutex_class_array= NULL;
131 PFS_rwlock_class *rwlock_class_array= NULL;
132 PFS_cond_class *cond_class_array= NULL;
133
134 /**
135 Current number or elements in thread_class_array.
136 This global variable is written to during:
137 - the performance schema initialization
138 - a plugin initialization
139 */
140 static uint32 thread_class_dirty_count= 0;
141 static uint32 thread_class_allocated_count= 0;
142
143 static PFS_thread_class *thread_class_array= NULL;
144
145 PFS_ALIGNED PFS_single_stat global_idle_stat;
146 PFS_ALIGNED PFS_table_io_stat global_table_io_stat;
147 PFS_ALIGNED PFS_table_lock_stat global_table_lock_stat;
148 PFS_ALIGNED PFS_single_stat global_metadata_stat;
149 PFS_ALIGNED PFS_transaction_stat global_transaction_stat;
150 PFS_ALIGNED PFS_instr_class global_table_io_class;
151 PFS_ALIGNED PFS_instr_class global_table_lock_class;
152 PFS_ALIGNED PFS_instr_class global_idle_class;
153 PFS_ALIGNED PFS_instr_class global_metadata_class;
154 PFS_ALIGNED PFS_transaction_class global_transaction_class;
155
156 /** Class-timer map */
157 enum_timer_name *class_timers[] =
158 {&wait_timer, /* PFS_CLASS_NONE */
159 &wait_timer, /* PFS_CLASS_MUTEX */
160 &wait_timer, /* PFS_CLASS_RWLOCK */
161 &wait_timer, /* PFS_CLASS_COND */
162 &wait_timer, /* PFS_CLASS_FILE */
163 &wait_timer, /* PFS_CLASS_TABLE */
164 &stage_timer, /* PFS_CLASS_STAGE */
165 &statement_timer, /* PFS_CLASS_STATEMENT */
166 &transaction_timer, /* PFS_CLASS_TRANSACTION */
167 &wait_timer, /* PFS_CLASS_SOCKET */
168 &wait_timer, /* PFS_CLASS_TABLE_IO */
169 &wait_timer, /* PFS_CLASS_TABLE_LOCK */
170 &idle_timer, /* PFS_CLASS_IDLE */
171 &wait_timer, /* PFS_CLASS_METADATA */
172 &wait_timer /* PFS_CLASS_MEMORY */
173 };
174
175 /**
176 Hash index for instrumented table shares.
177 This index is searched by table fully qualified name (@c PFS_table_share_key),
178 and points to instrumented table shares (@c PFS_table_share).
179 @sa PFS_table_share_key
180 @sa PFS_table_share
181 @sa table_share_hash_get_key
182 @sa get_table_share_hash_pins
183 */
184 LF_HASH table_share_hash;
185 /** True if table_share_hash is initialized. */
186 static bool table_share_hash_inited= false;
187
188 static uint32 file_class_dirty_count= 0;
189 static uint32 file_class_allocated_count= 0;
190
191 PFS_file_class *file_class_array= NULL;
192
193 static uint32 stage_class_dirty_count= 0;
194 static uint32 stage_class_allocated_count= 0;
195
196 static PFS_stage_class *stage_class_array= NULL;
197
198 static uint32 statement_class_dirty_count= 0;
199 static uint32 statement_class_allocated_count= 0;
200
201 static PFS_statement_class *statement_class_array= NULL;
202
203 static uint32 socket_class_dirty_count= 0;
204 static uint32 socket_class_allocated_count= 0;
205
206 static PFS_socket_class *socket_class_array= NULL;
207
208 static uint32 memory_class_dirty_count= 0;
209 static uint32 memory_class_allocated_count= 0;
210
211 static PFS_memory_class *memory_class_array= NULL;
212
213 uint mutex_class_start= 0;
214 uint rwlock_class_start= 0;
215 uint cond_class_start= 0;
216 uint file_class_start= 0;
217 uint wait_class_max= 0;
218 uint socket_class_start= 0;
219
init_event_name_sizing(const PFS_global_param * param)220 void init_event_name_sizing(const PFS_global_param *param)
221 {
222 /* global table io, table lock, idle, metadata */
223 mutex_class_start= COUNT_GLOBAL_EVENT_INDEX;
224 rwlock_class_start= mutex_class_start + param->m_mutex_class_sizing;
225 cond_class_start= rwlock_class_start + param->m_rwlock_class_sizing;
226 file_class_start= cond_class_start + param->m_cond_class_sizing;
227 socket_class_start= file_class_start + param->m_file_class_sizing;
228 wait_class_max= socket_class_start + param->m_socket_class_sizing;
229 }
230
register_global_classes()231 void register_global_classes()
232 {
233 /* Table IO class */
234 init_instr_class(&global_table_io_class, "wait/io/table/sql/handler", 25,
235 0, PFS_CLASS_TABLE_IO);
236 global_table_io_class.m_event_name_index= GLOBAL_TABLE_IO_EVENT_INDEX;
237 configure_instr_class(&global_table_io_class);
238
239 /* Table lock class */
240 init_instr_class(&global_table_lock_class, "wait/lock/table/sql/handler", 27,
241 0, PFS_CLASS_TABLE_LOCK);
242 global_table_lock_class.m_event_name_index= GLOBAL_TABLE_LOCK_EVENT_INDEX;
243 configure_instr_class(&global_table_lock_class);
244
245 /* Idle class */
246 init_instr_class(&global_idle_class, "idle", 4,
247 0, PFS_CLASS_IDLE);
248 global_idle_class.m_event_name_index= GLOBAL_IDLE_EVENT_INDEX;
249 configure_instr_class(&global_idle_class);
250
251 /* Metadata class */
252 init_instr_class(&global_metadata_class, "wait/lock/metadata/sql/mdl", 26,
253 0, PFS_CLASS_METADATA);
254 global_metadata_class.m_event_name_index= GLOBAL_METADATA_EVENT_INDEX;
255 global_metadata_class.m_enabled= false; /* Disabled by default */
256 global_metadata_class.m_timed= false;
257 configure_instr_class(&global_metadata_class);
258
259 /* Transaction class */
260 init_instr_class(&global_transaction_class, "transaction", 11,
261 0, PFS_CLASS_TRANSACTION);
262 global_transaction_class.m_event_name_index= GLOBAL_TRANSACTION_INDEX;
263 global_transaction_class.m_enabled= false; /* Disabled by default */
264 global_transaction_class.m_timed= false;
265 configure_instr_class(&global_transaction_class);
266 transaction_class_max= 1; /* used for sizing by other event classes */
267 }
268
269 /**
270 Initialize the instrument synch class buffers.
271 @param mutex_class_sizing max number of mutex class
272 @param rwlock_class_sizing max number of rwlock class
273 @param cond_class_sizing max number of condition class
274 @return 0 on success
275 */
init_sync_class(uint mutex_class_sizing,uint rwlock_class_sizing,uint cond_class_sizing)276 int init_sync_class(uint mutex_class_sizing,
277 uint rwlock_class_sizing,
278 uint cond_class_sizing)
279 {
280 mutex_class_dirty_count= mutex_class_allocated_count= 0;
281 rwlock_class_dirty_count= rwlock_class_allocated_count= 0;
282 cond_class_dirty_count= cond_class_allocated_count= 0;
283 mutex_class_max= mutex_class_sizing;
284 rwlock_class_max= rwlock_class_sizing;
285 cond_class_max= cond_class_sizing;
286 mutex_class_lost= rwlock_class_lost= cond_class_lost= 0;
287
288 mutex_class_array= NULL;
289 rwlock_class_array= NULL;
290 cond_class_array= NULL;
291
292 if (mutex_class_max > 0)
293 {
294 mutex_class_array= PFS_MALLOC_ARRAY(& builtin_memory_mutex_class,
295 mutex_class_max,
296 sizeof(PFS_mutex_class), PFS_mutex_class,
297 MYF(MY_ZEROFILL));
298 if (unlikely(mutex_class_array == NULL))
299 return 1;
300 }
301
302 if (rwlock_class_max > 0)
303 {
304 rwlock_class_array= PFS_MALLOC_ARRAY(& builtin_memory_rwlock_class,
305 rwlock_class_max,
306 sizeof(PFS_rwlock_class), PFS_rwlock_class,
307 MYF(MY_ZEROFILL));
308 if (unlikely(rwlock_class_array == NULL))
309 return 1;
310 }
311
312 if (cond_class_max > 0)
313 {
314 cond_class_array= PFS_MALLOC_ARRAY(& builtin_memory_cond_class,
315 cond_class_max,
316 sizeof(PFS_cond_class), PFS_cond_class,
317 MYF(MY_ZEROFILL));
318 if (unlikely(cond_class_array == NULL))
319 return 1;
320 }
321
322 return 0;
323 }
324
325 /** Cleanup the instrument synch class buffers. */
cleanup_sync_class(void)326 void cleanup_sync_class(void)
327 {
328 PFS_FREE_ARRAY(& builtin_memory_mutex_class,
329 mutex_class_max, sizeof(PFS_mutex_class),
330 mutex_class_array);
331 mutex_class_array= NULL;
332 mutex_class_dirty_count= mutex_class_allocated_count= mutex_class_max= 0;
333
334 PFS_FREE_ARRAY(& builtin_memory_rwlock_class,
335 rwlock_class_max, sizeof(PFS_rwlock_class),
336 rwlock_class_array);
337 rwlock_class_array= NULL;
338 rwlock_class_dirty_count= rwlock_class_allocated_count= rwlock_class_max= 0;
339
340 PFS_FREE_ARRAY(& builtin_memory_cond_class,
341 cond_class_max, sizeof(PFS_cond_class),
342 cond_class_array);
343 cond_class_array= NULL;
344 cond_class_dirty_count= cond_class_allocated_count= cond_class_max= 0;
345 }
346
347 /**
348 Initialize the thread class buffer.
349 @param thread_class_sizing max number of thread class
350 @return 0 on success
351 */
init_thread_class(uint thread_class_sizing)352 int init_thread_class(uint thread_class_sizing)
353 {
354 int result= 0;
355 thread_class_dirty_count= thread_class_allocated_count= 0;
356 thread_class_max= thread_class_sizing;
357 thread_class_lost= 0;
358
359 if (thread_class_max > 0)
360 {
361 thread_class_array= PFS_MALLOC_ARRAY(& builtin_memory_thread_class,
362 thread_class_max,
363 sizeof(PFS_thread_class), PFS_thread_class,
364 MYF(MY_ZEROFILL));
365 if (unlikely(thread_class_array == NULL))
366 result= 1;
367 }
368 else
369 thread_class_array= NULL;
370
371 return result;
372 }
373
374 /** Cleanup the thread class buffers. */
cleanup_thread_class(void)375 void cleanup_thread_class(void)
376 {
377 PFS_FREE_ARRAY(& builtin_memory_thread_class,
378 thread_class_max, sizeof(PFS_thread_class),
379 thread_class_array);
380 thread_class_array= NULL;
381 thread_class_dirty_count= thread_class_allocated_count= 0;
382 thread_class_max= 0;
383 }
384
385 /**
386 Initialize the table share buffer.
387 @param table_share_sizing max number of table share
388 @return 0 on success
389 */
init_table_share(uint table_share_sizing)390 int init_table_share(uint table_share_sizing)
391 {
392 if (global_table_share_container.init(table_share_sizing))
393 return 1;
394
395 return 0;
396 }
397
398 /** Cleanup the table share buffers. */
cleanup_table_share(void)399 void cleanup_table_share(void)
400 {
401 global_table_share_container.cleanup();
402 }
403
404 C_MODE_START
405 /** get_key function for @c table_share_hash. */
table_share_hash_get_key(const uchar * entry,size_t * length,my_bool)406 static uchar *table_share_hash_get_key(const uchar *entry, size_t *length,
407 my_bool)
408 {
409 const PFS_table_share * const *typed_entry;
410 const PFS_table_share *share;
411 const void *result;
412 typed_entry= reinterpret_cast<const PFS_table_share* const *> (entry);
413 assert(typed_entry != NULL);
414 share= *typed_entry;
415 assert(share != NULL);
416 *length= share->m_key.m_key_length;
417 result= &share->m_key.m_hash_key[0];
418 return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
419 }
420 C_MODE_END
421
422 /** Initialize the table share hash table. */
init_table_share_hash(const PFS_global_param * param)423 int init_table_share_hash(const PFS_global_param *param)
424 {
425 if ((! table_share_hash_inited) && (param->m_table_share_sizing != 0))
426 {
427 lf_hash_init(&table_share_hash, sizeof(PFS_table_share*), LF_HASH_UNIQUE,
428 0, 0, table_share_hash_get_key, &my_charset_bin);
429 table_share_hash_inited= true;
430 }
431 return 0;
432 }
433
434 /** Cleanup the table share hash table. */
cleanup_table_share_hash(void)435 void cleanup_table_share_hash(void)
436 {
437 if (table_share_hash_inited)
438 {
439 lf_hash_destroy(&table_share_hash);
440 table_share_hash_inited= false;
441 }
442 }
443
444 /**
445 Get the hash pins for @sa table_share_hash.
446 @param thread The running thread.
447 @returns The LF_HASH pins for the thread.
448 */
get_table_share_hash_pins(PFS_thread * thread)449 LF_PINS* get_table_share_hash_pins(PFS_thread *thread)
450 {
451 if (unlikely(thread->m_table_share_hash_pins == NULL))
452 {
453 if (! table_share_hash_inited)
454 return NULL;
455 thread->m_table_share_hash_pins= lf_hash_get_pins(&table_share_hash);
456 }
457 return thread->m_table_share_hash_pins;
458 }
459
460 /**
461 Set a table share hash key.
462 @param [out] key The key to populate.
463 @param temporary True for TEMPORARY TABLE.
464 @param schema_name The table schema name.
465 @param schema_name_length The table schema name length.
466 @param table_name The table name.
467 @param table_name_length The table name length.
468 */
set_table_share_key(PFS_table_share_key * key,bool temporary,const char * schema_name,size_t schema_name_length,const char * table_name,size_t table_name_length)469 static void set_table_share_key(PFS_table_share_key *key,
470 bool temporary,
471 const char *schema_name, size_t schema_name_length,
472 const char *table_name, size_t table_name_length)
473 {
474 assert(schema_name_length <= NAME_LEN);
475 assert(table_name_length <= NAME_LEN);
476 char *saved_schema_name;
477 char *saved_table_name;
478
479 char *ptr= &key->m_hash_key[0];
480 ptr[0]= (temporary ? OBJECT_TYPE_TEMPORARY_TABLE : OBJECT_TYPE_TABLE);
481 ptr++;
482 saved_schema_name= ptr;
483 memcpy(ptr, schema_name, schema_name_length);
484 ptr+= schema_name_length;
485 ptr[0]= 0;
486 ptr++;
487 saved_table_name= ptr;
488 memcpy(ptr, table_name, table_name_length);
489 ptr+= table_name_length;
490 ptr[0]= 0;
491 ptr++;
492 key->m_key_length= (uint)(ptr - &key->m_hash_key[0]);
493
494 if (lower_case_table_names)
495 {
496 my_casedn_str(files_charset_info, saved_schema_name);
497 my_casedn_str(files_charset_info, saved_table_name);
498 }
499 }
500
501 /**
502 Find an existing table share lock instrumentation.
503 @return a table share lock.
504 */
505 PFS_table_share_lock*
find_lock_stat() const506 PFS_table_share::find_lock_stat() const
507 {
508 PFS_table_share *that= const_cast<PFS_table_share*>(this);
509 void *addr= & that->m_race_lock_stat;
510 void * volatile * typed_addr= static_cast<void * volatile *>(addr);
511 void *ptr;
512
513 /* Atomic Load */
514 ptr= my_atomic_loadptr(typed_addr);
515
516 PFS_table_share_lock *pfs;
517 pfs= static_cast<PFS_table_share_lock *>(ptr);
518 return pfs;
519 }
520
521 /**
522 Find or create a table share lock instrumentation.
523 @return a table share lock, or NULL.
524 */
525 PFS_table_share_lock*
find_or_create_lock_stat()526 PFS_table_share::find_or_create_lock_stat()
527 {
528 void *addr= & this->m_race_lock_stat;
529 void * volatile * typed_addr= static_cast<void * volatile *>(addr);
530 void *ptr;
531
532 /* (1) Atomic Load */
533 ptr= my_atomic_loadptr(typed_addr);
534
535 PFS_table_share_lock *pfs;
536 if (ptr != NULL)
537 {
538 pfs= static_cast<PFS_table_share_lock *>(ptr);
539 return pfs;
540 }
541
542 /* (2) Create a lock stat */
543 pfs= create_table_share_lock_stat();
544 if (pfs == NULL)
545 return NULL;
546 pfs->m_owner= this;
547
548 void *old_ptr= NULL;
549 ptr= pfs;
550
551 /* (3) Atomic CAS */
552 if (my_atomic_casptr(typed_addr, & old_ptr, ptr))
553 {
554 /* Ok. */
555 return pfs;
556 }
557
558 /* Collision with another thread that also executed (2) and (3). */
559 release_table_share_lock_stat(pfs);
560
561 pfs= static_cast<PFS_table_share_lock *>(old_ptr);
562 return pfs;
563 }
564
565 /** Destroy a table share lock instrumentation. */
destroy_lock_stat()566 void PFS_table_share::destroy_lock_stat()
567 {
568 void *addr= & this->m_race_lock_stat;
569 void * volatile * typed_addr= static_cast<void * volatile *>(addr);
570 void *new_ptr= NULL;
571 void *old_ptr;
572
573 old_ptr= my_atomic_fasptr(typed_addr, new_ptr);
574 if (old_ptr != NULL)
575 {
576 PFS_table_share_lock *pfs;
577 pfs= static_cast<PFS_table_share_lock *>(old_ptr);
578 release_table_share_lock_stat(pfs);
579 }
580 }
581
582 /**
583 Find an existing table share index instrumentation.
584 @return a table share index
585 */
586 PFS_table_share_index*
find_index_stat(uint index) const587 PFS_table_share::find_index_stat(uint index) const
588 {
589 assert(index <= MAX_INDEXES);
590
591 PFS_table_share *that= const_cast<PFS_table_share*>(this);
592 void *addr= & that->m_race_index_stat[index];
593 void * volatile * typed_addr= static_cast<void * volatile *>(addr);
594 void *ptr;
595
596 /* Atomic Load */
597 ptr= my_atomic_loadptr(typed_addr);
598
599 PFS_table_share_index *pfs;
600 pfs= static_cast<PFS_table_share_index *>(ptr);
601 return pfs;
602 }
603
604 /**
605 Find or create a table share index instrumentation.
606 @param server_share
607 @index index
608 @return a table share index, or NULL
609 */
610 PFS_table_share_index*
find_or_create_index_stat(const TABLE_SHARE * server_share,uint index)611 PFS_table_share::find_or_create_index_stat(const TABLE_SHARE *server_share, uint index)
612 {
613 assert(index <= MAX_INDEXES);
614
615 void *addr= & this->m_race_index_stat[index];
616 void * volatile * typed_addr= static_cast<void * volatile *>(addr);
617 void *ptr;
618
619 /* (1) Atomic Load */
620 ptr= my_atomic_loadptr(typed_addr);
621
622 PFS_table_share_index *pfs;
623 if (ptr != NULL)
624 {
625 pfs= static_cast<PFS_table_share_index *>(ptr);
626 return pfs;
627 }
628
629 /* (2) Create an index stat */
630 pfs= create_table_share_index_stat(server_share, index);
631 if (pfs == NULL)
632 return NULL;
633 pfs->m_owner= this;
634
635 void *old_ptr= NULL;
636 ptr= pfs;
637
638 /* (3) Atomic CAS */
639 if (my_atomic_casptr(typed_addr, & old_ptr, ptr))
640 {
641 /* Ok. */
642 return pfs;
643 }
644
645 /* Collision with another thread that also executed (2) and (3). */
646 release_table_share_index_stat(pfs);
647
648 pfs= static_cast<PFS_table_share_index *>(old_ptr);
649 return pfs;
650 }
651
652 /** Destroy table share index instrumentation. */
destroy_index_stats()653 void PFS_table_share::destroy_index_stats()
654 {
655 uint index;
656
657 for (index= 0; index <= MAX_INDEXES; index++)
658 {
659 void *addr= & this->m_race_index_stat[index];
660 void * volatile * typed_addr= static_cast<void * volatile *>(addr);
661 void *new_ptr= NULL;
662 void *old_ptr;
663
664 old_ptr= my_atomic_fasptr(typed_addr, new_ptr);
665 if (old_ptr != NULL)
666 {
667 PFS_table_share_index *pfs;
668 pfs= static_cast<PFS_table_share_index *>(old_ptr);
669 release_table_share_index_stat(pfs);
670 }
671 }
672 }
673
refresh_setup_object_flags(PFS_thread * thread)674 void PFS_table_share::refresh_setup_object_flags(PFS_thread *thread)
675 {
676 bool old_enabled= m_enabled;
677
678 lookup_setup_object(thread,
679 OBJECT_TYPE_TABLE,
680 m_schema_name, m_schema_name_length,
681 m_table_name, m_table_name_length,
682 &m_enabled, &m_timed);
683
684 /*
685 If instrumentation for this table was enabled earlier and is disabled now,
686 cleanup slots reserved for lock stats and index stats.
687 */
688 if (old_enabled && ! m_enabled)
689 {
690 destroy_lock_stat();
691 destroy_index_stats();
692 }
693 }
694
695 /**
696 Initialize the table lock stat buffer.
697 @param table_stat_sizing max number of table lock statistics
698 @return 0 on success
699 */
init_table_share_lock_stat(uint table_stat_sizing)700 int init_table_share_lock_stat(uint table_stat_sizing)
701 {
702 if (global_table_share_lock_container.init(table_stat_sizing))
703 return 1;
704
705 return 0;
706 }
707
708 /**
709 Create a table share lock instrumentation.
710 @return table share lock instrumentation, or NULL
711 */
712 PFS_table_share_lock*
create_table_share_lock_stat()713 create_table_share_lock_stat()
714 {
715 PFS_table_share_lock *pfs= NULL;
716 pfs_dirty_state dirty_state;
717
718 /* Create a new record in table stat array. */
719 pfs= global_table_share_lock_container.allocate(& dirty_state);
720 if (pfs != NULL)
721 {
722 /* Reset the stats. */
723 pfs->m_stat.reset();
724
725 /* Use this stat buffer. */
726 pfs->m_lock.dirty_to_allocated(& dirty_state);
727 }
728
729 return pfs;
730 }
731
732 /** Release a table share lock instrumentation. */
release_table_share_lock_stat(PFS_table_share_lock * pfs)733 void release_table_share_lock_stat(PFS_table_share_lock *pfs)
734 {
735 pfs->m_owner= NULL;
736 global_table_share_lock_container.deallocate(pfs);
737 return;
738 }
739
740 /** Cleanup the table stat buffers. */
cleanup_table_share_lock_stat(void)741 void cleanup_table_share_lock_stat(void)
742 {
743 global_table_share_lock_container.cleanup();
744 }
745
746 /**
747 Initialize table index stat buffer.
748 @param index_stat_sizing max number of index statistics
749 @return 0 on success
750 */
init_table_share_index_stat(uint index_stat_sizing)751 int init_table_share_index_stat(uint index_stat_sizing)
752 {
753 if (global_table_share_index_container.init(index_stat_sizing))
754 return 1;
755
756 return 0;
757 }
758
759 /**
760 Create a table share index instrumentation.
761 @return table share index instrumentation, or NULL
762 */
763 PFS_table_share_index*
create_table_share_index_stat(const TABLE_SHARE * server_share,uint server_index)764 create_table_share_index_stat(const TABLE_SHARE *server_share, uint server_index)
765 {
766 assert((server_share != NULL) || (server_index == MAX_INDEXES));
767
768 PFS_table_share_index *pfs= NULL;
769 pfs_dirty_state dirty_state;
770
771 /* Create a new record in index stat array. */
772 pfs= global_table_share_index_container.allocate(& dirty_state);
773 if (pfs != NULL)
774 {
775 if (server_index == MAX_INDEXES)
776 {
777 pfs->m_key.m_name_length= 0;
778 }
779 else
780 {
781 KEY *key_info= server_share->key_info + server_index;
782 size_t len= key_info->name.length;
783
784 memcpy(pfs->m_key.m_name, key_info->name.str, len);
785 pfs->m_key.m_name_length= static_cast<uint>(len);
786 }
787
788 /* Reset the stats. */
789 pfs->m_stat.reset();
790
791 /* Use this stat buffer. */
792 pfs->m_lock.dirty_to_allocated(& dirty_state);
793 }
794
795 return pfs;
796 }
797
798 /** Release a table share index instrumentation. */
release_table_share_index_stat(PFS_table_share_index * pfs)799 void release_table_share_index_stat(PFS_table_share_index *pfs)
800 {
801 pfs->m_owner= NULL;
802 global_table_share_index_container.deallocate(pfs);
803 return;
804 }
805
806 /** Cleanup the table stat buffers. */
cleanup_table_share_index_stat(void)807 void cleanup_table_share_index_stat(void)
808 {
809 global_table_share_index_container.cleanup();
810 }
811
812 /**
813 Initialize the file class buffer.
814 @param file_class_sizing max number of file class
815 @return 0 on success
816 */
init_file_class(uint file_class_sizing)817 int init_file_class(uint file_class_sizing)
818 {
819 int result= 0;
820 file_class_dirty_count= file_class_allocated_count= 0;
821 file_class_max= file_class_sizing;
822 file_class_lost= 0;
823
824 if (file_class_max > 0)
825 {
826 file_class_array= PFS_MALLOC_ARRAY(& builtin_memory_file_class,
827 file_class_max,
828 sizeof(PFS_file_class), PFS_file_class,
829 MYF(MY_ZEROFILL));
830 if (unlikely(file_class_array == NULL))
831 return 1;
832 }
833 else
834 file_class_array= NULL;
835
836 return result;
837 }
838
839 /** Cleanup the file class buffers. */
cleanup_file_class(void)840 void cleanup_file_class(void)
841 {
842 PFS_FREE_ARRAY(& builtin_memory_file_class,
843 file_class_max, sizeof(PFS_file_class),
844 file_class_array);
845 file_class_array= NULL;
846 file_class_dirty_count= file_class_allocated_count= 0;
847 file_class_max= 0;
848 }
849
850 /**
851 Initialize the stage class buffer.
852 @param stage_class_sizing max number of stage class
853 @return 0 on success
854 */
init_stage_class(uint stage_class_sizing)855 int init_stage_class(uint stage_class_sizing)
856 {
857 int result= 0;
858 stage_class_dirty_count= stage_class_allocated_count= 0;
859 stage_class_max= stage_class_sizing;
860 stage_class_lost= 0;
861
862 if (stage_class_max > 0)
863 {
864 stage_class_array= PFS_MALLOC_ARRAY(& builtin_memory_stage_class,
865 stage_class_max,
866 sizeof(PFS_stage_class), PFS_stage_class,
867 MYF(MY_ZEROFILL));
868 if (unlikely(stage_class_array == NULL))
869 return 1;
870 }
871 else
872 stage_class_array= NULL;
873
874 return result;
875 }
876
877 /** Cleanup the stage class buffers. */
cleanup_stage_class(void)878 void cleanup_stage_class(void)
879 {
880 PFS_FREE_ARRAY(& builtin_memory_stage_class,
881 stage_class_max, sizeof(PFS_stage_class),
882 stage_class_array);
883 stage_class_array= NULL;
884 stage_class_dirty_count= stage_class_allocated_count= 0;
885 stage_class_max= 0;
886 }
887
888 /**
889 Initialize the statement class buffer.
890 @param statement_class_sizing max number of statement class
891 @return 0 on success
892 */
init_statement_class(uint statement_class_sizing)893 int init_statement_class(uint statement_class_sizing)
894 {
895 int result= 0;
896 statement_class_dirty_count= statement_class_allocated_count= 0;
897 statement_class_max= statement_class_sizing;
898 statement_class_lost= 0;
899
900 if (statement_class_max > 0)
901 {
902 statement_class_array= PFS_MALLOC_ARRAY(& builtin_memory_statement_class,
903 statement_class_max,
904 sizeof(PFS_statement_class), PFS_statement_class,
905 MYF(MY_ZEROFILL));
906 if (unlikely(statement_class_array == NULL))
907 return 1;
908 }
909 else
910 statement_class_array= NULL;
911
912 return result;
913 }
914
915 /** Cleanup the statement class buffers. */
cleanup_statement_class(void)916 void cleanup_statement_class(void)
917 {
918 PFS_FREE_ARRAY(& builtin_memory_statement_class,
919 statement_class_max, sizeof(PFS_statement_class),
920 statement_class_array);
921 statement_class_array= NULL;
922 statement_class_dirty_count= statement_class_allocated_count= 0;
923 statement_class_max= 0;
924 }
925
926 /**
927 Initialize the socket class buffer.
928 @param socket_class_sizing max number of socket class
929 @return 0 on success
930 */
init_socket_class(uint socket_class_sizing)931 int init_socket_class(uint socket_class_sizing)
932 {
933 int result= 0;
934 socket_class_dirty_count= socket_class_allocated_count= 0;
935 socket_class_max= socket_class_sizing;
936 socket_class_lost= 0;
937
938 if (socket_class_max > 0)
939 {
940 socket_class_array= PFS_MALLOC_ARRAY(& builtin_memory_socket_class,
941 socket_class_max,
942 sizeof(PFS_socket_class), PFS_socket_class,
943 MYF(MY_ZEROFILL));
944 if (unlikely(socket_class_array == NULL))
945 return 1;
946 }
947 else
948 socket_class_array= NULL;
949
950 return result;
951 }
952
953 /** Cleanup the socket class buffers. */
cleanup_socket_class(void)954 void cleanup_socket_class(void)
955 {
956 PFS_FREE_ARRAY(& builtin_memory_socket_class,
957 socket_class_max, sizeof(PFS_socket_class),
958 socket_class_array);
959 socket_class_array= NULL;
960 socket_class_dirty_count= socket_class_allocated_count= 0;
961 socket_class_max= 0;
962 }
963
964 /**
965 Initialize the memory class buffer.
966 @param memory_class_sizing max number of memory class
967 @return 0 on success
968 */
init_memory_class(uint memory_class_sizing)969 int init_memory_class(uint memory_class_sizing)
970 {
971 int result= 0;
972 memory_class_dirty_count= memory_class_allocated_count= 0;
973 memory_class_max= memory_class_sizing;
974 memory_class_lost= 0;
975
976 if (memory_class_max > 0)
977 {
978 memory_class_array= PFS_MALLOC_ARRAY(& builtin_memory_memory_class,
979 memory_class_max,
980 sizeof(PFS_memory_class), PFS_memory_class,
981 MYF(MY_ZEROFILL));
982 if (unlikely(memory_class_array == NULL))
983 return 1;
984 }
985 else
986 memory_class_array= NULL;
987
988 return result;
989 }
990
991 /** Cleanup the memory class buffers. */
cleanup_memory_class(void)992 void cleanup_memory_class(void)
993 {
994 PFS_FREE_ARRAY(& builtin_memory_memory_class,
995 memory_class_max, sizeof(PFS_memory_class),
996 memory_class_array);
997 memory_class_array= NULL;
998 memory_class_dirty_count= memory_class_allocated_count= 0;
999 memory_class_max= 0;
1000 }
1001
init_instr_class(PFS_instr_class * klass,const char * name,uint name_length,int flags,PFS_class_type class_type)1002 static void init_instr_class(PFS_instr_class *klass,
1003 const char *name,
1004 uint name_length,
1005 int flags,
1006 PFS_class_type class_type)
1007 {
1008 assert(name_length <= PFS_MAX_INFO_NAME_LENGTH);
1009 memset(klass, 0, sizeof(PFS_instr_class));
1010 strncpy(klass->m_name, name, name_length);
1011 klass->m_name[PFS_MAX_INFO_NAME_LENGTH - 1]= '\0';
1012 klass->m_name_length= name_length;
1013 klass->m_flags= flags;
1014 klass->m_enabled= true;
1015 klass->m_timed= true;
1016 klass->m_type= class_type;
1017 klass->m_timer= class_timers[class_type];
1018 }
1019
1020 /**
1021 Set user-defined configuration values for an instrument.
1022 */
configure_instr_class(PFS_instr_class * entry)1023 static void configure_instr_class(PFS_instr_class *entry)
1024 {
1025 uint match_length= 0; /* length of matching pattern */
1026
1027 // May be NULL in unit tests
1028 if (pfs_instr_config_array == NULL)
1029 return;
1030 PFS_instr_config **it= pfs_instr_config_array->front();
1031 for ( ; it != pfs_instr_config_array->end(); it++)
1032 {
1033 PFS_instr_config* e= *it;
1034
1035 /**
1036 Compare class name to all configuration entries. In case of multiple
1037 matches, the longer specification wins. For example, the pattern
1038 'ABC/DEF/GHI=ON' has precedence over 'ABC/DEF/%=OFF' regardless of
1039 position within the configuration file or command line.
1040
1041 Consecutive wildcards affect the count.
1042 */
1043 if (!my_charset_latin1.wildcmp(
1044 entry->m_name, entry->m_name+entry->m_name_length,
1045 e->m_name, e->m_name+e->m_name_length,
1046 '\\', '?','%'))
1047 {
1048 if (e->m_name_length >= match_length)
1049 {
1050 entry->m_enabled= e->m_enabled;
1051 entry->m_timed= e->m_timed;
1052 match_length= MY_MAX(e->m_name_length, match_length);
1053 }
1054 }
1055 }
1056 }
1057
1058 #define REGISTER_CLASS_BODY_PART(INDEX, ARRAY, MAX, NAME, NAME_LENGTH) \
1059 for (INDEX= 0; INDEX < MAX; INDEX++) \
1060 { \
1061 entry= &ARRAY[INDEX]; \
1062 if ((entry->m_name_length == NAME_LENGTH) && \
1063 (strncmp(entry->m_name, NAME, NAME_LENGTH) == 0)) \
1064 { \
1065 assert(entry->m_flags == flags); \
1066 return (INDEX + 1); \
1067 } \
1068 }
1069
1070 /**
1071 Register a mutex instrumentation metadata.
1072 @param name the instrumented name
1073 @param name_length length in bytes of name
1074 @param flags the instrumentation flags
1075 @return a mutex instrumentation key
1076 */
register_mutex_class(const char * name,uint name_length,int flags)1077 PFS_sync_key register_mutex_class(const char *name, uint name_length,
1078 int flags)
1079 {
1080 uint32 index;
1081 PFS_mutex_class *entry;
1082
1083 /*
1084 This is a full array scan, which is not optimal.
1085 This is acceptable since this code is only used at startup,
1086 or when a plugin is loaded.
1087 */
1088 REGISTER_CLASS_BODY_PART(index, mutex_class_array, mutex_class_max,
1089 name, name_length)
1090 /*
1091 Note that:
1092 mutex_class_dirty_count is incremented *before* an entry is added
1093 mutex_class_allocated_count is incremented *after* an entry is added
1094 */
1095 index= PFS_atomic::add_u32(&mutex_class_dirty_count, 1);
1096
1097 if (index < mutex_class_max)
1098 {
1099 /*
1100 The instrument was not found (from a possible previous
1101 load / unload of a plugin), allocate it.
1102 This code is safe when 2 threads execute in parallel
1103 for different mutex classes:
1104 - thread 1 registering class A
1105 - thread 2 registering class B
1106 will not collide in the same mutex_class_array[index] entry.
1107 This code does not protect against 2 threads registering
1108 in parallel the same class:
1109 - thread 1 registering class A
1110 - thread 2 registering class A
1111 could lead to a duplicate class A entry.
1112 This is ok, since this case can not happen in the caller:
1113 - classes names are derived from a plugin name
1114 ('wait/synch/mutex/<plugin>/xxx')
1115 - 2 threads can not register concurrently the same plugin
1116 in INSTALL PLUGIN.
1117 */
1118 entry= &mutex_class_array[index];
1119 init_instr_class(entry, name, name_length, flags, PFS_CLASS_MUTEX);
1120 entry->m_mutex_stat.reset();
1121 entry->m_event_name_index= mutex_class_start + index;
1122 entry->m_singleton= NULL;
1123 entry->m_enabled= false; /* disabled by default */
1124 entry->m_timed= false;
1125
1126 /* Set user-defined configuration options for this instrument */
1127 configure_instr_class(entry);
1128
1129 /*
1130 Now that this entry is populated, advertise it
1131
1132 Technically, there is a small race condition here:
1133 T0:
1134 mutex_class_dirty_count= 10
1135 mutex_class_allocated_count= 10
1136 T1: Thread A increment mutex_class_dirty_count to 11
1137 T2: Thread B increment mutex_class_dirty_count to 12
1138 T3: Thread A populate entry 11
1139 T4: Thread B populate entry 12
1140 T5: Thread B increment mutex_class_allocated_count to 11,
1141 advertise thread A incomplete record 11,
1142 but does not advertise thread B complete record 12
1143 T6: Thread A increment mutex_class_allocated_count to 12
1144 This has no impact, and is acceptable.
1145 A reader will not see record 12 for a short time.
1146 A reader will see an incomplete record 11 for a short time,
1147 which is ok: the mutex name / statistics will be temporarily
1148 empty/NULL/zero, but this won't cause a crash
1149 (mutex_class_array is initialized with MY_ZEROFILL).
1150 */
1151 PFS_atomic::add_u32(&mutex_class_allocated_count, 1);
1152 return (index + 1);
1153 }
1154
1155 /*
1156 Out of space, report to SHOW STATUS that
1157 the allocated memory was too small.
1158 */
1159 if (pfs_enabled)
1160 mutex_class_lost++;
1161 return 0;
1162 }
1163
1164 /**
1165 Register a rwlock instrumentation metadata.
1166 @param name the instrumented name
1167 @param name_length length in bytes of name
1168 @param flags the instrumentation flags
1169 @return a rwlock instrumentation key
1170 */
register_rwlock_class(const char * name,uint name_length,int flags)1171 PFS_sync_key register_rwlock_class(const char *name, uint name_length,
1172 int flags)
1173 {
1174 /* See comments in register_mutex_class */
1175 uint32 index;
1176 PFS_rwlock_class *entry;
1177
1178 REGISTER_CLASS_BODY_PART(index, rwlock_class_array, rwlock_class_max,
1179 name, name_length)
1180
1181 index= PFS_atomic::add_u32(&rwlock_class_dirty_count, 1);
1182
1183 if (index < rwlock_class_max)
1184 {
1185 entry= &rwlock_class_array[index];
1186 init_instr_class(entry, name, name_length, flags, PFS_CLASS_RWLOCK);
1187 entry->m_rwlock_stat.reset();
1188 entry->m_event_name_index= rwlock_class_start + index;
1189 entry->m_singleton= NULL;
1190 entry->m_enabled= false; /* disabled by default */
1191 entry->m_timed= false;
1192 /* Set user-defined configuration options for this instrument */
1193 configure_instr_class(entry);
1194 PFS_atomic::add_u32(&rwlock_class_allocated_count, 1);
1195 return (index + 1);
1196 }
1197
1198 if (pfs_enabled)
1199 rwlock_class_lost++;
1200 return 0;
1201 }
1202
1203 /**
1204 Register a condition instrumentation metadata.
1205 @param name the instrumented name
1206 @param name_length length in bytes of name
1207 @param flags the instrumentation flags
1208 @return a condition instrumentation key
1209 */
register_cond_class(const char * name,uint name_length,int flags)1210 PFS_sync_key register_cond_class(const char *name, uint name_length,
1211 int flags)
1212 {
1213 /* See comments in register_mutex_class */
1214 uint32 index;
1215 PFS_cond_class *entry;
1216
1217 REGISTER_CLASS_BODY_PART(index, cond_class_array, cond_class_max,
1218 name, name_length)
1219
1220 index= PFS_atomic::add_u32(&cond_class_dirty_count, 1);
1221
1222 if (index < cond_class_max)
1223 {
1224 entry= &cond_class_array[index];
1225 init_instr_class(entry, name, name_length, flags, PFS_CLASS_COND);
1226 entry->m_event_name_index= cond_class_start + index;
1227 entry->m_singleton= NULL;
1228 entry->m_enabled= false; /* disabled by default */
1229 entry->m_timed= false;
1230 /* Set user-defined configuration options for this instrument */
1231 configure_instr_class(entry);
1232 PFS_atomic::add_u32(&cond_class_allocated_count, 1);
1233 return (index + 1);
1234 }
1235
1236 if (pfs_enabled)
1237 cond_class_lost++;
1238 return 0;
1239 }
1240
1241 #define FIND_CLASS_BODY(KEY, COUNT, ARRAY) \
1242 if ((KEY == 0) || (KEY > COUNT)) \
1243 return NULL; \
1244 return &ARRAY[KEY - 1]
1245
1246 /**
1247 Find a mutex instrumentation class by key.
1248 @param key the instrument key
1249 @return the instrument class, or NULL
1250 */
find_mutex_class(PFS_sync_key key)1251 PFS_mutex_class *find_mutex_class(PFS_sync_key key)
1252 {
1253 FIND_CLASS_BODY(key, mutex_class_allocated_count, mutex_class_array);
1254 }
1255
sanitize_mutex_class(PFS_mutex_class * unsafe)1256 PFS_mutex_class *sanitize_mutex_class(PFS_mutex_class *unsafe)
1257 {
1258 SANITIZE_ARRAY_BODY(PFS_mutex_class, mutex_class_array, mutex_class_max, unsafe);
1259 }
1260
1261 /**
1262 Find a rwlock instrumentation class by key.
1263 @param key the instrument key
1264 @return the instrument class, or NULL
1265 */
find_rwlock_class(PFS_sync_key key)1266 PFS_rwlock_class *find_rwlock_class(PFS_sync_key key)
1267 {
1268 FIND_CLASS_BODY(key, rwlock_class_allocated_count, rwlock_class_array);
1269 }
1270
sanitize_rwlock_class(PFS_rwlock_class * unsafe)1271 PFS_rwlock_class *sanitize_rwlock_class(PFS_rwlock_class *unsafe)
1272 {
1273 SANITIZE_ARRAY_BODY(PFS_rwlock_class, rwlock_class_array, rwlock_class_max, unsafe);
1274 }
1275
1276 /**
1277 Find a condition instrumentation class by key.
1278 @param key the instrument key
1279 @return the instrument class, or NULL
1280 */
find_cond_class(PFS_sync_key key)1281 PFS_cond_class *find_cond_class(PFS_sync_key key)
1282 {
1283 FIND_CLASS_BODY(key, cond_class_allocated_count, cond_class_array);
1284 }
1285
sanitize_cond_class(PFS_cond_class * unsafe)1286 PFS_cond_class *sanitize_cond_class(PFS_cond_class *unsafe)
1287 {
1288 SANITIZE_ARRAY_BODY(PFS_cond_class, cond_class_array, cond_class_max, unsafe);
1289 }
1290
1291 /**
1292 Register a thread instrumentation metadata.
1293 @param name the instrumented name
1294 @param name_length length in bytes of name
1295 @param flags the instrumentation flags
1296 @return a thread instrumentation key
1297 */
register_thread_class(const char * name,uint name_length,int flags)1298 PFS_thread_key register_thread_class(const char *name, uint name_length,
1299 int flags)
1300 {
1301 /* See comments in register_mutex_class */
1302 uint32 index;
1303 PFS_thread_class *entry;
1304
1305 for (index= 0; index < thread_class_max; index++)
1306 {
1307 entry= &thread_class_array[index];
1308
1309 if ((entry->m_name_length == name_length) &&
1310 (strncmp(entry->m_name, name, name_length) == 0))
1311 return (index + 1);
1312 }
1313
1314 index= PFS_atomic::add_u32(&thread_class_dirty_count, 1);
1315
1316 if (index < thread_class_max)
1317 {
1318 entry= &thread_class_array[index];
1319 assert(name_length <= PFS_MAX_INFO_NAME_LENGTH);
1320 strncpy(entry->m_name, name, name_length);
1321 entry->m_name_length= name_length;
1322 entry->m_enabled= true;
1323 PFS_atomic::add_u32(&thread_class_allocated_count, 1);
1324 return (index + 1);
1325 }
1326
1327 if (pfs_enabled)
1328 thread_class_lost++;
1329 return 0;
1330 }
1331
1332 /**
1333 Find a thread instrumentation class by key.
1334 @param key the instrument key
1335 @return the instrument class, or NULL
1336 */
find_thread_class(PFS_sync_key key)1337 PFS_thread_class *find_thread_class(PFS_sync_key key)
1338 {
1339 FIND_CLASS_BODY(key, thread_class_allocated_count, thread_class_array);
1340 }
1341
sanitize_thread_class(PFS_thread_class * unsafe)1342 PFS_thread_class *sanitize_thread_class(PFS_thread_class *unsafe)
1343 {
1344 SANITIZE_ARRAY_BODY(PFS_thread_class, thread_class_array, thread_class_max, unsafe);
1345 }
1346
1347 /**
1348 Register a file instrumentation metadata.
1349 @param name the instrumented name
1350 @param name_length length in bytes of name
1351 @param flags the instrumentation flags
1352 @return a file instrumentation key
1353 */
register_file_class(const char * name,uint name_length,int flags)1354 PFS_file_key register_file_class(const char *name, uint name_length,
1355 int flags)
1356 {
1357 /* See comments in register_mutex_class */
1358 uint32 index;
1359 PFS_file_class *entry;
1360
1361 REGISTER_CLASS_BODY_PART(index, file_class_array, file_class_max,
1362 name, name_length)
1363
1364 index= PFS_atomic::add_u32(&file_class_dirty_count, 1);
1365
1366 if (index < file_class_max)
1367 {
1368 entry= &file_class_array[index];
1369 init_instr_class(entry, name, name_length, flags, PFS_CLASS_FILE);
1370 entry->m_event_name_index= file_class_start + index;
1371 entry->m_singleton= NULL;
1372 entry->m_enabled= true; /* enabled by default */
1373 entry->m_timed= true;
1374 /* Set user-defined configuration options for this instrument */
1375 configure_instr_class(entry);
1376 PFS_atomic::add_u32(&file_class_allocated_count, 1);
1377
1378 return (index + 1);
1379 }
1380
1381 if (pfs_enabled)
1382 file_class_lost++;
1383 return 0;
1384 }
1385
1386 /**
1387 Register a stage instrumentation metadata.
1388 @param name the instrumented name
1389 @param prefix_length length in bytes of the name prefix
1390 @param name_length length in bytes of name
1391 @param flags the instrumentation flags
1392 @return a stage instrumentation key
1393 */
register_stage_class(const char * name,uint prefix_length,uint name_length,int flags)1394 PFS_stage_key register_stage_class(const char *name,
1395 uint prefix_length,
1396 uint name_length,
1397 int flags)
1398 {
1399 /* See comments in register_mutex_class */
1400 uint32 index;
1401 PFS_stage_class *entry;
1402
1403 REGISTER_CLASS_BODY_PART(index, stage_class_array, stage_class_max,
1404 name, name_length)
1405
1406 index= PFS_atomic::add_u32(&stage_class_dirty_count, 1);
1407
1408 if (index < stage_class_max)
1409 {
1410 entry= &stage_class_array[index];
1411 init_instr_class(entry, name, name_length, flags, PFS_CLASS_STAGE);
1412 entry->m_prefix_length= prefix_length;
1413 entry->m_event_name_index= index;
1414
1415 if (flags & PSI_FLAG_STAGE_PROGRESS)
1416 {
1417 /* Stages with progress information are enabled and timed by default */
1418 entry->m_enabled= true;
1419 entry->m_timed= true;
1420 }
1421 else
1422 {
1423 /* Stages without progress information are disabled by default */
1424 entry->m_enabled= false;
1425 entry->m_timed= false;
1426 }
1427
1428 /* Set user-defined configuration options for this instrument */
1429 configure_instr_class(entry);
1430 PFS_atomic::add_u32(&stage_class_allocated_count, 1);
1431
1432 return (index + 1);
1433 }
1434
1435 if (pfs_enabled)
1436 stage_class_lost++;
1437 return 0;
1438 }
1439
1440 /**
1441 Register a statement instrumentation metadata.
1442 @param name the instrumented name
1443 @param name_length length in bytes of name
1444 @param flags the instrumentation flags
1445 @return a statement instrumentation key
1446 */
register_statement_class(const char * name,uint name_length,int flags)1447 PFS_statement_key register_statement_class(const char *name, uint name_length,
1448 int flags)
1449 {
1450 /* See comments in register_mutex_class */
1451 uint32 index;
1452 PFS_statement_class *entry;
1453
1454 REGISTER_CLASS_BODY_PART(index, statement_class_array, statement_class_max,
1455 name, name_length)
1456
1457 index= PFS_atomic::add_u32(&statement_class_dirty_count, 1);
1458
1459 if (index < statement_class_max)
1460 {
1461 entry= &statement_class_array[index];
1462 init_instr_class(entry, name, name_length, flags, PFS_CLASS_STATEMENT);
1463 entry->m_event_name_index= index;
1464 entry->m_enabled= true; /* enabled by default */
1465 entry->m_timed= true;
1466 /* Set user-defined configuration options for this instrument */
1467 configure_instr_class(entry);
1468 PFS_atomic::add_u32(&statement_class_allocated_count, 1);
1469
1470 return (index + 1);
1471 }
1472
1473 if (pfs_enabled)
1474 statement_class_lost++;
1475 return 0;
1476 }
1477
1478 /**
1479 Find a file instrumentation class by key.
1480 @param key the instrument key
1481 @return the instrument class, or NULL
1482 */
find_file_class(PFS_file_key key)1483 PFS_file_class *find_file_class(PFS_file_key key)
1484 {
1485 FIND_CLASS_BODY(key, file_class_allocated_count, file_class_array);
1486 }
1487
sanitize_file_class(PFS_file_class * unsafe)1488 PFS_file_class *sanitize_file_class(PFS_file_class *unsafe)
1489 {
1490 SANITIZE_ARRAY_BODY(PFS_file_class, file_class_array, file_class_max, unsafe);
1491 }
1492
1493 /**
1494 Find a stage instrumentation class by key.
1495 @param key the instrument key
1496 @return the instrument class, or NULL
1497 */
find_stage_class(PFS_stage_key key)1498 PFS_stage_class *find_stage_class(PFS_stage_key key)
1499 {
1500 FIND_CLASS_BODY(key, stage_class_allocated_count, stage_class_array);
1501 }
1502
sanitize_stage_class(PFS_stage_class * unsafe)1503 PFS_stage_class *sanitize_stage_class(PFS_stage_class *unsafe)
1504 {
1505 SANITIZE_ARRAY_BODY(PFS_stage_class, stage_class_array, stage_class_max, unsafe);
1506 }
1507
1508 /**
1509 Find a statement instrumentation class by key.
1510 @param key the instrument key
1511 @return the instrument class, or NULL
1512 */
find_statement_class(PFS_stage_key key)1513 PFS_statement_class *find_statement_class(PFS_stage_key key)
1514 {
1515 FIND_CLASS_BODY(key, statement_class_allocated_count, statement_class_array);
1516 }
1517
sanitize_statement_class(PFS_statement_class * unsafe)1518 PFS_statement_class *sanitize_statement_class(PFS_statement_class *unsafe)
1519 {
1520 SANITIZE_ARRAY_BODY(PFS_statement_class, statement_class_array, statement_class_max, unsafe);
1521 }
1522
1523 /**
1524 Register a socket instrumentation metadata.
1525 @param name the instrumented name
1526 @param name_length length in bytes of name
1527 @param flags the instrumentation flags
1528 @return a socket instrumentation key
1529 */
register_socket_class(const char * name,uint name_length,int flags)1530 PFS_socket_key register_socket_class(const char *name, uint name_length,
1531 int flags)
1532 {
1533 /* See comments in register_mutex_class */
1534 uint32 index;
1535 PFS_socket_class *entry;
1536
1537 REGISTER_CLASS_BODY_PART(index, socket_class_array, socket_class_max,
1538 name, name_length)
1539
1540 index= PFS_atomic::add_u32(&socket_class_dirty_count, 1);
1541
1542 if (index < socket_class_max)
1543 {
1544 entry= &socket_class_array[index];
1545 init_instr_class(entry, name, name_length, flags, PFS_CLASS_SOCKET);
1546 entry->m_event_name_index= socket_class_start + index;
1547 entry->m_singleton= NULL;
1548 entry->m_enabled= false; /* disabled by default */
1549 entry->m_timed= false;
1550 /* Set user-defined configuration options for this instrument */
1551 configure_instr_class(entry);
1552 PFS_atomic::add_u32(&socket_class_allocated_count, 1);
1553 return (index + 1);
1554 }
1555
1556 if (pfs_enabled)
1557 socket_class_lost++;
1558 return 0;
1559 }
1560
1561 /**
1562 Find a socket instrumentation class by key.
1563 @param key the instrument key
1564 @return the instrument class, or NULL
1565 */
find_socket_class(PFS_socket_key key)1566 PFS_socket_class *find_socket_class(PFS_socket_key key)
1567 {
1568 FIND_CLASS_BODY(key, socket_class_allocated_count, socket_class_array);
1569 }
1570
sanitize_socket_class(PFS_socket_class * unsafe)1571 PFS_socket_class *sanitize_socket_class(PFS_socket_class *unsafe)
1572 {
1573 SANITIZE_ARRAY_BODY(PFS_socket_class, socket_class_array, socket_class_max, unsafe);
1574 }
1575
1576 /**
1577 Register a memory instrumentation metadata.
1578 @param name the instrumented name
1579 @param name_length length in bytes of name
1580 @param flags the instrumentation flags
1581 @return a memory instrumentation key
1582 */
register_memory_class(const char * name,uint name_length,int flags)1583 PFS_memory_key register_memory_class(const char *name, uint name_length,
1584 int flags)
1585 {
1586 /* See comments in register_mutex_class */
1587 uint32 index;
1588 PFS_memory_class *entry;
1589
1590 REGISTER_CLASS_BODY_PART(index, memory_class_array, memory_class_max,
1591 name, name_length)
1592
1593 index= PFS_atomic::add_u32(&memory_class_dirty_count, 1);
1594
1595 if (index < memory_class_max)
1596 {
1597 entry= &memory_class_array[index];
1598 init_instr_class(entry, name, name_length, flags, PFS_CLASS_MEMORY);
1599 entry->m_event_name_index= index;
1600 entry->m_enabled= false; /* disabled by default */
1601 /* Set user-defined configuration options for this instrument */
1602 configure_instr_class(entry);
1603 entry->m_timed= false; /* Immutable */
1604 PFS_atomic::add_u32(&memory_class_allocated_count, 1);
1605 return (index + 1);
1606 }
1607
1608 if (pfs_enabled)
1609 memory_class_lost++;
1610 return 0;
1611 }
1612
1613 /**
1614 Find a memory instrumentation class by key.
1615 @param key the instrument key
1616 @return the instrument class, or NULL
1617 */
find_memory_class(PFS_memory_key key)1618 PFS_memory_class *find_memory_class(PFS_memory_key key)
1619 {
1620 FIND_CLASS_BODY(key, memory_class_allocated_count, memory_class_array);
1621 }
1622
sanitize_memory_class(PFS_memory_class * unsafe)1623 PFS_memory_class *sanitize_memory_class(PFS_memory_class *unsafe)
1624 {
1625 SANITIZE_ARRAY_BODY(PFS_memory_class, memory_class_array, memory_class_max, unsafe);
1626 }
1627
find_table_class(uint index)1628 PFS_instr_class *find_table_class(uint index)
1629 {
1630 if (index == 1)
1631 return & global_table_io_class;
1632 if (index == 2)
1633 return & global_table_lock_class;
1634 return NULL;
1635 }
1636
sanitize_table_class(PFS_instr_class * unsafe)1637 PFS_instr_class *sanitize_table_class(PFS_instr_class *unsafe)
1638 {
1639 if (likely((& global_table_io_class == unsafe) ||
1640 (& global_table_lock_class == unsafe)))
1641 return unsafe;
1642 return NULL;
1643 }
1644
find_idle_class(uint index)1645 PFS_instr_class *find_idle_class(uint index)
1646 {
1647 if (index == 1)
1648 return & global_idle_class;
1649 return NULL;
1650 }
1651
sanitize_idle_class(PFS_instr_class * unsafe)1652 PFS_instr_class *sanitize_idle_class(PFS_instr_class *unsafe)
1653 {
1654 if (likely(& global_idle_class == unsafe))
1655 return unsafe;
1656 return NULL;
1657 }
1658
find_metadata_class(uint index)1659 PFS_instr_class *find_metadata_class(uint index)
1660 {
1661 if (index == 1)
1662 return & global_metadata_class;
1663 return NULL;
1664 }
1665
sanitize_metadata_class(PFS_instr_class * unsafe)1666 PFS_instr_class *sanitize_metadata_class(PFS_instr_class *unsafe)
1667 {
1668 if (likely(& global_metadata_class == unsafe))
1669 return unsafe;
1670 return NULL;
1671 }
1672
find_transaction_class(uint index)1673 PFS_transaction_class *find_transaction_class(uint index)
1674 {
1675 if (index == 1)
1676 return &global_transaction_class;
1677 return NULL;
1678 }
1679
sanitize_transaction_class(PFS_transaction_class * unsafe)1680 PFS_transaction_class *sanitize_transaction_class(PFS_transaction_class *unsafe)
1681 {
1682 if (likely(&global_transaction_class == unsafe))
1683 return unsafe;
1684 return NULL;
1685 }
1686
compare_keys(PFS_table_share * pfs,const TABLE_SHARE * share)1687 static int compare_keys(PFS_table_share *pfs, const TABLE_SHARE *share)
1688 {
1689 if (pfs->m_key_count != share->keys)
1690 return 1;
1691
1692 size_t len;
1693 uint index= 0;
1694 uint key_count= share->keys;
1695 KEY *key_info= share->key_info;
1696 PFS_table_share_index *index_stat;
1697
1698 for ( ; index < key_count; key_info++, index++)
1699 {
1700 index_stat= pfs->find_index_stat(index);
1701 if (index_stat != NULL)
1702 {
1703 len= key_info->name.length;
1704
1705 if (len != index_stat->m_key.m_name_length)
1706 return 1;
1707
1708 if (memcmp(index_stat->m_key.m_name, key_info->name.str, len) != 0)
1709 return 1;
1710 }
1711 }
1712
1713 return 0;
1714 }
1715
1716
1717 /**
1718 Find or create a table share instrumentation.
1719 @param thread the executing instrumented thread
1720 @param temporary true for TEMPORARY TABLE
1721 @param share table share
1722 @return a table share, or NULL
1723 */
find_or_create_table_share(PFS_thread * thread,bool temporary,const TABLE_SHARE * share)1724 PFS_table_share* find_or_create_table_share(PFS_thread *thread,
1725 bool temporary,
1726 const TABLE_SHARE *share)
1727 {
1728 /* See comments in register_mutex_class */
1729 PFS_table_share_key key;
1730
1731 LF_PINS *pins= get_table_share_hash_pins(thread);
1732 if (unlikely(pins == NULL))
1733 {
1734 global_table_share_container.m_lost++;
1735 return NULL;
1736 }
1737
1738 const char *schema_name= share->db.str;
1739 size_t schema_name_length= share->db.length;
1740 const char *table_name= share->table_name.str;
1741 size_t table_name_length= share->table_name.length;
1742
1743 set_table_share_key(&key, temporary,
1744 schema_name, schema_name_length,
1745 table_name, table_name_length);
1746
1747 PFS_table_share **entry;
1748 uint retry_count= 0;
1749 const uint retry_max= 3;
1750 bool enabled= true;
1751 bool timed= true;
1752 PFS_table_share *pfs;
1753 pfs_dirty_state dirty_state;
1754
1755 search:
1756 entry= reinterpret_cast<PFS_table_share**>
1757 (lf_hash_search(&table_share_hash, pins,
1758 key.m_hash_key, key.m_key_length));
1759 if (entry && (entry != MY_ERRPTR))
1760 {
1761 pfs= *entry;
1762 pfs->inc_refcount() ;
1763 if (compare_keys(pfs, share) != 0)
1764 {
1765 /*
1766 Some DDL was detected.
1767 - keep the lock stats, they are unaffected
1768 - destroy the index stats, indexes changed.
1769 - adjust the expected key count
1770 - recreate index stats
1771 */
1772 pfs->destroy_index_stats();
1773 pfs->m_key_count= share->keys;
1774 for (uint index= 0; index < pfs->m_key_count; index++)
1775 {
1776 (void)pfs->find_or_create_index_stat(share, index);
1777 }
1778 }
1779 lf_hash_search_unpin(pins);
1780 return pfs;
1781 }
1782
1783 lf_hash_search_unpin(pins);
1784
1785 if (retry_count == 0)
1786 {
1787 lookup_setup_object(thread,
1788 OBJECT_TYPE_TABLE,
1789 schema_name, static_cast<uint>(schema_name_length),
1790 table_name, static_cast<uint>(table_name_length),
1791 &enabled, &timed);
1792 /*
1793 Even when enabled is false, a record is added in the dictionary:
1794 - It makes enabling a table already in the table cache possible,
1795 - It improves performances for the next time a TABLE_SHARE is reloaded
1796 in the table cache.
1797 */
1798 }
1799
1800 pfs= global_table_share_container.allocate(& dirty_state);
1801 if (pfs != NULL)
1802 {
1803 pfs->m_key= key;
1804 pfs->m_schema_name= &pfs->m_key.m_hash_key[1];
1805 pfs->m_schema_name_length= static_cast<uint>(schema_name_length);
1806 pfs->m_table_name= &pfs->m_key.m_hash_key[schema_name_length + 2];
1807 pfs->m_table_name_length= static_cast<uint>(table_name_length);
1808 pfs->m_enabled= enabled;
1809 pfs->m_timed= timed;
1810 pfs->init_refcount();
1811 pfs->destroy_lock_stat();
1812 pfs->destroy_index_stats();
1813 pfs->m_key_count= share->keys;
1814
1815 int res;
1816 pfs->m_lock.dirty_to_allocated(& dirty_state);
1817 res= lf_hash_insert(&table_share_hash, pins, &pfs);
1818
1819 if (likely(res == 0))
1820 {
1821 /* Create table share index stats. */
1822 for (uint index= 0; index < pfs->m_key_count; index++)
1823 {
1824 (void)pfs->find_or_create_index_stat(share, index);
1825 }
1826 return pfs;
1827 }
1828
1829 global_table_share_container.deallocate(pfs);
1830
1831 if (res > 0)
1832 {
1833 /* Duplicate insert by another thread */
1834 if (++retry_count > retry_max)
1835 {
1836 /* Avoid infinite loops */
1837 global_table_share_container.m_lost++;
1838 return NULL;
1839 }
1840 goto search;
1841 }
1842
1843 /* OOM in lf_hash_insert */
1844 global_table_share_container.m_lost++;
1845 return NULL;
1846 }
1847
1848 return NULL;
1849 }
1850
aggregate_io(void)1851 void PFS_table_share::aggregate_io(void)
1852 {
1853 uint index;
1854 uint safe_key_count= sanitize_index_count(m_key_count);
1855 PFS_table_share_index *from_stat;
1856 PFS_table_io_stat sum_io;
1857
1858 /* Aggregate stats for each index, if any */
1859 for (index= 0; index < safe_key_count; index++)
1860 {
1861 from_stat= find_index_stat(index);
1862 if (from_stat != NULL)
1863 {
1864 sum_io.aggregate(& from_stat->m_stat);
1865 from_stat->m_stat.reset();
1866 }
1867 }
1868
1869 /* Aggregate stats for the table */
1870 from_stat= find_index_stat(MAX_INDEXES);
1871 if (from_stat != NULL)
1872 {
1873 sum_io.aggregate(& from_stat->m_stat);
1874 from_stat->m_stat.reset();
1875 }
1876
1877 /* Add this table stats to the global sink. */
1878 global_table_io_stat.aggregate(& sum_io);
1879 }
1880
sum_io(PFS_single_stat * result,uint key_count)1881 void PFS_table_share::sum_io(PFS_single_stat *result, uint key_count)
1882 {
1883 uint index;
1884 PFS_table_share_index *stat;
1885
1886 assert(key_count <= MAX_INDEXES);
1887
1888 /* Sum stats for each index, if any */
1889 for (index= 0; index < key_count; index++)
1890 {
1891 stat= find_index_stat(index);
1892 if (stat != NULL)
1893 {
1894 stat->m_stat.sum(result);
1895 }
1896 }
1897
1898 /* Sum stats for the table */
1899 stat= find_index_stat(MAX_INDEXES);
1900 if (stat != NULL)
1901 {
1902 stat->m_stat.sum(result);
1903 }
1904 }
1905
sum_lock(PFS_single_stat * result)1906 void PFS_table_share::sum_lock(PFS_single_stat *result)
1907 {
1908 PFS_table_share_lock *lock_stat;
1909 lock_stat= find_lock_stat();
1910 if (lock_stat != NULL)
1911 lock_stat->m_stat.sum(result);
1912 }
1913
sum(PFS_single_stat * result,uint key_count)1914 void PFS_table_share::sum(PFS_single_stat *result, uint key_count)
1915 {
1916 sum_io(result, key_count);
1917 sum_lock(result);
1918 }
1919
aggregate_lock(void)1920 void PFS_table_share::aggregate_lock(void)
1921 {
1922 PFS_table_share_lock *lock_stat;
1923 lock_stat= find_lock_stat();
1924 if (lock_stat != NULL)
1925 {
1926 global_table_lock_stat.aggregate(& lock_stat->m_stat);
1927 /* Reset lock stat. */
1928 lock_stat->m_stat.reset();
1929 }
1930 }
1931
release_table_share(PFS_table_share * pfs)1932 void release_table_share(PFS_table_share *pfs)
1933 {
1934 assert(pfs->get_refcount() > 0);
1935 pfs->dec_refcount();
1936 }
1937
1938 /**
1939 Drop the instrumented table share associated with a table.
1940 @param thread The running thread
1941 @param temporary True for TEMPORARY TABLE
1942 @param schema_name The table schema name
1943 @param schema_name_length The table schema name length
1944 @param table_name The table name
1945 @param table_name_length The table name length
1946 */
drop_table_share(PFS_thread * thread,bool temporary,const char * schema_name,uint schema_name_length,const char * table_name,uint table_name_length)1947 void drop_table_share(PFS_thread *thread,
1948 bool temporary,
1949 const char *schema_name, uint schema_name_length,
1950 const char *table_name, uint table_name_length)
1951 {
1952 PFS_table_share_key key;
1953 LF_PINS* pins= get_table_share_hash_pins(thread);
1954 if (unlikely(pins == NULL))
1955 return;
1956 set_table_share_key(&key, temporary, schema_name, schema_name_length,
1957 table_name, table_name_length);
1958 PFS_table_share **entry;
1959 entry= reinterpret_cast<PFS_table_share**>
1960 (lf_hash_search(&table_share_hash, pins,
1961 key.m_hash_key, key.m_key_length));
1962 if (entry && (entry != MY_ERRPTR))
1963 {
1964 PFS_table_share *pfs= *entry;
1965 lf_hash_delete(&table_share_hash, pins,
1966 pfs->m_key.m_hash_key, pfs->m_key.m_key_length);
1967 pfs->destroy_lock_stat();
1968 pfs->destroy_index_stats();
1969
1970 pfs->m_lock.allocated_to_free();
1971 }
1972
1973 lf_hash_search_unpin(pins);
1974 }
1975
1976 /**
1977 Sanitize an unsafe table_share pointer.
1978 @param unsafe The possibly corrupt pointer.
1979 @return A valid table_safe_pointer, or NULL.
1980 */
sanitize_table_share(PFS_table_share * unsafe)1981 PFS_table_share *sanitize_table_share(PFS_table_share *unsafe)
1982 {
1983 return global_table_share_container.sanitize(unsafe);
1984 }
1985
1986 /** Reset the wait statistics per instrument class. */
reset_events_waits_by_class()1987 void reset_events_waits_by_class()
1988 {
1989 reset_file_class_io();
1990 reset_socket_class_io();
1991 global_idle_stat.reset();
1992 global_table_io_stat.reset();
1993 global_table_lock_stat.reset();
1994 global_metadata_stat.reset();
1995 }
1996
1997 /** Reset the io statistics per file class. */
reset_file_class_io(void)1998 void reset_file_class_io(void)
1999 {
2000 PFS_file_class *pfs= file_class_array;
2001 PFS_file_class *pfs_last= file_class_array + file_class_max;
2002
2003 for ( ; pfs < pfs_last; pfs++)
2004 pfs->m_file_stat.m_io_stat.reset();
2005 }
2006
2007 /** Reset the io statistics per socket class. */
reset_socket_class_io(void)2008 void reset_socket_class_io(void)
2009 {
2010 PFS_socket_class *pfs= socket_class_array;
2011 PFS_socket_class *pfs_last= socket_class_array + socket_class_max;
2012
2013 for ( ; pfs < pfs_last; pfs++)
2014 pfs->m_socket_stat.m_io_stat.reset();
2015 }
2016
2017 class Proc_table_share_derived_flags
2018 : public PFS_buffer_processor<PFS_table_share>
2019 {
2020 public:
Proc_table_share_derived_flags(PFS_thread * thread)2021 Proc_table_share_derived_flags(PFS_thread *thread)
2022 : m_thread(thread)
2023 {}
2024
operator ()(PFS_table_share * pfs)2025 virtual void operator()(PFS_table_share *pfs)
2026 {
2027 pfs->refresh_setup_object_flags(m_thread);
2028 }
2029
2030 private:
2031 PFS_thread* m_thread;
2032 };
2033
update_table_share_derived_flags(PFS_thread * thread)2034 void update_table_share_derived_flags(PFS_thread *thread)
2035 {
2036 Proc_table_share_derived_flags proc(thread);
2037 global_table_share_container.apply(proc);
2038 }
2039
2040 class Proc_program_share_derived_flags
2041 : public PFS_buffer_processor<PFS_program>
2042 {
2043 public:
Proc_program_share_derived_flags(PFS_thread * thread)2044 Proc_program_share_derived_flags(PFS_thread *thread)
2045 : m_thread(thread)
2046 {}
2047
operator ()(PFS_program * pfs)2048 virtual void operator()(PFS_program *pfs)
2049 {
2050 pfs->refresh_setup_object_flags(m_thread);
2051 }
2052
2053 private:
2054 PFS_thread* m_thread;
2055 };
2056
update_program_share_derived_flags(PFS_thread * thread)2057 void update_program_share_derived_flags(PFS_thread *thread)
2058 {
2059 Proc_program_share_derived_flags proc(thread);
2060 global_program_container.apply(proc);
2061 }
2062
2063 /** @} */
2064
2065