summaryrefslogtreecommitdiff
path: root/storage/perfschema/pfs_instr_class.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/perfschema/pfs_instr_class.cc')
-rw-r--r--storage/perfschema/pfs_instr_class.cc962
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);
+ }
}
/** @} */