diff options
Diffstat (limited to 'storage/perfschema/pfs_instr.cc')
-rw-r--r-- | storage/perfschema/pfs_instr.cc | 1760 |
1 files changed, 1411 insertions, 349 deletions
diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc index 8da1a9862e1..82e768c9be2 100644 --- a/storage/perfschema/pfs_instr.cc +++ b/storage/perfschema/pfs_instr.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,11 @@ #include "pfs.h" #include "pfs_stat.h" #include "pfs_instr.h" +#include "pfs_host.h" +#include "pfs_user.h" +#include "pfs_account.h" #include "pfs_global.h" +#include "pfs_instr_class.h" /** @addtogroup Performance_schema_buffers @@ -63,12 +67,21 @@ ulong file_handle_lost; ulong table_max; /** Number of table instances lost. @sa table_array */ ulong table_lost; +/** Size of the socket instances array. @sa socket_array */ +ulong socket_max; +/** Number of socket instances lost. @sa socket_array */ +ulong socket_lost; /** Number of EVENTS_WAITS_HISTORY records per thread. */ ulong events_waits_history_per_thread; -/** Number of instruments class per thread. */ -ulong instr_class_per_thread; +/** Number of EVENTS_STAGES_HISTORY records per thread. */ +ulong events_stages_history_per_thread; +/** Number of EVENTS_STATEMENTS_HISTORY records per thread. */ +ulong events_statements_history_per_thread; +uint statement_stack_max; /** Number of locker lost. @sa LOCKER_STACK_SIZE. */ ulong locker_lost= 0; +/** Number of statement lost. @sa STATEMENT_STACK_SIZE. */ +ulong statement_lost= 0; /** Mutex instrumentation instances array. @@ -120,24 +133,35 @@ PFS_file **file_handle_array= NULL; */ PFS_table *table_array= NULL; +/** + Socket instrumentation instances array. + @sa socket_max + @sa socket_lost +*/ +PFS_socket *socket_array= NULL; + +PFS_single_stat *global_instr_class_waits_array= NULL; +PFS_stage_stat *global_instr_class_stages_array= NULL; +PFS_statement_stat *global_instr_class_statements_array= NULL; + static volatile uint32 thread_internal_id_counter= 0; -static uint per_thread_rwlock_class_start; -static uint per_thread_cond_class_start; -static uint per_thread_file_class_start; static uint thread_instr_class_waits_sizing; -static PFS_single_stat_chain *thread_instr_class_waits_array= NULL; +static uint thread_instr_class_stages_sizing; +static uint thread_instr_class_statements_sizing; +static PFS_single_stat *thread_instr_class_waits_array= NULL; +static PFS_stage_stat *thread_instr_class_stages_array= NULL; +static PFS_statement_stat *thread_instr_class_statements_array= NULL; -static PFS_events_waits *thread_history_array= NULL; +static PFS_events_waits *thread_waits_history_array= NULL; +static PFS_events_stages *thread_stages_history_array= NULL; +static PFS_events_statements *thread_statements_history_array= NULL; +static PFS_events_statements *thread_statements_stack_array= NULL; /** Hash table for instrumented files. */ static LF_HASH filename_hash; /** True if filename_hash is initialized. */ static bool filename_hash_inited= false; -C_MODE_START -/** Get hash table key for instrumented files. */ -static uchar *filename_hash_get_key(const uchar *, size_t *, my_bool); -C_MODE_END /** Initialize all the instruments instance buffers. @@ -146,10 +170,16 @@ C_MODE_END */ int init_instruments(const PFS_global_param *param) { - uint thread_history_sizing; + uint thread_waits_history_sizing; + uint thread_stages_history_sizing; + uint thread_statements_history_sizing; + uint thread_statements_stack_sizing; uint index; DBUG_ENTER("init_instruments"); + /* Make sure init_event_name_sizing is called */ + DBUG_ASSERT(wait_class_max != 0); + mutex_max= param->m_mutex_sizing; mutex_lost= 0; rwlock_max= param->m_rwlock_sizing; @@ -164,21 +194,32 @@ int init_instruments(const PFS_global_param *param) table_lost= 0; thread_max= param->m_thread_sizing; thread_lost= 0; + socket_max= param->m_socket_sizing; + socket_lost= 0; events_waits_history_per_thread= param->m_events_waits_history_sizing; - thread_history_sizing= param->m_thread_sizing + thread_waits_history_sizing= param->m_thread_sizing * events_waits_history_per_thread; - per_thread_rwlock_class_start= param->m_mutex_class_sizing; - per_thread_cond_class_start= per_thread_rwlock_class_start - + param->m_rwlock_class_sizing; - per_thread_file_class_start= per_thread_cond_class_start - + param->m_cond_class_sizing; - instr_class_per_thread= per_thread_file_class_start - + param->m_file_class_sizing; - thread_instr_class_waits_sizing= param->m_thread_sizing - * instr_class_per_thread; + * wait_class_max; + + events_stages_history_per_thread= param->m_events_stages_history_sizing; + thread_stages_history_sizing= param->m_thread_sizing + * events_stages_history_per_thread; + + events_statements_history_per_thread= param->m_events_statements_history_sizing; + thread_statements_history_sizing= param->m_thread_sizing + * events_statements_history_per_thread; + + statement_stack_max= 1; + thread_statements_stack_sizing= param->m_thread_sizing * statement_stack_max; + + thread_instr_class_stages_sizing= param->m_thread_sizing + * param->m_stage_class_sizing; + + thread_instr_class_statements_sizing= param->m_thread_sizing + * param->m_statement_class_sizing; mutex_array= NULL; rwlock_array= NULL; @@ -186,9 +227,15 @@ int init_instruments(const PFS_global_param *param) file_array= NULL; file_handle_array= NULL; table_array= NULL; + socket_array= NULL; thread_array= NULL; - thread_history_array= NULL; + thread_waits_history_array= NULL; + thread_stages_history_array= NULL; + thread_statements_history_array= NULL; + thread_statements_stack_array= NULL; thread_instr_class_waits_array= NULL; + thread_instr_class_stages_array= NULL; + thread_instr_class_statements_array= NULL; thread_internal_id_counter= 0; if (mutex_max > 0) @@ -233,6 +280,13 @@ int init_instruments(const PFS_global_param *param) DBUG_RETURN(1); } + if (socket_max > 0) + { + socket_array= PFS_MALLOC_ARRAY(socket_max, PFS_socket, MYF(MY_ZEROFILL)); + if (unlikely(socket_array == NULL)) + DBUG_RETURN(1); + } + if (thread_max > 0) { thread_array= PFS_MALLOC_ARRAY(thread_max, PFS_thread, MYF(MY_ZEROFILL)); @@ -240,12 +294,12 @@ int init_instruments(const PFS_global_param *param) DBUG_RETURN(1); } - if (thread_history_sizing > 0) + if (thread_waits_history_sizing > 0) { - thread_history_array= - PFS_MALLOC_ARRAY(thread_history_sizing, PFS_events_waits, + thread_waits_history_array= + PFS_MALLOC_ARRAY(thread_waits_history_sizing, PFS_events_waits, MYF(MY_ZEROFILL)); - if (unlikely(thread_history_array == NULL)) + if (unlikely(thread_waits_history_array == NULL)) DBUG_RETURN(1); } @@ -253,146 +307,126 @@ int init_instruments(const PFS_global_param *param) { thread_instr_class_waits_array= PFS_MALLOC_ARRAY(thread_instr_class_waits_sizing, - PFS_single_stat_chain, MYF(MY_ZEROFILL)); + PFS_single_stat, MYF(MY_ZEROFILL)); if (unlikely(thread_instr_class_waits_array == NULL)) DBUG_RETURN(1); - } - for (index= 0; index < thread_instr_class_waits_sizing; index++) - { - /* - Currently, this chain is of length 1, - but it's still implemented as a stat chain, - since more aggregations are planned to be implemented in m_parent. - */ - thread_instr_class_waits_array[index].m_control_flag= - &flag_events_waits_summary_by_thread_by_event_name; - thread_instr_class_waits_array[index].m_parent= NULL; + for (index= 0; index < thread_instr_class_waits_sizing; index++) + thread_instr_class_waits_array[index].reset(); } - for (index= 0; index < thread_max; index++) + if (thread_stages_history_sizing > 0) { - thread_array[index].m_waits_history= - &thread_history_array[index * events_waits_history_per_thread]; - thread_array[index].m_instr_class_wait_stats= - &thread_instr_class_waits_array[index * instr_class_per_thread]; + thread_stages_history_array= + PFS_MALLOC_ARRAY(thread_stages_history_sizing, PFS_events_stages, + MYF(MY_ZEROFILL)); + if (unlikely(thread_stages_history_array == NULL)) + DBUG_RETURN(1); } - DBUG_RETURN(0); -} - -/** - Find the per-thread wait statistics for a mutex class. - @param thread input thread - @param klass mutex class - @return the per thread per mutex class wait stat -*/ -PFS_single_stat_chain * -find_per_thread_mutex_class_wait_stat(PFS_thread *thread, - PFS_mutex_class *klass) -{ - PFS_single_stat_chain *stat; - uint index; - DBUG_ENTER("find_per_thread_mutex_class_wait_stat"); + if (thread_instr_class_stages_sizing > 0) + { + thread_instr_class_stages_array= + PFS_MALLOC_ARRAY(thread_instr_class_stages_sizing, + PFS_stage_stat, MYF(MY_ZEROFILL)); + if (unlikely(thread_instr_class_stages_array == NULL)) + DBUG_RETURN(1); - DBUG_ASSERT(thread != NULL); - DBUG_ASSERT(klass != NULL); - index= klass->m_index; - DBUG_ASSERT(index < mutex_class_max); + for (index= 0; index < thread_instr_class_stages_sizing; index++) + thread_instr_class_stages_array[index].reset(); + } - stat= &(thread->m_instr_class_wait_stats[index]); - DBUG_RETURN(stat); -} + if (thread_statements_history_sizing > 0) + { + thread_statements_history_array= + PFS_MALLOC_ARRAY(thread_statements_history_sizing, PFS_events_statements, + MYF(MY_ZEROFILL)); + if (unlikely(thread_statements_history_array == NULL)) + DBUG_RETURN(1); + } -/** - Find the per-thread wait statistics for a rwlock class. - @param thread input thread - @param klass rwlock class - @return the per thread per rwlock class wait stat -*/ -PFS_single_stat_chain * -find_per_thread_rwlock_class_wait_stat(PFS_thread *thread, - PFS_rwlock_class *klass) -{ - PFS_single_stat_chain *stat; - uint index; - DBUG_ENTER("find_per_thread_rwlock_class_wait_stat"); + if (thread_statements_stack_sizing > 0) + { + thread_statements_stack_array= + PFS_MALLOC_ARRAY(thread_statements_stack_sizing, PFS_events_statements, + MYF(MY_ZEROFILL)); + if (unlikely(thread_statements_stack_array == NULL)) + DBUG_RETURN(1); + } - DBUG_ASSERT(thread != NULL); - DBUG_ASSERT(klass != NULL); - index= klass->m_index; - DBUG_ASSERT(index < rwlock_class_max); + if (thread_instr_class_statements_sizing > 0) + { + thread_instr_class_statements_array= + PFS_MALLOC_ARRAY(thread_instr_class_statements_sizing, + PFS_statement_stat, MYF(MY_ZEROFILL)); + if (unlikely(thread_instr_class_statements_array == NULL)) + DBUG_RETURN(1); - stat= &(thread->m_instr_class_wait_stats - [per_thread_rwlock_class_start + index]); - DBUG_RETURN(stat); -} + for (index= 0; index < thread_instr_class_statements_sizing; index++) + thread_instr_class_statements_array[index].reset(); + } -/** - Find the per-thread wait statistics for a condition class. - @param thread input thread - @param klass condition class - @return the per thread per condition class wait stat -*/ -PFS_single_stat_chain * -find_per_thread_cond_class_wait_stat(PFS_thread *thread, - PFS_cond_class *klass) -{ - PFS_single_stat_chain *stat; - uint index; - DBUG_ENTER("find_per_thread_cond_class_wait_stat"); + for (index= 0; index < thread_max; index++) + { + thread_array[index].m_waits_history= + &thread_waits_history_array[index * events_waits_history_per_thread]; + thread_array[index].m_instr_class_waits_stats= + &thread_instr_class_waits_array[index * wait_class_max]; + thread_array[index].m_stages_history= + &thread_stages_history_array[index * events_stages_history_per_thread]; + thread_array[index].m_instr_class_stages_stats= + &thread_instr_class_stages_array[index * stage_class_max]; + thread_array[index].m_statements_history= + &thread_statements_history_array[index * events_statements_history_per_thread]; + thread_array[index].m_statement_stack= + &thread_statements_stack_array[index * statement_stack_max]; + thread_array[index].m_instr_class_statements_stats= + &thread_instr_class_statements_array[index * statement_class_max]; + } - DBUG_ASSERT(thread != NULL); - DBUG_ASSERT(klass != NULL); - index= klass->m_index; - DBUG_ASSERT(index < cond_class_max); + if (wait_class_max > 0) + { + global_instr_class_waits_array= + PFS_MALLOC_ARRAY(wait_class_max, + PFS_single_stat, MYF(MY_ZEROFILL)); + if (unlikely(global_instr_class_waits_array == NULL)) + DBUG_RETURN(1); - stat= &(thread->m_instr_class_wait_stats - [per_thread_cond_class_start + index]); - DBUG_RETURN(stat); -} + for (index= 0; index < wait_class_max; index++) + global_instr_class_waits_array[index].reset(); + } -/** - Find the per-thread wait statistics for a file class. - @param thread input thread - @param klass file class - @return the per thread per file class wait stat -*/ -PFS_single_stat_chain * -find_per_thread_file_class_wait_stat(PFS_thread *thread, - PFS_file_class *klass) -{ - PFS_single_stat_chain *stat; - uint index; - DBUG_ENTER("find_per_thread_file_class_wait_stat"); + if (stage_class_max > 0) + { + global_instr_class_stages_array= + PFS_MALLOC_ARRAY(stage_class_max, + PFS_stage_stat, MYF(MY_ZEROFILL)); + if (unlikely(global_instr_class_stages_array == NULL)) + DBUG_RETURN(1); - DBUG_ASSERT(thread != NULL); - DBUG_ASSERT(klass != NULL); - index= klass->m_index; - DBUG_ASSERT(index < file_class_max); + for (index= 0; index < stage_class_max; index++) + global_instr_class_stages_array[index].reset(); + } - stat= &(thread->m_instr_class_wait_stats - [per_thread_file_class_start + index]); - DBUG_RETURN(stat); -} + if (statement_class_max > 0) + { + global_instr_class_statements_array= + PFS_MALLOC_ARRAY(statement_class_max, + PFS_statement_stat, MYF(MY_ZEROFILL)); + if (unlikely(global_instr_class_statements_array == NULL)) + DBUG_RETURN(1); -/** Reset the wait statistics per thread. */ -void reset_per_thread_wait_stat(void) -{ - PFS_single_stat_chain *stat= thread_instr_class_waits_array; - PFS_single_stat_chain *stat_last= stat + thread_instr_class_waits_sizing; - DBUG_ENTER("reset_per_thread_wait_stat"); + for (index= 0; index < statement_class_max; index++) + global_instr_class_statements_array[index].reset(); + } - for ( ; stat < stat_last; stat++) - reset_single_stat_link(stat); - DBUG_VOID_RETURN; + DBUG_RETURN(0); } /** Cleanup all the instruments buffers. */ void cleanup_instruments(void) { DBUG_ENTER("cleanup_instruments"); - pfs_free(mutex_array); mutex_array= NULL; mutex_max= 0; @@ -411,18 +445,33 @@ void cleanup_instruments(void) pfs_free(table_array); table_array= NULL; table_max= 0; + pfs_free(socket_array); + socket_array= NULL; + socket_max= 0; pfs_free(thread_array); thread_array= NULL; thread_max= 0; - pfs_free(thread_history_array); - thread_history_array= NULL; + pfs_free(thread_waits_history_array); + thread_waits_history_array= NULL; + pfs_free(thread_stages_history_array); + thread_stages_history_array= NULL; + pfs_free(thread_statements_history_array); + thread_statements_history_array= NULL; + pfs_free(thread_statements_stack_array); + thread_statements_stack_array= NULL; pfs_free(thread_instr_class_waits_array); thread_instr_class_waits_array= NULL; + pfs_free(global_instr_class_waits_array); + global_instr_class_waits_array= NULL; + pfs_free(global_instr_class_stages_array); + global_instr_class_stages_array= NULL; + pfs_free(global_instr_class_statements_array); + global_instr_class_statements_array= NULL; DBUG_VOID_RETURN; } -extern "C" -{ +C_MODE_START +/** Get hash table key for instrumented files. */ static uchar *filename_hash_get_key(const uchar *entry, size_t *length, my_bool) { @@ -439,7 +488,7 @@ static uchar *filename_hash_get_key(const uchar *entry, size_t *length, result= file->m_filename; DBUG_RETURN(const_cast<uchar*> (reinterpret_cast<const uchar*> (result))); } -} +C_MODE_END /** Initialize the file name hash. @@ -551,37 +600,52 @@ void PFS_scan::init(uint random, uint max_size) */ PFS_mutex* create_mutex(PFS_mutex_class *klass, const void *identity) { - PFS_scan scan; - uint random= randomized_index(identity, mutex_max); + static uint mutex_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_mutex *pfs; DBUG_ENTER("create_mutex"); - for (scan.init(random, mutex_max); - scan.has_pass(); - scan.next_pass()) + while (++attempts <= mutex_max) { - PFS_mutex *pfs= mutex_array + scan.first(); - PFS_mutex *pfs_last= mutex_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + /* + Problem: + Multiple threads running concurrently may need to create a new + instrumented mutex, and find an empty slot in mutex_array[]. + With N1 threads running on a N2 core hardware: + - up to N2 hardware threads can run concurrently, + causing contention if looking at the same array[i] slot. + - up to N1 threads can run almost concurrently (with thread scheduling), + scanning maybe overlapping regions in the [0-mutex_max] array. + + Solution: + Instead of letting different threads compete on the same array[i] entry, + this code forces all threads to cooperate with the monotonic_index. + Only one thread will be allowed to test a given array[i] slot. + All threads do scan from the same region, starting at monotonic_index. + Serializing on monotonic_index ensures that when a slot is found occupied + in a given loop by a given thread, other threads will not attempt this + slot. + */ + index= PFS_atomic::add_u32(& mutex_monotonic_index, 1) % mutex_max; + pfs= mutex_array + index; + + if (pfs->m_lock.is_free()) { - if (pfs->m_lock.is_free()) + if (pfs->m_lock.free_to_dirty()) { - if (pfs->m_lock.free_to_dirty()) - { - pfs->m_identity= identity; - pfs->m_class= klass; - pfs->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_instance; - pfs->m_wait_stat.m_parent= &klass->m_wait_stat; - reset_single_stat_link(&pfs->m_wait_stat); - pfs->m_lock_stat.m_control_flag= - &flag_events_locks_summary_by_instance; - pfs->m_lock_stat.m_parent= &klass->m_lock_stat; - reset_single_stat_link(&pfs->m_lock_stat); - pfs->m_owner= NULL; - pfs->m_last_locked= 0; - pfs->m_lock.dirty_to_allocated(); - DBUG_RETURN(pfs); - } + pfs->m_identity= identity; + pfs->m_class= klass; + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + pfs->m_wait_stat.reset(); + pfs->m_lock_stat.reset(); + pfs->m_owner= NULL; + pfs->m_last_locked= 0; + pfs->m_lock.dirty_to_allocated(); + if (klass->is_singleton()) + klass->m_singleton= pfs; + DBUG_RETURN(pfs); } } } @@ -597,8 +661,14 @@ PFS_mutex* create_mutex(PFS_mutex_class *klass, const void *identity) void destroy_mutex(PFS_mutex *pfs) { DBUG_ENTER("destroy_mutex"); - DBUG_ASSERT(pfs != NULL); + PFS_mutex_class *klass= pfs->m_class; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_EVENT_NAME */ + uint index= klass->m_event_name_index; + global_instr_class_waits_array[index].aggregate(& pfs->m_wait_stat); + pfs->m_wait_stat.reset(); + if (klass->is_singleton()) + klass->m_singleton= NULL; pfs->m_lock.allocated_to_free(); DBUG_VOID_RETURN; } @@ -611,43 +681,37 @@ void destroy_mutex(PFS_mutex *pfs) */ PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity) { - PFS_scan scan; - uint random= randomized_index(identity, rwlock_max); + static uint rwlock_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_rwlock *pfs; DBUG_ENTER("create_rwlock"); - for (scan.init(random, rwlock_max); - scan.has_pass(); - scan.next_pass()) + while (++attempts <= rwlock_max) { - PFS_rwlock *pfs= rwlock_array + scan.first(); - PFS_rwlock *pfs_last= rwlock_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + /* See create_mutex() */ + index= PFS_atomic::add_u32(& rwlock_monotonic_index, 1) % rwlock_max; + pfs= rwlock_array + index; + + if (pfs->m_lock.is_free()) { - if (pfs->m_lock.is_free()) + if (pfs->m_lock.free_to_dirty()) { - if (pfs->m_lock.free_to_dirty()) - { - pfs->m_identity= identity; - pfs->m_class= klass; - pfs->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_instance; - pfs->m_wait_stat.m_parent= &klass->m_wait_stat; - reset_single_stat_link(&pfs->m_wait_stat); - pfs->m_lock.dirty_to_allocated(); - pfs->m_read_lock_stat.m_control_flag= - &flag_events_locks_summary_by_instance; - pfs->m_read_lock_stat.m_parent= &klass->m_read_lock_stat; - reset_single_stat_link(&pfs->m_read_lock_stat); - pfs->m_write_lock_stat.m_control_flag= - &flag_events_locks_summary_by_instance; - pfs->m_write_lock_stat.m_parent= &klass->m_write_lock_stat; - reset_single_stat_link(&pfs->m_write_lock_stat); - pfs->m_writer= NULL; - pfs->m_readers= 0; - pfs->m_last_written= 0; - pfs->m_last_read= 0; - DBUG_RETURN(pfs); - } + pfs->m_identity= identity; + pfs->m_class= klass; + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + pfs->m_wait_stat.reset(); + pfs->m_lock.dirty_to_allocated(); + pfs->m_read_lock_stat.reset(); + pfs->m_write_lock_stat.reset(); + pfs->m_writer= NULL; + pfs->m_readers= 0; + pfs->m_last_written= 0; + pfs->m_last_read= 0; + if (klass->is_singleton()) + klass->m_singleton= pfs; + DBUG_RETURN(pfs); } } } @@ -663,8 +727,14 @@ PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity) void destroy_rwlock(PFS_rwlock *pfs) { DBUG_ENTER("destroy_rwlock"); - DBUG_ASSERT(pfs != NULL); + PFS_rwlock_class *klass= pfs->m_class; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_EVENT_NAME */ + uint index= klass->m_event_name_index; + global_instr_class_waits_array[index].aggregate(& pfs->m_wait_stat); + pfs->m_wait_stat.reset(); + if (klass->is_singleton()) + klass->m_singleton= NULL; pfs->m_lock.allocated_to_free(); DBUG_VOID_RETURN; } @@ -677,33 +747,33 @@ void destroy_rwlock(PFS_rwlock *pfs) */ PFS_cond* create_cond(PFS_cond_class *klass, const void *identity) { - PFS_scan scan; - uint random= randomized_index(identity, cond_max); + static uint cond_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_cond *pfs; DBUG_ENTER("create_cond"); - for (scan.init(random, cond_max); - scan.has_pass(); - scan.next_pass()) + while (++attempts <= cond_max) { - PFS_cond *pfs= cond_array + scan.first(); - PFS_cond *pfs_last= cond_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + /* See create_mutex() */ + index= PFS_atomic::add_u32(& cond_monotonic_index, 1) % cond_max; + pfs= cond_array + index; + + if (pfs->m_lock.is_free()) { - if (pfs->m_lock.is_free()) + if (pfs->m_lock.free_to_dirty()) { - if (pfs->m_lock.free_to_dirty()) - { - pfs->m_identity= identity; - pfs->m_class= klass; - pfs->m_cond_stat.m_signal_count= 0; - pfs->m_cond_stat.m_broadcast_count= 0; - pfs->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_instance; - pfs->m_wait_stat.m_parent= &klass->m_wait_stat; - reset_single_stat_link(&pfs->m_wait_stat); - pfs->m_lock.dirty_to_allocated(); - DBUG_RETURN(pfs); - } + pfs->m_identity= identity; + pfs->m_class= klass; + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + pfs->m_cond_stat.m_signal_count= 0; + pfs->m_cond_stat.m_broadcast_count= 0; + pfs->m_wait_stat.reset(); + pfs->m_lock.dirty_to_allocated(); + if (klass->is_singleton()) + klass->m_singleton= pfs; + DBUG_RETURN(pfs); } } } @@ -718,13 +788,26 @@ PFS_cond* create_cond(PFS_cond_class *klass, const void *identity) */ void destroy_cond(PFS_cond *pfs) { - DBUG_ENTER("destroy_cond"); + DBUG_ENTER("destroy_thread"); DBUG_ASSERT(pfs != NULL); + PFS_cond_class *klass= pfs->m_class; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_EVENT_NAME */ + uint index= klass->m_event_name_index; + global_instr_class_waits_array[index].aggregate(& pfs->m_wait_stat); + pfs->m_wait_stat.reset(); + if (klass->is_singleton()) + klass->m_singleton= NULL; pfs->m_lock.allocated_to_free(); DBUG_VOID_RETURN; } +PFS_thread* PFS_thread::get_current_thread() +{ + PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + return pfs; +} + /** Create instrumentation for a thread instance. @param klass the thread class @@ -737,41 +820,127 @@ void destroy_cond(PFS_cond *pfs) PFS_thread* create_thread(PFS_thread_class *klass, const void *identity, ulong thread_id) { - PFS_scan scan; - uint random= randomized_index(identity, thread_max); + static uint thread_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_thread *pfs; DBUG_ENTER("create_thread"); - for (scan.init(random, thread_max); - scan.has_pass(); - scan.next_pass()) + while (++attempts <= thread_max) { - PFS_thread *pfs= thread_array + scan.first(); - PFS_thread *pfs_last= thread_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + /* See create_mutex() */ + index= PFS_atomic::add_u32(& thread_monotonic_index, 1) % thread_max; + pfs= thread_array + index; + + if (pfs->m_lock.is_free()) { - if (pfs->m_lock.is_free()) + if (pfs->m_lock.free_to_dirty()) { - if (pfs->m_lock.free_to_dirty()) + pfs->m_thread_internal_id= + PFS_atomic::add_u32(&thread_internal_id_counter, 1); + pfs->m_parent_thread_internal_id= 0; + pfs->m_thread_id= thread_id; + pfs->m_event_id= 1; + pfs->m_enabled= true; + pfs->m_class= klass; + pfs->m_events_waits_current= & pfs->m_events_waits_stack[WAIT_STACK_BOTTOM]; + pfs->m_waits_history_full= false; + pfs->m_waits_history_index= 0; + pfs->m_stages_history_full= false; + pfs->m_stages_history_index= 0; + pfs->m_statements_history_full= false; + pfs->m_statements_history_index= 0; + + pfs->reset_stats(); + + pfs->m_filename_hash_pins= NULL; + pfs->m_table_share_hash_pins= NULL; + pfs->m_setup_actor_hash_pins= NULL; + pfs->m_setup_object_hash_pins= NULL; + pfs->m_user_hash_pins= NULL; + pfs->m_account_hash_pins= NULL; + pfs->m_host_hash_pins= NULL; + pfs->m_digest_hash_pins= NULL; + + pfs->m_username_length= 0; + pfs->m_hostname_length= 0; + pfs->m_dbname_length= 0; + pfs->m_command= 0; + pfs->m_start_time= 0; + pfs->m_processlist_state_length= 0; + pfs->m_processlist_info_length= 0; + + pfs->m_host= NULL; + pfs->m_user= NULL; + pfs->m_account= NULL; + set_thread_account(pfs); + + PFS_events_waits *child_wait; + for (index= 0; index < WAIT_STACK_SIZE; index++) { - pfs->m_thread_internal_id= - PFS_atomic::add_u32(&thread_internal_id_counter, 1); - pfs->m_thread_id= thread_id; - pfs->m_event_id= 1; - pfs->m_enabled= true; - pfs->m_class= klass; - pfs->m_wait_locker_count= 0; - pfs->m_waits_history_full= false; - pfs->m_waits_history_index= 0; - - PFS_single_stat_chain *stat= pfs->m_instr_class_wait_stats; - PFS_single_stat_chain *stat_last= stat + instr_class_per_thread; - for ( ; stat < stat_last; stat++) - reset_single_stat_link(stat); - pfs->m_filename_hash_pins= NULL; - pfs->m_table_share_hash_pins= NULL; - pfs->m_lock.dirty_to_allocated(); - DBUG_RETURN(pfs); + child_wait= & pfs->m_events_waits_stack[index]; + child_wait->m_thread_internal_id= pfs->m_thread_internal_id; + child_wait->m_event_id= 0; + child_wait->m_end_event_id= 0; + child_wait->m_event_type= EVENT_TYPE_STATEMENT; + child_wait->m_wait_class= NO_WAIT_CLASS; } + + PFS_events_stages *child_stage= & pfs->m_stage_current; + child_stage->m_thread_internal_id= pfs->m_thread_internal_id; + child_stage->m_event_id= 0; + child_stage->m_end_event_id= 0; + child_stage->m_event_type= EVENT_TYPE_STATEMENT; + child_stage->m_class= NULL; + child_stage->m_timer_start= 0; + child_stage->m_timer_end= 0; + child_stage->m_source_file= NULL; + child_stage->m_source_line= 0; + + PFS_events_statements *child_statement; + for (index= 0; index < statement_stack_max; index++) + { + child_statement= & pfs->m_statement_stack[index]; + child_statement->m_thread_internal_id= pfs->m_thread_internal_id; + child_statement->m_event_id= 0; + child_statement->m_end_event_id= 0; + child_statement->m_event_type= EVENT_TYPE_STATEMENT; + child_statement->m_class= NULL; + child_statement->m_timer_start= 0; + child_statement->m_timer_end= 0; + child_statement->m_lock_time= 0; + child_statement->m_source_file= NULL; + child_statement->m_source_line= 0; + child_statement->m_current_schema_name_length= 0; + child_statement->m_sqltext_length= 0; + + child_statement->m_message_text[0]= '\0'; + child_statement->m_sql_errno= 0; + child_statement->m_sqlstate[0]= '\0'; + child_statement->m_error_count= 0; + child_statement->m_warning_count= 0; + child_statement->m_rows_affected= 0; + + child_statement->m_rows_sent= 0; + child_statement->m_rows_examined= 0; + child_statement->m_created_tmp_disk_tables= 0; + child_statement->m_created_tmp_tables= 0; + child_statement->m_select_full_join= 0; + child_statement->m_select_full_range_join= 0; + child_statement->m_select_range= 0; + child_statement->m_select_range_check= 0; + child_statement->m_select_scan= 0; + child_statement->m_sort_merge_passes= 0; + child_statement->m_sort_range= 0; + child_statement->m_sort_rows= 0; + child_statement->m_sort_scan= 0; + child_statement->m_no_index_used= 0; + child_statement->m_no_good_index_used= 0; + } + pfs->m_events_statements_count= 0; + + pfs->m_lock.dirty_to_allocated(); + DBUG_RETURN(pfs); } } } @@ -780,6 +949,21 @@ PFS_thread* create_thread(PFS_thread_class *klass, const void *identity, DBUG_RETURN(NULL); } +PFS_mutex *sanitize_mutex(PFS_mutex *unsafe) +{ + SANITIZE_ARRAY_BODY(PFS_mutex, mutex_array, mutex_max, unsafe); +} + +PFS_rwlock *sanitize_rwlock(PFS_rwlock *unsafe) +{ + SANITIZE_ARRAY_BODY(PFS_rwlock, rwlock_array, rwlock_max, unsafe); +} + +PFS_cond *sanitize_cond(PFS_cond *unsafe) +{ + SANITIZE_ARRAY_BODY(PFS_cond, cond_array, cond_max, unsafe); +} + /** Sanitize a PFS_thread pointer. Validate that the PFS_thread is part of thread_array. @@ -794,25 +978,14 @@ PFS_thread *sanitize_thread(PFS_thread *unsafe) SANITIZE_ARRAY_BODY(PFS_thread, thread_array, thread_max, unsafe); } -const char *sanitize_file_name(const char *unsafe) +PFS_file *sanitize_file(PFS_file *unsafe) { - intptr ptr= (intptr) unsafe; - intptr first= (intptr) &file_array[0]; - intptr last= (intptr) &file_array[file_max]; - DBUG_ENTER("sanitize_file_name"); + SANITIZE_ARRAY_BODY(PFS_file, file_array, file_max, unsafe); +} - /* Check if unsafe points inside file_array[] */ - if (likely((first <= ptr) && (ptr < last))) - { - /* Check if unsafe points to PFS_file::m_filename */ - intptr offset= (ptr - first) % sizeof(PFS_file); - intptr valid_offset= my_offsetof(PFS_file, m_filename[0]); - if (likely(offset == valid_offset)) - { - DBUG_RETURN(unsafe); - } - } - DBUG_RETURN(NULL); +PFS_socket *sanitize_socket(PFS_socket *unsafe) +{ + SANITIZE_ARRAY_BODY(PFS_socket, socket_array, socket_max, unsafe); } /** @@ -824,6 +997,26 @@ void destroy_thread(PFS_thread *pfs) DBUG_ENTER("destroy_thread"); DBUG_ASSERT(pfs != NULL); + if (pfs->m_account != NULL) + { + pfs->m_account->release(); + pfs->m_account= NULL; + DBUG_ASSERT(pfs->m_user == NULL); + DBUG_ASSERT(pfs->m_host == NULL); + } + else + { + if (pfs->m_user != NULL) + { + pfs->m_user->release(); + pfs->m_user= NULL; + } + if (pfs->m_host != NULL) + { + pfs->m_host->release(); + pfs->m_host= NULL; + } + } if (pfs->m_filename_hash_pins) { lf_hash_put_pins(pfs->m_filename_hash_pins); @@ -834,6 +1027,36 @@ void destroy_thread(PFS_thread *pfs) lf_hash_put_pins(pfs->m_table_share_hash_pins); pfs->m_table_share_hash_pins= NULL; } + if (pfs->m_setup_actor_hash_pins) + { + lf_hash_put_pins(pfs->m_setup_actor_hash_pins); + pfs->m_setup_actor_hash_pins= NULL; + } + if (pfs->m_setup_object_hash_pins) + { + lf_hash_put_pins(pfs->m_setup_object_hash_pins); + pfs->m_setup_object_hash_pins= NULL; + } + if (pfs->m_user_hash_pins) + { + lf_hash_put_pins(pfs->m_user_hash_pins); + pfs->m_user_hash_pins= NULL; + } + if (pfs->m_account_hash_pins) + { + lf_hash_put_pins(pfs->m_account_hash_pins); + pfs->m_account_hash_pins= NULL; + } + if (pfs->m_host_hash_pins) + { + lf_hash_put_pins(pfs->m_host_hash_pins); + pfs->m_host_hash_pins= NULL; + } + if (pfs->m_digest_hash_pins) + { + lf_hash_put_pins(pfs->m_digest_hash_pins); + pfs->m_digest_hash_pins= NULL; + } pfs->m_lock.allocated_to_free(); DBUG_VOID_RETURN; } @@ -867,19 +1090,18 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, const char *filename, uint len) { PFS_file *pfs; - PFS_scan scan; + LF_PINS *pins; + char safe_buffer[FN_REFLEN]; + const char *safe_filename; DBUG_ENTER("find_or_create_file"); - LF_PINS *pins= get_filename_hash_pins(thread); + pins= get_filename_hash_pins(thread); if (unlikely(pins == NULL)) { file_lost++; DBUG_RETURN(NULL); } - char safe_buffer[FN_REFLEN]; - const char *safe_filename; - if (len >= FN_REFLEN) { /* @@ -948,7 +1170,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, /* Append the unresolved file name to the resolved path */ char *ptr= buffer + strlen(buffer); char *buf_end= &buffer[sizeof(buffer)-1]; - if ((buf_end > ptr) && (*(ptr-1) != FN_LIBCHAR)) + if (buf_end > ptr) *ptr++= FN_LIBCHAR; if (buf_end > ptr) strncpy(ptr, safe_filename + dirlen, buf_end - ptr); @@ -960,7 +1182,12 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, PFS_file **entry; uint retry_count= 0; const uint retry_max= 3; + static uint file_monotonic_index= 0; + uint index; + uint attempts= 0; + search: + entry= reinterpret_cast<PFS_file**> (lf_hash_search(&filename_hash, pins, normalized_filename, normalized_length)); @@ -974,58 +1201,55 @@ search: lf_hash_search_unpin(pins); - /* filename is not constant, just using it for noise on create */ - uint random= randomized_index(filename, file_max); - - for (scan.init(random, file_max); - scan.has_pass(); - scan.next_pass()) + while (++attempts <= file_max) { - pfs= file_array + scan.first(); - PFS_file *pfs_last= file_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + /* See create_mutex() */ + index= PFS_atomic::add_u32(& file_monotonic_index, 1) % file_max; + pfs= file_array + index; + + if (pfs->m_lock.is_free()) { - if (pfs->m_lock.is_free()) + if (pfs->m_lock.free_to_dirty()) { - if (pfs->m_lock.free_to_dirty()) + pfs->m_class= klass; + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + strncpy(pfs->m_filename, normalized_filename, normalized_length); + pfs->m_filename[normalized_length]= '\0'; + pfs->m_filename_length= normalized_length; + pfs->m_wait_stat.reset(); + pfs->m_file_stat.m_open_count= 1; + pfs->m_file_stat.m_io_stat.reset(); + pfs->m_identity= (const void *)pfs; + + int res; + res= lf_hash_insert(&filename_hash, thread->m_filename_hash_pins, + &pfs); + if (likely(res == 0)) { - pfs->m_class= klass; - strncpy(pfs->m_filename, normalized_filename, normalized_length); - pfs->m_filename[normalized_length]= '\0'; - pfs->m_filename_length= normalized_length; - pfs->m_file_stat.m_open_count= 1; - pfs->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_instance; - pfs->m_wait_stat.m_parent= &klass->m_wait_stat; - reset_single_stat_link(&pfs->m_wait_stat); - - int res; - res= lf_hash_insert(&filename_hash, pins, - &pfs); - if (likely(res == 0)) - { - pfs->m_lock.dirty_to_allocated(); - DBUG_RETURN(pfs); - } + pfs->m_lock.dirty_to_allocated(); + if (klass->is_singleton()) + klass->m_singleton= pfs; + DBUG_RETURN(pfs); + } - pfs->m_lock.dirty_to_free(); + pfs->m_lock.dirty_to_free(); - if (res > 0) + if (res > 0) + { + /* Duplicate insert by another thread */ + if (++retry_count > retry_max) { - /* Duplicate insert by another thread */ - if (++retry_count > retry_max) - { - /* Avoid infinite loops */ - file_lost++; - DBUG_RETURN(NULL); - } - goto search; + /* Avoid infinite loops */ + file_lost++; + DBUG_RETURN(NULL); } - - /* OOM in lf_hash_insert */ - file_lost++; - DBUG_RETURN(NULL); + goto search; } + + /* OOM in lf_hash_insert */ + file_lost++; + return NULL; } } } @@ -1058,12 +1282,27 @@ void destroy_file(PFS_thread *thread, PFS_file *pfs) DBUG_ASSERT(thread != NULL); DBUG_ASSERT(pfs != NULL); + PFS_file_class *klass= pfs->m_class; + + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_EVENT_NAME */ + uint index= klass->m_event_name_index; + global_instr_class_waits_array[index].aggregate(& pfs->m_wait_stat); + pfs->m_wait_stat.reset(); + + /* Aggregate to FILE_SUMMARY_BY_EVENT_NAME */ + klass->m_file_stat.m_io_stat.aggregate(& pfs->m_file_stat.m_io_stat); + pfs->m_file_stat.m_io_stat.reset(); + + if (klass->is_singleton()) + klass->m_singleton= NULL; LF_PINS *pins= get_filename_hash_pins(thread); DBUG_ASSERT(pins != NULL); lf_hash_delete(&filename_hash, pins, pfs->m_filename, pfs->m_filename_length); + if (klass->is_singleton()) + klass->m_singleton= NULL; pfs->m_lock.allocated_to_free(); DBUG_VOID_RETURN; } @@ -1071,53 +1310,282 @@ void destroy_file(PFS_thread *thread, PFS_file *pfs) /** Create instrumentation for a table instance. @param share the table share + @param opening_thread the opening thread @param identity the table address @return a table instance, or NULL */ -PFS_table* create_table(PFS_table_share *share, const void *identity) +PFS_table* create_table(PFS_table_share *share, PFS_thread *opening_thread, + const void *identity) { - PFS_scan scan; - uint random= randomized_index(identity, table_max); + static uint table_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_table *pfs; DBUG_ENTER("create_table"); - for (scan.init(random, table_max); + while (++attempts <= table_max) + { + /* See create_mutex() */ + index= PFS_atomic::add_u32(& table_monotonic_index, 1) % table_max; + pfs= table_array + index; + + if (pfs->m_lock.is_free()) + { + if (pfs->m_lock.free_to_dirty()) + { + pfs->m_identity= identity; + pfs->m_share= share; + pfs->m_io_enabled= share->m_enabled && + flag_global_instrumentation && global_table_io_class.m_enabled; + pfs->m_io_timed= share->m_timed && global_table_io_class.m_timed; + pfs->m_lock_enabled= share->m_enabled && + flag_global_instrumentation && global_table_lock_class.m_enabled; + pfs->m_lock_timed= share->m_timed && global_table_lock_class.m_timed; + pfs->m_has_io_stats= false; + pfs->m_has_lock_stats= false; + share->inc_refcount(); + pfs->m_table_stat.fast_reset(); + pfs->m_thread_owner= opening_thread; + pfs->m_lock.dirty_to_allocated(); + DBUG_RETURN(pfs); + } + } + } + + table_lost++; + DBUG_RETURN(NULL); +} + +void PFS_table::sanitized_aggregate(void) +{ + /* + This thread could be a TRUNCATE on an aggregated summary table, + and not own the table handle. + */ + PFS_table_share *safe_share= sanitize_table_share(m_share); + PFS_thread *safe_thread= sanitize_thread(m_thread_owner); + if ((safe_share != NULL && safe_thread != NULL) && + (m_has_io_stats || m_has_lock_stats)) + { + safe_aggregate(& m_table_stat, safe_share, safe_thread); + m_has_io_stats= false; + m_has_lock_stats= false; + } +} + +void PFS_table::sanitized_aggregate_io(void) +{ + PFS_table_share *safe_share= sanitize_table_share(m_share); + PFS_thread *safe_thread= sanitize_thread(m_thread_owner); + if (safe_share != NULL && safe_thread != NULL && m_has_io_stats) + { + safe_aggregate_io(& m_table_stat, safe_share, safe_thread); + m_has_io_stats= false; + } +} + +void PFS_table::sanitized_aggregate_lock(void) +{ + PFS_table_share *safe_share= sanitize_table_share(m_share); + PFS_thread *safe_thread= sanitize_thread(m_thread_owner); + if (safe_share != NULL && safe_thread != NULL && m_has_lock_stats) + { + safe_aggregate_lock(& m_table_stat, safe_share, safe_thread); + m_has_lock_stats= false; + } +} + +void PFS_table::safe_aggregate(PFS_table_stat *table_stat, + PFS_table_share *table_share, + PFS_thread *thread) +{ + DBUG_ASSERT(table_stat != NULL); + DBUG_ASSERT(table_share != NULL); + DBUG_ASSERT(thread != NULL); + + if (flag_thread_instrumentation && thread->m_enabled) + { + PFS_single_stat *event_name_array; + uint index; + event_name_array= thread->m_instr_class_waits_stats; + + /* + Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + (for wait/io/table/sql/handler) + */ + index= global_table_io_class.m_event_name_index; + table_stat->sum_io(& event_name_array[index]); + + /* + Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + (for wait/lock/table/sql/handler) + */ + index= global_table_lock_class.m_event_name_index; + table_stat->sum_lock(& event_name_array[index]); + } + + /* Aggregate to TABLE_IO_SUMMARY, TABLE_LOCK_SUMMARY */ + table_share->m_table_stat.aggregate(table_stat); + table_stat->fast_reset(); +} + +void PFS_table::safe_aggregate_io(PFS_table_stat *table_stat, + PFS_table_share *table_share, + PFS_thread *thread) +{ + DBUG_ASSERT(table_stat != NULL); + DBUG_ASSERT(table_share != NULL); + DBUG_ASSERT(thread != NULL); + + if (flag_thread_instrumentation && thread->m_enabled) + { + PFS_single_stat *event_name_array; + uint index; + event_name_array= thread->m_instr_class_waits_stats; + + /* + Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + (for wait/io/table/sql/handler) + */ + index= global_table_io_class.m_event_name_index; + table_stat->sum_io(& event_name_array[index]); + } + + /* Aggregate to TABLE_IO_SUMMARY */ + table_share->m_table_stat.aggregate_io(table_stat); + table_stat->fast_reset_io(); +} + +void PFS_table::safe_aggregate_lock(PFS_table_stat *table_stat, + PFS_table_share *table_share, + PFS_thread *thread) +{ + DBUG_ASSERT(table_stat != NULL); + DBUG_ASSERT(table_share != NULL); + DBUG_ASSERT(thread != NULL); + + if (flag_thread_instrumentation && thread->m_enabled) + { + PFS_single_stat *event_name_array; + uint index; + event_name_array= thread->m_instr_class_waits_stats; + + /* + Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + (for wait/lock/table/sql/handler) + */ + index= global_table_lock_class.m_event_name_index; + table_stat->sum_lock(& event_name_array[index]); + } + + /* Aggregate to TABLE_LOCK_SUMMARY */ + table_share->m_table_stat.aggregate_lock(table_stat); + table_stat->fast_reset_lock(); +} + +/** + Destroy instrumentation for a table instance. + @param pfs the table to destroy +*/ +void destroy_table(PFS_table *pfs) +{ + DBUG_ENTER("destroy_table"); + + DBUG_ASSERT(pfs != NULL); + pfs->m_share->dec_refcount(); + pfs->m_lock.allocated_to_free(); + DBUG_VOID_RETURN; +} + +/** + Create instrumentation for a socket instance. + @param klass the socket class + @param identity the socket descriptor + @return a socket instance, or NULL +*/ +PFS_socket* create_socket(PFS_socket_class *klass, const void *identity) +{ + PFS_scan scan; + DBUG_ENTER("create_socket"); + + /** + Unlike other instrumented objects, there is no socket 'object' to use as a + unique identifier. Instead, a pointer to the PFS_socket object will be used + to identify this socket instance. The socket descriptor will be used to + seed the the random index assignment. + */ + my_socket fd= likely(identity != NULL) ? + *(reinterpret_cast<const my_socket*>(identity)) : 0; + my_ptrdiff_t ptr= fd; + uint random= randomized_index((const void *)ptr, socket_max); + + for (scan.init(random, socket_max); scan.has_pass(); scan.next_pass()) { - PFS_table *pfs= table_array + scan.first(); - PFS_table *pfs_last= table_array + scan.last(); + PFS_socket *pfs= socket_array + scan.first(); + PFS_socket *pfs_last= socket_array + scan.last(); for ( ; pfs < pfs_last; pfs++) { if (pfs->m_lock.is_free()) { if (pfs->m_lock.free_to_dirty()) { - pfs->m_identity= identity; - pfs->m_share= share; - pfs->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_instance; - pfs->m_wait_stat.m_parent= &share->m_wait_stat; - reset_single_stat_link(&pfs->m_wait_stat); + pfs->m_fd= fd; + pfs->m_identity= pfs; + pfs->m_class= klass; + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + pfs->m_idle= false; + pfs->m_socket_stat.reset(); pfs->m_lock.dirty_to_allocated(); + pfs->m_thread_owner= NULL; + if (klass->is_singleton()) + klass->m_singleton= pfs; DBUG_RETURN(pfs); } } } } - table_lost++; + socket_lost++; DBUG_RETURN(NULL); } /** - Destroy instrumentation for a table instance. - @param pfs the table to destroy + Destroy instrumentation for a socket instance. + @param pfs the socket to destroy */ -void destroy_table(PFS_table *pfs) +void destroy_socket(PFS_socket *pfs) { - DBUG_ENTER("destroy_table"); - DBUG_ASSERT(pfs != NULL); + PFS_socket_class *klass= pfs->m_class; + DBUG_ENTER("destroy_socket"); + + /* Aggregate to SOCKET_SUMMARY_BY_EVENT_NAME */ + klass->m_socket_stat.m_io_stat.aggregate(&pfs->m_socket_stat.m_io_stat); + + if (klass->is_singleton()) + klass->m_singleton= NULL; + + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME */ + PFS_thread *thread= pfs->m_thread_owner; + if (thread != NULL) + { + PFS_single_stat *event_name_array; + event_name_array= thread->m_instr_class_waits_stats; + uint index= pfs->m_class->m_event_name_index; + + /* Combine stats for all operations */ + PFS_single_stat stat; + pfs->m_socket_stat.m_io_stat.sum_waits(&stat); + event_name_array[index].aggregate(&stat); + } + + pfs->m_socket_stat.reset(); + pfs->m_thread_owner= NULL; + pfs->m_fd= 0; + pfs->m_addr_len= 0; pfs->m_lock.allocated_to_free(); DBUG_VOID_RETURN; } @@ -1129,7 +1597,7 @@ static void reset_mutex_waits_by_instance(void) DBUG_ENTER("reset_mutex_waits_by_instance"); for ( ; pfs < pfs_last; pfs++) - reset_single_stat_link(&pfs->m_wait_stat); + pfs->m_wait_stat.reset(); DBUG_VOID_RETURN; } @@ -1140,7 +1608,7 @@ static void reset_rwlock_waits_by_instance(void) DBUG_ENTER("reset_rwlock_waits_by_instance"); for ( ; pfs < pfs_last; pfs++) - reset_single_stat_link(&pfs->m_wait_stat); + pfs->m_wait_stat.reset(); DBUG_VOID_RETURN; } @@ -1151,7 +1619,7 @@ static void reset_cond_waits_by_instance(void) DBUG_ENTER("reset_cond_waits_by_instance"); for ( ; pfs < pfs_last; pfs++) - reset_single_stat_link(&pfs->m_wait_stat); + pfs->m_wait_stat.reset(); DBUG_VOID_RETURN; } @@ -1162,20 +1630,27 @@ static void reset_file_waits_by_instance(void) DBUG_ENTER("reset_file_waits_by_instance"); for ( ; pfs < pfs_last; pfs++) - reset_single_stat_link(&pfs->m_wait_stat); + pfs->m_file_stat.reset(); DBUG_VOID_RETURN; } +static void reset_socket_waits_by_instance(void) +{ + PFS_socket *pfs= socket_array; + PFS_socket *pfs_last= socket_array + socket_max; + + for ( ; pfs < pfs_last; pfs++) + pfs->m_socket_stat.reset(); +} + /** Reset the wait statistics per object instance. */ void reset_events_waits_by_instance(void) { - DBUG_ENTER("reset_events_waits_by_instance"); - reset_mutex_waits_by_instance(); reset_rwlock_waits_by_instance(); reset_cond_waits_by_instance(); reset_file_waits_by_instance(); - DBUG_VOID_RETURN; + reset_socket_waits_by_instance(); } /** Reset the io statistics per file instance. */ @@ -1186,8 +1661,595 @@ void reset_file_instance_io(void) DBUG_ENTER("reset_file_instance_io"); for ( ; pfs < pfs_last; pfs++) - reset_file_stat(&pfs->m_file_stat); + pfs->m_file_stat.m_io_stat.reset(); + DBUG_VOID_RETURN; +} + +/** Reset the io statistics per socket instance. */ +void reset_socket_instance_io(void) +{ + PFS_socket *pfs= socket_array; + PFS_socket *pfs_last= socket_array + socket_max; + DBUG_ENTER("reset_socket_instance_io"); + + for ( ; pfs < pfs_last; pfs++) + pfs->m_socket_stat.m_io_stat.reset(); DBUG_VOID_RETURN; } +void reset_global_wait_stat() +{ + PFS_single_stat *stat= global_instr_class_waits_array; + PFS_single_stat *stat_last= global_instr_class_waits_array + wait_class_max; + + for ( ; stat < stat_last; stat++) + stat->reset(); +} + +void aggregate_all_event_names(PFS_single_stat *from_array, + PFS_single_stat *to_array) +{ + PFS_single_stat *from; + PFS_single_stat *from_last; + PFS_single_stat *to; + + from= from_array; + from_last= from_array + wait_class_max; + to= to_array; + + for ( ; from < from_last ; from++, to++) + { + if (from->m_count > 0) + { + to->aggregate(from); + from->reset(); + } + } +} + +void aggregate_all_event_names(PFS_single_stat *from_array, + PFS_single_stat *to_array_1, + PFS_single_stat *to_array_2) +{ + PFS_single_stat *from; + PFS_single_stat *from_last; + PFS_single_stat *to_1; + PFS_single_stat *to_2; + + from= from_array; + from_last= from_array + wait_class_max; + to_1= to_array_1; + to_2= to_array_2; + + for ( ; from < from_last ; from++, to_1++, to_2++) + { + if (from->m_count > 0) + { + to_1->aggregate(from); + to_2->aggregate(from); + from->reset(); + } + } +} + +void aggregate_all_stages(PFS_stage_stat *from_array, + PFS_stage_stat *to_array) +{ + PFS_stage_stat *from; + PFS_stage_stat *from_last; + PFS_stage_stat *to; + + from= from_array; + from_last= from_array + stage_class_max; + to= to_array; + + for ( ; from < from_last ; from++, to++) + { + if (from->m_timer1_stat.m_count > 0) + { + to->aggregate(from); + from->reset(); + } + } +} + +void aggregate_all_stages(PFS_stage_stat *from_array, + PFS_stage_stat *to_array_1, + PFS_stage_stat *to_array_2) +{ + PFS_stage_stat *from; + PFS_stage_stat *from_last; + PFS_stage_stat *to_1; + PFS_stage_stat *to_2; + + from= from_array; + from_last= from_array + stage_class_max; + to_1= to_array_1; + to_2= to_array_2; + + for ( ; from < from_last ; from++, to_1++, to_2++) + { + if (from->m_timer1_stat.m_count > 0) + { + to_1->aggregate(from); + to_2->aggregate(from); + from->reset(); + } + } +} + +void aggregate_all_statements(PFS_statement_stat *from_array, + PFS_statement_stat *to_array) +{ + PFS_statement_stat *from; + PFS_statement_stat *from_last; + PFS_statement_stat *to; + + from= from_array; + from_last= from_array + statement_class_max; + to= to_array; + + for ( ; from < from_last ; from++, to++) + { + if (from->m_timer1_stat.m_count > 0) + { + to->aggregate(from); + from->reset(); + } + } +} + +void aggregate_all_statements(PFS_statement_stat *from_array, + PFS_statement_stat *to_array_1, + PFS_statement_stat *to_array_2) +{ + PFS_statement_stat *from; + PFS_statement_stat *from_last; + PFS_statement_stat *to_1; + PFS_statement_stat *to_2; + + from= from_array; + from_last= from_array + statement_class_max; + to_1= to_array_1; + to_2= to_array_2; + + for ( ; from < from_last ; from++, to_1++, to_2++) + { + if (from->m_timer1_stat.m_count > 0) + { + to_1->aggregate(from); + to_2->aggregate(from); + from->reset(); + } + } +} + +void aggregate_thread_stats(PFS_thread *thread) +{ + if (likely(thread->m_account != NULL)) + { + thread->m_account->m_disconnected_count++; + return; + } + + if (thread->m_user != NULL) + thread->m_user->m_disconnected_count++; + + if (thread->m_host != NULL) + thread->m_host->m_disconnected_count++; + + /* There is no global table for connections statistics. */ + return; +} + +void aggregate_thread(PFS_thread *thread) +{ + aggregate_thread_waits(thread); + aggregate_thread_stages(thread); + aggregate_thread_statements(thread); + aggregate_thread_stats(thread); +} + +void aggregate_thread_waits(PFS_thread *thread) +{ + if (likely(thread->m_account != NULL)) + { + DBUG_ASSERT(thread->m_user == NULL); + DBUG_ASSERT(thread->m_host == NULL); + DBUG_ASSERT(thread->m_account->get_refcount() > 0); + + /* + Aggregate EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + */ + aggregate_all_event_names(thread->m_instr_class_waits_stats, + thread->m_account->m_instr_class_waits_stats); + + return; + } + + if ((thread->m_user != NULL) && (thread->m_host != NULL)) + { + DBUG_ASSERT(thread->m_user->get_refcount() > 0); + DBUG_ASSERT(thread->m_host->get_refcount() > 0); + + /* + Aggregate EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_event_names(thread->m_instr_class_waits_stats, + thread->m_user->m_instr_class_waits_stats, + thread->m_host->m_instr_class_waits_stats); + return; + } + + if (thread->m_user != NULL) + { + DBUG_ASSERT(thread->m_user->get_refcount() > 0); + + /* + Aggregate EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME, directly. + */ + aggregate_all_event_names(thread->m_instr_class_waits_stats, + thread->m_user->m_instr_class_waits_stats); + return; + } + + if (thread->m_host != NULL) + { + DBUG_ASSERT(thread->m_host->get_refcount() > 0); + + /* + Aggregate EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME, directly. + */ + aggregate_all_event_names(thread->m_instr_class_waits_stats, + thread->m_host->m_instr_class_waits_stats); + return; + } + + /* Orphan thread, clean the waits stats. */ + thread->reset_waits_stats(); +} + +void aggregate_thread_stages(PFS_thread *thread) +{ + if (likely(thread->m_account != NULL)) + { + DBUG_ASSERT(thread->m_user == NULL); + DBUG_ASSERT(thread->m_host == NULL); + DBUG_ASSERT(thread->m_account->get_refcount() > 0); + + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + */ + aggregate_all_stages(thread->m_instr_class_stages_stats, + thread->m_account->m_instr_class_stages_stats); + + return; + } + + if ((thread->m_user != NULL) && (thread->m_host != NULL)) + { + DBUG_ASSERT(thread->m_user->get_refcount() > 0); + DBUG_ASSERT(thread->m_host->get_refcount() > 0); + + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_stages(thread->m_instr_class_stages_stats, + thread->m_user->m_instr_class_stages_stats, + thread->m_host->m_instr_class_stages_stats); + return; + } + + if (thread->m_user != NULL) + { + DBUG_ASSERT(thread->m_user->get_refcount() > 0); + + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME + in parallel. + */ + aggregate_all_stages(thread->m_instr_class_stages_stats, + thread->m_user->m_instr_class_stages_stats, + global_instr_class_stages_array); + return; + } + + if (thread->m_host != NULL) + { + DBUG_ASSERT(thread->m_host->get_refcount() > 0); + + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME, directly. + */ + aggregate_all_stages(thread->m_instr_class_stages_stats, + thread->m_host->m_instr_class_stages_stats); + return; + } + + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME. + */ + aggregate_all_stages(thread->m_instr_class_stages_stats, + global_instr_class_stages_array); +} + +void aggregate_thread_statements(PFS_thread *thread) +{ + if (likely(thread->m_account != NULL)) + { + DBUG_ASSERT(thread->m_user == NULL); + DBUG_ASSERT(thread->m_host == NULL); + DBUG_ASSERT(thread->m_account->get_refcount() > 0); + + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + */ + aggregate_all_statements(thread->m_instr_class_statements_stats, + thread->m_account->m_instr_class_statements_stats); + + return; + } + + if ((thread->m_user != NULL) && (thread->m_host != NULL)) + { + DBUG_ASSERT(thread->m_user->get_refcount() > 0); + DBUG_ASSERT(thread->m_host->get_refcount() > 0); + + /* + Aggregate EVENTS_STATEMENT_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - EVENTS_STATEMENT_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STATEMENT_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_statements(thread->m_instr_class_statements_stats, + thread->m_user->m_instr_class_statements_stats, + thread->m_host->m_instr_class_statements_stats); + return; + } + + if (thread->m_user != NULL) + { + DBUG_ASSERT(thread->m_user->get_refcount() > 0); + + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME + in parallel. + */ + aggregate_all_statements(thread->m_instr_class_statements_stats, + thread->m_user->m_instr_class_statements_stats, + global_instr_class_statements_array); + return; + } + + if (thread->m_host != NULL) + { + DBUG_ASSERT(thread->m_host->get_refcount() > 0); + + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME, directly. + */ + aggregate_all_statements(thread->m_instr_class_statements_stats, + thread->m_host->m_instr_class_statements_stats); + return; + } + + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME. + */ + aggregate_all_statements(thread->m_instr_class_statements_stats, + global_instr_class_statements_array); +} + +void clear_thread_account(PFS_thread *thread) +{ + if (thread->m_account != NULL) + { + thread->m_account->release(); + thread->m_account= NULL; + } + + if (thread->m_user != NULL) + { + thread->m_user->release(); + thread->m_user= NULL; + } + + if (thread->m_host != NULL) + { + thread->m_host->release(); + thread->m_host= NULL; + } +} + +void set_thread_account(PFS_thread *thread) +{ + DBUG_ASSERT(thread->m_account == NULL); + DBUG_ASSERT(thread->m_user == NULL); + DBUG_ASSERT(thread->m_host == NULL); + + thread->m_account= find_or_create_account(thread, + thread->m_username, + thread->m_username_length, + thread->m_hostname, + thread->m_hostname_length); + + if ((thread->m_account == NULL) && (thread->m_username_length > 0)) + thread->m_user= find_or_create_user(thread, + thread->m_username, + thread->m_username_length); + + if ((thread->m_account == NULL) && (thread->m_hostname_length > 0)) + thread->m_host= find_or_create_host(thread, + thread->m_hostname, + thread->m_hostname_length); +} + +void update_mutex_derived_flags() +{ + PFS_mutex *pfs= mutex_array; + PFS_mutex *pfs_last= mutex_array + mutex_max; + PFS_mutex_class *klass; + + for ( ; pfs < pfs_last; pfs++) + { + klass= sanitize_mutex_class(pfs->m_class); + if (likely(klass != NULL)) + { + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + } + else + { + pfs->m_enabled= false; + pfs->m_timed= false; + } + } +} + +void update_rwlock_derived_flags() +{ + PFS_rwlock *pfs= rwlock_array; + PFS_rwlock *pfs_last= rwlock_array + rwlock_max; + PFS_rwlock_class *klass; + + for ( ; pfs < pfs_last; pfs++) + { + klass= sanitize_rwlock_class(pfs->m_class); + if (likely(klass != NULL)) + { + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + } + else + { + pfs->m_enabled= false; + pfs->m_timed= false; + } + } +} + +void update_cond_derived_flags() +{ + PFS_cond *pfs= cond_array; + PFS_cond *pfs_last= cond_array + cond_max; + PFS_cond_class *klass; + + for ( ; pfs < pfs_last; pfs++) + { + klass= sanitize_cond_class(pfs->m_class); + if (likely(klass != NULL)) + { + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + } + else + { + pfs->m_enabled= false; + pfs->m_timed= false; + } + } +} + +void update_file_derived_flags() +{ + PFS_file *pfs= file_array; + PFS_file *pfs_last= file_array + file_max; + PFS_file_class *klass; + + for ( ; pfs < pfs_last; pfs++) + { + klass= sanitize_file_class(pfs->m_class); + if (likely(klass != NULL)) + { + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + } + else + { + pfs->m_enabled= false; + pfs->m_timed= false; + } + } +} + +void update_table_derived_flags() +{ + PFS_table *pfs= table_array; + PFS_table *pfs_last= table_array + table_max; + PFS_table_share *share; + + for ( ; pfs < pfs_last; pfs++) + { + share= sanitize_table_share(pfs->m_share); + if (likely(share != NULL)) + { + pfs->m_io_enabled= share->m_enabled && + flag_global_instrumentation && global_table_io_class.m_enabled; + pfs->m_io_timed= share->m_timed && global_table_io_class.m_timed; + pfs->m_lock_enabled= share->m_enabled && + flag_global_instrumentation && global_table_lock_class.m_enabled; + pfs->m_lock_timed= share->m_timed && global_table_lock_class.m_timed; + } + else + { + pfs->m_io_enabled= false; + pfs->m_io_timed= false; + pfs->m_lock_enabled= false; + pfs->m_lock_timed= false; + } + } +} + +void update_socket_derived_flags() +{ + PFS_socket *pfs= socket_array; + PFS_socket *pfs_last= socket_array + socket_max; + PFS_socket_class *klass; + + for ( ; pfs < pfs_last; pfs++) + { + klass= sanitize_socket_class(pfs->m_class); + if (likely(klass != NULL)) + { + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + } + else + { + pfs->m_enabled= false; + pfs->m_timed= false; + } + } +} + +void update_instruments_derived_flags() +{ + update_mutex_derived_flags(); + update_rwlock_derived_flags(); + update_cond_derived_flags(); + update_file_derived_flags(); + update_table_derived_flags(); + update_socket_derived_flags(); + /* nothing for stages and statements (no instances) */ +} + /** @} */ |