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