diff options
Diffstat (limited to 'storage/perfschema/pfs_instr_class.cc')
-rw-r--r-- | storage/perfschema/pfs_instr_class.cc | 962 |
1 files changed, 746 insertions, 216 deletions
diff --git a/storage/perfschema/pfs_instr_class.cc b/storage/perfschema/pfs_instr_class.cc index 8bad6e99b3a..0a4b47404a4 100644 --- a/storage/perfschema/pfs_instr_class.cc +++ b/storage/perfschema/pfs_instr_class.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2010, 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 @@ -20,10 +20,14 @@ #include "my_global.h" #include "my_sys.h" +#include "structs.h" +#include "table.h" #include "pfs_instr_class.h" #include "pfs_instr.h" #include "pfs_global.h" +#include "pfs_timer.h" #include "pfs_events_waits.h" +#include "pfs_setup_object.h" #include "pfs_atomic.h" #include "mysql/psi/mysql_thread.h" #include "lf.h" @@ -44,6 +48,21 @@ my_bool pfs_enabled= TRUE; /** + PFS_INSTRUMENT option settings array and associated state variable to + serialize access during shutdown. + */ +DYNAMIC_ARRAY pfs_instr_config_array; +int pfs_instr_config_state= PFS_INSTR_CONFIG_NOT_INITIALIZED; + +static void configure_instr_class(PFS_instr_class *entry); + +static void init_instr_class(PFS_instr_class *klass, + const char *name, + uint name_length, + int flags, + PFS_class_type class_type); + +/** Current number of elements in mutex_class_array. This global variable is written to during: - the performance schema initialization @@ -76,14 +95,26 @@ ulong thread_class_lost= 0; ulong file_class_max= 0; /** Number of file class lost. @sa file_class_array */ ulong file_class_lost= 0; +/** Size of the stage class array. @sa stage_class_array */ +ulong stage_class_max= 0; +/** Number of stage class lost. @sa stage_class_array */ +ulong stage_class_lost= 0; +/** Size of the statement class array. @sa statement_class_array */ +ulong statement_class_max= 0; +/** Number of statement class lost. @sa statement_class_array */ +ulong statement_class_lost= 0; /** Size of the table share array. @sa table_share_array */ ulong table_share_max= 0; /** Number of table share lost. @sa table_share_array */ ulong table_share_lost= 0; +/** Size of the socket class array. @sa socket_class_array */ +ulong socket_class_max= 0; +/** Number of socket class lost. @sa socket_class_array */ +ulong socket_class_lost= 0; -static PFS_mutex_class *mutex_class_array= NULL; -static PFS_rwlock_class *rwlock_class_array= NULL; -static PFS_cond_class *cond_class_array= NULL; +PFS_mutex_class *mutex_class_array= NULL; +PFS_rwlock_class *rwlock_class_array= NULL; +PFS_cond_class *cond_class_array= NULL; /** Current number or elements in thread_class_array. @@ -104,29 +135,99 @@ static PFS_thread_class *thread_class_array= NULL; */ PFS_table_share *table_share_array= NULL; -PFS_instr_class global_table_class= -{ - "wait/table", /* name */ - 10, /* name length */ - 0, /* flags */ - true, /* enabled */ - true, /* timed */ - { &flag_events_waits_current, NULL, 0, 0, 0, 0} /* wait stat chain */ +PFS_instr_class global_table_io_class; +PFS_instr_class global_table_lock_class; +PFS_instr_class global_idle_class; + +/** Class-timer map */ +enum_timer_name *class_timers[] = +{&wait_timer, /* PFS_CLASS_NONE */ + &wait_timer, /* PFS_CLASS_MUTEX */ + &wait_timer, /* PFS_CLASS_RWLOCK */ + &wait_timer, /* PFS_CLASS_COND */ + &wait_timer, /* PFS_CLASS_FILE */ + &wait_timer, /* PFS_CLASS_TABLE */ + &stage_timer, /* PFS_CLASS_STAGE */ + &statement_timer, /* PFS_CLASS_STATEMENT */ + &wait_timer, /* PFS_CLASS_SOCKET */ + &wait_timer, /* PFS_CLASS_TABLE_IO */ + &wait_timer, /* PFS_CLASS_TABLE_LOCK */ + &idle_timer /* PFS_CLASS_IDLE */ }; -/** Hash table for instrumented tables. */ +/** + Hash index for instrumented table shares. + This index is searched by table fully qualified name (@c PFS_table_share_key), + and points to instrumented table shares (@c PFS_table_share). + @sa table_share_array + @sa PFS_table_share_key + @sa PFS_table_share + @sa table_share_hash_get_key + @sa get_table_share_hash_pins +*/ static LF_HASH table_share_hash; /** True if table_share_hash is initialized. */ static bool table_share_hash_inited= false; -C_MODE_START -/** Get hash table key for instrumented tables. */ -static uchar *table_share_hash_get_key(const uchar *, size_t *, my_bool); -C_MODE_END static volatile uint32 file_class_dirty_count= 0; static volatile uint32 file_class_allocated_count= 0; -static PFS_file_class *file_class_array= NULL; +PFS_file_class *file_class_array= NULL; + +static volatile uint32 stage_class_dirty_count= 0; +static volatile uint32 stage_class_allocated_count= 0; + +static PFS_stage_class *stage_class_array= NULL; + +static volatile uint32 statement_class_dirty_count= 0; +static volatile uint32 statement_class_allocated_count= 0; + +static PFS_statement_class *statement_class_array= NULL; + +static volatile uint32 socket_class_dirty_count= 0; +static volatile uint32 socket_class_allocated_count= 0; + +static PFS_socket_class *socket_class_array= NULL; + +uint mutex_class_start= 0; +uint rwlock_class_start= 0; +uint cond_class_start= 0; +uint file_class_start= 0; +uint table_class_start= 0; +uint wait_class_max= 0; +uint socket_class_start= 0; + +void init_event_name_sizing(const PFS_global_param *param) +{ + mutex_class_start= 0; + rwlock_class_start= mutex_class_start + param->m_mutex_class_sizing; + cond_class_start= rwlock_class_start + param->m_rwlock_class_sizing; + file_class_start= cond_class_start + param->m_cond_class_sizing; + socket_class_start= file_class_start + param->m_file_class_sizing; + table_class_start= socket_class_start + param->m_socket_class_sizing; + wait_class_max= table_class_start + 3; /* global table io, lock, idle */ +} + +void register_global_classes() +{ + /* Table IO class */ + init_instr_class(&global_table_io_class, "wait/io/table/sql/handler", 25, + 0, PFS_CLASS_TABLE_IO); + global_table_io_class.m_event_name_index= table_class_start; + configure_instr_class(&global_table_io_class); + + /* Table lock class */ + init_instr_class(&global_table_lock_class, "wait/lock/table/sql/handler", 27, + 0, PFS_CLASS_TABLE_LOCK); + global_table_lock_class.m_event_name_index= table_class_start + 1; + configure_instr_class(&global_table_lock_class); + + /* Idle class */ + init_instr_class(&global_idle_class, "idle", 4, + 0, PFS_CLASS_IDLE); + global_idle_class.m_event_name_index= table_class_start + 2; + configure_instr_class(&global_idle_class); +} /** Initialize the instrument synch class buffers. @@ -258,6 +359,8 @@ void cleanup_table_share(void) table_share_max= 0; } +C_MODE_START +/** get_key function for @c table_share_hash. */ static uchar *table_share_hash_get_key(const uchar *entry, size_t *length, my_bool) { @@ -272,6 +375,7 @@ static uchar *table_share_hash_get_key(const uchar *entry, size_t *length, result= &share->m_key.m_hash_key[0]; return const_cast<uchar*> (reinterpret_cast<const uchar*> (result)); } +C_MODE_END /** Initialize the table share hash table. */ int init_table_share_hash(void) @@ -296,6 +400,72 @@ void cleanup_table_share_hash(void) } /** + Get the hash pins for @sa table_share_hash. + @param thread The running thread. + @returns The LF_HASH pins for the thread. +*/ +LF_PINS* get_table_share_hash_pins(PFS_thread *thread) +{ + if (unlikely(thread->m_table_share_hash_pins == NULL)) + { + if (! table_share_hash_inited) + return NULL; + thread->m_table_share_hash_pins= lf_hash_get_pins(&table_share_hash); + } + return thread->m_table_share_hash_pins; +} + +/** + Set a table share hash key. + @param [out] key The key to populate. + @param temporary True for TEMPORARY TABLE. + @param schema_name The table schema name. + @param schema_name_length The table schema name length. + @param table_name The table name. + @param table_name_length The table name length. +*/ +static void set_table_share_key(PFS_table_share_key *key, + bool temporary, + const char *schema_name, uint schema_name_length, + const char *table_name, uint table_name_length) +{ + DBUG_ASSERT(schema_name_length <= NAME_LEN); + DBUG_ASSERT(table_name_length <= NAME_LEN); + char *saved_schema_name; + char *saved_table_name; + + char *ptr= &key->m_hash_key[0]; + ptr[0]= (temporary ? OBJECT_TYPE_TEMPORARY_TABLE : OBJECT_TYPE_TABLE); + ptr++; + saved_schema_name= ptr; + memcpy(ptr, schema_name, schema_name_length); + ptr+= schema_name_length; + ptr[0]= 0; + ptr++; + saved_table_name= ptr; + memcpy(ptr, table_name, table_name_length); + ptr+= table_name_length; + ptr[0]= 0; + ptr++; + key->m_key_length= ptr - &key->m_hash_key[0]; + + if (lower_case_table_names) + { + my_casedn_str(files_charset_info, saved_schema_name); + my_casedn_str(files_charset_info, saved_table_name); + } +} + +void PFS_table_share::refresh_setup_object_flags(PFS_thread *thread) +{ + lookup_setup_object(thread, + OBJECT_TYPE_TABLE, + m_schema_name, m_schema_name_length, + m_table_name, m_table_name_length, + &m_enabled, &m_timed); +} + +/** Initialize the file class buffer. @param file_class_sizing max number of file class @return 0 on success @@ -329,10 +499,113 @@ void cleanup_file_class(void) file_class_max= 0; } +/** + Initialize the stage class buffer. + @param stage_class_sizing max number of stage class + @return 0 on success +*/ +int init_stage_class(uint stage_class_sizing) +{ + int result= 0; + stage_class_dirty_count= stage_class_allocated_count= 0; + stage_class_max= stage_class_sizing; + stage_class_lost= 0; + + if (stage_class_max > 0) + { + stage_class_array= PFS_MALLOC_ARRAY(stage_class_max, PFS_stage_class, + MYF(MY_ZEROFILL)); + if (unlikely(stage_class_array == NULL)) + return 1; + } + else + stage_class_array= NULL; + + return result; +} + +/** Cleanup the stage class buffers. */ +void cleanup_stage_class(void) +{ + pfs_free(stage_class_array); + stage_class_array= NULL; + stage_class_dirty_count= stage_class_allocated_count= 0; + stage_class_max= 0; +} + +/** + Initialize the statement class buffer. + @param statement_class_sizing max number of statement class + @return 0 on success +*/ +int init_statement_class(uint statement_class_sizing) +{ + int result= 0; + statement_class_dirty_count= statement_class_allocated_count= 0; + statement_class_max= statement_class_sizing; + statement_class_lost= 0; + + if (statement_class_max > 0) + { + statement_class_array= PFS_MALLOC_ARRAY(statement_class_max, PFS_statement_class, + MYF(MY_ZEROFILL)); + if (unlikely(statement_class_array == NULL)) + return 1; + } + else + statement_class_array= NULL; + + return result; +} + +/** Cleanup the statement class buffers. */ +void cleanup_statement_class(void) +{ + pfs_free(statement_class_array); + statement_class_array= NULL; + statement_class_dirty_count= statement_class_allocated_count= 0; + statement_class_max= 0; +} + +/** + Initialize the socket class buffer. + @param socket_class_sizing max number of socket class + @return 0 on success +*/ +int init_socket_class(uint socket_class_sizing) +{ + int result= 0; + socket_class_dirty_count= socket_class_allocated_count= 0; + socket_class_max= socket_class_sizing; + socket_class_lost= 0; + + if (socket_class_max > 0) + { + socket_class_array= PFS_MALLOC_ARRAY(socket_class_max, PFS_socket_class, + MYF(MY_ZEROFILL)); + if (unlikely(socket_class_array == NULL)) + return 1; + } + else + socket_class_array= NULL; + + return result; +} + +/** Cleanup the socket class buffers. */ +void cleanup_socket_class(void) +{ + pfs_free(socket_class_array); + socket_class_array= NULL; + socket_class_dirty_count= socket_class_allocated_count= 0; + socket_class_max= 0; +} + static void init_instr_class(PFS_instr_class *klass, const char *name, uint name_length, - int flags) + int flags, + PFS_class_type class_type) { DBUG_ASSERT(name_length <= PFS_MAX_INFO_NAME_LENGTH); memset(klass, 0, sizeof(PFS_instr_class)); @@ -341,6 +614,43 @@ static void init_instr_class(PFS_instr_class *klass, klass->m_flags= flags; klass->m_enabled= true; klass->m_timed= true; + klass->m_type= class_type; + klass->m_timer= class_timers[class_type]; +} + +/** + Set user-defined configuration values for an instrument. +*/ +static void configure_instr_class(PFS_instr_class *entry) +{ + uint match_length= 0; /* length of matching pattern */ + + for (uint i= 0; i < pfs_instr_config_array.elements; i++) + { + PFS_instr_config* e; + get_dynamic(&pfs_instr_config_array, (uchar*)&e, i); + + /** + Compare class name to all configuration entries. In case of multiple + matches, the longer specification wins. For example, the pattern + 'ABC/DEF/GHI=ON' has precedence over 'ABC/DEF/%=OFF' regardless of + position within the configuration file or command line. + + Consecutive wildcards affect the count. + */ + if (!my_wildcmp(&my_charset_latin1, + entry->m_name, entry->m_name+entry->m_name_length, + e->m_name, e->m_name+e->m_name_length, + '\\', '?','%')) + { + if (e->m_name_length >= match_length) + { + entry->m_enabled= e->m_enabled; + entry->m_timed= e->m_timed; + match_length= MY_MAX(e->m_name_length, match_length); + } + } + } } #define REGISTER_CLASS_BODY_PART(INDEX, ARRAY, MAX, NAME, NAME_LENGTH) \ @@ -404,16 +714,16 @@ PFS_sync_key register_mutex_class(const char *name, uint name_length, in INSTALL PLUGIN. */ entry= &mutex_class_array[index]; - init_instr_class(entry, name, name_length, flags); - entry->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_event_name; - entry->m_wait_stat.m_parent= NULL; - reset_single_stat_link(&entry->m_wait_stat); - entry->m_lock_stat.m_control_flag= - &flag_events_locks_summary_by_event_name; - entry->m_lock_stat.m_parent= NULL; - reset_single_stat_link(&entry->m_lock_stat); - entry->m_index= index; + init_instr_class(entry, name, name_length, flags, PFS_CLASS_MUTEX); + entry->m_lock_stat.reset(); + entry->m_event_name_index= mutex_class_start + index; + entry->m_singleton= NULL; + entry->m_enabled= false; /* disabled by default */ + entry->m_timed= false; + + /* Set user-defined configuration options for this instrument */ + configure_instr_class(entry); + /* Now that this entry is populated, advertise it @@ -470,20 +780,15 @@ PFS_sync_key register_rwlock_class(const char *name, uint name_length, if (index < rwlock_class_max) { entry= &rwlock_class_array[index]; - init_instr_class(entry, name, name_length, flags); - entry->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_event_name; - entry->m_wait_stat.m_parent= NULL; - reset_single_stat_link(&entry->m_wait_stat); - entry->m_read_lock_stat.m_control_flag= - &flag_events_locks_summary_by_event_name; - entry->m_read_lock_stat.m_parent= NULL; - reset_single_stat_link(&entry->m_read_lock_stat); - entry->m_write_lock_stat.m_control_flag= - &flag_events_locks_summary_by_event_name; - entry->m_write_lock_stat.m_parent= NULL; - reset_single_stat_link(&entry->m_write_lock_stat); - entry->m_index= index; + init_instr_class(entry, name, name_length, flags, PFS_CLASS_RWLOCK); + entry->m_read_lock_stat.reset(); + entry->m_write_lock_stat.reset(); + entry->m_event_name_index= rwlock_class_start + index; + entry->m_singleton= NULL; + entry->m_enabled= false; /* disabled by default */ + entry->m_timed= false; + /* Set user-defined configuration options for this instrument */ + configure_instr_class(entry); PFS_atomic::add_u32(&rwlock_class_allocated_count, 1); return (index + 1); } @@ -514,12 +819,13 @@ PFS_sync_key register_cond_class(const char *name, uint name_length, if (index < cond_class_max) { entry= &cond_class_array[index]; - init_instr_class(entry, name, name_length, flags); - entry->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_event_name; - entry->m_wait_stat.m_parent= NULL; - reset_single_stat_link(&entry->m_wait_stat); - entry->m_index= index; + init_instr_class(entry, name, name_length, flags, PFS_CLASS_COND); + entry->m_event_name_index= cond_class_start + index; + entry->m_singleton= NULL; + entry->m_enabled= false; /* disabled by default */ + entry->m_timed= false; + /* Set user-defined configuration options for this instrument */ + configure_instr_class(entry); PFS_atomic::add_u32(&cond_class_allocated_count, 1); return (index + 1); } @@ -655,12 +961,13 @@ PFS_file_key register_file_class(const char *name, uint name_length, if (index < file_class_max) { entry= &file_class_array[index]; - init_instr_class(entry, name, name_length, flags); - entry->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_event_name; - entry->m_wait_stat.m_parent= NULL; - reset_single_stat_link(&entry->m_wait_stat); - entry->m_index= index; + init_instr_class(entry, name, name_length, flags, PFS_CLASS_FILE); + entry->m_event_name_index= file_class_start + index; + entry->m_singleton= NULL; + entry->m_enabled= true; /* enabled by default */ + entry->m_timed= true; + /* Set user-defined configuration options for this instrument */ + configure_instr_class(entry); PFS_atomic::add_u32(&file_class_allocated_count, 1); return (index + 1); } @@ -670,6 +977,80 @@ PFS_file_key register_file_class(const char *name, uint name_length, } /** + Register a stage instrumentation metadata. + @param name the instrumented name + @param name_length length in bytes of name + @param flags the instrumentation flags + @return a stage instrumentation key +*/ +PFS_stage_key register_stage_class(const char *name, uint name_length, + int flags) +{ + /* See comments in register_mutex_class */ + uint32 index; + PFS_stage_class *entry; + + REGISTER_CLASS_BODY_PART(index, stage_class_array, stage_class_max, + name, name_length) + + index= PFS_atomic::add_u32(&stage_class_dirty_count, 1); + + if (index < stage_class_max) + { + entry= &stage_class_array[index]; + init_instr_class(entry, name, name_length, flags, PFS_CLASS_STAGE); + entry->m_event_name_index= index; + entry->m_enabled= false; /* disabled by default */ + entry->m_timed= false; + /* Set user-defined configuration options for this instrument */ + configure_instr_class(entry); + PFS_atomic::add_u32(&stage_class_allocated_count, 1); + + return (index + 1); + } + + stage_class_lost++; + return 0; +} + +/** + Register a statement instrumentation metadata. + @param name the instrumented name + @param name_length length in bytes of name + @param flags the instrumentation flags + @return a statement instrumentation key +*/ +PFS_statement_key register_statement_class(const char *name, uint name_length, + int flags) +{ + /* See comments in register_mutex_class */ + uint32 index; + PFS_statement_class *entry; + + REGISTER_CLASS_BODY_PART(index, statement_class_array, statement_class_max, + name, name_length) + + index= PFS_atomic::add_u32(&statement_class_dirty_count, 1); + + if (index < statement_class_max) + { + entry= &statement_class_array[index]; + init_instr_class(entry, name, name_length, flags, PFS_CLASS_STATEMENT); + entry->m_event_name_index= index; + entry->m_enabled= true; /* enabled by default */ + entry->m_timed= true; + /* Set user-defined configuration options for this instrument */ + configure_instr_class(entry); + PFS_atomic::add_u32(&statement_class_allocated_count, 1); + + return (index + 1); + } + + statement_class_lost++; + return 0; +} + +/** Find a file instrumentation class by key. @param key the instrument key @return the instrument class, or NULL @@ -685,125 +1066,283 @@ PFS_file_class *sanitize_file_class(PFS_file_class *unsafe) } /** - Find or create a table instance by name. + Find a stage instrumentation class by key. + @param key the instrument key + @return the instrument class, or NULL +*/ +PFS_stage_class *find_stage_class(PFS_stage_key key) +{ + FIND_CLASS_BODY(key, stage_class_allocated_count, stage_class_array); +} + +PFS_stage_class *sanitize_stage_class(PFS_stage_class *unsafe) +{ + SANITIZE_ARRAY_BODY(PFS_stage_class, stage_class_array, stage_class_max, unsafe); +} + +/** + Find a statement instrumentation class by key. + @param key the instrument key + @return the instrument class, or NULL +*/ +PFS_statement_class *find_statement_class(PFS_stage_key key) +{ + FIND_CLASS_BODY(key, statement_class_allocated_count, statement_class_array); +} + +PFS_statement_class *sanitize_statement_class(PFS_statement_class *unsafe) +{ + SANITIZE_ARRAY_BODY(PFS_statement_class, statement_class_array, statement_class_max, unsafe); +} + +/** + Register a socket instrumentation metadata. + @param name the instrumented name + @param name_length length in bytes of name + @param flags the instrumentation flags + @return a socket instrumentation key +*/ +PFS_socket_key register_socket_class(const char *name, uint name_length, + int flags) +{ + /* See comments in register_mutex_class */ + uint32 index; + PFS_socket_class *entry; + + REGISTER_CLASS_BODY_PART(index, socket_class_array, socket_class_max, + name, name_length) + + index= PFS_atomic::add_u32(&socket_class_dirty_count, 1); + + if (index < socket_class_max) + { + entry= &socket_class_array[index]; + init_instr_class(entry, name, name_length, flags, PFS_CLASS_SOCKET); + entry->m_event_name_index= socket_class_start + index; + entry->m_singleton= NULL; + entry->m_enabled= false; /* disabled by default */ + entry->m_timed= false; + /* Set user-defined configuration options for this instrument */ + configure_instr_class(entry); + PFS_atomic::add_u32(&socket_class_allocated_count, 1); + return (index + 1); + } + + socket_class_lost++; + return 0; +} + +/** + Find a socket instrumentation class by key. + @param key the instrument key + @return the instrument class, or NULL +*/ +PFS_socket_class *find_socket_class(PFS_socket_key key) +{ + FIND_CLASS_BODY(key, socket_class_allocated_count, socket_class_array); +} + +PFS_socket_class *sanitize_socket_class(PFS_socket_class *unsafe) +{ + SANITIZE_ARRAY_BODY(PFS_socket_class, socket_class_array, socket_class_max, unsafe); +} + +PFS_instr_class *find_table_class(uint index) +{ + if (index == 1) + return & global_table_io_class; + if (index == 2) + return & global_table_lock_class; + return NULL; +} + +PFS_instr_class *sanitize_table_class(PFS_instr_class *unsafe) +{ + if (likely((& global_table_io_class == unsafe) || + (& global_table_lock_class == unsafe))) + return unsafe; + return NULL; +} + +PFS_instr_class *find_idle_class(uint index) +{ + if (index == 1) + return & global_idle_class; + return NULL; +} + +PFS_instr_class *sanitize_idle_class(PFS_instr_class *unsafe) +{ + if (likely(& global_idle_class == unsafe)) + return unsafe; + return NULL; +} + +static void set_keys(PFS_table_share *pfs, const TABLE_SHARE *share) +{ + int len; + KEY *key_info= share->key_info; + PFS_table_key *pfs_key= pfs->m_keys; + PFS_table_key *pfs_key_last= pfs->m_keys + share->keys; + pfs->m_key_count= share->keys; + + for ( ; pfs_key < pfs_key_last; pfs_key++, key_info++) + { + len= strlen(key_info->name); + memcpy(pfs_key->m_name, key_info->name, len); + pfs_key->m_name_length= len; + } + + pfs_key_last= pfs->m_keys + MAX_KEY; + for ( ; pfs_key < pfs_key_last; pfs_key++) + pfs_key->m_name_length= 0; +} + +static int compare_keys(PFS_table_share *pfs, const TABLE_SHARE *share) +{ + uint len; + KEY *key_info= share->key_info; + PFS_table_key *pfs_key= pfs->m_keys; + PFS_table_key *pfs_key_last= pfs->m_keys + share->keys; + + if (pfs->m_key_count != share->keys) + return 1; + + for ( ; pfs_key < pfs_key_last; pfs_key++, key_info++) + { + len= strlen(key_info->name); + if (len != pfs_key->m_name_length) + return 1; + + if (memcmp(pfs_key->m_name, key_info->name, len) != 0) + return 1; + } + + return 0; +} + +/** + Find or create a table share instrumentation. @param thread the executing instrumented thread - @param schema_name the table schema name - @param schema_name_length the table schema name length - @param table_name the table name - @param table_name_length the table name length - @return a table instance, or NULL + @param temporary true for TEMPORARY TABLE + @param share table share + @return a table share, or NULL */ PFS_table_share* find_or_create_table_share(PFS_thread *thread, - const char *schema_name, - uint schema_name_length, - const char *table_name, - uint table_name_length) + bool temporary, + const TABLE_SHARE *share) { /* See comments in register_mutex_class */ - int pass; PFS_table_share_key key; - if (! table_share_hash_inited) + LF_PINS *pins= get_table_share_hash_pins(thread); + if (unlikely(pins == NULL)) { - /* Table instrumentation can be turned off. */ table_share_lost++; return NULL; } - if (unlikely(thread->m_table_share_hash_pins == NULL)) - { - thread->m_table_share_hash_pins= lf_hash_get_pins(&table_share_hash); - if (unlikely(thread->m_table_share_hash_pins == NULL)) - { - table_share_lost++; - return NULL; - } - } + const char *schema_name= share->db.str; + uint schema_name_length= share->db.length; + const char *table_name= share->table_name.str; + uint table_name_length= share->table_name.length; - DBUG_ASSERT(schema_name_length <= NAME_LEN); - DBUG_ASSERT(table_name_length <= NAME_LEN); - - char *ptr= &key.m_hash_key[0]; - memcpy(ptr, schema_name, schema_name_length); - ptr+= schema_name_length; - ptr[0]= 0; ptr++; - memcpy(ptr, table_name, table_name_length); - ptr+= table_name_length; - ptr[0]= 0; ptr++; - key.m_key_length= ptr - &key.m_hash_key[0]; + set_table_share_key(&key, temporary, + schema_name, schema_name_length, + table_name, table_name_length); PFS_table_share **entry; uint retry_count= 0; const uint retry_max= 3; + bool enabled= true; + bool timed= true; + static uint table_share_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_table_share *pfs; + search: entry= reinterpret_cast<PFS_table_share**> - (lf_hash_search(&table_share_hash, thread->m_table_share_hash_pins, - &key.m_hash_key[0], key.m_key_length)); + (lf_hash_search(&table_share_hash, pins, + key.m_hash_key, key.m_key_length)); if (entry && (entry != MY_ERRPTR)) { - PFS_table_share *pfs; pfs= *entry; - lf_hash_search_unpin(thread->m_table_share_hash_pins); + pfs->inc_refcount() ; + if (compare_keys(pfs, share) != 0) + { + set_keys(pfs, share); + /* FIXME: aggregate to table_share sink ? */ + pfs->m_table_stat.fast_reset(); + } + lf_hash_search_unpin(pins); return pfs; } - /* table_name is not constant, just using it for noise on create */ - uint i= randomized_index(table_name, table_share_max); + lf_hash_search_unpin(pins); - /* - Pass 1: [random, table_share_max - 1] - Pass 2: [0, table_share_max - 1] - */ - for (pass= 1; pass <= 2; i=0, pass++) + if (retry_count == 0) + { + lookup_setup_object(thread, + OBJECT_TYPE_TABLE, + schema_name, schema_name_length, + table_name, table_name_length, + &enabled, &timed); + /* + Even when enabled is false, a record is added in the dictionary: + - It makes enabling a table already in the table cache possible, + - It improves performances for the next time a TABLE_SHARE is reloaded + in the table cache. + */ + } + + while (++attempts <= table_share_max) { - PFS_table_share *pfs= table_share_array + i; - PFS_table_share *pfs_last= table_share_array + table_share_max; - for ( ; pfs < pfs_last; pfs++) + /* See create_mutex() */ + PFS_atomic::add_u32(& table_share_monotonic_index, 1); + index= table_share_monotonic_index % table_share_max; + pfs= table_share_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_key= key; + pfs->m_schema_name= &pfs->m_key.m_hash_key[1]; + pfs->m_schema_name_length= schema_name_length; + pfs->m_table_name= &pfs->m_key.m_hash_key[schema_name_length + 2]; + pfs->m_table_name_length= table_name_length; + pfs->m_enabled= enabled; + pfs->m_timed= timed; + pfs->init_refcount(); + pfs->m_table_stat.fast_reset(); + set_keys(pfs, share); + + int res; + res= lf_hash_insert(&table_share_hash, pins, &pfs); + if (likely(res == 0)) { - pfs->m_key= key; - pfs->m_schema_name= &pfs->m_key.m_hash_key[0]; - pfs->m_schema_name_length= schema_name_length; - pfs->m_table_name= &pfs->m_key.m_hash_key[schema_name_length + 1]; - pfs->m_table_name_length= table_name_length; - pfs->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_instance; - pfs->m_wait_stat.m_parent= NULL; - reset_single_stat_link(&pfs->m_wait_stat); - pfs->m_enabled= true; - pfs->m_timed= true; - pfs->m_aggregated= false; - - int res; - res= lf_hash_insert(&table_share_hash, - thread->m_table_share_hash_pins, &pfs); - if (likely(res == 0)) - { - pfs->m_lock.dirty_to_allocated(); - return pfs; - } + pfs->m_lock.dirty_to_allocated(); + 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 */ - table_share_lost++; - return NULL; - } - goto search; + /* Avoid infinite loops */ + table_share_lost++; + return NULL; } - - /* OOM in lf_hash_insert */ - table_share_lost++; - return NULL; + goto search; } + + /* OOM in lf_hash_insert */ + table_share_lost++; + return NULL; } } } @@ -812,112 +1351,103 @@ search: return NULL; } -PFS_table_share *sanitize_table_share(PFS_table_share *unsafe) -{ - SANITIZE_ARRAY_BODY(PFS_table_share, table_share_array, table_share_max, unsafe); -} - -const char *sanitize_table_schema_name(const char *unsafe) +void PFS_table_share::aggregate_io(void) { - intptr ptr= (intptr) unsafe; - intptr first= (intptr) &table_share_array[0]; - intptr last= (intptr) &table_share_array[table_share_max]; - - - /* Check if unsafe points inside table_share_array[] */ - if (likely((first <= ptr) && (ptr < last))) - { - intptr offset= (ptr - first) % sizeof(PFS_table_share); - intptr from= my_offsetof(PFS_table_share, m_key.m_hash_key); - /* Check if unsafe points inside PFS_table_share::m_key::m_hash_key */ - if (likely((from <= offset) && (offset < from + PFS_TABLESHARE_HASHKEY_SIZE))) - { - PFS_table_share *base= (PFS_table_share*) (ptr - offset); - /* Check if unsafe really is the schema name */ - if (likely(base->m_schema_name == unsafe)) - return unsafe; - } - } - return NULL; + uint index= global_table_io_class.m_event_name_index; + PFS_single_stat *table_io_total= & global_instr_class_waits_array[index]; + m_table_stat.sum_io(table_io_total); + m_table_stat.fast_reset_io(); } -const char *sanitize_table_object_name(const char *unsafe) +void PFS_table_share::aggregate_lock(void) { - intptr ptr= (intptr) unsafe; - intptr first= (intptr) &table_share_array[0]; - intptr last= (intptr) &table_share_array[table_share_max]; - - - /* Check if unsafe points inside table_share_array[] */ - if (likely((first <= ptr) && (ptr < last))) - { - intptr offset= (ptr - first) % sizeof(PFS_table_share); - intptr from= my_offsetof(PFS_table_share, m_key.m_hash_key); - /* Check if unsafe points inside PFS_table_share::m_key::m_hash_key */ - if (likely((from <= offset) && (offset < from + PFS_TABLESHARE_HASHKEY_SIZE))) - { - PFS_table_share *base= (PFS_table_share*) (ptr - offset); - /* Check if unsafe really is the table name */ - if (likely(base->m_table_name == unsafe)) - return unsafe; - } - } - return NULL; + uint index= global_table_lock_class.m_event_name_index; + PFS_single_stat *table_lock_total= & global_instr_class_waits_array[index]; + m_table_stat.sum_lock(table_lock_total); + m_table_stat.fast_reset_lock(); } -static void reset_mutex_class_waits(void) +void release_table_share(PFS_table_share *pfs) { - PFS_mutex_class *pfs= mutex_class_array; - PFS_mutex_class *pfs_last= mutex_class_array + mutex_class_max; - - for ( ; pfs < pfs_last; pfs++) - reset_single_stat_link(&pfs->m_wait_stat); + DBUG_ASSERT(pfs->get_refcount() > 0); + pfs->dec_refcount(); } -static void reset_rwlock_class_waits(void) +/** + Drop the instrumented table share associated with a table. + @param thread The running thread + @param temporary True for TEMPORARY TABLE + @param schema_name The table schema name + @param schema_name_length The table schema name length + @param table_name The table name + @param table_name_length The table name length +*/ +void drop_table_share(PFS_thread *thread, + bool temporary, + const char *schema_name, uint schema_name_length, + const char *table_name, uint table_name_length) { - PFS_rwlock_class *pfs= rwlock_class_array; - PFS_rwlock_class *pfs_last= rwlock_class_array + rwlock_class_max; + PFS_table_share_key key; + LF_PINS* pins= get_table_share_hash_pins(thread); + if (unlikely(pins == NULL)) + return; + set_table_share_key(&key, temporary, schema_name, schema_name_length, + table_name, table_name_length); + PFS_table_share **entry; + entry= reinterpret_cast<PFS_table_share**> + (lf_hash_search(&table_share_hash, pins, + key.m_hash_key, key.m_key_length)); + if (entry && (entry != MY_ERRPTR)) + { + PFS_table_share *pfs= *entry; + lf_hash_delete(&table_share_hash, pins, + pfs->m_key.m_hash_key, pfs->m_key.m_key_length); + pfs->m_lock.allocated_to_free(); + } - for ( ; pfs < pfs_last; pfs++) - reset_single_stat_link(&pfs->m_wait_stat); + lf_hash_search_unpin(pins); } -static void reset_cond_class_waits(void) +/** + Sanitize an unsafe table_share pointer. + @param unsafe The possibly corrupt pointer. + @return A valid table_safe_pointer, or NULL. +*/ +PFS_table_share *sanitize_table_share(PFS_table_share *unsafe) { - PFS_cond_class *pfs= cond_class_array; - PFS_cond_class *pfs_last= cond_class_array + cond_class_max; - - for ( ; pfs < pfs_last; pfs++) - reset_single_stat_link(&pfs->m_wait_stat); + SANITIZE_ARRAY_BODY(PFS_table_share, table_share_array, table_share_max, unsafe); } -static void reset_file_class_waits(void) +/** Reset the io statistics per file class. */ +void reset_file_class_io(void) { PFS_file_class *pfs= file_class_array; PFS_file_class *pfs_last= file_class_array + file_class_max; for ( ; pfs < pfs_last; pfs++) - reset_single_stat_link(&pfs->m_wait_stat); + pfs->m_file_stat.m_io_stat.reset(); } -/** Reset the wait statistics for every instrument class. */ -void reset_instrument_class_waits(void) +/** Reset the io statistics per socket class. */ +void reset_socket_class_io(void) { - reset_mutex_class_waits(); - reset_rwlock_class_waits(); - reset_cond_class_waits(); - reset_file_class_waits(); + PFS_socket_class *pfs= socket_class_array; + PFS_socket_class *pfs_last= socket_class_array + socket_class_max; + + for ( ; pfs < pfs_last; pfs++) + pfs->m_socket_stat.m_io_stat.reset(); } -/** Reset the io statistics per file class. */ -void reset_file_class_io(void) +void update_table_share_derived_flags(PFS_thread *thread) { - PFS_file_class *pfs= file_class_array; - PFS_file_class *pfs_last= file_class_array + file_class_max; + PFS_table_share *pfs= table_share_array; + PFS_table_share *pfs_last= table_share_array + table_share_max; for ( ; pfs < pfs_last; pfs++) - reset_file_stat(&pfs->m_file_stat); + { + if (pfs->m_lock.is_populated()) + pfs->refresh_setup_object_flags(thread); + } } /** @} */ |