1 /* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
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 "structs.h"
32 #include "table.h"
33 #include "pfs_instr_class.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 "mysql/psi/mysql_thread.h"
41 #include "lf.h"
42 
43 #include <string.h>
44 
45 /**
46   @defgroup Performance_schema_buffers Performance Schema Buffers
47   @ingroup Performance_schema_implementation
48   @{
49 */
50 
51 /**
52   PFS_INSTRUMENT option settings array and associated state variable to
53   serialize access during shutdown.
54  */
55 DYNAMIC_ARRAY pfs_instr_config_array;
56 int pfs_instr_config_state= PFS_INSTR_CONFIG_NOT_INITIALIZED;
57 
58 static void configure_instr_class(PFS_instr_class *entry);
59 
60 static void init_instr_class(PFS_instr_class *klass,
61                              const char *name,
62                              uint name_length,
63                              int flags,
64                              PFS_class_type class_type);
65 
66 /**
67   Current number of elements in mutex_class_array.
68   This global variable is written to during:
69   - the performance schema initialization
70   - a plugin initialization
71 */
72 static volatile uint32 mutex_class_dirty_count= 0;
73 static volatile uint32 mutex_class_allocated_count= 0;
74 static volatile uint32 rwlock_class_dirty_count= 0;
75 static volatile uint32 rwlock_class_allocated_count= 0;
76 static volatile uint32 cond_class_dirty_count= 0;
77 static volatile uint32 cond_class_allocated_count= 0;
78 
79 /** Size of the mutex class array. @sa mutex_class_array */
80 ulong mutex_class_max= 0;
81 /** Number of mutex class lost. @sa mutex_class_array */
82 ulong mutex_class_lost= 0;
83 /** Size of the rwlock class array. @sa rwlock_class_array */
84 ulong rwlock_class_max= 0;
85 /** Number of rwlock class lost. @sa rwlock_class_array */
86 ulong rwlock_class_lost= 0;
87 /** Size of the condition class array. @sa cond_class_array */
88 ulong cond_class_max= 0;
89 /** Number of condition class lost. @sa cond_class_array */
90 ulong cond_class_lost= 0;
91 /** Size of the thread class array. @sa thread_class_array */
92 ulong thread_class_max= 0;
93 /** Number of thread class lost. @sa thread_class_array */
94 ulong thread_class_lost= 0;
95 /** Size of the file class array. @sa file_class_array */
96 ulong file_class_max= 0;
97 /** Number of file class lost. @sa file_class_array */
98 ulong file_class_lost= 0;
99 /** Size of the stage class array. @sa stage_class_array */
100 ulong stage_class_max= 0;
101 /** Number of stage class lost. @sa stage_class_array */
102 ulong stage_class_lost= 0;
103 /** Size of the statement class array. @sa statement_class_array */
104 ulong statement_class_max= 0;
105 /** Number of statement class lost. @sa statement_class_array */
106 ulong statement_class_lost= 0;
107 /** Size of the table share array. @sa table_share_array */
108 ulong table_share_max= 0;
109 /** Number of table share lost. @sa table_share_array */
110 ulong table_share_lost= 0;
111 /** Size of the socket class array. @sa socket_class_array */
112 ulong socket_class_max= 0;
113 /** Number of socket class lost. @sa socket_class_array */
114 ulong socket_class_lost= 0;
115 
116 PFS_mutex_class *mutex_class_array= NULL;
117 PFS_rwlock_class *rwlock_class_array= NULL;
118 PFS_cond_class *cond_class_array= NULL;
119 
120 /**
121   Current number or elements in thread_class_array.
122   This global variable is written to during:
123   - the performance schema initialization
124   - a plugin initialization
125 */
126 static volatile uint32 thread_class_dirty_count= 0;
127 static volatile uint32 thread_class_allocated_count= 0;
128 
129 static PFS_thread_class *thread_class_array= NULL;
130 
131 /**
132   Table instance array.
133   @sa table_share_max
134   @sa table_share_lost
135   @sa table_share_hash
136 */
137 PFS_table_share *table_share_array= NULL;
138 
139 PFS_ALIGNED PFS_single_stat global_idle_stat;
140 PFS_ALIGNED PFS_table_io_stat global_table_io_stat;
141 PFS_ALIGNED PFS_table_lock_stat global_table_lock_stat;
142 PFS_ALIGNED PFS_instr_class global_table_io_class;
143 PFS_ALIGNED PFS_instr_class global_table_lock_class;
144 PFS_ALIGNED PFS_instr_class global_idle_class;
145 
146 /** Class-timer map */
147 enum_timer_name *class_timers[] =
148 {&wait_timer,      /* PFS_CLASS_NONE */
149  &wait_timer,      /* PFS_CLASS_MUTEX */
150  &wait_timer,      /* PFS_CLASS_RWLOCK */
151  &wait_timer,      /* PFS_CLASS_COND */
152  &wait_timer,      /* PFS_CLASS_FILE */
153  &wait_timer,      /* PFS_CLASS_TABLE */
154  &stage_timer,     /* PFS_CLASS_STAGE */
155  &statement_timer, /* PFS_CLASS_STATEMENT */
156  &wait_timer,      /* PFS_CLASS_SOCKET */
157  &wait_timer,      /* PFS_CLASS_TABLE_IO */
158  &wait_timer,      /* PFS_CLASS_TABLE_LOCK */
159  &idle_timer       /* PFS_CLASS_IDLE */
160 };
161 
162 /**
163   Hash index for instrumented table shares.
164   This index is searched by table fully qualified name (@c PFS_table_share_key),
165   and points to instrumented table shares (@c PFS_table_share).
166   @sa table_share_array
167   @sa PFS_table_share_key
168   @sa PFS_table_share
169   @sa table_share_hash_get_key
170   @sa get_table_share_hash_pins
171 */
172 LF_HASH table_share_hash;
173 /** True if table_share_hash is initialized. */
174 static bool table_share_hash_inited= false;
175 
176 static volatile uint32 file_class_dirty_count= 0;
177 static volatile uint32 file_class_allocated_count= 0;
178 
179 PFS_file_class *file_class_array= NULL;
180 
181 static volatile uint32 stage_class_dirty_count= 0;
182 static volatile uint32 stage_class_allocated_count= 0;
183 
184 static PFS_stage_class *stage_class_array= NULL;
185 
186 static volatile uint32 statement_class_dirty_count= 0;
187 static volatile uint32 statement_class_allocated_count= 0;
188 
189 static PFS_statement_class *statement_class_array= NULL;
190 
191 static volatile uint32 socket_class_dirty_count= 0;
192 static volatile uint32 socket_class_allocated_count= 0;
193 
194 static PFS_socket_class *socket_class_array= NULL;
195 
196 uint mutex_class_start= 0;
197 uint rwlock_class_start= 0;
198 uint cond_class_start= 0;
199 uint file_class_start= 0;
200 uint wait_class_max= 0;
201 uint socket_class_start= 0;
202 
init_event_name_sizing(const PFS_global_param * param)203 void init_event_name_sizing(const PFS_global_param *param)
204 {
205   mutex_class_start= 3; /* global table io, table lock, idle */
206   rwlock_class_start= mutex_class_start + param->m_mutex_class_sizing;
207   cond_class_start= rwlock_class_start + param->m_rwlock_class_sizing;
208   file_class_start= cond_class_start + param->m_cond_class_sizing;
209   socket_class_start= file_class_start + param->m_file_class_sizing;
210   wait_class_max= socket_class_start + param->m_socket_class_sizing;
211 }
212 
register_global_classes()213 void register_global_classes()
214 {
215   /* Table IO class */
216   init_instr_class(&global_table_io_class, "wait/io/table/sql/handler", 25,
217                    0, PFS_CLASS_TABLE_IO);
218   global_table_io_class.m_event_name_index= GLOBAL_TABLE_IO_EVENT_INDEX;
219   configure_instr_class(&global_table_io_class);
220 
221   /* Table lock class */
222   init_instr_class(&global_table_lock_class, "wait/lock/table/sql/handler", 27,
223                    0, PFS_CLASS_TABLE_LOCK);
224   global_table_lock_class.m_event_name_index= GLOBAL_TABLE_LOCK_EVENT_INDEX;
225   configure_instr_class(&global_table_lock_class);
226 
227   /* Idle class */
228   init_instr_class(&global_idle_class, "idle", 4,
229                    0, PFS_CLASS_IDLE);
230   global_idle_class.m_event_name_index= GLOBAL_IDLE_EVENT_INDEX;
231   configure_instr_class(&global_idle_class);
232 }
233 
234 /**
235   Initialize the instrument synch class buffers.
236   @param mutex_class_sizing           max number of mutex class
237   @param rwlock_class_sizing          max number of rwlock class
238   @param cond_class_sizing            max number of condition class
239   @return 0 on success
240 */
init_sync_class(uint mutex_class_sizing,uint rwlock_class_sizing,uint cond_class_sizing)241 int init_sync_class(uint mutex_class_sizing,
242                     uint rwlock_class_sizing,
243                     uint cond_class_sizing)
244 {
245   mutex_class_dirty_count= mutex_class_allocated_count= 0;
246   rwlock_class_dirty_count= rwlock_class_allocated_count= 0;
247   cond_class_dirty_count= cond_class_allocated_count= 0;
248   mutex_class_max= mutex_class_sizing;
249   rwlock_class_max= rwlock_class_sizing;
250   cond_class_max= cond_class_sizing;
251   mutex_class_lost= rwlock_class_lost= cond_class_lost= 0;
252 
253   mutex_class_array= NULL;
254   rwlock_class_array= NULL;
255   cond_class_array= NULL;
256 
257   if (mutex_class_max > 0)
258   {
259     mutex_class_array= PFS_MALLOC_ARRAY(mutex_class_max, sizeof(PFS_mutex_class),
260                                         PFS_mutex_class, MYF(MY_ZEROFILL));
261     if (unlikely(mutex_class_array == NULL))
262       return 1;
263   }
264 
265   if (rwlock_class_max > 0)
266   {
267     rwlock_class_array= PFS_MALLOC_ARRAY(rwlock_class_max, sizeof(PFS_rwlock_class),
268                                          PFS_rwlock_class, MYF(MY_ZEROFILL));
269     if (unlikely(rwlock_class_array == NULL))
270       return 1;
271   }
272 
273   if (cond_class_max > 0)
274   {
275     cond_class_array= PFS_MALLOC_ARRAY(cond_class_max, sizeof(PFS_cond_class),
276                                        PFS_cond_class, MYF(MY_ZEROFILL));
277     if (unlikely(cond_class_array == NULL))
278       return 1;
279   }
280 
281   return 0;
282 }
283 
284 /** Cleanup the instrument synch class buffers. */
cleanup_sync_class(void)285 void cleanup_sync_class(void)
286 {
287   pfs_free(mutex_class_array);
288   mutex_class_array= NULL;
289   mutex_class_dirty_count= mutex_class_allocated_count= mutex_class_max= 0;
290   pfs_free(rwlock_class_array);
291   rwlock_class_array= NULL;
292   rwlock_class_dirty_count= rwlock_class_allocated_count= rwlock_class_max= 0;
293   pfs_free(cond_class_array);
294   cond_class_array= NULL;
295   cond_class_dirty_count= cond_class_allocated_count= cond_class_max= 0;
296 }
297 
298 /**
299   Initialize the thread class buffer.
300   @param thread_class_sizing          max number of thread class
301   @return 0 on success
302 */
init_thread_class(uint thread_class_sizing)303 int init_thread_class(uint thread_class_sizing)
304 {
305   int result= 0;
306   thread_class_dirty_count= thread_class_allocated_count= 0;
307   thread_class_max= thread_class_sizing;
308   thread_class_lost= 0;
309 
310   if (thread_class_max > 0)
311   {
312     thread_class_array= PFS_MALLOC_ARRAY(thread_class_max, sizeof(PFS_thread_class),
313                                          PFS_thread_class, MYF(MY_ZEROFILL));
314     if (unlikely(thread_class_array == NULL))
315       result= 1;
316   }
317   else
318     thread_class_array= NULL;
319 
320   return result;
321 }
322 
323 /** Cleanup the thread class buffers. */
cleanup_thread_class(void)324 void cleanup_thread_class(void)
325 {
326   pfs_free(thread_class_array);
327   thread_class_array= NULL;
328   thread_class_dirty_count= thread_class_allocated_count= 0;
329   thread_class_max= 0;
330 }
331 
332 /**
333   Initialize the table share buffer.
334   @param table_share_sizing           max number of table share
335   @return 0 on success
336 */
init_table_share(uint table_share_sizing)337 int init_table_share(uint table_share_sizing)
338 {
339   int result= 0;
340   table_share_max= table_share_sizing;
341   table_share_lost= 0;
342 
343   if (table_share_max > 0)
344   {
345     table_share_array= PFS_MALLOC_ARRAY(table_share_max, sizeof(PFS_table_share),
346                                         PFS_table_share, MYF(MY_ZEROFILL));
347     if (unlikely(table_share_array == NULL))
348       result= 1;
349   }
350   else
351     table_share_array= NULL;
352 
353   return result;
354 }
355 
356 /** Cleanup the table share buffers. */
cleanup_table_share(void)357 void cleanup_table_share(void)
358 {
359   pfs_free(table_share_array);
360   table_share_array= NULL;
361   table_share_max= 0;
362 }
363 
364 C_MODE_START
365 /** get_key function for @c table_share_hash. */
table_share_hash_get_key(const uchar * entry,size_t * length,my_bool)366 static uchar *table_share_hash_get_key(const uchar *entry, size_t *length,
367                                        my_bool)
368 {
369   const PFS_table_share * const *typed_entry;
370   const PFS_table_share *share;
371   const void *result;
372   typed_entry= reinterpret_cast<const PFS_table_share* const *> (entry);
373   DBUG_ASSERT(typed_entry != NULL);
374   share= *typed_entry;
375   DBUG_ASSERT(share != NULL);
376   *length= share->m_key.m_key_length;
377   result= &share->m_key.m_hash_key[0];
378   return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
379 }
380 C_MODE_END
381 
382 /** Initialize the table share hash table. */
init_table_share_hash(void)383 int init_table_share_hash(void)
384 {
385   if ((! table_share_hash_inited) && (table_share_max > 0))
386   {
387     lf_hash_init(&table_share_hash, sizeof(PFS_table_share*), LF_HASH_UNIQUE,
388                  0, 0, table_share_hash_get_key, &my_charset_bin);
389     /* table_share_hash.size= table_share_max; */
390     table_share_hash_inited= true;
391   }
392   return 0;
393 }
394 
395 /** Cleanup the table share hash table. */
cleanup_table_share_hash(void)396 void cleanup_table_share_hash(void)
397 {
398   if (table_share_hash_inited)
399   {
400     lf_hash_destroy(&table_share_hash);
401     table_share_hash_inited= false;
402   }
403 }
404 
405 /**
406   Get the hash pins for @sa table_share_hash.
407   @param thread The running thread.
408   @returns The LF_HASH pins for the thread.
409 */
get_table_share_hash_pins(PFS_thread * thread)410 LF_PINS* get_table_share_hash_pins(PFS_thread *thread)
411 {
412   if (unlikely(thread->m_table_share_hash_pins == NULL))
413   {
414     if (! table_share_hash_inited)
415       return NULL;
416     thread->m_table_share_hash_pins= lf_hash_get_pins(&table_share_hash);
417   }
418   return thread->m_table_share_hash_pins;
419 }
420 
421 /**
422   Set a table share hash key.
423   @param [out] key The key to populate.
424   @param temporary True for TEMPORARY TABLE.
425   @param schema_name The table schema name.
426   @param schema_name_length The table schema name length.
427   @param table_name The table name.
428   @param table_name_length The table name length.
429 */
set_table_share_key(PFS_table_share_key * key,bool temporary,const char * schema_name,uint schema_name_length,const char * table_name,uint table_name_length)430 static void set_table_share_key(PFS_table_share_key *key,
431                                 bool temporary,
432                                 const char *schema_name, uint schema_name_length,
433                                 const char *table_name, uint table_name_length)
434 {
435   DBUG_ASSERT(schema_name_length <= NAME_LEN);
436   DBUG_ASSERT(table_name_length <= NAME_LEN);
437   char *saved_schema_name;
438   char *saved_table_name;
439 
440   char *ptr= &key->m_hash_key[0];
441   ptr[0]= (temporary ? OBJECT_TYPE_TEMPORARY_TABLE : OBJECT_TYPE_TABLE);
442   ptr++;
443   saved_schema_name= ptr;
444   memcpy(ptr, schema_name, schema_name_length);
445   ptr+= schema_name_length;
446   ptr[0]= 0;
447   ptr++;
448   saved_table_name= ptr;
449   memcpy(ptr, table_name, table_name_length);
450   ptr+= table_name_length;
451   ptr[0]= 0;
452   ptr++;
453   key->m_key_length= (uint)(ptr - &key->m_hash_key[0]);
454 
455   if (lower_case_table_names)
456   {
457     my_casedn_str(files_charset_info, saved_schema_name);
458     my_casedn_str(files_charset_info, saved_table_name);
459   }
460 }
461 
refresh_setup_object_flags(PFS_thread * thread)462 void PFS_table_share::refresh_setup_object_flags(PFS_thread *thread)
463 {
464   lookup_setup_object(thread,
465                       OBJECT_TYPE_TABLE,
466                       m_schema_name, m_schema_name_length,
467                       m_table_name, m_table_name_length,
468                       &m_enabled, &m_timed);
469 }
470 
471 /**
472   Initialize the file class buffer.
473   @param file_class_sizing            max number of file class
474   @return 0 on success
475 */
init_file_class(uint file_class_sizing)476 int init_file_class(uint file_class_sizing)
477 {
478   int result= 0;
479   file_class_dirty_count= file_class_allocated_count= 0;
480   file_class_max= file_class_sizing;
481   file_class_lost= 0;
482 
483   if (file_class_max > 0)
484   {
485     file_class_array= PFS_MALLOC_ARRAY(file_class_max, sizeof(PFS_file_class),
486                                        PFS_file_class, MYF(MY_ZEROFILL));
487     if (unlikely(file_class_array == NULL))
488       return 1;
489   }
490   else
491     file_class_array= NULL;
492 
493   return result;
494 }
495 
496 /** Cleanup the file class buffers. */
cleanup_file_class(void)497 void cleanup_file_class(void)
498 {
499   pfs_free(file_class_array);
500   file_class_array= NULL;
501   file_class_dirty_count= file_class_allocated_count= 0;
502   file_class_max= 0;
503 }
504 
505 /**
506   Initialize the stage class buffer.
507   @param stage_class_sizing            max number of stage class
508   @return 0 on success
509 */
init_stage_class(uint stage_class_sizing)510 int init_stage_class(uint stage_class_sizing)
511 {
512   int result= 0;
513   stage_class_dirty_count= stage_class_allocated_count= 0;
514   stage_class_max= stage_class_sizing;
515   stage_class_lost= 0;
516 
517   if (stage_class_max > 0)
518   {
519     stage_class_array= PFS_MALLOC_ARRAY(stage_class_max, sizeof(PFS_stage_class),
520                                         PFS_stage_class, MYF(MY_ZEROFILL));
521     if (unlikely(stage_class_array == NULL))
522       return 1;
523   }
524   else
525     stage_class_array= NULL;
526 
527   return result;
528 }
529 
530 /** Cleanup the stage class buffers. */
cleanup_stage_class(void)531 void cleanup_stage_class(void)
532 {
533   pfs_free(stage_class_array);
534   stage_class_array= NULL;
535   stage_class_dirty_count= stage_class_allocated_count= 0;
536   stage_class_max= 0;
537 }
538 
539 /**
540   Initialize the statement class buffer.
541   @param statement_class_sizing            max number of statement class
542   @return 0 on success
543 */
init_statement_class(uint statement_class_sizing)544 int init_statement_class(uint statement_class_sizing)
545 {
546   int result= 0;
547   statement_class_dirty_count= statement_class_allocated_count= 0;
548   statement_class_max= statement_class_sizing;
549   statement_class_lost= 0;
550 
551   if (statement_class_max > 0)
552   {
553     statement_class_array= PFS_MALLOC_ARRAY(statement_class_max, sizeof(PFS_statement_class),
554                                             PFS_statement_class, MYF(MY_ZEROFILL));
555     if (unlikely(statement_class_array == NULL))
556       return 1;
557   }
558   else
559     statement_class_array= NULL;
560 
561   return result;
562 }
563 
564 /** Cleanup the statement class buffers. */
cleanup_statement_class(void)565 void cleanup_statement_class(void)
566 {
567   pfs_free(statement_class_array);
568   statement_class_array= NULL;
569   statement_class_dirty_count= statement_class_allocated_count= 0;
570   statement_class_max= 0;
571 }
572 
573 /**
574   Initialize the socket class buffer.
575   @param socket_class_sizing            max number of socket class
576   @return 0 on success
577 */
init_socket_class(uint socket_class_sizing)578 int init_socket_class(uint socket_class_sizing)
579 {
580   int result= 0;
581   socket_class_dirty_count= socket_class_allocated_count= 0;
582   socket_class_max= socket_class_sizing;
583   socket_class_lost= 0;
584 
585   if (socket_class_max > 0)
586   {
587     socket_class_array= PFS_MALLOC_ARRAY(socket_class_max, sizeof(PFS_socket_class),
588                                          PFS_socket_class, MYF(MY_ZEROFILL));
589     if (unlikely(socket_class_array == NULL))
590       return 1;
591   }
592   else
593     socket_class_array= NULL;
594 
595   return result;
596 }
597 
598 /** Cleanup the socket class buffers. */
cleanup_socket_class(void)599 void cleanup_socket_class(void)
600 {
601   pfs_free(socket_class_array);
602   socket_class_array= NULL;
603   socket_class_dirty_count= socket_class_allocated_count= 0;
604   socket_class_max= 0;
605 }
606 
init_instr_class(PFS_instr_class * klass,const char * name,uint name_length,int flags,PFS_class_type class_type)607 static void init_instr_class(PFS_instr_class *klass,
608                              const char *name,
609                              uint name_length,
610                              int flags,
611                              PFS_class_type class_type)
612 {
613   DBUG_ASSERT(name_length <= PFS_MAX_INFO_NAME_LENGTH);
614   memset(klass, 0, sizeof(PFS_instr_class));
615   strncpy(klass->m_name, name, name_length);
616   klass->m_name[PFS_MAX_INFO_NAME_LENGTH - 1]= '\0';
617   klass->m_name_length= name_length;
618   klass->m_flags= flags;
619   klass->m_enabled= true;
620   klass->m_timed= true;
621   klass->m_type= class_type;
622   klass->m_timer= class_timers[class_type];
623 }
624 
625 /**
626   Set user-defined configuration values for an instrument.
627 */
configure_instr_class(PFS_instr_class * entry)628 static void configure_instr_class(PFS_instr_class *entry)
629 {
630   uint match_length= 0; /* length of matching pattern */
631 
632   for (uint i= 0; i < pfs_instr_config_array.elements; i++)
633   {
634     PFS_instr_config* e;
635     get_dynamic(&pfs_instr_config_array, (uchar*)&e, i);
636 
637     /**
638       Compare class name to all configuration entries. In case of multiple
639       matches, the longer specification wins. For example, the pattern
640       'ABC/DEF/GHI=ON' has precedence over 'ABC/DEF/%=OFF' regardless of
641       position within the configuration file or command line.
642 
643       Consecutive wildcards affect the count.
644     */
645     if (!my_wildcmp(&my_charset_latin1,
646                     entry->m_name, entry->m_name+entry->m_name_length,
647                     e->m_name, e->m_name+e->m_name_length,
648                     '\\', '?','%'))
649     {
650         if (e->m_name_length >= match_length)
651         {
652            entry->m_enabled= e->m_enabled;
653            entry->m_timed= e->m_timed;
654            match_length= MY_MAX(e->m_name_length, match_length);
655         }
656     }
657   }
658 }
659 
660 #define REGISTER_CLASS_BODY_PART(INDEX, ARRAY, MAX, NAME, NAME_LENGTH) \
661   for (INDEX= 0; INDEX < MAX; INDEX++)                                 \
662   {                                                                    \
663     entry= &ARRAY[INDEX];                                              \
664     if ((entry->m_name_length == NAME_LENGTH) &&                       \
665         (strncmp(entry->m_name, NAME, NAME_LENGTH) == 0))              \
666     {                                                                  \
667       DBUG_ASSERT(entry->m_flags == flags);                            \
668       return (INDEX + 1);                                              \
669     }                                                                  \
670   }
671 
672 /**
673   Register a mutex instrumentation metadata.
674   @param name                         the instrumented name
675   @param name_length                  length in bytes of name
676   @param flags                        the instrumentation flags
677   @return a mutex instrumentation key
678 */
register_mutex_class(const char * name,uint name_length,int flags)679 PFS_sync_key register_mutex_class(const char *name, uint name_length,
680                                   int flags)
681 {
682   uint32 index;
683   PFS_mutex_class *entry;
684 
685   /*
686     This is a full array scan, which is not optimal.
687     This is acceptable since this code is only used at startup,
688     or when a plugin is loaded.
689   */
690   REGISTER_CLASS_BODY_PART(index, mutex_class_array, mutex_class_max,
691                            name, name_length)
692   /*
693     Note that:
694     mutex_class_dirty_count is incremented *before* an entry is added
695     mutex_class_allocated_count is incremented *after* an entry is added
696   */
697   index= PFS_atomic::add_u32(&mutex_class_dirty_count, 1);
698 
699   if (index < mutex_class_max)
700   {
701     /*
702       The instrument was not found (from a possible previous
703       load / unload of a plugin), allocate it.
704       This code is safe when 2 threads execute in parallel
705       for different mutex classes:
706       - thread 1 registering class A
707       - thread 2 registering class B
708       will not collide in the same mutex_class_array[index] entry.
709       This code does not protect against 2 threads registering
710       in parallel the same class:
711       - thread 1 registering class A
712       - thread 2 registering class A
713       could lead to a duplicate class A entry.
714       This is ok, since this case can not happen in the caller:
715       - classes names are derived from a plugin name
716         ('wait/synch/mutex/<plugin>/xxx')
717       - 2 threads can not register concurrently the same plugin
718         in INSTALL PLUGIN.
719     */
720     entry= &mutex_class_array[index];
721     init_instr_class(entry, name, name_length, flags, PFS_CLASS_MUTEX);
722     entry->m_mutex_stat.reset();
723     entry->m_event_name_index= mutex_class_start + index;
724     entry->m_singleton= NULL;
725     entry->m_enabled= false; /* disabled by default */
726     entry->m_timed= false;
727 
728     /* Set user-defined configuration options for this instrument */
729     configure_instr_class(entry);
730 
731     /*
732       Now that this entry is populated, advertise it
733 
734       Technically, there is a small race condition here:
735       T0:
736       mutex_class_dirty_count= 10
737       mutex_class_allocated_count= 10
738       T1: Thread A increment mutex_class_dirty_count to 11
739       T2: Thread B increment mutex_class_dirty_count to 12
740       T3: Thread A populate entry 11
741       T4: Thread B populate entry 12
742       T5: Thread B increment mutex_class_allocated_count to 11,
743           advertise thread A incomplete record 11,
744           but does not advertise thread B complete record 12
745       T6: Thread A increment mutex_class_allocated_count to 12
746       This has no impact, and is acceptable.
747       A reader will not see record 12 for a short time.
748       A reader will see an incomplete record 11 for a short time,
749       which is ok: the mutex name / statistics will be temporarily
750       empty/NULL/zero, but this won't cause a crash
751       (mutex_class_array is initialized with MY_ZEROFILL).
752     */
753     PFS_atomic::add_u32(&mutex_class_allocated_count, 1);
754     return (index + 1);
755   }
756 
757   /*
758     Out of space, report to SHOW STATUS that
759     the allocated memory was too small.
760   */
761   mutex_class_lost++;
762   return 0;
763 }
764 
765 /**
766   Register a rwlock instrumentation metadata.
767   @param name                         the instrumented name
768   @param name_length                  length in bytes of name
769   @param flags                        the instrumentation flags
770   @return a rwlock instrumentation key
771 */
register_rwlock_class(const char * name,uint name_length,int flags)772 PFS_sync_key register_rwlock_class(const char *name, uint name_length,
773                                    int flags)
774 {
775   /* See comments in register_mutex_class */
776   uint32 index;
777   PFS_rwlock_class *entry;
778 
779   REGISTER_CLASS_BODY_PART(index, rwlock_class_array, rwlock_class_max,
780                            name, name_length)
781 
782   index= PFS_atomic::add_u32(&rwlock_class_dirty_count, 1);
783 
784   if (index < rwlock_class_max)
785   {
786     entry= &rwlock_class_array[index];
787     init_instr_class(entry, name, name_length, flags, PFS_CLASS_RWLOCK);
788     entry->m_rwlock_stat.reset();
789     entry->m_event_name_index= rwlock_class_start + index;
790     entry->m_singleton= NULL;
791     entry->m_enabled= false; /* disabled by default */
792     entry->m_timed= false;
793     /* Set user-defined configuration options for this instrument */
794     configure_instr_class(entry);
795     PFS_atomic::add_u32(&rwlock_class_allocated_count, 1);
796     return (index + 1);
797   }
798 
799   rwlock_class_lost++;
800   return 0;
801 }
802 
803 /**
804   Register a condition instrumentation metadata.
805   @param name                         the instrumented name
806   @param name_length                  length in bytes of name
807   @param flags                        the instrumentation flags
808   @return a condition instrumentation key
809 */
register_cond_class(const char * name,uint name_length,int flags)810 PFS_sync_key register_cond_class(const char *name, uint name_length,
811                                  int flags)
812 {
813   /* See comments in register_mutex_class */
814   uint32 index;
815   PFS_cond_class *entry;
816 
817   REGISTER_CLASS_BODY_PART(index, cond_class_array, cond_class_max,
818                            name, name_length)
819 
820   index= PFS_atomic::add_u32(&cond_class_dirty_count, 1);
821 
822   if (index < cond_class_max)
823   {
824     entry= &cond_class_array[index];
825     init_instr_class(entry, name, name_length, flags, PFS_CLASS_COND);
826     entry->m_event_name_index= cond_class_start + index;
827     entry->m_singleton= NULL;
828     entry->m_enabled= false; /* disabled by default */
829     entry->m_timed= false;
830     /* Set user-defined configuration options for this instrument */
831     configure_instr_class(entry);
832     PFS_atomic::add_u32(&cond_class_allocated_count, 1);
833     return (index + 1);
834   }
835 
836   cond_class_lost++;
837   return 0;
838 }
839 
840 #define FIND_CLASS_BODY(KEY, COUNT, ARRAY) \
841   if ((KEY == 0) || (KEY > COUNT))         \
842     return NULL;                           \
843   return &ARRAY[KEY - 1]
844 
845 /**
846   Find a mutex instrumentation class by key.
847   @param key                          the instrument key
848   @return the instrument class, or NULL
849 */
find_mutex_class(PFS_sync_key key)850 PFS_mutex_class *find_mutex_class(PFS_sync_key key)
851 {
852   FIND_CLASS_BODY(key, mutex_class_allocated_count, mutex_class_array);
853 }
854 
sanitize_mutex_class(PFS_mutex_class * unsafe)855 PFS_mutex_class *sanitize_mutex_class(PFS_mutex_class *unsafe)
856 {
857   SANITIZE_ARRAY_BODY(PFS_mutex_class, mutex_class_array, mutex_class_max, unsafe);
858 }
859 
860 /**
861   Find a rwlock instrumentation class by key.
862   @param key                          the instrument key
863   @return the instrument class, or NULL
864 */
find_rwlock_class(PFS_sync_key key)865 PFS_rwlock_class *find_rwlock_class(PFS_sync_key key)
866 {
867   FIND_CLASS_BODY(key, rwlock_class_allocated_count, rwlock_class_array);
868 }
869 
sanitize_rwlock_class(PFS_rwlock_class * unsafe)870 PFS_rwlock_class *sanitize_rwlock_class(PFS_rwlock_class *unsafe)
871 {
872   SANITIZE_ARRAY_BODY(PFS_rwlock_class, rwlock_class_array, rwlock_class_max, unsafe);
873 }
874 
875 /**
876   Find a condition instrumentation class by key.
877   @param key                          the instrument key
878   @return the instrument class, or NULL
879 */
find_cond_class(PFS_sync_key key)880 PFS_cond_class *find_cond_class(PFS_sync_key key)
881 {
882   FIND_CLASS_BODY(key, cond_class_allocated_count, cond_class_array);
883 }
884 
sanitize_cond_class(PFS_cond_class * unsafe)885 PFS_cond_class *sanitize_cond_class(PFS_cond_class *unsafe)
886 {
887   SANITIZE_ARRAY_BODY(PFS_cond_class, cond_class_array, cond_class_max, unsafe);
888 }
889 
890 /**
891   Register a thread instrumentation metadata.
892   @param name                         the instrumented name
893   @param name_length                  length in bytes of name
894   @param flags                        the instrumentation flags
895   @return a thread instrumentation key
896 */
register_thread_class(const char * name,uint name_length,int flags)897 PFS_thread_key register_thread_class(const char *name, uint name_length,
898                                      int flags)
899 {
900   /* See comments in register_mutex_class */
901   uint32 index;
902   PFS_thread_class *entry;
903 
904   for (index= 0; index < thread_class_max; index++)
905   {
906     entry= &thread_class_array[index];
907 
908     if ((entry->m_name_length == name_length) &&
909         (strncmp(entry->m_name, name, name_length) == 0))
910       return (index + 1);
911   }
912 
913   index= PFS_atomic::add_u32(&thread_class_dirty_count, 1);
914 
915   if (index < thread_class_max)
916   {
917     entry= &thread_class_array[index];
918     DBUG_ASSERT(name_length <= PFS_MAX_INFO_NAME_LENGTH);
919     strncpy(entry->m_name, name, name_length);
920     entry->m_name_length= name_length;
921     entry->m_enabled= true;
922     PFS_atomic::add_u32(&thread_class_allocated_count, 1);
923     return (index + 1);
924   }
925 
926   thread_class_lost++;
927   return 0;
928 }
929 
930 /**
931   Find a thread instrumentation class by key.
932   @param key                          the instrument key
933   @return the instrument class, or NULL
934 */
find_thread_class(PFS_sync_key key)935 PFS_thread_class *find_thread_class(PFS_sync_key key)
936 {
937   FIND_CLASS_BODY(key, thread_class_allocated_count, thread_class_array);
938 }
939 
sanitize_thread_class(PFS_thread_class * unsafe)940 PFS_thread_class *sanitize_thread_class(PFS_thread_class *unsafe)
941 {
942   SANITIZE_ARRAY_BODY(PFS_thread_class, thread_class_array, thread_class_max, unsafe);
943 }
944 
945 /**
946   Register a file instrumentation metadata.
947   @param name                         the instrumented name
948   @param name_length                  length in bytes of name
949   @param flags                        the instrumentation flags
950   @return a file instrumentation key
951 */
register_file_class(const char * name,uint name_length,int flags)952 PFS_file_key register_file_class(const char *name, uint name_length,
953                                  int flags)
954 {
955   /* See comments in register_mutex_class */
956   uint32 index;
957   PFS_file_class *entry;
958 
959   REGISTER_CLASS_BODY_PART(index, file_class_array, file_class_max,
960                            name, name_length)
961 
962   index= PFS_atomic::add_u32(&file_class_dirty_count, 1);
963 
964   if (index < file_class_max)
965   {
966     entry= &file_class_array[index];
967     init_instr_class(entry, name, name_length, flags, PFS_CLASS_FILE);
968     entry->m_event_name_index= file_class_start + index;
969     entry->m_singleton= NULL;
970     entry->m_enabled= true; /* enabled by default */
971     entry->m_timed= true;
972     /* Set user-defined configuration options for this instrument */
973     configure_instr_class(entry);
974     PFS_atomic::add_u32(&file_class_allocated_count, 1);
975     return (index + 1);
976   }
977 
978   file_class_lost++;
979   return 0;
980 }
981 
982 /**
983   Register a stage instrumentation metadata.
984   @param name                         the instrumented name
985   @param prefix_length                length in bytes of the name prefix
986   @param name_length                  length in bytes of name
987   @param flags                        the instrumentation flags
988   @return a stage instrumentation key
989 */
register_stage_class(const char * name,uint prefix_length,uint name_length,int flags)990 PFS_stage_key register_stage_class(const char *name,
991                                    uint prefix_length,
992                                    uint name_length,
993                                    int flags)
994 {
995   /* See comments in register_mutex_class */
996   uint32 index;
997   PFS_stage_class *entry;
998 
999   REGISTER_CLASS_BODY_PART(index, stage_class_array, stage_class_max,
1000                            name, name_length)
1001 
1002   index= PFS_atomic::add_u32(&stage_class_dirty_count, 1);
1003 
1004   if (index < stage_class_max)
1005   {
1006     entry= &stage_class_array[index];
1007     init_instr_class(entry, name, name_length, flags, PFS_CLASS_STAGE);
1008     entry->m_prefix_length= prefix_length;
1009     entry->m_event_name_index= index;
1010     entry->m_enabled= false; /* disabled by default */
1011     entry->m_timed= false;
1012     /* Set user-defined configuration options for this instrument */
1013     configure_instr_class(entry);
1014     PFS_atomic::add_u32(&stage_class_allocated_count, 1);
1015 
1016     return (index + 1);
1017   }
1018 
1019   stage_class_lost++;
1020   return 0;
1021 }
1022 
1023 /**
1024   Register a statement instrumentation metadata.
1025   @param name                         the instrumented name
1026   @param name_length                  length in bytes of name
1027   @param flags                        the instrumentation flags
1028   @return a statement instrumentation key
1029 */
register_statement_class(const char * name,uint name_length,int flags)1030 PFS_statement_key register_statement_class(const char *name, uint name_length,
1031                                            int flags)
1032 {
1033   /* See comments in register_mutex_class */
1034   uint32 index;
1035   PFS_statement_class *entry;
1036 
1037   REGISTER_CLASS_BODY_PART(index, statement_class_array, statement_class_max,
1038                            name, name_length)
1039 
1040   index= PFS_atomic::add_u32(&statement_class_dirty_count, 1);
1041 
1042   if (index < statement_class_max)
1043   {
1044     entry= &statement_class_array[index];
1045     init_instr_class(entry, name, name_length, flags, PFS_CLASS_STATEMENT);
1046     entry->m_event_name_index= index;
1047     entry->m_enabled= true; /* enabled by default */
1048     entry->m_timed= true;
1049     /* Set user-defined configuration options for this instrument */
1050     configure_instr_class(entry);
1051     PFS_atomic::add_u32(&statement_class_allocated_count, 1);
1052 
1053     return (index + 1);
1054   }
1055 
1056   statement_class_lost++;
1057   return 0;
1058 }
1059 
1060 /**
1061   Find a file instrumentation class by key.
1062   @param key                          the instrument key
1063   @return the instrument class, or NULL
1064 */
find_file_class(PFS_file_key key)1065 PFS_file_class *find_file_class(PFS_file_key key)
1066 {
1067   FIND_CLASS_BODY(key, file_class_allocated_count, file_class_array);
1068 }
1069 
sanitize_file_class(PFS_file_class * unsafe)1070 PFS_file_class *sanitize_file_class(PFS_file_class *unsafe)
1071 {
1072   SANITIZE_ARRAY_BODY(PFS_file_class, file_class_array, file_class_max, unsafe);
1073 }
1074 
1075 /**
1076   Find a stage instrumentation class by key.
1077   @param key                          the instrument key
1078   @return the instrument class, or NULL
1079 */
find_stage_class(PFS_stage_key key)1080 PFS_stage_class *find_stage_class(PFS_stage_key key)
1081 {
1082   FIND_CLASS_BODY(key, stage_class_allocated_count, stage_class_array);
1083 }
1084 
sanitize_stage_class(PFS_stage_class * unsafe)1085 PFS_stage_class *sanitize_stage_class(PFS_stage_class *unsafe)
1086 {
1087   SANITIZE_ARRAY_BODY(PFS_stage_class, stage_class_array, stage_class_max, unsafe);
1088 }
1089 
1090 /**
1091   Find a statement instrumentation class by key.
1092   @param key                          the instrument key
1093   @return the instrument class, or NULL
1094 */
find_statement_class(PFS_stage_key key)1095 PFS_statement_class *find_statement_class(PFS_stage_key key)
1096 {
1097   FIND_CLASS_BODY(key, statement_class_allocated_count, statement_class_array);
1098 }
1099 
sanitize_statement_class(PFS_statement_class * unsafe)1100 PFS_statement_class *sanitize_statement_class(PFS_statement_class *unsafe)
1101 {
1102   SANITIZE_ARRAY_BODY(PFS_statement_class, statement_class_array, statement_class_max, unsafe);
1103 }
1104 
1105 /**
1106   Register a socket instrumentation metadata.
1107   @param name                         the instrumented name
1108   @param name_length                  length in bytes of name
1109   @param flags                        the instrumentation flags
1110   @return a socket instrumentation key
1111 */
register_socket_class(const char * name,uint name_length,int flags)1112 PFS_socket_key register_socket_class(const char *name, uint name_length,
1113                                      int flags)
1114 {
1115   /* See comments in register_mutex_class */
1116   uint32 index;
1117   PFS_socket_class *entry;
1118 
1119   REGISTER_CLASS_BODY_PART(index, socket_class_array, socket_class_max,
1120                            name, name_length)
1121 
1122   index= PFS_atomic::add_u32(&socket_class_dirty_count, 1);
1123 
1124   if (index < socket_class_max)
1125   {
1126     entry= &socket_class_array[index];
1127     init_instr_class(entry, name, name_length, flags, PFS_CLASS_SOCKET);
1128     entry->m_event_name_index= socket_class_start + index;
1129     entry->m_singleton= NULL;
1130     entry->m_enabled= false; /* disabled by default */
1131     entry->m_timed= false;
1132     /* Set user-defined configuration options for this instrument */
1133     configure_instr_class(entry);
1134     PFS_atomic::add_u32(&socket_class_allocated_count, 1);
1135     return (index + 1);
1136   }
1137 
1138   socket_class_lost++;
1139   return 0;
1140 }
1141 
1142 /**
1143   Find a socket instrumentation class by key.
1144   @param key                          the instrument key
1145   @return the instrument class, or NULL
1146 */
find_socket_class(PFS_socket_key key)1147 PFS_socket_class *find_socket_class(PFS_socket_key key)
1148 {
1149   FIND_CLASS_BODY(key, socket_class_allocated_count, socket_class_array);
1150 }
1151 
sanitize_socket_class(PFS_socket_class * unsafe)1152 PFS_socket_class *sanitize_socket_class(PFS_socket_class *unsafe)
1153 {
1154   SANITIZE_ARRAY_BODY(PFS_socket_class, socket_class_array, socket_class_max, unsafe);
1155 }
1156 
find_table_class(uint index)1157 PFS_instr_class *find_table_class(uint index)
1158 {
1159   if (index == 1)
1160     return & global_table_io_class;
1161   if (index == 2)
1162     return & global_table_lock_class;
1163   return NULL;
1164 }
1165 
sanitize_table_class(PFS_instr_class * unsafe)1166 PFS_instr_class *sanitize_table_class(PFS_instr_class *unsafe)
1167 {
1168   if (likely((& global_table_io_class == unsafe) ||
1169              (& global_table_lock_class == unsafe)))
1170     return unsafe;
1171   return NULL;
1172 }
1173 
find_idle_class(uint index)1174 PFS_instr_class *find_idle_class(uint index)
1175 {
1176   if (index == 1)
1177     return & global_idle_class;
1178   return NULL;
1179 }
1180 
sanitize_idle_class(PFS_instr_class * unsafe)1181 PFS_instr_class *sanitize_idle_class(PFS_instr_class *unsafe)
1182 {
1183   if (likely(& global_idle_class == unsafe))
1184     return unsafe;
1185   return NULL;
1186 }
1187 
set_keys(PFS_table_share * pfs,const TABLE_SHARE * share)1188 static void set_keys(PFS_table_share *pfs, const TABLE_SHARE *share)
1189 {
1190   uint len;
1191   KEY *key_info= share->key_info;
1192   PFS_table_key *pfs_key= pfs->m_keys;
1193   PFS_table_key *pfs_key_last= pfs->m_keys + share->keys;
1194   pfs->m_key_count= share->keys;
1195 
1196   for ( ; pfs_key < pfs_key_last; pfs_key++, key_info++)
1197   {
1198     len= (uint)key_info->name.length;
1199     memcpy(pfs_key->m_name, key_info->name.str, len);
1200     pfs_key->m_name_length= len;
1201   }
1202 
1203   pfs_key_last= pfs->m_keys + MAX_INDEXES;
1204   for ( ; pfs_key < pfs_key_last; pfs_key++)
1205     pfs_key->m_name_length= 0;
1206 }
1207 
compare_keys(PFS_table_share * pfs,const TABLE_SHARE * share)1208 static int compare_keys(PFS_table_share *pfs, const TABLE_SHARE *share)
1209 {
1210   uint len;
1211   KEY *key_info= share->key_info;
1212   PFS_table_key *pfs_key= pfs->m_keys;
1213   PFS_table_key *pfs_key_last= pfs->m_keys + share->keys;
1214 
1215   if (pfs->m_key_count != share->keys)
1216     return 1;
1217 
1218   for ( ; pfs_key < pfs_key_last; pfs_key++, key_info++)
1219   {
1220     len= (uint)key_info->name.length;
1221     if (len != pfs_key->m_name_length)
1222       return 1;
1223 
1224     if (memcmp(pfs_key->m_name, key_info->name.str, len) != 0)
1225       return 1;
1226   }
1227 
1228   return 0;
1229 }
1230 
1231 /**
1232   Find or create a table share instrumentation.
1233   @param thread                       the executing instrumented thread
1234   @param temporary                    true for TEMPORARY TABLE
1235   @param share                        table share
1236   @return a table share, or NULL
1237 */
find_or_create_table_share(PFS_thread * thread,bool temporary,const TABLE_SHARE * share)1238 PFS_table_share* find_or_create_table_share(PFS_thread *thread,
1239                                             bool temporary,
1240                                             const TABLE_SHARE *share)
1241 {
1242   /* See comments in register_mutex_class */
1243   PFS_table_share_key key;
1244 
1245   LF_PINS *pins= get_table_share_hash_pins(thread);
1246   if (unlikely(pins == NULL))
1247   {
1248     table_share_lost++;
1249     return NULL;
1250   }
1251 
1252   const char *schema_name= share->db.str;
1253   uint schema_name_length= (uint)share->db.length;
1254   const char *table_name= share->table_name.str;
1255   uint table_name_length= (uint)share->table_name.length;
1256 
1257   set_table_share_key(&key, temporary,
1258                       schema_name, schema_name_length,
1259                       table_name, table_name_length);
1260 
1261   PFS_table_share **entry;
1262   uint retry_count= 0;
1263   const uint retry_max= 3;
1264   bool enabled= true;
1265   bool timed= true;
1266   static uint PFS_ALIGNED table_share_monotonic_index= 0;
1267   uint index;
1268   uint attempts= 0;
1269   PFS_table_share *pfs;
1270 
1271 search:
1272   entry= reinterpret_cast<PFS_table_share**>
1273     (lf_hash_search(&table_share_hash, pins,
1274                     key.m_hash_key, key.m_key_length));
1275   if (entry && (entry != MY_ERRPTR))
1276   {
1277     pfs= *entry;
1278     pfs->inc_refcount() ;
1279     if (compare_keys(pfs, share) != 0)
1280     {
1281       set_keys(pfs, share);
1282       /* FIXME: aggregate to table_share sink ? */
1283       pfs->m_table_stat.fast_reset();
1284     }
1285     lf_hash_search_unpin(pins);
1286     return pfs;
1287   }
1288 
1289   lf_hash_search_unpin(pins);
1290 
1291   if (retry_count == 0)
1292   {
1293     lookup_setup_object(thread,
1294                         OBJECT_TYPE_TABLE,
1295                         schema_name, schema_name_length,
1296                         table_name, table_name_length,
1297                         &enabled, &timed);
1298     /*
1299       Even when enabled is false, a record is added in the dictionary:
1300       - It makes enabling a table already in the table cache possible,
1301       - It improves performances for the next time a TABLE_SHARE is reloaded
1302         in the table cache.
1303     */
1304   }
1305 
1306   while (++attempts <= table_share_max)
1307   {
1308     /* See create_mutex() */
1309     index= PFS_atomic::add_u32(& table_share_monotonic_index, 1) % table_share_max;
1310     pfs= table_share_array + index;
1311 
1312     if (pfs->m_lock.is_free())
1313     {
1314       if (pfs->m_lock.free_to_dirty())
1315       {
1316         pfs->m_key= key;
1317         pfs->m_schema_name= &pfs->m_key.m_hash_key[1];
1318         pfs->m_schema_name_length= schema_name_length;
1319         pfs->m_table_name= &pfs->m_key.m_hash_key[schema_name_length + 2];
1320         pfs->m_table_name_length= table_name_length;
1321         pfs->m_enabled= enabled;
1322         pfs->m_timed= timed;
1323         pfs->init_refcount();
1324         pfs->m_table_stat.fast_reset();
1325         set_keys(pfs, share);
1326 
1327         int res;
1328         res= lf_hash_insert(&table_share_hash, pins, &pfs);
1329         if (likely(res == 0))
1330         {
1331           pfs->m_lock.dirty_to_allocated();
1332           return pfs;
1333         }
1334 
1335         pfs->m_lock.dirty_to_free();
1336 
1337         if (res > 0)
1338         {
1339           /* Duplicate insert by another thread */
1340           if (++retry_count > retry_max)
1341           {
1342             /* Avoid infinite loops */
1343             table_share_lost++;
1344             return NULL;
1345           }
1346           goto search;
1347         }
1348 
1349         /* OOM in lf_hash_insert */
1350         table_share_lost++;
1351         return NULL;
1352       }
1353     }
1354   }
1355 
1356   table_share_lost++;
1357   return NULL;
1358 }
1359 
aggregate_io(void)1360 void PFS_table_share::aggregate_io(void)
1361 {
1362   uint safe_key_count= sanitize_index_count(m_key_count);
1363   PFS_table_io_stat *from_stat;
1364   PFS_table_io_stat *from_stat_last;
1365   PFS_table_io_stat sum_io;
1366 
1367   /* Aggregate stats for each index, if any */
1368   from_stat= & m_table_stat.m_index_stat[0];
1369   from_stat_last= from_stat + safe_key_count;
1370   for ( ; from_stat < from_stat_last ; from_stat++)
1371     sum_io.aggregate(from_stat);
1372 
1373   /* Aggregate stats for the table */
1374   sum_io.aggregate(& m_table_stat.m_index_stat[MAX_INDEXES]);
1375 
1376   /* Add this table stats to the global sink. */
1377   global_table_io_stat.aggregate(& sum_io);
1378   m_table_stat.fast_reset_io();
1379 }
1380 
aggregate_lock(void)1381 void PFS_table_share::aggregate_lock(void)
1382 {
1383   global_table_lock_stat.aggregate(& m_table_stat.m_lock_stat);
1384   m_table_stat.fast_reset_lock();
1385 }
1386 
release_table_share(PFS_table_share * pfs)1387 void release_table_share(PFS_table_share *pfs)
1388 {
1389   DBUG_ASSERT(pfs->get_refcount() > 0);
1390   pfs->dec_refcount();
1391 }
1392 
1393 /**
1394   Drop the instrumented table share associated with a table.
1395   @param thread The running thread
1396   @param temporary True for TEMPORARY TABLE
1397   @param schema_name The table schema name
1398   @param schema_name_length The table schema name length
1399   @param table_name The table name
1400   @param table_name_length The table name length
1401 */
drop_table_share(PFS_thread * thread,bool temporary,const char * schema_name,uint schema_name_length,const char * table_name,uint table_name_length)1402 void drop_table_share(PFS_thread *thread,
1403                       bool temporary,
1404                       const char *schema_name, uint schema_name_length,
1405                       const char *table_name, uint table_name_length)
1406 {
1407   PFS_table_share_key key;
1408   LF_PINS* pins= get_table_share_hash_pins(thread);
1409   if (unlikely(pins == NULL))
1410     return;
1411   set_table_share_key(&key, temporary, schema_name, schema_name_length,
1412                       table_name, table_name_length);
1413   PFS_table_share **entry;
1414   entry= reinterpret_cast<PFS_table_share**>
1415     (lf_hash_search(&table_share_hash, pins,
1416                     key.m_hash_key, key.m_key_length));
1417   if (entry && (entry != MY_ERRPTR))
1418   {
1419     PFS_table_share *pfs= *entry;
1420     lf_hash_delete(&table_share_hash, pins,
1421                    pfs->m_key.m_hash_key, pfs->m_key.m_key_length);
1422     pfs->m_lock.allocated_to_free();
1423   }
1424 
1425   lf_hash_search_unpin(pins);
1426 }
1427 
1428 /**
1429   Sanitize an unsafe table_share pointer.
1430   @param unsafe The possibly corrupt pointer.
1431   @return A valid table_safe_pointer, or NULL.
1432 */
sanitize_table_share(PFS_table_share * unsafe)1433 PFS_table_share *sanitize_table_share(PFS_table_share *unsafe)
1434 {
1435   SANITIZE_ARRAY_BODY(PFS_table_share, table_share_array, table_share_max, unsafe);
1436 }
1437 
1438 /** Reset the wait statistics per instrument class. */
reset_events_waits_by_class()1439 void reset_events_waits_by_class()
1440 {
1441   reset_file_class_io();
1442   reset_socket_class_io();
1443   global_idle_stat.reset();
1444   global_table_io_stat.reset();
1445   global_table_lock_stat.reset();
1446 }
1447 
1448 /** Reset the io statistics per file class. */
reset_file_class_io(void)1449 void reset_file_class_io(void)
1450 {
1451   PFS_file_class *pfs= file_class_array;
1452   PFS_file_class *pfs_last= file_class_array + file_class_max;
1453 
1454   for ( ; pfs < pfs_last; pfs++)
1455     pfs->m_file_stat.m_io_stat.reset();
1456 }
1457 
1458 /** Reset the io statistics per socket class. */
reset_socket_class_io(void)1459 void reset_socket_class_io(void)
1460 {
1461   PFS_socket_class *pfs= socket_class_array;
1462   PFS_socket_class *pfs_last= socket_class_array + socket_class_max;
1463 
1464   for ( ; pfs < pfs_last; pfs++)
1465     pfs->m_socket_stat.m_io_stat.reset();
1466 }
1467 
update_table_share_derived_flags(PFS_thread * thread)1468 void update_table_share_derived_flags(PFS_thread *thread)
1469 {
1470   PFS_table_share *pfs= table_share_array;
1471   PFS_table_share *pfs_last= table_share_array + table_share_max;
1472 
1473   for ( ; pfs < pfs_last; pfs++)
1474   {
1475     if (pfs->m_lock.is_populated())
1476       pfs->refresh_setup_object_flags(thread);
1477   }
1478 }
1479 
1480 /** @} */
1481 
1482