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