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