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