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