diff options
Diffstat (limited to 'storage/perfschema/pfs_instr.cc')
-rw-r--r-- | storage/perfschema/pfs_instr.cc | 962 |
1 files changed, 962 insertions, 0 deletions
diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc new file mode 100644 index 00000000000..2ce3a844290 --- /dev/null +++ b/storage/perfschema/pfs_instr.cc @@ -0,0 +1,962 @@ +/* Copyright (C) 2008-2009 Sun Microsystems, Inc + + 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + @file storage/perfschema/pfs_instr.cc + Performance schema instruments (implementation). +*/ + +#include "my_global.h" +#include "mysql_priv.h" +#include "my_sys.h" +#include "pfs_stat.h" +#include "pfs_instr.h" +#include "pfs_global.h" + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +/** Size of the mutex instances array. @sa mutex_array */ +ulong mutex_max; +/** Number of mutexes instance lost. @sa mutex_array */ +ulong mutex_lost; +/** Size of the rwlock instances array. @sa rwlock_array */ +ulong rwlock_max; +/** Number or rwlock instances lost. @sa rwlock_array */ +ulong rwlock_lost; +/** Size of the conditions instances array. @sa cond_array */ +ulong cond_max; +/** Number of conditions instances lost. @sa cond_array */ +ulong cond_lost; +/** Size of the thread instances array. @sa thread_array */ +ulong thread_max; +/** Number or thread instances lost. @sa thread_array */ +ulong thread_lost; +/** Size of the file instances array. @sa file_array */ +ulong file_max; +/** Number of file instances lost. @sa file_array */ +ulong file_lost; +/** + Size of the file handle array. @sa file_handle_array. + Signed value, for easier comparisons with a file descriptor number. +*/ +long file_handle_max; +/** Number of file handle lost. @sa file_handle_array */ +ulong file_handle_lost; +/** Size of the table instances array. @sa table_array */ +ulong table_max; +/** Number of table instances lost. @sa table_array */ +ulong table_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 locker lost. @sa LOCKER_STACK_SIZE. */ +ulong locker_lost; + +/** + Mutex instrumentation instances array. + @sa mutex_max + @sa mutex_lost +*/ +PFS_mutex *mutex_array= NULL; + +/** + RWLock instrumentation instances array. + @sa rwlock_max + @sa rwlock_lost +*/ +PFS_rwlock *rwlock_array= NULL; + +/** + Condition instrumentation instances array. + @sa cond_max + @sa cond_lost +*/ +PFS_cond *cond_array= NULL; + +/** + Thread instrumentation instances array. + @sa thread_max + @sa thread_lost +*/ +PFS_thread *thread_array= NULL; + +/** + File instrumentation instances array. + @sa file_max + @sa file_lost + @sa filename_hash +*/ +PFS_file *file_array= NULL; + +/** + File instrumentation handle array. + @sa file_handle_max + @sa file_handle_lost +*/ +PFS_file **file_handle_array= NULL; + +/** + Table instrumentation instances array. + @sa table_max + @sa table_lost +*/ +PFS_table *table_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 PFS_events_waits *thread_history_array= NULL; + +/** Hash table for instrumented files. */ +static LF_HASH filename_hash; +/** True if filename_hash is initialized. */ +static bool filename_hash_inited= false; + +/** + Initialize all the instruments instance buffers. + @param param sizing parameters + @return 0 on success +*/ +int init_instruments(const PFS_global_param *param) +{ + uint thread_history_sizing; + uint index; + + mutex_max= param->m_mutex_sizing; + mutex_lost= 0; + rwlock_max= param->m_rwlock_sizing; + rwlock_lost= 0; + cond_max= param->m_cond_sizing; + cond_lost= 0; + file_max= param->m_file_sizing; + file_lost= 0; + file_handle_max= param->m_file_handle_sizing; + file_handle_lost= 0; + table_max= param->m_table_sizing; + table_lost= 0; + thread_max= param->m_thread_sizing; + thread_lost= 0; + + events_waits_history_per_thread= param->m_events_waits_history_sizing; + thread_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; + + mutex_array= NULL; + rwlock_array= NULL; + cond_array= NULL; + file_array= NULL; + file_handle_array= NULL; + table_array= NULL; + thread_array= NULL; + thread_history_array= NULL; + thread_instr_class_waits_array= NULL; + thread_internal_id_counter= 0; + + if (mutex_max > 0) + { + mutex_array= PFS_MALLOC_ARRAY(mutex_max, PFS_mutex, MYF(MY_ZEROFILL)); + if (unlikely(mutex_array == NULL)) + return 1; + } + + if (rwlock_max > 0) + { + rwlock_array= PFS_MALLOC_ARRAY(rwlock_max, PFS_rwlock, MYF(MY_ZEROFILL)); + if (unlikely(rwlock_array == NULL)) + return 1; + } + + if (cond_max > 0) + { + cond_array= PFS_MALLOC_ARRAY(cond_max, PFS_cond, MYF(MY_ZEROFILL)); + if (unlikely(cond_array == NULL)) + return 1; + } + + if (file_max > 0) + { + file_array= PFS_MALLOC_ARRAY(file_max, PFS_file, MYF(MY_ZEROFILL)); + if (unlikely(file_array == NULL)) + return 1; + } + + if (file_handle_max > 0) + { + file_handle_array= PFS_MALLOC_ARRAY(file_handle_max, PFS_file*, MYF(MY_ZEROFILL)); + if (unlikely(file_handle_array == NULL)) + return 1; + } + + if (table_max > 0) + { + table_array= PFS_MALLOC_ARRAY(table_max, PFS_table, MYF(MY_ZEROFILL)); + if (unlikely(table_array == NULL)) + return 1; + } + + if (thread_max > 0) + { + thread_array= PFS_MALLOC_ARRAY(thread_max, PFS_thread, MYF(MY_ZEROFILL)); + if (unlikely(thread_array == NULL)) + return 1; + } + + if (thread_history_sizing > 0) + { + thread_history_array= + PFS_MALLOC_ARRAY(thread_history_sizing, PFS_events_waits, + MYF(MY_ZEROFILL)); + if (unlikely(thread_history_array == NULL)) + return 1; + } + + if (thread_instr_class_waits_sizing > 0) + { + thread_instr_class_waits_array= + PFS_MALLOC_ARRAY(thread_instr_class_waits_sizing, + PFS_single_stat_chain, MYF(MY_ZEROFILL)); + if (unlikely(thread_instr_class_waits_array == NULL)) + 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_max; index++) + { + 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]; + } + + 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_ASSERT(thread != NULL); + DBUG_ASSERT(klass != NULL); + index= klass->m_index; + DBUG_ASSERT(index < mutex_class_max); + + stat= &(thread->m_instr_class_wait_stats[index]); + return stat; +} + +/** + 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_ASSERT(thread != NULL); + DBUG_ASSERT(klass != NULL); + index= klass->m_index; + DBUG_ASSERT(index < rwlock_class_max); + + stat= &(thread->m_instr_class_wait_stats + [per_thread_rwlock_class_start + index]); + return stat; +} + +/** + 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_ASSERT(thread != NULL); + DBUG_ASSERT(klass != NULL); + index= klass->m_index; + DBUG_ASSERT(index < cond_class_max); + + stat= &(thread->m_instr_class_wait_stats + [per_thread_cond_class_start + index]); + return stat; +} + +/** + 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_ASSERT(thread != NULL); + DBUG_ASSERT(klass != NULL); + index= klass->m_index; + DBUG_ASSERT(index < file_class_max); + + stat= &(thread->m_instr_class_wait_stats + [per_thread_file_class_start + index]); + return stat; +} + +/** 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; + + for ( ; stat < stat_last; stat++) + reset_single_stat_link(stat); +} + +/** Cleanup all the instruments buffers. */ +void cleanup_instruments(void) +{ + pfs_free(mutex_array); + mutex_array= NULL; + mutex_max= 0; + pfs_free(rwlock_array); + rwlock_array= NULL; + rwlock_max= 0; + pfs_free(cond_array); + cond_array= NULL; + cond_max= 0; + pfs_free(file_array); + file_array= NULL; + file_max= 0; + pfs_free(file_handle_array); + file_handle_array= NULL; + file_handle_max= 0; + pfs_free(table_array); + table_array= NULL; + table_max= 0; + pfs_free(thread_array); + thread_array= NULL; + thread_max= 0; + pfs_free(thread_history_array); + thread_history_array= NULL; + pfs_free(thread_instr_class_waits_array); + thread_instr_class_waits_array= NULL; +} + +static uchar *filename_hash_get_key(const uchar *entry, size_t *length, + my_bool) +{ + const PFS_file * const *typed_entry; + const PFS_file *file; + const void *result; + typed_entry= reinterpret_cast<const PFS_file* const *> (entry); + DBUG_ASSERT(typed_entry != NULL); + file= *typed_entry; + DBUG_ASSERT(file != NULL); + *length= file->m_filename_length; + result= file->m_filename; + return const_cast<uchar*> (reinterpret_cast<const uchar*> (result)); +} + +/** + Initialize the file name hash. + @return 0 on success +*/ +int init_file_hash(void) +{ + if (! filename_hash_inited) + { + lf_hash_init(&filename_hash, sizeof(PFS_file*), LF_HASH_UNIQUE, + 0, 0, filename_hash_get_key, &my_charset_bin); + filename_hash_inited= true; + } + return 0; +} + +/** Cleanup the file name hash. */ +void cleanup_file_hash(void) +{ + if (filename_hash_inited) + { + lf_hash_destroy(&filename_hash); + filename_hash_inited= false; + } +} + +/** + Create instrumentation for a mutex instance. + @param klass the mutex class + @param identity the mutex address + @return a mutex instance, or NULL +*/ +PFS_mutex* create_mutex(PFS_mutex_class *klass, const void *identity) +{ + int pass; + uint i= randomized_index(identity, mutex_max); + + /* + Pass 1: [random, mutex_max - 1] + Pass 2: [0, mutex_max - 1] + */ + for (pass= 1; pass <= 2; i=0, pass++) + { + PFS_mutex *pfs= mutex_array + i; + PFS_mutex *pfs_last= mutex_array + mutex_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_free()) + { + 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(); + return pfs; + } + } + } + } + + mutex_lost++; + return NULL; +} + +/** + Destroy instrumentation for a mutex instance. + @param pfs the mutex to destroy +*/ +void destroy_mutex(PFS_mutex *pfs) +{ + DBUG_ASSERT(pfs != NULL); + pfs->m_lock.allocated_to_free(); +} + +/** + Create instrumentation for a rwlock instance. + @param klass the rwlock class + @param identity the rwlock address + @return a rwlock instance, or NULL +*/ +PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity) +{ + int pass; + uint i= randomized_index(identity, rwlock_max); + + /* + Pass 1: [random, rwlock_max - 1] + Pass 2: [0, rwlock_max - 1] + */ + for (pass= 1; pass <= 2; i=0, pass++) + { + PFS_rwlock *pfs= rwlock_array + i; + PFS_rwlock *pfs_last= rwlock_array + rwlock_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_free()) + { + 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; + return pfs; + } + } + } + } + + rwlock_lost++; + return NULL; +} + +/** + Destroy instrumentation for a rwlock instance. + @param pfs the rwlock to destroy +*/ +void destroy_rwlock(PFS_rwlock *pfs) +{ + DBUG_ASSERT(pfs != NULL); + pfs->m_lock.allocated_to_free(); +} + +/** + Create instrumentation for a condition instance. + @param klass the condition class + @param identity the condition address + @return a condition instance, or NULL +*/ +PFS_cond* create_cond(PFS_cond_class *klass, const void *identity) +{ + int pass; + uint i= randomized_index(identity, cond_max); + + /* + Pass 1: [random, cond_max - 1] + Pass 2: [0, cond_max - 1] + */ + for (pass= 1; pass <= 2; i=0, pass++) + { + PFS_cond *pfs= cond_array + i; + PFS_cond *pfs_last= cond_array + cond_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_free()) + { + 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(); + return pfs; + } + } + } + } + + cond_lost++; + return NULL; +} + +/** + Destroy instrumentation for a condition instance. + @param pfs the condition to destroy +*/ +void destroy_cond(PFS_cond *pfs) +{ + DBUG_ASSERT(pfs != NULL); + pfs->m_lock.allocated_to_free(); +} + +/** + Create instrumentation for a thread instance. + @param klass the thread class + @param identity the thread address, + or a value characteristic of this thread + @param thread_id the PROCESSLIST thread id, + or 0 if unknown + @return a thread instance, or NULL +*/ +PFS_thread* create_thread(PFS_thread_class *klass, const void *identity, + ulong thread_id) +{ + int pass; + uint i= randomized_index(identity, thread_max); + + /* + Pass 1: [random, thread_max - 1] + Pass 2: [0, thread_max - 1] + */ + for (pass= 1; pass <= 2; i=0, pass++) + { + PFS_thread *pfs= thread_array + i; + PFS_thread *pfs_last= thread_array + thread_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_free()) + { + if (pfs->m_lock.free_to_dirty()) + { + 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(); + return pfs; + } + } + } + } + + thread_lost++; + return NULL; +} + +/** + Sanitize a PFS_thread pointer. + Validate that the PFS_thread is part of thread_array. + Sanitizing data is required when the data can be + damaged with expected race conditions, for example + involving EVENTS_WAITS_HISTORY_LONG. + @param unsafe the pointer to sanitize + @return a valid pointer, or NULL +*/ +PFS_thread *sanitize_thread(PFS_thread *unsafe) +{ + if ((&thread_array[0] <= unsafe) && + (unsafe < &thread_array[thread_max])) + return unsafe; + return NULL; +} + +/** + Destroy instrumentation for a thread instance. + @param pfs the thread to destroy +*/ +void destroy_thread(PFS_thread *pfs) +{ + DBUG_ASSERT(pfs != NULL); + if (pfs->m_filename_hash_pins) + { + lf_hash_put_pins(pfs->m_filename_hash_pins); + pfs->m_filename_hash_pins= NULL; + } + if (pfs->m_table_share_hash_pins) + { + lf_hash_put_pins(pfs->m_table_share_hash_pins); + pfs->m_table_share_hash_pins= NULL; + } + pfs->m_lock.allocated_to_free(); +} + +/** + Find or create instrumentation for a file instance by file name. + @param thread the executing instrumented thread + @param klass the file class + @param filename the file name + @param len the length in bytes of filename + @return a file instance, or NULL +*/ +PFS_file* +find_or_create_file(PFS_thread *thread, PFS_file_class *klass, + const char *filename, uint len) +{ + PFS_file *pfs; + int pass; + + if (! filename_hash_inited) + { + /* File instrumentation can be turned off. */ + file_lost++; + return NULL; + } + + if (unlikely(thread->m_filename_hash_pins == NULL)) + { + thread->m_filename_hash_pins= lf_hash_get_pins(&filename_hash); + if (unlikely(thread->m_filename_hash_pins == NULL)) + { + file_lost++; + return NULL; + } + } + + if (len >= sizeof(pfs->m_filename)) + len= sizeof(pfs->m_filename) - 1; + + PFS_file **entry; + uint retry_count= 0; + const uint retry_max= 3; +search: + entry= reinterpret_cast<PFS_file**> + (lf_hash_search(&filename_hash, thread->m_filename_hash_pins, + filename, len)); + if (entry && (entry != MY_ERRPTR)) + { + pfs= *entry; + pfs->m_file_stat.m_open_count++; + lf_hash_search_unpin(thread->m_filename_hash_pins); + return pfs; + } + + /* filename is not constant, just using it for noise on create */ + uint i= randomized_index(filename, file_max); + + /* + Pass 1: [random, file_max - 1] + Pass 2: [0, file_max - 1] + */ + for (pass= 1; pass <= 2; i=0, pass++) + { + pfs= file_array + i; + PFS_file *pfs_last= file_array + file_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_free()) + { + if (pfs->m_lock.free_to_dirty()) + { + pfs->m_class= klass; + strncpy(pfs->m_filename, filename, len); + pfs->m_filename[len]= '\0'; + pfs->m_filename_length= len; + 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, thread->m_filename_hash_pins, + &pfs); + if (likely(res == 0)) + { + pfs->m_lock.dirty_to_allocated(); + return pfs; + } + + pfs->m_lock.dirty_to_free(); + + if (res > 0) + { + /* Duplicate insert by another thread */ + if (++retry_count > retry_max) + { + /* Avoid infinite loops */ + file_lost++; + return NULL; + } + goto search; + } + + /* OOM in lf_hash_insert */ + file_lost++; + return NULL; + } + } + } + } + + file_lost++; + return NULL; +} + +/** + Release instrumentation for a file instance. + @param pfs the file to release +*/ +void release_file(PFS_file *pfs) +{ + DBUG_ASSERT(pfs != NULL); + pfs->m_file_stat.m_open_count--; +} + +/** + Destroy instrumentation for a file instance. + @param thread the executing thread instrumentation + @param pfs the file to destroy +*/ +void destroy_file(PFS_thread *thread, PFS_file *pfs) +{ + DBUG_ASSERT(thread != NULL); + DBUG_ASSERT(thread->m_filename_hash_pins != NULL); + DBUG_ASSERT(pfs != NULL); + lf_hash_delete(&filename_hash, thread->m_filename_hash_pins, + pfs->m_filename, pfs->m_filename_length); + pfs->m_lock.allocated_to_free(); +} + +/** + Create instrumentation for a table instance. + @param share the table share + @param identity the table address + @return a table instance, or NULL +*/ +PFS_table* create_table(PFS_table_share *share, const void *identity) +{ + int pass; + uint i= randomized_index(identity, table_max); + + /* + Pass 1: [random, table_max - 1] + Pass 2: [0, table_max - 1] + */ + for (pass= 1; pass <= 2; i=0, pass++) + { + PFS_table *pfs= table_array + i; + PFS_table *pfs_last= table_array + table_max; + 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_lock.dirty_to_allocated(); + return pfs; + } + } + } + } + + table_lost++; + return NULL; +} + +/** + Destroy instrumentation for a table instance. + @param pfs the table to destroy +*/ +void destroy_table(PFS_table *pfs) +{ + DBUG_ASSERT(pfs != NULL); + pfs->m_lock.allocated_to_free(); +} + +static void reset_mutex_waits_by_instance(void) +{ + PFS_mutex *pfs= mutex_array; + PFS_mutex *pfs_last= mutex_array + mutex_max; + + for ( ; pfs < pfs_last; pfs++) + reset_single_stat_link(&pfs->m_wait_stat); +} + +static void reset_rwlock_waits_by_instance(void) +{ + PFS_rwlock *pfs= rwlock_array; + PFS_rwlock *pfs_last= rwlock_array + rwlock_max; + + for ( ; pfs < pfs_last; pfs++) + reset_single_stat_link(&pfs->m_wait_stat); +} + +static void reset_cond_waits_by_instance(void) +{ + PFS_cond *pfs= cond_array; + PFS_cond *pfs_last= cond_array + cond_max; + + for ( ; pfs < pfs_last; pfs++) + reset_single_stat_link(&pfs->m_wait_stat); +} + +static void reset_file_waits_by_instance(void) +{ + PFS_file *pfs= file_array; + PFS_file *pfs_last= file_array + file_max; + + for ( ; pfs < pfs_last; pfs++) + reset_single_stat_link(&pfs->m_wait_stat); +} + +/** Reset the wait statistics per object instance. */ +void reset_events_waits_by_instance(void) +{ + reset_mutex_waits_by_instance(); + reset_rwlock_waits_by_instance(); + reset_cond_waits_by_instance(); + reset_file_waits_by_instance(); +} + +/** Reset the io statistics per file instance. */ +void reset_file_instance_io(void) +{ + PFS_file *pfs= file_array; + PFS_file *pfs_last= file_array + file_max; + + for ( ; pfs < pfs_last; pfs++) + reset_file_stat(&pfs->m_file_stat); +} + +/** @} */ |