diff options
author | Michael Widenius <monty@askmonty.org> | 2012-08-01 17:27:34 +0300 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2012-08-01 17:27:34 +0300 |
commit | 1d0f70c2f894b27e98773a282871d32802f67964 (patch) | |
tree | 833e683e0ced29c4323c29a9d845703d4dfcd81b /storage/perfschema | |
parent | 5a86a61219826aadf8d08cbc447fe438f2bf50c3 (diff) | |
download | mariadb-git-1d0f70c2f894b27e98773a282871d32802f67964.tar.gz |
Temporary commit of merge of MariaDB 10.0-base and MySQL 5.6
Diffstat (limited to 'storage/perfschema')
162 files changed, 35292 insertions, 2833 deletions
diff --git a/storage/perfschema/CMakeLists.txt b/storage/perfschema/CMakeLists.txt index 7702b7365af..16087740da3 100644 --- a/storage/perfschema/CMakeLists.txt +++ b/storage/perfschema/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 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 @@ -21,56 +21,174 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ADD_DEFINITIONS(-DMYSQL_SERVER) -SET(PERFSCHEMA_SOURCES ha_perfschema.h - pfs_column_types.h - pfs_column_values.h - pfs_events_waits.h - pfs_global.h - pfs.h - pfs_instr.h - pfs_instr_class.h - pfs_lock.h - pfs_atomic.h - pfs_server.h - pfs_stat.h - pfs_engine_table.h - pfs_timer.h - table_all_instr.h - table_events_waits.h - table_events_waits_summary.h - table_ews_global_by_event_name.h - table_file_instances.h - table_file_summary.h - table_performance_timers.h - table_setup_consumers.h - table_setup_instruments.h - table_setup_timers.h - table_sync_instances.h - table_threads.h - ha_perfschema.cc - pfs.cc - pfs_column_values.cc - pfs_events_waits.cc - pfs_global.cc - pfs_instr.cc - pfs_instr_class.cc - pfs_server.cc - pfs_engine_table.cc - pfs_timer.cc - table_all_instr.cc - table_events_waits.cc - table_events_waits_summary.cc - table_ews_global_by_event_name.cc - table_file_instances.cc - table_file_summary.cc - table_performance_timers.cc - table_setup_consumers.cc - table_setup_instruments.cc - table_setup_timers.cc - table_sync_instances.cc - table_threads.cc - pfs_atomic.cc - pfs_check.cc +# Gen_pfs_lex_token +ADD_EXECUTABLE(gen_pfs_lex_token gen_pfs_lex_token.cc) +# gen_pfs_lex_token itself depends on ${CMAKE_CURRENT_BINARY_DIR}/sql/sql_yacc.h +ADD_DEPENDENCIES(gen_pfs_lex_token GenServerSource) + +ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pfs_lex_token.h + COMMAND gen_pfs_lex_token > pfs_lex_token.h + DEPENDS gen_pfs_lex_token +) + +SET(PFS_GEN_SOURCES + ${CMAKE_CURRENT_BINARY_DIR}/pfs_lex_token.h +) + +SET_SOURCE_FILES_PROPERTIES(${PFS_GEN_SOURCES} PROPERTIES GENERATED 1) + +# +# Maintainer: keep this list sorted, to avoid merge collisions. +# Tip: ls -1 *.h, ls -1 *.cc +# +SET(PERFSCHEMA_SOURCES +${PFS_GEN_SOURCES} +ha_perfschema.h +cursor_by_account.h +cursor_by_host.h +cursor_by_thread.h +cursor_by_user.h +pfs.h +pfs_account.h +pfs_atomic.h +pfs_column_types.h +pfs_column_values.h +pfs_con_slice.h +pfs_defaults.h +pfs_digest.h +pfs_engine_table.h +pfs_events.h +pfs_events_stages.h +pfs_events_statements.h +pfs_events_waits.h +pfs_global.h +pfs_host.h +pfs_instr.h +pfs_instr_class.h +pfs_lock.h +pfs_server.h +pfs_setup_actor.h +pfs_setup_object.h +pfs_stat.h +pfs_timer.h +pfs_user.h +pfs_visitor.h +table_accounts.h +table_all_instr.h +table_esgs_by_account_by_event_name.h +table_esgs_by_host_by_event_name.h +table_esgs_by_thread_by_event_name.h +table_esgs_by_user_by_event_name.h +table_esgs_global_by_event_name.h +table_esms_by_account_by_event_name.h +table_esms_by_host_by_event_name.h +table_esms_by_digest.h +table_esms_by_thread_by_event_name.h +table_esms_by_user_by_event_name.h +table_esms_global_by_event_name.h +table_events_stages.h +table_events_statements.h +table_events_waits.h +table_events_waits_summary.h +table_ews_by_account_by_event_name.h +table_ews_by_host_by_event_name.h +table_ews_by_thread_by_event_name.h +table_ews_by_user_by_event_name.h +table_ews_global_by_event_name.h +table_file_instances.h +table_file_summary_by_instance.h +table_file_summary_by_event_name.h +table_socket_instances.h +table_socket_summary_by_instance.h +table_socket_summary_by_event_name.h +table_helper.h +table_host_cache.h +table_hosts.h +table_os_global_by_type.h +table_performance_timers.h +table_setup_actors.h +table_setup_consumers.h +table_setup_instruments.h +table_setup_objects.h +table_setup_timers.h +table_sync_instances.h +table_threads.h +table_tiws_by_index_usage.h +table_tiws_by_table.h +table_tlws_by_table.h +table_users.h +cursor_by_account.cc +cursor_by_host.cc +cursor_by_thread.cc +cursor_by_user.cc +ha_perfschema.cc +pfs.cc +pfs_account.cc +pfs_atomic.cc +pfs_check.cc +pfs_column_values.cc +pfs_con_slice.cc +pfs_defaults.cc +pfs_digest.cc +pfs_engine_table.cc +pfs_events_stages.cc +pfs_events_statements.cc +pfs_events_waits.cc +pfs_global.cc +pfs_host.cc +pfs_instr.cc +pfs_instr_class.cc +pfs_server.cc +pfs_setup_actor.cc +pfs_setup_object.cc +pfs_timer.cc +pfs_user.cc +pfs_visitor.cc +table_accounts.cc +table_all_instr.cc +table_esgs_by_account_by_event_name.cc +table_esgs_by_host_by_event_name.cc +table_esgs_by_thread_by_event_name.cc +table_esgs_by_user_by_event_name.cc +table_esgs_global_by_event_name.cc +table_esms_by_account_by_event_name.cc +table_esms_by_host_by_event_name.cc +table_esms_by_digest.cc +table_esms_by_thread_by_event_name.cc +table_esms_by_user_by_event_name.cc +table_esms_global_by_event_name.cc +table_events_stages.cc +table_events_statements.cc +table_events_waits.cc +table_events_waits_summary.cc +table_ews_by_account_by_event_name.cc +table_ews_by_host_by_event_name.cc +table_ews_by_thread_by_event_name.cc +table_ews_by_user_by_event_name.cc +table_ews_global_by_event_name.cc +table_file_instances.cc +table_file_summary_by_instance.cc +table_file_summary_by_event_name.cc +table_socket_instances.cc +table_socket_summary_by_instance.cc +table_socket_summary_by_event_name.cc +table_helper.cc +table_host_cache.cc +table_hosts.cc +table_os_global_by_type.cc +table_performance_timers.cc +table_setup_actors.cc +table_setup_consumers.cc +table_setup_instruments.cc +table_setup_objects.cc +table_setup_timers.cc +table_sync_instances.cc +table_threads.cc +table_tiws_by_index_usage.cc +table_tiws_by_table.cc +table_tlws_by_table.cc +table_users.cc ) MYSQL_ADD_PLUGIN(perfschema ${PERFSCHEMA_SOURCES} STORAGE_ENGINE DEFAULT STATIC_ONLY) diff --git a/storage/perfschema/cursor_by_account.cc b/storage/perfschema/cursor_by_account.cc new file mode 100644 index 00000000000..91e9e3c6e54 --- /dev/null +++ b/storage/perfschema/cursor_by_account.cc @@ -0,0 +1,72 @@ +/* Copyright (c) 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 + 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/cursor_by_account.cc + Cursor CURSOR_BY_ACCOUNT (implementation). +*/ + +#include "my_global.h" +#include "cursor_by_account.h" +#include "pfs_user.h" + +cursor_by_account::cursor_by_account(const PFS_engine_table_share *share) + : PFS_engine_table(share, &m_pos), + m_pos(0), m_next_pos(0) +{} + +void cursor_by_account::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int cursor_by_account::rnd_next(void) +{ + PFS_account *pfs; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < account_max; + m_pos.next()) + { + pfs= &account_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int +cursor_by_account::rnd_pos(const void *pos) +{ + PFS_account *pfs; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < account_max); + pfs= &account_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + diff --git a/storage/perfschema/cursor_by_account.h b/storage/perfschema/cursor_by_account.h new file mode 100644 index 00000000000..98321df5751 --- /dev/null +++ b/storage/perfschema/cursor_by_account.h @@ -0,0 +1,59 @@ +/* Copyright (c) 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 + 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 */ + +#ifndef CURSOR_BY_ACCOUNT_H +#define CURSOR_BY_ACCOUNT_H + +/** + @file storage/perfschema/cursor_by_account.h + Cursor CURSOR_BY_ACCOUNT (declarations). +*/ + +#include "pfs_engine_table.h" +#include "pfs_account.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** Cursor CURSOR_BY_ACCOUNT. */ +class cursor_by_account : public PFS_engine_table +{ +public: + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + cursor_by_account(const PFS_engine_table_share *share); + +public: + ~cursor_by_account() + {} + +protected: + virtual void make_row(PFS_account *account)= 0; + +private: + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/cursor_by_host.cc b/storage/perfschema/cursor_by_host.cc new file mode 100644 index 00000000000..f62005511bf --- /dev/null +++ b/storage/perfschema/cursor_by_host.cc @@ -0,0 +1,72 @@ +/* Copyright (c) 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 + 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/cursor_by_host.cc + Cursor CURSOR_BY_HOST (implementation). +*/ + +#include "my_global.h" +#include "cursor_by_host.h" +#include "pfs_host.h" + +cursor_by_host::cursor_by_host(const PFS_engine_table_share *share) + : PFS_engine_table(share, &m_pos), + m_pos(0), m_next_pos(0) +{} + +void cursor_by_host::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int cursor_by_host::rnd_next(void) +{ + PFS_host *host; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < host_max; + m_pos.next()) + { + host= & host_array[m_pos.m_index]; + if (host->m_lock.is_populated()) + { + make_row(host); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int +cursor_by_host::rnd_pos(const void *pos) +{ + PFS_host *pfs; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < host_max); + pfs= &host_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + diff --git a/storage/perfschema/cursor_by_host.h b/storage/perfschema/cursor_by_host.h new file mode 100644 index 00000000000..3fbd09e3018 --- /dev/null +++ b/storage/perfschema/cursor_by_host.h @@ -0,0 +1,59 @@ +/* Copyright (c) 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 + 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 */ + +#ifndef CURSOR_BY_HOST_H +#define CURSOR_BY_HOST_H + +/** + @file storage/perfschema/cursor_by_host.h + Cursor CURSOR_BY_HOST (declarations). +*/ + +#include "pfs_engine_table.h" +#include "pfs_host.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** Cursor CURSOR_BY_HOST. */ +class cursor_by_host : public PFS_engine_table +{ +public: + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + cursor_by_host(const PFS_engine_table_share *share); + +public: + ~cursor_by_host() + {} + +protected: + virtual void make_row(PFS_host *host)= 0; + +private: + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/cursor_by_thread.cc b/storage/perfschema/cursor_by_thread.cc new file mode 100644 index 00000000000..06ee2f6cbef --- /dev/null +++ b/storage/perfschema/cursor_by_thread.cc @@ -0,0 +1,72 @@ +/* Copyright (c) 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 + 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/cursor_by_thread.cc + Cursor CURSOR_BY_THREAD (implementation). +*/ + +#include "my_global.h" +#include "cursor_by_thread.h" +#include "pfs_instr.h" + +cursor_by_thread::cursor_by_thread(const PFS_engine_table_share *share) + : PFS_engine_table(share, &m_pos), + m_pos(0), m_next_pos(0) +{} + +void cursor_by_thread::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int cursor_by_thread::rnd_next(void) +{ + PFS_thread *pfs; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < thread_max; + m_pos.next()) + { + pfs= &thread_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int +cursor_by_thread::rnd_pos(const void *pos) +{ + PFS_thread *pfs; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < thread_max); + pfs= &thread_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + diff --git a/storage/perfschema/cursor_by_thread.h b/storage/perfschema/cursor_by_thread.h new file mode 100644 index 00000000000..8f2edef6b7e --- /dev/null +++ b/storage/perfschema/cursor_by_thread.h @@ -0,0 +1,59 @@ +/* Copyright (c) 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 + 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 */ + +#ifndef CURSOR_BY_THREAD_H +#define CURSOR_BY_THREAD_H + +/** + @file storage/perfschema/cursor_by_thread.h + Cursor CURSOR_BY_THREAD (declarations). +*/ + +#include "pfs_engine_table.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** Cursor CURSOR_BY_THREAD. */ +class cursor_by_thread : public PFS_engine_table +{ +public: + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + cursor_by_thread(const PFS_engine_table_share *share); + +public: + ~cursor_by_thread() + {} + +protected: + virtual void make_row(PFS_thread *thread)= 0; + +private: + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/cursor_by_user.cc b/storage/perfschema/cursor_by_user.cc new file mode 100644 index 00000000000..8f8fe99f513 --- /dev/null +++ b/storage/perfschema/cursor_by_user.cc @@ -0,0 +1,72 @@ +/* Copyright (c) 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 + 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/cursor_by_user.cc + Cursor CURSOR_BY_USER (implementation). +*/ + +#include "my_global.h" +#include "cursor_by_user.h" +#include "pfs_user.h" + +cursor_by_user::cursor_by_user(const PFS_engine_table_share *share) + : PFS_engine_table(share, &m_pos), + m_pos(0), m_next_pos(0) +{} + +void cursor_by_user::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int cursor_by_user::rnd_next(void) +{ + PFS_user *pfs; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < user_max; + m_pos.next()) + { + pfs= &user_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int +cursor_by_user::rnd_pos(const void *pos) +{ + PFS_user *pfs; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < user_max); + pfs= &user_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + diff --git a/storage/perfschema/cursor_by_user.h b/storage/perfschema/cursor_by_user.h new file mode 100644 index 00000000000..c4f9cabc2dd --- /dev/null +++ b/storage/perfschema/cursor_by_user.h @@ -0,0 +1,59 @@ +/* Copyright (c) 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 + 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 */ + +#ifndef CURSOR_BY_USER_H +#define CURSOR_BY_USER_H + +/** + @file storage/perfschema/cursor_by_user.h + Cursor CURSOR_BY_USER (declarations). +*/ + +#include "pfs_engine_table.h" +#include "pfs_user.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** Cursor CURSOR_BY_USER. */ +class cursor_by_user : public PFS_engine_table +{ +public: + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + cursor_by_user(const PFS_engine_table_share *share); + +public: + ~cursor_by_user() + {} + +protected: + virtual void make_row(PFS_user *user)= 0; + +private: + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/gen_pfs_lex_token b/storage/perfschema/gen_pfs_lex_token Binary files differnew file mode 100755 index 00000000000..0b4116982bb --- /dev/null +++ b/storage/perfschema/gen_pfs_lex_token diff --git a/storage/perfschema/gen_pfs_lex_token.cc b/storage/perfschema/gen_pfs_lex_token.cc new file mode 100644 index 00000000000..b7470061de1 --- /dev/null +++ b/storage/perfschema/gen_pfs_lex_token.cc @@ -0,0 +1,265 @@ +/* + Copyright (c) 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +/* We only need the tokens here */ +#define YYSTYPE_IS_DECLARED +#include <../sql/sql_yacc.h> +#include <lex.h> + +#include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */ + +/* + This is a tool used during build only, + so MY_MAX_TOKEN does not need to be exact, + only big enough to hold: + - 256 character terminal tokens + - YYNTOKENS named terminal tokens + from bison. + See also YYMAXUTOK. +*/ +#define MY_MAX_TOKEN 1000 +struct gen_lex_token_string +{ + const char *m_token_string; + int m_token_length; +}; + +gen_lex_token_string compiled_token_array[MY_MAX_TOKEN]; +int max_token_seen= 0; + +char char_tokens[256]; + +int tok_pfs_generic_value= 0; +int tok_pfs_generic_value_list= 0; +int tok_pfs_row_single_value= 0; +int tok_pfs_row_single_value_list= 0; +int tok_pfs_row_multiple_value= 0; +int tok_pfs_row_multiple_value_list= 0; +int tok_pfs_unused= 0; + +void set_token(int tok, const char *str) +{ + if (tok <= 0) + { + fprintf(stderr, "Bad token found\n"); + exit(1); + } + + if (tok > max_token_seen) + { + max_token_seen= tok; + } + + if (max_token_seen >= MY_MAX_TOKEN) + { + fprintf(stderr, "Added that many new keywords ? Increase MY_MAX_TOKEN\n"); + exit(1); + } + + compiled_token_array[tok].m_token_string= str; + compiled_token_array[tok].m_token_length= strlen(str); +} + +void compute_tokens() +{ + int tok; + unsigned int i; + char *str; + + /* + Default value. + */ + for (tok= 0; tok < MY_MAX_TOKEN; tok++) + { + compiled_token_array[tok].m_token_string= "(unknown)"; + compiled_token_array[tok].m_token_length= 9; + } + + /* + Tokens made of just one terminal character + */ + for (tok=0; tok < 256; tok++) + { + str= & char_tokens[tok]; + str[0]= (char) tok; + compiled_token_array[tok].m_token_string= str; + compiled_token_array[tok].m_token_length= 1; + } + + max_token_seen= 255; + + /* + String terminal tokens, used in sql_yacc.yy + */ + set_token(NEG, "~"); + set_token(TABLE_REF_PRIORITY, "TABLE_REF_PRIORITY"); + + /* + Tokens hard coded in sql_lex.cc + */ + + set_token(WITH_CUBE_SYM, "WITH CUBE"); + set_token(WITH_ROLLUP_SYM, "WITH ROLLUP"); + set_token(NOT2_SYM, "!"); + set_token(OR2_SYM, "|"); + set_token(PARAM_MARKER, "?"); + set_token(SET_VAR, ":="); + set_token(UNDERSCORE_CHARSET, "(_charset)"); + set_token(END_OF_INPUT, ""); + + /* + Values. + These tokens are all normalized later, + so this strings will never be displayed. + */ + set_token(BIN_NUM, "(bin)"); + set_token(DECIMAL_NUM, "(decimal)"); + set_token(FLOAT_NUM, "(float)"); + set_token(HEX_NUM, "(hex)"); + set_token(LEX_HOSTNAME, "(hostname)"); + set_token(LONG_NUM, "(long)"); + set_token(NUM, "(num)"); + set_token(TEXT_STRING, "(text)"); + set_token(NCHAR_STRING, "(nchar)"); + set_token(ULONGLONG_NUM, "(ulonglong)"); + + /* + Identifiers. + */ + set_token(IDENT, "(id)"); + set_token(IDENT_QUOTED, "(id_quoted)"); + + /* + Unused tokens + */ + set_token(LOCATOR_SYM, "LOCATOR"); + set_token(SERVER_OPTIONS, "SERVER_OPTIONS"); + set_token(UDF_RETURNS_SYM, "UDF_RETURNS"); + + /* + See symbols[] in sql/lex.h + */ + for (i= 0; i< sizeof(symbols)/sizeof(symbols[0]); i++) + { + set_token(symbols[i].tok, symbols[i].name); + } + + /* + See sql_functions[] in sql/lex.h + */ + for (i= 0; i< sizeof(sql_functions)/sizeof(sql_functions[0]); i++) + { + set_token(sql_functions[i].tok, sql_functions[i].name); + } + + /* + Additional FAKE tokens, + used internally to normalize a digest text. + */ + + max_token_seen++; + tok_pfs_generic_value= max_token_seen; + set_token(tok_pfs_generic_value, "?"); + + max_token_seen++; + tok_pfs_generic_value_list= max_token_seen; + set_token(tok_pfs_generic_value_list, "?, ..."); + + max_token_seen++; + tok_pfs_row_single_value= max_token_seen; + set_token(tok_pfs_row_single_value, "(?)"); + + max_token_seen++; + tok_pfs_row_single_value_list= max_token_seen; + set_token(tok_pfs_row_single_value_list, "(?) /* , ... */"); + + max_token_seen++; + tok_pfs_row_multiple_value= max_token_seen; + set_token(tok_pfs_row_multiple_value, "(...)"); + + max_token_seen++; + tok_pfs_row_multiple_value_list= max_token_seen; + set_token(tok_pfs_row_multiple_value_list, "(...) /* , ... */"); + + max_token_seen++; + tok_pfs_unused= max_token_seen; + set_token(tok_pfs_unused, "UNUSED"); +} + +void print_tokens() +{ + int tok; + + printf("lex_token_string lex_token_array[]=\n"); + printf("{\n"); + printf("/* PART 1: character tokens. */\n"); + + for (tok= 0; tok<256; tok++) + { + printf("/* %03d */ { \"\\x%02x\", 1},\n", tok, tok); + } + + printf("/* PART 2: named tokens. */\n"); + + for (tok= 256; tok<= max_token_seen; tok++) + { + printf("/* %03d */ { \"%s\", %d},\n", + tok, + compiled_token_array[tok].m_token_string, + compiled_token_array[tok].m_token_length); + } + + printf("/* DUMMY */ { \"\", 0}\n"); + printf("};\n"); + + printf("/* PFS specific tokens. */\n"); + printf("#define TOK_PFS_GENERIC_VALUE %d\n", tok_pfs_generic_value); + printf("#define TOK_PFS_GENERIC_VALUE_LIST %d\n", tok_pfs_generic_value_list); + printf("#define TOK_PFS_ROW_SINGLE_VALUE %d\n", tok_pfs_row_single_value); + printf("#define TOK_PFS_ROW_SINGLE_VALUE_LIST %d\n", tok_pfs_row_single_value_list); + printf("#define TOK_PFS_ROW_MULTIPLE_VALUE %d\n", tok_pfs_row_multiple_value); + printf("#define TOK_PFS_ROW_MULTIPLE_VALUE_LIST %d\n", tok_pfs_row_multiple_value_list); + printf("#define TOK_PFS_UNUSED %d\n", tok_pfs_unused); +} + +int main(int argc,char **argv) +{ + puts("/*"); + puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2011, 2012")); + puts("*/"); + + printf("/*\n"); + printf(" This file is generated, do not edit.\n"); + printf(" See file storage/perfschema/gen_pfs_lex_token.cc.\n"); + printf("*/\n"); + printf("struct lex_token_string\n"); + printf("{\n"); + printf(" const char *m_token_string;\n"); + printf(" int m_token_length;\n"); + printf("};\n"); + printf("typedef struct lex_token_string lex_token_string;\n"); + + compute_tokens(); + print_tokens(); + + return 0; +} + diff --git a/storage/perfschema/ha_perfschema.cc b/storage/perfschema/ha_perfschema.cc index 0fb86cfe5cd..773d822af2b 100644 --- a/storage/perfschema/ha_perfschema.cc +++ b/storage/perfschema/ha_perfschema.cc @@ -28,6 +28,10 @@ #include "pfs_column_values.h" #include "pfs_instr_class.h" #include "pfs_instr.h" +#include "pfs_account.h" +#include "pfs_host.h" +#include "pfs_user.h" +#include "pfs_account.h" #ifdef MY_ATOMIC_MODE_DUMMY /* @@ -80,7 +84,8 @@ static int pfs_init_func(void *p) pfs_hton->show_status= pfs_show_status; pfs_hton->flags= HTON_ALTER_NOT_SUPPORTED | HTON_TEMPORARY_NOT_SUPPORTED | - HTON_NO_PARTITION; + HTON_NO_PARTITION | + HTON_NO_BINLOG_ROW_OPT; /* As long as the server implementation keeps using legacy_db_type, @@ -125,6 +130,8 @@ static struct st_mysql_show_var pfs_status_vars[]= (char*) &thread_class_lost, SHOW_LONG_NOFLUSH}, {"Performance_schema_file_classes_lost", (char*) &file_class_lost, SHOW_LONG_NOFLUSH}, + {"Performance_schema_socket_classes_lost", + (char*) &socket_class_lost, SHOW_LONG_NOFLUSH}, {"Performance_schema_mutex_instances_lost", (char*) &mutex_lost, SHOW_LONG}, {"Performance_schema_rwlock_instances_lost", @@ -137,6 +144,8 @@ static struct st_mysql_show_var pfs_status_vars[]= (char*) &file_lost, SHOW_LONG}, {"Performance_schema_file_handles_lost", (char*) &file_handle_lost, SHOW_LONG}, + {"Performance_schema_socket_instances_lost", + (char*) &socket_lost, SHOW_LONG}, {"Performance_schema_locker_lost", (char*) &locker_lost, SHOW_LONG}, /* table shares, can be flushed */ @@ -145,6 +154,18 @@ static struct st_mysql_show_var pfs_status_vars[]= /* table handles, can be flushed */ {"Performance_schema_table_handles_lost", (char*) &table_lost, SHOW_LONG}, + {"Performance_schema_hosts_lost", + (char*) &host_lost, SHOW_LONG}, + {"Performance_schema_users_lost", + (char*) &user_lost, SHOW_LONG}, + {"Performance_schema_accounts_lost", + (char*) &account_lost, SHOW_LONG}, + {"Performance_schema_stage_classes_lost", + (char*) &stage_class_lost, SHOW_LONG}, + {"Performance_schema_statement_classes_lost", + (char*) &statement_class_lost, SHOW_LONG}, + {"Performance_schema_digest_lost", + (char*) &digest_lost, SHOW_LONG}, {NullS, NullS, SHOW_LONG} }; @@ -217,8 +238,6 @@ int ha_perfschema::open(const char *name, int mode, uint test_if_locked) thr_lock_data_init(m_table_share->m_thr_lock_ptr, &m_thr_lock, NULL); ref_length= m_table_share->m_ref_length; - psi_open(); - DBUG_RETURN(0); } @@ -229,8 +248,6 @@ int ha_perfschema::close(void) delete m_table; m_table= NULL; - psi_close(); - DBUG_RETURN(0); } @@ -243,12 +260,7 @@ int ha_perfschema::write_row(uchar *buf) ha_statistic_increment(&SSV::ha_write_count); DBUG_ASSERT(m_table_share); - if (m_table_share->m_write_row) - result= m_table_share->m_write_row(table, buf, table->field); - else - { - result= HA_ERR_WRONG_COMMAND; - } + result= m_table_share->write_row(table, buf, table->field); DBUG_RETURN(result); } @@ -269,10 +281,21 @@ int ha_perfschema::update_row(const uchar *old_data, uchar *new_data) DBUG_ENTER("ha_perfschema::update_row"); DBUG_ASSERT(m_table); + ha_statistic_increment(&SSV::ha_update_count); int result= m_table->update_row(table, old_data, new_data, table->field); DBUG_RETURN(result); } +int ha_perfschema::delete_row(const uchar *buf) +{ + DBUG_ENTER("ha_perfschema::delete_row"); + + DBUG_ASSERT(m_table); + ha_statistic_increment(&SSV::ha_delete_count); + int result= m_table->delete_row(table, buf, table->field); + DBUG_RETURN(result); +} + int ha_perfschema::rnd_init(bool scan) { int result; @@ -287,6 +310,9 @@ int ha_perfschema::rnd_init(bool scan) else m_table->reset_position(); + if (m_table != NULL) + m_table->rnd_init(scan); + result= m_table ? 0 : HA_ERR_OUT_OF_MEM; DBUG_RETURN(result); } @@ -305,6 +331,8 @@ int ha_perfschema::rnd_next(uchar *buf) DBUG_ENTER("ha_perfschema::rnd_next"); DBUG_ASSERT(m_table); + ha_statistic_increment(&SSV::ha_read_rnd_next_count); + int result= m_table->rnd_next(); if (result == 0) { @@ -329,6 +357,7 @@ int ha_perfschema::rnd_pos(uchar *buf, uchar *pos) DBUG_ENTER("ha_perfschema::rnd_pos"); DBUG_ASSERT(m_table); + ha_statistic_increment(&SSV::ha_read_rnd_count); int result= m_table->rnd_pos(pos); if (result == 0) result= m_table->read_row(table, buf, table->field); @@ -340,7 +369,7 @@ int ha_perfschema::info(uint flag) DBUG_ENTER("ha_perfschema::info"); DBUG_ASSERT(m_table_share); if (flag & HA_STATUS_VARIABLE) - stats.records= m_table_share->m_records; + stats.records= m_table_share->get_row_count(); if (flag & HA_STATUS_CONST) ref_length= m_table_share->m_ref_length; DBUG_RETURN(0); @@ -406,6 +435,8 @@ int ha_perfschema::create(const char *name, TABLE *table_arg, This is not a general purpose engine. Failure to CREATE TABLE is the expected result. */ + DBUG_PRINT("error", ("unknown table: %s.%s", table_arg->s->db.str, + table_arg->s->table_name.str)); DBUG_RETURN(HA_ERR_WRONG_COMMAND); } diff --git a/storage/perfschema/ha_perfschema.h b/storage/perfschema/ha_perfschema.h index 17ab601e60f..91ca83c443e 100644 --- a/storage/perfschema/ha_perfschema.h +++ b/storage/perfschema/ha_perfschema.h @@ -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 @@ -18,10 +18,6 @@ #include "handler.h" /* class handler */ -#ifdef USE_PRAGMA_INTERFACE -#pragma interface /* gcc class implementation */ -#endif - /** @file storage/perfschema/ha_perfschema.h Performance schema storage engine (declarations). @@ -32,12 +28,18 @@ */ struct PFS_engine_table_share; class PFS_engine_table; +/** Name of the performance schema engine. */ extern const char *pfs_engine_name; /** A handler for a PERFORMANCE_SCHEMA table. */ class ha_perfschema : public handler { public: + /** + Create a new performance schema table handle on a table. + @param hton storage engine handler singleton + @param share table share + */ ha_perfschema(handlerton *hton, TABLE_SHARE *share); ~ha_perfschema(); @@ -70,13 +72,10 @@ public: Without HA_FAST_KEY_READ, the optimizer reads all columns and never calls ::rnd_pos(), so it is guaranteed to return only thread <n> records. - We use HA_HAS_OWN_BINLOGGING to stop changes to this table to - be logged to slaves (as enabled performance tracking on all slaves - is probably not what anyone wants) */ return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_NO_AUTO_INCREMENT | HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | - HA_HAS_OWN_BINLOGGING | HA_NO_BLOBS); + HA_PRIMARY_KEY_REQUIRED_FOR_DELETE | HA_HAS_OWN_BINLOGGING); } /** @@ -104,24 +103,72 @@ public: double scan_time(void) { return 1.0; } + /** + Open a performance schema table. + @param name the table to open + @param mode unused + @param test_if_locked unused + @return 0 on success + */ int open(const char *name, int mode, uint test_if_locked); + /** + Close a table handle. + @sa open. + */ int close(void); + /** + Write a row. + @param buf the row to write + @return 0 on success + */ int write_row(uchar *buf); void use_hidden_primary_key(); + /** + Update a row. + @param old_data the row old values + @param new_data the row new values + @return 0 on success + */ int update_row(const uchar *old_data, uchar *new_data); + /** + Delete a row. + @param buf the row to delete + @return 0 on success + */ + int delete_row(const uchar *buf); + int rnd_init(bool scan); + /** + Scan end. + @sa rnd_init. + */ int rnd_end(void); + /** + Iterator, fetch the next row. + @param[out] buf the row fetched. + @return 0 on success + */ int rnd_next(uchar *buf); + /** + Iterator, fetch the row at a given position. + @param[out] buf the row fetched. + @param pos the row position + @return 0 on success + */ int rnd_pos(uchar *buf, uchar *pos); + /** + Read the row current position. + @param record the current row + */ void position(const uchar *record); int info(uint); diff --git a/storage/perfschema/pfs.cc b/storage/perfschema/pfs.cc index 9a6ada2f814..ccb8c77d573 100644 --- a/storage/perfschema/pfs.cc +++ b/storage/perfschema/pfs.cc @@ -17,18 +17,29 @@ @file storage/perfschema/pfs.cc The performance schema implementation of all instruments. */ - #include "my_global.h" +#include "thr_lock.h" +#include "mysql/psi/psi.h" +#include "mysql/psi/mysql_thread.h" +#include "my_pthread.h" +#include "sql_const.h" #include "pfs.h" #include "pfs_instr_class.h" #include "pfs_instr.h" +#include "pfs_host.h" +#include "pfs_user.h" +#include "pfs_account.h" #include "pfs_global.h" #include "pfs_column_values.h" #include "pfs_timer.h" #include "pfs_events_waits.h" - -/* Pending WL#4895 PERFORMANCE_SCHEMA Instrumenting Table IO */ -#undef HAVE_TABLE_WAIT +#include "pfs_events_stages.h" +#include "pfs_events_statements.h" +#include "pfs_setup_actor.h" +#include "pfs_setup_object.h" +#include "sql_error.h" +#include "sp_head.h" +#include "pfs_digest.h" /** @page PAGE_PERFORMANCE_SCHEMA The Performance Schema main page @@ -300,8 +311,7 @@ */ /** - @page PAGE_INSTRUMENTATION_INTERFACE - Performance schema: instrumentation interface page. + @page PAGE_INSTRUMENTATION_INTERFACE Performance schema: instrumentation interface page. MySQL performance schema instrumentation interface. @section INTRO Introduction @@ -355,26 +365,14 @@ For a given instrumentation point in the API, the basic coding pattern used is: - - (a) If the performance schema is not initialized, do nothing - - (b) If the object acted upon is not instrumented, do nothing - - (c) otherwise, notify the performance schema of the operation + - (a) notify the performance schema of the operation about to be performed. + - (b) execute the instrumented code. + - (c) notify the performance schema that the operation + is completed. - The implementation of the instrumentation interface can: - - decide that it is not interested by the event, and return NULL. - In this context, 'interested' means whether the instrumentation for - this object + event is turned on in the performance schema configuration - (the SETUP_ tables). - - decide that this event is to be instrumented. - In this case, the instrumentation returns an opaque pointer, - that acts as a listener. - - If a listener is returned, the instrumentation point then: - - (d) invokes the "start" event method - - (e) executes the instrumented code. - - (f) invokes the "end" event method. - - If no listener is returned, only the instrumented code (e) is invoked. + An opaque "locker" pointer is returned by (a), that is given to (c). + This pointer helps the implementation to keep context, for performances. The following code fragment is annotated to show how in detail this pattern in implemented, when the instrumentation is compiled in: @@ -384,25 +382,18 @@ static inline int mysql_mutex_lock( mysql_mutex_t *that, myf flags, const char *src_file, uint src_line) { int result; + struct PSI_mutex_locker_state state; struct PSI_mutex_locker *locker= NULL; - ...... (a) .......... (b) - if (PSI_server && that->m_psi) + ............... (a) + locker= PSI_server->start_mutex_wait(&state, that->p_psi, + PSI_MUTEX_LOCK, locker, src_file, src_line); - .......................... (c) - if ((locker= PSI_server->get_thread_mutex_locker(that->m_psi, - PSI_MUTEX_LOCK))) - - ............... (d) - PSI_server->start_mutex_wait(locker, src_file, src_line); - - ........ (e) + ............... (b) result= pthread_mutex_lock(&that->m_mutex); - if (locker) - - ............. (f) - PSI_server->end_mutex_wait(locker, result); + ............... (c) + PSI_server->end_mutex_wait(locker, result); return result; } @@ -416,7 +407,7 @@ static inline int mysql_mutex_lock(...) { int result; - ........ (e) + ............... (b) result= pthread_mutex_lock(&that->m_mutex); return result; @@ -487,7 +478,7 @@ static inline int mysql_mutex_lock(...) Applying this function to our point P gives another point P': F_i (P): - P(x1, x2, ..., x{i-1}, x_i, x{i+1}, ..., x_N + P(x1, x2, ..., x{i-1}, x_i, x{i+1}, ..., x_N) --> P' (x1, x2, ..., x{i-1}, f_i(x_i), x{i+1}, ..., x_N) That function defines in fact an aggregate ! @@ -583,27 +574,17 @@ static inline int mysql_mutex_lock(...) What has all this to do with the code ? - Function composition such as F_2_to_3 o F_1_to_2 o F1 is implemented - as PFS_single_stat_chain, where each link in the chain represents - an individual F_{i}_to_{i+1} aggregation step. - - A single call to aggregate_single_stat_chain() updates all the tables - described in the statistics chain. - - @section STAT_CHAIN Statistics chains + Functions (or aggregates) such as F_3 are not implemented as is. + Instead, they are decomposed into F_2_to_3 o F_1_to_2 o F1, + and each intermediate aggregate is stored into an internal buffer. + This allows to support every F1, F2, F3 aggregates from shared + internal buffers, where computation already performed to compute F2 + is reused when computing F3. - Statistics chains are only used for on the fly aggregates, - and are therefore all based initially on the '_CURRENT' base table that - contains the data recorded. - The following table aggregates are implemented with a statistics chain: + @section OBJECT_GRAPH Object graph - EVENTS_WAITS_CURRENT --> EVENTS_WAITS_SUMMARY_BY_INSTANCE - --> EVENTS_WAITS_SUMMARY_BY_EVENT_NAME - - This relationship is between classes. - - In terms of object instances, or records, this chain is implemented - as a flyweight. + In terms of object instances, or records, pointers between + different buffers define an object instance graph. For example, assuming the following scenario: - A mutex class "M" is instrumented, the instrument name @@ -654,10 +635,413 @@ static inline int mysql_mutex_lock(...) This is necessary because the data the aggregate is based on is volatile, and can not be kept indefinitely. + With on the fly aggregates: + - the writer thread does all the computation + - the reader thread accesses the result directly + + This model is to be avoided if possible, due to the overhead + caused when instrumenting code. + @section HIGHER_LEVEL Higher level aggregates - Note: no higher level aggregate is implemented yet, - this section is a place holder. + 'Higher level' aggregates are implemented on demand only. + The code executing a SELECT from the aggregate table is + collecting data from multiple internal buffers to produce the result. + + With higher level aggregates: + - the reader thread does all the computation + - the writer thread has no overhead. + + @section MIXED Mixed level aggregates + + The 'Mixed' model is a compromise between 'On the fly' and 'Higher level' + aggregates, for internal buffers that are not permanent. + + While an object is present in a buffer, the higher level model is used. + When an object is about to be destroyed, statistics are saved into + a 'parent' buffer with a longer life cycle, to follow the on the fly model. + + With mixed aggregates: + - the reader thread does a lot of complex computation, + - the writer thread has minimal overhead, on destroy events. + + @section IMPL_WAIT Implementation for waits aggregates + + For waits, the tables that contains aggregated wait data are: + - EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME + - EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME + - EVENTS_WAITS_SUMMARY_BY_INSTANCE + - EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + - EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME + - FILE_SUMMARY_BY_EVENT_NAME + - FILE_SUMMARY_BY_INSTANCE + - SOCKET_SUMMARY_BY_INSTANCE + - SOCKET_SUMMARY_BY_EVENT_NAME + - OBJECTS_SUMMARY_GLOBAL_BY_TYPE + + The instrumented code that generates waits events consist of: + - mutexes (mysql_mutex_t) + - rwlocks (mysql_rwlock_t) + - conditions (mysql_cond_t) + - file io (MYSQL_FILE) + - socket io (MYSQL_SOCKET) + - table io + - table lock + + The flow of data between aggregates tables varies for each instrumentation. + + @subsection IMPL_WAIT_MUTEX Mutex waits + +@verbatim + mutex_locker(T, M) + | + | [1] + | + |-> pfs_mutex(M) =====>> [B], [C] + | | + | | [2] + | | + | |-> pfs_mutex_class(M.class) =====>> [C] + | + |-> pfs_thread(T).event_name(M) =====>> [A], [D], [E], [F] + | + | [3] + | + 3a |-> pfs_account(U, H).event_name(M) =====>> [D], [E], [F] + . | + . | [4-RESET] + . | + 3b .....+-> pfs_user(U).event_name(M) =====>> [E] + . | + 3c .....+-> pfs_host(H).event_name(M) =====>> [F] +@endverbatim + + How to read this diagram: + - events that occur during the instrumented code execution are noted with numbers, + as in [1]. Code executed by these events has an impact on overhead. + - events that occur during TRUNCATE TABLE operations are noted with numbers, + followed by "-RESET", as in [4-RESET]. + Code executed by these events has no impact on overhead, + since they are executed by independent monitoring sessions. + - events that occur when a reader extracts data from a performance schema table + are noted with letters, as in [A]. The name of the table involved, + and the method that builds a row are documented. Code executed by these events + has no impact on the instrumentation overhead. Note that the table + implementation may pull data from different buffers. + - nominal code paths are in plain lines. A "nominal" code path corresponds to + cases where the performance schema buffers are sized so that no records are lost. + - degenerated code paths are in dotted lines. A "degenerated" code path corresponds + to edge cases where parent buffers are full, which forces the code to aggregate to + grand parents directly. + + Implemented as: + - [1] @c start_mutex_wait_v1(), @c end_mutex_wait_v1() + - [2] @c destroy_mutex_v1() + - [3] @c aggregate_thread_waits() + - [4] @c PFS_account::aggregate_waits() + - [A] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME, + @c table_ews_by_thread_by_event_name::make_row() + - [B] EVENTS_WAITS_SUMMARY_BY_INSTANCE, + @c table_events_waits_summary_by_instance::make_mutex_row() + - [C] EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME, + @c table_ews_global_by_event_name::make_mutex_row() + - [D] EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME, + @c table_ews_by_account_by_event_name::make_row() + - [E] EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME, + @c table_ews_by_user_by_event_name::make_row() + - [F] EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME, + @c table_ews_by_host_by_event_name::make_row() + + Table EVENTS_WAITS_SUMMARY_BY_INSTANCE is a 'on the fly' aggregate, + because the data is collected on the fly by (1) and stored into a buffer, + pfs_mutex. The table implementation [B] simply reads the results directly + from this buffer. + + Table EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME is a 'mixed' aggregate, + because some data is collected on the fly (1), + some data is preserved with (2) at a later time in the life cycle, + and two different buffers pfs_mutex and pfs_mutex_class are used to store the + statistics collected. The table implementation [C] is more complex, since + it reads from two buffers pfs_mutex and pfs_mutex_class. + + @subsection IMPL_WAIT_RWLOCK Rwlock waits + +@verbatim + rwlock_locker(T, R) + | + | [1] + | + |-> pfs_rwlock(R) =====>> [B], [C] + | | + | | [2] + | | + | |-> pfs_rwlock_class(R.class) =====>> [C] + | + |-> pfs_thread(T).event_name(R) =====>> [A] + | + ... +@endverbatim + + Implemented as: + - [1] @c start_rwlock_rdwait_v1(), @c end_rwlock_rdwait_v1(), ... + - [2] @c destroy_rwlock_v1() + - [A] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME, + @c table_ews_by_thread_by_event_name::make_row() + - [B] EVENTS_WAITS_SUMMARY_BY_INSTANCE, + @c table_events_waits_summary_by_instance::make_rwlock_row() + - [C] EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME, + @c table_ews_global_by_event_name::make_rwlock_row() + + @subsection IMPL_WAIT_COND Cond waits + +@verbatim + cond_locker(T, C) + | + | [1] + | + |-> pfs_cond(C) =====>> [B], [C] + | | + | | [2] + | | + | |-> pfs_cond_class(C.class) =====>> [C] + | + |-> pfs_thread(T).event_name(C) =====>> [A] + | + ... +@endverbatim + + Implemented as: + - [1] @c start_cond_wait_v1(), @c end_cond_wait_v1() + - [2] @c destroy_cond_v1() + - [A] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME, + @c table_ews_by_thread_by_event_name::make_row() + - [B] EVENTS_WAITS_SUMMARY_BY_INSTANCE, + @c table_events_waits_summary_by_instance::make_cond_row() + - [C] EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME, + @c table_ews_global_by_event_name::make_cond_row() + + @subsection IMPL_WAIT_FILE File waits + +@verbatim + file_locker(T, F) + | + | [1] + | + |-> pfs_file(F) =====>> [B], [C], [D], [E] + | | + | | [2] + | | + | |-> pfs_file_class(F.class) =====>> [C], [D] + | + |-> pfs_thread(T).event_name(F) =====>> [A] + | + ... +@endverbatim + + Implemented as: + - [1] @c get_thread_file_name_locker_v1(), @c start_file_wait_v1(), + @c end_file_wait_v1(), ... + - [2] @c close_file_v1() + - [A] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME, + @c table_ews_by_thread_by_event_name::make_row() + - [B] EVENTS_WAITS_SUMMARY_BY_INSTANCE, + @c table_events_waits_summary_by_instance::make_file_row() + - [C] EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME, + @c table_ews_global_by_event_name::make_file_row() + - [D] FILE_SUMMARY_BY_EVENT_NAME, + @c table_file_summary_by_event_name::make_row() + - [E] FILE_SUMMARY_BY_INSTANCE, + @c table_file_summary_by_instance::make_row() + + @subsection IMPL_WAIT_SOCKET Socket waits + +@verbatim + socket_locker(T, F) + | + | [1] + | + |-> pfs_socket(F) =====>> [A], [B], [C], [D], [E] + | + | [2] + | + |-> pfs_socket_class(F.class) =====>> [C], [D] + | + |-> pfs_thread(T).event_name(F) =====>> [A] + | + ... +@endverbatim + + Implemented as: + - [1] @c start_socket_wait_v1(), @c end_socket_wait_v1(). + - [2] @c close_socket_v1() + - [A] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME, + @c table_ews_by_thread_by_event_name::make_row() + - [B] EVENTS_WAITS_SUMMARY_BY_INSTANCE, + @c table_events_waits_summary_by_instance::make_socket_row() + - [C] EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME, + @c table_ews_global_by_event_name::make_socket_row() + - [D] SOCKET_SUMMARY_BY_EVENT_NAME, + @c table_socket_summary_by_event_name::make_row() + - [E] SOCKET_SUMMARY_BY_INSTANCE, + @c table_socket_summary_by_instance::make_row() + + @subsection IMPL_WAIT_TABLE Table waits + +@verbatim + table_locker(T, Tb) + | + | [1] + | + |-> pfs_table(Tb) =====>> [B], [C], [D] + | + | [2] + | + |-> pfs_table_share(Tb.share) =====>> [C], [D] + | + |-> pfs_thread(T).event_name(Tb) =====>> [A] + | + ... +@endverbatim + + Implemented as: + - [1] @c start_table_io_wait_v1(), @c end_table_io_wait_v1() + - [2] @c close_table_v1() + - [A] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME, + @c table_ews_by_thread_by_event_name::make_row() + - [B] EVENTS_WAITS_SUMMARY_BY_INSTANCE, + @c table_events_waits_summary_by_instance::make_table_row() + - [C] EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME, + @c table_ews_global_by_event_name::make_table_io_row(), + @c table_ews_global_by_event_name::make_table_lock_row() + - [D] OBJECTS_SUMMARY_GLOBAL_BY_TYPE, + @c table_os_global_by_type::make_row() + + @section IMPL_STAGE Implementation for stages aggregates + + For stages, the tables that contains aggregated data are: + - EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME + - EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME + - EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME + - EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME + +@verbatim + start_stage(T, S) + | + | [1] + | +1a |-> pfs_thread(T).event_name(S) =====>> [A], [B], [C], [D], [E] + | | + | | [2] + | | + | 2a |-> pfs_account(U, H).event_name(S) =====>> [B], [C], [D], [E] + | . | + | . | [3-RESET] + | . | + | 2b .....+-> pfs_user(U).event_name(S) =====>> [C] + | . | + | 2c .....+-> pfs_host(H).event_name(S) =====>> [D], [E] + | . . | + | . . | [4-RESET] + | 2d . . | +1b |----+----+----+-> pfs_stage_class(S) =====>> [E] + +@endverbatim + + Implemented as: + - [1] @c start_stage_v1() + - [2] @c delete_thread_v1(), @c aggregate_thread_stages() + - [3] @c PFS_account::aggregate_stages() + - [4] @c PFS_host::aggregate_stages() + - [A] EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME, + @c table_esgs_by_thread_by_event_name::make_row() + - [B] EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME, + @c table_esgs_by_account_by_event_name::make_row() + - [C] EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME, + @c table_esgs_by_user_by_event_name::make_row() + - [D] EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME, + @c table_esgs_by_host_by_event_name::make_row() + - [E] EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME, + @c table_esgs_global_by_event_name::make_row() + +@section IMPL_STATEMENT Implementation for statements consumers + + For statements, the tables that contains individual event data are: + - EVENTS_STATEMENTS_CURRENT + - EVENTS_STATEMENTS_HISTORY + - EVENTS_STATEMENTS_HISTORY_LONG + + For statements, the tables that contains aggregated data are: + - EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME + - EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME + - EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME + - EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME + - EVENTS_STATEMENTS_SUMMARY_BY_DIGEST + +@verbatim + statement_locker(T, S) + | + | [1] + | +1a |-> pfs_thread(T).event_name(S) =====>> [A], [B], [C], [D], [E] + | | + | | [2] + | | + | 2a |-> pfs_account(U, H).event_name(S) =====>> [B], [C], [D], [E] + | . | + | . | [3-RESET] + | . | + | 2b .....+-> pfs_user(U).event_name(S) =====>> [C] + | . | + | 2c .....+-> pfs_host(H).event_name(S) =====>> [D], [E] + | . . | + | . . | [4-RESET] + | 2d . . | +1b |----+----+----+-> pfs_statement_class(S) =====>> [E] + | +1c |-> pfs_thread(T).statement_current(S) =====>> [F] + | +1d |-> pfs_thread(T).statement_history(S) =====>> [G] + | +1e |-> statement_history_long(S) =====>> [H] + | +1f |-> statement_digest(S) =====>> [I] + +@endverbatim + + Implemented as: + - [1] @c start_statement_v1(), end_statement_v1() + (1a, 1b) is an aggregation by EVENT_NAME, + (1c, 1d, 1e) is an aggregation by TIME, + (1f) is an aggregation by DIGEST + all of these are orthogonal, + and implemented in end_statement_v1(). + - [2] @c delete_thread_v1(), @c aggregate_thread_statements() + - [3] @c PFS_account::aggregate_statements() + - [4] @c PFS_host::aggregate_statements() + - [A] EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME, + @c table_esms_by_thread_by_event_name::make_row() + - [B] EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME, + @c table_esms_by_account_by_event_name::make_row() + - [C] EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME, + @c table_esms_by_user_by_event_name::make_row() + - [D] EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME, + @c table_esms_by_host_by_event_name::make_row() + - [E] EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME, + @c table_esms_global_by_event_name::make_row() + - [F] EVENTS_STATEMENTS_CURRENT, + @c table_events_statements_current::rnd_next(), + @c table_events_statements_common::make_row() + - [G] EVENTS_STATEMENTS_HISTORY, + @c table_events_statements_history::rnd_next(), + @c table_events_statements_common::make_row() + - [H] EVENTS_STATEMENTS_HISTORY_LONG, + @c table_events_statements_history_long::rnd_next(), + @c table_events_statements_common::make_row() + - [I] EVENTS_STATEMENTS_SUMMARY_BY_DIGEST + @c table_esms_by_digest::make_row() */ /** @@ -676,12 +1060,20 @@ static inline int mysql_mutex_lock(...) pthread_key(PFS_thread*, THR_PFS); bool THR_PFS_initialized= false; +/** + Conversion map from PSI_mutex_operation to enum_operation_type. + Indexed by enum PSI_mutex_operation. +*/ static enum_operation_type mutex_operation_map[]= { OPERATION_TYPE_LOCK, OPERATION_TYPE_TRYLOCK }; +/** + Conversion map from PSI_rwlock_operation to enum_operation_type. + Indexed by enum PSI_rwlock_operation. +*/ static enum_operation_type rwlock_operation_map[]= { OPERATION_TYPE_READLOCK, @@ -690,6 +1082,10 @@ static enum_operation_type rwlock_operation_map[]= OPERATION_TYPE_TRYWRITELOCK }; +/** + Conversion map from PSI_cond_operation to enum_operation_type. + Indexed by enum PSI_cond_operation. +*/ static enum_operation_type cond_operation_map[]= { OPERATION_TYPE_WAIT, @@ -722,6 +1118,60 @@ static enum_operation_type file_operation_map[]= }; /** + Conversion map from PSI_table_operation to enum_operation_type. + Indexed by enum PSI_table_io_operation. +*/ +static enum_operation_type table_io_operation_map[]= +{ + OPERATION_TYPE_TABLE_FETCH, + OPERATION_TYPE_TABLE_WRITE_ROW, + OPERATION_TYPE_TABLE_UPDATE_ROW, + OPERATION_TYPE_TABLE_DELETE_ROW +}; + +/** + Conversion map from enum PFS_TL_LOCK_TYPE to enum_operation_type. + Indexed by enum PFS_TL_LOCK_TYPE. +*/ +static enum_operation_type table_lock_operation_map[]= +{ + OPERATION_TYPE_TL_READ_NORMAL, /* PFS_TL_READ */ + OPERATION_TYPE_TL_READ_WITH_SHARED_LOCKS, /* PFS_TL_READ_WITH_SHARED_LOCKS */ + OPERATION_TYPE_TL_READ_HIGH_PRIORITY, /* PFS_TL_READ_HIGH_PRIORITY */ + OPERATION_TYPE_TL_READ_NO_INSERTS, /* PFS_TL_READ_NO_INSERT */ + OPERATION_TYPE_TL_WRITE_ALLOW_WRITE, /* PFS_TL_WRITE_ALLOW_WRITE */ + OPERATION_TYPE_TL_WRITE_CONCURRENT_INSERT, /* PFS_TL_WRITE_CONCURRENT_INSERT */ + OPERATION_TYPE_TL_WRITE_DELAYED, /* PFS_TL_WRITE_DELAYED */ + OPERATION_TYPE_TL_WRITE_LOW_PRIORITY, /* PFS_TL_WRITE_LOW_PRIORITY */ + OPERATION_TYPE_TL_WRITE_NORMAL, /* PFS_TL_WRITE */ + OPERATION_TYPE_TL_READ_EXTERNAL, /* PFS_TL_READ_EXTERNAL */ + OPERATION_TYPE_TL_WRITE_EXTERNAL /* PFS_TL_WRITE_EXTERNAL */ +}; + +/** + Conversion map from PSI_socket_operation to enum_operation_type. + Indexed by enum PSI_socket_operation. +*/ +static enum_operation_type socket_operation_map[]= +{ + OPERATION_TYPE_SOCKETCREATE, + OPERATION_TYPE_SOCKETCONNECT, + OPERATION_TYPE_SOCKETBIND, + OPERATION_TYPE_SOCKETCLOSE, + OPERATION_TYPE_SOCKETSEND, + OPERATION_TYPE_SOCKETRECV, + OPERATION_TYPE_SOCKETSENDTO, + OPERATION_TYPE_SOCKETRECVFROM, + OPERATION_TYPE_SOCKETSENDMSG, + OPERATION_TYPE_SOCKETRECVMSG, + OPERATION_TYPE_SOCKETSEEK, + OPERATION_TYPE_SOCKETOPT, + OPERATION_TYPE_SOCKETSTAT, + OPERATION_TYPE_SOCKETSHUTDOWN, + OPERATION_TYPE_SOCKETSELECT +}; + +/** Build the prefix name of a class of instruments in a category. For example, this function builds the string 'wait/sync/mutex/sql/' from a prefix 'wait/sync/mutex' and a category 'sql'. @@ -810,6 +1260,10 @@ static int build_prefix(const LEX_STRING *prefix, const char *category, C_MODE_START +/** + Implementation of the mutex instrumentation interface. + @sa PSI_v1::register_mutex. +*/ static void register_mutex_v1(const char *category, PSI_mutex_info_v1 *info, int count) @@ -819,6 +1273,10 @@ static void register_mutex_v1(const char *category, register_mutex_class) } +/** + Implementation of the rwlock instrumentation interface. + @sa PSI_v1::register_rwlock. +*/ static void register_rwlock_v1(const char *category, PSI_rwlock_info_v1 *info, int count) @@ -828,6 +1286,10 @@ static void register_rwlock_v1(const char *category, register_rwlock_class) } +/** + Implementation of the cond instrumentation interface. + @sa PSI_v1::register_cond. +*/ static void register_cond_v1(const char *category, PSI_cond_info_v1 *info, int count) @@ -837,6 +1299,10 @@ static void register_cond_v1(const char *category, register_cond_class) } +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::register_thread. +*/ static void register_thread_v1(const char *category, PSI_thread_info_v1 *info, int count) @@ -846,6 +1312,10 @@ static void register_thread_v1(const char *category, register_thread_class) } +/** + Implementation of the file instrumentation interface. + @sa PSI_v1::register_file. +*/ static void register_file_v1(const char *category, PSI_file_info_v1 *info, int count) @@ -855,14 +1325,100 @@ static void register_file_v1(const char *category, register_file_class) } +static void register_stage_v1(const char *category, + PSI_stage_info_v1 **info_array, + int count) +{ + char formatted_name[PFS_MAX_INFO_NAME_LENGTH]; + int prefix_length; + int len; + int full_length; + PSI_stage_info_v1 *info; + + DBUG_ASSERT(category != NULL); + DBUG_ASSERT(info_array != NULL); + if (unlikely(build_prefix(&stage_instrument_prefix, category, + formatted_name, &prefix_length))) + { + for (; count>0; count--, info_array++) + (*info_array)->m_key= 0; + return ; + } + + for (; count>0; count--, info_array++) + { + info= *info_array; + DBUG_ASSERT(info != NULL); + DBUG_ASSERT(info->m_name != NULL); + len= strlen(info->m_name); + full_length= prefix_length + len; + if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH)) + { + memcpy(formatted_name + prefix_length, info->m_name, len); + info->m_key= register_stage_class(formatted_name, full_length, + info->m_flags); + } + else + { + pfs_print_error("register_stage_v1: name too long <%s> <%s>\n", + category, info->m_name); + info->m_key= 0; + } + } + return; +} + +static void register_statement_v1(const char *category, + PSI_statement_info_v1 *info, + int count) +{ + char formatted_name[PFS_MAX_INFO_NAME_LENGTH]; + int prefix_length; + int len; + int full_length; + + DBUG_ASSERT(category != NULL); + DBUG_ASSERT(info != NULL); + if (unlikely(build_prefix(&statement_instrument_prefix, + category, formatted_name, &prefix_length))) + { + for (; count>0; count--, info++) + info->m_key= 0; + return ; + } + + for (; count>0; count--, info++) + { + DBUG_ASSERT(info->m_name != NULL); + len= strlen(info->m_name); + full_length= prefix_length + len; + if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH)) + { + memcpy(formatted_name + prefix_length, info->m_name, len); + info->m_key= register_statement_class(formatted_name, full_length, info->m_flags); + } + else + { + pfs_print_error("register_statement_v1: name too long <%s>\n", + info->m_name); + info->m_key= 0; + } + } + return; +} + +static void register_socket_v1(const char *category, + PSI_socket_info_v1 *info, + int count) +{ + REGISTER_BODY_V1(PSI_socket_key, + socket_instrument_prefix, + register_socket_class) +} + #define INIT_BODY_V1(T, KEY, ID) \ PFS_##T##_class *klass; \ PFS_##T *pfs; \ - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); \ - if (unlikely(pfs_thread == NULL)) \ - return NULL; \ - if (! pfs_thread->m_enabled) \ - return NULL; \ klass= find_##T##_class(KEY); \ if (unlikely(klass == NULL)) \ return NULL; \ @@ -871,111 +1427,320 @@ static void register_file_v1(const char *category, pfs= create_##T(klass, ID); \ return reinterpret_cast<PSI_##T *> (pfs) +/** + Implementation of the mutex instrumentation interface. + @sa PSI_v1::init_mutex. +*/ static PSI_mutex* init_mutex_v1(PSI_mutex_key key, const void *identity) { INIT_BODY_V1(mutex, key, identity); } +/** + Implementation of the mutex instrumentation interface. + @sa PSI_v1::destroy_mutex. +*/ static void destroy_mutex_v1(PSI_mutex* mutex) { PFS_mutex *pfs= reinterpret_cast<PFS_mutex*> (mutex); + + DBUG_ASSERT(pfs != NULL); + destroy_mutex(pfs); } +/** + Implementation of the rwlock instrumentation interface. + @sa PSI_v1::init_rwlock. +*/ static PSI_rwlock* init_rwlock_v1(PSI_rwlock_key key, const void *identity) { INIT_BODY_V1(rwlock, key, identity); } +/** + Implementation of the rwlock instrumentation interface. + @sa PSI_v1::destroy_rwlock. +*/ static void destroy_rwlock_v1(PSI_rwlock* rwlock) { PFS_rwlock *pfs= reinterpret_cast<PFS_rwlock*> (rwlock); + + DBUG_ASSERT(pfs != NULL); + destroy_rwlock(pfs); } +/** + Implementation of the cond instrumentation interface. + @sa PSI_v1::init_cond. +*/ static PSI_cond* init_cond_v1(PSI_cond_key key, const void *identity) { INIT_BODY_V1(cond, key, identity); } +/** + Implementation of the cond instrumentation interface. + @sa PSI_v1::destroy_cond. +*/ static void destroy_cond_v1(PSI_cond* cond) { PFS_cond *pfs= reinterpret_cast<PFS_cond*> (cond); + + DBUG_ASSERT(pfs != NULL); + destroy_cond(pfs); } +/** + Implementation of the table instrumentation interface. + @sa PSI_v1::get_table_share. +*/ static PSI_table_share* -get_table_share_v1(const char *schema_name, int schema_name_length, - const char *table_name, int table_name_length, - const void *identity) +get_table_share_v1(my_bool temporary, TABLE_SHARE *share) { -#ifdef HAVE_TABLE_WAIT + /* Ignore temporary tables and views. */ + if (temporary || share->is_view) + return NULL; + /* An instrumented thread is required, for LF_PINS. */ PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); if (unlikely(pfs_thread == NULL)) return NULL; - PFS_table_share* share; - share= find_or_create_table_share(pfs_thread, - schema_name, schema_name_length, - table_name, table_name_length); - return reinterpret_cast<PSI_table_share*> (share); -#else - return NULL; -#endif + PFS_table_share* pfs_share; + pfs_share= find_or_create_table_share(pfs_thread, temporary, share); + return reinterpret_cast<PSI_table_share*> (pfs_share); } +/** + Implementation of the table instrumentation interface. + @sa PSI_v1::release_table_share. +*/ static void release_table_share_v1(PSI_table_share* share) { - /* - To be implemented by WL#4895 PERFORMANCE_SCHEMA Instrumenting Table IO. - */ + PFS_table_share* pfs= reinterpret_cast<PFS_table_share*> (share); + + if (unlikely(pfs == NULL)) + return; + + release_table_share(pfs); } +/** + Implementation of the table instrumentation interface. + @sa PSI_v1::drop_table_share. +*/ +static void +drop_table_share_v1(my_bool temporary, + const char *schema_name, int schema_name_length, + const char *table_name, int table_name_length) +{ + /* Ignore temporary tables. */ + if (temporary) + return; + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(pfs_thread == NULL)) + return; + /* TODO: temporary tables */ + drop_table_share(pfs_thread, temporary, schema_name, schema_name_length, + table_name, table_name_length); +} + +/** + Implementation of the table instrumentation interface. + @sa PSI_v1::open_table. +*/ static PSI_table* open_table_v1(PSI_table_share *share, const void *identity) { - PFS_table_share *pfs_table_share= - reinterpret_cast<PFS_table_share*> (share); - PFS_table *pfs_table; - DBUG_ASSERT(pfs_table_share); - pfs_table= create_table(pfs_table_share, identity); + PFS_table_share *pfs_table_share= reinterpret_cast<PFS_table_share*> (share); + + if (unlikely(pfs_table_share == NULL)) + return NULL; + + /* This object is not to be instrumented. */ + if (! pfs_table_share->m_enabled) + return NULL; + + /* This object is instrumented, but all table instruments are disabled. */ + if (! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled) + return NULL; + + /* + When the performance schema is off, do not instrument anything. + Table handles have short life cycle, instrumentation will happen + again if needed during the next open(). + */ + if (! flag_global_instrumentation) + return NULL; + + PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(thread == NULL)) + return NULL; + + PFS_table *pfs_table= create_table(pfs_table_share, thread, identity); return reinterpret_cast<PSI_table *> (pfs_table); } +/** + Implementation of the table instrumentation interface. + @sa PSI_v1::unbind_table. +*/ +static void unbind_table_v1(PSI_table *table) +{ + PFS_table *pfs= reinterpret_cast<PFS_table*> (table); + if (likely(pfs != NULL)) + { + pfs->aggregate(); + pfs->m_thread_owner= NULL; + } +} + +/** + Implementation of the table instrumentation interface. + @sa PSI_v1::rebind_table. +*/ +static PSI_table * +rebind_table_v1(PSI_table_share *share, const void *identity, PSI_table *table) +{ + PFS_table *pfs= reinterpret_cast<PFS_table*> (table); + if (likely(pfs != NULL)) + { + PFS_thread *thread; + DBUG_ASSERT(pfs->m_thread_owner == NULL); + + /* The table handle was already instrumented, reuse it for this thread. */ + thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + + if (unlikely(thread == NULL)) + { + destroy_table(pfs); + return NULL; + } + + if (unlikely(! pfs->m_share->m_enabled)) + { + destroy_table(pfs); + return NULL; + } + + if (unlikely(! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled)) + { + destroy_table(pfs); + return NULL; + } + + if (unlikely(! flag_global_instrumentation)) + { + destroy_table(pfs); + return NULL; + } + + pfs->m_thread_owner= thread; + return table; + } + + /* See open_table_v1() */ + + PFS_table_share *pfs_table_share= reinterpret_cast<PFS_table_share*> (share); + + if (unlikely(pfs_table_share == NULL)) + return NULL; + + if (! pfs_table_share->m_enabled) + return NULL; + + if (! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled) + return NULL; + + if (! flag_global_instrumentation) + return NULL; + + PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(thread == NULL)) + return NULL; + + PFS_table *pfs_table= create_table(pfs_table_share, thread, identity); + return reinterpret_cast<PSI_table *> (pfs_table); +} + +/** + Implementation of the table instrumentation interface. + @sa PSI_v1::close_table. +*/ static void close_table_v1(PSI_table *table) { PFS_table *pfs= reinterpret_cast<PFS_table*> (table); - DBUG_ASSERT(pfs); + if (unlikely(pfs == NULL)) + return; + pfs->aggregate(); destroy_table(pfs); } +static PSI_socket* +init_socket_v1(PSI_socket_key key, const my_socket *fd) +{ + INIT_BODY_V1(socket, key, fd); +} + +static void destroy_socket_v1(PSI_socket *socket) +{ + PFS_socket *pfs= reinterpret_cast<PFS_socket*> (socket); + + DBUG_ASSERT(pfs != NULL); + + destroy_socket(pfs); +} + +/** + Implementation of the file instrumentation interface. + @sa PSI_v1::create_file. +*/ static void create_file_v1(PSI_file_key key, const char *name, File file) { + if (! flag_global_instrumentation) + return; int index= (int) file; if (unlikely(index < 0)) return; - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); - if (unlikely(pfs_thread == NULL)) - return; - if (! pfs_thread->m_enabled) - return; PFS_file_class *klass= find_file_class(key); if (unlikely(klass == NULL)) return; if (! klass->m_enabled) return; - if (likely(index < file_handle_max)) + + /* A thread is needed for LF_PINS */ + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(pfs_thread == NULL)) + return; + + if (flag_thread_instrumentation && ! pfs_thread->m_enabled) + return; + + /* + We want this check after pfs_thread->m_enabled, + to avoid reporting false loss. + */ + if (unlikely(index >= file_handle_max)) { - uint len= strlen(name); - PFS_file *pfs= find_or_create_file(pfs_thread, klass, name, len); - file_handle_array[index]= pfs; - } - else file_handle_lost++; + return; + } + + uint len= strlen(name); + PFS_file *pfs_file= find_or_create_file(pfs_thread, klass, name, len); + + file_handle_array[index]= pfs_file; } +/** + Arguments given from a parent to a child thread, packaged in one structure. + This data is used when spawning a new instrumented thread. + @sa pfs_spawn_thread. +*/ struct PFS_spawn_thread_arg { PFS_thread *m_parent_thread; @@ -996,9 +1761,29 @@ void* pfs_spawn_thread(void *arg) /* First, attach instrumentation to this newly created pthread. */ PFS_thread_class *klass= find_thread_class(typed_arg->m_child_key); if (likely(klass != NULL)) + { pfs= create_thread(klass, typed_arg->m_child_identity, 0); + if (likely(pfs != NULL)) + { + PFS_thread *parent= typed_arg->m_parent_thread; + + clear_thread_account(pfs); + + pfs->m_parent_thread_internal_id= parent->m_thread_internal_id; + + memcpy(pfs->m_username, parent->m_username, sizeof(pfs->m_username)); + pfs->m_username_length= parent->m_username_length; + + memcpy(pfs->m_hostname, parent->m_hostname, sizeof(pfs->m_hostname)); + pfs->m_hostname_length= parent->m_hostname_length; + + set_thread_account(pfs); + } + } else + { pfs= NULL; + } my_pthread_setspecific_ptr(THR_PFS, pfs); /* @@ -1017,6 +1802,10 @@ void* pfs_spawn_thread(void *arg) return NULL; } +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::spawn_thread. +*/ static int spawn_thread_v1(PSI_thread_key key, pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg) @@ -1041,6 +1830,10 @@ static int spawn_thread_v1(PSI_thread_key key, return result; } +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::new_thread. +*/ static PSI_thread* new_thread_v1(PSI_thread_key key, const void *identity, ulong thread_id) { @@ -1055,13 +1848,22 @@ new_thread_v1(PSI_thread_key key, const void *identity, ulong thread_id) return reinterpret_cast<PSI_thread*> (pfs); } +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::set_thread_id. +*/ static void set_thread_id_v1(PSI_thread *thread, unsigned long id) { - DBUG_ASSERT(thread); PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread); + if (unlikely(pfs == NULL)) + return; pfs->m_thread_id= id; } +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::get_thread_id. +*/ static PSI_thread* get_thread_v1(void) { @@ -1069,124 +1871,448 @@ get_thread_v1(void) return reinterpret_cast<PSI_thread*> (pfs); } +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::set_thread_user. +*/ +static void set_thread_user_v1(const char *user, int user_len) +{ + PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + + DBUG_ASSERT((user != NULL) || (user_len == 0)); + DBUG_ASSERT(user_len >= 0); + DBUG_ASSERT((uint) user_len <= sizeof(pfs->m_username)); + + if (unlikely(pfs == NULL)) + return; + + aggregate_thread(pfs); + + pfs->m_lock.allocated_to_dirty(); + + clear_thread_account(pfs); + + if (user_len > 0) + memcpy(pfs->m_username, user, user_len); + pfs->m_username_length= user_len; + + set_thread_account(pfs); + + bool enabled= true; + if (flag_thread_instrumentation) + { + if ((pfs->m_username_length > 0) && (pfs->m_hostname_length > 0)) + { + /* + TODO: performance improvement. + Once performance_schema.USERS is exposed, + we can use PFS_user::m_enabled instead of looking up + SETUP_ACTORS every time. + */ + lookup_setup_actor(pfs, + pfs->m_username, pfs->m_username_length, + pfs->m_hostname, pfs->m_hostname_length, + &enabled); + } + } + + pfs->m_enabled= enabled; + + pfs->m_lock.dirty_to_allocated(); +} + +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::set_thread_account. +*/ +static void set_thread_account_v1(const char *user, int user_len, + const char *host, int host_len) +{ + PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + + DBUG_ASSERT((user != NULL) || (user_len == 0)); + DBUG_ASSERT(user_len >= 0); + DBUG_ASSERT((uint) user_len <= sizeof(pfs->m_username)); + DBUG_ASSERT((host != NULL) || (host_len == 0)); + DBUG_ASSERT(host_len >= 0); + DBUG_ASSERT((uint) host_len <= sizeof(pfs->m_hostname)); + + if (unlikely(pfs == NULL)) + return; + + pfs->m_lock.allocated_to_dirty(); + + clear_thread_account(pfs); + + if (host_len > 0) + memcpy(pfs->m_hostname, host, host_len); + pfs->m_hostname_length= host_len; + + if (user_len > 0) + memcpy(pfs->m_username, user, user_len); + pfs->m_username_length= user_len; + + set_thread_account(pfs); + + bool enabled= true; + if (flag_thread_instrumentation) + { + if ((pfs->m_username_length > 0) && (pfs->m_hostname_length > 0)) + { + /* + TODO: performance improvement. + Once performance_schema.USERS is exposed, + we can use PFS_user::m_enabled instead of looking up + SETUP_ACTORS every time. + */ + lookup_setup_actor(pfs, + pfs->m_username, pfs->m_username_length, + pfs->m_hostname, pfs->m_hostname_length, + &enabled); + } + } + pfs->m_enabled= enabled; + + pfs->m_lock.dirty_to_allocated(); +} + +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::set_thread_db. +*/ +static void set_thread_db_v1(const char* db, int db_len) +{ + PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + + DBUG_ASSERT((db != NULL) || (db_len == 0)); + DBUG_ASSERT(db_len >= 0); + DBUG_ASSERT((uint) db_len <= sizeof(pfs->m_dbname)); + + if (likely(pfs != NULL)) + { + pfs->m_lock.allocated_to_dirty(); + if (db_len > 0) + memcpy(pfs->m_dbname, db, db_len); + pfs->m_dbname_length= db_len; + pfs->m_lock.dirty_to_allocated(); + } +} + +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::set_thread_command. +*/ +static void set_thread_command_v1(int command) +{ + PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + + DBUG_ASSERT(command >= 0); + DBUG_ASSERT(command <= (int) COM_END); + + if (likely(pfs != NULL)) + { + pfs->m_lock.allocated_to_dirty(); + pfs->m_command= command; + pfs->m_lock.dirty_to_allocated(); + } +} + +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::set_thread_start_time. +*/ +static void set_thread_start_time_v1(time_t start_time) +{ + PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + + if (likely(pfs != NULL)) + { + pfs->m_lock.allocated_to_dirty(); + pfs->m_start_time= start_time; + pfs->m_lock.dirty_to_allocated(); + } +} + +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::set_thread_state. +*/ +static void set_thread_state_v1(const char* state) +{ + PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + + if (likely(pfs != NULL)) + { + int state_len= state ? strlen(state) : 0; + + pfs->m_lock.allocated_to_dirty(); + pfs->m_processlist_state_ptr= state; + pfs->m_processlist_state_length= state_len; + pfs->m_lock.dirty_to_allocated(); + } +} + +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::set_thread_info. +*/ +static void set_thread_info_v1(const char* info, int info_len) +{ + PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + + if (likely(pfs != NULL)) + { + pfs->m_lock.allocated_to_dirty(); + pfs->m_processlist_info_ptr= info; + pfs->m_processlist_info_length= info_len; + pfs->m_lock.dirty_to_allocated(); + } +} + +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::set_thread. +*/ static void set_thread_v1(PSI_thread* thread) { PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread); my_pthread_setspecific_ptr(THR_PFS, pfs); } +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::delete_current_thread. +*/ static void delete_current_thread_v1(void) { PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); if (thread != NULL) { + aggregate_thread(thread); my_pthread_setspecific_ptr(THR_PFS, NULL); destroy_thread(thread); } } +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::delete_thread. +*/ static void delete_thread_v1(PSI_thread *thread) { PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread); + if (pfs != NULL) + { + aggregate_thread(pfs); destroy_thread(pfs); + } } +/** + Implementation of the mutex instrumentation interface. + @sa PSI_v1::start_mutex_wait. +*/ static PSI_mutex_locker* -get_thread_mutex_locker_v1(PSI_mutex_locker_state *state, - PSI_mutex *mutex, PSI_mutex_operation op) +start_mutex_wait_v1(PSI_mutex_locker_state *state, + PSI_mutex *mutex, PSI_mutex_operation op, + const char *src_file, uint src_line) { PFS_mutex *pfs_mutex= reinterpret_cast<PFS_mutex*> (mutex); DBUG_ASSERT((int) op >= 0); DBUG_ASSERT((uint) op < array_elements(mutex_operation_map)); + DBUG_ASSERT(state != NULL); + DBUG_ASSERT(pfs_mutex != NULL); DBUG_ASSERT(pfs_mutex->m_class != NULL); - if (! flag_events_waits_current) - return NULL; - if (! pfs_mutex->m_class->m_enabled) - return NULL; - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); - if (unlikely(pfs_thread == NULL)) - return NULL; - if (! pfs_thread->m_enabled) - return NULL; - if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE)) - { - locker_lost++; + + if (! pfs_mutex->m_enabled) return NULL; - } - PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack - [pfs_thread->m_wait_locker_count]; - pfs_locker->m_target.m_mutex= pfs_mutex; - pfs_locker->m_waits_current.m_thread= pfs_thread; - pfs_locker->m_waits_current.m_class= pfs_mutex->m_class; - if (pfs_mutex->m_class->m_timed) + register uint flags; + ulonglong timer_start= 0; + + if (flag_thread_instrumentation) { - pfs_locker->m_timer_name= wait_timer; - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING; + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(pfs_thread == NULL)) + return NULL; + if (! pfs_thread->m_enabled) + return NULL; + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + flags= STATE_FLAG_THREAD; + + if (pfs_mutex->m_timed) + { + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + flags|= STATE_FLAG_TIMED; + } + + if (flag_events_waits_current) + { + if (unlikely(pfs_thread->m_events_waits_current >= + & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE])) + { + locker_lost++; + return NULL; + } + PFS_events_waits *wait= pfs_thread->m_events_waits_current; + state->m_wait= wait; + flags|= STATE_FLAG_EVENT; + + PFS_events_waits *parent_event= wait - 1; + wait->m_event_type= EVENT_TYPE_WAIT; + wait->m_nesting_event_id= parent_event->m_event_id; + wait->m_nesting_event_type= parent_event->m_event_type; + + wait->m_thread= pfs_thread; + wait->m_class= pfs_mutex->m_class; + wait->m_timer_start= timer_start; + wait->m_timer_end= 0; + wait->m_object_instance_addr= pfs_mutex->m_identity; + wait->m_event_id= pfs_thread->m_event_id++; + wait->m_end_event_id= 0; + wait->m_operation= mutex_operation_map[(int) op]; + wait->m_source_file= src_file; + wait->m_source_line= src_line; + wait->m_wait_class= WAIT_CLASS_MUTEX; + + pfs_thread->m_events_waits_current++; + } } else - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED; - pfs_locker->m_waits_current.m_object_instance_addr= pfs_mutex->m_identity; - pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++; - pfs_locker->m_waits_current.m_operation= mutex_operation_map[(int) op]; - pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_MUTEX; + { + if (pfs_mutex->m_timed) + { + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + flags= STATE_FLAG_TIMED; + state->m_thread= NULL; + } + else + { + /* + Complete shortcut. + */ + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */ + pfs_mutex->m_wait_stat.aggregate_counted(); + return NULL; + } + } - pfs_thread->m_wait_locker_count++; - return reinterpret_cast<PSI_mutex_locker*> (pfs_locker); + state->m_flags= flags; + state->m_mutex= mutex; + return reinterpret_cast<PSI_mutex_locker*> (state); } +/** + Implementation of the rwlock instrumentation interface. + @sa PSI_v1::start_rwlock_rdwait + @sa PSI_v1::start_rwlock_wrwait +*/ static PSI_rwlock_locker* -get_thread_rwlock_locker_v1(PSI_rwlock_locker_state *state, - PSI_rwlock *rwlock, PSI_rwlock_operation op) +start_rwlock_wait_v1(PSI_rwlock_locker_state *state, + PSI_rwlock *rwlock, + PSI_rwlock_operation op, + const char *src_file, uint src_line) { PFS_rwlock *pfs_rwlock= reinterpret_cast<PFS_rwlock*> (rwlock); DBUG_ASSERT(static_cast<int> (op) >= 0); DBUG_ASSERT(static_cast<uint> (op) < array_elements(rwlock_operation_map)); + DBUG_ASSERT(state != NULL); DBUG_ASSERT(pfs_rwlock != NULL); DBUG_ASSERT(pfs_rwlock->m_class != NULL); - if (! flag_events_waits_current) - return NULL; - if (! pfs_rwlock->m_class->m_enabled) - return NULL; - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); - if (unlikely(pfs_thread == NULL)) - return NULL; - if (! pfs_thread->m_enabled) - return NULL; - if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE)) - { - locker_lost++; + + if (! pfs_rwlock->m_enabled) return NULL; - } - PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack - [pfs_thread->m_wait_locker_count]; - pfs_locker->m_target.m_rwlock= pfs_rwlock; - pfs_locker->m_waits_current.m_thread= pfs_thread; - pfs_locker->m_waits_current.m_class= pfs_rwlock->m_class; - if (pfs_rwlock->m_class->m_timed) + register uint flags; + ulonglong timer_start= 0; + + if (flag_thread_instrumentation) { - pfs_locker->m_timer_name= wait_timer; - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING; + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(pfs_thread == NULL)) + return NULL; + if (! pfs_thread->m_enabled) + return NULL; + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + flags= STATE_FLAG_THREAD; + + if (pfs_rwlock->m_timed) + { + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + flags|= STATE_FLAG_TIMED; + } + + if (flag_events_waits_current) + { + if (unlikely(pfs_thread->m_events_waits_current >= + & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE])) + { + locker_lost++; + return NULL; + } + PFS_events_waits *wait= pfs_thread->m_events_waits_current; + state->m_wait= wait; + flags|= STATE_FLAG_EVENT; + + PFS_events_waits *parent_event= wait - 1; + wait->m_event_type= EVENT_TYPE_WAIT; + wait->m_nesting_event_id= parent_event->m_event_id; + wait->m_nesting_event_type= parent_event->m_event_type; + + wait->m_thread= pfs_thread; + wait->m_class= pfs_rwlock->m_class; + wait->m_timer_start= timer_start; + wait->m_timer_end= 0; + wait->m_object_instance_addr= pfs_rwlock->m_identity; + wait->m_event_id= pfs_thread->m_event_id++; + wait->m_end_event_id= 0; + wait->m_operation= rwlock_operation_map[static_cast<int> (op)]; + wait->m_source_file= src_file; + wait->m_source_line= src_line; + wait->m_wait_class= WAIT_CLASS_RWLOCK; + + pfs_thread->m_events_waits_current++; + } } else - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED; - pfs_locker->m_waits_current.m_object_instance_addr= pfs_rwlock->m_identity; - pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++; - pfs_locker->m_waits_current.m_operation= - rwlock_operation_map[static_cast<int> (op)]; - pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_RWLOCK; + { + if (pfs_rwlock->m_timed) + { + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + flags= STATE_FLAG_TIMED; + state->m_thread= NULL; + } + else + { + /* + Complete shortcut. + */ + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */ + pfs_rwlock->m_wait_stat.aggregate_counted(); + return NULL; + } + } - pfs_thread->m_wait_locker_count++; - return reinterpret_cast<PSI_rwlock_locker*> (pfs_locker); + state->m_flags= flags; + state->m_rwlock= rwlock; + return reinterpret_cast<PSI_rwlock_locker*> (state); } +/** + Implementation of the cond instrumentation interface. + @sa PSI_v1::start_cond_wait. +*/ static PSI_cond_locker* -get_thread_cond_locker_v1(PSI_cond_locker_state *state, - PSI_cond *cond, PSI_mutex * /* unused: mutex */, - PSI_cond_operation op) +start_cond_wait_v1(PSI_cond_locker_state *state, + PSI_cond *cond, PSI_mutex *mutex, + PSI_cond_operation op, + const char *src_file, uint src_line) { /* Note about the unused PSI_mutex *mutex parameter: @@ -1202,87 +2328,373 @@ get_thread_cond_locker_v1(PSI_cond_locker_state *state, PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond); DBUG_ASSERT(static_cast<int> (op) >= 0); DBUG_ASSERT(static_cast<uint> (op) < array_elements(cond_operation_map)); + DBUG_ASSERT(state != NULL); DBUG_ASSERT(pfs_cond != NULL); DBUG_ASSERT(pfs_cond->m_class != NULL); - if (! flag_events_waits_current) + + if (! pfs_cond->m_enabled) return NULL; - if (! pfs_cond->m_class->m_enabled) + + register uint flags; + ulonglong timer_start= 0; + + if (flag_thread_instrumentation) + { + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(pfs_thread == NULL)) + return NULL; + if (! pfs_thread->m_enabled) + return NULL; + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + flags= STATE_FLAG_THREAD; + + if (pfs_cond->m_timed) + { + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + flags|= STATE_FLAG_TIMED; + } + + if (flag_events_waits_current) + { + if (unlikely(pfs_thread->m_events_waits_current >= + & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE])) + { + locker_lost++; + return NULL; + } + PFS_events_waits *wait= pfs_thread->m_events_waits_current; + state->m_wait= wait; + flags|= STATE_FLAG_EVENT; + + PFS_events_waits *parent_event= wait - 1; + wait->m_event_type= EVENT_TYPE_WAIT; + wait->m_nesting_event_id= parent_event->m_event_id; + wait->m_nesting_event_type= parent_event->m_event_type; + + wait->m_thread= pfs_thread; + wait->m_class= pfs_cond->m_class; + wait->m_timer_start= timer_start; + wait->m_timer_end= 0; + wait->m_object_instance_addr= pfs_cond->m_identity; + wait->m_event_id= pfs_thread->m_event_id++; + wait->m_end_event_id= 0; + wait->m_operation= cond_operation_map[static_cast<int> (op)]; + wait->m_source_file= src_file; + wait->m_source_line= src_line; + wait->m_wait_class= WAIT_CLASS_COND; + + pfs_thread->m_events_waits_current++; + } + } + else + { + if (pfs_cond->m_timed) + { + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + flags= STATE_FLAG_TIMED; + } + else + { + /* + Complete shortcut. + */ + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */ + pfs_cond->m_wait_stat.aggregate_counted(); + return NULL; + } + } + + state->m_flags= flags; + state->m_cond= cond; + state->m_mutex= mutex; + return reinterpret_cast<PSI_cond_locker*> (state); +} + +static inline PFS_TL_LOCK_TYPE lock_flags_to_lock_type(uint flags) +{ + enum thr_lock_type value= static_cast<enum thr_lock_type> (flags); + + switch (value) + { + case TL_READ: + return PFS_TL_READ; + case TL_READ_WITH_SHARED_LOCKS: + return PFS_TL_READ_WITH_SHARED_LOCKS; + case TL_READ_HIGH_PRIORITY: + return PFS_TL_READ_HIGH_PRIORITY; + case TL_READ_NO_INSERT: + return PFS_TL_READ_NO_INSERT; + case TL_WRITE_ALLOW_WRITE: + return PFS_TL_WRITE_ALLOW_WRITE; + case TL_WRITE_CONCURRENT_INSERT: + return PFS_TL_WRITE_CONCURRENT_INSERT; + case TL_WRITE_DELAYED: + return PFS_TL_WRITE_DELAYED; + case TL_WRITE_LOW_PRIORITY: + return PFS_TL_WRITE_LOW_PRIORITY; + case TL_WRITE: + return PFS_TL_WRITE; + + case TL_WRITE_ONLY: + case TL_IGNORE: + case TL_UNLOCK: + case TL_READ_DEFAULT: + case TL_WRITE_DEFAULT: + default: + DBUG_ASSERT(false); + } + + /* Dead code */ + return PFS_TL_READ; +} + +static inline PFS_TL_LOCK_TYPE external_lock_flags_to_lock_type(uint flags) +{ + DBUG_ASSERT(flags == F_RDLCK || flags == F_WRLCK); + return (flags == F_RDLCK ? PFS_TL_READ_EXTERNAL : PFS_TL_WRITE_EXTERNAL); +} + +/** + Implementation of the table instrumentation interface. + @sa PSI_v1::start_table_io_wait_v1 +*/ +static PSI_table_locker* +start_table_io_wait_v1(PSI_table_locker_state *state, + PSI_table *table, + PSI_table_io_operation op, + uint index, + const char *src_file, uint src_line) +{ + DBUG_ASSERT(static_cast<int> (op) >= 0); + DBUG_ASSERT(static_cast<uint> (op) < array_elements(table_io_operation_map)); + DBUG_ASSERT(state != NULL); + PFS_table *pfs_table= reinterpret_cast<PFS_table*> (table); + DBUG_ASSERT(pfs_table != NULL); + DBUG_ASSERT(pfs_table->m_share != NULL); + + if (! pfs_table->m_io_enabled) return NULL; - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + + PFS_thread *pfs_thread= pfs_table->m_thread_owner; if (unlikely(pfs_thread == NULL)) return NULL; - if (! pfs_thread->m_enabled) - return NULL; - if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE)) - { - locker_lost++; - return NULL; - } - PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack - [pfs_thread->m_wait_locker_count]; - pfs_locker->m_target.m_cond= pfs_cond; - pfs_locker->m_waits_current.m_thread= pfs_thread; - pfs_locker->m_waits_current.m_class= pfs_cond->m_class; - if (pfs_cond->m_class->m_timed) + DBUG_ASSERT(pfs_thread == + my_pthread_getspecific_ptr(PFS_thread*, THR_PFS)); + + register uint flags; + ulonglong timer_start= 0; + + if (flag_thread_instrumentation) { - pfs_locker->m_timer_name= wait_timer; - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING; + if (! pfs_thread->m_enabled) + return NULL; + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + flags= STATE_FLAG_THREAD; + + if (pfs_table->m_io_timed) + { + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + flags|= STATE_FLAG_TIMED; + } + + if (flag_events_waits_current) + { + if (unlikely(pfs_thread->m_events_waits_current >= + & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE])) + { + locker_lost++; + return NULL; + } + PFS_events_waits *wait= pfs_thread->m_events_waits_current; + state->m_wait= wait; + flags|= STATE_FLAG_EVENT; + + PFS_events_waits *parent_event= wait - 1; + wait->m_event_type= EVENT_TYPE_WAIT; + wait->m_nesting_event_id= parent_event->m_event_id; + wait->m_nesting_event_type= parent_event->m_event_type; + + PFS_table_share *share= pfs_table->m_share; + wait->m_thread= pfs_thread; + wait->m_class= &global_table_io_class; + wait->m_timer_start= timer_start; + wait->m_timer_end= 0; + wait->m_object_instance_addr= pfs_table->m_identity; + wait->m_event_id= pfs_thread->m_event_id++; + wait->m_end_event_id= 0; + wait->m_operation= table_io_operation_map[static_cast<int> (op)]; + wait->m_flags= 0; + wait->m_object_type= share->get_object_type(); + wait->m_weak_table_share= share; + wait->m_weak_version= share->get_version(); + wait->m_index= index; + wait->m_source_file= src_file; + wait->m_source_line= src_line; + wait->m_wait_class= WAIT_CLASS_TABLE; + + pfs_thread->m_events_waits_current++; + } + /* TODO: consider a shortcut here */ } else - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED; - pfs_locker->m_waits_current.m_object_instance_addr= pfs_cond->m_identity; - pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++; - pfs_locker->m_waits_current.m_operation= - cond_operation_map[static_cast<int> (op)]; - pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_COND; + { + if (pfs_table->m_io_timed) + { + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + flags= STATE_FLAG_TIMED; + } + else + { + /* TODO: consider a shortcut here */ + flags= 0; + } + } - pfs_thread->m_wait_locker_count++; - return reinterpret_cast<PSI_cond_locker*> (pfs_locker); + state->m_flags= flags; + state->m_table= table; + state->m_io_operation= op; + state->m_index= index; + return reinterpret_cast<PSI_table_locker*> (state); } +/** + Implementation of the table instrumentation interface. + @sa PSI_v1::start_table_lock_wait. +*/ static PSI_table_locker* -get_thread_table_locker_v1(PSI_table_locker_state *state, - PSI_table *table) +start_table_lock_wait_v1(PSI_table_locker_state *state, + PSI_table *table, + PSI_table_lock_operation op, + ulong op_flags, + const char *src_file, uint src_line) { + DBUG_ASSERT(state != NULL); + DBUG_ASSERT((op == PSI_TABLE_LOCK) || (op == PSI_TABLE_EXTERNAL_LOCK)); + PFS_table *pfs_table= reinterpret_cast<PFS_table*> (table); + DBUG_ASSERT(pfs_table != NULL); DBUG_ASSERT(pfs_table->m_share != NULL); - if (! flag_events_waits_current) - return NULL; - if (! pfs_table->m_share->m_enabled) + + if (! pfs_table->m_lock_enabled) return NULL; - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + + PFS_thread *pfs_thread= pfs_table->m_thread_owner; if (unlikely(pfs_thread == NULL)) return NULL; - if (! pfs_thread->m_enabled) - return NULL; - if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE)) + + DBUG_ASSERT(pfs_thread == + my_pthread_getspecific_ptr(PFS_thread*, THR_PFS)); + + PFS_TL_LOCK_TYPE lock_type; + + switch (op) { - locker_lost++; - return NULL; + case PSI_TABLE_LOCK: + lock_type= lock_flags_to_lock_type(op_flags); + break; + case PSI_TABLE_EXTERNAL_LOCK: + /* + See the handler::external_lock() API design, + there is no handler::external_unlock(). + */ + if (op_flags == F_UNLCK) + return NULL; + lock_type= external_lock_flags_to_lock_type(op_flags); + break; + default: + lock_type= PFS_TL_READ; + DBUG_ASSERT(false); } - PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack - [pfs_thread->m_wait_locker_count]; - pfs_locker->m_target.m_table= pfs_table; - pfs_locker->m_waits_current.m_thread= pfs_thread; - pfs_locker->m_waits_current.m_class= &global_table_class; - if (pfs_table->m_share->m_timed) + DBUG_ASSERT((uint) lock_type < array_elements(table_lock_operation_map)); + + register uint flags; + ulonglong timer_start= 0; + + if (flag_thread_instrumentation) { - pfs_locker->m_timer_name= wait_timer; - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING; + if (! pfs_thread->m_enabled) + return NULL; + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + flags= STATE_FLAG_THREAD; + + if (pfs_table->m_lock_timed) + { + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + flags|= STATE_FLAG_TIMED; + } + + if (flag_events_waits_current) + { + if (unlikely(pfs_thread->m_events_waits_current >= + & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE])) + { + locker_lost++; + return NULL; + } + PFS_events_waits *wait= pfs_thread->m_events_waits_current; + state->m_wait= wait; + flags|= STATE_FLAG_EVENT; + + PFS_events_waits *parent_event= wait - 1; + wait->m_event_type= EVENT_TYPE_WAIT; + wait->m_nesting_event_id= parent_event->m_event_id; + wait->m_nesting_event_type= parent_event->m_event_type; + + PFS_table_share *share= pfs_table->m_share; + wait->m_thread= pfs_thread; + wait->m_class= &global_table_lock_class; + wait->m_timer_start= timer_start; + wait->m_timer_end= 0; + wait->m_object_instance_addr= pfs_table->m_identity; + wait->m_event_id= pfs_thread->m_event_id++; + wait->m_end_event_id= 0; + wait->m_operation= table_lock_operation_map[lock_type]; + wait->m_flags= 0; + wait->m_object_type= share->get_object_type(); + wait->m_weak_table_share= share; + wait->m_weak_version= share->get_version(); + wait->m_index= 0; + wait->m_source_file= src_file; + wait->m_source_line= src_line; + wait->m_wait_class= WAIT_CLASS_TABLE; + + pfs_thread->m_events_waits_current++; + } + /* TODO: consider a shortcut here */ } else - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED; - pfs_locker->m_waits_current.m_object_instance_addr= pfs_table->m_identity; - pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++; - pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_TABLE; + { + if (pfs_table->m_lock_timed) + { + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + flags= STATE_FLAG_TIMED; + } + else + { + /* TODO: consider a shortcut here */ + flags= 0; + } + } - pfs_thread->m_wait_locker_count++; - return reinterpret_cast<PSI_table_locker*> (pfs_locker); + state->m_flags= flags; + state->m_table= table; + state->m_index= lock_type; + return reinterpret_cast<PSI_table_locker*> (state); } +/** + Implementation of the file instrumentation interface. + @sa PSI_v1::get_thread_file_name_locker. +*/ static PSI_file_locker* get_thread_file_name_locker_v1(PSI_file_locker_state *state, PSI_file_key key, @@ -1291,180 +2703,398 @@ get_thread_file_name_locker_v1(PSI_file_locker_state *state, { DBUG_ASSERT(static_cast<int> (op) >= 0); DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map)); + DBUG_ASSERT(state != NULL); - if (! flag_events_waits_current) + if (! flag_global_instrumentation) return NULL; PFS_file_class *klass= find_file_class(key); if (unlikely(klass == NULL)) return NULL; if (! klass->m_enabled) return NULL; + + /* Needed for the LF_HASH */ PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); if (unlikely(pfs_thread == NULL)) return NULL; - if (! pfs_thread->m_enabled) - return NULL; - if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE)) - { - locker_lost++; + + if (flag_thread_instrumentation && ! pfs_thread->m_enabled) return NULL; - } + + register uint flags; + + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + flags= STATE_FLAG_THREAD; + + if (klass->m_timed) + flags|= STATE_FLAG_TIMED; + uint len= strlen(name); PFS_file *pfs_file= find_or_create_file(pfs_thread, klass, name, len); if (unlikely(pfs_file == NULL)) return NULL; - PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack - [pfs_thread->m_wait_locker_count]; - - pfs_locker->m_target.m_file= pfs_file; - pfs_locker->m_waits_current.m_thread= pfs_thread; - pfs_locker->m_waits_current.m_class= pfs_file->m_class; - if (pfs_file->m_class->m_timed) + if (flag_events_waits_current) { - pfs_locker->m_timer_name= wait_timer; - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING; + if (unlikely(pfs_thread->m_events_waits_current >= + & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE])) + { + locker_lost++; + return NULL; + } + PFS_events_waits *wait= pfs_thread->m_events_waits_current; + state->m_wait= wait; + flags|= STATE_FLAG_EVENT; + + PFS_events_waits *parent_event= wait - 1; + wait->m_event_type= EVENT_TYPE_WAIT; + wait->m_nesting_event_id= parent_event->m_event_id; + wait->m_nesting_event_type= parent_event->m_event_type; + + wait->m_thread= pfs_thread; + wait->m_class= klass; + wait->m_timer_start= 0; + wait->m_timer_end= 0; + wait->m_object_instance_addr= pfs_file; + wait->m_weak_file= pfs_file; + wait->m_weak_version= pfs_file->get_version(); + wait->m_event_id= pfs_thread->m_event_id++; + wait->m_end_event_id= 0; + wait->m_operation= file_operation_map[static_cast<int> (op)]; + wait->m_wait_class= WAIT_CLASS_FILE; + + pfs_thread->m_events_waits_current++; } - else - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED; - pfs_locker->m_waits_current.m_object_instance_addr= pfs_file; - pfs_locker->m_waits_current.m_object_name= pfs_file->m_filename; - pfs_locker->m_waits_current.m_object_name_length= - pfs_file->m_filename_length; - pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++; - pfs_locker->m_waits_current.m_operation= - file_operation_map[static_cast<int> (op)]; - pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_FILE; - pfs_thread->m_wait_locker_count++; - return reinterpret_cast<PSI_file_locker*> (pfs_locker); + state->m_flags= flags; + state->m_file= reinterpret_cast<PSI_file*> (pfs_file); + state->m_operation= op; + return reinterpret_cast<PSI_file_locker*> (state); } +/** + Implementation of the file instrumentation interface. + @sa PSI_v1::get_thread_file_stream_locker. +*/ static PSI_file_locker* get_thread_file_stream_locker_v1(PSI_file_locker_state *state, PSI_file *file, PSI_file_operation op) { PFS_file *pfs_file= reinterpret_cast<PFS_file*> (file); - DBUG_ASSERT(static_cast<int> (op) >= 0); DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map)); - DBUG_ASSERT(pfs_file != NULL); - DBUG_ASSERT(pfs_file->m_class != NULL); + DBUG_ASSERT(state != NULL); - if (! flag_events_waits_current) - return NULL; - if (! pfs_file->m_class->m_enabled) - return NULL; - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); - if (unlikely(pfs_thread == NULL)) - return NULL; - if (! pfs_thread->m_enabled) + if (unlikely(pfs_file == NULL)) return NULL; - if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE)) - { - locker_lost++; + DBUG_ASSERT(pfs_file->m_class != NULL); + + if (! pfs_file->m_enabled) return NULL; - } - PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack - [pfs_thread->m_wait_locker_count]; - pfs_locker->m_target.m_file= pfs_file; - pfs_locker->m_waits_current.m_thread= pfs_thread; - pfs_locker->m_waits_current.m_class= pfs_file->m_class; - if (pfs_file->m_class->m_timed) + register uint flags; + + if (flag_thread_instrumentation) { - pfs_locker->m_timer_name= wait_timer; - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING; + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(pfs_thread == NULL)) + return NULL; + if (! pfs_thread->m_enabled) + return NULL; + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + flags= STATE_FLAG_THREAD; + + if (pfs_file->m_timed) + flags|= STATE_FLAG_TIMED; + + if (flag_events_waits_current) + { + if (unlikely(pfs_thread->m_events_waits_current >= + & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE])) + { + locker_lost++; + return NULL; + } + PFS_events_waits *wait= pfs_thread->m_events_waits_current; + state->m_wait= wait; + flags|= STATE_FLAG_EVENT; + + PFS_events_waits *parent_event= wait - 1; + wait->m_event_type= EVENT_TYPE_WAIT; + wait->m_nesting_event_id= parent_event->m_event_id; + wait->m_nesting_event_type= parent_event->m_event_type; + + wait->m_thread= pfs_thread; + wait->m_class= pfs_file->m_class; + wait->m_timer_start= 0; + wait->m_timer_end= 0; + wait->m_object_instance_addr= pfs_file; + wait->m_weak_file= pfs_file; + wait->m_weak_version= pfs_file->get_version(); + wait->m_event_id= pfs_thread->m_event_id++; + wait->m_end_event_id= 0; + wait->m_operation= file_operation_map[static_cast<int> (op)]; + wait->m_wait_class= WAIT_CLASS_FILE; + + pfs_thread->m_events_waits_current++; + } } else - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED; - pfs_locker->m_waits_current.m_object_instance_addr= pfs_file; - pfs_locker->m_waits_current.m_object_name= pfs_file->m_filename; - pfs_locker->m_waits_current.m_object_name_length= - pfs_file->m_filename_length; - pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++; - pfs_locker->m_waits_current.m_operation= - file_operation_map[static_cast<int> (op)]; - pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_FILE; + { + state->m_thread= NULL; + if (pfs_file->m_timed) + { + flags= STATE_FLAG_TIMED; + } + else + { + /* TODO: consider a shortcut. */ + flags= 0; + } + } - pfs_thread->m_wait_locker_count++; - return reinterpret_cast<PSI_file_locker*> (pfs_locker); + state->m_flags= flags; + state->m_file= reinterpret_cast<PSI_file*> (pfs_file); + state->m_operation= op; + return reinterpret_cast<PSI_file_locker*> (state); } +/** + Implementation of the file instrumentation interface. + @sa PSI_v1::get_thread_file_descriptor_locker. +*/ static PSI_file_locker* get_thread_file_descriptor_locker_v1(PSI_file_locker_state *state, File file, PSI_file_operation op) { int index= static_cast<int> (file); - DBUG_ASSERT(static_cast<int> (op) >= 0); DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map)); + DBUG_ASSERT(state != NULL); - if (! flag_events_waits_current) + if (unlikely((index < 0) || (index >= file_handle_max))) return NULL; - if (likely((index >= 0) && (index < file_handle_max))) + + PFS_file *pfs_file= file_handle_array[index]; + if (unlikely(pfs_file == NULL)) + return NULL; + + /* + We are about to close a file by descriptor number, + and the calling code still holds the descriptor. + Cleanup the file descriptor <--> file instrument association. + Remove the instrumentation *before* the close to avoid race + conditions with another thread opening a file + (that could be given the same descriptor). + */ + if (op == PSI_FILE_CLOSE) + file_handle_array[index]= NULL; + + DBUG_ASSERT(pfs_file->m_class != NULL); + if (! pfs_file->m_enabled) + return NULL; + + register uint flags; + + if (flag_thread_instrumentation) + { + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(pfs_thread == NULL)) + return NULL; + if (! pfs_thread->m_enabled) + return NULL; + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + flags= STATE_FLAG_THREAD; + + if (pfs_file->m_timed) + flags|= STATE_FLAG_TIMED; + + if (flag_events_waits_current) + { + if (unlikely(pfs_thread->m_events_waits_current >= + & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE])) + { + locker_lost++; + return NULL; + } + PFS_events_waits *wait= pfs_thread->m_events_waits_current; + state->m_wait= wait; + flags|= STATE_FLAG_EVENT; + + PFS_events_waits *parent_event= wait - 1; + wait->m_event_type= EVENT_TYPE_WAIT; + wait->m_nesting_event_id= parent_event->m_event_id; + wait->m_nesting_event_type= parent_event->m_event_type; + + wait->m_thread= pfs_thread; + wait->m_class= pfs_file->m_class; + wait->m_timer_start= 0; + wait->m_timer_end= 0; + wait->m_object_instance_addr= pfs_file; + wait->m_weak_file= pfs_file; + wait->m_weak_version= pfs_file->get_version(); + wait->m_event_id= pfs_thread->m_event_id++; + wait->m_end_event_id= 0; + wait->m_operation= file_operation_map[static_cast<int> (op)]; + wait->m_wait_class= WAIT_CLASS_FILE; + + pfs_thread->m_events_waits_current++; + } + } + else { - PFS_file *pfs_file= file_handle_array[index]; - if (likely(pfs_file != NULL)) + state->m_thread= NULL; + if (pfs_file->m_timed) { - PFS_thread *pfs_thread; + flags= STATE_FLAG_TIMED; + } + else + { + /* TODO: consider a shortcut. */ + flags= 0; + } + } - /* - We are about to close a file by descriptor number, - and the calling code still holds the descriptor. - Cleanup the file descriptor <--> file instrument association. - Remove the instrumentation *before* the close to avoid race - conditions with another thread opening a file - (that could be given the same descriptor). - */ - if (op == PSI_FILE_CLOSE) - file_handle_array[index]= NULL; + state->m_flags= flags; + state->m_file= reinterpret_cast<PSI_file*> (pfs_file); + state->m_operation= op; + return reinterpret_cast<PSI_file_locker*> (state); +} - DBUG_ASSERT(pfs_file->m_class != NULL); - if (! pfs_file->m_class->m_enabled) - return NULL; - pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); - if (unlikely(pfs_thread == NULL)) - return NULL; - if (! pfs_thread->m_enabled) - return NULL; - if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE)) +/** Socket locker */ + +static PSI_socket_locker* +start_socket_wait_v1(PSI_socket_locker_state *state, + PSI_socket *socket, + PSI_socket_operation op, + size_t count, + const char *src_file, uint src_line) +{ + DBUG_ASSERT(static_cast<int> (op) >= 0); + DBUG_ASSERT(static_cast<uint> (op) < array_elements(socket_operation_map)); + DBUG_ASSERT(state != NULL); + PFS_socket *pfs_socket= reinterpret_cast<PFS_socket*> (socket); + + DBUG_ASSERT(pfs_socket != NULL); + DBUG_ASSERT(pfs_socket->m_class != NULL); + + if (!pfs_socket->m_enabled || pfs_socket->m_idle) + return NULL; + + register uint flags= 0; + ulonglong timer_start= 0; + + if (flag_thread_instrumentation) + { + PFS_thread *pfs_thread= pfs_socket->m_thread_owner; + + if (unlikely(pfs_thread == NULL)) + return NULL; + +#ifdef LATER + /* + Needs refinement, because of KILL. + */ + DBUG_ASSERT(pfs_thread == + my_pthread_getspecific_ptr(PFS_thread*, THR_PFS)); +#endif + + if (!pfs_thread->m_enabled) + return NULL; + + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + flags= STATE_FLAG_THREAD; + + if (pfs_socket->m_timed) + { + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + flags|= STATE_FLAG_TIMED; + } + + if (flag_events_waits_current) + { + if (unlikely(pfs_thread->m_events_waits_current >= + & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE])) { locker_lost++; return NULL; } - PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack - [pfs_thread->m_wait_locker_count]; - - pfs_locker->m_target.m_file= pfs_file; - pfs_locker->m_waits_current.m_thread= pfs_thread; - pfs_locker->m_waits_current.m_class= pfs_file->m_class; - if (pfs_file->m_class->m_timed) + PFS_events_waits *wait= pfs_thread->m_events_waits_current; + state->m_wait= wait; + flags|= STATE_FLAG_EVENT; + + PFS_events_waits *parent_event= wait - 1; + wait->m_event_type= EVENT_TYPE_WAIT; + wait->m_nesting_event_id= parent_event->m_event_id; + wait->m_nesting_event_type= parent_event->m_event_type; + wait->m_thread= pfs_thread; + wait->m_class= pfs_socket->m_class; + wait->m_timer_start= timer_start; + wait->m_timer_end= 0; + wait->m_object_instance_addr= pfs_socket->m_identity; + wait->m_weak_socket= pfs_socket; + wait->m_weak_version= pfs_socket->get_version(); + wait->m_event_id= pfs_thread->m_event_id++; + wait->m_end_event_id= 0; + wait->m_operation= socket_operation_map[static_cast<int>(op)]; + wait->m_source_file= src_file; + wait->m_source_line= src_line; + wait->m_number_of_bytes= count; + wait->m_wait_class= WAIT_CLASS_SOCKET; + + pfs_thread->m_events_waits_current++; + } + } + else + { + if (pfs_socket->m_timed) + { + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + flags= STATE_FLAG_TIMED; + } + else + { + /* + Even if timing is disabled, end_socket_wait() still needs a locker to + capture the number of bytes sent or received by the socket operation. + For operations that do not have a byte count, then just increment the + event counter and return a NULL locker. + */ + switch (op) { - pfs_locker->m_timer_name= wait_timer; - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING; + case PSI_SOCKET_CONNECT: + case PSI_SOCKET_CREATE: + case PSI_SOCKET_BIND: + case PSI_SOCKET_SEEK: + case PSI_SOCKET_OPT: + case PSI_SOCKET_STAT: + case PSI_SOCKET_SHUTDOWN: + case PSI_SOCKET_CLOSE: + case PSI_SOCKET_SELECT: + pfs_socket->m_socket_stat.m_io_stat.m_misc.aggregate_counted(); + return NULL; + default: + break; } - else - pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED; - pfs_locker->m_waits_current.m_object_instance_addr= pfs_file; - pfs_locker->m_waits_current.m_object_name= pfs_file->m_filename; - pfs_locker->m_waits_current.m_object_name_length= - pfs_file->m_filename_length; - pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++; - pfs_locker->m_waits_current.m_operation= - file_operation_map[static_cast<int> (op)]; - pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_FILE; - - pfs_thread->m_wait_locker_count++; - return reinterpret_cast<PSI_file_locker*> (pfs_locker); } } - return NULL; + + state->m_flags= flags; + state->m_socket= socket; + state->m_operation= op; + return reinterpret_cast<PSI_socket_locker*> (state); } +/** + Implementation of the mutex instrumentation interface. + @sa PSI_v1::unlock_mutex. +*/ static void unlock_mutex_v1(PSI_mutex *mutex) { PFS_mutex *pfs_mutex= reinterpret_cast<PFS_mutex*> (mutex); + DBUG_ASSERT(pfs_mutex != NULL); /* @@ -1495,16 +3125,24 @@ static void unlock_mutex_v1(PSI_mutex *mutex) if (pfs_mutex->m_class->m_timed) { ulonglong locked_time; - locked_time= get_timer_value(wait_timer) - pfs_mutex->m_last_locked; + locked_time= get_timer_pico_value(wait_timer) - pfs_mutex->m_last_locked; aggregate_single_stat_chain(&pfs_mutex->m_lock_stat, locked_time); } #endif } +/** + Implementation of the rwlock instrumentation interface. + @sa PSI_v1::unlock_rwlock. +*/ static void unlock_rwlock_v1(PSI_rwlock *rwlock) { PFS_rwlock *pfs_rwlock= reinterpret_cast<PFS_rwlock*> (rwlock); DBUG_ASSERT(pfs_rwlock != NULL); + DBUG_ASSERT(pfs_rwlock == sanitize_rwlock(pfs_rwlock)); + DBUG_ASSERT(pfs_rwlock->m_class != NULL); + DBUG_ASSERT(pfs_rwlock->m_lock.is_populated()); + bool last_writer= false; bool last_reader= false; @@ -1517,7 +3155,7 @@ static void unlock_rwlock_v1(PSI_rwlock *rwlock) */ /* Always update the instrumented state */ - if (pfs_rwlock->m_writer) + if (pfs_rwlock->m_writer != NULL) { /* Nominal case, a writer is unlocking. */ last_writer= true; @@ -1562,7 +3200,7 @@ static void unlock_rwlock_v1(PSI_rwlock *rwlock) { if (pfs_rwlock->m_class->m_timed) { - locked_time= get_timer_value(wait_timer) - pfs_rwlock->m_last_written; + locked_time= get_timer_pico_value(wait_timer) - pfs_rwlock->m_last_written; aggregate_single_stat_chain(&pfs_rwlock->m_write_lock_stat, locked_time); } } @@ -1570,7 +3208,7 @@ static void unlock_rwlock_v1(PSI_rwlock *rwlock) { if (pfs_rwlock->m_class->m_timed) { - locked_time= get_timer_value(wait_timer) - pfs_rwlock->m_last_read; + locked_time= get_timer_pico_value(wait_timer) - pfs_rwlock->m_last_read; aggregate_single_stat_chain(&pfs_rwlock->m_read_lock_stat, locked_time); } } @@ -1580,109 +3218,266 @@ static void unlock_rwlock_v1(PSI_rwlock *rwlock) #endif } +/** + Implementation of the cond instrumentation interface. + @sa PSI_v1::signal_cond. +*/ static void signal_cond_v1(PSI_cond* cond) { PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond); + DBUG_ASSERT(pfs_cond != NULL); pfs_cond->m_cond_stat.m_signal_count++; } +/** + Implementation of the cond instrumentation interface. + @sa PSI_v1::broadcast_cond. +*/ static void broadcast_cond_v1(PSI_cond* cond) { PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond); + DBUG_ASSERT(pfs_cond != NULL); pfs_cond->m_cond_stat.m_broadcast_count++; } -static void start_mutex_wait_v1(PSI_mutex_locker* locker, - const char *src_file, uint src_line) +/** + Implementation of the idle instrumentation interface. + @sa PSI_v1::start_idle_wait. +*/ +static PSI_idle_locker* +start_idle_wait_v1(PSI_idle_locker_state* state, const char *src_file, uint src_line) { - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); + DBUG_ASSERT(state != NULL); + + if (!flag_global_instrumentation) + return NULL; + + if (!global_idle_class.m_enabled) + return NULL; + + register uint flags= 0; + ulonglong timer_start= 0; + + if (flag_thread_instrumentation) + { + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(pfs_thread == NULL)) + return NULL; + if (!pfs_thread->m_enabled) + return NULL; + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + flags= STATE_FLAG_THREAD; + + if (global_idle_class.m_timed) + { + timer_start= get_timer_raw_value_and_function(idle_timer, &state->m_timer); + state->m_timer_start= timer_start; + flags|= STATE_FLAG_TIMED; + } - PFS_events_waits *wait= &pfs_locker->m_waits_current; - if (wait->m_timer_state == TIMER_STATE_STARTING) + if (flag_events_waits_current) + { + if (unlikely(pfs_thread->m_events_waits_current >= + & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE])) + { + locker_lost++; + return NULL; + } + PFS_events_waits *wait= pfs_thread->m_events_waits_current; + state->m_wait= wait; + flags|= STATE_FLAG_EVENT; + + wait->m_event_type= EVENT_TYPE_WAIT; + /* + IDLE events are waits, but by definition we know that + such waits happen outside of any STAGE and STATEMENT, + so they have no parents. + */ + wait->m_nesting_event_id= 0; + /* no need to set wait->m_nesting_event_type */ + + wait->m_thread= pfs_thread; + wait->m_class= &global_idle_class; + wait->m_timer_start= timer_start; + wait->m_timer_end= 0; + wait->m_event_id= pfs_thread->m_event_id++; + wait->m_end_event_id= 0; + wait->m_operation= OPERATION_TYPE_IDLE; + wait->m_source_file= src_file; + wait->m_source_line= src_line; + wait->m_wait_class= WAIT_CLASS_IDLE; + + pfs_thread->m_events_waits_current++; + } + } + else { - wait->m_timer_start= get_timer_value(pfs_locker->m_timer_name); - wait->m_timer_state= TIMER_STATE_STARTED; + if (global_idle_class.m_timed) + { + timer_start= get_timer_raw_value_and_function(idle_timer, &state->m_timer); + state->m_timer_start= timer_start; + flags= STATE_FLAG_TIMED; + } } - wait->m_source_file= src_file; - wait->m_source_line= src_line; + + state->m_flags= flags; + return reinterpret_cast<PSI_idle_locker*> (state); } -static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc) +/** + Implementation of the mutex instrumentation interface. + @sa PSI_v1::end_idle_wait. +*/ +static void end_idle_wait_v1(PSI_idle_locker* locker) { - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); - PFS_events_waits *wait= &pfs_locker->m_waits_current; + PSI_idle_locker_state *state= reinterpret_cast<PSI_idle_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + ulonglong timer_end= 0; + ulonglong wait_time= 0; + + register uint flags= state->m_flags; - if (wait->m_timer_state == TIMER_STATE_STARTED) + if (flags & STATE_FLAG_TIMED) { - wait->m_timer_end= get_timer_value(pfs_locker->m_timer_name); - wait->m_timer_state= TIMER_STATE_TIMED; + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; } - if (flag_events_waits_history) - insert_events_waits_history(wait->m_thread, wait); - if (flag_events_waits_history_long) - insert_events_waits_history_long(wait); - if (rc == 0) + if (flags & STATE_FLAG_THREAD) { - /* Thread safe: we are protected by the instrumented mutex */ - PFS_mutex *mutex= pfs_locker->m_target.m_mutex; - PFS_single_stat_chain *stat= find_per_thread_mutex_class_wait_stat(wait->m_thread, mutex->m_class); - mutex->m_owner= wait->m_thread; - mutex->m_last_locked= wait->m_timer_end; + PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread); + PFS_single_stat *event_name_array; + event_name_array= thread->m_instr_class_waits_stats; + uint index= global_idle_class.m_event_name_index; - /* If timed then aggregate stats, else increment the value counts only */ - if (wait->m_timer_state == TIMER_STATE_TIMED) + if (flags & STATE_FLAG_TIMED) { - ulonglong wait_time= wait->m_timer_end - wait->m_timer_start; - aggregate_single_stat_chain(&mutex->m_wait_stat, wait_time); - aggregate_single_stat_chain(stat, wait_time); + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */ + event_name_array[index].aggregate_value(wait_time); } else { - increment_single_stat_chain(&mutex->m_wait_stat); - increment_single_stat_chain(stat); + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */ + event_name_array[index].aggregate_counted(); + } + + if (flags & STATE_FLAG_EVENT) + { + PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait); + DBUG_ASSERT(wait != NULL); + + wait->m_timer_end= timer_end; + wait->m_end_event_id= thread->m_event_id; + if (flag_events_waits_history) + insert_events_waits_history(thread, wait); + if (flag_events_waits_history_long) + insert_events_waits_history_long(wait); + thread->m_events_waits_current--; } } - wait->m_thread->m_wait_locker_count--; } -static void start_rwlock_rdwait_v1(PSI_rwlock_locker* locker, - const char *src_file, uint src_line) +/** + Implementation of the mutex instrumentation interface. + @sa PSI_v1::end_mutex_wait. +*/ +static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc) { - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); + PSI_mutex_locker_state *state= reinterpret_cast<PSI_mutex_locker_state*> (locker); + DBUG_ASSERT(state != NULL); - PFS_events_waits *wait= &pfs_locker->m_waits_current; - if (wait->m_timer_state == TIMER_STATE_STARTING) + ulonglong timer_end= 0; + ulonglong wait_time= 0; + + PFS_mutex *mutex= reinterpret_cast<PFS_mutex *> (state->m_mutex); + DBUG_ASSERT(mutex != NULL); + PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread); + + register uint flags= state->m_flags; + + if (flags & STATE_FLAG_TIMED) + { + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */ + mutex->m_wait_stat.aggregate_value(wait_time); + } + else { - wait->m_timer_start= get_timer_value(pfs_locker->m_timer_name); - wait->m_timer_state= TIMER_STATE_STARTED; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */ + mutex->m_wait_stat.aggregate_counted(); + } + + if (likely(rc == 0)) + { + mutex->m_owner= thread; + mutex->m_last_locked= timer_end; + } + + if (flags & STATE_FLAG_THREAD) + { + PFS_single_stat *event_name_array; + event_name_array= thread->m_instr_class_waits_stats; + uint index= mutex->m_class->m_event_name_index; + + if (flags & STATE_FLAG_TIMED) + { + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */ + event_name_array[index].aggregate_value(wait_time); + } + else + { + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */ + event_name_array[index].aggregate_counted(); + } + + if (flags & STATE_FLAG_EVENT) + { + PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait); + DBUG_ASSERT(wait != NULL); + + wait->m_timer_end= timer_end; + wait->m_end_event_id= thread->m_event_id; + if (flag_events_waits_history) + insert_events_waits_history(thread, wait); + if (flag_events_waits_history_long) + insert_events_waits_history_long(wait); + thread->m_events_waits_current--; + } } - wait->m_source_file= src_file; - wait->m_source_line= src_line; } +/** + Implementation of the rwlock instrumentation interface. + @sa PSI_v1::end_rwlock_rdwait. +*/ static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc) { - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); - PFS_events_waits *wait= &pfs_locker->m_waits_current; + PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + ulonglong timer_end= 0; + ulonglong wait_time= 0; - if (wait->m_timer_state == TIMER_STATE_STARTED) + PFS_rwlock *rwlock= reinterpret_cast<PFS_rwlock *> (state->m_rwlock); + DBUG_ASSERT(rwlock != NULL); + + if (state->m_flags & STATE_FLAG_TIMED) + { + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */ + rwlock->m_wait_stat.aggregate_value(wait_time); + } + else { - wait->m_timer_end= get_timer_value(pfs_locker->m_timer_name); - wait->m_timer_state= TIMER_STATE_TIMED; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */ + rwlock->m_wait_stat.aggregate_counted(); } - if (flag_events_waits_history) - insert_events_waits_history(wait->m_thread, wait); - if (flag_events_waits_history_long) - insert_events_waits_history_long(wait); if (rc == 0) { @@ -1693,220 +3488,307 @@ static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc) The statistics generated are not safe, which is why they are just statistics, not facts. */ - PFS_rwlock *rwlock= pfs_locker->m_target.m_rwlock; - PFS_single_stat_chain *stat= find_per_thread_rwlock_class_wait_stat(wait->m_thread, rwlock->m_class); - if (rwlock->m_readers == 0) - rwlock->m_last_read= wait->m_timer_end; + rwlock->m_last_read= timer_end; rwlock->m_writer= NULL; rwlock->m_readers++; + } + + if (state->m_flags & STATE_FLAG_THREAD) + { + PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread); + DBUG_ASSERT(thread != NULL); + + PFS_single_stat *event_name_array; + event_name_array= thread->m_instr_class_waits_stats; + uint index= rwlock->m_class->m_event_name_index; - /* If timed then aggregate stats, else increment the value counts only */ - if (wait->m_timer_state == TIMER_STATE_TIMED) + if (state->m_flags & STATE_FLAG_TIMED) { - ulonglong wait_time= wait->m_timer_end - wait->m_timer_start; - aggregate_single_stat_chain(&rwlock->m_wait_stat, wait_time); - aggregate_single_stat_chain(stat, wait_time); + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */ + event_name_array[index].aggregate_value(wait_time); } else { - increment_single_stat_chain(&rwlock->m_wait_stat); - increment_single_stat_chain(stat); + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */ + event_name_array[index].aggregate_counted(); } - } - wait->m_thread->m_wait_locker_count--; -} - -static void start_rwlock_wrwait_v1(PSI_rwlock_locker* locker, - const char *src_file, uint src_line) -{ - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); - PFS_events_waits *wait= &pfs_locker->m_waits_current; - if (wait->m_timer_state == TIMER_STATE_STARTING) - { - wait->m_timer_start= get_timer_value(pfs_locker->m_timer_name); - wait->m_timer_state= TIMER_STATE_STARTED; + if (state->m_flags & STATE_FLAG_EVENT) + { + PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait); + DBUG_ASSERT(wait != NULL); + + wait->m_timer_end= timer_end; + wait->m_end_event_id= thread->m_event_id; + if (flag_events_waits_history) + insert_events_waits_history(thread, wait); + if (flag_events_waits_history_long) + insert_events_waits_history_long(wait); + thread->m_events_waits_current--; + } } - wait->m_source_file= src_file; - wait->m_source_line= src_line; } +/** + Implementation of the rwlock instrumentation interface. + @sa PSI_v1::end_rwlock_wrwait. +*/ static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc) { - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); - PFS_events_waits *wait= &pfs_locker->m_waits_current; + PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker); + DBUG_ASSERT(state != NULL); - if (wait->m_timer_state == TIMER_STATE_STARTED) + ulonglong timer_end= 0; + ulonglong wait_time= 0; + + PFS_rwlock *rwlock= reinterpret_cast<PFS_rwlock *> (state->m_rwlock); + DBUG_ASSERT(rwlock != NULL); + PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread); + + if (state->m_flags & STATE_FLAG_TIMED) + { + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */ + rwlock->m_wait_stat.aggregate_value(wait_time); + } + else { - wait->m_timer_end= get_timer_value(pfs_locker->m_timer_name); - wait->m_timer_state= TIMER_STATE_TIMED; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */ + rwlock->m_wait_stat.aggregate_counted(); } - if (flag_events_waits_history) - insert_events_waits_history(wait->m_thread, wait); - if (flag_events_waits_history_long) - insert_events_waits_history_long(wait); - if (rc == 0) + if (likely(rc == 0)) { /* Thread safe : we are protected by the instrumented rwlock */ - PFS_rwlock *rwlock= pfs_locker->m_target.m_rwlock; - PFS_single_stat_chain *stat= find_per_thread_rwlock_class_wait_stat(wait->m_thread, rwlock->m_class); - rwlock->m_writer= wait->m_thread; - rwlock->m_last_written= wait->m_timer_end; + rwlock->m_writer= thread; + rwlock->m_last_written= timer_end; /* Reset the readers stats, they could be off */ rwlock->m_readers= 0; rwlock->m_last_read= 0; + } + + if (state->m_flags & STATE_FLAG_THREAD) + { + PFS_single_stat *event_name_array; + event_name_array= thread->m_instr_class_waits_stats; + uint index= rwlock->m_class->m_event_name_index; - /* If timed then aggregate stats, else increment the value counts only */ - if (wait->m_timer_state == TIMER_STATE_TIMED) + if (state->m_flags & STATE_FLAG_TIMED) { - ulonglong wait_time= wait->m_timer_end - wait->m_timer_start; - aggregate_single_stat_chain(&rwlock->m_wait_stat, wait_time); - aggregate_single_stat_chain(stat, wait_time); + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */ + event_name_array[index].aggregate_value(wait_time); } else { - increment_single_stat_chain(&rwlock->m_wait_stat); - increment_single_stat_chain(stat); + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */ + event_name_array[index].aggregate_counted(); } - } - wait->m_thread->m_wait_locker_count--; -} - -static void start_cond_wait_v1(PSI_cond_locker* locker, - const char *src_file, uint src_line) -{ - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); - PFS_events_waits *wait= &pfs_locker->m_waits_current; - if (wait->m_timer_state == TIMER_STATE_STARTING) - { - wait->m_timer_start= get_timer_value(pfs_locker->m_timer_name); - wait->m_timer_state= TIMER_STATE_STARTED; + if (state->m_flags & STATE_FLAG_EVENT) + { + PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait); + DBUG_ASSERT(wait != NULL); + + wait->m_timer_end= timer_end; + wait->m_end_event_id= thread->m_event_id; + if (flag_events_waits_history) + insert_events_waits_history(thread, wait); + if (flag_events_waits_history_long) + insert_events_waits_history_long(wait); + thread->m_events_waits_current--; + } } - wait->m_source_file= src_file; - wait->m_source_line= src_line; } +/** + Implementation of the cond instrumentation interface. + @sa PSI_v1::end_cond_wait. +*/ static void end_cond_wait_v1(PSI_cond_locker* locker, int rc) { - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); - PFS_events_waits *wait= &pfs_locker->m_waits_current; + PSI_cond_locker_state *state= reinterpret_cast<PSI_cond_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + ulonglong timer_end= 0; + ulonglong wait_time= 0; - if (wait->m_timer_state == TIMER_STATE_STARTED) + PFS_cond *cond= reinterpret_cast<PFS_cond *> (state->m_cond); + /* PFS_mutex *mutex= reinterpret_cast<PFS_mutex *> (state->m_mutex); */ + + if (state->m_flags & STATE_FLAG_TIMED) + { + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */ + cond->m_wait_stat.aggregate_value(wait_time); + } + else { - wait->m_timer_end= get_timer_value(pfs_locker->m_timer_name); - wait->m_timer_state= TIMER_STATE_TIMED; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */ + cond->m_wait_stat.aggregate_counted(); } - if (flag_events_waits_history) - insert_events_waits_history(wait->m_thread, wait); - if (flag_events_waits_history_long) - insert_events_waits_history_long(wait); - if (rc == 0) + if (state->m_flags & STATE_FLAG_THREAD) { - /* - Not thread safe, race conditions will occur. - A first race condition is: - - thread 1 waits on cond A - - thread 2 waits on cond B - threads 1 and 2 compete when updating the same cond A - statistics, possibly missing a min / max / sum / count. - A second race condition is: - - thread 1 waits on cond A - - thread 2 destroys cond A - - thread 2 or 3 creates cond B in the same condition slot - thread 1 will then aggregate statistics about defunct A - in condition B. - This is accepted, the data will be slightly inaccurate. - */ - PFS_cond *cond= pfs_locker->m_target.m_cond; - PFS_single_stat_chain *stat= find_per_thread_cond_class_wait_stat(wait->m_thread, cond->m_class); + PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread); + DBUG_ASSERT(thread != NULL); - /* If timed then aggregate stats, else increment the value counts only */ - if (wait->m_timer_state == TIMER_STATE_TIMED) + PFS_single_stat *event_name_array; + event_name_array= thread->m_instr_class_waits_stats; + uint index= cond->m_class->m_event_name_index; + + if (state->m_flags & STATE_FLAG_TIMED) { - ulonglong wait_time= wait->m_timer_end - wait->m_timer_start; - aggregate_single_stat_chain(&cond->m_wait_stat, wait_time); - aggregate_single_stat_chain(stat, wait_time); + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */ + event_name_array[index].aggregate_value(wait_time); } else { - increment_single_stat_chain(&cond->m_wait_stat); - increment_single_stat_chain(stat); + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */ + event_name_array[index].aggregate_counted(); + } + + if (state->m_flags & STATE_FLAG_EVENT) + { + PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait); + DBUG_ASSERT(wait != NULL); + + wait->m_timer_end= timer_end; + wait->m_end_event_id= thread->m_event_id; + if (flag_events_waits_history) + insert_events_waits_history(thread, wait); + if (flag_events_waits_history_long) + insert_events_waits_history_long(wait); + thread->m_events_waits_current--; } } - wait->m_thread->m_wait_locker_count--; } -static void start_table_wait_v1(PSI_table_locker* locker, - const char *src_file, uint src_line) +/** + Implementation of the table instrumentation interface. + @sa PSI_v1::end_table_io_wait. +*/ +static void end_table_io_wait_v1(PSI_table_locker* locker) { - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); + PSI_table_locker_state *state= reinterpret_cast<PSI_table_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + ulonglong timer_end= 0; + ulonglong wait_time= 0; + + PFS_table *table= reinterpret_cast<PFS_table *> (state->m_table); + DBUG_ASSERT(table != NULL); + + PFS_single_stat *stat; - PFS_events_waits *wait= &pfs_locker->m_waits_current; - if (wait->m_timer_state == TIMER_STATE_STARTING) + DBUG_ASSERT((state->m_index < table->m_share->m_key_count) || + (state->m_index == MAX_KEY)); + + switch (state->m_io_operation) { - wait->m_timer_start= get_timer_value(pfs_locker->m_timer_name); - wait->m_timer_state= TIMER_STATE_STARTED; + case PSI_TABLE_FETCH_ROW: + stat= & table->m_table_stat.m_index_stat[state->m_index].m_fetch; + break; + case PSI_TABLE_WRITE_ROW: + stat= & table->m_table_stat.m_index_stat[state->m_index].m_insert; + break; + case PSI_TABLE_UPDATE_ROW: + stat= & table->m_table_stat.m_index_stat[state->m_index].m_update; + break; + case PSI_TABLE_DELETE_ROW: + stat= & table->m_table_stat.m_index_stat[state->m_index].m_delete; + break; + default: + DBUG_ASSERT(false); + stat= NULL; + break; } - wait->m_source_file= src_file; - wait->m_source_line= src_line; - wait->m_operation= OPERATION_TYPE_LOCK; - PFS_table_share *share= pfs_locker->m_target.m_table->m_share; - wait->m_schema_name= share->m_schema_name; - wait->m_schema_name_length= share->m_schema_name_length; - wait->m_object_name= share->m_table_name; - wait->m_object_name_length= share->m_table_name_length; -} -static void end_table_wait_v1(PSI_table_locker* locker) -{ - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); - PFS_events_waits *wait= &pfs_locker->m_waits_current; + register uint flags= state->m_flags; + + if (flags & STATE_FLAG_TIMED) + { + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; + stat->aggregate_value(wait_time); + } + else + { + stat->aggregate_counted(); + } - if (wait->m_timer_state == TIMER_STATE_STARTED) + if (flags & STATE_FLAG_EVENT) { - wait->m_timer_end= get_timer_value(pfs_locker->m_timer_name); - wait->m_timer_state= TIMER_STATE_TIMED; + DBUG_ASSERT(flags & STATE_FLAG_THREAD); + PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread); + DBUG_ASSERT(thread != NULL); + + PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait); + DBUG_ASSERT(wait != NULL); + + wait->m_timer_end= timer_end; + wait->m_end_event_id= thread->m_event_id; + if (flag_events_waits_history) + insert_events_waits_history(thread, wait); + if (flag_events_waits_history_long) + insert_events_waits_history_long(wait); + thread->m_events_waits_current--; } - if (flag_events_waits_history) - insert_events_waits_history(wait->m_thread, wait); - if (flag_events_waits_history_long) - insert_events_waits_history_long(wait); - PFS_table *table= pfs_locker->m_target.m_table; + table->m_has_io_stats= true; +} + +/** + Implementation of the table instrumentation interface. + @sa PSI_v1::end_table_lock_wait. +*/ +static void end_table_lock_wait_v1(PSI_table_locker* locker) +{ + PSI_table_locker_state *state= reinterpret_cast<PSI_table_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + ulonglong timer_end= 0; + ulonglong wait_time= 0; + + PFS_table *table= reinterpret_cast<PFS_table *> (state->m_table); + DBUG_ASSERT(table != NULL); - /* If timed then aggregate stats, else increment the value counts only */ - if (wait->m_timer_state == TIMER_STATE_TIMED) + PFS_single_stat *stat= & table->m_table_stat.m_lock_stat.m_stat[state->m_index]; + + register uint flags= state->m_flags; + + if (flags & STATE_FLAG_TIMED) { - ulonglong wait_time= wait->m_timer_end - wait->m_timer_start; - aggregate_single_stat_chain(&table->m_wait_stat, wait_time); + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; + stat->aggregate_value(wait_time); } else { - increment_single_stat_chain(&table->m_wait_stat); + stat->aggregate_counted(); } - /* - There is currently no per table and per thread aggregation. - The number of tables in the application is arbitrary, and may be high. - The number of slots per thread to hold aggregates is fixed, - and is constrained by memory. - Implementing a per thread and per table aggregate has not been - decided yet. - If it's implemented, it's likely that the user will have to specify, - per table name, if the aggregate per thread is to be computed or not. - This will mean a SETUP_ table. - */ - wait->m_thread->m_wait_locker_count--; + if (flags & STATE_FLAG_EVENT) + { + DBUG_ASSERT(flags & STATE_FLAG_THREAD); + PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread); + DBUG_ASSERT(thread != NULL); + + PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait); + DBUG_ASSERT(wait != NULL); + + wait->m_timer_end= timer_end; + wait->m_end_event_id= thread->m_event_id; + if (flag_events_waits_history) + insert_events_waits_history(thread, wait); + if (flag_events_waits_history_long) + insert_events_waits_history_long(wait); + thread->m_events_waits_current--; + } + + table->m_has_lock_stats= true; } static void start_file_wait_v1(PSI_file_locker *locker, @@ -1917,34 +3799,45 @@ static void start_file_wait_v1(PSI_file_locker *locker, static void end_file_wait_v1(PSI_file_locker *locker, size_t count); +/** + Implementation of the file instrumentation interface. + @sa PSI_v1::start_file_open_wait. +*/ static PSI_file* start_file_open_wait_v1(PSI_file_locker *locker, const char *src_file, uint src_line) { - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); + PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker); + DBUG_ASSERT(state != NULL); start_file_wait_v1(locker, 0, src_file, src_line); - PFS_file *pfs_file= pfs_locker->m_target.m_file; - return reinterpret_cast<PSI_file*> (pfs_file); + return state->m_file; } +/** + Implementation of the file instrumentation interface. + @sa PSI_v1::end_file_open_wait. +*/ static void end_file_open_wait_v1(PSI_file_locker *locker) { end_file_wait_v1(locker, 0); } +/** + Implementation of the file instrumentation interface. + @sa PSI_v1::end_file_open_wait_and_bind_to_descriptor. +*/ static void end_file_open_wait_and_bind_to_descriptor_v1 (PSI_file_locker *locker, File file) { int index= (int) file; - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); + PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker); + DBUG_ASSERT(state != NULL); end_file_wait_v1(locker, 0); - PFS_file *pfs_file= pfs_locker->m_target.m_file; + PFS_file *pfs_file= reinterpret_cast<PFS_file*> (state->m_file); DBUG_ASSERT(pfs_file != NULL); if (likely(index >= 0)) @@ -1955,93 +3848,1031 @@ static void end_file_open_wait_and_bind_to_descriptor_v1 file_handle_lost++; } else + { release_file(pfs_file); + } } +/** + Implementation of the file instrumentation interface. + @sa PSI_v1::start_file_wait. +*/ static void start_file_wait_v1(PSI_file_locker *locker, size_t count, const char *src_file, uint src_line) { - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); + ulonglong timer_start= 0; + PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + register uint flags= state->m_flags; - PFS_events_waits *wait= &pfs_locker->m_waits_current; - if (wait->m_timer_state == TIMER_STATE_STARTING) + if (flags & STATE_FLAG_TIMED) { - wait->m_timer_start= get_timer_value(pfs_locker->m_timer_name); - wait->m_timer_state= TIMER_STATE_STARTED; + timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer); + state->m_timer_start= timer_start; + } + + if (flags & STATE_FLAG_EVENT) + { + PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait); + DBUG_ASSERT(wait != NULL); + + wait->m_timer_start= timer_start; + wait->m_source_file= src_file; + wait->m_source_line= src_line; + wait->m_number_of_bytes= count; } - wait->m_source_file= src_file; - wait->m_source_line= src_line; - wait->m_number_of_bytes= count; } +/** + Implementation of the file instrumentation interface. + @sa PSI_v1::end_file_wait. +*/ static void end_file_wait_v1(PSI_file_locker *locker, - size_t count) + size_t byte_count) { - PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker); - DBUG_ASSERT(pfs_locker != NULL); - PFS_events_waits *wait= &pfs_locker->m_waits_current; - - wait->m_number_of_bytes= count; - if (wait->m_timer_state == TIMER_STATE_STARTED) + PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + PFS_file *file= reinterpret_cast<PFS_file *> (state->m_file); + DBUG_ASSERT(file != NULL); + PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread); + + ulonglong timer_end= 0; + ulonglong wait_time= 0; + PFS_byte_stat *byte_stat; + register uint flags= state->m_flags; + size_t bytes= ((int)byte_count > -1 ? byte_count : 0); + + switch (state->m_operation) { - wait->m_timer_end= get_timer_value(pfs_locker->m_timer_name); - wait->m_timer_state= TIMER_STATE_TIMED; + /* Group read operations */ + case PSI_FILE_READ: + byte_stat= &file->m_file_stat.m_io_stat.m_read; + break; + /* Group write operations */ + case PSI_FILE_WRITE: + byte_stat= &file->m_file_stat.m_io_stat.m_write; + break; + /* Group remaining operations as miscellaneous */ + case PSI_FILE_CREATE: + case PSI_FILE_CREATE_TMP: + case PSI_FILE_OPEN: + case PSI_FILE_STREAM_OPEN: + case PSI_FILE_STREAM_CLOSE: + case PSI_FILE_SEEK: + case PSI_FILE_TELL: + case PSI_FILE_FLUSH: + case PSI_FILE_FSTAT: + case PSI_FILE_CHSIZE: + case PSI_FILE_DELETE: + case PSI_FILE_RENAME: + case PSI_FILE_SYNC: + case PSI_FILE_STAT: + case PSI_FILE_CLOSE: + byte_stat= &file->m_file_stat.m_io_stat.m_misc; + break; + default: + DBUG_ASSERT(false); + byte_stat= NULL; + break; } - if (flag_events_waits_history) - insert_events_waits_history(wait->m_thread, wait); - if (flag_events_waits_history_long) - insert_events_waits_history_long(wait); - PFS_file *file= pfs_locker->m_target.m_file; - PFS_single_stat_chain *stat= find_per_thread_file_class_wait_stat(wait->m_thread, file->m_class); - - /* If timed then aggregate stats, else increment the value counts only */ - if (wait->m_timer_state == TIMER_STATE_TIMED) + /* Aggregation for EVENTS_WAITS_SUMMARY_BY_INSTANCE */ + if (flags & STATE_FLAG_TIMED) { - ulonglong wait_time= wait->m_timer_end - wait->m_timer_start; - aggregate_single_stat_chain(&file->m_wait_stat, wait_time); - aggregate_single_stat_chain(stat, wait_time); + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */ + byte_stat->aggregate(wait_time, bytes); } else { - increment_single_stat_chain(&file->m_wait_stat); - increment_single_stat_chain(stat); + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */ + byte_stat->aggregate_counted(bytes); } - PFS_file_class *klass= file->m_class; + if (flags & STATE_FLAG_THREAD) + { + DBUG_ASSERT(thread != NULL); + + PFS_single_stat *event_name_array; + event_name_array= thread->m_instr_class_waits_stats; + uint index= file->m_class->m_event_name_index; + + if (flags & STATE_FLAG_TIMED) + { + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */ + event_name_array[index].aggregate_value(wait_time); + } + else + { + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */ + event_name_array[index].aggregate_counted(); + } + + if (state->m_flags & STATE_FLAG_EVENT) + { + PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait); + DBUG_ASSERT(wait != NULL); + + wait->m_timer_end= timer_end; + wait->m_number_of_bytes= bytes; + wait->m_end_event_id= thread->m_event_id; + + if (flag_events_waits_history) + insert_events_waits_history(thread, wait); + if (flag_events_waits_history_long) + insert_events_waits_history_long(wait); + thread->m_events_waits_current--; + } + } - switch(wait->m_operation) + /* Release or destroy the file if necessary */ + switch(state->m_operation) { - case OPERATION_TYPE_FILEREAD: - file->m_file_stat.m_count_read++; - file->m_file_stat.m_read_bytes+= count; - klass->m_file_stat.m_count_read++; - klass->m_file_stat.m_read_bytes+= count; - break; - case OPERATION_TYPE_FILEWRITE: - file->m_file_stat.m_count_write++; - file->m_file_stat.m_write_bytes+= count; - klass->m_file_stat.m_count_write++; - klass->m_file_stat.m_write_bytes+= count; + case PSI_FILE_CLOSE: + case PSI_FILE_STREAM_CLOSE: + case PSI_FILE_STAT: + release_file(file); break; - case OPERATION_TYPE_FILECLOSE: - case OPERATION_TYPE_FILESTREAMCLOSE: - case OPERATION_TYPE_FILESTAT: - release_file(pfs_locker->m_target.m_file); - break; - case OPERATION_TYPE_FILEDELETE: - destroy_file(wait->m_thread, pfs_locker->m_target.m_file); + case PSI_FILE_DELETE: + DBUG_ASSERT(thread != NULL); + destroy_file(thread, file); break; default: break; } +} + +static void start_stage_v1(PSI_stage_key key, const char *src_file, int src_line) +{ + ulonglong timer_value= 0; + + if (! flag_global_instrumentation) + return; - wait->m_thread->m_wait_locker_count--; + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(pfs_thread == NULL)) + return; + + if (flag_thread_instrumentation && ! pfs_thread->m_enabled) + return; + + PFS_events_stages *pfs= & pfs_thread->m_stage_current; + PFS_events_waits *child_wait= & pfs_thread->m_events_waits_stack[0]; + PFS_events_statements *parent_statement= & pfs_thread->m_statement_stack[0]; + + PFS_instr_class *old_class= pfs->m_class; + if (likely(old_class != NULL)) + { + PFS_stage_stat *event_name_array; + event_name_array= pfs_thread->m_instr_class_stages_stats; + uint index= old_class->m_event_name_index; + + /* Finish old event */ + if (old_class->m_timed) + { + timer_value= get_timer_raw_value(stage_timer);; + pfs->m_timer_end= timer_value; + + /* Aggregate to EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */ + ulonglong stage_time= timer_value - pfs->m_timer_start; + event_name_array[index].aggregate_value(stage_time); + } + else + { + /* Aggregate to EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */ + event_name_array[index].aggregate_counted(); + } + + if (flag_events_stages_current) + { + pfs->m_end_event_id= pfs_thread->m_event_id; + if (flag_events_stages_history) + insert_events_stages_history(pfs_thread, pfs); + if (flag_events_stages_history_long) + insert_events_stages_history_long(pfs); + } + + /* This stage event is now complete. */ + pfs->m_class= NULL; + + /* New waits will now be attached directly to the parent statement. */ + child_wait->m_event_id= parent_statement->m_event_id; + child_wait->m_event_type= parent_statement->m_event_type; + /* See below for new stages, that may overwrite this. */ + } + + /* Start new event */ + + PFS_stage_class *new_klass= find_stage_class(key); + if (unlikely(new_klass == NULL)) + return; + + if (! new_klass->m_enabled) + return; + + pfs->m_class= new_klass; + if (new_klass->m_timed) + { + /* + Do not call the timer again if we have a + TIMER_END for the previous stage already. + */ + if (timer_value == 0) + timer_value= get_timer_raw_value(stage_timer); + pfs->m_timer_start= timer_value; + } + else + pfs->m_timer_start= 0; + pfs->m_timer_end= 0; + + if (flag_events_stages_current) + { + /* m_thread_internal_id is immutable and already set */ + DBUG_ASSERT(pfs->m_thread_internal_id == pfs_thread->m_thread_internal_id); + pfs->m_event_id= pfs_thread->m_event_id++; + pfs->m_end_event_id= 0; + pfs->m_source_file= src_file; + pfs->m_source_line= src_line; + + /* New wait events will have this new stage as parent. */ + child_wait->m_event_id= pfs->m_event_id; + child_wait->m_event_type= EVENT_TYPE_STAGE; + } +} + +static void end_stage_v1() +{ + ulonglong timer_value= 0; + + if (! flag_global_instrumentation) + return; + + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(pfs_thread == NULL)) + return; + + if (flag_thread_instrumentation && ! pfs_thread->m_enabled) + return; + + PFS_events_stages *pfs= & pfs_thread->m_stage_current; + + PFS_instr_class *old_class= pfs->m_class; + if (likely(old_class != NULL)) + { + PFS_stage_stat *event_name_array; + event_name_array= pfs_thread->m_instr_class_stages_stats; + uint index= old_class->m_event_name_index; + + /* Finish old event */ + if (old_class->m_timed) + { + timer_value= get_timer_raw_value(stage_timer);; + pfs->m_timer_end= timer_value; + + /* Aggregate to EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */ + ulonglong stage_time= timer_value - pfs->m_timer_start; + event_name_array[index].aggregate_value(stage_time); + } + else + { + /* Aggregate to EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */ + event_name_array[index].aggregate_counted(); + } + + if (flag_events_stages_current) + { + pfs->m_end_event_id= pfs_thread->m_event_id; + if (flag_events_stages_history) + insert_events_stages_history(pfs_thread, pfs); + if (flag_events_stages_history_long) + insert_events_stages_history_long(pfs); + } + + /* New waits will now be attached directly to the parent statement. */ + PFS_events_waits *child_wait= & pfs_thread->m_events_waits_stack[0]; + PFS_events_statements *parent_statement= & pfs_thread->m_statement_stack[0]; + child_wait->m_event_id= parent_statement->m_event_id; + child_wait->m_event_type= parent_statement->m_event_type; + + /* This stage is completed */ + pfs->m_class= NULL; + } +} + +static PSI_statement_locker* +get_thread_statement_locker_v1(PSI_statement_locker_state *state, + PSI_statement_key key) +{ + DBUG_ASSERT(state != NULL); + if (! flag_global_instrumentation) + return NULL; + PFS_statement_class *klass= find_statement_class(key); + if (unlikely(klass == NULL)) + return NULL; + if (! klass->m_enabled) + return NULL; + + register uint flags; + + if (flag_thread_instrumentation) + { + PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (unlikely(pfs_thread == NULL)) + return NULL; + if (! pfs_thread->m_enabled) + return NULL; + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + flags= STATE_FLAG_THREAD; + + if (klass->m_timed) + flags|= STATE_FLAG_TIMED; + + if (flag_events_statements_current) + { + ulonglong event_id= pfs_thread->m_event_id++; + + if (pfs_thread->m_events_statements_count >= statement_stack_max) + { + return NULL; + } + + PFS_events_statements *pfs= & pfs_thread->m_statement_stack[pfs_thread->m_events_statements_count]; + /* m_thread_internal_id is immutable and already set */ + DBUG_ASSERT(pfs->m_thread_internal_id == pfs_thread->m_thread_internal_id); + pfs->m_event_id= event_id; + pfs->m_end_event_id= 0; + pfs->m_class= klass; + pfs->m_timer_start= 0; + pfs->m_timer_end= 0; + pfs->m_lock_time= 0; + pfs->m_current_schema_name_length= 0; + pfs->m_sqltext_length= 0; + + pfs->m_message_text[0]= '\0'; + pfs->m_sql_errno= 0; + pfs->m_sqlstate[0]= '\0'; + pfs->m_error_count= 0; + pfs->m_warning_count= 0; + pfs->m_rows_affected= 0; + + pfs->m_rows_sent= 0; + pfs->m_rows_examined= 0; + pfs->m_created_tmp_disk_tables= 0; + pfs->m_created_tmp_tables= 0; + pfs->m_select_full_join= 0; + pfs->m_select_full_range_join= 0; + pfs->m_select_range= 0; + pfs->m_select_range_check= 0; + pfs->m_select_scan= 0; + pfs->m_sort_merge_passes= 0; + pfs->m_sort_range= 0; + pfs->m_sort_rows= 0; + pfs->m_sort_scan= 0; + pfs->m_no_index_used= 0; + pfs->m_no_good_index_used= 0; + digest_reset(& pfs->m_digest_storage); + + /* New stages will have this statement as parent */ + PFS_events_stages *child_stage= & pfs_thread->m_stage_current; + child_stage->m_nesting_event_id= event_id; + child_stage->m_nesting_event_type= EVENT_TYPE_STATEMENT; + + /* New waits will have this statement as parent, if no stage is instrumented */ + PFS_events_waits *child_wait= & pfs_thread->m_events_waits_stack[0]; + child_wait->m_nesting_event_id= event_id; + child_wait->m_nesting_event_type= EVENT_TYPE_STATEMENT; + + state->m_statement= pfs; + flags|= STATE_FLAG_EVENT; + + pfs_thread->m_events_statements_count++; + } + } + else + { + if (klass->m_timed) + flags= STATE_FLAG_TIMED; + else + flags= 0; + } + + if (flag_statements_digest) + { + flags|= STATE_FLAG_DIGEST; + state->m_digest_state.m_last_id_index= 0; + digest_reset(& state->m_digest_state.m_digest_storage); + } + + state->m_discarded= false; + state->m_class= klass; + state->m_flags= flags; + + state->m_lock_time= 0; + state->m_rows_sent= 0; + state->m_rows_examined= 0; + state->m_created_tmp_disk_tables= 0; + state->m_created_tmp_tables= 0; + state->m_select_full_join= 0; + state->m_select_full_range_join= 0; + state->m_select_range= 0; + state->m_select_range_check= 0; + state->m_select_scan= 0; + state->m_sort_merge_passes= 0; + state->m_sort_range= 0; + state->m_sort_rows= 0; + state->m_sort_scan= 0; + state->m_no_index_used= 0; + state->m_no_good_index_used= 0; + + return reinterpret_cast<PSI_statement_locker*> (state); +} + +static PSI_statement_locker* +refine_statement_v1(PSI_statement_locker *locker, + PSI_statement_key key) +{ + PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker); + if (state == NULL) + return NULL; + DBUG_ASSERT(state->m_class != NULL); + PFS_statement_class *klass; + /* Only refine statements for mutable instrumentation */ + klass= reinterpret_cast<PFS_statement_class*> (state->m_class); + DBUG_ASSERT(klass->m_flags & PSI_FLAG_MUTABLE); + klass= find_statement_class(key); + if (unlikely(klass == NULL)) + { + /* FIXME : pop statement stack */ + state->m_discarded= true; + return NULL; + } + if (! klass->m_enabled) + { + /* FIXME : pop statement stack */ + state->m_discarded= true; + return NULL; + } + + register uint flags= state->m_flags; + + if ((flags & STATE_FLAG_TIMED) && ! klass->m_timed) + flags= flags & ~STATE_FLAG_TIMED; + + if (flags & STATE_FLAG_EVENT) + { + PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement); + DBUG_ASSERT(pfs != NULL); + + /* mutate EVENTS_STATEMENTS_CURRENT.EVENT_NAME */ + pfs->m_class= klass; + } + + state->m_class= klass; + state->m_flags= flags; + return reinterpret_cast<PSI_statement_locker*> (state); +} + +static void start_statement_v1(PSI_statement_locker *locker, + const char *db, uint db_len, + const char *src_file, uint src_line) +{ + PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + register uint flags= state->m_flags; + ulonglong timer_start= 0; + + if (flags & STATE_FLAG_TIMED) + { + timer_start= get_timer_raw_value_and_function(statement_timer, & state->m_timer); + state->m_timer_start= timer_start; + } + + if (flags & STATE_FLAG_EVENT) + { + PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement); + DBUG_ASSERT(pfs != NULL); + + pfs->m_timer_start= timer_start; + pfs->m_source_file= src_file; + pfs->m_source_line= src_line; + + DBUG_ASSERT(db_len <= sizeof(pfs->m_current_schema_name)); + if (db_len > 0) + memcpy(pfs->m_current_schema_name, db, db_len); + pfs->m_current_schema_name_length= db_len; + } +} + +static void set_statement_text_v1(PSI_statement_locker *locker, + const char *text, uint text_len) +{ + PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + if (state->m_discarded) + return; + + if (state->m_flags & STATE_FLAG_EVENT) + { + PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement); + DBUG_ASSERT(pfs != NULL); + if (text_len > sizeof (pfs->m_sqltext)) + text_len= sizeof(pfs->m_sqltext); + if (text_len) + memcpy(pfs->m_sqltext, text, text_len); + pfs->m_sqltext_length= text_len; + } + + return; +} + +#define SET_STATEMENT_ATTR_BODY(LOCKER, ATTR, VALUE) \ + PSI_statement_locker_state *state; \ + state= reinterpret_cast<PSI_statement_locker_state*> (LOCKER); \ + if (unlikely(state == NULL)) \ + return; \ + if (state->m_discarded) \ + return; \ + state->ATTR= VALUE; \ + if (state->m_flags & STATE_FLAG_EVENT) \ + { \ + PFS_events_statements *pfs; \ + pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement); \ + DBUG_ASSERT(pfs != NULL); \ + pfs->ATTR= VALUE; \ + } \ + return; + +#define INC_STATEMENT_ATTR_BODY(LOCKER, ATTR, VALUE) \ + PSI_statement_locker_state *state; \ + state= reinterpret_cast<PSI_statement_locker_state*> (LOCKER); \ + if (unlikely(state == NULL)) \ + return; \ + if (state->m_discarded) \ + return; \ + state->ATTR+= VALUE; \ + if (state->m_flags & STATE_FLAG_EVENT) \ + { \ + PFS_events_statements *pfs; \ + pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement); \ + DBUG_ASSERT(pfs != NULL); \ + pfs->ATTR+= VALUE; \ + } \ + return; + +static void set_statement_lock_time_v1(PSI_statement_locker *locker, + ulonglong count) +{ + SET_STATEMENT_ATTR_BODY(locker, m_lock_time, count); +} + +static void set_statement_rows_sent_v1(PSI_statement_locker *locker, + ulonglong count) +{ + SET_STATEMENT_ATTR_BODY(locker, m_rows_sent, count); +} + +static void set_statement_rows_examined_v1(PSI_statement_locker *locker, + ulonglong count) +{ + SET_STATEMENT_ATTR_BODY(locker, m_rows_examined, count); +} + +static void inc_statement_created_tmp_disk_tables_v1(PSI_statement_locker *locker, + ulong count) +{ + INC_STATEMENT_ATTR_BODY(locker, m_created_tmp_disk_tables, count); +} + +static void inc_statement_created_tmp_tables_v1(PSI_statement_locker *locker, + ulong count) +{ + INC_STATEMENT_ATTR_BODY(locker, m_created_tmp_tables, count); } +static void inc_statement_select_full_join_v1(PSI_statement_locker *locker, + ulong count) +{ + INC_STATEMENT_ATTR_BODY(locker, m_select_full_join, count); +} + +static void inc_statement_select_full_range_join_v1(PSI_statement_locker *locker, + ulong count) +{ + INC_STATEMENT_ATTR_BODY(locker, m_select_full_range_join, count); +} + +static void inc_statement_select_range_v1(PSI_statement_locker *locker, + ulong count) +{ + INC_STATEMENT_ATTR_BODY(locker, m_select_range, count); +} + +static void inc_statement_select_range_check_v1(PSI_statement_locker *locker, + ulong count) +{ + INC_STATEMENT_ATTR_BODY(locker, m_select_range_check, count); +} + +static void inc_statement_select_scan_v1(PSI_statement_locker *locker, + ulong count) +{ + INC_STATEMENT_ATTR_BODY(locker, m_select_scan, count); +} + +static void inc_statement_sort_merge_passes_v1(PSI_statement_locker *locker, + ulong count) +{ + INC_STATEMENT_ATTR_BODY(locker, m_sort_merge_passes, count); +} + +static void inc_statement_sort_range_v1(PSI_statement_locker *locker, + ulong count) +{ + INC_STATEMENT_ATTR_BODY(locker, m_sort_range, count); +} + +static void inc_statement_sort_rows_v1(PSI_statement_locker *locker, + ulong count) +{ + INC_STATEMENT_ATTR_BODY(locker, m_sort_rows, count); +} + +static void inc_statement_sort_scan_v1(PSI_statement_locker *locker, + ulong count) +{ + INC_STATEMENT_ATTR_BODY(locker, m_sort_scan, count); +} + +static void set_statement_no_index_used_v1(PSI_statement_locker *locker) +{ + SET_STATEMENT_ATTR_BODY(locker, m_no_index_used, 1); +} + +static void set_statement_no_good_index_used_v1(PSI_statement_locker *locker) +{ + SET_STATEMENT_ATTR_BODY(locker, m_no_good_index_used, 1); +} + +static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) +{ + PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker); + Diagnostics_area *da= reinterpret_cast<Diagnostics_area*> (stmt_da); + DBUG_ASSERT(state != NULL); + DBUG_ASSERT(da != NULL); + + if (state->m_discarded) + return; + + PFS_statement_class *klass= reinterpret_cast<PFS_statement_class *> (state->m_class); + DBUG_ASSERT(klass != NULL); + + ulonglong timer_end= 0; + ulonglong wait_time= 0; + register uint flags= state->m_flags; + + if (flags & STATE_FLAG_TIMED) + { + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; + } + + PFS_statement_stat *event_name_array; + uint index= klass->m_event_name_index; + PFS_statement_stat *stat; + + /* + Capture statement stats by digest. + */ + PSI_digest_storage *digest_storage= NULL; + PFS_statement_stat *digest_stat= NULL; + + if (flags & STATE_FLAG_THREAD) + { + PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread); + DBUG_ASSERT(thread != NULL); + event_name_array= thread->m_instr_class_statements_stats; + /* Aggregate to EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME */ + stat= & event_name_array[index]; + + if (flags & STATE_FLAG_DIGEST) + { + digest_storage= &state->m_digest_state.m_digest_storage; + + /* + Populate PFS_statements_digest_stat with computed digest information. + */ + digest_stat= find_or_create_digest(thread, digest_storage); + } + + if (flags & STATE_FLAG_EVENT) + { + PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement); + DBUG_ASSERT(pfs != NULL); + + switch(da->status()) + { + case Diagnostics_area::DA_EMPTY: + break; + case Diagnostics_area::DA_OK: + memcpy(pfs->m_message_text, da->message(), MYSQL_ERRMSG_SIZE); + pfs->m_message_text[MYSQL_ERRMSG_SIZE]= 0; + pfs->m_rows_affected= da->affected_rows(); + pfs->m_warning_count= da->statement_warn_count(); + memcpy(pfs->m_sqlstate, "00000", SQLSTATE_LENGTH); + break; + case Diagnostics_area::DA_EOF: + pfs->m_warning_count= da->statement_warn_count(); + break; + case Diagnostics_area::DA_ERROR: + memcpy(pfs->m_message_text, da->message(), MYSQL_ERRMSG_SIZE); + pfs->m_message_text[MYSQL_ERRMSG_SIZE]= 0; + pfs->m_sql_errno= da->sql_errno(); + memcpy(pfs->m_sqlstate, da->get_sqlstate(), SQLSTATE_LENGTH); + break; + case Diagnostics_area::DA_DISABLED: + break; + } + + pfs->m_timer_end= timer_end; + pfs->m_end_event_id= thread->m_event_id; + + if (flags & STATE_FLAG_DIGEST) + { + /* + The following columns in events_statement_current: + - DIGEST, + - DIGEST_TEXT + are computed from the digest storage. + */ + digest_copy(& pfs->m_digest_storage, digest_storage); + } + + if (flag_events_statements_history) + insert_events_statements_history(thread, pfs); + if (flag_events_statements_history_long) + insert_events_statements_history_long(pfs); + + DBUG_ASSERT(thread->m_events_statements_count > 0); + thread->m_events_statements_count--; + } + } + else + { + if (flags & STATE_FLAG_DIGEST) + { + PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + + /* An instrumented thread is required, for LF_PINS. */ + if (thread != NULL) + { + /* Set digest stat. */ + digest_storage= &state->m_digest_state.m_digest_storage; + + /* + Populate PFS_statements_digest_stat with computed digest information. + */ + digest_stat= find_or_create_digest(thread, digest_storage); + } + } + + event_name_array= global_instr_class_statements_array; + /* Aggregate to EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME */ + stat= & event_name_array[index]; + } + + if (flags & STATE_FLAG_TIMED) + { + /* Aggregate to EVENTS_STATEMENTS_SUMMARY_..._BY_EVENT_NAME (timed) */ + stat->aggregate_value(wait_time); + } + else + { + /* Aggregate to EVENTS_STATEMENTS_SUMMARY_..._BY_EVENT_NAME (counted) */ + stat->aggregate_counted(); + } + + stat->m_lock_time+= state->m_lock_time; + stat->m_rows_sent+= state->m_rows_sent; + stat->m_rows_examined+= state->m_rows_examined; + stat->m_created_tmp_disk_tables+= state->m_created_tmp_disk_tables; + stat->m_created_tmp_tables+= state->m_created_tmp_tables; + stat->m_select_full_join+= state->m_select_full_join; + stat->m_select_full_range_join+= state->m_select_full_range_join; + stat->m_select_range+= state->m_select_range; + stat->m_select_range_check+= state->m_select_range_check; + stat->m_select_scan+= state->m_select_scan; + stat->m_sort_merge_passes+= state->m_sort_merge_passes; + stat->m_sort_range+= state->m_sort_range; + stat->m_sort_rows+= state->m_sort_rows; + stat->m_sort_scan+= state->m_sort_scan; + stat->m_no_index_used+= state->m_no_index_used; + stat->m_no_good_index_used+= state->m_no_good_index_used; + + if (digest_stat != NULL) + { + if (flags & STATE_FLAG_TIMED) + { + digest_stat->aggregate_value(wait_time); + } + else + { + digest_stat->aggregate_counted(); + } + + digest_stat->m_lock_time+= state->m_lock_time; + digest_stat->m_rows_sent+= state->m_rows_sent; + digest_stat->m_rows_examined+= state->m_rows_examined; + digest_stat->m_created_tmp_disk_tables+= state->m_created_tmp_disk_tables; + digest_stat->m_created_tmp_tables+= state->m_created_tmp_tables; + digest_stat->m_select_full_join+= state->m_select_full_join; + digest_stat->m_select_full_range_join+= state->m_select_full_range_join; + digest_stat->m_select_range+= state->m_select_range; + digest_stat->m_select_range_check+= state->m_select_range_check; + digest_stat->m_select_scan+= state->m_select_scan; + digest_stat->m_sort_merge_passes+= state->m_sort_merge_passes; + digest_stat->m_sort_range+= state->m_sort_range; + digest_stat->m_sort_rows+= state->m_sort_rows; + digest_stat->m_sort_scan+= state->m_sort_scan; + digest_stat->m_no_index_used+= state->m_no_index_used; + digest_stat->m_no_good_index_used+= state->m_no_good_index_used; + } + + switch (da->status()) + { + case Diagnostics_area::DA_EMPTY: + break; + case Diagnostics_area::DA_OK: + stat->m_rows_affected+= da->affected_rows(); + stat->m_warning_count+= da->statement_warn_count(); + if (digest_stat != NULL) + { + digest_stat->m_rows_affected+= da->affected_rows(); + digest_stat->m_warning_count+= da->statement_warn_count(); + } + break; + case Diagnostics_area::DA_EOF: + stat->m_warning_count+= da->statement_warn_count(); + if (digest_stat != NULL) + { + digest_stat->m_warning_count+= da->statement_warn_count(); + } + break; + case Diagnostics_area::DA_ERROR: + stat->m_error_count++; + if (digest_stat != NULL) + { + digest_stat->m_error_count++; + } + break; + case Diagnostics_area::DA_DISABLED: + break; + } +} + +/** + Implementation of the socket instrumentation interface. + @sa PSI_v1::end_socket_wait. +*/ +static void end_socket_wait_v1(PSI_socket_locker *locker, size_t byte_count) +{ + PSI_socket_locker_state *state= reinterpret_cast<PSI_socket_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + PFS_socket *socket= reinterpret_cast<PFS_socket *>(state->m_socket); + DBUG_ASSERT(socket != NULL); + + ulonglong timer_end= 0; + ulonglong wait_time= 0; + PFS_byte_stat *byte_stat; + register uint flags= state->m_flags; + size_t bytes= ((int)byte_count > -1 ? byte_count : 0); + + switch (state->m_operation) + { + /* Group read operations */ + case PSI_SOCKET_RECV: + case PSI_SOCKET_RECVFROM: + case PSI_SOCKET_RECVMSG: + byte_stat= &socket->m_socket_stat.m_io_stat.m_read; + break; + /* Group write operations */ + case PSI_SOCKET_SEND: + case PSI_SOCKET_SENDTO: + case PSI_SOCKET_SENDMSG: + byte_stat= &socket->m_socket_stat.m_io_stat.m_write; + break; + /* Group remaining operations as miscellaneous */ + case PSI_SOCKET_CONNECT: + case PSI_SOCKET_CREATE: + case PSI_SOCKET_BIND: + case PSI_SOCKET_SEEK: + case PSI_SOCKET_OPT: + case PSI_SOCKET_STAT: + case PSI_SOCKET_SHUTDOWN: + case PSI_SOCKET_SELECT: + case PSI_SOCKET_CLOSE: + byte_stat= &socket->m_socket_stat.m_io_stat.m_misc; + break; + default: + DBUG_ASSERT(false); + byte_stat= NULL; + break; + } + + /* Aggregation for EVENTS_WAITS_SUMMARY_BY_INSTANCE */ + if (flags & STATE_FLAG_TIMED) + { + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; + + /* Aggregate to the socket instrument for now (timed) */ + byte_stat->aggregate(wait_time, bytes); + } + else + { + /* Aggregate to the socket instrument (event count and byte count) */ + byte_stat->aggregate_counted(bytes); + } + + /* Aggregate to EVENTS_WAITS_HISTORY and EVENTS_WAITS_HISTORY_LONG */ + if (flags & STATE_FLAG_EVENT) + { + PFS_thread *thread= reinterpret_cast<PFS_thread *>(state->m_thread); + DBUG_ASSERT(thread != NULL); + PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait); + DBUG_ASSERT(wait != NULL); + + wait->m_timer_end= timer_end; + wait->m_end_event_id= thread->m_event_id; + wait->m_number_of_bytes= bytes; + + if (flag_events_waits_history) + insert_events_waits_history(thread, wait); + if (flag_events_waits_history_long) + insert_events_waits_history_long(wait); + thread->m_events_waits_current--; + } +} + +static void set_socket_state_v1(PSI_socket *socket, PSI_socket_state state) +{ + DBUG_ASSERT((state == PSI_SOCKET_STATE_IDLE) || (state == PSI_SOCKET_STATE_ACTIVE)); + PFS_socket *pfs= reinterpret_cast<PFS_socket*>(socket); + DBUG_ASSERT(pfs != NULL); + DBUG_ASSERT(pfs->m_idle || (state == PSI_SOCKET_STATE_IDLE)); + DBUG_ASSERT(!pfs->m_idle || (state == PSI_SOCKET_STATE_ACTIVE)); + pfs->m_idle= (state == PSI_SOCKET_STATE_IDLE); +} + +/** + Set socket descriptor and address info. +*/ +static void set_socket_info_v1(PSI_socket *socket, + const my_socket *fd, + const struct sockaddr *addr, + socklen_t addr_len) +{ + PFS_socket *pfs= reinterpret_cast<PFS_socket*>(socket); + DBUG_ASSERT(pfs != NULL); + + /** Set socket descriptor */ + if (fd != NULL) + pfs->m_fd= *fd; + + /** Set raw socket address and length */ + if (likely(addr != NULL && addr_len > 0)) + { + pfs->m_addr_len= addr_len; + + /** Restrict address length to size of struct */ + if (unlikely(pfs->m_addr_len > sizeof(sockaddr_storage))) + pfs->m_addr_len= sizeof(struct sockaddr_storage); + + memcpy(&pfs->m_sock_addr, addr, pfs->m_addr_len); + } +} + +/** + Implementation of the socket instrumentation interface. + @sa PSI_v1::set_socket_info. +*/ +static void set_socket_thread_owner_v1(PSI_socket *socket) +{ + PFS_socket *pfs_socket= reinterpret_cast<PFS_socket*>(socket); + DBUG_ASSERT(pfs_socket != NULL); + pfs_socket->m_thread_owner= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); +} + +/** + Implementation of the instrumentation interface. + @sa PSI_v1. +*/ PSI_v1 PFS_v1= { register_mutex_v1, @@ -2049,28 +4880,39 @@ PSI_v1 PFS_v1= register_cond_v1, register_thread_v1, register_file_v1, + register_stage_v1, + register_statement_v1, + register_socket_v1, init_mutex_v1, destroy_mutex_v1, init_rwlock_v1, destroy_rwlock_v1, init_cond_v1, destroy_cond_v1, + init_socket_v1, + destroy_socket_v1, get_table_share_v1, release_table_share_v1, + drop_table_share_v1, open_table_v1, + unbind_table_v1, + rebind_table_v1, close_table_v1, create_file_v1, spawn_thread_v1, new_thread_v1, set_thread_id_v1, get_thread_v1, + set_thread_user_v1, + set_thread_account_v1, + set_thread_db_v1, + set_thread_command_v1, + set_thread_start_time_v1, + set_thread_state_v1, + set_thread_info_v1, set_thread_v1, delete_current_thread_v1, delete_thread_v1, - get_thread_mutex_locker_v1, - get_thread_rwlock_locker_v1, - get_thread_cond_locker_v1, - get_thread_table_locker_v1, get_thread_file_name_locker_v1, get_thread_file_stream_locker_v1, get_thread_file_descriptor_locker_v1, @@ -2078,21 +4920,55 @@ PSI_v1 PFS_v1= unlock_rwlock_v1, signal_cond_v1, broadcast_cond_v1, + start_idle_wait_v1, + end_idle_wait_v1, start_mutex_wait_v1, end_mutex_wait_v1, - start_rwlock_rdwait_v1, + start_rwlock_wait_v1, /* read */ end_rwlock_rdwait_v1, - start_rwlock_wrwait_v1, + start_rwlock_wait_v1, /* write */ end_rwlock_wrwait_v1, start_cond_wait_v1, end_cond_wait_v1, - start_table_wait_v1, - end_table_wait_v1, + start_table_io_wait_v1, + end_table_io_wait_v1, + start_table_lock_wait_v1, + end_table_lock_wait_v1, start_file_open_wait_v1, end_file_open_wait_v1, end_file_open_wait_and_bind_to_descriptor_v1, start_file_wait_v1, - end_file_wait_v1 + end_file_wait_v1, + start_stage_v1, + end_stage_v1, + get_thread_statement_locker_v1, + refine_statement_v1, + start_statement_v1, + set_statement_text_v1, + set_statement_lock_time_v1, + set_statement_rows_sent_v1, + set_statement_rows_examined_v1, + inc_statement_created_tmp_disk_tables_v1, + inc_statement_created_tmp_tables_v1, + inc_statement_select_full_join_v1, + inc_statement_select_full_range_join_v1, + inc_statement_select_range_v1, + inc_statement_select_range_check_v1, + inc_statement_select_scan_v1, + inc_statement_sort_merge_passes_v1, + inc_statement_sort_range_v1, + inc_statement_sort_rows_v1, + inc_statement_sort_scan_v1, + set_statement_no_index_used_v1, + set_statement_no_good_index_used_v1, + end_statement_v1, + start_socket_wait_v1, + end_socket_wait_v1, + set_socket_state_v1, + set_socket_info_v1, + set_socket_thread_owner_v1, + pfs_digest_start_v1, + pfs_digest_add_token_v1 }; static void* get_interface(int version) diff --git a/storage/perfschema/pfs.h b/storage/perfschema/pfs.h index 4e11736b1b9..5f543d80375 100644 --- a/storage/perfschema/pfs.h +++ b/storage/perfschema/pfs.h @@ -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 @@ -27,8 +27,14 @@ #include <my_pthread.h> #include <mysql/psi/psi.h> +/** + Entry point to the performance schema implementation. + This singleton is used to discover the performance schema services. +*/ extern struct PSI_bootstrap PFS_bootstrap; +/** Performance schema Thread Local Storage key. */ extern pthread_key(PFS_thread*, THR_PFS); +/** True when @c THR_PFS is initialized. */ extern bool THR_PFS_initialized; #endif diff --git a/storage/perfschema/pfs_account.cc b/storage/perfschema/pfs_account.cc new file mode 100644 index 00000000000..c9298c7972c --- /dev/null +++ b/storage/perfschema/pfs_account.cc @@ -0,0 +1,573 @@ +/* Copyright (c) 2010, 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 + 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_account.cc + Performance schema user@host (implementation). +*/ + +#include "my_global.h" +#include "my_sys.h" +#include "pfs.h" +#include "pfs_stat.h" +#include "pfs_instr.h" +#include "pfs_setup_actor.h" +#include "pfs_host.h" +#include "pfs_host.h" +#include "pfs_user.h" +#include "pfs_account.h" +#include "pfs_global.h" +#include "pfs_instr_class.h" + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +ulong account_max; +ulong account_lost; + +PFS_account *account_array= NULL; + +static PFS_single_stat *account_instr_class_waits_array= NULL; +static PFS_stage_stat *account_instr_class_stages_array= NULL; +static PFS_statement_stat *account_instr_class_statements_array= NULL; + +static LF_HASH account_hash; +static bool account_hash_inited= false; + +/** + Initialize the user buffers. + @param param sizing parameters + @return 0 on success +*/ +int init_account(const PFS_global_param *param) +{ + uint index; + + account_max= param->m_account_sizing; + + account_array= NULL; + account_instr_class_waits_array= NULL; + account_instr_class_stages_array= NULL; + account_instr_class_statements_array= NULL; + uint waits_sizing= account_max * wait_class_max; + uint stages_sizing= account_max * stage_class_max; + uint statements_sizing= account_max * statement_class_max; + + if (account_max > 0) + { + account_array= PFS_MALLOC_ARRAY(account_max, PFS_account, + MYF(MY_ZEROFILL)); + if (unlikely(account_array == NULL)) + return 1; + } + + if (waits_sizing > 0) + { + account_instr_class_waits_array= + PFS_connection_slice::alloc_waits_slice(waits_sizing); + if (unlikely(account_instr_class_waits_array == NULL)) + return 1; + } + + if (stages_sizing > 0) + { + account_instr_class_stages_array= + PFS_connection_slice::alloc_stages_slice(stages_sizing); + if (unlikely(account_instr_class_stages_array == NULL)) + return 1; + } + + if (statements_sizing > 0) + { + account_instr_class_statements_array= + PFS_connection_slice::alloc_statements_slice(statements_sizing); + if (unlikely(account_instr_class_statements_array == NULL)) + return 1; + } + + for (index= 0; index < account_max; index++) + { + account_array[index].m_instr_class_waits_stats= + &account_instr_class_waits_array[index * wait_class_max]; + account_array[index].m_instr_class_stages_stats= + &account_instr_class_stages_array[index * stage_class_max]; + account_array[index].m_instr_class_statements_stats= + &account_instr_class_statements_array[index * statement_class_max]; + } + + return 0; +} + +/** Cleanup all the user buffers. */ +void cleanup_account(void) +{ + pfs_free(account_array); + account_array= NULL; + pfs_free(account_instr_class_waits_array); + account_instr_class_waits_array= NULL; + account_max= 0; +} + +C_MODE_START +static uchar *account_hash_get_key(const uchar *entry, size_t *length, + my_bool) +{ + const PFS_account * const *typed_entry; + const PFS_account *account; + const void *result; + typed_entry= reinterpret_cast<const PFS_account* const *> (entry); + DBUG_ASSERT(typed_entry != NULL); + account= *typed_entry; + DBUG_ASSERT(account != NULL); + *length= account->m_key.m_key_length; + result= account->m_key.m_hash_key; + return const_cast<uchar*> (reinterpret_cast<const uchar*> (result)); +} +C_MODE_END + +/** + Initialize the user hash. + @return 0 on success +*/ +int init_account_hash(void) +{ + if (! account_hash_inited) + { + lf_hash_init(&account_hash, sizeof(PFS_account*), LF_HASH_UNIQUE, + 0, 0, account_hash_get_key, &my_charset_bin); + account_hash_inited= true; + } + return 0; +} + +/** Cleanup the user hash. */ +void cleanup_account_hash(void) +{ + if (account_hash_inited) + { + lf_hash_destroy(&account_hash); + account_hash_inited= false; + } +} + +static LF_PINS* get_account_hash_pins(PFS_thread *thread) +{ + if (unlikely(thread->m_account_hash_pins == NULL)) + { + if (! account_hash_inited) + return NULL; + thread->m_account_hash_pins= lf_hash_get_pins(&account_hash); + } + return thread->m_account_hash_pins; +} + +static void set_account_key(PFS_account_key *key, + const char *user, uint user_length, + const char *host, uint host_length) +{ + DBUG_ASSERT(user_length <= USERNAME_LENGTH); + DBUG_ASSERT(host_length <= HOSTNAME_LENGTH); + + char *ptr= &key->m_hash_key[0]; + if (user_length > 0) + { + memcpy(ptr, user, user_length); + ptr+= user_length; + } + ptr[0]= 0; + ptr++; + if (host_length > 0) + { + memcpy(ptr, host, host_length); + ptr+= host_length; + } + ptr[0]= 0; + ptr++; + key->m_key_length= ptr - &key->m_hash_key[0]; +} + +PFS_account * +find_or_create_account(PFS_thread *thread, + const char *username, uint username_length, + const char *hostname, uint hostname_length) +{ + if (account_max == 0) + { + account_lost++; + return NULL; + } + + LF_PINS *pins= get_account_hash_pins(thread); + if (unlikely(pins == NULL)) + { + account_lost++; + return NULL; + } + + PFS_account_key key; + set_account_key(&key, username, username_length, + hostname, hostname_length); + + PFS_account **entry; + uint retry_count= 0; + const uint retry_max= 3; + +search: + entry= reinterpret_cast<PFS_account**> + (lf_hash_search(&account_hash, pins, + key.m_hash_key, key.m_key_length)); + if (entry && (entry != MY_ERRPTR)) + { + PFS_account *pfs; + pfs= *entry; + pfs->inc_refcount(); + lf_hash_search_unpin(pins); + return pfs; + } + + lf_hash_search_unpin(pins); + + PFS_scan scan; + uint random= randomized_index(username, account_max); + + for (scan.init(random, account_max); + scan.has_pass(); + scan.next_pass()) + { + PFS_account *pfs= account_array + scan.first(); + PFS_account *pfs_last= account_array + scan.last(); + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_free()) + { + if (pfs->m_lock.free_to_dirty()) + { + pfs->m_key= key; + if (username_length > 0) + pfs->m_username= &pfs->m_key.m_hash_key[0]; + else + pfs->m_username= NULL; + pfs->m_username_length= username_length; + + if (hostname_length > 0) + pfs->m_hostname= &pfs->m_key.m_hash_key[username_length + 1]; + else + pfs->m_hostname= NULL; + pfs->m_hostname_length= hostname_length; + + pfs->m_user= find_or_create_user(thread, username, username_length); + pfs->m_host= find_or_create_host(thread, hostname, hostname_length); + + pfs->init_refcount(); + pfs->reset_stats(); + pfs->m_disconnected_count= 0; + + int res; + res= lf_hash_insert(&account_hash, pins, &pfs); + if (likely(res == 0)) + { + pfs->m_lock.dirty_to_allocated(); + return pfs; + } + + if (pfs->m_user) + { + pfs->m_user->release(); + pfs->m_user= NULL; + } + if (pfs->m_host) + { + pfs->m_host->release(); + pfs->m_host= NULL; + } + + pfs->m_lock.dirty_to_free(); + + if (res > 0) + { + if (++retry_count > retry_max) + { + account_lost++; + return NULL; + } + goto search; + } + + account_lost++; + return NULL; + } + } + } + } + + account_lost++; + return NULL; +} + +void PFS_account::aggregate() +{ + aggregate_waits(); + aggregate_stages(); + aggregate_statements(); + aggregate_stats(); +} + +void PFS_account::aggregate_waits() +{ + if (likely(m_user != NULL && m_host != NULL)) + { + /* + Aggregate EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_event_names(m_instr_class_waits_stats, + m_user->m_instr_class_waits_stats, + m_host->m_instr_class_waits_stats); + return; + } + + if (m_user != NULL) + { + /* + Aggregate EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME + */ + aggregate_all_event_names(m_instr_class_waits_stats, + m_user->m_instr_class_waits_stats); + return; + } + + if (m_host != NULL) + { + /* + Aggregate EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME + */ + aggregate_all_event_names(m_instr_class_waits_stats, + m_host->m_instr_class_waits_stats); + return; + } + + /* Orphan account, no parent to aggregate to. */ + reset_waits_stats(); + return; +} + +void PFS_account::aggregate_stages() +{ + if (likely(m_user != NULL && m_host != NULL)) + { + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_stages(m_instr_class_stages_stats, + m_user->m_instr_class_stages_stats, + m_host->m_instr_class_stages_stats); + return; + } + + if (m_user != NULL) + { + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME + in parallel. + */ + aggregate_all_stages(m_instr_class_stages_stats, + m_user->m_instr_class_stages_stats, + global_instr_class_stages_array); + return; + } + + if (m_host != NULL) + { + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME + */ + aggregate_all_stages(m_instr_class_stages_stats, + m_host->m_instr_class_stages_stats); + return; + } + + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME + */ + aggregate_all_stages(m_instr_class_stages_stats, + global_instr_class_stages_array); + return; +} + +void PFS_account::aggregate_statements() +{ + if (likely(m_user != NULL && m_host != NULL)) + { + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_statements(m_instr_class_statements_stats, + m_user->m_instr_class_statements_stats, + m_host->m_instr_class_statements_stats); + return; + } + + if (m_user != NULL) + { + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME + in parallel. + */ + aggregate_all_statements(m_instr_class_statements_stats, + m_user->m_instr_class_statements_stats, + global_instr_class_statements_array); + return; + } + + if (m_host != NULL) + { + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME + */ + aggregate_all_statements(m_instr_class_statements_stats, + m_host->m_instr_class_statements_stats); + return; + } + + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME + */ + aggregate_all_statements(m_instr_class_statements_stats, + global_instr_class_statements_array); + return; +} + +void PFS_account::aggregate_stats() +{ + if (likely(m_user != NULL && m_host != NULL)) + { + m_user->m_disconnected_count+= m_disconnected_count; + m_host->m_disconnected_count+= m_disconnected_count; + m_disconnected_count= 0; + return; + } + + if (m_user != NULL) + { + m_user->m_disconnected_count+= m_disconnected_count; + m_disconnected_count= 0; + return; + } + + if (m_host != NULL) + { + m_host->m_disconnected_count+= m_disconnected_count; + m_disconnected_count= 0; + return; + } + + m_disconnected_count= 0; + return; +} + +void PFS_account::release() +{ + dec_refcount(); +} + +PFS_account *sanitize_account(PFS_account *unsafe) +{ + if ((&account_array[0] <= unsafe) && + (unsafe < &account_array[account_max])) + return unsafe; + return NULL; +} + +void purge_account(PFS_thread *thread, PFS_account *account) +{ + account->aggregate(); + + LF_PINS *pins= get_account_hash_pins(thread); + if (unlikely(pins == NULL)) + return; + + PFS_account **entry; + entry= reinterpret_cast<PFS_account**> + (lf_hash_search(&account_hash, pins, + account->m_key.m_hash_key, + account->m_key.m_key_length)); + if (entry && (entry != MY_ERRPTR)) + { + DBUG_ASSERT(*entry == account); + if (account->get_refcount() == 0) + { + lf_hash_delete(&account_hash, pins, + account->m_key.m_hash_key, + account->m_key.m_key_length); + if (account->m_user != NULL) + { + account->m_user->release(); + account->m_user= NULL; + } + if (account->m_host != NULL) + { + account->m_host->release(); + account->m_host= NULL; + } + account->m_lock.allocated_to_free(); + } + } + + lf_hash_search_unpin(pins); +} + +/** Purge non connected user@host, reset stats of connected user@host. */ +void purge_all_account(void) +{ + PFS_thread *thread= PFS_thread::get_current_thread(); + if (unlikely(thread == NULL)) + return; + + PFS_account *pfs= account_array; + PFS_account *pfs_last= account_array + account_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + { + pfs->aggregate_stats(); + + if (pfs->get_refcount() == 0) + purge_account(thread, pfs); + } + } +} + +/** @} */ diff --git a/storage/perfschema/pfs_account.h b/storage/perfschema/pfs_account.h new file mode 100644 index 00000000000..77a9dfab7ba --- /dev/null +++ b/storage/perfschema/pfs_account.h @@ -0,0 +1,120 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef PFS_ACCOUNT_H +#define PFS_ACCOUNT_H + +/** + @file storage/perfschema/pfs_account.h + Performance schema user@host (declarations). +*/ + +#include "pfs_lock.h" +#include "lf.h" +#include "pfs_con_slice.h" + +struct PFS_global_param; +struct PFS_user; +struct PFS_host; +struct PFS_thread; + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +struct PFS_account_key +{ + /** + Hash search key. + This has to be a string for LF_HASH, + the format is "<username><0x00><hostname><0x00>" + */ + char m_hash_key[USERNAME_LENGTH + 1 + HOSTNAME_LENGTH + 1]; + uint m_key_length; +}; + +struct PFS_account : PFS_connection_slice +{ +public: + inline void init_refcount(void) + { + PFS_atomic::store_32(& m_refcount, 1); + } + + inline int get_refcount(void) + { + return PFS_atomic::load_32(& m_refcount); + } + + inline void inc_refcount(void) + { + PFS_atomic::add_32(& m_refcount, 1); + } + + inline void dec_refcount(void) + { + PFS_atomic::add_32(& m_refcount, -1); + } + + void aggregate(void); + void aggregate_waits(void); + void aggregate_stages(void); + void aggregate_statements(void); + void aggregate_stats(void); + void release(void); + + /** Internal lock. */ + pfs_lock m_lock; + PFS_account_key m_key; + const char *m_username; + uint m_username_length; + const char *m_hostname; + uint m_hostname_length; + PFS_user *m_user; + PFS_host *m_host; + + ulonglong m_disconnected_count; + +private: + int m_refcount; +}; + +int init_account(const PFS_global_param *param); +void cleanup_account(void); +int init_account_hash(void); +void cleanup_account_hash(void); + +PFS_account * +find_or_create_account(PFS_thread *thread, + const char *username, uint username_length, + const char *hostname, uint hostname_length); + +PFS_account *sanitize_account(PFS_account *unsafe); +void purge_all_account(void); + + +/* For iterators and show status. */ + +extern ulong account_max; +extern ulong account_lost; + +/* Exposing the data directly, for iterators. */ + +extern PFS_account *account_array; + +/** @} */ +#endif + diff --git a/storage/perfschema/pfs_atomic.cc b/storage/perfschema/pfs_atomic.cc index 4db807b1d88..601bd94cabd 100644 --- a/storage/perfschema/pfs_atomic.cc +++ b/storage/perfschema/pfs_atomic.cc @@ -1,6 +1,4 @@ -/* - Copyright (c) 2009, 2010 Sun Microsystems, Inc. - Use is subject to license terms. +/* Copyright (c) 2009, 2010, 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 diff --git a/storage/perfschema/pfs_atomic.h b/storage/perfschema/pfs_atomic.h index 4daebfbbae4..ffb4c24ecbf 100644 --- a/storage/perfschema/pfs_atomic.h +++ b/storage/perfschema/pfs_atomic.h @@ -1,6 +1,4 @@ -/* - Copyright (c) 2009, 2010 Sun Microsystems, Inc. - Use is subject to license terms. +/* Copyright (c) 2009, 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 @@ -29,7 +27,9 @@ class PFS_atomic { public: + /** Initialise the PFS_atomic component. */ static void init(); + /** Cleanup the PFS_atomic component. */ static void cleanup(); /** Atomic load. */ @@ -114,6 +114,10 @@ public: private: static my_atomic_rwlock_t m_rwlock_array[256]; + /** + Helper used only with non native atomic implementations. + @sa MY_ATOMIC_MODE_RWLOCKS + */ static inline my_atomic_rwlock_t *get_rwlock(volatile void *ptr) { /* @@ -125,21 +129,37 @@ private: return result; } + /** + Helper used only with non native atomic implementations. + @sa MY_ATOMIC_MODE_RWLOCKS + */ static inline void rdlock(volatile void *ptr) { my_atomic_rwlock_rdlock(get_rwlock(ptr)); } + /** + Helper used only with non native atomic implementations. + @sa MY_ATOMIC_MODE_RWLOCKS + */ static inline void wrlock(volatile void *ptr) { my_atomic_rwlock_wrlock(get_rwlock(ptr)); } + /** + Helper used only with non native atomic implementations. + @sa MY_ATOMIC_MODE_RWLOCKS + */ static inline void rdunlock(volatile void *ptr) { my_atomic_rwlock_rdunlock(get_rwlock(ptr)); } + /** + Helper used only with non native atomic implementations. + @sa MY_ATOMIC_MODE_RWLOCKS + */ static inline void wrunlock(volatile void *ptr) { my_atomic_rwlock_wrunlock(get_rwlock(ptr)); diff --git a/storage/perfschema/pfs_column_types.h b/storage/perfschema/pfs_column_types.h index dc990664a8f..23ef946ee82 100644 --- a/storage/perfschema/pfs_column_types.h +++ b/storage/perfschema/pfs_column_types.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc. - Use is subject to license terms. +/* 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 @@ -39,9 +38,27 @@ /** Size of the OBJECT_NAME columns. */ #define COL_OBJECT_NAME_SIZE 64 +/** Size of the INDEX_NAME columns. */ +#define COL_INDEX_NAME_SIZE 64 + +/** + Size of INFO columns. + Size in bytes of: + - performance_schema.events_statement_current (INFO) + - performance_schema.events_statement_history (INFO) + - performance_schema.events_statement_history_long (INFO) +*/ +#define COL_INFO_SIZE 1024 + /** Size of the SOURCE columns. */ #define COL_SOURCE_SIZE 64 +/** Size of the DIGEST columns. */ +#define COL_DIGEST_SIZE 64 + +/** Size of the DIGEST_TEXT columns. */ +#define COL_DIGEST_TEXT_SIZE 1024 + /** Enum values for the TIMER_NAME columns. This enum is found in the following tables: @@ -57,8 +74,11 @@ enum enum_timer_name TIMER_NAME_TICK= 5 }; +/** Integer, first value of @sa enum_timer_name. */ #define FIRST_TIMER_NAME (static_cast<int> (TIMER_NAME_CYCLE)) +/** Integer, last value of @sa enum_timer_name. */ #define LAST_TIMER_NAME (static_cast<int> (TIMER_NAME_TICK)) +/** Integer, number of values of @sa enum_timer_name. */ #define COUNT_TIMER_NAME (LAST_TIMER_NAME - FIRST_TIMER_NAME + 1) /** @@ -83,17 +103,21 @@ enum enum_yes_no */ enum enum_operation_type { + /* Mutex operations */ OPERATION_TYPE_LOCK= 1, OPERATION_TYPE_TRYLOCK= 2, + /* Rwlock operations */ OPERATION_TYPE_READLOCK= 3, OPERATION_TYPE_WRITELOCK= 4, OPERATION_TYPE_TRYREADLOCK= 5, OPERATION_TYPE_TRYWRITELOCK= 6, + /* Cond operations */ OPERATION_TYPE_WAIT= 7, OPERATION_TYPE_TIMEDWAIT= 8, + /* File operations */ OPERATION_TYPE_FILECREATE= 9, OPERATION_TYPE_FILECREATETMP= 10, OPERATION_TYPE_FILEOPEN= 11, @@ -110,11 +134,89 @@ enum enum_operation_type OPERATION_TYPE_FILECHSIZE= 22, OPERATION_TYPE_FILEDELETE= 23, OPERATION_TYPE_FILERENAME= 24, - OPERATION_TYPE_FILESYNC= 25 + OPERATION_TYPE_FILESYNC= 25, + + /* Table io operations */ + OPERATION_TYPE_TABLE_FETCH= 26, + OPERATION_TYPE_TABLE_WRITE_ROW= 27, + OPERATION_TYPE_TABLE_UPDATE_ROW= 28, + OPERATION_TYPE_TABLE_DELETE_ROW= 29, + + /* Table lock operations */ + OPERATION_TYPE_TL_READ_NORMAL= 30, + OPERATION_TYPE_TL_READ_WITH_SHARED_LOCKS= 31, + OPERATION_TYPE_TL_READ_HIGH_PRIORITY= 32, + OPERATION_TYPE_TL_READ_NO_INSERTS= 33, + OPERATION_TYPE_TL_WRITE_ALLOW_WRITE= 34, + OPERATION_TYPE_TL_WRITE_CONCURRENT_INSERT= 35, + OPERATION_TYPE_TL_WRITE_DELAYED= 36, + OPERATION_TYPE_TL_WRITE_LOW_PRIORITY= 37, + OPERATION_TYPE_TL_WRITE_NORMAL= 38, + OPERATION_TYPE_TL_READ_EXTERNAL= 39, + OPERATION_TYPE_TL_WRITE_EXTERNAL= 40, + + /* Socket operations */ + OPERATION_TYPE_SOCKETCREATE = 41, + OPERATION_TYPE_SOCKETCONNECT = 42, + OPERATION_TYPE_SOCKETBIND = 43, + OPERATION_TYPE_SOCKETCLOSE = 44, + OPERATION_TYPE_SOCKETSEND = 45, + OPERATION_TYPE_SOCKETRECV = 46, + OPERATION_TYPE_SOCKETSENDTO = 47, + OPERATION_TYPE_SOCKETRECVFROM = 48, + OPERATION_TYPE_SOCKETSENDMSG = 49, + OPERATION_TYPE_SOCKETRECVMSG = 50, + OPERATION_TYPE_SOCKETSEEK = 51, + OPERATION_TYPE_SOCKETOPT = 52, + OPERATION_TYPE_SOCKETSTAT = 53, + OPERATION_TYPE_SOCKETSHUTDOWN = 54, + OPERATION_TYPE_SOCKETSELECT = 55, + + /* Idle operation */ + OPERATION_TYPE_IDLE= 56 }; +/** Integer, first value of @sa enum_operation_type. */ #define FIRST_OPERATION_TYPE (static_cast<int> (OPERATION_TYPE_LOCK)) -#define LAST_OPERATION_TYPE (static_cast<int> (OPERATION_TYPE_FILESYNC)) +/** Integer, last value of @sa enum_operation_type. */ +#define LAST_OPERATION_TYPE (static_cast<int> (OPERATION_TYPE_IDLE)) +/** Integer, number of values of @sa enum_operation_type. */ #define COUNT_OPERATION_TYPE (LAST_OPERATION_TYPE - FIRST_OPERATION_TYPE + 1) +/** + Enum values for the various OBJECT_TYPE columns. +*/ +enum enum_object_type +{ + OBJECT_TYPE_TABLE= 1, + OBJECT_TYPE_TEMPORARY_TABLE= 2 +}; +/** Integer, first value of @sa enum_object_type. */ +#define FIRST_OBJECT_TYPE (static_cast<int> (OBJECT_TYPE_TABLE)) +/** Integer, last value of @sa enum_object_type. */ +#define LAST_OBJECT_TYPE (static_cast<int> (OBJECT_TYPE_TEMPORARY_TABLE)) +/** Integer, number of values of @sa enum_object_type. */ +#define COUNT_OBJECT_TYPE (LAST_OBJECT_TYPE - FIRST_OBJECT_TYPE + 1) + +/** + Enum values for the NESTING_EVENT_TYPE columns. + This enum is found in the following tables: + - performance_schema.events_waits_current (NESTING_EVENT_TYPE) + - performance_schema.events_stages_current (NESTING_EVENT_TYPE) + - performance_schema.events_statements_current (NESTING_EVENT_TYPE) +*/ +enum enum_event_type +{ + EVENT_TYPE_STATEMENT= 1, + EVENT_TYPE_STAGE= 2, + EVENT_TYPE_WAIT= 3 +}; + +/** Integer, first value of @sa enum_event_type. */ +#define FIRST_EVENT_TYPE (static_cast<int> (EVENT_TYPE_STATEMENT)) +/** Integer, last value of @sa enum_event_type. */ +#define LAST_EVENT_TYPE (static_cast<int> (EVENT_TYPE_WAIT)) +/** Integer, number of values of @sa enum_event_type. */ +#define COUNT_EVENT_TYPE (LAST_EVENT_TYPE - FIRST_EVENT_TYPE + 1) + #endif diff --git a/storage/perfschema/pfs_column_values.cc b/storage/perfschema/pfs_column_values.cc index ea65441b8c6..65d0ae7171b 100644 --- a/storage/perfschema/pfs_column_values.cc +++ b/storage/perfschema/pfs_column_values.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 @@ -19,6 +19,7 @@ schema tables (implementation). */ +#include "my_global.h" #include "pfs_column_values.h" LEX_STRING PERFORMANCE_SCHEMA_str= @@ -39,3 +40,11 @@ LEX_STRING thread_instrument_prefix= LEX_STRING file_instrument_prefix= { C_STRING_WITH_LEN("wait/io/file/") }; +LEX_STRING stage_instrument_prefix= +{ C_STRING_WITH_LEN("stage/") }; + +LEX_STRING statement_instrument_prefix= +{ C_STRING_WITH_LEN("statement/") }; + +LEX_STRING socket_instrument_prefix= +{ C_STRING_WITH_LEN("wait/io/socket/") }; diff --git a/storage/perfschema/pfs_column_values.h b/storage/perfschema/pfs_column_values.h index f9e7f90dbc9..204d5230ddf 100644 --- a/storage/perfschema/pfs_column_values.h +++ b/storage/perfschema/pfs_column_values.h @@ -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 @@ -24,13 +24,24 @@ performance schema tables (declarations). */ +/** String, "PERFORMANCE_SCHEMA". */ extern LEX_STRING PERFORMANCE_SCHEMA_str; +/** String prefix for all mutex instruments. */ extern LEX_STRING mutex_instrument_prefix; +/** String prefix for all rwlock instruments. */ extern LEX_STRING rwlock_instrument_prefix; +/** String prefix for all cond instruments. */ extern LEX_STRING cond_instrument_prefix; +/** String prefix for all thread instruments. */ extern LEX_STRING thread_instrument_prefix; +/** String prefix for all file instruments. */ extern LEX_STRING file_instrument_prefix; +/** String prefix for all stage instruments. */ +extern LEX_STRING stage_instrument_prefix; +/** String prefix for all statement instruments. */ +extern LEX_STRING statement_instrument_prefix; +extern LEX_STRING socket_instrument_prefix; #endif diff --git a/storage/perfschema/pfs_con_slice.cc b/storage/perfschema/pfs_con_slice.cc new file mode 100644 index 00000000000..263f25c1c08 --- /dev/null +++ b/storage/perfschema/pfs_con_slice.cc @@ -0,0 +1,116 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_con_slice.h" +#include "pfs_stat.h" +#include "pfs_global.h" +#include "pfs_instr_class.h" + +/** + @file storage/perfschema/pfs_con_slice.cc + Performance schema connection slice (implementation). +*/ + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +PFS_single_stat * +PFS_connection_slice::alloc_waits_slice(uint sizing) +{ + PFS_single_stat *slice= NULL; + uint index; + + if (sizing > 0) + { + slice= PFS_MALLOC_ARRAY(sizing, PFS_single_stat, MYF(MY_ZEROFILL)); + if (unlikely(slice == NULL)) + return NULL; + + for (index= 0; index < sizing; index++) + slice[index].reset(); + } + + return slice; +} + +PFS_stage_stat * +PFS_connection_slice::alloc_stages_slice(uint sizing) +{ + PFS_stage_stat *slice= NULL; + uint index; + + if (sizing > 0) + { + slice= PFS_MALLOC_ARRAY(sizing, PFS_stage_stat, MYF(MY_ZEROFILL)); + if (unlikely(slice == NULL)) + return NULL; + + for (index= 0; index < sizing; index++) + slice[index].reset(); + } + + return slice; +} + +PFS_statement_stat * +PFS_connection_slice::alloc_statements_slice(uint sizing) +{ + PFS_statement_stat *slice= NULL; + uint index; + + if (sizing > 0) + { + slice= PFS_MALLOC_ARRAY(sizing, PFS_statement_stat, MYF(MY_ZEROFILL)); + if (unlikely(slice == NULL)) + return NULL; + + for (index= 0; index < sizing; index++) + slice[index].reset(); + } + + return slice; +} + +void PFS_connection_slice::reset_waits_stats() +{ + PFS_single_stat *stat= m_instr_class_waits_stats; + PFS_single_stat *stat_last= stat + wait_class_max; + for ( ; stat < stat_last; stat++) + stat->reset(); +} + +void PFS_connection_slice::reset_stages_stats() +{ + PFS_stage_stat *stat= m_instr_class_stages_stats; + PFS_stage_stat *stat_last= stat + stage_class_max; + for ( ; stat < stat_last; stat++) + stat->reset(); +} + +void PFS_connection_slice::reset_statements_stats() +{ + PFS_statement_stat *stat= m_instr_class_statements_stats; + PFS_statement_stat *stat_last= stat + statement_class_max; + for ( ; stat < stat_last; stat++) + stat->reset(); +} + +/** @} */ + diff --git a/storage/perfschema/pfs_con_slice.h b/storage/perfschema/pfs_con_slice.h new file mode 100644 index 00000000000..d82adcb58a3 --- /dev/null +++ b/storage/perfschema/pfs_con_slice.h @@ -0,0 +1,103 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef PFS_CON_SLICE_H +#define PFS_CON_SLICE_H + +/** + @file storage/perfschema/pfs_con_slice.h + Performance schema connection slice (declarations). +*/ + +#include "pfs_lock.h" +#include "lf.h" + +struct PFS_single_stat; +struct PFS_stage_stat; +struct PFS_statement_stat; + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +/** + A connection slice, an arbitrary grouping of several connections. + This structure holds statistics for grouping of connections. +*/ +struct PFS_connection_slice +{ + /** + Allocate memory for waits statistics. + @param sizing the number of wait classes. + @return wait statistics for this slice. + */ + static PFS_single_stat *alloc_waits_slice(uint sizing); + /** + Allocate memory for stages statistics. + @param sizing the number of stage classes. + @return stage statistics for this slice. + */ + static PFS_stage_stat *alloc_stages_slice(uint sizing); + /** + Allocate memory for statement statistics. + @param sizing the number of statement classes. + @return statement statistics for this slice. + */ + static PFS_statement_stat *alloc_statements_slice(uint sizing); + + /** Reset all statistics. */ + inline void reset_stats() + { + reset_waits_stats(); + reset_stages_stats(); + reset_statements_stats(); + } + + /** Reset all wait statistics. */ + void reset_waits_stats(); + /** Reset all stages statistics. */ + void reset_stages_stats(); + /** Reset all statements statistics. */ + void reset_statements_stats(); + + /** + Per connection slice waits aggregated statistics. + This member holds the data for the table + PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_*_BY_EVENT_NAME. + Immutable, safe to use without internal lock. + */ + PFS_single_stat *m_instr_class_waits_stats; + + /** + Per connection slice stages aggregated statistics. + This member holds the data for the table + PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_*_BY_EVENT_NAME. + Immutable, safe to use without internal lock. + */ + PFS_stage_stat *m_instr_class_stages_stats; + + /** + Per connection slice statements aggregated statistics. + This member holds the data for the table + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_*_BY_EVENT_NAME. + Immutable, safe to use without internal lock. + */ + PFS_statement_stat *m_instr_class_statements_stats; +}; + +/** @} */ +#endif + diff --git a/storage/perfschema/pfs_defaults.cc b/storage/perfschema/pfs_defaults.cc new file mode 100644 index 00000000000..4bd24f59ca8 --- /dev/null +++ b/storage/perfschema/pfs_defaults.cc @@ -0,0 +1,63 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/pfs_defaults.cc + Default setup (implementation). +*/ + +#include "pfs.h" +#include "pfs_defaults.h" +#include "pfs_instr.h" +#include "pfs_setup_actor.h" +#include "pfs_setup_object.h" + +static PSI_thread_key key; +static PSI_thread_info info= { &key, "setup", PSI_FLAG_GLOBAL }; + +void install_default_setup(PSI_bootstrap *boot) +{ + PSI *psi= (PSI*) boot->get_interface(PSI_CURRENT_VERSION); + if (psi == NULL) + return; + + psi->register_thread("performance_schema", &info, 1); + PSI_thread *psi_thread= psi->new_thread(key, NULL, 0); + if (psi_thread == NULL) + return; + + /* LF_HASH needs a thread, for PINS */ + psi->set_thread(psi_thread); + + String percent("%", 1, &my_charset_utf8_bin); + /* Enable all users on all hosts by default */ + insert_setup_actor(&percent, &percent, &percent); + + /* Disable system tables by default */ + String mysql_db("mysql", 5, &my_charset_utf8_bin); + insert_setup_object(OBJECT_TYPE_TABLE, &mysql_db, &percent, false, false); + + /* Disable performance/information schema tables. */ + String PS_db("performance_schema", 18, &my_charset_utf8_bin); + String IS_db("information_schema", 18, &my_charset_utf8_bin); + insert_setup_object(OBJECT_TYPE_TABLE, &PS_db, &percent, false, false); + insert_setup_object(OBJECT_TYPE_TABLE, &IS_db, &percent, false, false); + + /* Enable every other tables */ + insert_setup_object(OBJECT_TYPE_TABLE, &percent, &percent, true, true); + + psi->delete_current_thread(); +} + diff --git a/storage/perfschema/pfs_defaults.h b/storage/perfschema/pfs_defaults.h new file mode 100644 index 00000000000..bbb041504e2 --- /dev/null +++ b/storage/perfschema/pfs_defaults.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef PFS_DEFAULTS_H +#define PFS_DEFAULTS_H + +/** + @file storage/perfschema/pfs_defaults.h + Default setup (declarations). +*/ + +/** + Configure the performance schema setup tables with default content. + The tables populated are: + - SETUP_ACTORS + - SETUP_OBJECTS +*/ +void install_default_setup(PSI_bootstrap *boot); + +#endif diff --git a/storage/perfschema/pfs_digest.cc b/storage/perfschema/pfs_digest.cc new file mode 100644 index 00000000000..92c27b2e85f --- /dev/null +++ b/storage/perfschema/pfs_digest.cc @@ -0,0 +1,676 @@ +/* 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/pfs_digest.h + Statement Digest data structures (implementation). +*/ + +/* + This code needs extra visibility in the lexer structures +*/ + +#include "my_global.h" +#include "my_sys.h" +#include "pfs_instr.h" +#include "pfs_digest.h" +#include "pfs_global.h" +#include "table_helper.h" +#include "my_md5.h" +#include "sql_lex.h" +#include <string.h> + +/* Generated code */ +#include "../sql/sql_yacc.h" +#include "../storage/perfschema/pfs_lex_token.h" + +/* Name pollution from sql/sql_lex.h */ +#ifdef LEX_YYSTYPE +#undef LEX_YYSTYPE +#endif + +#define LEX_YYSTYPE YYSTYPE + +/** + Token array : + Token array is an array of bytes to store tokens recieved during parsing. + Following is the way token array is formed. + + ...<non-id-token><non-id-token><id-token><id_len><id_text>... + + For Ex: + SELECT * FROM T1; + <SELECT_TOKEN><*><FROM_TOKEN><ID_TOKEN><2><T1> +*/ + +ulong digest_max= 0; +ulong digest_lost= 0; + + +/** EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */ +PFS_statements_digest_stat *statements_digest_stat_array= NULL; +/** Consumer flag for table EVENTS_STATEMENTS_SUMMARY_BY_DIGEST. */ +bool flag_statements_digest= true; +/** + Current index in Stat array where new record is to be inserted. + index 0 is reserved for "all else" case when entire array is full. +*/ +volatile uint32 digest_index= 1; + +static LF_HASH digest_hash; +static bool digest_hash_inited= false; + +/** + Initialize table EVENTS_STATEMENTS_SUMMARY_BY_DIGEST. + @param digest_sizing +*/ +int init_digest(const PFS_global_param *param) +{ + unsigned int index; + + /* + Allocate memory for statements_digest_stat_array based on + performance_schema_digests_size values + */ + digest_max= param->m_digest_sizing; + digest_lost= 0; + + if (digest_max == 0) + return 0; + + statements_digest_stat_array= + PFS_MALLOC_ARRAY(digest_max, PFS_statements_digest_stat, + MYF(MY_ZEROFILL)); + if (unlikely(statements_digest_stat_array == NULL)) + return 1; + + for (index= 0; index < digest_max; index++) + { + statements_digest_stat_array[index].reset_data(); + } + + return 0; +} + +/** Cleanup table EVENTS_STATEMENTS_SUMMARY_BY_DIGEST. */ +void cleanup_digest(void) +{ + /* Free memory allocated to statements_digest_stat_array. */ + pfs_free(statements_digest_stat_array); + statements_digest_stat_array= NULL; +} + +C_MODE_START +static uchar *digest_hash_get_key(const uchar *entry, size_t *length, + my_bool) +{ + const PFS_statements_digest_stat * const *typed_entry; + const PFS_statements_digest_stat *digest; + const void *result; + typed_entry= reinterpret_cast<const PFS_statements_digest_stat*const*>(entry); + DBUG_ASSERT(typed_entry != NULL); + digest= *typed_entry; + DBUG_ASSERT(digest != NULL); + *length= PFS_MD5_SIZE; + result= digest->m_digest_hash.m_md5; + return const_cast<uchar*> (reinterpret_cast<const uchar*> (result)); +} +C_MODE_END + + +/** + Initialize the digest hash. + @return 0 on success +*/ +int init_digest_hash(void) +{ + if (! digest_hash_inited) + { + lf_hash_init(&digest_hash, sizeof(PFS_statements_digest_stat*), + LF_HASH_UNIQUE, 0, 0, digest_hash_get_key, + &my_charset_bin); + digest_hash_inited= true; + } + return 0; +} + +void cleanup_digest_hash(void) +{ + if (digest_hash_inited) + { + lf_hash_destroy(&digest_hash); + digest_hash_inited= false; + } +} + +static LF_PINS* get_digest_hash_pins(PFS_thread *thread) +{ + if (unlikely(thread->m_digest_hash_pins == NULL)) + { + if (!digest_hash_inited) + return NULL; + thread->m_digest_hash_pins= lf_hash_get_pins(&digest_hash); + } + return thread->m_digest_hash_pins; +} + +PFS_statement_stat* +find_or_create_digest(PFS_thread* thread, + PSI_digest_storage* digest_storage) +{ + if (statements_digest_stat_array == NULL) + return NULL; + + if (digest_storage->m_byte_count <= 0) + return NULL; + + LF_PINS *pins= get_digest_hash_pins(thread); + if (unlikely(pins == NULL)) + return NULL; + + /* Compute MD5 Hash of the tokens received. */ + PFS_digest_hash md5; + compute_md5_hash((char *) md5.m_md5, + (char *) digest_storage->m_token_array, + digest_storage->m_byte_count); + + unsigned char* hash_key= md5.m_md5; + + int res; + ulong safe_index; + uint retry_count= 0; + const uint retry_max= 3; + PFS_statements_digest_stat **entry; + PFS_statements_digest_stat *pfs= NULL; + + ulonglong now= microsecond_interval_timer(); + +search: + + /* Lookup LF_HASH using this new key. */ + entry= reinterpret_cast<PFS_statements_digest_stat**> + (lf_hash_search(&digest_hash, pins, + hash_key, PFS_MD5_SIZE)); + + if (entry && (entry != MY_ERRPTR)) + { + /* If digest already exists, update stats and return. */ + pfs= *entry; + pfs->m_last_seen= now; + lf_hash_search_unpin(pins); + return & pfs->m_stat; + } + + lf_hash_search_unpin(pins); + + /* Dirty read of digest_index */ + if (digest_index == 0) + { + /* digest_stat array is full. Add stat at index 0 and return. */ + pfs= &statements_digest_stat_array[0]; + + if (pfs->m_first_seen == 0) + pfs->m_first_seen= now; + pfs->m_last_seen= now; + return & pfs->m_stat; + } + + safe_index= PFS_atomic::add_u32(& digest_index, 1); + if (safe_index >= digest_max) + { + /* The digest array is now full. */ + digest_index= 0; + pfs= &statements_digest_stat_array[0]; + + if (pfs->m_first_seen == 0) + pfs->m_first_seen= now; + pfs->m_last_seen= now; + return & pfs->m_stat; + } + + /* Add a new record in digest stat array. */ + pfs= &statements_digest_stat_array[safe_index]; + + /* Copy digest hash/LF Hash search key. */ + memcpy(pfs->m_digest_hash.m_md5, md5.m_md5, PFS_MD5_SIZE); + + /* + Copy digest storage to statement_digest_stat_array so that it could be + used later to generate digest text. + */ + digest_copy(& pfs->m_digest_storage, digest_storage); + + pfs->m_first_seen= now; + pfs->m_last_seen= now; + + res= lf_hash_insert(&digest_hash, pins, &pfs); + if (likely(res == 0)) + { + return & pfs->m_stat; + } + + if (res > 0) + { + /* Duplicate insert by another thread */ + if (++retry_count > retry_max) + { + /* Avoid infinite loops */ + digest_lost++; + return NULL; + } + goto search; + } + + /* OOM in lf_hash_insert */ + digest_lost++; + return NULL; +} + +void purge_digest(PFS_thread* thread, unsigned char* hash_key) +{ + LF_PINS *pins= get_digest_hash_pins(thread); + if (unlikely(pins == NULL)) + return; + + PFS_statements_digest_stat **entry; + + /* Lookup LF_HASH using this new key. */ + entry= reinterpret_cast<PFS_statements_digest_stat**> + (lf_hash_search(&digest_hash, pins, + hash_key, PFS_MD5_SIZE)); + + if (entry && (entry != MY_ERRPTR)) + { + lf_hash_delete(&digest_hash, pins, + hash_key, PFS_MD5_SIZE); + } + lf_hash_search_unpin(pins); + return; +} + +void PFS_statements_digest_stat::reset_data() +{ + digest_reset(& m_digest_storage); + m_stat.reset(); + m_first_seen= 0; + m_last_seen= 0; +} + +void PFS_statements_digest_stat::reset_index(PFS_thread *thread) +{ + /* Only remove entries that exists in the HASH index. */ + if (m_digest_storage.m_byte_count > 0) + { + purge_digest(thread, m_digest_hash.m_md5); + } +} + +void reset_esms_by_digest() +{ + uint index; + + if (statements_digest_stat_array == NULL) + return; + + PFS_thread *thread= PFS_thread::get_current_thread(); + if (unlikely(thread == NULL)) + return; + + /* Reset statements_digest_stat_array. */ + for (index= 0; index < digest_max; index++) + { + statements_digest_stat_array[index].reset_index(thread); + statements_digest_stat_array[index].reset_data(); + } + + /* + Reset index which indicates where the next calculated digest information + to be inserted in statements_digest_stat_array. + */ + digest_index= 1; +} + +/* + Iterate token array and updates digest_text. +*/ +void get_digest_text(char* digest_text, PSI_digest_storage* digest_storage) +{ + bool truncated= false; + int byte_count= digest_storage->m_byte_count; + int need_bytes; + uint tok= 0; + char *id_string; + int id_length; + int current_byte= 0; + lex_token_string *tok_data; + /* -4 is to make sure extra space for '...' and a '\0' at the end. */ + int available_bytes_to_write= COL_DIGEST_TEXT_SIZE - 4; + + DBUG_ASSERT(byte_count <= PSI_MAX_DIGEST_STORAGE_SIZE); + + while ((current_byte < byte_count) && + (available_bytes_to_write > 0) && + (! truncated)) + { + current_byte= read_token(digest_storage, current_byte, &tok); + tok_data= & lex_token_array[tok]; + + switch (tok) + { + /* All identifiers are printed with their name. */ + case IDENT: + current_byte= read_identifier(digest_storage, current_byte, + & id_string, & id_length); + need_bytes= id_length + 1; /* <id> space */ + if (need_bytes <= available_bytes_to_write) + { + if (id_length > 0) + { + strncpy(digest_text, id_string, id_length); + digest_text+= id_length; + } + *digest_text= ' '; + digest_text++; + available_bytes_to_write-= need_bytes; + } + else + { + truncated= true; + } + break; + case IDENT_QUOTED: + current_byte= read_identifier(digest_storage, current_byte, + & id_string, & id_length); + need_bytes= id_length + 3; /* quote <id> quote space */ + if (need_bytes <= available_bytes_to_write) + { + *digest_text= '`'; + digest_text++; + if (id_length > 0) + { + strncpy(digest_text, id_string, id_length); + digest_text+= id_length; + } + *digest_text= '`'; + digest_text++; + *digest_text= ' '; + digest_text++; + available_bytes_to_write-= need_bytes; + } + else + { + truncated= true; + } + break; + + /* Everything else is printed as is. */ + default: + /* + Make sure not to overflow digest_text buffer while writing + this token string. + +1 is to make sure extra space for ' '. + */ + int tok_length= tok_data->m_token_length; + need_bytes= tok_length + 1; + + if (need_bytes <= available_bytes_to_write) + { + strncpy(digest_text, + tok_data->m_token_string, + tok_length); + digest_text+= tok_length; + *digest_text= ' '; + digest_text++; + available_bytes_to_write-= need_bytes; + } + else + { + truncated= true; + } + } + } + + /* Truncate digest text in case of long queries. */ + if (digest_storage->m_full || truncated) + { + strcpy(digest_text, "..."); + digest_text+= 3; + } + + *digest_text= '\0'; +} + +static inline uint peek_token(const PSI_digest_storage *digest, int index) +{ + uint token; + DBUG_ASSERT(index >= 0); + DBUG_ASSERT(index + PFS_SIZE_OF_A_TOKEN <= digest->m_byte_count); + DBUG_ASSERT(digest->m_byte_count <= PSI_MAX_DIGEST_STORAGE_SIZE); + + token= ((digest->m_token_array[index + 1])<<8) | digest->m_token_array[index]; + return token; +} + +/** + Function to read last two tokens from token array. If an identifier + is found, do not look for token after that. +*/ +static inline void peek_last_two_tokens(const PSI_digest_storage* digest_storage, + int last_id_index, uint *t1, uint *t2) +{ + int byte_count= digest_storage->m_byte_count; + + if (last_id_index <= byte_count - PFS_SIZE_OF_A_TOKEN) + { + /* Take last token. */ + *t1= peek_token(digest_storage, byte_count - PFS_SIZE_OF_A_TOKEN); + } + else + { + *t1= TOK_PFS_UNUSED; + } + + if (last_id_index <= byte_count - 2*PFS_SIZE_OF_A_TOKEN) + { + /* Take 2nd token from last. */ + *t2= peek_token(digest_storage, byte_count - 2 * PFS_SIZE_OF_A_TOKEN); + } + else + { + *t2= TOK_PFS_UNUSED; + } +} + +struct PSI_digest_locker* pfs_digest_start_v1(PSI_statement_locker *locker) +{ + PSI_statement_locker_state *statement_state; + statement_state= reinterpret_cast<PSI_statement_locker_state*> (locker); + DBUG_ASSERT(statement_state != NULL); + + if (statement_state->m_discarded) + return NULL; + + if (statement_state->m_flags & STATE_FLAG_DIGEST) + { + PSI_digest_locker_state *digest_state; + digest_state= &statement_state->m_digest_state; + return reinterpret_cast<PSI_digest_locker*> (digest_state); + } + + return NULL; +} + +PSI_digest_locker* pfs_digest_add_token_v1(PSI_digest_locker *locker, + uint token, + OPAQUE_LEX_YYSTYPE *yylval) +{ + PSI_digest_locker_state *state= NULL; + PSI_digest_storage *digest_storage= NULL; + + state= reinterpret_cast<PSI_digest_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + digest_storage= &state->m_digest_storage; + + if (digest_storage->m_full) + return NULL; + + /* + Take last_token 2 tokens collected till now. These tokens will be used + in reduce for normalisation. Make sure not to consider ID tokens in reduce. + */ + uint last_token; + uint last_token2; + + peek_last_two_tokens(digest_storage, state->m_last_id_index, + &last_token, &last_token2); + + switch (token) + { + case BIN_NUM: + case DECIMAL_NUM: + case FLOAT_NUM: + case HEX_NUM: + case LEX_HOSTNAME: + case LONG_NUM: + case NUM: + case TEXT_STRING: + case NCHAR_STRING: + case ULONGLONG_NUM: + { + /* + REDUCE: + TOK_PFS_GENERIC_VALUE := BIN_NUM | DECIMAL_NUM | ... | ULONGLONG_NUM + */ + token= TOK_PFS_GENERIC_VALUE; + + if ((last_token2 == TOK_PFS_GENERIC_VALUE || + last_token2 == TOK_PFS_GENERIC_VALUE_LIST) && + (last_token == ',')) + { + /* + REDUCE: + TOK_PFS_GENERIC_VALUE_LIST := + TOK_PFS_GENERIC_VALUE ',' TOK_PFS_GENERIC_VALUE + + REDUCE: + TOK_PFS_GENERIC_VALUE_LIST := + TOK_PFS_GENERIC_VALUE_LIST ',' TOK_PFS_GENERIC_VALUE + */ + digest_storage->m_byte_count-= 2*PFS_SIZE_OF_A_TOKEN; + token= TOK_PFS_GENERIC_VALUE_LIST; + } + /* + Add this token or the resulting reduce to digest storage. + */ + store_token(digest_storage, token); + break; + } + case ')': + { + if (last_token == TOK_PFS_GENERIC_VALUE && + last_token2 == '(') + { + /* + REDUCE: + TOK_PFS_ROW_SINGLE_VALUE := + '(' TOK_PFS_GENERIC_VALUE ')' + */ + digest_storage->m_byte_count-= 2*PFS_SIZE_OF_A_TOKEN; + token= TOK_PFS_ROW_SINGLE_VALUE; + + /* Read last two tokens again */ + peek_last_two_tokens(digest_storage, state->m_last_id_index, + &last_token, &last_token2); + + if ((last_token2 == TOK_PFS_ROW_SINGLE_VALUE || + last_token2 == TOK_PFS_ROW_SINGLE_VALUE_LIST) && + (last_token == ',')) + { + /* + REDUCE: + TOK_PFS_ROW_SINGLE_VALUE_LIST := + TOK_PFS_ROW_SINGLE_VALUE ',' TOK_PFS_ROW_SINGLE_VALUE + + REDUCE: + TOK_PFS_ROW_SINGLE_VALUE_LIST := + TOK_PFS_ROW_SINGLE_VALUE_LIST ',' TOK_PFS_ROW_SINGLE_VALUE + */ + digest_storage->m_byte_count-= 2*PFS_SIZE_OF_A_TOKEN; + token= TOK_PFS_ROW_SINGLE_VALUE_LIST; + } + } + else if (last_token == TOK_PFS_GENERIC_VALUE_LIST && + last_token2 == '(') + { + /* + REDUCE: + TOK_PFS_ROW_MULTIPLE_VALUE := + '(' TOK_PFS_GENERIC_VALUE_LIST ')' + */ + digest_storage->m_byte_count-= 2*PFS_SIZE_OF_A_TOKEN; + token= TOK_PFS_ROW_MULTIPLE_VALUE; + + /* Read last two tokens again */ + peek_last_two_tokens(digest_storage, state->m_last_id_index, + &last_token, &last_token2); + + if ((last_token2 == TOK_PFS_ROW_MULTIPLE_VALUE || + last_token2 == TOK_PFS_ROW_MULTIPLE_VALUE_LIST) && + (last_token == ',')) + { + /* + REDUCE: + TOK_PFS_ROW_MULTIPLE_VALUE_LIST := + TOK_PFS_ROW_MULTIPLE_VALUE ',' TOK_PFS_ROW_MULTIPLE_VALUE + + REDUCE: + TOK_PFS_ROW_MULTIPLE_VALUE_LIST := + TOK_PFS_ROW_MULTIPLE_VALUE_LIST ',' TOK_PFS_ROW_MULTIPLE_VALUE + */ + digest_storage->m_byte_count-= 2*PFS_SIZE_OF_A_TOKEN; + token= TOK_PFS_ROW_MULTIPLE_VALUE_LIST; + } + } + /* + Add this token or the resulting reduce to digest storage. + */ + store_token(digest_storage, token); + break; + } + case IDENT: + case IDENT_QUOTED: + { + LEX_YYSTYPE *lex_token= (LEX_YYSTYPE*) yylval; + char *yytext= lex_token->lex_str.str; + int yylen= lex_token->lex_str.length; + + /* Add this token and identifier string to digest storage. */ + store_token_identifier(digest_storage, token, yylen, yytext); + + /* Update the index of last identifier found. */ + state->m_last_id_index= digest_storage->m_byte_count; + break; + } + default: + { + /* Add this token to digest storage. */ + store_token(digest_storage, token); + break; + } + } + + return locker; +} diff --git a/storage/perfschema/pfs_digest.h b/storage/perfschema/pfs_digest.h new file mode 100644 index 00000000000..2646596171c --- /dev/null +++ b/storage/perfschema/pfs_digest.h @@ -0,0 +1,221 @@ +/* Copyright (c) 2011, 2012, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef PFS_DIGEST_H +#define PFS_DIGEST_H + +/** + @file storage/perfschema/pfs_digest.h + Statement Digest data structures (declarations). +*/ + +#include "pfs_column_types.h" +#include "lf.h" +#include "pfs_stat.h" + +#define PFS_SIZE_OF_A_TOKEN 2 + +extern bool flag_statements_digest; +extern ulong digest_max; +extern ulong digest_lost; +struct PFS_thread; + +/* Fixed, per MD5 hash. */ +#define PFS_MD5_SIZE 16 + +/** + Structure to store a MD5 hash value (digest) for a statement. +*/ +struct PFS_digest_hash +{ + unsigned char m_md5[PFS_MD5_SIZE]; +}; + +/** A statement digest stat record. */ +struct PFS_statements_digest_stat +{ + /** + Digest MD5 Hash. + */ + PFS_digest_hash m_digest_hash; + + /** + Digest Storage. + */ + PSI_digest_storage m_digest_storage; + + /** + Statement stat. + */ + PFS_statement_stat m_stat; + + /** + First Seen/last seen. + */ + ulonglong m_first_seen; + ulonglong m_last_seen; + + /** Reset data for this record. */ + void reset_data(); + /** Reset data and remove index for this record. */ + void reset_index(PFS_thread *thread); +}; + +int init_digest(const PFS_global_param *param); +void cleanup_digest(); + +int init_digest_hash(void); +void cleanup_digest_hash(void); +PFS_statement_stat* find_or_create_digest(PFS_thread*, + PSI_digest_storage*); + +void get_digest_text(char* digest_text, PSI_digest_storage*); + +void reset_esms_by_digest(); + +/* Exposing the data directly, for iterators. */ +extern PFS_statements_digest_stat *statements_digest_stat_array; + +/* Instrumentation callbacks for pfs.cc */ + +struct PSI_digest_locker* pfs_digest_start_v1(PSI_statement_locker *locker); +PSI_digest_locker* pfs_digest_add_token_v1(PSI_digest_locker *locker, + uint token, + OPAQUE_LEX_YYSTYPE *yylval); + +static inline void digest_reset(PSI_digest_storage *digest) +{ + digest->m_full= false; + digest->m_byte_count= 0; +} + +static inline void digest_copy(PSI_digest_storage *to, const PSI_digest_storage *from) +{ + if (from->m_byte_count > 0) + { + to->m_full= from->m_full; + to->m_byte_count= from->m_byte_count; + DBUG_ASSERT(to->m_byte_count <= PSI_MAX_DIGEST_STORAGE_SIZE); + memcpy(to->m_token_array, from->m_token_array, to->m_byte_count); + } + else + { + DBUG_ASSERT(! from->m_full); + DBUG_ASSERT(from->m_byte_count == 0); + to->m_full= false; + to->m_byte_count= 0; + } +} + +/** + Function to read a single token from token array. +*/ +inline int read_token(PSI_digest_storage *digest_storage, + int index, uint *tok) +{ + DBUG_ASSERT(index <= digest_storage->m_byte_count); + DBUG_ASSERT(digest_storage->m_byte_count <= PSI_MAX_DIGEST_STORAGE_SIZE); + + if (index + PFS_SIZE_OF_A_TOKEN <= digest_storage->m_byte_count) + { + unsigned char *src= & digest_storage->m_token_array[index]; + *tok= src[0] | (src[1] << 8); + return index + PFS_SIZE_OF_A_TOKEN; + } + + /* The input byte stream is exhausted. */ + *tok= 0; + return PSI_MAX_DIGEST_STORAGE_SIZE + 1; +} + +/** + Function to store a single token in token array. +*/ +inline void store_token(PSI_digest_storage* digest_storage, uint token) +{ + DBUG_ASSERT(digest_storage->m_byte_count >= 0); + DBUG_ASSERT(digest_storage->m_byte_count <= PSI_MAX_DIGEST_STORAGE_SIZE); + + if (digest_storage->m_byte_count + PFS_SIZE_OF_A_TOKEN <= PSI_MAX_DIGEST_STORAGE_SIZE) + { + unsigned char* dest= & digest_storage->m_token_array[digest_storage->m_byte_count]; + dest[0]= token & 0xff; + dest[1]= (token >> 8) & 0xff; + digest_storage->m_byte_count+= PFS_SIZE_OF_A_TOKEN; + } + else + { + digest_storage->m_full= true; + } +} + +/** + Function to read an identifier from token array. +*/ +inline int read_identifier(PSI_digest_storage* digest_storage, + int index, char ** id_string, int *id_length) +{ + int new_index; + DBUG_ASSERT(index <= digest_storage->m_byte_count); + DBUG_ASSERT(digest_storage->m_byte_count <= PSI_MAX_DIGEST_STORAGE_SIZE); + + /* + token + length + string are written in an atomic way, + so we do always expect a length + string here + */ + unsigned char *src= & digest_storage->m_token_array[index]; + uint length= src[0] | (src[1] << 8); + *id_string= (char *) (src + 2); + *id_length= length; + + new_index= index + PFS_SIZE_OF_A_TOKEN + length; + DBUG_ASSERT(new_index <= digest_storage->m_byte_count); + return new_index; +} + +/** + Function to store an identifier in token array. +*/ +inline void store_token_identifier(PSI_digest_storage* digest_storage, + uint token, + uint id_length, const char *id_name) +{ + DBUG_ASSERT(digest_storage->m_byte_count >= 0); + DBUG_ASSERT(digest_storage->m_byte_count <= PSI_MAX_DIGEST_STORAGE_SIZE); + + uint bytes_needed= 2 * PFS_SIZE_OF_A_TOKEN + id_length; + if (digest_storage->m_byte_count + bytes_needed <= PSI_MAX_DIGEST_STORAGE_SIZE) + { + unsigned char* dest= & digest_storage->m_token_array[digest_storage->m_byte_count]; + /* Write the token */ + dest[0]= token & 0xff; + dest[1]= (token >> 8) & 0xff; + /* Write the string length */ + dest[2]= id_length & 0xff; + dest[3]= (id_length >> 8) & 0xff; + /* Write the string data */ + if (id_length > 0) + { + strncpy((char *)(dest + 4), id_name, id_length); + } + digest_storage->m_byte_count+= bytes_needed; + } + else + { + digest_storage->m_full= true; + } +} + +#endif diff --git a/storage/perfschema/pfs_engine_table.cc b/storage/perfschema/pfs_engine_table.cc index 38f6df3003d..884a0f9e848 100644 --- a/storage/perfschema/pfs_engine_table.cc +++ b/storage/perfschema/pfs_engine_table.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 @@ -18,24 +18,66 @@ Performance schema tables (implementation). */ +#include "my_global.h" +#include "my_pthread.h" #include "pfs_engine_table.h" #include "table_events_waits.h" +#include "table_setup_actors.h" #include "table_setup_consumers.h" #include "table_setup_instruments.h" +#include "table_setup_objects.h" #include "table_setup_timers.h" #include "table_performance_timers.h" -#include "table_threads.h" #include "table_events_waits_summary.h" +#include "table_ews_by_thread_by_event_name.h" #include "table_ews_global_by_event_name.h" +#include "table_host_cache.h" +#include "table_os_global_by_type.h" #include "table_sync_instances.h" #include "table_file_instances.h" -#include "table_file_summary.h" +#include "table_file_summary_by_instance.h" +#include "table_file_summary_by_event_name.h" +#include "table_threads.h" + +#include "table_ews_by_host_by_event_name.h" +#include "table_ews_by_user_by_event_name.h" +#include "table_ews_by_account_by_event_name.h" +#include "table_tiws_by_index_usage.h" +#include "table_tiws_by_table.h" +#include "table_tlws_by_table.h" + +#include "table_events_stages.h" +#include "table_esgs_by_thread_by_event_name.h" +#include "table_esgs_by_host_by_event_name.h" +#include "table_esgs_by_user_by_event_name.h" +#include "table_esgs_by_account_by_event_name.h" +#include "table_esgs_global_by_event_name.h" + +#include "table_events_statements.h" +#include "table_esms_by_thread_by_event_name.h" +#include "table_esms_by_host_by_event_name.h" +#include "table_esms_by_user_by_event_name.h" +#include "table_esms_by_account_by_event_name.h" +#include "table_esms_global_by_event_name.h" +#include "table_esms_by_digest.h" + +#include "table_users.h" +#include "table_accounts.h" +#include "table_hosts.h" + +#include "table_socket_instances.h" +#include "table_socket_summary_by_instance.h" +#include "table_socket_summary_by_event_name.h" /* For show status */ #include "pfs_column_values.h" +#include "pfs_instr_class.h" #include "pfs_instr.h" +#include "pfs_setup_actor.h" +#include "pfs_setup_object.h" #include "pfs_global.h" +#include "pfs_digest.h" #include "sql_base.h" // close_thread_tables #include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT @@ -47,23 +89,62 @@ static PFS_engine_table_share *all_shares[]= { + &table_cond_instances::m_share, &table_events_waits_current::m_share, &table_events_waits_history::m_share, &table_events_waits_history_long::m_share, - &table_setup_consumers::m_share, - &table_setup_instruments::m_share, - &table_setup_timers::m_share, - &table_performance_timers::m_share, - &table_threads::m_share, - &table_events_waits_summary_by_thread_by_event_name::m_share, + &table_ews_by_host_by_event_name::m_share, &table_events_waits_summary_by_instance::m_share, + &table_ews_by_thread_by_event_name::m_share, + &table_ews_by_user_by_event_name::m_share, + &table_ews_by_account_by_event_name::m_share, &table_ews_global_by_event_name::m_share, + &table_file_instances::m_share, &table_file_summary_by_event_name::m_share, &table_file_summary_by_instance::m_share, +#ifdef QQ_NOT_YET + &table_host_cache::m_share, +#endif &table_mutex_instances::m_share, + &table_os_global_by_type::m_share, + &table_performance_timers::m_share, &table_rwlock_instances::m_share, - &table_cond_instances::m_share, - &table_file_instances::m_share, + &table_setup_actors::m_share, + &table_setup_consumers::m_share, + &table_setup_instruments::m_share, + &table_setup_objects::m_share, + &table_setup_timers::m_share, + &table_tiws_by_index_usage::m_share, + &table_tiws_by_table::m_share, + &table_tlws_by_table::m_share, + &table_threads::m_share, + + &table_events_stages_current::m_share, + &table_events_stages_history::m_share, + &table_events_stages_history_long::m_share, + &table_esgs_by_thread_by_event_name::m_share, + &table_esgs_by_account_by_event_name::m_share, + &table_esgs_by_user_by_event_name::m_share, + &table_esgs_by_host_by_event_name::m_share, + &table_esgs_global_by_event_name::m_share, + + &table_events_statements_current::m_share, + &table_events_statements_history::m_share, + &table_events_statements_history_long::m_share, + &table_esms_by_thread_by_event_name::m_share, + &table_esms_by_account_by_event_name::m_share, + &table_esms_by_user_by_event_name::m_share, + &table_esms_by_host_by_event_name::m_share, + &table_esms_global_by_event_name::m_share, + &table_esms_by_digest::m_share, + + &table_users::m_share, + &table_accounts::m_share, + &table_hosts::m_share, + + &table_socket_instances::m_share, + &table_socket_summary_by_instance::m_share, + &table_socket_summary_by_event_name::m_share, NULL }; @@ -78,13 +159,14 @@ void PFS_engine_table_share::check_all_tables(THD *thd) DBUG_EXECUTE_IF("tampered_perfschema_table1", { /* Hack SETUP_INSTRUMENT, incompatible change. */ - all_shares[4]->m_field_def->count++; + all_shares[20]->m_field_def->count++; }); for (current= &all_shares[0]; (*current) != NULL; current++) (*current)->check_one_table(thd); } +/** Error reporting for schema integrity checks. */ class PFS_check_intact : public Table_check_intact { protected: @@ -169,6 +251,42 @@ void PFS_engine_table_share::delete_all_locks(void) thr_lock_delete((*current)->m_thr_lock_ptr); } +ha_rows PFS_engine_table_share::get_row_count(void) const +{ + /* If available, count the exact number or records */ + if (m_get_row_count) + return m_get_row_count(); + /* Otherwise, return an estimate */ + return m_records; +} + +int PFS_engine_table_share::write_row(TABLE *table, unsigned char *buf, + Field **fields) const +{ + my_bitmap_map *org_bitmap; + + /* + Make sure the table structure is as expected before mapping + hard wired columns in m_write_row. + */ + if (! m_checked) + { + return HA_ERR_TABLE_NEEDS_UPGRADE; + } + + if (m_write_row == NULL) + { + return HA_ERR_WRONG_COMMAND; + } + + /* We internally read from Fields to support the write interface */ + org_bitmap= dbug_tmp_use_all_columns(table, table->read_set); + int result= m_write_row(table, buf, fields); + dbug_tmp_restore_column_map(table->read_set, org_bitmap); + + return result; +} + static int compare_table_names(const char *name1, const char *name2) { /* @@ -288,6 +406,36 @@ int PFS_engine_table::update_row(TABLE *table, return result; } +int PFS_engine_table::delete_row(TABLE *table, + const unsigned char *buf, + Field **fields) +{ + my_bitmap_map *org_bitmap; + + /* + Make sure the table structure is as expected before mapping + hard wired columns in delete_row_values. + */ + if (! m_share_ptr->m_checked) + { + return HA_ERR_TABLE_NEEDS_UPGRADE; + } + + /* We internally read from Fields to support the delete interface */ + org_bitmap= dbug_tmp_use_all_columns(table, table->read_set); + int result= delete_row_values(table, buf, fields); + dbug_tmp_restore_column_map(table->read_set, org_bitmap); + + return result; +} + +int PFS_engine_table::delete_row_values(TABLE *, + const unsigned char *, + Field **) +{ + return HA_ERR_WRONG_COMMAND; +} + /** Get the position of the current row. @param [out] ref position @@ -306,6 +454,19 @@ void PFS_engine_table::set_position(const void *ref) memcpy(m_pos_ptr, ref, m_share_ptr->m_ref_length); } +/** + Get the timer normalizer and class type for the current row. + @param [in] instr_class class +*/ +void PFS_engine_table::get_normalizer(PFS_instr_class *instr_class) +{ + if (instr_class->m_type != m_class_type) + { + m_normalizer= time_normalizer::get(*instr_class->m_timer); + m_class_type= instr_class->m_type; + } +} + void PFS_engine_table::set_field_ulong(Field *f, ulong value) { DBUG_ASSERT(f->real_type() == MYSQL_TYPE_LONG); @@ -320,6 +481,14 @@ void PFS_engine_table::set_field_ulonglong(Field *f, ulonglong value) f2->store(value, true); } +void PFS_engine_table::set_field_char_utf8(Field *f, const char* str, + uint len) +{ + DBUG_ASSERT(f->real_type() == MYSQL_TYPE_STRING); + Field_string *f2= (Field_string*) f; + f2->store(str, len, &my_charset_utf8_bin); +} + void PFS_engine_table::set_field_varchar_utf8(Field *f, const char* str, uint len) { @@ -328,6 +497,14 @@ void PFS_engine_table::set_field_varchar_utf8(Field *f, const char* str, f2->store(str, len, &my_charset_utf8_bin); } +void PFS_engine_table::set_field_longtext_utf8(Field *f, const char* str, + uint len) +{ + DBUG_ASSERT(f->real_type() == MYSQL_TYPE_BLOB); + Field_blob *f2= (Field_blob*) f; + f2->store(str, len, &my_charset_utf8_bin); +} + void PFS_engine_table::set_field_enum(Field *f, ulonglong value) { DBUG_ASSERT(f->real_type() == MYSQL_TYPE_ENUM); @@ -335,6 +512,13 @@ void PFS_engine_table::set_field_enum(Field *f, ulonglong value) f2->store_type(value); } +void PFS_engine_table::set_field_timestamp(Field *f, ulonglong value) +{ + DBUG_ASSERT(f->real_type() == MYSQL_TYPE_TIMESTAMP); + Field_timestamp *f2= (Field_timestamp*) f; + f2->store_TIME((long)(value / 1000000), (value % 1000000)); +} + ulonglong PFS_engine_table::get_field_enum(Field *f) { DBUG_ASSERT(f->real_type() == MYSQL_TYPE_ENUM); @@ -342,6 +526,24 @@ ulonglong PFS_engine_table::get_field_enum(Field *f) return f2->val_int(); } +String* +PFS_engine_table::get_field_char_utf8(Field *f, String *val) +{ + DBUG_ASSERT(f->real_type() == MYSQL_TYPE_STRING); + Field_string *f2= (Field_string*) f; + val= f2->val_str(NULL, val); + return val; +} + +String* +PFS_engine_table::get_field_varchar_utf8(Field *f, String *val) +{ + DBUG_ASSERT(f->real_type() == MYSQL_TYPE_VARCHAR); + Field_varstring *f2= (Field_varstring*) f; + val= f2->val_str(NULL, val); + return val; +} + int PFS_engine_table::update_row_values(TABLE *, const unsigned char *, unsigned char *, @@ -350,6 +552,7 @@ int PFS_engine_table::update_row_values(TABLE *, return HA_ERR_WRONG_COMMAND; } +/** Implementation of internal ACL checks, for the performance schema. */ class PFS_internal_schema_access : public ACL_internal_schema_access { public: @@ -533,11 +736,11 @@ bool pfs_show_status(handlerton *hton, THD *thd, switch (i){ case 0: name= "events_waits_current.row_size"; - size= sizeof(PFS_wait_locker); + size= sizeof(PFS_events_waits); break; case 1: name= "events_waits_current.row_count"; - size= LOCKER_STACK_SIZE * thread_max; + size= WAIT_STACK_SIZE * thread_max; break; case 2: name= "events_waits_history.row_size"; @@ -711,15 +914,15 @@ bool pfs_show_status(handlerton *hton, THD *thd, break; case 41: name= "events_waits_summary_by_thread_by_event_name.row_size"; - size= sizeof(PFS_single_stat_chain); + size= sizeof(PFS_single_stat); break; case 42: name= "events_waits_summary_by_thread_by_event_name.row_count"; - size= thread_max * instr_class_per_thread; + size= thread_max * wait_class_max; break; case 43: name= "events_waits_summary_by_thread_by_event_name.memory"; - size= thread_max * instr_class_per_thread * sizeof(PFS_single_stat_chain); + size= thread_max * wait_class_max * sizeof(PFS_single_stat); total_memory+= size; break; case 44: @@ -748,11 +951,390 @@ bool pfs_show_status(handlerton *hton, THD *thd, size= table_max * sizeof(PFS_table); total_memory+= size; break; + case 50: + name= "setup_actors.row_size"; + size= sizeof(PFS_setup_actor); + break; + case 51: + name= "setup_actors.row_count"; + size= setup_actor_max; + break; + case 52: + name= "setup_actors.memory"; + size= setup_actor_max * sizeof(PFS_setup_actor); + total_memory+= size; + break; + case 53: + name= "setup_objects.row_size"; + size= sizeof(PFS_setup_object); + break; + case 54: + name= "setup_objects.row_count"; + size= setup_object_max; + break; + case 55: + name= "setup_objects.memory"; + size= setup_object_max * sizeof(PFS_setup_object); + total_memory+= size; + break; + case 56: + name= "events_waits_summary_global_by_event_name.row_size"; + size= sizeof(PFS_single_stat); + break; + case 57: + name= "events_waits_summary_global_by_event_name.row_count"; + size= wait_class_max; + break; + case 58: + name= "events_waits_summary_global_by_event_name.memory"; + size= wait_class_max * sizeof(PFS_single_stat); + total_memory+= size; + break; + case 59: + name= "(pfs_account).row_size"; + size= sizeof(PFS_account); + break; + case 60: + name= "(pfs_account).row_count"; + size= account_max; + break; + case 61: + name= "(pfs_account).memory"; + size= account_max * sizeof(PFS_account); + total_memory+= size; + break; + case 62: + name= "events_waits_summary_by_account_by_event_name.row_size"; + size= sizeof(PFS_single_stat); + break; + case 63: + name= "events_waits_summary_by_account_by_event_name.row_count"; + size= account_max * wait_class_max; + break; + case 64: + name= "events_waits_summary_by_account_by_event_name.memory"; + size= account_max * wait_class_max * sizeof(PFS_single_stat); + total_memory+= size; + break; + case 65: + name= "events_waits_summary_by_user_by_event_name.row_size"; + size= sizeof(PFS_single_stat); + break; + case 66: + name= "events_waits_summary_by_user_by_event_name.row_count"; + size= user_max * wait_class_max; + break; + case 67: + name= "events_waits_summary_by_user_by_event_name.memory"; + size= user_max * wait_class_max * sizeof(PFS_single_stat); + total_memory+= size; + break; + case 68: + name= "events_waits_summary_by_host_by_event_name.row_size"; + size= sizeof(PFS_single_stat); + break; + case 69: + name= "events_waits_summary_by_host_by_event_name.row_count"; + size= host_max * wait_class_max; + break; + case 70: + name= "events_waits_summary_by_host_by_event_name.memory"; + size= host_max * wait_class_max * sizeof(PFS_single_stat); + total_memory+= size; + break; + case 71: + name= "(pfs_user).row_size"; + size= sizeof(PFS_user); + break; + case 72: + name= "(pfs_user).row_count"; + size= user_max; + break; + case 73: + name= "(pfs_user).memory"; + size= user_max * sizeof(PFS_user); + total_memory+= size; + break; + case 74: + name= "(pfs_host).row_size"; + size= sizeof(PFS_host); + break; + case 75: + name= "(pfs_host).row_count"; + size= host_max; + break; + case 76: + name= "(pfs_host).memory"; + size= host_max * sizeof(PFS_host); + total_memory+= size; + break; + case 77: + name= "(pfs_stage_class).row_size"; + size= sizeof(PFS_stage_class); + break; + case 78: + name= "(pfs_stage_class).row_count"; + size= stage_class_max; + break; + case 79: + name= "(pfs_stage_class).memory"; + size= stage_class_max * sizeof(PFS_stage_class); + total_memory+= size; + break; + case 80: + name= "events_stages_history.row_size"; + size= sizeof(PFS_events_stages); + break; + case 81: + name= "events_stages_history.row_count"; + size= events_stages_history_per_thread * thread_max; + break; + case 82: + name= "events_stages_history.memory"; + size= events_stages_history_per_thread * thread_max + * sizeof(PFS_events_stages); + total_memory+= size; + break; + case 83: + name= "events_stages_history_long.row_size"; + size= sizeof(PFS_events_stages); + break; + case 84: + name= "events_stages_history_long.row_count"; + size= events_stages_history_long_size; + break; + case 85: + name= "events_stages_history_long.memory"; + size= events_stages_history_long_size * sizeof(PFS_events_stages); + total_memory+= size; + break; + case 86: + name= "events_stages_summary_by_thread_by_event_name.row_size"; + size= sizeof(PFS_stage_stat); + break; + case 87: + name= "events_stages_summary_by_thread_by_event_name.row_count"; + size= thread_max * stage_class_max; + break; + case 88: + name= "events_stages_summary_by_thread_by_event_name.memory"; + size= thread_max * stage_class_max * sizeof(PFS_stage_stat); + total_memory+= size; + break; + case 89: + name= "events_stages_summary_global_by_event_name.row_size"; + size= sizeof(PFS_stage_stat); + break; + case 90: + name= "events_stages_summary_global_by_event_name.row_count"; + size= stage_class_max; + break; + case 91: + name= "events_stages_summary_global_by_event_name.memory"; + size= stage_class_max * sizeof(PFS_stage_stat); + total_memory+= size; + break; + case 92: + name= "events_stages_summary_by_account_by_event_name.row_size"; + size= sizeof(PFS_stage_stat); + break; + case 93: + name= "events_stages_summary_by_account_by_event_name.row_count"; + size= account_max * stage_class_max; + break; + case 94: + name= "events_stages_summary_by_account_by_event_name.memory"; + size= account_max * stage_class_max * sizeof(PFS_stage_stat); + total_memory+= size; + break; + case 95: + name= "events_stages_summary_by_user_by_event_name.row_size"; + size= sizeof(PFS_stage_stat); + break; + case 96: + name= "events_stages_summary_by_user_by_event_name.row_count"; + size= user_max * stage_class_max; + break; + case 97: + name= "events_stages_summary_by_user_by_event_name.memory"; + size= user_max * stage_class_max * sizeof(PFS_stage_stat); + total_memory+= size; + break; + case 98: + name= "events_stages_summary_by_host_by_event_name.row_size"; + size= sizeof(PFS_stage_stat); + break; + case 99: + name= "events_stages_summary_by_host_by_event_name.row_count"; + size= host_max * stage_class_max; + break; + case 100: + name= "events_stages_summary_by_host_by_event_name.memory"; + size= host_max * stage_class_max * sizeof(PFS_stage_stat); + total_memory+= size; + break; + case 101: + name= "(pfs_statement_class).row_size"; + size= sizeof(PFS_statement_class); + break; + case 102: + name= "(pfs_statement_class).row_count"; + size= statement_class_max; + break; + case 103: + name= "(pfs_statement_class).memory"; + size= statement_class_max * sizeof(PFS_statement_class); + total_memory+= size; + break; + case 104: + name= "events_statements_history.row_size"; + size= sizeof(PFS_events_statements); + break; + case 105: + name= "events_statements_history.row_count"; + size= events_statements_history_per_thread * thread_max; + break; + case 106: + name= "events_statements_history.memory"; + size= events_statements_history_per_thread * thread_max + * sizeof(PFS_events_statements); + total_memory+= size; + break; + case 107: + name= "events_statements_history_long.row_size"; + size= sizeof(PFS_events_statements); + break; + case 108: + name= "events_statements_history_long.row_count"; + size= events_statements_history_long_size; + break; + case 109: + name= "events_statements_history_long.memory"; + size= events_statements_history_long_size * sizeof(PFS_events_statements); + total_memory+= size; + break; + case 110: + name= "events_statements_summary_by_thread_by_event_name.row_size"; + size= sizeof(PFS_statement_stat); + break; + case 111: + name= "events_statements_summary_by_thread_by_event_name.row_count"; + size= thread_max * statement_class_max; + break; + case 112: + name= "events_statements_summary_by_thread_by_event_name.memory"; + size= thread_max * statement_class_max * sizeof(PFS_statement_stat); + total_memory+= size; + break; + case 113: + name= "events_statements_summary_global_by_event_name.row_size"; + size= sizeof(PFS_statement_stat); + break; + case 114: + name= "events_statements_summary_global_by_event_name.row_count"; + size= statement_class_max; + break; + case 115: + name= "events_statements_summary_global_by_event_name.memory"; + size= statement_class_max * sizeof(PFS_statement_stat); + total_memory+= size; + break; + case 116: + name= "events_statements_summary_by_account_by_event_name.row_size"; + size= sizeof(PFS_statement_stat); + break; + case 117: + name= "events_statements_summary_by_account_by_event_name.row_count"; + size= account_max * statement_class_max; + break; + case 118: + name= "events_statements_summary_by_account_by_event_name.memory"; + size= account_max * statement_class_max * sizeof(PFS_statement_stat); + total_memory+= size; + break; + case 119: + name= "events_statements_summary_by_user_by_event_name.row_size"; + size= sizeof(PFS_statement_stat); + break; + case 120: + name= "events_statements_summary_by_user_by_event_name.row_count"; + size= user_max * statement_class_max; + break; + case 121: + name= "events_statements_summary_by_user_by_event_name.memory"; + size= user_max * statement_class_max * sizeof(PFS_statement_stat); + total_memory+= size; + break; + case 122: + name= "events_statements_summary_by_host_by_event_name.row_size"; + size= sizeof(PFS_statement_stat); + break; + case 123: + name= "events_statements_summary_by_host_by_event_name.row_count"; + size= host_max * statement_class_max; + break; + case 124: + name= "events_statements_summary_by_host_by_event_name.memory"; + size= host_max * statement_class_max * sizeof(PFS_statement_stat); + total_memory+= size; + break; + case 125: + name= "events_statements_current.row_size"; + size= sizeof(PFS_events_statements); + break; + case 126: + name= "events_statements_current.row_count"; + size= thread_max * statement_stack_max; + break; + case 127: + name= "events_statements_current.memory"; + size= thread_max * statement_stack_max * sizeof(PFS_events_statements); + total_memory+= size; + break; + case 128: + name= "(pfs_socket_class).row_size"; + size= sizeof(PFS_socket_class); + break; + case 129: + name= "(pfs_socket_class).row_count"; + size= socket_class_max; + break; + case 130: + name= "(pfs_socket_class).memory"; + size= socket_class_max * sizeof(PFS_socket_class); + total_memory+= size; + break; + case 131: + name= "socket_instances.row_size"; + size= sizeof(PFS_socket); + break; + case 132: + name= "socket_instances.row_count"; + size= socket_max; + break; + case 133: + name= "socket_instances.memory"; + size= socket_max * sizeof(PFS_socket); + total_memory+= size; + break; + case 134: + name= "events_statements_summary_by_digest.row_size"; + size= sizeof(PFS_statements_digest_stat); + break; + case 135: + name= "events_statements_summary_by_digest.row_count"; + size= digest_max; + break; + case 136: + name= "events_statements_summary_by_digest.memory"; + size= digest_max * sizeof(PFS_statements_digest_stat); + total_memory+= size; + break; /* This case must be last, for aggregation in total_memory. */ - case 50: + case 137: name= "performance_schema.memory"; size= total_memory; /* This will fail if something is not advertised here */ @@ -777,4 +1359,3 @@ end: /** @} */ - diff --git a/storage/perfschema/pfs_engine_table.h b/storage/perfschema/pfs_engine_table.h index ec73c5a3688..40f5404d0b7 100644 --- a/storage/perfschema/pfs_engine_table.h +++ b/storage/perfschema/pfs_engine_table.h @@ -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 @@ -22,8 +22,10 @@ Performance schema tables (declarations). */ +#include "pfs_instr_class.h" class Field; struct PFS_engine_table_share; +struct time_normalizer; /** @addtogroup Performance_schema_engine @@ -46,6 +48,18 @@ public: int update_row(TABLE *table, const unsigned char *old_buf, unsigned char *new_buf, Field **fields); + /** + Delete a row from this table. + @param table Table handle + @param buf the row buffer to delete + @param fields Table fields + @return 0 on success + */ + int delete_row(TABLE *table, const unsigned char *buf, Field **fields); + + /** Initialize table scan. */ + virtual int rnd_init(bool scan){return 0;}; + /** Fetch the next row in this cursor. */ virtual int rnd_next(void)= 0; /** @@ -56,12 +70,82 @@ public: void get_position(void *ref); void set_position(const void *ref); + /** Reset the cursor position to the beginning of the table. */ virtual void reset_position(void)= 0; + /** Get the normalizer and class type for the current row. */ + void get_normalizer(PFS_instr_class *instr_class); + /** Destructor. */ virtual ~PFS_engine_table() {} + /** + Helper, assign a value to a ulong field. + @param f the field to set + @param value the value to assign + */ + static void set_field_ulong(Field *f, ulong value); + /** + Helper, assign a value to a ulonglong field. + @param f the field to set + @param value the value to assign + */ + static void set_field_ulonglong(Field *f, ulonglong value); + /** + Helper, assign a value to a char utf8 field. + @param f the field to set + @param str the string to assign + @param len the length of the string to assign + */ + static void set_field_char_utf8(Field *f, const char *str, uint len); + /** + Helper, assign a value to a varchar utf8 field. + @param f the field to set + @param str the string to assign + @param len the length of the string to assign + */ + static void set_field_varchar_utf8(Field *f, const char *str, uint len); + /** + Helper, assign a value to a longtext utf8 field. + @param f the field to set + @param str the string to assign + @param len the length of the string to assign + */ + static void set_field_longtext_utf8(Field *f, const char *str, uint len); + /** + Helper, assign a value to an enum field. + @param f the field to set + @param value the value to assign + */ + static void set_field_enum(Field *f, ulonglong value); + /** + Helper, assign a value to a timestamp field. + @param f the field to set + @param value the value to assign + */ + static void set_field_timestamp(Field *f, ulonglong value); + /** + Helper, read a value from an enum field. + @param f the field to read + @return the field value + */ + static ulonglong get_field_enum(Field *f); + /** + Helper, read a value from a char utf8 field. + @param f the field to read + @param[out] val the field value + @return the field value + */ + static String *get_field_char_utf8(Field *f, String *val); + /** + Helper, read a value from a varchar utf8 field. + @param f the field to read + @param[out] val the field value + @return the field value + */ + static String *get_field_varchar_utf8(Field *f, String *val); + protected: /** Read the current row values. @@ -84,25 +168,32 @@ protected: unsigned char *new_buf, Field **fields); /** + Delete a row. + @param table Table handle + @param buf Row buffer + @param fields Table fields + */ + virtual int delete_row_values(TABLE *table, const unsigned char *buf, + Field **fields); + + /** Constructor. @param share table share @param pos address of the m_pos position member */ PFS_engine_table(const PFS_engine_table_share *share, void *pos) - : m_share_ptr(share), m_pos_ptr(pos) + : m_share_ptr(share), m_pos_ptr(pos), + m_normalizer(NULL), m_class_type(PFS_CLASS_NONE) {} - void set_field_ulong(Field *f, ulong value); - void set_field_ulonglong(Field *f, ulonglong value); - void set_field_varchar_utf8(Field *f, const char* str, uint len); - void set_field_enum(Field *f, ulonglong value); - - ulonglong get_field_enum(Field *f); - /** Table share. */ const PFS_engine_table_share *m_share_ptr; /** Opaque pointer to the m_pos position of this cursor. */ void *m_pos_ptr; + /** Current normalizer */ + time_normalizer *m_normalizer; + /** Current class type */ + enum PFS_class_type m_class_type; }; /** Callback to open a table. */ @@ -112,6 +203,8 @@ typedef int (*pfs_write_row_t)(TABLE *table, unsigned char *buf, Field **fields); /** Callback to delete all rows. */ typedef int (*pfs_delete_all_rows_t)(void); +/** Callback to get a row count. */ +typedef ha_rows (*pfs_get_row_count_t)(void); /** A PERFORMANCE_SCHEMA table share. @@ -123,6 +216,10 @@ struct PFS_engine_table_share void check_one_table(THD *thd); static void init_all_locks(void); static void delete_all_locks(void); + /** Get the row count. */ + ha_rows get_row_count(void) const; + /** Write a row. */ + int write_row(TABLE *table, unsigned char *buf, Field **fields) const; /** Table name. */ LEX_STRING m_name; @@ -134,6 +231,8 @@ struct PFS_engine_table_share pfs_write_row_t m_write_row; /** Delete all rows function. */ pfs_delete_all_rows_t m_delete_all_rows; + /** Get rows count function. */ + pfs_get_row_count_t m_get_row_count; /** Number or records. This number does not need to be precise, @@ -151,6 +250,10 @@ struct PFS_engine_table_share bool m_checked; }; +/** + Privileges for read only tables. + The only operation allowed is SELECT. +*/ class PFS_readonly_acl : public ACL_internal_table_access { public: @@ -163,8 +266,13 @@ public: ACL_internal_access_result check(ulong want_access, ulong *save_priv) const; }; +/** Singleton instance of PFS_readonly_acl. */ extern PFS_readonly_acl pfs_readonly_acl; +/** + Privileges for truncatable tables. + Operations allowed are SELECT and TRUNCATE. +*/ class PFS_truncatable_acl : public ACL_internal_table_access { public: @@ -177,8 +285,13 @@ public: ACL_internal_access_result check(ulong want_access, ulong *save_priv) const; }; +/** Singleton instance of PFS_truncatable_acl. */ extern PFS_truncatable_acl pfs_truncatable_acl; +/** + Privileges for updatable tables. + Operations allowed are SELECT and UPDATE. +*/ class PFS_updatable_acl : public ACL_internal_table_access { public: @@ -191,8 +304,13 @@ public: ACL_internal_access_result check(ulong want_access, ulong *save_priv) const; }; +/** Singleton instance of PFS_updatable_acl. */ extern PFS_updatable_acl pfs_updatable_acl; +/** + Privileges for editable tables. + Operations allowed are SELECT, INSERT, UPDATE, DELETE and TRUNCATE. +*/ class PFS_editable_acl : public ACL_internal_table_access { public: @@ -205,8 +323,12 @@ public: ACL_internal_access_result check(ulong want_access, ulong *save_priv) const; }; +/** Singleton instance of PFS_editable_acl. */ extern PFS_editable_acl pfs_editable_acl; +/** + Privileges for unknown tables. +*/ class PFS_unknown_acl : public ACL_internal_table_access { public: @@ -219,6 +341,7 @@ public: ACL_internal_access_result check(ulong want_access, ulong *save_priv) const; }; +/** Singleton instance of PFS_unknown_acl. */ extern PFS_unknown_acl pfs_unknown_acl; /** Position of a cursor, for simple iterations. */ @@ -227,20 +350,34 @@ struct PFS_simple_index /** Current row index. */ uint m_index; + /** + Constructor. + @param index the index initial value. + */ PFS_simple_index(uint index) : m_index(index) {} + /** + Set this index at a given position. + @param other a position + */ void set_at(const struct PFS_simple_index *other) { m_index= other->m_index; } + /** + Set this index after a given position. + @param other a position + */ void set_after(const struct PFS_simple_index *other) { m_index= other->m_index + 1; } + /** Set this index to the next record. */ void next(void) { m_index++; } }; +/** Position of a double cursor, for iterations using 2 nested loops. */ struct PFS_double_index { /** Outer index. */ @@ -248,16 +385,29 @@ struct PFS_double_index /** Current index within index_1. */ uint m_index_2; + /** + Constructor. + @param index_1 the first index initial value. + @param index_2 the second index initial value. + */ PFS_double_index(uint index_1, uint index_2) : m_index_1(index_1), m_index_2(index_2) {} + /** + Set this index at a given position. + @param other a position + */ void set_at(const struct PFS_double_index *other) { m_index_1= other->m_index_1; m_index_2= other->m_index_2; } + /** + Set this index after a given position. + @param other a position + */ void set_after(const struct PFS_double_index *other) { m_index_1= other->m_index_1; @@ -265,6 +415,7 @@ struct PFS_double_index } }; +/** Position of a triple cursor, for iterations using 3 nested loops. */ struct PFS_triple_index { /** Outer index. */ @@ -274,10 +425,20 @@ struct PFS_triple_index /** Current index within index_2. */ uint m_index_3; + /** + Constructor. + @param index_1 the first index initial value. + @param index_2 the second index initial value. + @param index_3 the third index initial value. + */ PFS_triple_index(uint index_1, uint index_2, uint index_3) : m_index_1(index_1), m_index_2(index_2), m_index_3(index_3) {} + /** + Set this index at a given position. + @param other a position + */ void set_at(const struct PFS_triple_index *other) { m_index_1= other->m_index_1; @@ -285,6 +446,10 @@ struct PFS_triple_index m_index_3= other->m_index_3; } + /** + Set this index after a given position. + @param other a position + */ void set_after(const struct PFS_triple_index *other) { m_index_1= other->m_index_1; @@ -293,22 +458,6 @@ struct PFS_triple_index } }; -struct PFS_instrument_view_constants -{ - static const uint VIEW_MUTEX= 1; - static const uint VIEW_RWLOCK= 2; - static const uint VIEW_COND= 3; - static const uint VIEW_FILE= 4; -}; - -struct PFS_object_view_constants -{ - static const uint VIEW_TABLE= 1; - static const uint VIEW_EVENT= 2; - static const uint VIEW_PROCEDURE= 3; - static const uint VIEW_FUNCTION= 4; -}; - bool pfs_show_status(handlerton *hton, THD *thd, stat_print_fn *print, enum ha_stat_type stat); diff --git a/storage/perfschema/pfs_events.h b/storage/perfschema/pfs_events.h new file mode 100644 index 00000000000..c9586df11bd --- /dev/null +++ b/storage/perfschema/pfs_events.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef PFS_EVENTS_H +#define PFS_EVENTS_H + +/** + @file storage/perfschema/pfs_events.h + Events data structures (declarations). +*/ + +#include "pfs_column_types.h" + +struct PFS_instr_class; + +/** An event record. */ +struct PFS_events +{ + /** THREAD_ID. */ + ulong m_thread_internal_id; + /** EVENT_ID. */ + ulonglong m_event_id; + /** END_EVENT_ID. */ + ulonglong m_end_event_id; + /** (EVENT_TYPE) */ + enum_event_type m_event_type; + /** NESTING_EVENT_ID. */ + ulonglong m_nesting_event_id; + /** NESTING_EVENT_TYPE */ + enum_event_type m_nesting_event_type; + /** Instrument metadata. */ + PFS_instr_class *m_class; + /** + Timer start. + This member is populated only if m_class->m_timed is true. + */ + ulonglong m_timer_start; + /** + Timer end. + This member is populated only if m_class->m_timed is true. + */ + ulonglong m_timer_end; + /** Location of the instrumentation in the source code (file name). */ + const char *m_source_file; + /** Location of the instrumentation in the source code (line number). */ + uint m_source_line; +}; + +#endif + diff --git a/storage/perfschema/pfs_events_stages.cc b/storage/perfschema/pfs_events_stages.cc new file mode 100644 index 00000000000..dbdfa6068ed --- /dev/null +++ b/storage/perfschema/pfs_events_stages.cc @@ -0,0 +1,238 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/pfs_events_stages.cc + Events stages data structures (implementation). +*/ + +#include "my_global.h" +#include "my_sys.h" +#include "pfs_global.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_account.h" +#include "pfs_host.h" +#include "pfs_user.h" +#include "pfs_events_stages.h" +#include "pfs_atomic.h" +#include "m_string.h" + +ulong events_stages_history_long_size= 0; +/** Consumer flag for table EVENTS_STAGES_CURRENT. */ +bool flag_events_stages_current= false; +/** Consumer flag for table EVENTS_STAGES_HISTORY. */ +bool flag_events_stages_history= false; +/** Consumer flag for table EVENTS_STAGES_HISTORY_LONG. */ +bool flag_events_stages_history_long= false; + +/** True if EVENTS_STAGES_HISTORY_LONG circular buffer is full. */ +bool events_stages_history_long_full= false; +/** Index in EVENTS_STAGES_HISTORY_LONG circular buffer. */ +volatile uint32 events_stages_history_long_index= 0; +/** EVENTS_STAGES_HISTORY_LONG circular buffer. */ +PFS_events_stages *events_stages_history_long_array= NULL; + +/** + Initialize table EVENTS_STAGES_HISTORY_LONG. + @param events_stages_history_long_sizing table sizing +*/ +int init_events_stages_history_long(uint events_stages_history_long_sizing) +{ + events_stages_history_long_size= events_stages_history_long_sizing; + events_stages_history_long_full= false; + PFS_atomic::store_u32(&events_stages_history_long_index, 0); + + if (events_stages_history_long_size == 0) + return 0; + + events_stages_history_long_array= + PFS_MALLOC_ARRAY(events_stages_history_long_size, PFS_events_stages, + MYF(MY_ZEROFILL)); + + return (events_stages_history_long_array ? 0 : 1); +} + +/** Cleanup table EVENTS_STAGES_HISTORY_LONG. */ +void cleanup_events_stages_history_long(void) +{ + pfs_free(events_stages_history_long_array); + events_stages_history_long_array= NULL; +} + +static inline void copy_events_stages(PFS_events_stages *dest, + const PFS_events_stages *source) +{ + memcpy(dest, source, sizeof(PFS_events_stages)); +} + +/** + Insert a stage record in table EVENTS_STAGES_HISTORY. + @param thread thread that executed the wait + @param stage record to insert +*/ +void insert_events_stages_history(PFS_thread *thread, PFS_events_stages *stage) +{ + if (unlikely(events_stages_history_per_thread == 0)) + return; + + DBUG_ASSERT(thread->m_stages_history != NULL); + + uint index= thread->m_stages_history_index; + + /* + A concurrent thread executing TRUNCATE TABLE EVENTS_STAGES_CURRENT + could alter the data that this thread is inserting, + causing a potential race condition. + We are not testing for this and insert a possibly empty record, + to make this thread (the writer) faster. + This is ok, the readers of m_stages_history will filter this out. + */ + copy_events_stages(&thread->m_stages_history[index], stage); + + index++; + if (index >= events_stages_history_per_thread) + { + index= 0; + thread->m_stages_history_full= true; + } + thread->m_stages_history_index= index; +} + +/** + Insert a stage record in table EVENTS_STAGES_HISTORY_LONG. + @param stage record to insert +*/ +void insert_events_stages_history_long(PFS_events_stages *stage) +{ + if (unlikely(events_stages_history_long_size == 0)) + return; + + DBUG_ASSERT(events_stages_history_long_array != NULL); + + uint index= PFS_atomic::add_u32(&events_stages_history_long_index, 1); + + index= index % events_stages_history_long_size; + if (index == 0) + events_stages_history_long_full= true; + + /* See related comment in insert_events_stages_history. */ + copy_events_stages(&events_stages_history_long_array[index], stage); +} + +/** Reset table EVENTS_STAGES_CURRENT data. */ +void reset_events_stages_current(void) +{ + PFS_thread *pfs_thread= thread_array; + PFS_thread *pfs_thread_last= thread_array + thread_max; + + for ( ; pfs_thread < pfs_thread_last; pfs_thread++) + { + pfs_thread->m_stage_current.m_class= NULL; + } +} + +/** Reset table EVENTS_STAGES_HISTORY data. */ +void reset_events_stages_history(void) +{ + PFS_thread *pfs_thread= thread_array; + PFS_thread *pfs_thread_last= thread_array + thread_max; + + for ( ; pfs_thread < pfs_thread_last; pfs_thread++) + { + PFS_events_stages *pfs= pfs_thread->m_stages_history; + PFS_events_stages *pfs_last= pfs + events_stages_history_per_thread; + + pfs_thread->m_stages_history_index= 0; + pfs_thread->m_stages_history_full= false; + for ( ; pfs < pfs_last; pfs++) + pfs->m_class= NULL; + } +} + +/** Reset table EVENTS_STAGES_HISTORY_LONG data. */ +void reset_events_stages_history_long(void) +{ + PFS_atomic::store_u32(&events_stages_history_long_index, 0); + events_stages_history_long_full= false; + + PFS_events_stages *pfs= events_stages_history_long_array; + PFS_events_stages *pfs_last= pfs + events_stages_history_long_size; + for ( ; pfs < pfs_last; pfs++) + pfs->m_class= NULL; +} + +/** Reset table EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */ +void reset_events_stages_by_thread() +{ + PFS_thread *thread= thread_array; + PFS_thread *thread_last= thread_array + thread_max; + + for ( ; thread < thread_last; thread++) + { + if (thread->m_lock.is_populated()) + aggregate_thread_stages(thread); + } +} + +/** Reset table EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */ +void reset_events_stages_by_account() +{ + PFS_account *pfs= account_array; + PFS_account *pfs_last= account_array + account_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->aggregate_stages(); + } +} + +/** Reset table EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME data. */ +void reset_events_stages_by_user() +{ + PFS_user *pfs= user_array; + PFS_user *pfs_last= user_array + user_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->aggregate_stages(); + } +} + +/** Reset table EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME data. */ +void reset_events_stages_by_host() +{ + PFS_host *pfs= host_array; + PFS_host *pfs_last= host_array + host_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->aggregate_stages(); + } +} + +/** Reset table EVENTS_STAGES_GLOBAL_BY_EVENT_NAME data. */ +void reset_events_stages_global() +{ + PFS_stage_stat *stat= global_instr_class_stages_array; + PFS_stage_stat *stat_last= global_instr_class_stages_array + stage_class_max; + + for ( ; stat < stat_last; stat++) + stat->reset(); +} + diff --git a/storage/perfschema/pfs_events_stages.h b/storage/perfschema/pfs_events_stages.h new file mode 100644 index 00000000000..43231796be5 --- /dev/null +++ b/storage/perfschema/pfs_events_stages.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef PFS_EVENTS_STAGES_H +#define PFS_EVENTS_STAGES_H + +/** + @file storage/perfschema/pfs_events_stages.h + Events waits data structures (declarations). +*/ + +#include "pfs_events.h" + +struct PFS_thread; +struct PFS_account; +struct PFS_user; +struct PFS_host; + +/** A stage record. */ +struct PFS_events_stages : public PFS_events +{ + /* No specific attributes */ +}; + +void insert_events_stages_history(PFS_thread *thread, PFS_events_stages *stage); +void insert_events_stages_history_long(PFS_events_stages *stage); + +extern bool flag_events_stages_current; +extern bool flag_events_stages_history; +extern bool flag_events_stages_history_long; + +extern bool events_stages_history_long_full; +extern volatile uint32 events_stages_history_long_index; +extern PFS_events_stages *events_stages_history_long_array; +extern ulong events_stages_history_long_size; + +int init_events_stages_history_long(uint events_stages_history_long_sizing); +void cleanup_events_stages_history_long(); + +void reset_events_stages_current(); +void reset_events_stages_history(); +void reset_events_stages_history_long(); +void reset_events_stages_by_thread(); +void reset_events_stages_by_account(); +void reset_events_stages_by_user(); +void reset_events_stages_by_host(); +void reset_events_stages_global(); +void aggregate_account_stages(PFS_account *account); +void aggregate_user_stages(PFS_user *user); +void aggregate_host_stages(PFS_host *host); + +#endif + diff --git a/storage/perfschema/pfs_events_statements.cc b/storage/perfschema/pfs_events_statements.cc new file mode 100644 index 00000000000..66def924d80 --- /dev/null +++ b/storage/perfschema/pfs_events_statements.cc @@ -0,0 +1,242 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/pfs_events_statements.cc + Events statements data structures (implementation). +*/ + +#include "my_global.h" +#include "my_sys.h" +#include "pfs_global.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_account.h" +#include "pfs_host.h" +#include "pfs_user.h" +#include "pfs_events_statements.h" +#include "pfs_atomic.h" +#include "m_string.h" + +ulong events_statements_history_long_size= 0; +/** Consumer flag for table EVENTS_STATEMENTS_CURRENT. */ +bool flag_events_statements_current= false; +/** Consumer flag for table EVENTS_STATEMENTS_HISTORY. */ +bool flag_events_statements_history= false; +/** Consumer flag for table EVENTS_STATEMENTS_HISTORY_LONG. */ +bool flag_events_statements_history_long= false; + +/** True if EVENTS_STATEMENTS_HISTORY_LONG circular buffer is full. */ +bool events_statements_history_long_full= false; +/** Index in EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */ +volatile uint32 events_statements_history_long_index= 0; +/** EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */ +PFS_events_statements *events_statements_history_long_array= NULL; + +/** + Initialize table EVENTS_STATEMENTS_HISTORY_LONG. + @param events_statements_history_long_sizing table sizing +*/ +int init_events_statements_history_long(uint events_statements_history_long_sizing) +{ + events_statements_history_long_size= events_statements_history_long_sizing; + events_statements_history_long_full= false; + PFS_atomic::store_u32(&events_statements_history_long_index, 0); + + if (events_statements_history_long_size == 0) + return 0; + + events_statements_history_long_array= + PFS_MALLOC_ARRAY(events_statements_history_long_size, PFS_events_statements, + MYF(MY_ZEROFILL)); + + return (events_statements_history_long_array ? 0 : 1); +} + +/** Cleanup table EVENTS_STATEMENTS_HISTORY_LONG. */ +void cleanup_events_statements_history_long(void) +{ + pfs_free(events_statements_history_long_array); + events_statements_history_long_array= NULL; +} + +static inline void copy_events_statements(PFS_events_statements *dest, + const PFS_events_statements *source) +{ + memcpy(dest, source, sizeof(PFS_events_statements)); +} + +/** + Insert a statement record in table EVENTS_STATEMENTS_HISTORY. + @param thread thread that executed the wait + @param statement record to insert +*/ +void insert_events_statements_history(PFS_thread *thread, PFS_events_statements *statement) +{ + if (unlikely(events_statements_history_per_thread == 0)) + return; + + DBUG_ASSERT(thread->m_statements_history != NULL); + + uint index= thread->m_statements_history_index; + + /* + A concurrent thread executing TRUNCATE TABLE EVENTS_STATEMENTS_CURRENT + could alter the data that this thread is inserting, + causing a potential race condition. + We are not testing for this and insert a possibly empty record, + to make this thread (the writer) faster. + This is ok, the readers of m_statements_history will filter this out. + */ + copy_events_statements(&thread->m_statements_history[index], statement); + + index++; + if (index >= events_statements_history_per_thread) + { + index= 0; + thread->m_statements_history_full= true; + } + thread->m_statements_history_index= index; +} + +/** + Insert a statement record in table EVENTS_STATEMENTS_HISTORY_LONG. + @param statement record to insert +*/ +void insert_events_statements_history_long(PFS_events_statements *statement) +{ + if (unlikely(events_statements_history_long_size == 0)) + return ; + + DBUG_ASSERT(events_statements_history_long_array != NULL); + + uint index= PFS_atomic::add_u32(&events_statements_history_long_index, 1); + + index= index % events_statements_history_long_size; + if (index == 0) + events_statements_history_long_full= true; + + /* See related comment in insert_events_statements_history. */ + copy_events_statements(&events_statements_history_long_array[index], statement); +} + +/** Reset table EVENTS_STATEMENTS_CURRENT data. */ +void reset_events_statements_current(void) +{ + PFS_thread *pfs_thread= thread_array; + PFS_thread *pfs_thread_last= thread_array + thread_max; + + for ( ; pfs_thread < pfs_thread_last; pfs_thread++) + { + PFS_events_statements *pfs_stmt= & pfs_thread->m_statement_stack[0]; + PFS_events_statements *pfs_stmt_last= pfs_stmt + statement_stack_max; + + for ( ; pfs_stmt < pfs_stmt_last; pfs_stmt++) + pfs_stmt->m_class= NULL; + } +} + +/** Reset table EVENTS_STATEMENTS_HISTORY data. */ +void reset_events_statements_history(void) +{ + PFS_thread *pfs_thread= thread_array; + PFS_thread *pfs_thread_last= thread_array + thread_max; + + for ( ; pfs_thread < pfs_thread_last; pfs_thread++) + { + PFS_events_statements *pfs= pfs_thread->m_statements_history; + PFS_events_statements *pfs_last= pfs + events_statements_history_per_thread; + + pfs_thread->m_statements_history_index= 0; + pfs_thread->m_statements_history_full= false; + for ( ; pfs < pfs_last; pfs++) + pfs->m_class= NULL; + } +} + +/** Reset table EVENTS_STATEMENTS_HISTORY_LONG data. */ +void reset_events_statements_history_long(void) +{ + PFS_atomic::store_u32(&events_statements_history_long_index, 0); + events_statements_history_long_full= false; + + PFS_events_statements *pfs= events_statements_history_long_array; + PFS_events_statements *pfs_last= pfs + events_statements_history_long_size; + for ( ; pfs < pfs_last; pfs++) + pfs->m_class= NULL; +} + +/** Reset table EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */ +void reset_events_statements_by_thread() +{ + PFS_thread *thread= thread_array; + PFS_thread *thread_last= thread_array + thread_max; + + for ( ; thread < thread_last; thread++) + { + if (thread->m_lock.is_populated()) + aggregate_thread_statements(thread); + } +} + +/** Reset table EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */ +void reset_events_statements_by_account() +{ + PFS_account *pfs= account_array; + PFS_account *pfs_last= account_array + account_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->aggregate_statements(); + } +} + +/** Reset table EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME data. */ +void reset_events_statements_by_user() +{ + PFS_user *pfs= user_array; + PFS_user *pfs_last= user_array + user_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->aggregate_statements(); + } +} + +/** Reset table EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME data. */ +void reset_events_statements_by_host() +{ + PFS_host *pfs= host_array; + PFS_host *pfs_last= host_array + host_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->aggregate_statements(); + } +} + +/** Reset table EVENTS_STATEMENTS_GLOBAL_BY_EVENT_NAME data. */ +void reset_events_statements_global() +{ + PFS_statement_stat *stat= global_instr_class_statements_array; + PFS_statement_stat *stat_last= global_instr_class_statements_array + statement_class_max; + + for ( ; stat < stat_last; stat++) + stat->reset(); +} + diff --git a/storage/perfschema/pfs_events_statements.h b/storage/perfschema/pfs_events_statements.h new file mode 100644 index 00000000000..5d90250c618 --- /dev/null +++ b/storage/perfschema/pfs_events_statements.h @@ -0,0 +1,123 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef PFS_EVENTS_STATEMENTS_H +#define PFS_EVENTS_STATEMENTS_H + +/** + @file storage/perfschema/pfs_events_statements.h + Events statements data structures (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_events.h" +#include "pfs_digest.h" + +struct PFS_thread; +struct PFS_account; +struct PFS_user; +struct PFS_host; + +/** A statement record. */ +struct PFS_events_statements : public PFS_events +{ + /** Database name. */ + char m_current_schema_name[NAME_LEN]; + /** Length of @c m_current_schema_name. */ + uint m_current_schema_name_length; + /** SQL_TEXT */ + char m_sqltext[COL_INFO_SIZE]; + /** Length of @ m_info. */ + uint m_sqltext_length; + + /** Locked time. */ + ulonglong m_lock_time; + + /** Diagnostics area, message text. */ + char m_message_text[MYSQL_ERRMSG_SIZE+1]; + /** Diagnostics area, error number. */ + uint m_sql_errno; + /** Diagnostics area, SQLSTATE. */ + char m_sqlstate[SQLSTATE_LENGTH]; + /** Diagnostics area, error count. */ + uint m_error_count; + /** Diagnostics area, warning count. */ + uint m_warning_count; + /** Diagnostics area, rows affected. */ + ulonglong m_rows_affected; + + /** Optimizer metric, number of rows sent. */ + ulonglong m_rows_sent; + /** Optimizer metric, number of rows examined. */ + ulonglong m_rows_examined; + /** Optimizer metric, number of temporary tables created on disk. */ + ulonglong m_created_tmp_disk_tables; + /** Optimizer metric, number of temporary tables created. */ + ulonglong m_created_tmp_tables; + /** Optimizer metric, number of full join. */ + ulonglong m_select_full_join; + /** Optimizer metric, number of full range join. */ + ulonglong m_select_full_range_join; + /** Optimizer metric, number of select range. */ + ulonglong m_select_range; + /** Optimizer metric, number of select range checks. */ + ulonglong m_select_range_check; + /** Optimizer metric, number of select scans. */ + ulonglong m_select_scan; + /** Optimizer metric, number of sort merge passes. */ + ulonglong m_sort_merge_passes; + /** Optimizer metric, number of sort ranges. */ + ulonglong m_sort_range; + /** Optimizer metric, number of sort rows. */ + ulonglong m_sort_rows; + /** Optimizer metric, number of sort scans. */ + ulonglong m_sort_scan; + /** Optimizer metric, number of 'no index used'. */ + ulonglong m_no_index_used; + /** Optimizer metric, number of 'no good index used'. */ + ulonglong m_no_good_index_used; + /** Statement digest. */ + PSI_digest_storage m_digest_storage; +}; + +void insert_events_statements_history(PFS_thread *thread, PFS_events_statements *statement); +void insert_events_statements_history_long(PFS_events_statements *statement); + +extern bool flag_events_statements_current; +extern bool flag_events_statements_history; +extern bool flag_events_statements_history_long; + +extern bool events_statements_history_long_full; +extern volatile uint32 events_statements_history_long_index; +extern PFS_events_statements *events_statements_history_long_array; +extern ulong events_statements_history_long_size; + +int init_events_statements_history_long(uint events_statements_history_long_sizing); +void cleanup_events_statements_history_long(); + +void reset_events_statements_current(); +void reset_events_statements_history(); +void reset_events_statements_history_long(); +void reset_events_statements_by_thread(); +void reset_events_statements_by_account(); +void reset_events_statements_by_user(); +void reset_events_statements_by_host(); +void reset_events_statements_global(); +void aggregate_account_statements(PFS_account *account); +void aggregate_user_statements(PFS_user *user); +void aggregate_host_statements(PFS_host *host); + +#endif + diff --git a/storage/perfschema/pfs_events_waits.cc b/storage/perfschema/pfs_events_waits.cc index b6cadf9e61c..2ee9ec292a2 100644 --- a/storage/perfschema/pfs_events_waits.cc +++ b/storage/perfschema/pfs_events_waits.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 @@ -21,30 +21,26 @@ #include "my_global.h" #include "my_sys.h" #include "pfs_global.h" +#include "pfs_instr_class.h" #include "pfs_instr.h" +#include "pfs_user.h" +#include "pfs_host.h" +#include "pfs_account.h" #include "pfs_events_waits.h" #include "pfs_atomic.h" #include "m_string.h" ulong events_waits_history_long_size= 0; /** Consumer flag for table EVENTS_WAITS_CURRENT. */ -bool flag_events_waits_current= true; +bool flag_events_waits_current= false; /** Consumer flag for table EVENTS_WAITS_HISTORY. */ -bool flag_events_waits_history= true; +bool flag_events_waits_history= false; /** Consumer flag for table EVENTS_WAITS_HISTORY_LONG. */ -bool flag_events_waits_history_long= true; -/** Consumer flag for table EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME. */ -bool flag_events_waits_summary_by_thread_by_event_name= true; -/** Consumer flag for table EVENTS_WAITS_SUMMARY_BY_EVENT_NAME. */ -bool flag_events_waits_summary_by_event_name= true; -/** Consumer flag for table EVENTS_WAITS_SUMMARY_BY_INSTANCE. */ -bool flag_events_waits_summary_by_instance= true; -bool flag_events_locks_summary_by_event_name= true; -bool flag_events_locks_summary_by_instance= true; -/** Consumer flag for table FILE_SUMMARY_BY_EVENT_NAME. */ -bool flag_file_summary_by_event_name= true; -/** Consumer flag for table FILE_SUMMARY_BY_INSTANCE. */ -bool flag_file_summary_by_instance= true; +bool flag_events_waits_history_long= false; +/** Consumer flag for the global instrumentation. */ +bool flag_global_instrumentation= false; +/** Consumer flag for the per thread instrumentation. */ +bool flag_thread_instrumentation= false; /** True if EVENTS_WAITS_HISTORY_LONG circular buffer is full. */ bool events_waits_history_long_full= false; @@ -93,6 +89,9 @@ static inline void copy_events_waits(PFS_events_waits *dest, */ void insert_events_waits_history(PFS_thread *thread, PFS_events_waits *wait) { + if (unlikely(events_waits_history_per_thread == 0)) + return; + uint index= thread->m_waits_history_index; /* @@ -120,6 +119,9 @@ void insert_events_waits_history(PFS_thread *thread, PFS_events_waits *wait) */ void insert_events_waits_history_long(PFS_events_waits *wait) { + if (unlikely(events_waits_history_long_size == 0)) + return; + uint index= PFS_atomic::add_u32(&events_waits_history_long_index, 1); index= index % events_waits_history_long_size; @@ -138,11 +140,11 @@ void reset_events_waits_current(void) for ( ; pfs_thread < pfs_thread_last; pfs_thread++) { - PFS_wait_locker *locker= pfs_thread->m_wait_locker_stack; - PFS_wait_locker *locker_last= locker + LOCKER_STACK_SIZE; + PFS_events_waits *pfs_wait= pfs_thread->m_events_waits_stack; + PFS_events_waits *pfs_wait_last= pfs_wait + WAIT_STACK_SIZE; - for ( ; locker < locker_last; locker++) - locker->m_waits_current.m_wait_class= NO_WAIT_CLASS; + for ( ; pfs_wait < pfs_wait_last; pfs_wait++) + pfs_wait->m_wait_class= NO_WAIT_CLASS; } } @@ -176,3 +178,137 @@ void reset_events_waits_history_long(void) wait->m_wait_class= NO_WAIT_CLASS; } +/** Reset table EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */ +void reset_events_waits_by_thread() +{ + PFS_thread *thread= thread_array; + PFS_thread *thread_last= thread_array + thread_max; + + for ( ; thread < thread_last; thread++) + { + if (thread->m_lock.is_populated()) + aggregate_thread_waits(thread); + } +} + +/** Reset table EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */ +void reset_events_waits_by_account() +{ + PFS_account *pfs= account_array; + PFS_account *pfs_last= account_array + account_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->aggregate_waits(); + } +} + +/** Reset table EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME data. */ +void reset_events_waits_by_user() +{ + PFS_user *pfs= user_array; + PFS_user *pfs_last= user_array + user_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->aggregate_waits(); + } +} + +/** Reset table EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME data. */ +void reset_events_waits_by_host() +{ + PFS_host *pfs= host_array; + PFS_host *pfs_last= host_array + host_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->aggregate_waits(); + } +} + +/** Reset table EVENTS_WAITS_GLOBAL_BY_EVENT_NAME data. */ +void reset_events_waits_global() +{ + PFS_single_stat *stat= global_instr_class_waits_array; + PFS_single_stat *stat_last= global_instr_class_waits_array + wait_class_max; + + for ( ; stat < stat_last; stat++) + stat->reset(); +} + +void reset_table_waits_by_table() +{ + PFS_table_share *pfs= table_share_array; + PFS_table_share *pfs_last= pfs + table_share_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->aggregate(); + } +} + +void reset_table_io_waits_by_table() +{ + PFS_table_share *pfs= table_share_array; + PFS_table_share *pfs_last= pfs + table_share_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->aggregate_io(); + } +} + +void reset_table_lock_waits_by_table() +{ + PFS_table_share *pfs= table_share_array; + PFS_table_share *pfs_last= pfs + table_share_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->aggregate_lock(); + } +} + +void reset_table_waits_by_table_handle() +{ + PFS_table *pfs= table_array; + PFS_table *pfs_last= pfs + table_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->sanitized_aggregate(); + } +} + +void reset_table_io_waits_by_table_handle() +{ + PFS_table *pfs= table_array; + PFS_table *pfs_last= pfs + table_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->sanitized_aggregate_io(); + } +} + +void reset_table_lock_waits_by_table_handle() +{ + PFS_table *pfs= table_array; + PFS_table *pfs_last= pfs + table_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + pfs->sanitized_aggregate_lock(); + } +} + diff --git a/storage/perfschema/pfs_events_waits.h b/storage/perfschema/pfs_events_waits.h index d277db39d8d..a7f7a095b9f 100644 --- a/storage/perfschema/pfs_events_waits.h +++ b/storage/perfschema/pfs_events_waits.h @@ -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 @@ -23,6 +23,7 @@ #include "pfs_column_types.h" #include "pfs_lock.h" +#include "pfs_events.h" struct PFS_mutex; struct PFS_rwlock; @@ -30,7 +31,12 @@ struct PFS_cond; struct PFS_table; struct PFS_file; struct PFS_thread; +struct PFS_socket; struct PFS_instr_class; +struct PFS_table_share; +struct PFS_account; +struct PFS_user; +struct PFS_host; /** Class of a wait event. */ enum events_waits_class @@ -40,51 +46,13 @@ enum events_waits_class WAIT_CLASS_RWLOCK, WAIT_CLASS_COND, WAIT_CLASS_TABLE, - WAIT_CLASS_FILE -}; - -/** State of a timer. */ -enum timer_state -{ - /** - Not timed. - In this state, TIMER_START, TIMER_END and TIMER_WAIT are NULL. - */ - TIMER_STATE_UNTIMED, - /** - About to start. - In this state, TIMER_START, TIMER_END and TIMER_WAIT are NULL. - */ - TIMER_STATE_STARTING, - /** - Started, but not yet ended. - In this state, TIMER_START has a value, TIMER_END and TIMER_WAIT are NULL. - */ - TIMER_STATE_STARTED, - /** - Ended. - In this state, TIMER_START, TIMER_END and TIMER_WAIT have a value. - */ - TIMER_STATE_TIMED -}; - -/** Target object a wait event is waiting on. */ -union events_waits_target -{ - /** Mutex waited on. */ - PFS_mutex *m_mutex; - /** RWLock waited on. */ - PFS_rwlock *m_rwlock; - /** Condition waited on. */ - PFS_cond *m_cond; - /** Table waited on. */ - PFS_table *m_table; - /** File waited on. */ - PFS_file *m_file; + WAIT_CLASS_FILE, + WAIT_CLASS_SOCKET, + WAIT_CLASS_IDLE }; /** A wait event record. */ -struct PFS_events_waits +struct PFS_events_waits : public PFS_events { /** The type of wait. @@ -100,36 +68,18 @@ struct PFS_events_waits events_waits_class m_wait_class; /** Executing thread. */ PFS_thread *m_thread; - /** Instrument metadata. */ - PFS_instr_class *m_class; - /** Timer state. */ - enum timer_state m_timer_state; - /** Event id. */ - ulonglong m_event_id; - /** - Timer start. - This member is populated only if m_timed is true. - */ - ulonglong m_timer_start; - /** - Timer end. - This member is populated only if m_timed is true. - */ - ulonglong m_timer_end; - /** Schema name. */ - const char *m_schema_name; - /** Length in bytes of @c m_schema_name. */ - uint m_schema_name_length; - /** Object name. */ - const char *m_object_name; - /** Length in bytes of @c m_object_name. */ - uint m_object_name_length; + /** Object type */ + enum_object_type m_object_type; + /** Table share, for table operations only. */ + PFS_table_share *m_weak_table_share; + /** File, for file operations only. */ + PFS_file *m_weak_file; + /** Socket, for socket operations only. */ + PFS_socket *m_weak_socket; + /** For weak pointers, target object version. */ + uint32 m_weak_version; /** Address in memory of the object instance waited on. */ const void *m_object_instance_addr; - /** Location of the instrumentation in the source code (file name). */ - const char *m_source_file; - /** Location of the instrumentation in the source code (line number). */ - uint m_source_line; /** Operation performed. */ enum_operation_type m_operation; /** @@ -137,22 +87,23 @@ struct PFS_events_waits This member is populated for file READ/WRITE operations only. */ size_t m_number_of_bytes; + /** + Index used. + This member is populated for TABLE IO operations only. + */ + uint m_index; + /** Flags */ + ulong m_flags; }; -/** - A wait locker. - A locker is a transient helper structure used by the instrumentation - during the recording of a wait. -*/ -struct PFS_wait_locker -{ - /** The timer used to measure the wait. */ - enum_timer_name m_timer_name; - /** The object waited on. */ - events_waits_target m_target; - /** The wait data recorded. */ - PFS_events_waits m_waits_current; -}; +/** TIMED bit in the state flags bitfield. */ +#define STATE_FLAG_TIMED (1<<0) +/** THREAD bit in the state flags bitfield. */ +#define STATE_FLAG_THREAD (1<<1) +/** EVENT bit in the state flags bitfield. */ +#define STATE_FLAG_EVENT (1<<2) +/** DIGEST bit in the state flags bitfield. */ +#define STATE_FLAG_DIGEST (1<<3) void insert_events_waits_history(PFS_thread *thread, PFS_events_waits *wait); @@ -161,14 +112,9 @@ void insert_events_waits_history_long(PFS_events_waits *wait); extern bool flag_events_waits_current; extern bool flag_events_waits_history; extern bool flag_events_waits_history_long; -extern bool flag_events_waits_summary_by_thread_by_event_name; -extern bool flag_events_waits_summary_by_event_name; -extern bool flag_events_waits_summary_by_instance; -extern bool flag_events_locks_summary_by_thread_by_name; -extern bool flag_events_locks_summary_by_event_name; -extern bool flag_events_locks_summary_by_instance; -extern bool flag_file_summary_by_event_name; -extern bool flag_file_summary_by_instance; +extern bool flag_global_instrumentation; +extern bool flag_thread_instrumentation; + extern bool events_waits_history_long_full; extern volatile uint32 events_waits_history_long_index; extern PFS_events_waits *events_waits_history_long_array; @@ -180,6 +126,21 @@ void cleanup_events_waits_history_long(); void reset_events_waits_current(); void reset_events_waits_history(); void reset_events_waits_history_long(); +void reset_events_waits_by_thread(); +void reset_events_waits_by_account(); +void reset_events_waits_by_user(); +void reset_events_waits_by_host(); +void reset_events_waits_global(); +void aggregate_account_waits(PFS_account *account); +void aggregate_user_waits(PFS_user *user); +void aggregate_host_waits(PFS_host *host); + +void reset_table_waits_by_table(); +void reset_table_io_waits_by_table(); +void reset_table_lock_waits_by_table(); +void reset_table_waits_by_table_handle(); +void reset_table_io_waits_by_table_handle(); +void reset_table_lock_waits_by_table_handle(); #endif diff --git a/storage/perfschema/pfs_global.cc b/storage/perfschema/pfs_global.cc index fa57f335325..6c3b79a3e1f 100644 --- a/storage/perfschema/pfs_global.cc +++ b/storage/perfschema/pfs_global.cc @@ -21,10 +21,17 @@ #include "my_global.h" #include "my_sys.h" #include "pfs_global.h" +#include "my_net.h" #include <stdlib.h> #include <string.h> +#ifdef __WIN__ + #include <winsock2.h> +#else + #include <arpa/inet.h> +#endif + bool pfs_initialized= false; ulonglong pfs_allocated_memory= 0; @@ -67,3 +74,62 @@ void pfs_print_error(const char *format, ...) fflush(stderr); } +/** Convert raw ip address into readable format. Do not do a reverse DNS lookup. */ + +uint pfs_get_socket_address(char *host, + uint host_len, + uint *port, + const struct sockaddr_storage *src_addr, + socklen_t src_len) +{ + DBUG_ASSERT(host); + DBUG_ASSERT(src_addr); + DBUG_ASSERT(port); + + memset(host, 0, host_len); + *port= 0; + + switch (src_addr->ss_family) + { + case AF_INET: + { + if (host_len < INET_ADDRSTRLEN+1) + return 0; + struct sockaddr_in *sa4= (struct sockaddr_in *)(src_addr); + #ifdef __WIN__ + /* Older versions of Windows do not support inet_ntop() */ + getnameinfo((struct sockaddr *)sa4, sizeof(struct sockaddr_in), + host, host_len, NULL, 0, NI_NUMERICHOST); + #else + inet_ntop(AF_INET, &(sa4->sin_addr), host, INET_ADDRSTRLEN); + #endif + *port= ntohs(sa4->sin_port); + } + break; + +#ifdef HAVE_IPV6 + case AF_INET6: + { + if (host_len < INET6_ADDRSTRLEN+1) + return 0; + struct sockaddr_in6 *sa6= (struct sockaddr_in6 *)(src_addr); + #ifdef __WIN__ + /* Older versions of Windows do not support inet_ntop() */ + getnameinfo((struct sockaddr *)sa6, sizeof(struct sockaddr_in6), + host, host_len, NULL, 0, NI_NUMERICHOST); + #else + inet_ntop(AF_INET6, &(sa6->sin6_addr), host, INET6_ADDRSTRLEN); + #endif + *port= ntohs(sa6->sin6_port); + } + break; +#endif + + default: + break; + } + + /* Return actual IP address string length */ + return (strlen((const char*)host)); +} + diff --git a/storage/perfschema/pfs_global.h b/storage/perfschema/pfs_global.h index c0c0490a380..693153cb097 100644 --- a/storage/perfschema/pfs_global.h +++ b/storage/perfschema/pfs_global.h @@ -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 @@ -21,14 +21,38 @@ Miscellaneous global dependencies (declarations). */ +/** True when the performance schema is initialized. */ extern bool pfs_initialized; +/** Total memory allocated by the performance schema, in bytes. */ extern ulonglong pfs_allocated_memory; void *pfs_malloc(size_t size, myf flags); + +/** + Helper, to allocate an array of structures. + @param n number of elements in the array. + @param T type of an element. + @param f flags to use when allocating memory +*/ #define PFS_MALLOC_ARRAY(n, T, f) \ reinterpret_cast<T*> (pfs_malloc((n) * sizeof(T), (f))) + +/** Free memory allocated with @sa pfs_malloc. */ void pfs_free(void *ptr); + +uint pfs_get_socket_address(char *host, + uint host_len, + uint *port, + const struct sockaddr_storage *src_addr, + socklen_t src_len); + +/** + Compute a random index value in an interval. + @param ptr seed address + @param max_size maximun size of the interval + @return a random value in [0, max_size-1] +*/ inline uint randomized_index(const void *ptr, uint max_size) { static uint seed1= 0; diff --git a/storage/perfschema/pfs_host.cc b/storage/perfschema/pfs_host.cc new file mode 100644 index 00000000000..82b78e19ce8 --- /dev/null +++ b/storage/perfschema/pfs_host.cc @@ -0,0 +1,380 @@ +/* Copyright (c) 2010, 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 + 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_host.cc + Performance schema host (implementation). +*/ + +#include "my_global.h" +#include "my_sys.h" +#include "pfs.h" +#include "pfs_stat.h" +#include "pfs_instr.h" +#include "pfs_setup_actor.h" +#include "pfs_host.h" +#include "pfs_global.h" +#include "pfs_instr_class.h" + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +ulong host_max; +ulong host_lost; + +PFS_host *host_array= NULL; + +static PFS_single_stat *host_instr_class_waits_array= NULL; +static PFS_stage_stat *host_instr_class_stages_array= NULL; +static PFS_statement_stat *host_instr_class_statements_array= NULL; + +static LF_HASH host_hash; +static bool host_hash_inited= false; + +/** + Initialize the host buffers. + @param param sizing parameters + @return 0 on success +*/ +int init_host(const PFS_global_param *param) +{ + uint index; + + host_max= param->m_host_sizing; + + host_array= NULL; + host_instr_class_waits_array= NULL; + host_instr_class_stages_array= NULL; + host_instr_class_statements_array= NULL; + uint waits_sizing= host_max * wait_class_max; + uint stages_sizing= host_max * stage_class_max; + uint statements_sizing= host_max * statement_class_max; + + if (host_max > 0) + { + host_array= PFS_MALLOC_ARRAY(host_max, PFS_host, + MYF(MY_ZEROFILL)); + if (unlikely(host_array == NULL)) + return 1; + } + + if (waits_sizing > 0) + { + host_instr_class_waits_array= + PFS_connection_slice::alloc_waits_slice(waits_sizing); + if (unlikely(host_instr_class_waits_array == NULL)) + return 1; + } + + if (stages_sizing > 0) + { + host_instr_class_stages_array= + PFS_connection_slice::alloc_stages_slice(stages_sizing); + if (unlikely(host_instr_class_stages_array == NULL)) + return 1; + } + + if (statements_sizing > 0) + { + host_instr_class_statements_array= + PFS_connection_slice::alloc_statements_slice(statements_sizing); + if (unlikely(host_instr_class_statements_array == NULL)) + return 1; + } + + for (index= 0; index < host_max; index++) + { + host_array[index].m_instr_class_waits_stats= + &host_instr_class_waits_array[index * wait_class_max]; + host_array[index].m_instr_class_stages_stats= + &host_instr_class_stages_array[index * stage_class_max]; + host_array[index].m_instr_class_statements_stats= + &host_instr_class_statements_array[index * statement_class_max]; + } + + return 0; +} + +/** Cleanup all the host buffers. */ +void cleanup_host(void) +{ + pfs_free(host_array); + host_array= NULL; + pfs_free(host_instr_class_waits_array); + host_instr_class_waits_array= NULL; + pfs_free(host_instr_class_stages_array); + host_instr_class_stages_array= NULL; + pfs_free(host_instr_class_statements_array); + host_instr_class_statements_array= NULL; + host_max= 0; +} + +C_MODE_START +static uchar *host_hash_get_key(const uchar *entry, size_t *length, + my_bool) +{ + const PFS_host * const *typed_entry; + const PFS_host *host; + const void *result; + typed_entry= reinterpret_cast<const PFS_host* const *> (entry); + DBUG_ASSERT(typed_entry != NULL); + host= *typed_entry; + DBUG_ASSERT(host != NULL); + *length= host->m_key.m_key_length; + result= host->m_key.m_hash_key; + return const_cast<uchar*> (reinterpret_cast<const uchar*> (result)); +} +C_MODE_END + +/** + Initialize the host hash. + @return 0 on success +*/ +int init_host_hash(void) +{ + if (! host_hash_inited) + { + lf_hash_init(&host_hash, sizeof(PFS_host*), LF_HASH_UNIQUE, + 0, 0, host_hash_get_key, &my_charset_bin); + host_hash_inited= true; + } + return 0; +} + +/** Cleanup the host hash. */ +void cleanup_host_hash(void) +{ + if (host_hash_inited) + { + lf_hash_destroy(&host_hash); + host_hash_inited= false; + } +} + +static LF_PINS* get_host_hash_pins(PFS_thread *thread) +{ + if (unlikely(thread->m_host_hash_pins == NULL)) + { + if (! host_hash_inited) + return NULL; + thread->m_host_hash_pins= lf_hash_get_pins(&host_hash); + } + return thread->m_host_hash_pins; +} + +static void set_host_key(PFS_host_key *key, + const char *host, uint host_length) +{ + DBUG_ASSERT(host_length <= HOSTNAME_LENGTH); + + char *ptr= &key->m_hash_key[0]; + if (host_length > 0) + { + memcpy(ptr, host, host_length); + ptr+= host_length; + } + ptr[0]= 0; + ptr++; + key->m_key_length= ptr - &key->m_hash_key[0]; +} + +PFS_host *find_or_create_host(PFS_thread *thread, + const char *hostname, uint hostname_length) +{ + if (host_max == 0) + { + host_lost++; + return NULL; + } + + LF_PINS *pins= get_host_hash_pins(thread); + if (unlikely(pins == NULL)) + { + host_lost++; + return NULL; + } + + PFS_host_key key; + set_host_key(&key, hostname, hostname_length); + + PFS_host **entry; + uint retry_count= 0; + const uint retry_max= 3; + +search: + entry= reinterpret_cast<PFS_host**> + (lf_hash_search(&host_hash, pins, + key.m_hash_key, key.m_key_length)); + if (entry && (entry != MY_ERRPTR)) + { + PFS_host *pfs; + pfs= *entry; + pfs->inc_refcount(); + lf_hash_search_unpin(pins); + return pfs; + } + + lf_hash_search_unpin(pins); + + PFS_scan scan; + uint random= randomized_index(hostname, host_max); + + for (scan.init(random, host_max); + scan.has_pass(); + scan.next_pass()) + { + PFS_host *pfs= host_array + scan.first(); + PFS_host *pfs_last= host_array + scan.last(); + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_free()) + { + if (pfs->m_lock.free_to_dirty()) + { + pfs->m_key= key; + if (hostname_length > 0) + pfs->m_hostname= &pfs->m_key.m_hash_key[0]; + else + pfs->m_hostname= NULL; + pfs->m_hostname_length= hostname_length; + + pfs->init_refcount(); + pfs->reset_stats(); + pfs->m_disconnected_count= 0; + + int res; + res= lf_hash_insert(&host_hash, pins, &pfs); + if (likely(res == 0)) + { + pfs->m_lock.dirty_to_allocated(); + return pfs; + } + + pfs->m_lock.dirty_to_free(); + + if (res > 0) + { + if (++retry_count > retry_max) + { + host_lost++; + return NULL; + } + goto search; + } + + host_lost++; + return NULL; + } + } + } + } + + host_lost++; + return NULL; +} + +void PFS_host::aggregate() +{ + aggregate_waits(); + aggregate_stages(); + aggregate_statements(); + aggregate_stats(); +} + +void PFS_host::aggregate_waits() +{ + /* No parent to aggregate to, clean the stats */ + reset_waits_stats(); +} + +void PFS_host::aggregate_stages() +{ + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME to: + - EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME + */ + aggregate_all_stages(m_instr_class_stages_stats, + global_instr_class_stages_array); +} + +void PFS_host::aggregate_statements() +{ + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME to: + - EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME + */ + aggregate_all_statements(m_instr_class_statements_stats, + global_instr_class_statements_array); +} + +void PFS_host::aggregate_stats() +{ + /* No parent to aggregate to, clean the stats */ + m_disconnected_count= 0; +} + +void PFS_host::release() +{ + dec_refcount(); +} + +void purge_host(PFS_thread *thread, PFS_host *host) +{ + LF_PINS *pins= get_host_hash_pins(thread); + if (unlikely(pins == NULL)) + return; + + PFS_host **entry; + entry= reinterpret_cast<PFS_host**> + (lf_hash_search(&host_hash, pins, + host->m_key.m_hash_key, host->m_key.m_key_length)); + if (entry && (entry != MY_ERRPTR)) + { + DBUG_ASSERT(*entry == host); + if (host->get_refcount() == 0) + { + lf_hash_delete(&host_hash, pins, + host->m_key.m_hash_key, host->m_key.m_key_length); + host->m_lock.allocated_to_free(); + } + } + + lf_hash_search_unpin(pins); +} + +/** Purge non connected hosts, reset stats of connected hosts. */ +void purge_all_host(void) +{ + PFS_thread *thread= PFS_thread::get_current_thread(); + if (unlikely(thread == NULL)) + return; + + PFS_host *pfs= host_array; + PFS_host *pfs_last= host_array + host_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + { + pfs->aggregate(); + if (pfs->get_refcount() == 0) + purge_host(thread, pfs); + } + } +} + +/** @} */ diff --git a/storage/perfschema/pfs_host.h b/storage/perfschema/pfs_host.h new file mode 100644 index 00000000000..d04b88e62f3 --- /dev/null +++ b/storage/perfschema/pfs_host.h @@ -0,0 +1,110 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef PFS_HOST_H +#define PFS_HOST_H + +/** + @file storage/perfschema/pfs_host.h + Performance schema host (declarations). +*/ + +#include "pfs_lock.h" +#include "lf.h" +#include "pfs_con_slice.h" + +struct PFS_global_param; +struct PFS_thread; + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +struct PFS_host_key +{ + /** + Hash search key. + This has to be a string for LF_HASH, + the format is "<hostname><0x00>" + */ + char m_hash_key[HOSTNAME_LENGTH + 1]; + uint m_key_length; +}; + +struct PFS_host : PFS_connection_slice +{ +public: + inline void init_refcount(void) + { + PFS_atomic::store_32(& m_refcount, 1); + } + + inline int get_refcount(void) + { + return PFS_atomic::load_32(& m_refcount); + } + + inline void inc_refcount(void) + { + PFS_atomic::add_32(& m_refcount, 1); + } + + inline void dec_refcount(void) + { + PFS_atomic::add_32(& m_refcount, -1); + } + + void aggregate(void); + void aggregate_waits(void); + void aggregate_stages(void); + void aggregate_statements(void); + void aggregate_stats(void); + void release(void); + + /* Internal lock. */ + pfs_lock m_lock; + PFS_host_key m_key; + const char *m_hostname; + uint m_hostname_length; + + ulonglong m_disconnected_count; + +private: + int m_refcount; +}; + +int init_host(const PFS_global_param *param); +void cleanup_host(void); +int init_host_hash(void); +void cleanup_host_hash(void); + +PFS_host *find_or_create_host(PFS_thread *thread, + const char *hostname, uint hostname_length); + +void purge_all_host(void); + +/* For iterators and show status. */ + +extern ulong host_max; +extern ulong host_lost; + +/* Exposing the data directly, for iterators. */ + +extern PFS_host *host_array; + +/** @} */ +#endif + diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc index 8da1a9862e1..82e768c9be2 100644 --- a/storage/perfschema/pfs_instr.cc +++ b/storage/perfschema/pfs_instr.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,11 @@ #include "pfs.h" #include "pfs_stat.h" #include "pfs_instr.h" +#include "pfs_host.h" +#include "pfs_user.h" +#include "pfs_account.h" #include "pfs_global.h" +#include "pfs_instr_class.h" /** @addtogroup Performance_schema_buffers @@ -63,12 +67,21 @@ ulong file_handle_lost; ulong table_max; /** Number of table instances lost. @sa table_array */ ulong table_lost; +/** Size of the socket instances array. @sa socket_array */ +ulong socket_max; +/** Number of socket instances lost. @sa socket_array */ +ulong socket_lost; /** Number of EVENTS_WAITS_HISTORY records per thread. */ ulong events_waits_history_per_thread; -/** Number of instruments class per thread. */ -ulong instr_class_per_thread; +/** Number of EVENTS_STAGES_HISTORY records per thread. */ +ulong events_stages_history_per_thread; +/** Number of EVENTS_STATEMENTS_HISTORY records per thread. */ +ulong events_statements_history_per_thread; +uint statement_stack_max; /** Number of locker lost. @sa LOCKER_STACK_SIZE. */ ulong locker_lost= 0; +/** Number of statement lost. @sa STATEMENT_STACK_SIZE. */ +ulong statement_lost= 0; /** Mutex instrumentation instances array. @@ -120,24 +133,35 @@ PFS_file **file_handle_array= NULL; */ PFS_table *table_array= NULL; +/** + Socket instrumentation instances array. + @sa socket_max + @sa socket_lost +*/ +PFS_socket *socket_array= NULL; + +PFS_single_stat *global_instr_class_waits_array= NULL; +PFS_stage_stat *global_instr_class_stages_array= NULL; +PFS_statement_stat *global_instr_class_statements_array= NULL; + static volatile uint32 thread_internal_id_counter= 0; -static uint per_thread_rwlock_class_start; -static uint per_thread_cond_class_start; -static uint per_thread_file_class_start; static uint thread_instr_class_waits_sizing; -static PFS_single_stat_chain *thread_instr_class_waits_array= NULL; +static uint thread_instr_class_stages_sizing; +static uint thread_instr_class_statements_sizing; +static PFS_single_stat *thread_instr_class_waits_array= NULL; +static PFS_stage_stat *thread_instr_class_stages_array= NULL; +static PFS_statement_stat *thread_instr_class_statements_array= NULL; -static PFS_events_waits *thread_history_array= NULL; +static PFS_events_waits *thread_waits_history_array= NULL; +static PFS_events_stages *thread_stages_history_array= NULL; +static PFS_events_statements *thread_statements_history_array= NULL; +static PFS_events_statements *thread_statements_stack_array= NULL; /** Hash table for instrumented files. */ static LF_HASH filename_hash; /** True if filename_hash is initialized. */ static bool filename_hash_inited= false; -C_MODE_START -/** Get hash table key for instrumented files. */ -static uchar *filename_hash_get_key(const uchar *, size_t *, my_bool); -C_MODE_END /** Initialize all the instruments instance buffers. @@ -146,10 +170,16 @@ C_MODE_END */ int init_instruments(const PFS_global_param *param) { - uint thread_history_sizing; + uint thread_waits_history_sizing; + uint thread_stages_history_sizing; + uint thread_statements_history_sizing; + uint thread_statements_stack_sizing; uint index; DBUG_ENTER("init_instruments"); + /* Make sure init_event_name_sizing is called */ + DBUG_ASSERT(wait_class_max != 0); + mutex_max= param->m_mutex_sizing; mutex_lost= 0; rwlock_max= param->m_rwlock_sizing; @@ -164,21 +194,32 @@ int init_instruments(const PFS_global_param *param) table_lost= 0; thread_max= param->m_thread_sizing; thread_lost= 0; + socket_max= param->m_socket_sizing; + socket_lost= 0; events_waits_history_per_thread= param->m_events_waits_history_sizing; - thread_history_sizing= param->m_thread_sizing + thread_waits_history_sizing= param->m_thread_sizing * events_waits_history_per_thread; - per_thread_rwlock_class_start= param->m_mutex_class_sizing; - per_thread_cond_class_start= per_thread_rwlock_class_start - + param->m_rwlock_class_sizing; - per_thread_file_class_start= per_thread_cond_class_start - + param->m_cond_class_sizing; - instr_class_per_thread= per_thread_file_class_start - + param->m_file_class_sizing; - thread_instr_class_waits_sizing= param->m_thread_sizing - * instr_class_per_thread; + * wait_class_max; + + events_stages_history_per_thread= param->m_events_stages_history_sizing; + thread_stages_history_sizing= param->m_thread_sizing + * events_stages_history_per_thread; + + events_statements_history_per_thread= param->m_events_statements_history_sizing; + thread_statements_history_sizing= param->m_thread_sizing + * events_statements_history_per_thread; + + statement_stack_max= 1; + thread_statements_stack_sizing= param->m_thread_sizing * statement_stack_max; + + thread_instr_class_stages_sizing= param->m_thread_sizing + * param->m_stage_class_sizing; + + thread_instr_class_statements_sizing= param->m_thread_sizing + * param->m_statement_class_sizing; mutex_array= NULL; rwlock_array= NULL; @@ -186,9 +227,15 @@ int init_instruments(const PFS_global_param *param) file_array= NULL; file_handle_array= NULL; table_array= NULL; + socket_array= NULL; thread_array= NULL; - thread_history_array= NULL; + thread_waits_history_array= NULL; + thread_stages_history_array= NULL; + thread_statements_history_array= NULL; + thread_statements_stack_array= NULL; thread_instr_class_waits_array= NULL; + thread_instr_class_stages_array= NULL; + thread_instr_class_statements_array= NULL; thread_internal_id_counter= 0; if (mutex_max > 0) @@ -233,6 +280,13 @@ int init_instruments(const PFS_global_param *param) DBUG_RETURN(1); } + if (socket_max > 0) + { + socket_array= PFS_MALLOC_ARRAY(socket_max, PFS_socket, MYF(MY_ZEROFILL)); + if (unlikely(socket_array == NULL)) + DBUG_RETURN(1); + } + if (thread_max > 0) { thread_array= PFS_MALLOC_ARRAY(thread_max, PFS_thread, MYF(MY_ZEROFILL)); @@ -240,12 +294,12 @@ int init_instruments(const PFS_global_param *param) DBUG_RETURN(1); } - if (thread_history_sizing > 0) + if (thread_waits_history_sizing > 0) { - thread_history_array= - PFS_MALLOC_ARRAY(thread_history_sizing, PFS_events_waits, + thread_waits_history_array= + PFS_MALLOC_ARRAY(thread_waits_history_sizing, PFS_events_waits, MYF(MY_ZEROFILL)); - if (unlikely(thread_history_array == NULL)) + if (unlikely(thread_waits_history_array == NULL)) DBUG_RETURN(1); } @@ -253,146 +307,126 @@ int init_instruments(const PFS_global_param *param) { thread_instr_class_waits_array= PFS_MALLOC_ARRAY(thread_instr_class_waits_sizing, - PFS_single_stat_chain, MYF(MY_ZEROFILL)); + PFS_single_stat, MYF(MY_ZEROFILL)); if (unlikely(thread_instr_class_waits_array == NULL)) DBUG_RETURN(1); - } - for (index= 0; index < thread_instr_class_waits_sizing; index++) - { - /* - Currently, this chain is of length 1, - but it's still implemented as a stat chain, - since more aggregations are planned to be implemented in m_parent. - */ - thread_instr_class_waits_array[index].m_control_flag= - &flag_events_waits_summary_by_thread_by_event_name; - thread_instr_class_waits_array[index].m_parent= NULL; + for (index= 0; index < thread_instr_class_waits_sizing; index++) + thread_instr_class_waits_array[index].reset(); } - for (index= 0; index < thread_max; index++) + if (thread_stages_history_sizing > 0) { - thread_array[index].m_waits_history= - &thread_history_array[index * events_waits_history_per_thread]; - thread_array[index].m_instr_class_wait_stats= - &thread_instr_class_waits_array[index * instr_class_per_thread]; + thread_stages_history_array= + PFS_MALLOC_ARRAY(thread_stages_history_sizing, PFS_events_stages, + MYF(MY_ZEROFILL)); + if (unlikely(thread_stages_history_array == NULL)) + DBUG_RETURN(1); } - DBUG_RETURN(0); -} - -/** - Find the per-thread wait statistics for a mutex class. - @param thread input thread - @param klass mutex class - @return the per thread per mutex class wait stat -*/ -PFS_single_stat_chain * -find_per_thread_mutex_class_wait_stat(PFS_thread *thread, - PFS_mutex_class *klass) -{ - PFS_single_stat_chain *stat; - uint index; - DBUG_ENTER("find_per_thread_mutex_class_wait_stat"); + if (thread_instr_class_stages_sizing > 0) + { + thread_instr_class_stages_array= + PFS_MALLOC_ARRAY(thread_instr_class_stages_sizing, + PFS_stage_stat, MYF(MY_ZEROFILL)); + if (unlikely(thread_instr_class_stages_array == NULL)) + DBUG_RETURN(1); - DBUG_ASSERT(thread != NULL); - DBUG_ASSERT(klass != NULL); - index= klass->m_index; - DBUG_ASSERT(index < mutex_class_max); + for (index= 0; index < thread_instr_class_stages_sizing; index++) + thread_instr_class_stages_array[index].reset(); + } - stat= &(thread->m_instr_class_wait_stats[index]); - DBUG_RETURN(stat); -} + if (thread_statements_history_sizing > 0) + { + thread_statements_history_array= + PFS_MALLOC_ARRAY(thread_statements_history_sizing, PFS_events_statements, + MYF(MY_ZEROFILL)); + if (unlikely(thread_statements_history_array == NULL)) + DBUG_RETURN(1); + } -/** - Find the per-thread wait statistics for a rwlock class. - @param thread input thread - @param klass rwlock class - @return the per thread per rwlock class wait stat -*/ -PFS_single_stat_chain * -find_per_thread_rwlock_class_wait_stat(PFS_thread *thread, - PFS_rwlock_class *klass) -{ - PFS_single_stat_chain *stat; - uint index; - DBUG_ENTER("find_per_thread_rwlock_class_wait_stat"); + if (thread_statements_stack_sizing > 0) + { + thread_statements_stack_array= + PFS_MALLOC_ARRAY(thread_statements_stack_sizing, PFS_events_statements, + MYF(MY_ZEROFILL)); + if (unlikely(thread_statements_stack_array == NULL)) + DBUG_RETURN(1); + } - DBUG_ASSERT(thread != NULL); - DBUG_ASSERT(klass != NULL); - index= klass->m_index; - DBUG_ASSERT(index < rwlock_class_max); + if (thread_instr_class_statements_sizing > 0) + { + thread_instr_class_statements_array= + PFS_MALLOC_ARRAY(thread_instr_class_statements_sizing, + PFS_statement_stat, MYF(MY_ZEROFILL)); + if (unlikely(thread_instr_class_statements_array == NULL)) + DBUG_RETURN(1); - stat= &(thread->m_instr_class_wait_stats - [per_thread_rwlock_class_start + index]); - DBUG_RETURN(stat); -} + for (index= 0; index < thread_instr_class_statements_sizing; index++) + thread_instr_class_statements_array[index].reset(); + } -/** - Find the per-thread wait statistics for a condition class. - @param thread input thread - @param klass condition class - @return the per thread per condition class wait stat -*/ -PFS_single_stat_chain * -find_per_thread_cond_class_wait_stat(PFS_thread *thread, - PFS_cond_class *klass) -{ - PFS_single_stat_chain *stat; - uint index; - DBUG_ENTER("find_per_thread_cond_class_wait_stat"); + for (index= 0; index < thread_max; index++) + { + thread_array[index].m_waits_history= + &thread_waits_history_array[index * events_waits_history_per_thread]; + thread_array[index].m_instr_class_waits_stats= + &thread_instr_class_waits_array[index * wait_class_max]; + thread_array[index].m_stages_history= + &thread_stages_history_array[index * events_stages_history_per_thread]; + thread_array[index].m_instr_class_stages_stats= + &thread_instr_class_stages_array[index * stage_class_max]; + thread_array[index].m_statements_history= + &thread_statements_history_array[index * events_statements_history_per_thread]; + thread_array[index].m_statement_stack= + &thread_statements_stack_array[index * statement_stack_max]; + thread_array[index].m_instr_class_statements_stats= + &thread_instr_class_statements_array[index * statement_class_max]; + } - DBUG_ASSERT(thread != NULL); - DBUG_ASSERT(klass != NULL); - index= klass->m_index; - DBUG_ASSERT(index < cond_class_max); + if (wait_class_max > 0) + { + global_instr_class_waits_array= + PFS_MALLOC_ARRAY(wait_class_max, + PFS_single_stat, MYF(MY_ZEROFILL)); + if (unlikely(global_instr_class_waits_array == NULL)) + DBUG_RETURN(1); - stat= &(thread->m_instr_class_wait_stats - [per_thread_cond_class_start + index]); - DBUG_RETURN(stat); -} + for (index= 0; index < wait_class_max; index++) + global_instr_class_waits_array[index].reset(); + } -/** - Find the per-thread wait statistics for a file class. - @param thread input thread - @param klass file class - @return the per thread per file class wait stat -*/ -PFS_single_stat_chain * -find_per_thread_file_class_wait_stat(PFS_thread *thread, - PFS_file_class *klass) -{ - PFS_single_stat_chain *stat; - uint index; - DBUG_ENTER("find_per_thread_file_class_wait_stat"); + if (stage_class_max > 0) + { + global_instr_class_stages_array= + PFS_MALLOC_ARRAY(stage_class_max, + PFS_stage_stat, MYF(MY_ZEROFILL)); + if (unlikely(global_instr_class_stages_array == NULL)) + DBUG_RETURN(1); - DBUG_ASSERT(thread != NULL); - DBUG_ASSERT(klass != NULL); - index= klass->m_index; - DBUG_ASSERT(index < file_class_max); + for (index= 0; index < stage_class_max; index++) + global_instr_class_stages_array[index].reset(); + } - stat= &(thread->m_instr_class_wait_stats - [per_thread_file_class_start + index]); - DBUG_RETURN(stat); -} + if (statement_class_max > 0) + { + global_instr_class_statements_array= + PFS_MALLOC_ARRAY(statement_class_max, + PFS_statement_stat, MYF(MY_ZEROFILL)); + if (unlikely(global_instr_class_statements_array == NULL)) + DBUG_RETURN(1); -/** Reset the wait statistics per thread. */ -void reset_per_thread_wait_stat(void) -{ - PFS_single_stat_chain *stat= thread_instr_class_waits_array; - PFS_single_stat_chain *stat_last= stat + thread_instr_class_waits_sizing; - DBUG_ENTER("reset_per_thread_wait_stat"); + for (index= 0; index < statement_class_max; index++) + global_instr_class_statements_array[index].reset(); + } - for ( ; stat < stat_last; stat++) - reset_single_stat_link(stat); - DBUG_VOID_RETURN; + DBUG_RETURN(0); } /** Cleanup all the instruments buffers. */ void cleanup_instruments(void) { DBUG_ENTER("cleanup_instruments"); - pfs_free(mutex_array); mutex_array= NULL; mutex_max= 0; @@ -411,18 +445,33 @@ void cleanup_instruments(void) pfs_free(table_array); table_array= NULL; table_max= 0; + pfs_free(socket_array); + socket_array= NULL; + socket_max= 0; pfs_free(thread_array); thread_array= NULL; thread_max= 0; - pfs_free(thread_history_array); - thread_history_array= NULL; + pfs_free(thread_waits_history_array); + thread_waits_history_array= NULL; + pfs_free(thread_stages_history_array); + thread_stages_history_array= NULL; + pfs_free(thread_statements_history_array); + thread_statements_history_array= NULL; + pfs_free(thread_statements_stack_array); + thread_statements_stack_array= NULL; pfs_free(thread_instr_class_waits_array); thread_instr_class_waits_array= NULL; + pfs_free(global_instr_class_waits_array); + global_instr_class_waits_array= NULL; + pfs_free(global_instr_class_stages_array); + global_instr_class_stages_array= NULL; + pfs_free(global_instr_class_statements_array); + global_instr_class_statements_array= NULL; DBUG_VOID_RETURN; } -extern "C" -{ +C_MODE_START +/** Get hash table key for instrumented files. */ static uchar *filename_hash_get_key(const uchar *entry, size_t *length, my_bool) { @@ -439,7 +488,7 @@ static uchar *filename_hash_get_key(const uchar *entry, size_t *length, result= file->m_filename; DBUG_RETURN(const_cast<uchar*> (reinterpret_cast<const uchar*> (result))); } -} +C_MODE_END /** Initialize the file name hash. @@ -551,37 +600,52 @@ void PFS_scan::init(uint random, uint max_size) */ PFS_mutex* create_mutex(PFS_mutex_class *klass, const void *identity) { - PFS_scan scan; - uint random= randomized_index(identity, mutex_max); + static uint mutex_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_mutex *pfs; DBUG_ENTER("create_mutex"); - for (scan.init(random, mutex_max); - scan.has_pass(); - scan.next_pass()) + while (++attempts <= mutex_max) { - PFS_mutex *pfs= mutex_array + scan.first(); - PFS_mutex *pfs_last= mutex_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + /* + Problem: + Multiple threads running concurrently may need to create a new + instrumented mutex, and find an empty slot in mutex_array[]. + With N1 threads running on a N2 core hardware: + - up to N2 hardware threads can run concurrently, + causing contention if looking at the same array[i] slot. + - up to N1 threads can run almost concurrently (with thread scheduling), + scanning maybe overlapping regions in the [0-mutex_max] array. + + Solution: + Instead of letting different threads compete on the same array[i] entry, + this code forces all threads to cooperate with the monotonic_index. + Only one thread will be allowed to test a given array[i] slot. + All threads do scan from the same region, starting at monotonic_index. + Serializing on monotonic_index ensures that when a slot is found occupied + in a given loop by a given thread, other threads will not attempt this + slot. + */ + index= PFS_atomic::add_u32(& mutex_monotonic_index, 1) % mutex_max; + pfs= mutex_array + index; + + if (pfs->m_lock.is_free()) { - if (pfs->m_lock.is_free()) + if (pfs->m_lock.free_to_dirty()) { - if (pfs->m_lock.free_to_dirty()) - { - pfs->m_identity= identity; - pfs->m_class= klass; - pfs->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_instance; - pfs->m_wait_stat.m_parent= &klass->m_wait_stat; - reset_single_stat_link(&pfs->m_wait_stat); - pfs->m_lock_stat.m_control_flag= - &flag_events_locks_summary_by_instance; - pfs->m_lock_stat.m_parent= &klass->m_lock_stat; - reset_single_stat_link(&pfs->m_lock_stat); - pfs->m_owner= NULL; - pfs->m_last_locked= 0; - pfs->m_lock.dirty_to_allocated(); - DBUG_RETURN(pfs); - } + pfs->m_identity= identity; + pfs->m_class= klass; + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + pfs->m_wait_stat.reset(); + pfs->m_lock_stat.reset(); + pfs->m_owner= NULL; + pfs->m_last_locked= 0; + pfs->m_lock.dirty_to_allocated(); + if (klass->is_singleton()) + klass->m_singleton= pfs; + DBUG_RETURN(pfs); } } } @@ -597,8 +661,14 @@ PFS_mutex* create_mutex(PFS_mutex_class *klass, const void *identity) void destroy_mutex(PFS_mutex *pfs) { DBUG_ENTER("destroy_mutex"); - DBUG_ASSERT(pfs != NULL); + PFS_mutex_class *klass= pfs->m_class; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_EVENT_NAME */ + uint index= klass->m_event_name_index; + global_instr_class_waits_array[index].aggregate(& pfs->m_wait_stat); + pfs->m_wait_stat.reset(); + if (klass->is_singleton()) + klass->m_singleton= NULL; pfs->m_lock.allocated_to_free(); DBUG_VOID_RETURN; } @@ -611,43 +681,37 @@ void destroy_mutex(PFS_mutex *pfs) */ PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity) { - PFS_scan scan; - uint random= randomized_index(identity, rwlock_max); + static uint rwlock_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_rwlock *pfs; DBUG_ENTER("create_rwlock"); - for (scan.init(random, rwlock_max); - scan.has_pass(); - scan.next_pass()) + while (++attempts <= rwlock_max) { - PFS_rwlock *pfs= rwlock_array + scan.first(); - PFS_rwlock *pfs_last= rwlock_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + /* See create_mutex() */ + index= PFS_atomic::add_u32(& rwlock_monotonic_index, 1) % rwlock_max; + pfs= rwlock_array + index; + + if (pfs->m_lock.is_free()) { - if (pfs->m_lock.is_free()) + if (pfs->m_lock.free_to_dirty()) { - if (pfs->m_lock.free_to_dirty()) - { - pfs->m_identity= identity; - pfs->m_class= klass; - pfs->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_instance; - pfs->m_wait_stat.m_parent= &klass->m_wait_stat; - reset_single_stat_link(&pfs->m_wait_stat); - pfs->m_lock.dirty_to_allocated(); - pfs->m_read_lock_stat.m_control_flag= - &flag_events_locks_summary_by_instance; - pfs->m_read_lock_stat.m_parent= &klass->m_read_lock_stat; - reset_single_stat_link(&pfs->m_read_lock_stat); - pfs->m_write_lock_stat.m_control_flag= - &flag_events_locks_summary_by_instance; - pfs->m_write_lock_stat.m_parent= &klass->m_write_lock_stat; - reset_single_stat_link(&pfs->m_write_lock_stat); - pfs->m_writer= NULL; - pfs->m_readers= 0; - pfs->m_last_written= 0; - pfs->m_last_read= 0; - DBUG_RETURN(pfs); - } + pfs->m_identity= identity; + pfs->m_class= klass; + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + pfs->m_wait_stat.reset(); + pfs->m_lock.dirty_to_allocated(); + pfs->m_read_lock_stat.reset(); + pfs->m_write_lock_stat.reset(); + pfs->m_writer= NULL; + pfs->m_readers= 0; + pfs->m_last_written= 0; + pfs->m_last_read= 0; + if (klass->is_singleton()) + klass->m_singleton= pfs; + DBUG_RETURN(pfs); } } } @@ -663,8 +727,14 @@ PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity) void destroy_rwlock(PFS_rwlock *pfs) { DBUG_ENTER("destroy_rwlock"); - DBUG_ASSERT(pfs != NULL); + PFS_rwlock_class *klass= pfs->m_class; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_EVENT_NAME */ + uint index= klass->m_event_name_index; + global_instr_class_waits_array[index].aggregate(& pfs->m_wait_stat); + pfs->m_wait_stat.reset(); + if (klass->is_singleton()) + klass->m_singleton= NULL; pfs->m_lock.allocated_to_free(); DBUG_VOID_RETURN; } @@ -677,33 +747,33 @@ void destroy_rwlock(PFS_rwlock *pfs) */ PFS_cond* create_cond(PFS_cond_class *klass, const void *identity) { - PFS_scan scan; - uint random= randomized_index(identity, cond_max); + static uint cond_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_cond *pfs; DBUG_ENTER("create_cond"); - for (scan.init(random, cond_max); - scan.has_pass(); - scan.next_pass()) + while (++attempts <= cond_max) { - PFS_cond *pfs= cond_array + scan.first(); - PFS_cond *pfs_last= cond_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + /* See create_mutex() */ + index= PFS_atomic::add_u32(& cond_monotonic_index, 1) % cond_max; + pfs= cond_array + index; + + if (pfs->m_lock.is_free()) { - if (pfs->m_lock.is_free()) + if (pfs->m_lock.free_to_dirty()) { - if (pfs->m_lock.free_to_dirty()) - { - pfs->m_identity= identity; - pfs->m_class= klass; - pfs->m_cond_stat.m_signal_count= 0; - pfs->m_cond_stat.m_broadcast_count= 0; - pfs->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_instance; - pfs->m_wait_stat.m_parent= &klass->m_wait_stat; - reset_single_stat_link(&pfs->m_wait_stat); - pfs->m_lock.dirty_to_allocated(); - DBUG_RETURN(pfs); - } + pfs->m_identity= identity; + pfs->m_class= klass; + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + pfs->m_cond_stat.m_signal_count= 0; + pfs->m_cond_stat.m_broadcast_count= 0; + pfs->m_wait_stat.reset(); + pfs->m_lock.dirty_to_allocated(); + if (klass->is_singleton()) + klass->m_singleton= pfs; + DBUG_RETURN(pfs); } } } @@ -718,13 +788,26 @@ PFS_cond* create_cond(PFS_cond_class *klass, const void *identity) */ void destroy_cond(PFS_cond *pfs) { - DBUG_ENTER("destroy_cond"); + DBUG_ENTER("destroy_thread"); DBUG_ASSERT(pfs != NULL); + PFS_cond_class *klass= pfs->m_class; + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_EVENT_NAME */ + uint index= klass->m_event_name_index; + global_instr_class_waits_array[index].aggregate(& pfs->m_wait_stat); + pfs->m_wait_stat.reset(); + if (klass->is_singleton()) + klass->m_singleton= NULL; pfs->m_lock.allocated_to_free(); DBUG_VOID_RETURN; } +PFS_thread* PFS_thread::get_current_thread() +{ + PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + return pfs; +} + /** Create instrumentation for a thread instance. @param klass the thread class @@ -737,41 +820,127 @@ void destroy_cond(PFS_cond *pfs) PFS_thread* create_thread(PFS_thread_class *klass, const void *identity, ulong thread_id) { - PFS_scan scan; - uint random= randomized_index(identity, thread_max); + static uint thread_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_thread *pfs; DBUG_ENTER("create_thread"); - for (scan.init(random, thread_max); - scan.has_pass(); - scan.next_pass()) + while (++attempts <= thread_max) { - PFS_thread *pfs= thread_array + scan.first(); - PFS_thread *pfs_last= thread_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + /* See create_mutex() */ + index= PFS_atomic::add_u32(& thread_monotonic_index, 1) % thread_max; + pfs= thread_array + index; + + if (pfs->m_lock.is_free()) { - if (pfs->m_lock.is_free()) + if (pfs->m_lock.free_to_dirty()) { - if (pfs->m_lock.free_to_dirty()) + pfs->m_thread_internal_id= + PFS_atomic::add_u32(&thread_internal_id_counter, 1); + pfs->m_parent_thread_internal_id= 0; + pfs->m_thread_id= thread_id; + pfs->m_event_id= 1; + pfs->m_enabled= true; + pfs->m_class= klass; + pfs->m_events_waits_current= & pfs->m_events_waits_stack[WAIT_STACK_BOTTOM]; + pfs->m_waits_history_full= false; + pfs->m_waits_history_index= 0; + pfs->m_stages_history_full= false; + pfs->m_stages_history_index= 0; + pfs->m_statements_history_full= false; + pfs->m_statements_history_index= 0; + + pfs->reset_stats(); + + pfs->m_filename_hash_pins= NULL; + pfs->m_table_share_hash_pins= NULL; + pfs->m_setup_actor_hash_pins= NULL; + pfs->m_setup_object_hash_pins= NULL; + pfs->m_user_hash_pins= NULL; + pfs->m_account_hash_pins= NULL; + pfs->m_host_hash_pins= NULL; + pfs->m_digest_hash_pins= NULL; + + pfs->m_username_length= 0; + pfs->m_hostname_length= 0; + pfs->m_dbname_length= 0; + pfs->m_command= 0; + pfs->m_start_time= 0; + pfs->m_processlist_state_length= 0; + pfs->m_processlist_info_length= 0; + + pfs->m_host= NULL; + pfs->m_user= NULL; + pfs->m_account= NULL; + set_thread_account(pfs); + + PFS_events_waits *child_wait; + for (index= 0; index < WAIT_STACK_SIZE; index++) { - pfs->m_thread_internal_id= - PFS_atomic::add_u32(&thread_internal_id_counter, 1); - pfs->m_thread_id= thread_id; - pfs->m_event_id= 1; - pfs->m_enabled= true; - pfs->m_class= klass; - pfs->m_wait_locker_count= 0; - pfs->m_waits_history_full= false; - pfs->m_waits_history_index= 0; - - PFS_single_stat_chain *stat= pfs->m_instr_class_wait_stats; - PFS_single_stat_chain *stat_last= stat + instr_class_per_thread; - for ( ; stat < stat_last; stat++) - reset_single_stat_link(stat); - pfs->m_filename_hash_pins= NULL; - pfs->m_table_share_hash_pins= NULL; - pfs->m_lock.dirty_to_allocated(); - DBUG_RETURN(pfs); + child_wait= & pfs->m_events_waits_stack[index]; + child_wait->m_thread_internal_id= pfs->m_thread_internal_id; + child_wait->m_event_id= 0; + child_wait->m_end_event_id= 0; + child_wait->m_event_type= EVENT_TYPE_STATEMENT; + child_wait->m_wait_class= NO_WAIT_CLASS; } + + PFS_events_stages *child_stage= & pfs->m_stage_current; + child_stage->m_thread_internal_id= pfs->m_thread_internal_id; + child_stage->m_event_id= 0; + child_stage->m_end_event_id= 0; + child_stage->m_event_type= EVENT_TYPE_STATEMENT; + child_stage->m_class= NULL; + child_stage->m_timer_start= 0; + child_stage->m_timer_end= 0; + child_stage->m_source_file= NULL; + child_stage->m_source_line= 0; + + PFS_events_statements *child_statement; + for (index= 0; index < statement_stack_max; index++) + { + child_statement= & pfs->m_statement_stack[index]; + child_statement->m_thread_internal_id= pfs->m_thread_internal_id; + child_statement->m_event_id= 0; + child_statement->m_end_event_id= 0; + child_statement->m_event_type= EVENT_TYPE_STATEMENT; + child_statement->m_class= NULL; + child_statement->m_timer_start= 0; + child_statement->m_timer_end= 0; + child_statement->m_lock_time= 0; + child_statement->m_source_file= NULL; + child_statement->m_source_line= 0; + child_statement->m_current_schema_name_length= 0; + child_statement->m_sqltext_length= 0; + + child_statement->m_message_text[0]= '\0'; + child_statement->m_sql_errno= 0; + child_statement->m_sqlstate[0]= '\0'; + child_statement->m_error_count= 0; + child_statement->m_warning_count= 0; + child_statement->m_rows_affected= 0; + + child_statement->m_rows_sent= 0; + child_statement->m_rows_examined= 0; + child_statement->m_created_tmp_disk_tables= 0; + child_statement->m_created_tmp_tables= 0; + child_statement->m_select_full_join= 0; + child_statement->m_select_full_range_join= 0; + child_statement->m_select_range= 0; + child_statement->m_select_range_check= 0; + child_statement->m_select_scan= 0; + child_statement->m_sort_merge_passes= 0; + child_statement->m_sort_range= 0; + child_statement->m_sort_rows= 0; + child_statement->m_sort_scan= 0; + child_statement->m_no_index_used= 0; + child_statement->m_no_good_index_used= 0; + } + pfs->m_events_statements_count= 0; + + pfs->m_lock.dirty_to_allocated(); + DBUG_RETURN(pfs); } } } @@ -780,6 +949,21 @@ PFS_thread* create_thread(PFS_thread_class *klass, const void *identity, DBUG_RETURN(NULL); } +PFS_mutex *sanitize_mutex(PFS_mutex *unsafe) +{ + SANITIZE_ARRAY_BODY(PFS_mutex, mutex_array, mutex_max, unsafe); +} + +PFS_rwlock *sanitize_rwlock(PFS_rwlock *unsafe) +{ + SANITIZE_ARRAY_BODY(PFS_rwlock, rwlock_array, rwlock_max, unsafe); +} + +PFS_cond *sanitize_cond(PFS_cond *unsafe) +{ + SANITIZE_ARRAY_BODY(PFS_cond, cond_array, cond_max, unsafe); +} + /** Sanitize a PFS_thread pointer. Validate that the PFS_thread is part of thread_array. @@ -794,25 +978,14 @@ PFS_thread *sanitize_thread(PFS_thread *unsafe) SANITIZE_ARRAY_BODY(PFS_thread, thread_array, thread_max, unsafe); } -const char *sanitize_file_name(const char *unsafe) +PFS_file *sanitize_file(PFS_file *unsafe) { - intptr ptr= (intptr) unsafe; - intptr first= (intptr) &file_array[0]; - intptr last= (intptr) &file_array[file_max]; - DBUG_ENTER("sanitize_file_name"); + SANITIZE_ARRAY_BODY(PFS_file, file_array, file_max, unsafe); +} - /* Check if unsafe points inside file_array[] */ - if (likely((first <= ptr) && (ptr < last))) - { - /* Check if unsafe points to PFS_file::m_filename */ - intptr offset= (ptr - first) % sizeof(PFS_file); - intptr valid_offset= my_offsetof(PFS_file, m_filename[0]); - if (likely(offset == valid_offset)) - { - DBUG_RETURN(unsafe); - } - } - DBUG_RETURN(NULL); +PFS_socket *sanitize_socket(PFS_socket *unsafe) +{ + SANITIZE_ARRAY_BODY(PFS_socket, socket_array, socket_max, unsafe); } /** @@ -824,6 +997,26 @@ void destroy_thread(PFS_thread *pfs) DBUG_ENTER("destroy_thread"); DBUG_ASSERT(pfs != NULL); + if (pfs->m_account != NULL) + { + pfs->m_account->release(); + pfs->m_account= NULL; + DBUG_ASSERT(pfs->m_user == NULL); + DBUG_ASSERT(pfs->m_host == NULL); + } + else + { + if (pfs->m_user != NULL) + { + pfs->m_user->release(); + pfs->m_user= NULL; + } + if (pfs->m_host != NULL) + { + pfs->m_host->release(); + pfs->m_host= NULL; + } + } if (pfs->m_filename_hash_pins) { lf_hash_put_pins(pfs->m_filename_hash_pins); @@ -834,6 +1027,36 @@ void destroy_thread(PFS_thread *pfs) lf_hash_put_pins(pfs->m_table_share_hash_pins); pfs->m_table_share_hash_pins= NULL; } + if (pfs->m_setup_actor_hash_pins) + { + lf_hash_put_pins(pfs->m_setup_actor_hash_pins); + pfs->m_setup_actor_hash_pins= NULL; + } + if (pfs->m_setup_object_hash_pins) + { + lf_hash_put_pins(pfs->m_setup_object_hash_pins); + pfs->m_setup_object_hash_pins= NULL; + } + if (pfs->m_user_hash_pins) + { + lf_hash_put_pins(pfs->m_user_hash_pins); + pfs->m_user_hash_pins= NULL; + } + if (pfs->m_account_hash_pins) + { + lf_hash_put_pins(pfs->m_account_hash_pins); + pfs->m_account_hash_pins= NULL; + } + if (pfs->m_host_hash_pins) + { + lf_hash_put_pins(pfs->m_host_hash_pins); + pfs->m_host_hash_pins= NULL; + } + if (pfs->m_digest_hash_pins) + { + lf_hash_put_pins(pfs->m_digest_hash_pins); + pfs->m_digest_hash_pins= NULL; + } pfs->m_lock.allocated_to_free(); DBUG_VOID_RETURN; } @@ -867,19 +1090,18 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, const char *filename, uint len) { PFS_file *pfs; - PFS_scan scan; + LF_PINS *pins; + char safe_buffer[FN_REFLEN]; + const char *safe_filename; DBUG_ENTER("find_or_create_file"); - LF_PINS *pins= get_filename_hash_pins(thread); + pins= get_filename_hash_pins(thread); if (unlikely(pins == NULL)) { file_lost++; DBUG_RETURN(NULL); } - char safe_buffer[FN_REFLEN]; - const char *safe_filename; - if (len >= FN_REFLEN) { /* @@ -948,7 +1170,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, /* Append the unresolved file name to the resolved path */ char *ptr= buffer + strlen(buffer); char *buf_end= &buffer[sizeof(buffer)-1]; - if ((buf_end > ptr) && (*(ptr-1) != FN_LIBCHAR)) + if (buf_end > ptr) *ptr++= FN_LIBCHAR; if (buf_end > ptr) strncpy(ptr, safe_filename + dirlen, buf_end - ptr); @@ -960,7 +1182,12 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, PFS_file **entry; uint retry_count= 0; const uint retry_max= 3; + static uint file_monotonic_index= 0; + uint index; + uint attempts= 0; + search: + entry= reinterpret_cast<PFS_file**> (lf_hash_search(&filename_hash, pins, normalized_filename, normalized_length)); @@ -974,58 +1201,55 @@ search: lf_hash_search_unpin(pins); - /* filename is not constant, just using it for noise on create */ - uint random= randomized_index(filename, file_max); - - for (scan.init(random, file_max); - scan.has_pass(); - scan.next_pass()) + while (++attempts <= file_max) { - pfs= file_array + scan.first(); - PFS_file *pfs_last= file_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + /* See create_mutex() */ + index= PFS_atomic::add_u32(& file_monotonic_index, 1) % file_max; + pfs= file_array + index; + + if (pfs->m_lock.is_free()) { - if (pfs->m_lock.is_free()) + if (pfs->m_lock.free_to_dirty()) { - if (pfs->m_lock.free_to_dirty()) + pfs->m_class= klass; + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + strncpy(pfs->m_filename, normalized_filename, normalized_length); + pfs->m_filename[normalized_length]= '\0'; + pfs->m_filename_length= normalized_length; + pfs->m_wait_stat.reset(); + pfs->m_file_stat.m_open_count= 1; + pfs->m_file_stat.m_io_stat.reset(); + pfs->m_identity= (const void *)pfs; + + int res; + res= lf_hash_insert(&filename_hash, thread->m_filename_hash_pins, + &pfs); + if (likely(res == 0)) { - pfs->m_class= klass; - strncpy(pfs->m_filename, normalized_filename, normalized_length); - pfs->m_filename[normalized_length]= '\0'; - pfs->m_filename_length= normalized_length; - pfs->m_file_stat.m_open_count= 1; - pfs->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_instance; - pfs->m_wait_stat.m_parent= &klass->m_wait_stat; - reset_single_stat_link(&pfs->m_wait_stat); - - int res; - res= lf_hash_insert(&filename_hash, pins, - &pfs); - if (likely(res == 0)) - { - pfs->m_lock.dirty_to_allocated(); - DBUG_RETURN(pfs); - } + pfs->m_lock.dirty_to_allocated(); + if (klass->is_singleton()) + klass->m_singleton= pfs; + DBUG_RETURN(pfs); + } - pfs->m_lock.dirty_to_free(); + pfs->m_lock.dirty_to_free(); - if (res > 0) + if (res > 0) + { + /* Duplicate insert by another thread */ + if (++retry_count > retry_max) { - /* Duplicate insert by another thread */ - if (++retry_count > retry_max) - { - /* Avoid infinite loops */ - file_lost++; - DBUG_RETURN(NULL); - } - goto search; + /* Avoid infinite loops */ + file_lost++; + DBUG_RETURN(NULL); } - - /* OOM in lf_hash_insert */ - file_lost++; - DBUG_RETURN(NULL); + goto search; } + + /* OOM in lf_hash_insert */ + file_lost++; + return NULL; } } } @@ -1058,12 +1282,27 @@ void destroy_file(PFS_thread *thread, PFS_file *pfs) DBUG_ASSERT(thread != NULL); DBUG_ASSERT(pfs != NULL); + PFS_file_class *klass= pfs->m_class; + + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_EVENT_NAME */ + uint index= klass->m_event_name_index; + global_instr_class_waits_array[index].aggregate(& pfs->m_wait_stat); + pfs->m_wait_stat.reset(); + + /* Aggregate to FILE_SUMMARY_BY_EVENT_NAME */ + klass->m_file_stat.m_io_stat.aggregate(& pfs->m_file_stat.m_io_stat); + pfs->m_file_stat.m_io_stat.reset(); + + if (klass->is_singleton()) + klass->m_singleton= NULL; LF_PINS *pins= get_filename_hash_pins(thread); DBUG_ASSERT(pins != NULL); lf_hash_delete(&filename_hash, pins, pfs->m_filename, pfs->m_filename_length); + if (klass->is_singleton()) + klass->m_singleton= NULL; pfs->m_lock.allocated_to_free(); DBUG_VOID_RETURN; } @@ -1071,53 +1310,282 @@ void destroy_file(PFS_thread *thread, PFS_file *pfs) /** Create instrumentation for a table instance. @param share the table share + @param opening_thread the opening thread @param identity the table address @return a table instance, or NULL */ -PFS_table* create_table(PFS_table_share *share, const void *identity) +PFS_table* create_table(PFS_table_share *share, PFS_thread *opening_thread, + const void *identity) { - PFS_scan scan; - uint random= randomized_index(identity, table_max); + static uint table_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_table *pfs; DBUG_ENTER("create_table"); - for (scan.init(random, table_max); + while (++attempts <= table_max) + { + /* See create_mutex() */ + index= PFS_atomic::add_u32(& table_monotonic_index, 1) % table_max; + pfs= table_array + index; + + if (pfs->m_lock.is_free()) + { + if (pfs->m_lock.free_to_dirty()) + { + pfs->m_identity= identity; + pfs->m_share= share; + pfs->m_io_enabled= share->m_enabled && + flag_global_instrumentation && global_table_io_class.m_enabled; + pfs->m_io_timed= share->m_timed && global_table_io_class.m_timed; + pfs->m_lock_enabled= share->m_enabled && + flag_global_instrumentation && global_table_lock_class.m_enabled; + pfs->m_lock_timed= share->m_timed && global_table_lock_class.m_timed; + pfs->m_has_io_stats= false; + pfs->m_has_lock_stats= false; + share->inc_refcount(); + pfs->m_table_stat.fast_reset(); + pfs->m_thread_owner= opening_thread; + pfs->m_lock.dirty_to_allocated(); + DBUG_RETURN(pfs); + } + } + } + + table_lost++; + DBUG_RETURN(NULL); +} + +void PFS_table::sanitized_aggregate(void) +{ + /* + This thread could be a TRUNCATE on an aggregated summary table, + and not own the table handle. + */ + PFS_table_share *safe_share= sanitize_table_share(m_share); + PFS_thread *safe_thread= sanitize_thread(m_thread_owner); + if ((safe_share != NULL && safe_thread != NULL) && + (m_has_io_stats || m_has_lock_stats)) + { + safe_aggregate(& m_table_stat, safe_share, safe_thread); + m_has_io_stats= false; + m_has_lock_stats= false; + } +} + +void PFS_table::sanitized_aggregate_io(void) +{ + PFS_table_share *safe_share= sanitize_table_share(m_share); + PFS_thread *safe_thread= sanitize_thread(m_thread_owner); + if (safe_share != NULL && safe_thread != NULL && m_has_io_stats) + { + safe_aggregate_io(& m_table_stat, safe_share, safe_thread); + m_has_io_stats= false; + } +} + +void PFS_table::sanitized_aggregate_lock(void) +{ + PFS_table_share *safe_share= sanitize_table_share(m_share); + PFS_thread *safe_thread= sanitize_thread(m_thread_owner); + if (safe_share != NULL && safe_thread != NULL && m_has_lock_stats) + { + safe_aggregate_lock(& m_table_stat, safe_share, safe_thread); + m_has_lock_stats= false; + } +} + +void PFS_table::safe_aggregate(PFS_table_stat *table_stat, + PFS_table_share *table_share, + PFS_thread *thread) +{ + DBUG_ASSERT(table_stat != NULL); + DBUG_ASSERT(table_share != NULL); + DBUG_ASSERT(thread != NULL); + + if (flag_thread_instrumentation && thread->m_enabled) + { + PFS_single_stat *event_name_array; + uint index; + event_name_array= thread->m_instr_class_waits_stats; + + /* + Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + (for wait/io/table/sql/handler) + */ + index= global_table_io_class.m_event_name_index; + table_stat->sum_io(& event_name_array[index]); + + /* + Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + (for wait/lock/table/sql/handler) + */ + index= global_table_lock_class.m_event_name_index; + table_stat->sum_lock(& event_name_array[index]); + } + + /* Aggregate to TABLE_IO_SUMMARY, TABLE_LOCK_SUMMARY */ + table_share->m_table_stat.aggregate(table_stat); + table_stat->fast_reset(); +} + +void PFS_table::safe_aggregate_io(PFS_table_stat *table_stat, + PFS_table_share *table_share, + PFS_thread *thread) +{ + DBUG_ASSERT(table_stat != NULL); + DBUG_ASSERT(table_share != NULL); + DBUG_ASSERT(thread != NULL); + + if (flag_thread_instrumentation && thread->m_enabled) + { + PFS_single_stat *event_name_array; + uint index; + event_name_array= thread->m_instr_class_waits_stats; + + /* + Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + (for wait/io/table/sql/handler) + */ + index= global_table_io_class.m_event_name_index; + table_stat->sum_io(& event_name_array[index]); + } + + /* Aggregate to TABLE_IO_SUMMARY */ + table_share->m_table_stat.aggregate_io(table_stat); + table_stat->fast_reset_io(); +} + +void PFS_table::safe_aggregate_lock(PFS_table_stat *table_stat, + PFS_table_share *table_share, + PFS_thread *thread) +{ + DBUG_ASSERT(table_stat != NULL); + DBUG_ASSERT(table_share != NULL); + DBUG_ASSERT(thread != NULL); + + if (flag_thread_instrumentation && thread->m_enabled) + { + PFS_single_stat *event_name_array; + uint index; + event_name_array= thread->m_instr_class_waits_stats; + + /* + Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + (for wait/lock/table/sql/handler) + */ + index= global_table_lock_class.m_event_name_index; + table_stat->sum_lock(& event_name_array[index]); + } + + /* Aggregate to TABLE_LOCK_SUMMARY */ + table_share->m_table_stat.aggregate_lock(table_stat); + table_stat->fast_reset_lock(); +} + +/** + Destroy instrumentation for a table instance. + @param pfs the table to destroy +*/ +void destroy_table(PFS_table *pfs) +{ + DBUG_ENTER("destroy_table"); + + DBUG_ASSERT(pfs != NULL); + pfs->m_share->dec_refcount(); + pfs->m_lock.allocated_to_free(); + DBUG_VOID_RETURN; +} + +/** + Create instrumentation for a socket instance. + @param klass the socket class + @param identity the socket descriptor + @return a socket instance, or NULL +*/ +PFS_socket* create_socket(PFS_socket_class *klass, const void *identity) +{ + PFS_scan scan; + DBUG_ENTER("create_socket"); + + /** + Unlike other instrumented objects, there is no socket 'object' to use as a + unique identifier. Instead, a pointer to the PFS_socket object will be used + to identify this socket instance. The socket descriptor will be used to + seed the the random index assignment. + */ + my_socket fd= likely(identity != NULL) ? + *(reinterpret_cast<const my_socket*>(identity)) : 0; + my_ptrdiff_t ptr= fd; + uint random= randomized_index((const void *)ptr, socket_max); + + for (scan.init(random, socket_max); scan.has_pass(); scan.next_pass()) { - PFS_table *pfs= table_array + scan.first(); - PFS_table *pfs_last= table_array + scan.last(); + PFS_socket *pfs= socket_array + scan.first(); + PFS_socket *pfs_last= socket_array + scan.last(); for ( ; pfs < pfs_last; pfs++) { if (pfs->m_lock.is_free()) { if (pfs->m_lock.free_to_dirty()) { - pfs->m_identity= identity; - pfs->m_share= share; - pfs->m_wait_stat.m_control_flag= - &flag_events_waits_summary_by_instance; - pfs->m_wait_stat.m_parent= &share->m_wait_stat; - reset_single_stat_link(&pfs->m_wait_stat); + pfs->m_fd= fd; + pfs->m_identity= pfs; + pfs->m_class= klass; + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + pfs->m_idle= false; + pfs->m_socket_stat.reset(); pfs->m_lock.dirty_to_allocated(); + pfs->m_thread_owner= NULL; + if (klass->is_singleton()) + klass->m_singleton= pfs; DBUG_RETURN(pfs); } } } } - table_lost++; + socket_lost++; DBUG_RETURN(NULL); } /** - Destroy instrumentation for a table instance. - @param pfs the table to destroy + Destroy instrumentation for a socket instance. + @param pfs the socket to destroy */ -void destroy_table(PFS_table *pfs) +void destroy_socket(PFS_socket *pfs) { - DBUG_ENTER("destroy_table"); - DBUG_ASSERT(pfs != NULL); + PFS_socket_class *klass= pfs->m_class; + DBUG_ENTER("destroy_socket"); + + /* Aggregate to SOCKET_SUMMARY_BY_EVENT_NAME */ + klass->m_socket_stat.m_io_stat.aggregate(&pfs->m_socket_stat.m_io_stat); + + if (klass->is_singleton()) + klass->m_singleton= NULL; + + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME */ + PFS_thread *thread= pfs->m_thread_owner; + if (thread != NULL) + { + PFS_single_stat *event_name_array; + event_name_array= thread->m_instr_class_waits_stats; + uint index= pfs->m_class->m_event_name_index; + + /* Combine stats for all operations */ + PFS_single_stat stat; + pfs->m_socket_stat.m_io_stat.sum_waits(&stat); + event_name_array[index].aggregate(&stat); + } + + pfs->m_socket_stat.reset(); + pfs->m_thread_owner= NULL; + pfs->m_fd= 0; + pfs->m_addr_len= 0; pfs->m_lock.allocated_to_free(); DBUG_VOID_RETURN; } @@ -1129,7 +1597,7 @@ static void reset_mutex_waits_by_instance(void) DBUG_ENTER("reset_mutex_waits_by_instance"); for ( ; pfs < pfs_last; pfs++) - reset_single_stat_link(&pfs->m_wait_stat); + pfs->m_wait_stat.reset(); DBUG_VOID_RETURN; } @@ -1140,7 +1608,7 @@ static void reset_rwlock_waits_by_instance(void) DBUG_ENTER("reset_rwlock_waits_by_instance"); for ( ; pfs < pfs_last; pfs++) - reset_single_stat_link(&pfs->m_wait_stat); + pfs->m_wait_stat.reset(); DBUG_VOID_RETURN; } @@ -1151,7 +1619,7 @@ static void reset_cond_waits_by_instance(void) DBUG_ENTER("reset_cond_waits_by_instance"); for ( ; pfs < pfs_last; pfs++) - reset_single_stat_link(&pfs->m_wait_stat); + pfs->m_wait_stat.reset(); DBUG_VOID_RETURN; } @@ -1162,20 +1630,27 @@ static void reset_file_waits_by_instance(void) DBUG_ENTER("reset_file_waits_by_instance"); for ( ; pfs < pfs_last; pfs++) - reset_single_stat_link(&pfs->m_wait_stat); + pfs->m_file_stat.reset(); DBUG_VOID_RETURN; } +static void reset_socket_waits_by_instance(void) +{ + PFS_socket *pfs= socket_array; + PFS_socket *pfs_last= socket_array + socket_max; + + for ( ; pfs < pfs_last; pfs++) + pfs->m_socket_stat.reset(); +} + /** Reset the wait statistics per object instance. */ void reset_events_waits_by_instance(void) { - DBUG_ENTER("reset_events_waits_by_instance"); - reset_mutex_waits_by_instance(); reset_rwlock_waits_by_instance(); reset_cond_waits_by_instance(); reset_file_waits_by_instance(); - DBUG_VOID_RETURN; + reset_socket_waits_by_instance(); } /** Reset the io statistics per file instance. */ @@ -1186,8 +1661,595 @@ void reset_file_instance_io(void) DBUG_ENTER("reset_file_instance_io"); for ( ; pfs < pfs_last; pfs++) - reset_file_stat(&pfs->m_file_stat); + pfs->m_file_stat.m_io_stat.reset(); + DBUG_VOID_RETURN; +} + +/** Reset the io statistics per socket instance. */ +void reset_socket_instance_io(void) +{ + PFS_socket *pfs= socket_array; + PFS_socket *pfs_last= socket_array + socket_max; + DBUG_ENTER("reset_socket_instance_io"); + + for ( ; pfs < pfs_last; pfs++) + pfs->m_socket_stat.m_io_stat.reset(); DBUG_VOID_RETURN; } +void reset_global_wait_stat() +{ + PFS_single_stat *stat= global_instr_class_waits_array; + PFS_single_stat *stat_last= global_instr_class_waits_array + wait_class_max; + + for ( ; stat < stat_last; stat++) + stat->reset(); +} + +void aggregate_all_event_names(PFS_single_stat *from_array, + PFS_single_stat *to_array) +{ + PFS_single_stat *from; + PFS_single_stat *from_last; + PFS_single_stat *to; + + from= from_array; + from_last= from_array + wait_class_max; + to= to_array; + + for ( ; from < from_last ; from++, to++) + { + if (from->m_count > 0) + { + to->aggregate(from); + from->reset(); + } + } +} + +void aggregate_all_event_names(PFS_single_stat *from_array, + PFS_single_stat *to_array_1, + PFS_single_stat *to_array_2) +{ + PFS_single_stat *from; + PFS_single_stat *from_last; + PFS_single_stat *to_1; + PFS_single_stat *to_2; + + from= from_array; + from_last= from_array + wait_class_max; + to_1= to_array_1; + to_2= to_array_2; + + for ( ; from < from_last ; from++, to_1++, to_2++) + { + if (from->m_count > 0) + { + to_1->aggregate(from); + to_2->aggregate(from); + from->reset(); + } + } +} + +void aggregate_all_stages(PFS_stage_stat *from_array, + PFS_stage_stat *to_array) +{ + PFS_stage_stat *from; + PFS_stage_stat *from_last; + PFS_stage_stat *to; + + from= from_array; + from_last= from_array + stage_class_max; + to= to_array; + + for ( ; from < from_last ; from++, to++) + { + if (from->m_timer1_stat.m_count > 0) + { + to->aggregate(from); + from->reset(); + } + } +} + +void aggregate_all_stages(PFS_stage_stat *from_array, + PFS_stage_stat *to_array_1, + PFS_stage_stat *to_array_2) +{ + PFS_stage_stat *from; + PFS_stage_stat *from_last; + PFS_stage_stat *to_1; + PFS_stage_stat *to_2; + + from= from_array; + from_last= from_array + stage_class_max; + to_1= to_array_1; + to_2= to_array_2; + + for ( ; from < from_last ; from++, to_1++, to_2++) + { + if (from->m_timer1_stat.m_count > 0) + { + to_1->aggregate(from); + to_2->aggregate(from); + from->reset(); + } + } +} + +void aggregate_all_statements(PFS_statement_stat *from_array, + PFS_statement_stat *to_array) +{ + PFS_statement_stat *from; + PFS_statement_stat *from_last; + PFS_statement_stat *to; + + from= from_array; + from_last= from_array + statement_class_max; + to= to_array; + + for ( ; from < from_last ; from++, to++) + { + if (from->m_timer1_stat.m_count > 0) + { + to->aggregate(from); + from->reset(); + } + } +} + +void aggregate_all_statements(PFS_statement_stat *from_array, + PFS_statement_stat *to_array_1, + PFS_statement_stat *to_array_2) +{ + PFS_statement_stat *from; + PFS_statement_stat *from_last; + PFS_statement_stat *to_1; + PFS_statement_stat *to_2; + + from= from_array; + from_last= from_array + statement_class_max; + to_1= to_array_1; + to_2= to_array_2; + + for ( ; from < from_last ; from++, to_1++, to_2++) + { + if (from->m_timer1_stat.m_count > 0) + { + to_1->aggregate(from); + to_2->aggregate(from); + from->reset(); + } + } +} + +void aggregate_thread_stats(PFS_thread *thread) +{ + if (likely(thread->m_account != NULL)) + { + thread->m_account->m_disconnected_count++; + return; + } + + if (thread->m_user != NULL) + thread->m_user->m_disconnected_count++; + + if (thread->m_host != NULL) + thread->m_host->m_disconnected_count++; + + /* There is no global table for connections statistics. */ + return; +} + +void aggregate_thread(PFS_thread *thread) +{ + aggregate_thread_waits(thread); + aggregate_thread_stages(thread); + aggregate_thread_statements(thread); + aggregate_thread_stats(thread); +} + +void aggregate_thread_waits(PFS_thread *thread) +{ + if (likely(thread->m_account != NULL)) + { + DBUG_ASSERT(thread->m_user == NULL); + DBUG_ASSERT(thread->m_host == NULL); + DBUG_ASSERT(thread->m_account->get_refcount() > 0); + + /* + Aggregate EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + */ + aggregate_all_event_names(thread->m_instr_class_waits_stats, + thread->m_account->m_instr_class_waits_stats); + + return; + } + + if ((thread->m_user != NULL) && (thread->m_host != NULL)) + { + DBUG_ASSERT(thread->m_user->get_refcount() > 0); + DBUG_ASSERT(thread->m_host->get_refcount() > 0); + + /* + Aggregate EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_event_names(thread->m_instr_class_waits_stats, + thread->m_user->m_instr_class_waits_stats, + thread->m_host->m_instr_class_waits_stats); + return; + } + + if (thread->m_user != NULL) + { + DBUG_ASSERT(thread->m_user->get_refcount() > 0); + + /* + Aggregate EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME, directly. + */ + aggregate_all_event_names(thread->m_instr_class_waits_stats, + thread->m_user->m_instr_class_waits_stats); + return; + } + + if (thread->m_host != NULL) + { + DBUG_ASSERT(thread->m_host->get_refcount() > 0); + + /* + Aggregate EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME, directly. + */ + aggregate_all_event_names(thread->m_instr_class_waits_stats, + thread->m_host->m_instr_class_waits_stats); + return; + } + + /* Orphan thread, clean the waits stats. */ + thread->reset_waits_stats(); +} + +void aggregate_thread_stages(PFS_thread *thread) +{ + if (likely(thread->m_account != NULL)) + { + DBUG_ASSERT(thread->m_user == NULL); + DBUG_ASSERT(thread->m_host == NULL); + DBUG_ASSERT(thread->m_account->get_refcount() > 0); + + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + */ + aggregate_all_stages(thread->m_instr_class_stages_stats, + thread->m_account->m_instr_class_stages_stats); + + return; + } + + if ((thread->m_user != NULL) && (thread->m_host != NULL)) + { + DBUG_ASSERT(thread->m_user->get_refcount() > 0); + DBUG_ASSERT(thread->m_host->get_refcount() > 0); + + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_stages(thread->m_instr_class_stages_stats, + thread->m_user->m_instr_class_stages_stats, + thread->m_host->m_instr_class_stages_stats); + return; + } + + if (thread->m_user != NULL) + { + DBUG_ASSERT(thread->m_user->get_refcount() > 0); + + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME + in parallel. + */ + aggregate_all_stages(thread->m_instr_class_stages_stats, + thread->m_user->m_instr_class_stages_stats, + global_instr_class_stages_array); + return; + } + + if (thread->m_host != NULL) + { + DBUG_ASSERT(thread->m_host->get_refcount() > 0); + + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME, directly. + */ + aggregate_all_stages(thread->m_instr_class_stages_stats, + thread->m_host->m_instr_class_stages_stats); + return; + } + + /* + Aggregate EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME. + */ + aggregate_all_stages(thread->m_instr_class_stages_stats, + global_instr_class_stages_array); +} + +void aggregate_thread_statements(PFS_thread *thread) +{ + if (likely(thread->m_account != NULL)) + { + DBUG_ASSERT(thread->m_user == NULL); + DBUG_ASSERT(thread->m_host == NULL); + DBUG_ASSERT(thread->m_account->get_refcount() > 0); + + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + */ + aggregate_all_statements(thread->m_instr_class_statements_stats, + thread->m_account->m_instr_class_statements_stats); + + return; + } + + if ((thread->m_user != NULL) && (thread->m_host != NULL)) + { + DBUG_ASSERT(thread->m_user->get_refcount() > 0); + DBUG_ASSERT(thread->m_host->get_refcount() > 0); + + /* + Aggregate EVENTS_STATEMENT_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - EVENTS_STATEMENT_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STATEMENT_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_statements(thread->m_instr_class_statements_stats, + thread->m_user->m_instr_class_statements_stats, + thread->m_host->m_instr_class_statements_stats); + return; + } + + if (thread->m_user != NULL) + { + DBUG_ASSERT(thread->m_user->get_refcount() > 0); + + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME + in parallel. + */ + aggregate_all_statements(thread->m_instr_class_statements_stats, + thread->m_user->m_instr_class_statements_stats, + global_instr_class_statements_array); + return; + } + + if (thread->m_host != NULL) + { + DBUG_ASSERT(thread->m_host->get_refcount() > 0); + + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME, directly. + */ + aggregate_all_statements(thread->m_instr_class_statements_stats, + thread->m_host->m_instr_class_statements_stats); + return; + } + + /* + Aggregate EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME. + */ + aggregate_all_statements(thread->m_instr_class_statements_stats, + global_instr_class_statements_array); +} + +void clear_thread_account(PFS_thread *thread) +{ + if (thread->m_account != NULL) + { + thread->m_account->release(); + thread->m_account= NULL; + } + + if (thread->m_user != NULL) + { + thread->m_user->release(); + thread->m_user= NULL; + } + + if (thread->m_host != NULL) + { + thread->m_host->release(); + thread->m_host= NULL; + } +} + +void set_thread_account(PFS_thread *thread) +{ + DBUG_ASSERT(thread->m_account == NULL); + DBUG_ASSERT(thread->m_user == NULL); + DBUG_ASSERT(thread->m_host == NULL); + + thread->m_account= find_or_create_account(thread, + thread->m_username, + thread->m_username_length, + thread->m_hostname, + thread->m_hostname_length); + + if ((thread->m_account == NULL) && (thread->m_username_length > 0)) + thread->m_user= find_or_create_user(thread, + thread->m_username, + thread->m_username_length); + + if ((thread->m_account == NULL) && (thread->m_hostname_length > 0)) + thread->m_host= find_or_create_host(thread, + thread->m_hostname, + thread->m_hostname_length); +} + +void update_mutex_derived_flags() +{ + PFS_mutex *pfs= mutex_array; + PFS_mutex *pfs_last= mutex_array + mutex_max; + PFS_mutex_class *klass; + + for ( ; pfs < pfs_last; pfs++) + { + klass= sanitize_mutex_class(pfs->m_class); + if (likely(klass != NULL)) + { + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + } + else + { + pfs->m_enabled= false; + pfs->m_timed= false; + } + } +} + +void update_rwlock_derived_flags() +{ + PFS_rwlock *pfs= rwlock_array; + PFS_rwlock *pfs_last= rwlock_array + rwlock_max; + PFS_rwlock_class *klass; + + for ( ; pfs < pfs_last; pfs++) + { + klass= sanitize_rwlock_class(pfs->m_class); + if (likely(klass != NULL)) + { + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + } + else + { + pfs->m_enabled= false; + pfs->m_timed= false; + } + } +} + +void update_cond_derived_flags() +{ + PFS_cond *pfs= cond_array; + PFS_cond *pfs_last= cond_array + cond_max; + PFS_cond_class *klass; + + for ( ; pfs < pfs_last; pfs++) + { + klass= sanitize_cond_class(pfs->m_class); + if (likely(klass != NULL)) + { + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + } + else + { + pfs->m_enabled= false; + pfs->m_timed= false; + } + } +} + +void update_file_derived_flags() +{ + PFS_file *pfs= file_array; + PFS_file *pfs_last= file_array + file_max; + PFS_file_class *klass; + + for ( ; pfs < pfs_last; pfs++) + { + klass= sanitize_file_class(pfs->m_class); + if (likely(klass != NULL)) + { + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + } + else + { + pfs->m_enabled= false; + pfs->m_timed= false; + } + } +} + +void update_table_derived_flags() +{ + PFS_table *pfs= table_array; + PFS_table *pfs_last= table_array + table_max; + PFS_table_share *share; + + for ( ; pfs < pfs_last; pfs++) + { + share= sanitize_table_share(pfs->m_share); + if (likely(share != NULL)) + { + pfs->m_io_enabled= share->m_enabled && + flag_global_instrumentation && global_table_io_class.m_enabled; + pfs->m_io_timed= share->m_timed && global_table_io_class.m_timed; + pfs->m_lock_enabled= share->m_enabled && + flag_global_instrumentation && global_table_lock_class.m_enabled; + pfs->m_lock_timed= share->m_timed && global_table_lock_class.m_timed; + } + else + { + pfs->m_io_enabled= false; + pfs->m_io_timed= false; + pfs->m_lock_enabled= false; + pfs->m_lock_timed= false; + } + } +} + +void update_socket_derived_flags() +{ + PFS_socket *pfs= socket_array; + PFS_socket *pfs_last= socket_array + socket_max; + PFS_socket_class *klass; + + for ( ; pfs < pfs_last; pfs++) + { + klass= sanitize_socket_class(pfs->m_class); + if (likely(klass != NULL)) + { + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + } + else + { + pfs->m_enabled= false; + pfs->m_timed= false; + } + } +} + +void update_instruments_derived_flags() +{ + update_mutex_derived_flags(); + update_rwlock_derived_flags(); + update_cond_derived_flags(); + update_file_derived_flags(); + update_table_derived_flags(); + update_socket_derived_flags(); + /* nothing for stages and statements (no instances) */ +} + /** @} */ diff --git a/storage/perfschema/pfs_instr.h b/storage/perfschema/pfs_instr.h index 2f6b729628e..b579c1d7902 100644 --- a/storage/perfschema/pfs_instr.h +++ b/storage/perfschema/pfs_instr.h @@ -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 @@ -21,11 +21,28 @@ Performance schema instruments (declarations). */ +struct PFS_mutex_class; +struct PFS_rwlock_class; +struct PFS_cond_class; +struct PFS_file_class; +struct PFS_table_share; +struct PFS_thread_class; +struct PFS_socket_class; + +#ifdef __WIN__ +#include <winsock2.h> +#else +#include <arpa/inet.h> +#endif #include "pfs_lock.h" +#include "pfs_stat.h" #include "pfs_instr_class.h" #include "pfs_events_waits.h" +#include "pfs_events_stages.h" +#include "pfs_events_statements.h" #include "pfs_server.h" #include "lf.h" +#include "pfs_con_slice.h" /** @addtogroup Performance_schema_buffers @@ -33,13 +50,21 @@ */ struct PFS_thread; +struct PFS_host; +struct PFS_user; +struct PFS_account; +/** Base structure for wait instruments. */ struct PFS_instr { /** Internal lock. */ pfs_lock m_lock; - /** Instrument wait statistics chain. */ - PFS_single_stat_chain m_wait_stat; + /** Enabled flag. */ + bool m_enabled; + /** Timed flag. */ + bool m_timed; + /** Instrument wait statistics. */ + PFS_single_stat m_wait_stat; }; /** Instrumented mutex implementation. @see PSI_mutex. */ @@ -49,11 +74,13 @@ struct PFS_mutex : public PFS_instr const void *m_identity; /** Mutex class. */ PFS_mutex_class *m_class; + /** Instrument wait statistics. */ + PFS_single_stat m_wait_stat; /** - Mutex lock usage statistics chain. + Mutex lock usage statistics. This statistic is not exposed in user visible tables yet. */ - PFS_single_stat_chain m_lock_stat; + PFS_single_stat m_lock_stat; /** Current owner. */ PFS_thread *m_owner; /** @@ -70,16 +97,18 @@ struct PFS_rwlock : public PFS_instr const void *m_identity; /** RWLock class. */ PFS_rwlock_class *m_class; + /** Instrument wait statistics. */ + PFS_single_stat m_wait_stat; /** - RWLock read lock usage statistics chain. + RWLock read lock usage statistics. This statistic is not exposed in user visible tables yet. */ - PFS_single_stat_chain m_read_lock_stat; + PFS_single_stat m_read_lock_stat; /** - RWLock write lock usage statistics chain. + RWLock write lock usage statistics. This statistic is not exposed in user visible tables yet. */ - PFS_single_stat_chain m_write_lock_stat; + PFS_single_stat m_write_lock_stat; /** Current writer thread. */ PFS_thread *m_writer; /** Current count of readers. */ @@ -103,6 +132,8 @@ struct PFS_cond : public PFS_instr const void *m_identity; /** Condition class. */ PFS_cond_class *m_class; + /** Instrument wait statistics. */ + PFS_single_stat m_wait_stat; /** Condition instance usage statistics. */ PFS_cond_stat m_cond_stat; }; @@ -110,30 +141,173 @@ struct PFS_cond : public PFS_instr /** Instrumented File and FILE implementation. @see PSI_file. */ struct PFS_file : public PFS_instr { + uint32 get_version() + { return m_lock.get_version(); } + + /** File identity */ + const void *m_identity; /** File name. */ char m_filename[FN_REFLEN]; /** File name length in bytes. */ uint m_filename_length; /** File class. */ PFS_file_class *m_class; + /** Instrument wait statistics. */ + PFS_single_stat m_wait_stat; /** File usage statistics. */ PFS_file_stat m_file_stat; }; /** Instrumented table implementation. @see PSI_table. */ -struct PFS_table : public PFS_instr +struct PFS_table { + /** + True if table io instrumentation is enabled. + This flag is computed. + */ + bool m_io_enabled; + /** + True if table lock instrumentation is enabled. + This flag is computed. + */ + bool m_lock_enabled; + /** + True if table io instrumentation is timed. + This flag is computed. + */ + bool m_io_timed; + /** + True if table lock instrumentation is timed. + This flag is computed. + */ + bool m_lock_timed; + + /** True if table io statistics have been collected. */ + bool m_has_io_stats; + + /** True if table lock statistics have been collected. */ + bool m_has_lock_stats; + +public: + /** + Aggregate this table handle statistics to the parents. + Only use this method for handles owned by the calling code. + @sa sanitized_aggregate. + */ + void aggregate(void) + { + if (likely((m_thread_owner != NULL) && (m_has_io_stats || m_has_lock_stats))) + { + safe_aggregate(& m_table_stat, m_share, m_thread_owner); + m_has_io_stats= false; + m_has_lock_stats= false; + } + } + + /** + Aggregate this table handle statistics to the parents. + This method is safe to call on handles not owned by the calling code. + @sa aggregate + @sa sanitized_aggregate_io + @sa sanitized_aggregate_lock + */ + void sanitized_aggregate(void); + + /** + Aggregate this table handle io statistics to the parents. + This method is safe to call on handles not owned by the calling code. + */ + void sanitized_aggregate_io(void); + + /** + Aggregate this table handle lock statistics to the parents. + This method is safe to call on handles not owned by the calling code. + */ + void sanitized_aggregate_lock(void); + + /** Internal lock. */ + pfs_lock m_lock; + /** Owner. */ + PFS_thread *m_thread_owner; /** Table share. */ PFS_table_share *m_share; /** Table identity, typically a handler. */ const void *m_identity; + /** Table statistics. */ + PFS_table_stat m_table_stat; + +private: + static void safe_aggregate(PFS_table_stat *stat, + PFS_table_share *safe_share, + PFS_thread *safe_thread); + static void safe_aggregate_io(PFS_table_stat *stat, + PFS_table_share *safe_share, + PFS_thread *safe_thread); + static void safe_aggregate_lock(PFS_table_stat *stat, + PFS_table_share *safe_share, + PFS_thread *safe_thread); +}; + +/** Instrumented socket implementation. @see PSI_socket. */ +struct PFS_socket : public PFS_instr +{ + uint32 get_version() + { return m_lock.get_version(); } + + /** Socket identity, typically int */ + const void *m_identity; + /** Owning thread, if applicable */ + PFS_thread *m_thread_owner; + /** Socket file descriptor */ + uint m_fd; + /** Raw socket address */ + struct sockaddr_storage m_sock_addr; + /** Length of address */ + socklen_t m_addr_len; + /** Idle flag. */ + bool m_idle; + /** Socket class. */ + PFS_socket_class *m_class; + /** Socket usage statistics. */ + PFS_socket_stat m_socket_stat; }; /** - @def LOCKER_STACK_SIZE + @def WAIT_STACK_LOGICAL_SIZE Maximum number of nested waits. + Some waits, such as: + - "wait/io/table/sql/handler" + - "wait/lock/table/sql/handler" + are implemented by calling code in a storage engine, + that can cause nested waits (file io, mutex, ...) + Because of partitioned tables, a table io event (on the whole table) + can contain a nested table io event (on a partition). + Because of additional debug instrumentation, + waiting on what looks like a "mutex" (safe_mutex, innodb sync0sync, ...) + can cause nested waits to be recorded. + For example, a wait on innodb mutexes can lead to: + - wait/sync/mutex/innobase/some_mutex + - wait/sync/mutex/innobase/sync0sync + - wait/sync/mutex/innobase/os0sync + The max depth of the event stack must be sufficient + for these low level details to be visible. */ -#define LOCKER_STACK_SIZE 3 +#define WAIT_STACK_LOGICAL_SIZE 5 +/** + @def WAIT_STACK_BOTTOM + Maximum number dummy waits records. + One dummy record is reserved for the parent stage / statement, + at the bottom of the wait stack. +*/ +#define WAIT_STACK_BOTTOM 1 +/** + @def WAIT_STACK_SIZE + Physical size of the waits stack +*/ +#define WAIT_STACK_SIZE (WAIT_STACK_BOTTOM + WAIT_STACK_LOGICAL_SIZE) + +/** Max size of the statements stack. */ +extern uint statement_stack_max; /** @def PFS_MAX_ALLOC_RETRY @@ -142,6 +316,7 @@ struct PFS_table : public PFS_instr */ #define PFS_MAX_ALLOC_RETRY 1000 +/** The maximun number of passes in @sa PFS_scan. */ #define PFS_MAX_SCAN_PASS 2 /** @@ -155,59 +330,113 @@ struct PFS_table : public PFS_instr struct PFS_scan { public: + /** + Initialize a new scan. + @param random a random index to start from + @param max_size the max size of the interval to scan + */ void init(uint random, uint max_size); + /** + Predicate, has a next pass. + @return true if there is a next pass to perform. + */ bool has_pass() const { return (m_pass < m_pass_max); } + /** + Iterator, proceed to the next pass. + */ void next_pass() { m_pass++; } + /** First index for this pass. */ uint first() const { return m_first[m_pass]; } + /** Last index for this pass. */ uint last() const { return m_last[m_pass]; } private: + /** Current pass. */ uint m_pass; + /** Maximum number of passes. */ uint m_pass_max; + /** First element for each pass. */ uint m_first[PFS_MAX_SCAN_PASS]; + /** Last element for each pass. */ uint m_last[PFS_MAX_SCAN_PASS]; }; /** Instrumented thread implementation. @see PSI_thread. */ -struct PFS_thread +struct PFS_thread : PFS_connection_slice { + static PFS_thread* get_current_thread(void); + + /** Thread instrumentation flag. */ + bool m_enabled; + /** Current wait event in the event stack. */ + PFS_events_waits *m_events_waits_current; + /** Event ID counter */ + ulonglong m_event_id; /** Internal lock. */ pfs_lock m_lock; /** Pins for filename_hash. */ LF_PINS *m_filename_hash_pins; /** Pins for table_share_hash. */ LF_PINS *m_table_share_hash_pins; - /** Event ID counter */ - ulonglong m_event_id; - /** Thread instrumentation flag. */ - bool m_enabled; + /** Pins for setup_actor_hash. */ + LF_PINS *m_setup_actor_hash_pins; + /** Pins for setup_object_hash. */ + LF_PINS *m_setup_object_hash_pins; + /** Pins for host_hash. */ + LF_PINS *m_host_hash_pins; + /** Pins for user_hash. */ + LF_PINS *m_user_hash_pins; + /** Pins for account_hash. */ + LF_PINS *m_account_hash_pins; + /** Pins for digest_hash. */ + LF_PINS *m_digest_hash_pins; /** Internal thread identifier, unique. */ ulong m_thread_internal_id; + /** Parent internal thread identifier. */ + ulong m_parent_thread_internal_id; /** External (SHOW PROCESSLIST) thread identifier, not unique. */ ulong m_thread_id; /** Thread class. */ PFS_thread_class *m_class; - /** Size of @c m_wait_locker_stack. */ - uint m_wait_locker_count; /** - Stack of wait lockers. - This member holds the data for the table - PERFORMANCE_SCHEMA.EVENTS_WAITS_CURRENT. - For most locks, only 1 wait locker is used at a given time. - For composite locks, several records are needed: - - 1 for a 'logical' wait (for example on the GLOBAL READ LOCK state) - - 1 for a 'physical' wait (for example on COND_refresh) + Stack of events waits. + This member holds the data for the table PERFORMANCE_SCHEMA.EVENTS_WAITS_CURRENT. + Note that stack[0] is a dummy record that represents the parent stage/statement. + For example, assuming the following tree: + - STAGE ID 100 + - WAIT ID 101, parent STAGE 100 + - WAIT ID 102, parent wait 101 + the data in the stack will be: + stack[0].m_event_id= 100, set by the stage instrumentation + stack[0].m_event_type= STAGE, set by the stage instrumentation + stack[0].m_nesting_event_id= unused + stack[0].m_nesting_event_type= unused + stack[1].m_event_id= 101 + stack[1].m_event_type= WAIT + stack[1].m_nesting_event_id= stack[0].m_event_id= 100 + stack[1].m_nesting_event_type= stack[0].m_event_type= STAGE + stack[2].m_event_id= 102 + stack[2].m_event_type= WAIT + stack[2].m_nesting_event_id= stack[1].m_event_id= 101 + stack[2].m_nesting_event_type= stack[1].m_event_type= WAIT + + The whole point of the stack[0] record is to allow this optimization + in the code, in the instrumentation for wait events: + wait->m_nesting_event_id= (wait-1)->m_event_id; + wait->m_nesting_event_type= (wait-1)->m_event_type; + This code works for both the top level wait, and nested waits, + and works without if conditions, which helps performances. */ - PFS_wait_locker m_wait_locker_stack[LOCKER_STACK_SIZE]; + PFS_events_waits m_events_waits_stack[WAIT_STACK_SIZE]; /** True if the circular buffer @c m_waits_history is full. */ bool m_waits_history_full; /** Current index in the circular buffer @c m_waits_history. */ @@ -218,32 +447,75 @@ struct PFS_thread PERFORMANCE_SCHEMA.EVENTS_WAITS_HISTORY. */ PFS_events_waits *m_waits_history; + + /** True if the circular buffer @c m_stages_history is full. */ + bool m_stages_history_full; + /** Current index in the circular buffer @c m_stages_history. */ + uint m_stages_history_index; /** - Per thread waits aggregated statistics. + Stages history circular buffer. This member holds the data for the table - PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME. + PERFORMANCE_SCHEMA.EVENTS_STAGES_HISTORY. */ - PFS_single_stat_chain *m_instr_class_wait_stats; -}; + PFS_events_stages *m_stages_history; -PFS_thread *sanitize_thread(PFS_thread *unsafe); -const char *sanitize_file_name(const char *unsafe); - -PFS_single_stat_chain* -find_per_thread_mutex_class_wait_stat(PFS_thread *thread, - PFS_mutex_class *klass); - -PFS_single_stat_chain* -find_per_thread_rwlock_class_wait_stat(PFS_thread *thread, - PFS_rwlock_class *klass); + /** True if the circular buffer @c m_statements_history is full. */ + bool m_statements_history_full; + /** Current index in the circular buffer @c m_statements_history. */ + uint m_statements_history_index; + /** + Statements history circular buffer. + This member holds the data for the table + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_HISTORY. + */ + PFS_events_statements *m_statements_history; + + /** User name. */ + char m_username[USERNAME_LENGTH]; + /** Length of @c m_username. */ + uint m_username_length; + /** Host name. */ + char m_hostname[HOSTNAME_LENGTH]; + /** Length of @c m_hostname. */ + uint m_hostname_length; + /** Database name. */ + char m_dbname[NAME_LEN]; + /** Length of @c m_dbname. */ + uint m_dbname_length; + /** Current command. */ + int m_command; + /** Start time. */ + time_t m_start_time; + /** Processlist state. */ + const char *m_processlist_state_ptr; + /** Length of @c m_processlist_state_ptr. */ + uint m_processlist_state_length; + /** Processlist info. */ + const char *m_processlist_info_ptr; + /** Length of @c m_processlist_info_length. */ + uint m_processlist_info_length; + + PFS_events_stages m_stage_current; + + /** Size of @c m_events_statements_stack. */ + uint m_events_statements_count; + PFS_events_statements *m_statement_stack; + + PFS_host *m_host; + PFS_user *m_user; + PFS_account *m_account; +}; -PFS_single_stat_chain* -find_per_thread_cond_class_wait_stat(PFS_thread *thread, - PFS_cond_class *klass); +extern PFS_single_stat *global_instr_class_waits_array; +extern PFS_stage_stat *global_instr_class_stages_array; +extern PFS_statement_stat *global_instr_class_statements_array; -PFS_single_stat_chain* -find_per_thread_file_class_wait_stat(PFS_thread *thread, - PFS_file_class *klass); +PFS_mutex *sanitize_mutex(PFS_mutex *unsafe); +PFS_rwlock *sanitize_rwlock(PFS_rwlock *unsafe); +PFS_cond *sanitize_cond(PFS_cond *unsafe); +PFS_thread *sanitize_thread(PFS_thread *unsafe); +PFS_file *sanitize_file(PFS_file *unsafe); +PFS_socket *sanitize_socket(PFS_socket *unsafe); int init_instruments(const PFS_global_param *param); void cleanup_instruments(); @@ -266,9 +538,13 @@ PFS_file* find_or_create_file(PFS_thread *thread, PFS_file_class *klass, void release_file(PFS_file *pfs); void destroy_file(PFS_thread *thread, PFS_file *pfs); -PFS_table* create_table(PFS_table_share *share, const void *identity); +PFS_table* create_table(PFS_table_share *share, PFS_thread *opening_thread, + const void *identity); void destroy_table(PFS_table *pfs); +PFS_socket* create_socket(PFS_socket_class *socket_class, const void *identity); +void destroy_socket(PFS_socket *pfs); + /* For iterators and show status. */ extern ulong mutex_max; @@ -285,9 +561,13 @@ extern long file_handle_max; extern ulong file_handle_lost; extern ulong table_max; extern ulong table_lost; +extern ulong socket_max; +extern ulong socket_lost; extern ulong events_waits_history_per_thread; -extern ulong instr_class_per_thread; +extern ulong events_stages_history_per_thread; +extern ulong events_statements_history_per_thread; extern ulong locker_lost; +extern ulong statement_lost; /* Exposing the data directly, for iterators. */ @@ -298,10 +578,51 @@ extern PFS_thread *thread_array; extern PFS_file *file_array; extern PFS_file **file_handle_array; extern PFS_table *table_array; +extern PFS_socket *socket_array; void reset_events_waits_by_instance(); -void reset_per_thread_wait_stat(); void reset_file_instance_io(); +void reset_socket_instance_io(); + +void aggregate_all_event_names(PFS_single_stat *from_array, + PFS_single_stat *to_array); +void aggregate_all_event_names(PFS_single_stat *from_array, + PFS_single_stat *to_array_1, + PFS_single_stat *to_array_2); + +void aggregate_all_stages(PFS_stage_stat *from_array, + PFS_stage_stat *to_array); +void aggregate_all_stages(PFS_stage_stat *from_array, + PFS_stage_stat *to_array_1, + PFS_stage_stat *to_array_2); + +void aggregate_all_statements(PFS_statement_stat *from_array, + PFS_statement_stat *to_array); +void aggregate_all_statements(PFS_statement_stat *from_array, + PFS_statement_stat *to_array_1, + PFS_statement_stat *to_array_2); + +void aggregate_thread(PFS_thread *thread); +void aggregate_thread_waits(PFS_thread *thread); +void aggregate_thread_stages(PFS_thread *thread); +void aggregate_thread_statements(PFS_thread *thread); +void clear_thread_account(PFS_thread *thread); +void set_thread_account(PFS_thread *thread); + +/** Update derived flags for all mutex instances. */ +void update_mutex_derived_flags(); +/** Update derived flags for all rwlock instances. */ +void update_rwlock_derived_flags(); +/** Update derived flags for all condition instances. */ +void update_cond_derived_flags(); +/** Update derived flags for all file handles. */ +void update_file_derived_flags(); +/** Update derived flags for all table handles. */ +void update_table_derived_flags(); +/** Update derived flags for all socket instances. */ +void update_socket_derived_flags(); +/** Update derived flags for all instruments. */ +void update_instruments_derived_flags(); /** @} */ #endif 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); + } } /** @} */ diff --git a/storage/perfschema/pfs_instr_class.h b/storage/perfschema/pfs_instr_class.h index b84691ccde5..bef25e76467 100644 --- a/storage/perfschema/pfs_instr_class.h +++ b/storage/perfschema/pfs_instr_class.h @@ -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 @@ -39,9 +39,13 @@ #define PFS_MAX_FULL_PREFIX_NAME_LENGTH 32 #include <my_global.h> +#include <my_sys.h> #include <mysql/psi/psi.h> #include "pfs_lock.h" #include "pfs_stat.h" +#include "pfs_column_types.h" + +struct PFS_global_param; /** @addtogroup Performance_schema_buffers @@ -49,6 +53,7 @@ */ extern my_bool pfs_enabled; +extern enum_timer_name *class_timers[]; /** Key, naming a synch instrument (mutex, rwlock, cond). */ typedef unsigned int PFS_sync_key; @@ -56,55 +61,143 @@ typedef unsigned int PFS_sync_key; typedef unsigned int PFS_thread_key; /** Key, naming a file instrument. */ typedef unsigned int PFS_file_key; +/** Key, naming a stage instrument. */ +typedef unsigned int PFS_stage_key; +/** Key, naming a statement instrument. */ +typedef unsigned int PFS_statement_key; +/** Key, naming a socket instrument. */ +typedef unsigned int PFS_socket_key; + +enum PFS_class_type +{ + PFS_CLASS_NONE= 0, + PFS_CLASS_MUTEX= 1, + PFS_CLASS_RWLOCK= 2, + PFS_CLASS_COND= 3, + PFS_CLASS_FILE= 4, + PFS_CLASS_TABLE= 5, + PFS_CLASS_STAGE= 6, + PFS_CLASS_STATEMENT= 7, + PFS_CLASS_SOCKET= 8, + PFS_CLASS_TABLE_IO= 9, + PFS_CLASS_TABLE_LOCK= 10, + PFS_CLASS_IDLE= 11, + PFS_CLASS_LAST= PFS_CLASS_IDLE, + PFS_CLASS_MAX= PFS_CLASS_LAST + 1 +}; + +/** User-defined instrument configuration. */ +struct PFS_instr_config +{ + /* Instrument name. */ + char *m_name; + /* Name length. */ + uint m_name_length; + /** Enabled flag. */ + bool m_enabled; + /** Timed flag. */ + bool m_timed; +}; + +extern DYNAMIC_ARRAY pfs_instr_config_array; +extern int pfs_instr_config_state; + +static const int PFS_INSTR_CONFIG_NOT_INITIALIZED= 0; +static const int PFS_INSTR_CONFIG_ALLOCATED= 1; +static const int PFS_INSTR_CONFIG_DEALLOCATED= 2; struct PFS_thread; +extern uint mutex_class_start; +extern uint rwlock_class_start; +extern uint cond_class_start; +extern uint file_class_start; +extern uint table_class_start; +extern uint socket_class_start; +extern uint wait_class_max; + /** Information for all instrumentation. */ struct PFS_instr_class { - /** Instrument name. */ - char m_name[PFS_MAX_INFO_NAME_LENGTH]; - /** Length in bytes of @c m_name. */ - uint m_name_length; - /** Instrument flags. */ - int m_flags; + /** Class type */ + PFS_class_type m_type; /** True if this instrument is enabled. */ bool m_enabled; /** True if this instrument is timed. */ bool m_timed; - /** Wait statistics chain. */ - PFS_single_stat_chain m_wait_stat; + /** Instrument flags. */ + int m_flags; + /** + Instrument name index. + Self index in: + - EVENTS_WAITS_SUMMARY_*_BY_EVENT_NAME for waits + - EVENTS_STAGES_SUMMARY_*_BY_EVENT_NAME for stages + - EVENTS_STATEMENTS_SUMMARY_*_BY_EVENT_NAME for statements + */ + uint m_event_name_index; + /** Instrument name. */ + char m_name[PFS_MAX_INFO_NAME_LENGTH]; + /** Length in bytes of @c m_name. */ + uint m_name_length; + /** Timer associated with this class. */ + enum_timer_name *m_timer; + + bool is_singleton() const + { + return m_flags & PSI_FLAG_GLOBAL; + } + static void set_enabled(PFS_instr_class *pfs, bool enabled); + static void set_timed(PFS_instr_class *pfs, bool timed); + + bool is_deferred() const + { + switch(m_type) + { + case PFS_CLASS_SOCKET: + return true; + break; + default: + return false; + break; + }; + } }; +struct PFS_mutex; + /** Instrumentation metadata for a MUTEX. */ struct PFS_mutex_class : public PFS_instr_class { /** - Lock statistics chain. + Lock statistics. This statistic is not exposed in user visible tables yet. */ - PFS_single_stat_chain m_lock_stat; - /** Self index in @c mutex_class_array. */ - uint m_index; + PFS_single_stat m_lock_stat; + /** Singleton instance. */ + PFS_mutex *m_singleton; }; +struct PFS_rwlock; + /** Instrumentation metadata for a RWLOCK. */ struct PFS_rwlock_class : public PFS_instr_class { /** - Read lock statistics chain. + Read lock statistics. This statistic is not exposed in user visible tables yet. */ - PFS_single_stat_chain m_read_lock_stat; + PFS_single_stat m_read_lock_stat; /** - Write lock statistics chain. + Write lock statistics. This statistic is not exposed in user visible tables yet. */ - PFS_single_stat_chain m_write_lock_stat; - /** Self index in @c rwlock_class_array. */ - uint m_index; + PFS_single_stat m_write_lock_stat; + /** Singleton instance. */ + PFS_rwlock *m_singleton; }; +struct PFS_cond; + /** Instrumentation metadata for a COND. */ struct PFS_cond_class : public PFS_instr_class { @@ -113,19 +206,21 @@ struct PFS_cond_class : public PFS_instr_class This statistic is not exposed in user visible tables yet. */ PFS_cond_stat m_cond_stat; - /** Self index in @c cond_class_array. */ - uint m_index; + /** Singleton instance. */ + PFS_cond *m_singleton; }; /** Instrumentation metadata of a thread. */ struct PFS_thread_class { + /** True if this thread instrument is enabled. */ + bool m_enabled; + /** Singleton instance. */ + PFS_thread *m_singleton; /** Thread instrument name. */ char m_name[PFS_MAX_INFO_NAME_LENGTH]; /** Length in bytes of @c m_name. */ uint m_name_length; - /** True if this thread instrument is enabled. */ - bool m_enabled; }; #define PFS_TABLESHARE_HASHKEY_SIZE (NAME_LEN + 1 + NAME_LEN + 1) @@ -136,7 +231,7 @@ struct PFS_table_share_key /** Hash search key. This has to be a string for LF_HASH, - the format is "<schema_name><0x00><object_name><0x00>" + the format is "<enum_object_type><schema_name><0x00><object_name><0x00>" @see create_table_def_key */ char m_hash_key[PFS_TABLESHARE_HASHKEY_SIZE]; @@ -144,11 +239,70 @@ struct PFS_table_share_key uint m_key_length; }; +/** Table index or 'key' */ +struct PFS_table_key +{ + /** Index name */ + char m_name[NAME_LEN]; + /** Length in bytes of @c m_name. */ + uint m_name_length; +}; + /** Instrumentation metadata for a table share. */ struct PFS_table_share { +public: + uint32 get_version() + { return m_lock.get_version(); } + + enum_object_type get_object_type() + { + return (enum_object_type) m_key.m_hash_key[0]; + } + + void aggregate_io(void); + void aggregate_lock(void); + + inline void aggregate(void) + { + aggregate_io(); + aggregate_lock(); + } + + inline void init_refcount(void) + { + PFS_atomic::store_32(& m_refcount, 1); + } + + inline int get_refcount(void) + { + return PFS_atomic::load_32(& m_refcount); + } + + inline void inc_refcount(void) + { + PFS_atomic::add_32(& m_refcount, 1); + } + + inline void dec_refcount(void) + { + PFS_atomic::add_32(& m_refcount, -1); + } + + void refresh_setup_object_flags(PFS_thread *thread); + /** Internal lock. */ pfs_lock m_lock; + /** + True if table instrumentation is enabled. + This flag is computed from the content of table setup_objects. + */ + bool m_enabled; + /** + True if table instrumentation is timed. + This flag is computed from the content of table setup_objects. + */ + bool m_timed; /** Search key. */ PFS_table_share_key m_key; /** Schema name. */ @@ -159,32 +313,73 @@ struct PFS_table_share const char *m_table_name; /** Length in bytes of @c m_table_name. */ uint m_table_name_length; - /** Wait statistics chain. */ - PFS_single_stat_chain m_wait_stat; - /** True if this table instrument is enabled. */ - bool m_enabled; - /** True if this table instrument is timed. */ - bool m_timed; - /** True if this table instrument is aggregated. */ - bool m_aggregated; + /** Number of indexes. */ + uint m_key_count; + /** Table statistics. */ + PFS_table_stat m_table_stat; + /** Index names. */ + PFS_table_key m_keys[MAX_KEY]; + +private: + /** Number of opened table handles. */ + int m_refcount; }; /** - Instrument controlling all tables. - This instrument is used as a default when there is no - entry present in SETUP_OBJECTS. + Instrument controlling all table io. + This instrument is used with table SETUP_OBJECTS. */ -extern PFS_instr_class global_table_class; +extern PFS_instr_class global_table_io_class; + +/** + Instrument controlling all table lock. + This instrument is used with table SETUP_OBJECTS. +*/ +extern PFS_instr_class global_table_lock_class; + +/** + Instrument controlling all idle waits. +*/ +extern PFS_instr_class global_idle_class; + +struct PFS_file; /** Instrumentation metadata for a file. */ struct PFS_file_class : public PFS_instr_class { /** File usage statistics. */ PFS_file_stat m_file_stat; - /** Self index in @c file_class_array. */ - uint m_index; + /** Singleton instance. */ + PFS_file *m_singleton; }; +/** Instrumentation metadata for a stage. */ +struct PFS_stage_class : public PFS_instr_class +{ + /** Stage usage statistics. */ + PFS_stage_stat m_stage_stat; +}; + +/** Instrumentation metadata for a statement. */ +struct PFS_statement_class : public PFS_instr_class +{ +}; + +struct PFS_socket; + +/** Instrumentation metadata for a socket. */ +struct PFS_socket_class : public PFS_instr_class +{ + /** Socket usage statistics. */ + PFS_socket_stat m_socket_stat; + /** Singleton instance. */ + PFS_socket *m_singleton; +}; + +void init_event_name_sizing(const PFS_global_param *param); + +void register_global_classes(); + int init_sync_class(uint mutex_class_sizing, uint rwlock_class_sizing, uint cond_class_sizing); @@ -198,6 +393,12 @@ int init_table_share_hash(); void cleanup_table_share_hash(); int init_file_class(uint file_class_sizing); void cleanup_file_class(); +int init_stage_class(uint stage_class_sizing); +void cleanup_stage_class(); +int init_statement_class(uint statement_class_sizing); +void cleanup_statement_class(); +int init_socket_class(uint socket_class_sizing); +void cleanup_socket_class(); PFS_sync_key register_mutex_class(const char *name, uint name_length, int flags); @@ -214,6 +415,15 @@ PFS_thread_key register_thread_class(const char *name, uint name_length, PFS_file_key register_file_class(const char *name, uint name_length, int flags); +PFS_stage_key register_stage_class(const char *name, uint name_length, + int flags); + +PFS_statement_key register_statement_class(const char *name, uint name_length, + int flags); + +PFS_socket_key register_socket_class(const char *name, uint name_length, + int flags); + PFS_mutex_class *find_mutex_class(PSI_mutex_key key); PFS_mutex_class *sanitize_mutex_class(PFS_mutex_class *unsafe); PFS_rwlock_class *find_rwlock_class(PSI_rwlock_key key); @@ -224,14 +434,25 @@ PFS_thread_class *find_thread_class(PSI_thread_key key); PFS_thread_class *sanitize_thread_class(PFS_thread_class *unsafe); PFS_file_class *find_file_class(PSI_file_key key); PFS_file_class *sanitize_file_class(PFS_file_class *unsafe); -const char *sanitize_table_schema_name(const char *unsafe); -const char *sanitize_table_object_name(const char *unsafe); +PFS_stage_class *find_stage_class(PSI_stage_key key); +PFS_stage_class *sanitize_stage_class(PFS_stage_class *unsafe); +PFS_statement_class *find_statement_class(PSI_statement_key key); +PFS_statement_class *sanitize_statement_class(PFS_statement_class *unsafe); +PFS_instr_class *find_table_class(uint index); +PFS_instr_class *sanitize_table_class(PFS_instr_class *unsafe); +PFS_socket_class *find_socket_class(PSI_socket_key key); +PFS_socket_class *sanitize_socket_class(PFS_socket_class *unsafe); +PFS_instr_class *find_idle_class(uint index); +PFS_instr_class *sanitize_idle_class(PFS_instr_class *unsafe); 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); +void release_table_share(PFS_table_share *pfs); +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_table_share *sanitize_table_share(PFS_table_share *unsafe); @@ -245,12 +466,28 @@ extern ulong thread_class_max; extern ulong thread_class_lost; extern ulong file_class_max; extern ulong file_class_lost; +extern ulong stage_class_max; +extern ulong stage_class_lost; +extern ulong statement_class_max; +extern ulong statement_class_lost; +extern ulong socket_class_max; +extern ulong socket_class_lost; extern ulong table_share_max; extern ulong table_share_lost; + +/* Exposing the data directly, for iterators. */ + +extern PFS_mutex_class *mutex_class_array; +extern PFS_rwlock_class *rwlock_class_array; +extern PFS_cond_class *cond_class_array; +extern PFS_file_class *file_class_array; extern PFS_table_share *table_share_array; -void reset_instrument_class_waits(); void reset_file_class_io(); +void reset_socket_class_io(); + +/** Update derived flags for all table shares. */ +void update_table_share_derived_flags(PFS_thread *thread); /** @} */ #endif diff --git a/storage/perfschema/pfs_lex_token.h b/storage/perfschema/pfs_lex_token.h new file mode 100644 index 00000000000..6074570f56f --- /dev/null +++ b/storage/perfschema/pfs_lex_token.h @@ -0,0 +1,906 @@ +/* +Copyright (c) 2011, 2012, Oracle, Monty Program Ab and others. + +*/ +/* + This file is generated, do not edit. + See file storage/perfschema/gen_pfs_lex_token.cc. +*/ +struct lex_token_string +{ + const char *m_token_string; + int m_token_length; +}; +typedef struct lex_token_string lex_token_string; +lex_token_string lex_token_array[]= +{ +/* PART 1: character tokens. */ +/* 000 */ { "\x00", 1}, +/* 001 */ { "\x01", 1}, +/* 002 */ { "\x02", 1}, +/* 003 */ { "\x03", 1}, +/* 004 */ { "\x04", 1}, +/* 005 */ { "\x05", 1}, +/* 006 */ { "\x06", 1}, +/* 007 */ { "\x07", 1}, +/* 008 */ { "\x08", 1}, +/* 009 */ { "\x09", 1}, +/* 010 */ { "\x0a", 1}, +/* 011 */ { "\x0b", 1}, +/* 012 */ { "\x0c", 1}, +/* 013 */ { "\x0d", 1}, +/* 014 */ { "\x0e", 1}, +/* 015 */ { "\x0f", 1}, +/* 016 */ { "\x10", 1}, +/* 017 */ { "\x11", 1}, +/* 018 */ { "\x12", 1}, +/* 019 */ { "\x13", 1}, +/* 020 */ { "\x14", 1}, +/* 021 */ { "\x15", 1}, +/* 022 */ { "\x16", 1}, +/* 023 */ { "\x17", 1}, +/* 024 */ { "\x18", 1}, +/* 025 */ { "\x19", 1}, +/* 026 */ { "\x1a", 1}, +/* 027 */ { "\x1b", 1}, +/* 028 */ { "\x1c", 1}, +/* 029 */ { "\x1d", 1}, +/* 030 */ { "\x1e", 1}, +/* 031 */ { "\x1f", 1}, +/* 032 */ { "\x20", 1}, +/* 033 */ { "\x21", 1}, +/* 034 */ { "\x22", 1}, +/* 035 */ { "\x23", 1}, +/* 036 */ { "\x24", 1}, +/* 037 */ { "\x25", 1}, +/* 038 */ { "\x26", 1}, +/* 039 */ { "\x27", 1}, +/* 040 */ { "\x28", 1}, +/* 041 */ { "\x29", 1}, +/* 042 */ { "\x2a", 1}, +/* 043 */ { "\x2b", 1}, +/* 044 */ { "\x2c", 1}, +/* 045 */ { "\x2d", 1}, +/* 046 */ { "\x2e", 1}, +/* 047 */ { "\x2f", 1}, +/* 048 */ { "\x30", 1}, +/* 049 */ { "\x31", 1}, +/* 050 */ { "\x32", 1}, +/* 051 */ { "\x33", 1}, +/* 052 */ { "\x34", 1}, +/* 053 */ { "\x35", 1}, +/* 054 */ { "\x36", 1}, +/* 055 */ { "\x37", 1}, +/* 056 */ { "\x38", 1}, +/* 057 */ { "\x39", 1}, +/* 058 */ { "\x3a", 1}, +/* 059 */ { "\x3b", 1}, +/* 060 */ { "\x3c", 1}, +/* 061 */ { "\x3d", 1}, +/* 062 */ { "\x3e", 1}, +/* 063 */ { "\x3f", 1}, +/* 064 */ { "\x40", 1}, +/* 065 */ { "\x41", 1}, +/* 066 */ { "\x42", 1}, +/* 067 */ { "\x43", 1}, +/* 068 */ { "\x44", 1}, +/* 069 */ { "\x45", 1}, +/* 070 */ { "\x46", 1}, +/* 071 */ { "\x47", 1}, +/* 072 */ { "\x48", 1}, +/* 073 */ { "\x49", 1}, +/* 074 */ { "\x4a", 1}, +/* 075 */ { "\x4b", 1}, +/* 076 */ { "\x4c", 1}, +/* 077 */ { "\x4d", 1}, +/* 078 */ { "\x4e", 1}, +/* 079 */ { "\x4f", 1}, +/* 080 */ { "\x50", 1}, +/* 081 */ { "\x51", 1}, +/* 082 */ { "\x52", 1}, +/* 083 */ { "\x53", 1}, +/* 084 */ { "\x54", 1}, +/* 085 */ { "\x55", 1}, +/* 086 */ { "\x56", 1}, +/* 087 */ { "\x57", 1}, +/* 088 */ { "\x58", 1}, +/* 089 */ { "\x59", 1}, +/* 090 */ { "\x5a", 1}, +/* 091 */ { "\x5b", 1}, +/* 092 */ { "\x5c", 1}, +/* 093 */ { "\x5d", 1}, +/* 094 */ { "\x5e", 1}, +/* 095 */ { "\x5f", 1}, +/* 096 */ { "\x60", 1}, +/* 097 */ { "\x61", 1}, +/* 098 */ { "\x62", 1}, +/* 099 */ { "\x63", 1}, +/* 100 */ { "\x64", 1}, +/* 101 */ { "\x65", 1}, +/* 102 */ { "\x66", 1}, +/* 103 */ { "\x67", 1}, +/* 104 */ { "\x68", 1}, +/* 105 */ { "\x69", 1}, +/* 106 */ { "\x6a", 1}, +/* 107 */ { "\x6b", 1}, +/* 108 */ { "\x6c", 1}, +/* 109 */ { "\x6d", 1}, +/* 110 */ { "\x6e", 1}, +/* 111 */ { "\x6f", 1}, +/* 112 */ { "\x70", 1}, +/* 113 */ { "\x71", 1}, +/* 114 */ { "\x72", 1}, +/* 115 */ { "\x73", 1}, +/* 116 */ { "\x74", 1}, +/* 117 */ { "\x75", 1}, +/* 118 */ { "\x76", 1}, +/* 119 */ { "\x77", 1}, +/* 120 */ { "\x78", 1}, +/* 121 */ { "\x79", 1}, +/* 122 */ { "\x7a", 1}, +/* 123 */ { "\x7b", 1}, +/* 124 */ { "\x7c", 1}, +/* 125 */ { "\x7d", 1}, +/* 126 */ { "\x7e", 1}, +/* 127 */ { "\x7f", 1}, +/* 128 */ { "\x80", 1}, +/* 129 */ { "\x81", 1}, +/* 130 */ { "\x82", 1}, +/* 131 */ { "\x83", 1}, +/* 132 */ { "\x84", 1}, +/* 133 */ { "\x85", 1}, +/* 134 */ { "\x86", 1}, +/* 135 */ { "\x87", 1}, +/* 136 */ { "\x88", 1}, +/* 137 */ { "\x89", 1}, +/* 138 */ { "\x8a", 1}, +/* 139 */ { "\x8b", 1}, +/* 140 */ { "\x8c", 1}, +/* 141 */ { "\x8d", 1}, +/* 142 */ { "\x8e", 1}, +/* 143 */ { "\x8f", 1}, +/* 144 */ { "\x90", 1}, +/* 145 */ { "\x91", 1}, +/* 146 */ { "\x92", 1}, +/* 147 */ { "\x93", 1}, +/* 148 */ { "\x94", 1}, +/* 149 */ { "\x95", 1}, +/* 150 */ { "\x96", 1}, +/* 151 */ { "\x97", 1}, +/* 152 */ { "\x98", 1}, +/* 153 */ { "\x99", 1}, +/* 154 */ { "\x9a", 1}, +/* 155 */ { "\x9b", 1}, +/* 156 */ { "\x9c", 1}, +/* 157 */ { "\x9d", 1}, +/* 158 */ { "\x9e", 1}, +/* 159 */ { "\x9f", 1}, +/* 160 */ { "\xa0", 1}, +/* 161 */ { "\xa1", 1}, +/* 162 */ { "\xa2", 1}, +/* 163 */ { "\xa3", 1}, +/* 164 */ { "\xa4", 1}, +/* 165 */ { "\xa5", 1}, +/* 166 */ { "\xa6", 1}, +/* 167 */ { "\xa7", 1}, +/* 168 */ { "\xa8", 1}, +/* 169 */ { "\xa9", 1}, +/* 170 */ { "\xaa", 1}, +/* 171 */ { "\xab", 1}, +/* 172 */ { "\xac", 1}, +/* 173 */ { "\xad", 1}, +/* 174 */ { "\xae", 1}, +/* 175 */ { "\xaf", 1}, +/* 176 */ { "\xb0", 1}, +/* 177 */ { "\xb1", 1}, +/* 178 */ { "\xb2", 1}, +/* 179 */ { "\xb3", 1}, +/* 180 */ { "\xb4", 1}, +/* 181 */ { "\xb5", 1}, +/* 182 */ { "\xb6", 1}, +/* 183 */ { "\xb7", 1}, +/* 184 */ { "\xb8", 1}, +/* 185 */ { "\xb9", 1}, +/* 186 */ { "\xba", 1}, +/* 187 */ { "\xbb", 1}, +/* 188 */ { "\xbc", 1}, +/* 189 */ { "\xbd", 1}, +/* 190 */ { "\xbe", 1}, +/* 191 */ { "\xbf", 1}, +/* 192 */ { "\xc0", 1}, +/* 193 */ { "\xc1", 1}, +/* 194 */ { "\xc2", 1}, +/* 195 */ { "\xc3", 1}, +/* 196 */ { "\xc4", 1}, +/* 197 */ { "\xc5", 1}, +/* 198 */ { "\xc6", 1}, +/* 199 */ { "\xc7", 1}, +/* 200 */ { "\xc8", 1}, +/* 201 */ { "\xc9", 1}, +/* 202 */ { "\xca", 1}, +/* 203 */ { "\xcb", 1}, +/* 204 */ { "\xcc", 1}, +/* 205 */ { "\xcd", 1}, +/* 206 */ { "\xce", 1}, +/* 207 */ { "\xcf", 1}, +/* 208 */ { "\xd0", 1}, +/* 209 */ { "\xd1", 1}, +/* 210 */ { "\xd2", 1}, +/* 211 */ { "\xd3", 1}, +/* 212 */ { "\xd4", 1}, +/* 213 */ { "\xd5", 1}, +/* 214 */ { "\xd6", 1}, +/* 215 */ { "\xd7", 1}, +/* 216 */ { "\xd8", 1}, +/* 217 */ { "\xd9", 1}, +/* 218 */ { "\xda", 1}, +/* 219 */ { "\xdb", 1}, +/* 220 */ { "\xdc", 1}, +/* 221 */ { "\xdd", 1}, +/* 222 */ { "\xde", 1}, +/* 223 */ { "\xdf", 1}, +/* 224 */ { "\xe0", 1}, +/* 225 */ { "\xe1", 1}, +/* 226 */ { "\xe2", 1}, +/* 227 */ { "\xe3", 1}, +/* 228 */ { "\xe4", 1}, +/* 229 */ { "\xe5", 1}, +/* 230 */ { "\xe6", 1}, +/* 231 */ { "\xe7", 1}, +/* 232 */ { "\xe8", 1}, +/* 233 */ { "\xe9", 1}, +/* 234 */ { "\xea", 1}, +/* 235 */ { "\xeb", 1}, +/* 236 */ { "\xec", 1}, +/* 237 */ { "\xed", 1}, +/* 238 */ { "\xee", 1}, +/* 239 */ { "\xef", 1}, +/* 240 */ { "\xf0", 1}, +/* 241 */ { "\xf1", 1}, +/* 242 */ { "\xf2", 1}, +/* 243 */ { "\xf3", 1}, +/* 244 */ { "\xf4", 1}, +/* 245 */ { "\xf5", 1}, +/* 246 */ { "\xf6", 1}, +/* 247 */ { "\xf7", 1}, +/* 248 */ { "\xf8", 1}, +/* 249 */ { "\xf9", 1}, +/* 250 */ { "\xfa", 1}, +/* 251 */ { "\xfb", 1}, +/* 252 */ { "\xfc", 1}, +/* 253 */ { "\xfd", 1}, +/* 254 */ { "\xfe", 1}, +/* 255 */ { "\xff", 1}, +/* PART 2: named tokens. */ +/* 256 */ { "(unknown)", 9}, +/* 257 */ { "(unknown)", 9}, +/* 258 */ { "(unknown)", 9}, +/* 259 */ { "ACCESSIBLE", 10}, +/* 260 */ { "ACTION", 6}, +/* 261 */ { "ADD", 3}, +/* 262 */ { "ADDDATE", 7}, +/* 263 */ { "AFTER", 5}, +/* 264 */ { "AGAINST", 7}, +/* 265 */ { "AGGREGATE", 9}, +/* 266 */ { "ALGORITHM", 9}, +/* 267 */ { "ALL", 3}, +/* 268 */ { "ALTER", 5}, +/* 269 */ { "ALWAYS", 6}, +/* 270 */ { "ANALYZE", 7}, +/* 271 */ { "&&", 2}, +/* 272 */ { "AND", 3}, +/* 273 */ { "SOME", 4}, +/* 274 */ { "AS", 2}, +/* 275 */ { "ASC", 3}, +/* 276 */ { "ASCII", 5}, +/* 277 */ { "ASENSITIVE", 10}, +/* 278 */ { "AT", 2}, +/* 279 */ { "AUTHORS", 7}, +/* 280 */ { "AUTOEXTEND_SIZE", 15}, +/* 281 */ { "AUTO_INCREMENT", 14}, +/* 282 */ { "AVG_ROW_LENGTH", 14}, +/* 283 */ { "AVG", 3}, +/* 284 */ { "BACKUP", 6}, +/* 285 */ { "BEFORE", 6}, +/* 286 */ { "BEGIN", 5}, +/* 287 */ { "BETWEEN", 7}, +/* 288 */ { "INT8", 4}, +/* 289 */ { "BINARY", 6}, +/* 290 */ { "BINLOG", 6}, +/* 291 */ { "(bin)", 5}, +/* 292 */ { "BIT_AND", 7}, +/* 293 */ { "BIT_OR", 6}, +/* 294 */ { "BIT", 3}, +/* 295 */ { "BIT_XOR", 7}, +/* 296 */ { "BLOB", 4}, +/* 297 */ { "BLOCK", 5}, +/* 298 */ { "BOOLEAN", 7}, +/* 299 */ { "BOOL", 4}, +/* 300 */ { "BOTH", 4}, +/* 301 */ { "BTREE", 5}, +/* 302 */ { "BY", 2}, +/* 303 */ { "BYTE", 4}, +/* 304 */ { "CACHE", 5}, +/* 305 */ { "CALL", 4}, +/* 306 */ { "CASCADE", 7}, +/* 307 */ { "CASCADED", 8}, +/* 308 */ { "CASE", 4}, +/* 309 */ { "CAST", 4}, +/* 310 */ { "CATALOG_NAME", 12}, +/* 311 */ { "CHAIN", 5}, +/* 312 */ { "CHANGE", 6}, +/* 313 */ { "CHANGED", 7}, +/* 314 */ { "CHARSET", 7}, +/* 315 */ { "CHARACTER", 9}, +/* 316 */ { "CHECKPOINT", 10}, +/* 317 */ { "CHECKSUM", 8}, +/* 318 */ { "CHECK", 5}, +/* 319 */ { "CIPHER", 6}, +/* 320 */ { "CLASS_ORIGIN", 12}, +/* 321 */ { "CLIENT", 6}, +/* 322 */ { "CLIENT_STATISTICS", 17}, +/* 323 */ { "CLOSE", 5}, +/* 324 */ { "COALESCE", 8}, +/* 325 */ { "CODE", 4}, +/* 326 */ { "COLLATE", 7}, +/* 327 */ { "COLLATION", 9}, +/* 328 */ { "FIELDS", 6}, +/* 329 */ { "COLUMN_ADD", 10}, +/* 330 */ { "COLUMN_CREATE", 13}, +/* 331 */ { "COLUMN_DELETE", 13}, +/* 332 */ { "COLUMN_EXISTS", 13}, +/* 333 */ { "COLUMN_GET", 10}, +/* 334 */ { "COLUMN_LIST", 11}, +/* 335 */ { "COLUMN", 6}, +/* 336 */ { "COLUMN_NAME", 11}, +/* 337 */ { "COMMENT", 7}, +/* 338 */ { "COMMITTED", 9}, +/* 339 */ { "COMMIT", 6}, +/* 340 */ { "COMPACT", 7}, +/* 341 */ { "COMPLETION", 10}, +/* 342 */ { "COMPRESSED", 10}, +/* 343 */ { "CONCURRENT", 10}, +/* 344 */ { "CONDITION", 9}, +/* 345 */ { "CONNECTION", 10}, +/* 346 */ { "CONSISTENT", 10}, +/* 347 */ { "CONSTRAINT", 10}, +/* 348 */ { "CONSTRAINT_CATALOG", 18}, +/* 349 */ { "CONSTRAINT_NAME", 15}, +/* 350 */ { "CONSTRAINT_SCHEMA", 17}, +/* 351 */ { "CONTAINS", 8}, +/* 352 */ { "CONTEXT", 7}, +/* 353 */ { "CONTINUE", 8}, +/* 354 */ { "CONTRIBUTORS", 12}, +/* 355 */ { "CONVERT", 7}, +/* 356 */ { "COUNT", 5}, +/* 357 */ { "CPU", 3}, +/* 358 */ { "CREATE", 6}, +/* 359 */ { "CROSS", 5}, +/* 360 */ { "CUBE", 4}, +/* 361 */ { "CURDATE", 7}, +/* 362 */ { "CURRENT_USER", 12}, +/* 363 */ { "CURSOR", 6}, +/* 364 */ { "CURSOR_NAME", 11}, +/* 365 */ { "CURTIME", 7}, +/* 366 */ { "SCHEMA", 6}, +/* 367 */ { "SCHEMAS", 7}, +/* 368 */ { "DATAFILE", 8}, +/* 369 */ { "DATA", 4}, +/* 370 */ { "DATETIME", 8}, +/* 371 */ { "DATE_ADD", 8}, +/* 372 */ { "DATE_SUB", 8}, +/* 373 */ { "DATE", 4}, +/* 374 */ { "DAY_HOUR", 8}, +/* 375 */ { "DAY_MICROSECOND", 15}, +/* 376 */ { "DAY_MINUTE", 10}, +/* 377 */ { "DAY_SECOND", 10}, +/* 378 */ { "SQL_TSI_DAY", 11}, +/* 379 */ { "DEALLOCATE", 10}, +/* 380 */ { "(decimal)", 9}, +/* 381 */ { "DECIMAL", 7}, +/* 382 */ { "DECLARE", 7}, +/* 383 */ { "DEFAULT", 7}, +/* 384 */ { "DEFINER", 7}, +/* 385 */ { "DELAYED", 7}, +/* 386 */ { "DELAY_KEY_WRITE", 15}, +/* 387 */ { "DELETE", 6}, +/* 388 */ { "DESC", 4}, +/* 389 */ { "EXPLAIN", 7}, +/* 390 */ { "DES_KEY_FILE", 12}, +/* 391 */ { "DETERMINISTIC", 13}, +/* 392 */ { "DIRECTORY", 9}, +/* 393 */ { "DISABLE", 7}, +/* 394 */ { "DISCARD", 7}, +/* 395 */ { "DISK", 4}, +/* 396 */ { "DISTINCTROW", 11}, +/* 397 */ { "DIV", 3}, +/* 398 */ { "FLOAT8", 6}, +/* 399 */ { "DO", 2}, +/* 400 */ { "DROP", 4}, +/* 401 */ { "DUAL", 4}, +/* 402 */ { "DUMPFILE", 8}, +/* 403 */ { "DUPLICATE", 9}, +/* 404 */ { "DYNAMIC", 7}, +/* 405 */ { "EACH", 4}, +/* 406 */ { "ELSE", 4}, +/* 407 */ { "ELSEIF", 6}, +/* 408 */ { "ENABLE", 6}, +/* 409 */ { "ENCLOSED", 8}, +/* 410 */ { "END", 3}, +/* 411 */ { "ENDS", 4}, +/* 412 */ { "", 0}, +/* 413 */ { "ENGINES", 7}, +/* 414 */ { "ENGINE", 6}, +/* 415 */ { "ENUM", 4}, +/* 416 */ { "=", 1}, +/* 417 */ { "<=>", 3}, +/* 418 */ { "ERROR", 5}, +/* 419 */ { "ERRORS", 6}, +/* 420 */ { "ESCAPED", 7}, +/* 421 */ { "ESCAPE", 6}, +/* 422 */ { "EVENTS", 6}, +/* 423 */ { "EVENT", 5}, +/* 424 */ { "EVERY", 5}, +/* 425 */ { "EXAMINED", 8}, +/* 426 */ { "EXECUTE", 7}, +/* 427 */ { "EXISTS", 6}, +/* 428 */ { "EXIT", 4}, +/* 429 */ { "EXPANSION", 9}, +/* 430 */ { "EXTENDED", 8}, +/* 431 */ { "EXTENT_SIZE", 11}, +/* 432 */ { "EXTRACT", 7}, +/* 433 */ { "FALSE", 5}, +/* 434 */ { "FAST", 4}, +/* 435 */ { "FAULTS", 6}, +/* 436 */ { "FETCH", 5}, +/* 437 */ { "FILE", 4}, +/* 438 */ { "FIRST", 5}, +/* 439 */ { "FIXED", 5}, +/* 440 */ { "(float)", 7}, +/* 441 */ { "FLOAT4", 6}, +/* 442 */ { "FLUSH", 5}, +/* 443 */ { "FORCE", 5}, +/* 444 */ { "FOREIGN", 7}, +/* 445 */ { "FOR", 3}, +/* 446 */ { "FOUND", 5}, +/* 447 */ { "FROM", 4}, +/* 448 */ { "FULL", 4}, +/* 449 */ { "FULLTEXT", 8}, +/* 450 */ { "FUNCTION", 8}, +/* 451 */ { ">=", 2}, +/* 452 */ { "GENERAL", 7}, +/* 453 */ { "GENERATED", 9}, +/* 454 */ { "GEOMETRYCOLLECTION", 18}, +/* 455 */ { "GEOMETRY", 8}, +/* 456 */ { "GET_FORMAT", 10}, +/* 457 */ { "GLOBAL", 6}, +/* 458 */ { "GRANT", 5}, +/* 459 */ { "GRANTS", 6}, +/* 460 */ { "GROUP", 5}, +/* 461 */ { "GROUP_CONCAT", 12}, +/* 462 */ { ">", 1}, +/* 463 */ { "HANDLER", 7}, +/* 464 */ { "HARD", 4}, +/* 465 */ { "HASH", 4}, +/* 466 */ { "HAVING", 6}, +/* 467 */ { "HELP", 4}, +/* 468 */ { "(hex)", 5}, +/* 469 */ { "HIGH_PRIORITY", 13}, +/* 470 */ { "HOST", 4}, +/* 471 */ { "HOSTS", 5}, +/* 472 */ { "HOUR_MICROSECOND", 16}, +/* 473 */ { "HOUR_MINUTE", 11}, +/* 474 */ { "HOUR_SECOND", 11}, +/* 475 */ { "SQL_TSI_HOUR", 12}, +/* 476 */ { "(id)", 4}, +/* 477 */ { "IDENTIFIED", 10}, +/* 478 */ { "(id_quoted)", 11}, +/* 479 */ { "IF", 2}, +/* 480 */ { "IGNORE", 6}, +/* 481 */ { "IGNORE_SERVER_IDS", 17}, +/* 482 */ { "IMPORT", 6}, +/* 483 */ { "INDEXES", 7}, +/* 484 */ { "INDEX", 5}, +/* 485 */ { "INDEX_STATISTICS", 16}, +/* 486 */ { "INFILE", 6}, +/* 487 */ { "INITIAL_SIZE", 12}, +/* 488 */ { "INNER", 5}, +/* 489 */ { "INOUT", 5}, +/* 490 */ { "INSENSITIVE", 11}, +/* 491 */ { "INSERT", 6}, +/* 492 */ { "INSERT_METHOD", 13}, +/* 493 */ { "INSTALL", 7}, +/* 494 */ { "INTERVAL", 8}, +/* 495 */ { "INTO", 4}, +/* 496 */ { "INTEGER", 7}, +/* 497 */ { "INVOKER", 7}, +/* 498 */ { "IN", 2}, +/* 499 */ { "IO", 2}, +/* 500 */ { "IPC", 3}, +/* 501 */ { "IS", 2}, +/* 502 */ { "ISOLATION", 9}, +/* 503 */ { "ISSUER", 6}, +/* 504 */ { "ITERATE", 7}, +/* 505 */ { "JOIN", 4}, +/* 506 */ { "KEYS", 4}, +/* 507 */ { "KEY_BLOCK_SIZE", 14}, +/* 508 */ { "KEY", 3}, +/* 509 */ { "KILL", 4}, +/* 510 */ { "LANGUAGE", 8}, +/* 511 */ { "LAST", 4}, +/* 512 */ { "<=", 2}, +/* 513 */ { "LEADING", 7}, +/* 514 */ { "LEAVES", 6}, +/* 515 */ { "LEAVE", 5}, +/* 516 */ { "LEFT", 4}, +/* 517 */ { "LESS", 4}, +/* 518 */ { "LEVEL", 5}, +/* 519 */ { "(hostname)", 10}, +/* 520 */ { "LIKE", 4}, +/* 521 */ { "LIMIT", 5}, +/* 522 */ { "LINEAR", 6}, +/* 523 */ { "LINES", 5}, +/* 524 */ { "LINESTRING", 10}, +/* 525 */ { "LIST", 4}, +/* 526 */ { "LOAD", 4}, +/* 527 */ { "LOCAL", 5}, +/* 528 */ { "LOCATOR", 7}, +/* 529 */ { "LOCKS", 5}, +/* 530 */ { "LOCK", 4}, +/* 531 */ { "LOGFILE", 7}, +/* 532 */ { "LOGS", 4}, +/* 533 */ { "LONGBLOB", 8}, +/* 534 */ { "LONGTEXT", 8}, +/* 535 */ { "(long)", 6}, +/* 536 */ { "LONG", 4}, +/* 537 */ { "LOOP", 4}, +/* 538 */ { "LOW_PRIORITY", 12}, +/* 539 */ { "<", 1}, +/* 540 */ { "MASTER_CONNECT_RETRY", 20}, +/* 541 */ { "MASTER_HOST", 11}, +/* 542 */ { "MASTER_LOG_FILE", 15}, +/* 543 */ { "MASTER_LOG_POS", 14}, +/* 544 */ { "MASTER_PASSWORD", 15}, +/* 545 */ { "MASTER_PORT", 11}, +/* 546 */ { "MASTER_SERVER_ID", 16}, +/* 547 */ { "MASTER_SSL_CAPATH", 17}, +/* 548 */ { "MASTER_SSL_CA", 13}, +/* 549 */ { "MASTER_SSL_CERT", 15}, +/* 550 */ { "MASTER_SSL_CIPHER", 17}, +/* 551 */ { "MASTER_SSL_KEY", 14}, +/* 552 */ { "MASTER_SSL", 10}, +/* 553 */ { "MASTER_SSL_VERIFY_SERVER_CERT", 29}, +/* 554 */ { "MASTER", 6}, +/* 555 */ { "MASTER_USER", 11}, +/* 556 */ { "MASTER_HEARTBEAT_PERIOD", 23}, +/* 557 */ { "MATCH", 5}, +/* 558 */ { "MAX_CONNECTIONS_PER_HOUR", 24}, +/* 559 */ { "MAX_QUERIES_PER_HOUR", 20}, +/* 560 */ { "MAX_ROWS", 8}, +/* 561 */ { "MAX_SIZE", 8}, +/* 562 */ { "MAX", 3}, +/* 563 */ { "MAX_UPDATES_PER_HOUR", 20}, +/* 564 */ { "MAX_USER_CONNECTIONS", 20}, +/* 565 */ { "MAXVALUE", 8}, +/* 566 */ { "MEDIUMBLOB", 10}, +/* 567 */ { "MIDDLEINT", 9}, +/* 568 */ { "MEDIUMTEXT", 10}, +/* 569 */ { "MEDIUM", 6}, +/* 570 */ { "MEMORY", 6}, +/* 571 */ { "MERGE", 5}, +/* 572 */ { "MESSAGE_TEXT", 12}, +/* 573 */ { "MICROSECOND", 11}, +/* 574 */ { "MIGRATE", 7}, +/* 575 */ { "MINUTE_MICROSECOND", 18}, +/* 576 */ { "MINUTE_SECOND", 13}, +/* 577 */ { "SQL_TSI_MINUTE", 14}, +/* 578 */ { "MIN_ROWS", 8}, +/* 579 */ { "MIN", 3}, +/* 580 */ { "MODE", 4}, +/* 581 */ { "MODIFIES", 8}, +/* 582 */ { "MODIFY", 6}, +/* 583 */ { "MOD", 3}, +/* 584 */ { "SQL_TSI_MONTH", 13}, +/* 585 */ { "MULTILINESTRING", 15}, +/* 586 */ { "MULTIPOINT", 10}, +/* 587 */ { "MULTIPOLYGON", 12}, +/* 588 */ { "MUTEX", 5}, +/* 589 */ { "MYSQL_ERRNO", 11}, +/* 590 */ { "NAMES", 5}, +/* 591 */ { "NAME", 4}, +/* 592 */ { "NATIONAL", 8}, +/* 593 */ { "NATURAL", 7}, +/* 594 */ { "(nchar)", 7}, +/* 595 */ { "NCHAR", 5}, +/* 596 */ { "NDBCLUSTER", 10}, +/* 597 */ { "!=", 2}, +/* 598 */ { "~", 1}, +/* 599 */ { "NEW", 3}, +/* 600 */ { "NEXT", 4}, +/* 601 */ { "NODEGROUP", 9}, +/* 602 */ { "NONE", 4}, +/* 603 */ { "!", 1}, +/* 604 */ { "NOT", 3}, +/* 605 */ { "NOW", 3}, +/* 606 */ { "NO", 2}, +/* 607 */ { "NO_WAIT", 7}, +/* 608 */ { "NO_WRITE_TO_BINLOG", 18}, +/* 609 */ { "NULL", 4}, +/* 610 */ { "(num)", 5}, +/* 611 */ { "NUMERIC", 7}, +/* 612 */ { "NVARCHAR", 8}, +/* 613 */ { "OFFSET", 6}, +/* 614 */ { "OLD_PASSWORD", 12}, +/* 615 */ { "ON", 2}, +/* 616 */ { "ONE_SHOT", 8}, +/* 617 */ { "ONE", 3}, +/* 618 */ { "ONLINE", 6}, +/* 619 */ { "OPEN", 4}, +/* 620 */ { "OPTIMIZE", 8}, +/* 621 */ { "OPTIONS", 7}, +/* 622 */ { "OPTION", 6}, +/* 623 */ { "OPTIONALLY", 10}, +/* 624 */ { "|", 1}, +/* 625 */ { "ORDER", 5}, +/* 626 */ { "||", 2}, +/* 627 */ { "OR", 2}, +/* 628 */ { "OUTER", 5}, +/* 629 */ { "OUTFILE", 7}, +/* 630 */ { "OUT", 3}, +/* 631 */ { "OWNER", 5}, +/* 632 */ { "PACK_KEYS", 9}, +/* 633 */ { "PAGE", 4}, +/* 634 */ { "PAGE_CHECKSUM", 13}, +/* 635 */ { "?", 1}, +/* 636 */ { "PARSER", 6}, +/* 637 */ { "PARSE_VCOL_EXPR", 15}, +/* 638 */ { "PARTIAL", 7}, +/* 639 */ { "PARTITIONING", 12}, +/* 640 */ { "PARTITIONS", 10}, +/* 641 */ { "PARTITION", 9}, +/* 642 */ { "PASSWORD", 8}, +/* 643 */ { "PERSISTENT", 10}, +/* 644 */ { "PHASE", 5}, +/* 645 */ { "PLUGINS", 7}, +/* 646 */ { "PLUGIN", 6}, +/* 647 */ { "POINT", 5}, +/* 648 */ { "POLYGON", 7}, +/* 649 */ { "PORT", 4}, +/* 650 */ { "POSITION", 8}, +/* 651 */ { "PRECISION", 9}, +/* 652 */ { "PREPARE", 7}, +/* 653 */ { "PRESERVE", 8}, +/* 654 */ { "PREV", 4}, +/* 655 */ { "PRIMARY", 7}, +/* 656 */ { "PRIVILEGES", 10}, +/* 657 */ { "PROCEDURE", 9}, +/* 658 */ { "PROCESS", 7}, +/* 659 */ { "PROCESSLIST", 11}, +/* 660 */ { "PROFILE", 7}, +/* 661 */ { "PROFILES", 8}, +/* 662 */ { "PROXY", 5}, +/* 663 */ { "PURGE", 5}, +/* 664 */ { "SQL_TSI_QUARTER", 15}, +/* 665 */ { "QUERY", 5}, +/* 666 */ { "QUICK", 5}, +/* 667 */ { "RANGE", 5}, +/* 668 */ { "READS", 5}, +/* 669 */ { "READ_ONLY", 9}, +/* 670 */ { "READ", 4}, +/* 671 */ { "READ_WRITE", 10}, +/* 672 */ { "REAL", 4}, +/* 673 */ { "REBUILD", 7}, +/* 674 */ { "RECOVER", 7}, +/* 675 */ { "REDOFILE", 8}, +/* 676 */ { "REDO_BUFFER_SIZE", 16}, +/* 677 */ { "REDUNDANT", 9}, +/* 678 */ { "REFERENCES", 10}, +/* 679 */ { "RLIKE", 5}, +/* 680 */ { "RELAY", 5}, +/* 681 */ { "RELAYLOG", 8}, +/* 682 */ { "RELAY_LOG_FILE", 14}, +/* 683 */ { "RELAY_LOG_POS", 13}, +/* 684 */ { "RELAY_THREAD", 12}, +/* 685 */ { "RELEASE", 7}, +/* 686 */ { "RELOAD", 6}, +/* 687 */ { "REMOVE", 6}, +/* 688 */ { "RENAME", 6}, +/* 689 */ { "REORGANIZE", 10}, +/* 690 */ { "REPAIR", 6}, +/* 691 */ { "REPEATABLE", 10}, +/* 692 */ { "REPEAT", 6}, +/* 693 */ { "REPLACE", 7}, +/* 694 */ { "REPLICATION", 11}, +/* 695 */ { "REQUIRE", 7}, +/* 696 */ { "RESET", 5}, +/* 697 */ { "RESIGNAL", 8}, +/* 698 */ { "USER_RESOURCES", 14}, +/* 699 */ { "RESTORE", 7}, +/* 700 */ { "RESTRICT", 8}, +/* 701 */ { "RESUME", 6}, +/* 702 */ { "RETURNS", 7}, +/* 703 */ { "RETURN", 6}, +/* 704 */ { "REVOKE", 6}, +/* 705 */ { "RIGHT", 5}, +/* 706 */ { "ROLLBACK", 8}, +/* 707 */ { "ROLLUP", 6}, +/* 708 */ { "ROUTINE", 7}, +/* 709 */ { "ROWS", 4}, +/* 710 */ { "ROW_FORMAT", 10}, +/* 711 */ { "ROW", 3}, +/* 712 */ { "RTREE", 5}, +/* 713 */ { "SAVEPOINT", 9}, +/* 714 */ { "SCHEDULE", 8}, +/* 715 */ { "SCHEMA_NAME", 11}, +/* 716 */ { "SECOND_MICROSECOND", 18}, +/* 717 */ { "SQL_TSI_SECOND", 14}, +/* 718 */ { "SECURITY", 8}, +/* 719 */ { "SELECT", 6}, +/* 720 */ { "SENSITIVE", 9}, +/* 721 */ { "SEPARATOR", 9}, +/* 722 */ { "SERIALIZABLE", 12}, +/* 723 */ { "SERIAL", 6}, +/* 724 */ { "SESSION", 7}, +/* 725 */ { "SERVER", 6}, +/* 726 */ { "SERVER_OPTIONS", 14}, +/* 727 */ { "SET", 3}, +/* 728 */ { ":=", 2}, +/* 729 */ { "SHARE", 5}, +/* 730 */ { "<<", 2}, +/* 731 */ { ">>", 2}, +/* 732 */ { "SHOW", 4}, +/* 733 */ { "SHUTDOWN", 8}, +/* 734 */ { "SIGNAL", 6}, +/* 735 */ { "SIGNED", 6}, +/* 736 */ { "SIMPLE", 6}, +/* 737 */ { "SLAVE", 5}, +/* 738 */ { "SLOW", 4}, +/* 739 */ { "SMALLINT", 8}, +/* 740 */ { "SNAPSHOT", 8}, +/* 741 */ { "SOCKET", 6}, +/* 742 */ { "SOFT", 4}, +/* 743 */ { "SONAME", 6}, +/* 744 */ { "SOUNDS", 6}, +/* 745 */ { "SOURCE", 6}, +/* 746 */ { "SPATIAL", 7}, +/* 747 */ { "SPECIFIC", 8}, +/* 748 */ { "SQLEXCEPTION", 12}, +/* 749 */ { "SQLSTATE", 8}, +/* 750 */ { "SQLWARNING", 10}, +/* 751 */ { "SQL_BIG_RESULT", 14}, +/* 752 */ { "SQL_BUFFER_RESULT", 17}, +/* 753 */ { "SQL_CACHE", 9}, +/* 754 */ { "SQL_CALC_FOUND_ROWS", 19}, +/* 755 */ { "SQL_NO_CACHE", 12}, +/* 756 */ { "SQL_SMALL_RESULT", 16}, +/* 757 */ { "SQL", 3}, +/* 758 */ { "SQL_THREAD", 10}, +/* 759 */ { "SSL", 3}, +/* 760 */ { "STARTING", 8}, +/* 761 */ { "STARTS", 6}, +/* 762 */ { "START", 5}, +/* 763 */ { "STATUS", 6}, +/* 764 */ { "STDDEV_SAMP", 11}, +/* 765 */ { "STDDEV_POP", 10}, +/* 766 */ { "STOP", 4}, +/* 767 */ { "STORAGE", 7}, +/* 768 */ { "STRAIGHT_JOIN", 13}, +/* 769 */ { "STRING", 6}, +/* 770 */ { "SUBCLASS_ORIGIN", 15}, +/* 771 */ { "SUBDATE", 7}, +/* 772 */ { "SUBJECT", 7}, +/* 773 */ { "SUBPARTITIONS", 13}, +/* 774 */ { "SUBPARTITION", 12}, +/* 775 */ { "SUBSTRING", 9}, +/* 776 */ { "SUM", 3}, +/* 777 */ { "SUPER", 5}, +/* 778 */ { "SUSPEND", 7}, +/* 779 */ { "SWAPS", 5}, +/* 780 */ { "SWITCHES", 8}, +/* 781 */ { "SYSDATE", 7}, +/* 782 */ { "TABLES", 6}, +/* 783 */ { "TABLESPACE", 10}, +/* 784 */ { "TABLE_REF_PRIORITY", 18}, +/* 785 */ { "TABLE_STATISTICS", 16}, +/* 786 */ { "TABLE", 5}, +/* 787 */ { "TABLE_CHECKSUM", 14}, +/* 788 */ { "TABLE_NAME", 10}, +/* 789 */ { "TEMPORARY", 9}, +/* 790 */ { "TEMPTABLE", 9}, +/* 791 */ { "TERMINATED", 10}, +/* 792 */ { "(text)", 6}, +/* 793 */ { "TEXT", 4}, +/* 794 */ { "THAN", 4}, +/* 795 */ { "THEN", 4}, +/* 796 */ { "TIMESTAMP", 9}, +/* 797 */ { "TIMESTAMPADD", 12}, +/* 798 */ { "TIMESTAMPDIFF", 13}, +/* 799 */ { "TIME", 4}, +/* 800 */ { "TINYBLOB", 8}, +/* 801 */ { "TINYINT", 7}, +/* 802 */ { "TINYTEXT", 8}, +/* 803 */ { "TO", 2}, +/* 804 */ { "TRAILING", 8}, +/* 805 */ { "TRANSACTION", 11}, +/* 806 */ { "TRANSACTIONAL", 13}, +/* 807 */ { "TRIGGERS", 8}, +/* 808 */ { "TRIGGER", 7}, +/* 809 */ { "TRIM", 4}, +/* 810 */ { "TRUE", 4}, +/* 811 */ { "TRUNCATE", 8}, +/* 812 */ { "TYPES", 5}, +/* 813 */ { "TYPE", 4}, +/* 814 */ { "UDF_RETURNS", 11}, +/* 815 */ { "(ulonglong)", 11}, +/* 816 */ { "UNCOMMITTED", 11}, +/* 817 */ { "UNDEFINED", 9}, +/* 818 */ { "(_charset)", 10}, +/* 819 */ { "UNDOFILE", 8}, +/* 820 */ { "UNDO_BUFFER_SIZE", 16}, +/* 821 */ { "UNDO", 4}, +/* 822 */ { "UNICODE", 7}, +/* 823 */ { "UNINSTALL", 9}, +/* 824 */ { "UNION", 5}, +/* 825 */ { "UNIQUE", 6}, +/* 826 */ { "UNKNOWN", 7}, +/* 827 */ { "UNLOCK", 6}, +/* 828 */ { "UNSIGNED", 8}, +/* 829 */ { "UNTIL", 5}, +/* 830 */ { "UPDATE", 6}, +/* 831 */ { "UPGRADE", 7}, +/* 832 */ { "USAGE", 5}, +/* 833 */ { "SYSTEM_USER", 11}, +/* 834 */ { "USER_STATISTICS", 15}, +/* 835 */ { "USE_FRM", 7}, +/* 836 */ { "USE", 3}, +/* 837 */ { "USING", 5}, +/* 838 */ { "UTC_DATE", 8}, +/* 839 */ { "UTC_TIMESTAMP", 13}, +/* 840 */ { "UTC_TIME", 8}, +/* 841 */ { "VALUES", 6}, +/* 842 */ { "VALUE", 5}, +/* 843 */ { "VARBINARY", 9}, +/* 844 */ { "VARCHARACTER", 12}, +/* 845 */ { "VARIABLES", 9}, +/* 846 */ { "VAR_POP", 7}, +/* 847 */ { "VARYING", 7}, +/* 848 */ { "VAR_SAMP", 8}, +/* 849 */ { "VIA", 3}, +/* 850 */ { "VIEW", 4}, +/* 851 */ { "VIRTUAL", 7}, +/* 852 */ { "WAIT", 4}, +/* 853 */ { "WARNINGS", 8}, +/* 854 */ { "WEEK", 4}, +/* 855 */ { "WHEN", 4}, +/* 856 */ { "WHERE", 5}, +/* 857 */ { "WHILE", 5}, +/* 858 */ { "WITH", 4}, +/* 859 */ { "WITH CUBE", 9}, +/* 860 */ { "WITH ROLLUP", 11}, +/* 861 */ { "WORK", 4}, +/* 862 */ { "WRAPPER", 7}, +/* 863 */ { "WRITE", 5}, +/* 864 */ { "X509", 4}, +/* 865 */ { "XA", 2}, +/* 866 */ { "XML", 3}, +/* 867 */ { "XOR", 3}, +/* 868 */ { "YEAR_MONTH", 10}, +/* 869 */ { "YEAR", 4}, +/* 870 */ { "ZEROFILL", 8}, +/* 871 */ { "?", 1}, +/* 872 */ { "?, ...", 6}, +/* 873 */ { "(?)", 3}, +/* 874 */ { "(?) /* , ... */", 15}, +/* 875 */ { "(...)", 5}, +/* 876 */ { "(...) /* , ... */", 17}, +/* 877 */ { "UNUSED", 6}, +/* DUMMY */ { "", 0} +}; +/* PFS specific tokens. */ +#define TOK_PFS_GENERIC_VALUE 871 +#define TOK_PFS_GENERIC_VALUE_LIST 872 +#define TOK_PFS_ROW_SINGLE_VALUE 873 +#define TOK_PFS_ROW_SINGLE_VALUE_LIST 874 +#define TOK_PFS_ROW_MULTIPLE_VALUE 875 +#define TOK_PFS_ROW_MULTIPLE_VALUE_LIST 876 +#define TOK_PFS_UNUSED 877 diff --git a/storage/perfschema/pfs_lock.h b/storage/perfschema/pfs_lock.h index 82c34fc2702..65937e94ece 100644 --- a/storage/perfschema/pfs_lock.h +++ b/storage/perfschema/pfs_lock.h @@ -108,6 +108,17 @@ struct pfs_lock } /** + Execute an allocated to dirty transition. + This transition should be executed by the writer that owns the record, + before the record is modified. + */ + void allocated_to_dirty(void) + { + DBUG_ASSERT(m_state == PFS_LOCK_ALLOCATED); + PFS_atomic::store_32(&m_state, PFS_LOCK_DIRTY); + } + + /** Execute a dirty to allocated transition. This transition should be executed by the writer that owns the record, after the record is in a state ready to be read. @@ -172,6 +183,11 @@ struct pfs_lock (copy->m_state == PFS_atomic::load_32(&m_state)) && (copy->m_state == PFS_LOCK_ALLOCATED)); } + + uint32 get_version() + { + return PFS_atomic::load_u32(&m_version); + } }; diff --git a/storage/perfschema/pfs_server.cc b/storage/perfschema/pfs_server.cc index 0f322a9cb76..1f7010e5b5f 100644 --- a/storage/perfschema/pfs_server.cc +++ b/storage/perfschema/pfs_server.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 @@ -27,21 +27,35 @@ #include "pfs_instr_class.h" #include "pfs_instr.h" #include "pfs_events_waits.h" +#include "pfs_events_stages.h" +#include "pfs_events_statements.h" #include "pfs_timer.h" +#include "pfs_setup_actor.h" +#include "pfs_setup_object.h" +#include "pfs_host.h" +#include "pfs_user.h" +#include "pfs_account.h" +#include "pfs_defaults.h" +#include "pfs_digest.h" PFS_global_param pfs_param; +PFS_table_stat PFS_table_stat::g_reset_template; + C_MODE_START static void destroy_pfs_thread(void *key); C_MODE_END static void cleanup_performance_schema(void); +void cleanup_instrument_config(void); struct PSI_bootstrap* initialize_performance_schema(const PFS_global_param *param) { pfs_initialized= false; + PFS_table_stat::g_reset_template.reset(); + if (! param->m_enabled) { /* @@ -54,6 +68,9 @@ initialize_performance_schema(const PFS_global_param *param) init_timers(); PFS_atomic::init(); + init_event_name_sizing(param); + register_global_classes(); + if (pthread_key_create(&THR_PFS, destroy_pfs_thread)) return NULL; @@ -65,11 +82,30 @@ initialize_performance_schema(const PFS_global_param *param) init_thread_class(param->m_thread_class_sizing) || init_table_share(param->m_table_share_sizing) || init_file_class(param->m_file_class_sizing) || + init_stage_class(param->m_stage_class_sizing) || + init_statement_class(param->m_statement_class_sizing) || + init_socket_class(param->m_socket_class_sizing) || init_instruments(param) || init_events_waits_history_long( param->m_events_waits_history_long_sizing) || + init_events_stages_history_long( + param->m_events_stages_history_long_sizing) || + init_events_statements_history_long( + param->m_events_statements_history_long_sizing) || init_file_hash() || - init_table_share_hash()) + init_table_share_hash() || + init_setup_actor(param) || + init_setup_actor_hash() || + init_setup_object(param) || + init_setup_object_hash() || + init_host(param) || + init_host_hash() || + init_user(param) || + init_user_hash() || + init_account(param) || + init_account_hash() || + init_digest(param) || + init_digest_hash()) { /* The performance schema initialization failed. @@ -80,6 +116,22 @@ initialize_performance_schema(const PFS_global_param *param) } pfs_initialized= true; + + /** Default values for SETUP_CONSUMERS */ + flag_events_stages_current= param->m_consumer_events_stages_current_enabled; + flag_events_stages_history= param->m_consumer_events_stages_history_enabled; + flag_events_stages_history_long= param->m_consumer_events_stages_history_long_enabled; + flag_events_statements_current= param->m_consumer_events_statements_current_enabled; + flag_events_statements_history= param->m_consumer_events_statements_history_enabled; + flag_events_statements_history_long= param->m_consumer_events_statements_history_long_enabled; + flag_events_waits_current= param->m_consumer_events_waits_current_enabled; + flag_events_waits_history= param->m_consumer_events_waits_history_enabled; + flag_events_waits_history_long= param->m_consumer_events_waits_history_long_enabled; + flag_global_instrumentation= param->m_consumer_global_instrumentation_enabled; + flag_thread_instrumentation= param->m_consumer_thread_instrumentation_enabled; + flag_statements_digest= param->m_consumer_statement_digest_enabled; + + install_default_setup(&PFS_bootstrap); return &PFS_bootstrap; } @@ -104,21 +156,41 @@ static void destroy_pfs_thread(void *key) static void cleanup_performance_schema(void) { + cleanup_instrument_config(); +/* Disabled: Bug#5666 cleanup_instruments(); cleanup_sync_class(); cleanup_thread_class(); cleanup_table_share(); cleanup_file_class(); + cleanup_stage_class(); + cleanup_statement_class(); + cleanup_socket_class(); cleanup_events_waits_history_long(); + cleanup_events_stages_history_long(); + cleanup_events_statements_history_long(); cleanup_table_share_hash(); cleanup_file_hash(); + cleanup_setup_actor(); + cleanup_setup_actor_hash(); + cleanup_setup_object(); + cleanup_setup_object_hash(); + cleanup_host(); + cleanup_host_hash(); + cleanup_user(); + cleanup_user_hash(); + cleanup_account(); + cleanup_account_hash(); + cleanup_digest(); PFS_atomic::cleanup(); +*/ } void shutdown_performance_schema(void) { pfs_initialized= false; cleanup_performance_schema(); +#if 0 /* Be careful to not delete un-initialized keys, this would affect key 0, which is THR_KEY_mysys, @@ -129,5 +201,94 @@ void shutdown_performance_schema(void) pthread_key_delete(THR_PFS); THR_PFS_initialized= false; } +#endif +} + +/** + Initialize the dynamic array used to hold PFS_INSTRUMENT configuration + options. +*/ +void init_pfs_instrument_array() +{ + my_init_dynamic_array(&pfs_instr_config_array, sizeof(PFS_instr_config*), 10, 10); + pfs_instr_config_state= PFS_INSTR_CONFIG_ALLOCATED; } +/** + Deallocate the PFS_INSTRUMENT array. Use an atomic compare-and-swap to ensure + that it is deallocated only once in the chaotic environment of server shutdown. +*/ +void cleanup_instrument_config() +{ + int desired_state= PFS_INSTR_CONFIG_ALLOCATED; + + /* Ignore if another thread has already deallocated the array */ + if (my_atomic_cas32(&pfs_instr_config_state, &desired_state, PFS_INSTR_CONFIG_DEALLOCATED)) + delete_dynamic(&pfs_instr_config_array); +} + +/** + Process one performance_schema_instrument configuration string. Isolate the + instrument name, evaluate the option value, and store them in a dynamic array. + Return 'false' for success, 'true' for error. + + @param name Instrument name + @param value Configuration option: 'on', 'off', etc. + @return 0 for success, non zero for errors +*/ + +int add_pfs_instr_to_array(const char* name, const char* value) +{ + int name_length= strlen(name); + int value_length= strlen(value); + + /* Allocate structure plus string buffers plus null terminators */ + PFS_instr_config* e = (PFS_instr_config*)my_malloc(sizeof(PFS_instr_config) + + name_length + 1 + value_length + 1, MYF(MY_WME)); + if (!e) return 1; + + /* Copy the instrument name */ + e->m_name= (char*)e + sizeof(PFS_instr_config); + memcpy(e->m_name, name, name_length); + e->m_name_length= name_length; + e->m_name[name_length]= '\0'; + + /* Set flags accordingly */ + if (!my_strcasecmp(&my_charset_latin1, value, "counted")) + { + e->m_enabled= true; + e->m_timed= false; + } + else + if (!my_strcasecmp(&my_charset_latin1, value, "true") || + !my_strcasecmp(&my_charset_latin1, value, "on") || + !my_strcasecmp(&my_charset_latin1, value, "1") || + !my_strcasecmp(&my_charset_latin1, value, "yes")) + { + e->m_enabled= true; + e->m_timed= true; + } + else + if (!my_strcasecmp(&my_charset_latin1, value, "false") || + !my_strcasecmp(&my_charset_latin1, value, "off") || + !my_strcasecmp(&my_charset_latin1, value, "0") || + !my_strcasecmp(&my_charset_latin1, value, "no")) + { + e->m_enabled= false; + e->m_timed= false; + } + else + { + my_free(e); + return 1; + } + + /* Add to the array of default startup options */ + if (insert_dynamic(&pfs_instr_config_array, &e)) + { + my_free(e); + return 1; + } + + return 0; +} diff --git a/storage/perfschema/pfs_server.h b/storage/perfschema/pfs_server.h index 8cb68cd52b1..f65febdeb6d 100644 --- a/storage/perfschema/pfs_server.h +++ b/storage/perfschema/pfs_server.h @@ -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 @@ -54,11 +54,17 @@ #ifndef PFS_MAX_FILE_HANDLE #define PFS_MAX_FILE_HANDLE 32768 #endif +#ifndef PFS_MAX_SOCKETS + #define PFS_MAX_SOCKETS 1000 +#endif +#ifndef PFS_MAX_SOCKET_CLASS + #define PFS_MAX_SOCKET_CLASS 10 +#endif #ifndef PFS_MAX_TABLE_SHARE - #define PFS_MAX_TABLE_SHARE 50000 + #define PFS_MAX_TABLE_SHARE 1000 #endif #ifndef PFS_MAX_TABLE - #define PFS_MAX_TABLE 100000 + #define PFS_MAX_TABLE 10000 #endif #ifndef PFS_WAITS_HISTORY_SIZE #define PFS_WAITS_HISTORY_SIZE 10 @@ -66,36 +72,217 @@ #ifndef PFS_WAITS_HISTORY_LONG_SIZE #define PFS_WAITS_HISTORY_LONG_SIZE 10000 #endif +#ifndef PFS_MAX_SETUP_ACTOR + #define PFS_MAX_SETUP_ACTOR 100 +#endif +#ifndef PFS_MAX_SETUP_OBJECT + #define PFS_MAX_SETUP_OBJECT 100 +#endif +#ifndef PFS_MAX_HOST + #define PFS_MAX_HOST 100 +#endif +#ifndef PFS_MAX_USER + #define PFS_MAX_USER 100 +#endif +#ifndef PFS_MAX_ACCOUNT + #define PFS_MAX_ACCOUNT 100 +#endif +#ifndef PFS_MAX_STAGE_CLASS + #define PFS_MAX_STAGE_CLASS 150 +#endif +#ifndef PFS_STAGES_HISTORY_SIZE + #define PFS_STAGES_HISTORY_SIZE 10 +#endif +#ifndef PFS_STAGES_HISTORY_LONG_SIZE + #define PFS_STAGES_HISTORY_LONG_SIZE 10000 +#endif +#ifndef PFS_STATEMENTS_HISTORY_SIZE + #define PFS_STATEMENTS_HISTORY_SIZE 10 +#endif +#ifndef PFS_STATEMENTS_HISTORY_LONG_SIZE + #define PFS_STATEMENTS_HISTORY_LONG_SIZE 10000 +#endif +#ifndef PFS_STATEMENTS_STACK_SIZE + #define PFS_STATEMENTS_STACK_SIZE 10 +#endif +#ifndef PFS_DIGEST_SIZE + #define PFS_DIGEST_SIZE 200 +#endif +/** Performance schema global sizing parameters. */ struct PFS_global_param { - bool m_enabled; + /** True if the performance schema is enabled. */ + bool m_enabled; + /** Default values for SETUP_CONSUMERS. */ + bool m_consumer_events_stages_current_enabled; + bool m_consumer_events_stages_history_enabled; + bool m_consumer_events_stages_history_long_enabled; + bool m_consumer_events_statements_current_enabled; + bool m_consumer_events_statements_history_enabled; + bool m_consumer_events_statements_history_long_enabled; + bool m_consumer_events_waits_current_enabled; + bool m_consumer_events_waits_history_enabled; + bool m_consumer_events_waits_history_long_enabled; + bool m_consumer_global_instrumentation_enabled; + bool m_consumer_thread_instrumentation_enabled; + bool m_consumer_statement_digest_enabled; + + /** Default instrument configuration option. */ + char *m_pfs_instrument; + + /** + Maximum number of instrumented mutex classes. + @sa mutex_class_lost. + */ ulong m_mutex_class_sizing; + /** + Maximum number of instrumented rwlock classes. + @sa rwlock_class_lost. + */ ulong m_rwlock_class_sizing; + /** + Maximum number of instrumented cond classes. + @sa cond_class_lost. + */ ulong m_cond_class_sizing; + /** + Maximum number of instrumented thread classes. + @sa thread_class_lost. + */ ulong m_thread_class_sizing; + /** + Maximum number of instrumented table share. + @sa table_share_lost. + */ ulong m_table_share_sizing; + /** + Maximum number of instrumented file classes. + @sa file_class_lost. + */ ulong m_file_class_sizing; + /** + Maximum number of instrumented mutex instances. + @sa mutex_lost. + */ ulong m_mutex_sizing; + /** + Maximum number of instrumented rwlock instances. + @sa rwlock_lost. + */ ulong m_rwlock_sizing; + /** + Maximum number of instrumented cond instances. + @sa cond_lost. + */ ulong m_cond_sizing; + /** + Maximum number of instrumented thread instances. + @sa thread_lost. + */ ulong m_thread_sizing; + /** + Maximum number of instrumented table handles. + @sa table_lost. + */ ulong m_table_sizing; + /** + Maximum number of instrumented file instances. + @sa file_lost. + */ ulong m_file_sizing; + /** + Maximum number of instrumented file handles. + @sa file_handle_lost. + */ ulong m_file_handle_sizing; + /** + Maxium number of instrumented socket instances + @sa socket_lost + */ + ulong m_socket_sizing; + /** + Maximum number of instrumented socket classes. + @sa socket_class_lost. + */ + ulong m_socket_class_sizing; + /** Maximum number of rows per thread in table EVENTS_WAITS_HISTORY. */ ulong m_events_waits_history_sizing; + /** Maximum number of rows in table EVENTS_WAITS_HISTORY_LONG. */ ulong m_events_waits_history_long_sizing; + /** Maximum number of rows in table SETUP_ACTORS. */ + ulong m_setup_actor_sizing; + /** Maximum number of rows in table SETUP_OBJECTS. */ + ulong m_setup_object_sizing; + /** Maximum number of rows in table HOSTS. */ + ulong m_host_sizing; + /** Maximum number of rows in table USERS. */ + ulong m_user_sizing; + /** Maximum number of rows in table ACCOUNTS. */ + ulong m_account_sizing; + /** + Maximum number of instrumented stage classes. + @sa stage_class_lost. + */ + ulong m_stage_class_sizing; + /** Maximum number of rows per thread in table EVENTS_STAGES_HISTORY. */ + ulong m_events_stages_history_sizing; + /** Maximum number of rows in table EVENTS_STAGES_HISTORY_LONG. */ + ulong m_events_stages_history_long_sizing; + /** + Maximum number of instrumented statement classes. + @sa statement_class_lost. + */ + ulong m_statement_class_sizing; + /** Maximum number of rows per thread in table EVENTS_STATEMENT_HISTORY. */ + ulong m_events_statements_history_sizing; + /** Maximum number of rows in table EVENTS_STATEMENTS_HISTORY_LONG. */ + ulong m_events_statements_history_long_sizing; + /** Maximum number of digests to be captured */ + ulong m_digest_sizing; }; +/** + Performance schema sizing values for the server. + This global variable is set when parsing server startup options. +*/ extern PFS_global_param pfs_param; +/** + Initialize the performance schema. + @param param Size parameters to use. + @return A boostrap handle, or NULL. +*/ struct PSI_bootstrap* initialize_performance_schema(const PFS_global_param *param); +/** + Initialize the performance schema ACL. + ACL is strictly enforced when the server is running in normal mode, + to enforce that only legal operations are allowed. + When running in boostrap mode, ACL restrictions are relaxed, + to allow the boostrap scripts to DROP / CREATE performance schema tables. + @sa ACL_internal_schema_registry + @param bootstrap True if the server is starting in bootstrap mode. +*/ void initialize_performance_schema_acl(bool bootstrap); void check_performance_schema(); +/** + Initialize the dynamic array holding individual instrument settings collected + from the server configuration options. +*/ +void init_pfs_instrument_array(); + +/** + Process one PFS_INSTRUMENT configuration string. +*/ +int add_pfs_instr_to_array(const char* name, const char* value); + +/** + Shutdown the performance schema. +*/ void shutdown_performance_schema(); #endif diff --git a/storage/perfschema/pfs_setup_actor.cc b/storage/perfschema/pfs_setup_actor.cc new file mode 100644 index 00000000000..a587d3643d2 --- /dev/null +++ b/storage/perfschema/pfs_setup_actor.cc @@ -0,0 +1,337 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/pfs_setup_actor.cc + Performance schema setup actor (implementation). +*/ + +#include "my_global.h" +#include "my_sys.h" +#include "my_base.h" +#include "pfs.h" +#include "pfs_stat.h" +#include "pfs_instr.h" +#include "pfs_setup_actor.h" +#include "pfs_global.h" + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +/** Size of the setup_actor instances array. @sa setup_actor_array */ +ulong setup_actor_max; + +/** + Setup_actor instances array. + @sa setup_actor_max +*/ + +PFS_setup_actor *setup_actor_array= NULL; + +/** Hash table for setup_actor records. */ +static LF_HASH setup_actor_hash; +/** True if @c setup_actor_hash is initialized. */ +static bool setup_actor_hash_inited= false; + +/** + Initialize the setup actor buffers. + @param param sizing parameters + @return 0 on success +*/ +int init_setup_actor(const PFS_global_param *param) +{ + setup_actor_max= param->m_setup_actor_sizing; + + setup_actor_array= NULL; + + if (setup_actor_max > 0) + { + setup_actor_array= PFS_MALLOC_ARRAY(setup_actor_max, PFS_setup_actor, + MYF(MY_ZEROFILL)); + if (unlikely(setup_actor_array == NULL)) + return 1; + } + + return 0; +} + +/** Cleanup all the setup actor buffers. */ +void cleanup_setup_actor(void) +{ + pfs_free(setup_actor_array); + setup_actor_array= NULL; + setup_actor_max= 0; +} + +C_MODE_START +static uchar *setup_actor_hash_get_key(const uchar *entry, size_t *length, + my_bool) +{ + const PFS_setup_actor * const *typed_entry; + const PFS_setup_actor *setup_actor; + const void *result; + typed_entry= reinterpret_cast<const PFS_setup_actor* const *> (entry); + DBUG_ASSERT(typed_entry != NULL); + setup_actor= *typed_entry; + DBUG_ASSERT(setup_actor != NULL); + *length= setup_actor->m_key.m_key_length; + result= setup_actor->m_key.m_hash_key; + return const_cast<uchar*> (reinterpret_cast<const uchar*> (result)); +} +C_MODE_END + +/** + Initialize the setup actor hash. + @return 0 on success +*/ +int init_setup_actor_hash(void) +{ + if (! setup_actor_hash_inited) + { + lf_hash_init(&setup_actor_hash, sizeof(PFS_setup_actor*), LF_HASH_UNIQUE, + 0, 0, setup_actor_hash_get_key, &my_charset_bin); + setup_actor_hash_inited= true; + } + return 0; +} + +/** Cleanup the setup actor hash. */ +void cleanup_setup_actor_hash(void) +{ + if (setup_actor_hash_inited) + { + lf_hash_destroy(&setup_actor_hash); + setup_actor_hash_inited= false; + } +} + +static LF_PINS* get_setup_actor_hash_pins(PFS_thread *thread) +{ + if (unlikely(thread->m_setup_actor_hash_pins == NULL)) + { + if (! setup_actor_hash_inited) + return NULL; + thread->m_setup_actor_hash_pins= lf_hash_get_pins(&setup_actor_hash); + } + return thread->m_setup_actor_hash_pins; +} + +static void set_setup_actor_key(PFS_setup_actor_key *key, + const char *user, uint user_length, + const char *host, uint host_length, + const char *role, uint role_length) +{ + DBUG_ASSERT(user_length <= USERNAME_LENGTH); + DBUG_ASSERT(host_length <= HOSTNAME_LENGTH); + + char *ptr= &key->m_hash_key[0]; + memcpy(ptr, user, user_length); + ptr+= user_length; + ptr[0]= 0; + ptr++; + memcpy(ptr, host, host_length); + ptr+= host_length; + ptr[0]= 0; + ptr++; + memcpy(ptr, role, role_length); + ptr+= role_length; + ptr[0]= 0; + ptr++; + key->m_key_length= ptr - &key->m_hash_key[0]; +} + +int insert_setup_actor(const String *user, const String *host, const String *role) +{ + if (setup_actor_max == 0) + return HA_ERR_RECORD_FILE_FULL; + + PFS_thread *thread= PFS_thread::get_current_thread(); + if (unlikely(thread == NULL)) + return HA_ERR_OUT_OF_MEM; + + LF_PINS *pins= get_setup_actor_hash_pins(thread); + if (unlikely(pins == NULL)) + return HA_ERR_OUT_OF_MEM; + + static uint setup_actor_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_setup_actor *pfs; + + while (++attempts <= setup_actor_max) + { + /* See create_mutex() */ + PFS_atomic::add_u32(& setup_actor_monotonic_index, 1); + index= setup_actor_monotonic_index % setup_actor_max; + pfs= setup_actor_array + index; + + if (pfs->m_lock.is_free()) + { + if (pfs->m_lock.free_to_dirty()) + { + set_setup_actor_key(&pfs->m_key, + user->ptr(), user->length(), + host->ptr(), host->length(), + role->ptr(), role->length()); + pfs->m_username= &pfs->m_key.m_hash_key[0]; + pfs->m_username_length= user->length(); + pfs->m_hostname= pfs->m_username + pfs->m_username_length + 1; + pfs->m_hostname_length= host->length(); + pfs->m_rolename= pfs->m_hostname + pfs->m_hostname_length + 1; + pfs->m_rolename_length= role->length(); + + int res; + res= lf_hash_insert(&setup_actor_hash, pins, &pfs); + if (likely(res == 0)) + { + pfs->m_lock.dirty_to_allocated(); + return 0; + } + + pfs->m_lock.dirty_to_free(); + if (res > 0) + return HA_ERR_FOUND_DUPP_KEY; + return HA_ERR_OUT_OF_MEM; + } + } + } + + return HA_ERR_RECORD_FILE_FULL; +} + +int delete_setup_actor(const String *user, const String *host, const String *role) +{ + PFS_thread *thread= PFS_thread::get_current_thread(); + if (unlikely(thread == NULL)) + return HA_ERR_OUT_OF_MEM; + + LF_PINS* pins= get_setup_actor_hash_pins(thread); + if (unlikely(pins == NULL)) + return HA_ERR_OUT_OF_MEM; + + PFS_setup_actor_key key; + set_setup_actor_key(&key, + user->ptr(), user->length(), + host->ptr(), host->length(), + role->ptr(), role->length()); + + PFS_setup_actor **entry; + entry= reinterpret_cast<PFS_setup_actor**> + (lf_hash_search(&setup_actor_hash, pins, key.m_hash_key, key.m_key_length)); + + if (entry && (entry != MY_ERRPTR)) + { + PFS_setup_actor *pfs= *entry; + lf_hash_delete(&setup_actor_hash, pins, key.m_hash_key, key.m_key_length); + pfs->m_lock.allocated_to_free(); + } + + lf_hash_search_unpin(pins); + + return 0; +} + +int reset_setup_actor() +{ + PFS_thread *thread= PFS_thread::get_current_thread(); + if (unlikely(thread == NULL)) + return HA_ERR_OUT_OF_MEM; + + LF_PINS* pins= get_setup_actor_hash_pins(thread); + if (unlikely(pins == NULL)) + return HA_ERR_OUT_OF_MEM; + + PFS_setup_actor *pfs= setup_actor_array; + PFS_setup_actor *pfs_last= setup_actor_array + setup_actor_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + { + lf_hash_delete(&setup_actor_hash, pins, + pfs->m_key.m_hash_key, pfs->m_key.m_key_length); + pfs->m_lock.allocated_to_free(); + } + } + + return 0; +} + +long setup_actor_count() +{ + return setup_actor_hash.count; +} + +/* + - '%' should be replaced by NULL in table SETUP_ACTOR + - add an ENABLED column to include/exclude patterns, more flexible + - the principle is similar to SETUP_OBJECTS +*/ +void lookup_setup_actor(PFS_thread *thread, + const char *user, uint user_length, + const char *host, uint host_length, + bool *enabled) +{ + PFS_setup_actor_key key; + PFS_setup_actor **entry; + int i; + + LF_PINS* pins= get_setup_actor_hash_pins(thread); + if (unlikely(pins == NULL)) + { + *enabled= false; + return; + } + + for (i= 1; i<=4; i++) + { + /* + WL#988 Roles is not implemented, so we do not have a role name. + Looking up "%" in SETUP_ACTORS.ROLE. + */ + switch(i) + { + case 1: + set_setup_actor_key(&key, user, user_length, host, host_length, "%", 1); + break; + case 2: + set_setup_actor_key(&key, user, user_length, "%", 1, "%", 1); + break; + case 3: + set_setup_actor_key(&key, "%", 1, host, host_length, "%", 1); + break; + case 4: + set_setup_actor_key(&key, "%", 1, "%", 1, "%", 1); + break; + } + entry= reinterpret_cast<PFS_setup_actor**> + (lf_hash_search(&setup_actor_hash, pins, key.m_hash_key, key.m_key_length)); + + if (entry && (entry != MY_ERRPTR)) + { + lf_hash_search_unpin(pins); + *enabled= true; + return; + } + + lf_hash_search_unpin(pins); + } + *enabled= false; + return; +} + +/** @} */ diff --git a/storage/perfschema/pfs_setup_actor.h b/storage/perfschema/pfs_setup_actor.h new file mode 100644 index 00000000000..8b0ee8a485c --- /dev/null +++ b/storage/perfschema/pfs_setup_actor.h @@ -0,0 +1,97 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef PFS_SETUP_ACTOR_H +#define PFS_SETUP_ACTOR_H + +/** + @file storage/perfschema/pfs_setup_actor.h + Performance schema setup actors (declarations). +*/ + +#include "sql_string.h" +#include "pfs_lock.h" +#include "lf.h" + +struct PFS_global_param; + +/* WL#988 Roles Not implemented yet */ +#define ROLENAME_LENGTH 64 + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +/** Hash key for @sa PFS_setup_actor. */ +struct PFS_setup_actor_key +{ + /** + Hash search key. + This has to be a string for LF_HASH, + the format is "<username><0x00><hostname><0x00><rolename><0x00>" + */ + char m_hash_key[USERNAME_LENGTH + 1 + HOSTNAME_LENGTH + 1 + ROLENAME_LENGTH + 1]; + /** Length of @c m_hash_key. */ + uint m_key_length; +}; + +/** A setup_actor record. */ +struct PFS_setup_actor +{ + /** Internal lock. */ + pfs_lock m_lock; + /** Hash key. */ + PFS_setup_actor_key m_key; + /** User name. This points inside the hash key. */ + const char *m_username; + /** Length of @c m_username. */ + uint m_username_length; + /** Host name. This points inside the hash key. */ + const char *m_hostname; + /** Length of @c m_hostname. */ + uint m_hostname_length; + /** Role name. This points inside the hash key. */ + const char *m_rolename; + /** Length of @c m_rolename. */ + uint m_rolename_length; +}; + +int init_setup_actor(const PFS_global_param *param); +void cleanup_setup_actor(void); +int init_setup_actor_hash(void); +void cleanup_setup_actor_hash(void); + +int insert_setup_actor(const String *user, const String *host, const String *role); +int delete_setup_actor(const String *user, const String *host, const String *role); +int reset_setup_actor(void); +long setup_actor_count(void); + +void lookup_setup_actor(PFS_thread *thread, + const char *user, uint user_length, + const char *host, uint host_length, + bool *enabled); + +/* For iterators and show status. */ + +extern ulong setup_actor_max; + +/* Exposing the data directly, for iterators. */ + +extern PFS_setup_actor *setup_actor_array; + +/** @} */ +#endif + diff --git a/storage/perfschema/pfs_setup_object.cc b/storage/perfschema/pfs_setup_object.cc new file mode 100644 index 00000000000..a9e9bb7881b --- /dev/null +++ b/storage/perfschema/pfs_setup_object.cc @@ -0,0 +1,345 @@ +/* Copyright (c) 2010, 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 + 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_setup_object.cc + Performance schema setup object (implementation). +*/ + +#include "my_global.h" +#include "my_sys.h" +#include "my_base.h" +#include "sql_string.h" +#include "pfs.h" +#include "pfs_stat.h" +#include "pfs_instr.h" +#include "pfs_setup_object.h" +#include "pfs_global.h" + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +uint setup_objects_version= 0; + +ulong setup_object_max; + +PFS_setup_object *setup_object_array= NULL; + +static LF_HASH setup_object_hash; +static bool setup_object_hash_inited= false; + +/** + Initialize the setup object buffers. + @param param sizing parameters + @return 0 on success +*/ +int init_setup_object(const PFS_global_param *param) +{ + setup_object_max= param->m_setup_object_sizing; + + setup_object_array= NULL; + + if (setup_object_max > 0) + { + setup_object_array= PFS_MALLOC_ARRAY(setup_object_max, PFS_setup_object, + MYF(MY_ZEROFILL)); + if (unlikely(setup_object_array == NULL)) + return 1; + } + + return 0; +} + +/** Cleanup all the setup object buffers. */ +void cleanup_setup_object(void) +{ + pfs_free(setup_object_array); + setup_object_array= NULL; + setup_object_max= 0; +} + +C_MODE_START +static uchar *setup_object_hash_get_key(const uchar *entry, size_t *length, + my_bool) +{ + const PFS_setup_object * const *typed_entry; + const PFS_setup_object *setup_object; + const void *result; + typed_entry= reinterpret_cast<const PFS_setup_object* const *> (entry); + DBUG_ASSERT(typed_entry != NULL); + setup_object= *typed_entry; + DBUG_ASSERT(setup_object != NULL); + *length= setup_object->m_key.m_key_length; + result= setup_object->m_key.m_hash_key; + return const_cast<uchar*> (reinterpret_cast<const uchar*> (result)); +} +C_MODE_END + +/** + Initialize the setup objects hash. + @return 0 on success +*/ +int init_setup_object_hash(void) +{ + if (! setup_object_hash_inited) + { + lf_hash_init(&setup_object_hash, sizeof(PFS_setup_object*), LF_HASH_UNIQUE, + 0, 0, setup_object_hash_get_key, &my_charset_bin); + setup_object_hash_inited= true; + } + return 0; +} + +/** Cleanup the setup objects hash. */ +void cleanup_setup_object_hash(void) +{ + if (setup_object_hash_inited) + { + lf_hash_destroy(&setup_object_hash); + setup_object_hash_inited= false; + } +} + +static LF_PINS* get_setup_object_hash_pins(PFS_thread *thread) +{ + if (unlikely(thread->m_setup_object_hash_pins == NULL)) + { + if (! setup_object_hash_inited) + return NULL; + thread->m_setup_object_hash_pins= lf_hash_get_pins(&setup_object_hash); + } + return thread->m_setup_object_hash_pins; +} + +static void set_setup_object_key(PFS_setup_object_key *key, + enum_object_type object_type, + const char *schema, uint schema_length, + const char *object, uint object_length) +{ + DBUG_ASSERT(schema_length <= NAME_LEN); + DBUG_ASSERT(object_length <= NAME_LEN); + + char *ptr= &key->m_hash_key[0]; + ptr[0]= (char) object_type; + ptr++; + memcpy(ptr, schema, schema_length); + ptr+= schema_length; + ptr[0]= 0; + ptr++; + memcpy(ptr, object, object_length); + ptr+= object_length; + ptr[0]= 0; + ptr++; + key->m_key_length= ptr - &key->m_hash_key[0]; +} + +int insert_setup_object(enum_object_type object_type, const String *schema, + const String *object, bool enabled, bool timed) +{ + if (setup_object_max == 0) + return HA_ERR_RECORD_FILE_FULL; + + PFS_thread *thread= PFS_thread::get_current_thread(); + if (unlikely(thread == NULL)) + return HA_ERR_OUT_OF_MEM; + + LF_PINS* pins= get_setup_object_hash_pins(thread); + if (unlikely(pins == NULL)) + return HA_ERR_OUT_OF_MEM; + + static uint setup_object_monotonic_index= 0; + uint index; + uint attempts= 0; + PFS_setup_object *pfs; + + while (++attempts <= setup_object_max) + { + /* See create_mutex() */ + PFS_atomic::add_u32(& setup_object_monotonic_index, 1); + index= setup_object_monotonic_index % setup_object_max; + pfs= setup_object_array + index; + + if (pfs->m_lock.is_free()) + { + if (pfs->m_lock.free_to_dirty()) + { + set_setup_object_key(&pfs->m_key, object_type, + schema->ptr(), schema->length(), + object->ptr(), object->length()); + pfs->m_schema_name= &pfs->m_key.m_hash_key[1]; + pfs->m_schema_name_length= schema->length(); + pfs->m_object_name= pfs->m_schema_name + pfs->m_schema_name_length + 1; + pfs->m_object_name_length= object->length(); + pfs->m_enabled= enabled; + pfs->m_timed= timed; + + int res; + res= lf_hash_insert(&setup_object_hash, pins, &pfs); + if (likely(res == 0)) + { + pfs->m_lock.dirty_to_allocated(); + setup_objects_version++; + return 0; + } + + pfs->m_lock.dirty_to_free(); + if (res > 0) + return HA_ERR_FOUND_DUPP_KEY; + /* OOM in lf_hash_insert */ + return HA_ERR_OUT_OF_MEM; + } + } + } + + return HA_ERR_RECORD_FILE_FULL; +} + +int delete_setup_object(enum_object_type object_type, const String *schema, + const String *object) +{ + PFS_thread *thread= PFS_thread::get_current_thread(); + if (unlikely(thread == NULL)) + return HA_ERR_OUT_OF_MEM; + + LF_PINS* pins= get_setup_object_hash_pins(thread); + if (unlikely(pins == NULL)) + return HA_ERR_OUT_OF_MEM; + + PFS_setup_object_key key; + set_setup_object_key(&key, object_type, + schema->ptr(), schema->length(), + object->ptr(), object->length()); + + PFS_setup_object **entry; + entry= reinterpret_cast<PFS_setup_object**> + (lf_hash_search(&setup_object_hash, pins, key.m_hash_key, key.m_key_length)); + + if (entry && (entry != MY_ERRPTR)) + { + PFS_setup_object *pfs= *entry; + lf_hash_delete(&setup_object_hash, pins, key.m_hash_key, key.m_key_length); + pfs->m_lock.allocated_to_free(); + } + + lf_hash_search_unpin(pins); + + setup_objects_version++; + return 0; +} + +int reset_setup_object() +{ + PFS_thread *thread= PFS_thread::get_current_thread(); + if (unlikely(thread == NULL)) + return HA_ERR_OUT_OF_MEM; + + LF_PINS* pins= get_setup_object_hash_pins(thread); + if (unlikely(pins == NULL)) + return HA_ERR_OUT_OF_MEM; + + PFS_setup_object *pfs= setup_object_array; + PFS_setup_object *pfs_last= setup_object_array + setup_object_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + { + lf_hash_delete(&setup_object_hash, pins, + pfs->m_key.m_hash_key, pfs->m_key.m_key_length); + pfs->m_lock.allocated_to_free(); + } + } + + setup_objects_version++; + return 0; +} + +long setup_object_count() +{ + return setup_object_hash.count; +} + +void lookup_setup_object(PFS_thread *thread, + enum_object_type object_type, + const char *schema_name, int schema_name_length, + const char *object_name, int object_name_length, + bool *enabled, bool *timed) +{ + PFS_setup_object_key key; + PFS_setup_object **entry; + PFS_setup_object *pfs; + int i; + + /* + The table io instrumentation uses "TABLE" and "TEMPORARY TABLE". + SETUP_OBJECT uses "TABLE" for both concepts. + There is no way to provide a different setup for: + - TABLE foo.bar + - TEMPORARY TABLE foo.bar + */ + DBUG_ASSERT(object_type != OBJECT_TYPE_TEMPORARY_TABLE); + + LF_PINS* pins= get_setup_object_hash_pins(thread); + if (unlikely(pins == NULL)) + { + *enabled= false; + *timed= false; + return; + } + + for (i= 1; i<=3; i++) + { + switch(i) + { + case 1: + /* Lookup OBJECT_TYPE + OBJECT_SCHEMA + OBJECT_NAME in SETUP_OBJECTS */ + set_setup_object_key(&key, + object_type, + schema_name, schema_name_length, + object_name, object_name_length); + break; + case 2: + /* Lookup OBJECT_TYPE + OBJECT_SCHEMA + "%" in SETUP_OBJECTS */ + set_setup_object_key(&key, + object_type, + schema_name, schema_name_length, "%", 1); + break; + case 3: + /* Lookup OBJECT_TYPE + "%" + "%" in SETUP_OBJECTS */ + set_setup_object_key(&key, object_type, "%", 1, "%", 1); + break; + } + entry= reinterpret_cast<PFS_setup_object**> + (lf_hash_search(&setup_object_hash, pins, key.m_hash_key, key.m_key_length)); + + if (entry && (entry != MY_ERRPTR)) + { + pfs= *entry; + *enabled= pfs->m_enabled; + *timed= pfs->m_timed; + lf_hash_search_unpin(pins); + return; + } + + lf_hash_search_unpin(pins); + } + *enabled= false; + *timed= false; + return; +} + +/** @} */ diff --git a/storage/perfschema/pfs_setup_object.h b/storage/perfschema/pfs_setup_object.h new file mode 100644 index 00000000000..44d2b76c627 --- /dev/null +++ b/storage/perfschema/pfs_setup_object.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef PFS_SETUP_OBJECT_H +#define PFS_SETUP_OBJECT_H + +/** + @file storage/perfschema/pfs_setup_object.h + Performance schema setup object (declarations). +*/ + +#include "pfs_lock.h" +#include "lf.h" + +class String; +struct PFS_global_param; + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +/** Hash key for @sa PFS_setup_object. */ +struct PFS_setup_object_key +{ + /** + Hash search key. + This has to be a string for LF_HASH, + the format is "<enum_object_type><schema_name><0x00><object_name><0x00>" + */ + char m_hash_key[1 + NAME_LEN + 1 + NAME_LEN + 1]; + uint m_key_length; +}; + +/** A setup_object record. */ +struct PFS_setup_object +{ + enum_object_type get_object_type() + { + return (enum_object_type) m_key.m_hash_key[0]; + } + + /** Internal lock. */ + pfs_lock m_lock; + /** Hash key. */ + PFS_setup_object_key m_key; + /** Schema name. Points inside m_key. */ + const char *m_schema_name; + /** Length of @c m_schema_name. */ + uint m_schema_name_length; + /** Object name. Points inside m_key. */ + const char *m_object_name; + /** Length of @c m_object_name. */ + uint m_object_name_length; + /** ENABLED flag. */ + bool m_enabled; + /** TIMED flag. */ + bool m_timed; +}; + +int init_setup_object(const PFS_global_param *param); +void cleanup_setup_object(void); +int init_setup_object_hash(void); +void cleanup_setup_object_hash(void); + +int insert_setup_object(enum_object_type object_type, const String *schema, + const String *object, bool enabled, bool timed); +int delete_setup_object(enum_object_type object_type, const String *schema, + const String *object); +int reset_setup_object(void); +long setup_object_count(void); + +void lookup_setup_object(PFS_thread *thread, + enum_object_type object_type, + const char *schema_name, int schema_name_length, + const char *object_name, int object_name_length, + bool *enabled, bool *timed); + +/* For iterators and show status. */ + +extern ulong setup_object_max; + +/* Exposing the data directly, for iterators. */ + +extern PFS_setup_object *setup_object_array; + +/** @} */ +#endif + diff --git a/storage/perfschema/pfs_stat.h b/storage/perfschema/pfs_stat.h index 5955a515d1a..32c462b8ba2 100644 --- a/storage/perfschema/pfs_stat.h +++ b/storage/perfschema/pfs_stat.h @@ -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 @@ -16,6 +16,10 @@ #ifndef PFS_STAT_H #define PFS_STAT_H +#include "sql_const.h" +/* memcpy */ +#include "string.h" + /** @file storage/perfschema/pfs_stat.h Statistics (declarations). @@ -26,16 +30,9 @@ @{ */ -/** Usage statistics chain, for a single value and its aggregates. */ -struct PFS_single_stat_chain +/** Single statistic. */ +struct PFS_single_stat { - /** - Control flag. - Statistics are aggregated only if the control flag is true. - */ - bool *m_control_flag; - /** Next link in the statistics chain. */ - struct PFS_single_stat_chain *m_parent; /** Count of values. */ ulonglong m_count; /** Sum of values. */ @@ -44,60 +41,104 @@ struct PFS_single_stat_chain ulonglong m_min; /** Maximum value. */ ulonglong m_max; + + PFS_single_stat() + { + m_count= 0; + m_sum= 0; + m_min= ULONGLONG_MAX; + m_max= 0; + } + + inline void reset(void) + { + m_count= 0; + m_sum= 0; + m_min= ULONGLONG_MAX; + m_max= 0; + } + + inline void aggregate(const PFS_single_stat *stat) + { + m_count+= stat->m_count; + m_sum+= stat->m_sum; + if (unlikely(m_min > stat->m_min)) + m_min= stat->m_min; + if (unlikely(m_max < stat->m_max)) + m_max= stat->m_max; + } + + inline void aggregate_counted() + { + m_count++; + } + + inline void aggregate_counted(ulonglong count) + { + m_count+= count; + } + + inline void aggregate_value(ulonglong value) + { + m_count++; + m_sum+= value; + if (unlikely(m_min > value)) + m_min= value; + if (unlikely(m_max < value)) + m_max= value; + } }; -/** - Reset a single statistic link. - Only the current link is reset, parents are not affected. - @param stat the statistics link to reset -*/ -inline void reset_single_stat_link(PFS_single_stat_chain *stat) +/** Combined statistic. */ +struct PFS_byte_stat : public PFS_single_stat { - stat->m_count= 0; - stat->m_sum= 0; - stat->m_min= ULONGLONG_MAX; - stat->m_max= 0; -} + /** Byte count statistics */ + ulonglong m_bytes; -/** - Aggregate a value to a statistic chain. - @param stat the aggregated statistic chain - @param value the value to aggregate -*/ -inline void aggregate_single_stat_chain(PFS_single_stat_chain *stat, - ulonglong value) -{ - do - { - if (*stat->m_control_flag) - { - stat->m_count++; - stat->m_sum+= value; - if (stat->m_min > value) - stat->m_min= value; - if (stat->m_max < value) - stat->m_max= value; - } - stat= stat->m_parent; - } - while (stat); -} + /* Aggregate wait stats, event count and byte count */ + inline void aggregate(const PFS_byte_stat *stat) + { + PFS_single_stat::aggregate(stat); + m_bytes+= stat->m_bytes; + } -/** - Increment the value counts in a statistic chain. - Used for instruments that are 'ENABLED' but not 'TIMED'. - @param stat the aggregated statistic chain -*/ -inline void increment_single_stat_chain(PFS_single_stat_chain *stat) -{ - do + /* Aggregate individual wait time, event count and byte count */ + inline void aggregate(ulonglong wait, ulonglong bytes) + { + aggregate_value(wait); + m_bytes+= bytes; + } + + /* Aggregate wait stats and event count */ + inline void aggregate_waits(const PFS_byte_stat *stat) + { + PFS_single_stat::aggregate(stat); + } + + /* Aggregate event count and byte count */ + inline void aggregate_counted() + { + PFS_single_stat::aggregate_counted(); + } + + /* Aggregate event count and byte count */ + inline void aggregate_counted(ulonglong bytes) + { + PFS_single_stat::aggregate_counted(); + m_bytes+= bytes; + } + + PFS_byte_stat() { - if (*stat->m_control_flag) - stat->m_count++; - stat= stat->m_parent; + reset(); } - while (stat); -} + + inline void reset(void) + { + PFS_single_stat::reset(); + m_bytes= 0; + } +}; /** Statistics for COND usage. */ struct PFS_cond_stat @@ -108,33 +149,440 @@ struct PFS_cond_stat ulonglong m_broadcast_count; }; +/** Statistics for FILE IO. Used for both waits and byte counts. */ +struct PFS_file_io_stat +{ + /** READ statistics */ + PFS_byte_stat m_read; + /** WRITE statistics */ + PFS_byte_stat m_write; + /** Miscelleanous statistics */ + PFS_byte_stat m_misc; + + inline void reset(void) + { + m_read.reset(); + m_write.reset(); + m_misc.reset(); + } + + inline void aggregate(const PFS_file_io_stat *stat) + { + m_read.aggregate(&stat->m_read); + m_write.aggregate(&stat->m_write); + m_misc.aggregate(&stat->m_misc); + } + + /* Sum waits and byte counts */ + inline void sum(PFS_byte_stat *stat) + { + stat->aggregate(&m_read); + stat->aggregate(&m_write); + stat->aggregate(&m_misc); + } + + /* Sum waits only */ + inline void sum_waits(PFS_single_stat *stat) + { + stat->aggregate(&m_read); + stat->aggregate(&m_write); + stat->aggregate(&m_misc); + } +}; + /** Statistics for FILE usage. */ struct PFS_file_stat { /** Number of current open handles. */ ulong m_open_count; - /** Count of READ operations. */ - ulonglong m_count_read; - /** Count of WRITE operations. */ - ulonglong m_count_write; - /** Number of bytes read. */ - ulonglong m_read_bytes; - /** Number of bytes written. */ - ulonglong m_write_bytes; + /** File IO statistics. */ + PFS_file_io_stat m_io_stat; + + /** Reset file statistics. */ + inline void reset(void) + { + m_io_stat.reset(); + } }; -/** - Reset file statistic. - @param stat the statistics to reset -*/ -inline void reset_file_stat(PFS_file_stat *stat) +/** Statistics for stage usage. */ +struct PFS_stage_stat +{ + PFS_single_stat m_timer1_stat; + + inline void reset(void) + { m_timer1_stat.reset(); } + + inline void aggregate_counted() + { m_timer1_stat.aggregate_counted(); } + + inline void aggregate_value(ulonglong value) + { m_timer1_stat.aggregate_value(value); } + + inline void aggregate(PFS_stage_stat *stat) + { m_timer1_stat.aggregate(& stat->m_timer1_stat); } +}; + +/** Statistics for statement usage. */ +struct PFS_statement_stat +{ + PFS_single_stat m_timer1_stat; + ulonglong m_error_count; + ulonglong m_warning_count; + ulonglong m_rows_affected; + ulonglong m_lock_time; + ulonglong m_rows_sent; + ulonglong m_rows_examined; + ulonglong m_created_tmp_disk_tables; + ulonglong m_created_tmp_tables; + ulonglong m_select_full_join; + ulonglong m_select_full_range_join; + ulonglong m_select_range; + ulonglong m_select_range_check; + ulonglong m_select_scan; + ulonglong m_sort_merge_passes; + ulonglong m_sort_range; + ulonglong m_sort_rows; + ulonglong m_sort_scan; + ulonglong m_no_index_used; + ulonglong m_no_good_index_used; + + PFS_statement_stat() + { + m_error_count= 0; + m_warning_count= 0; + m_rows_affected= 0; + m_lock_time= 0; + m_rows_sent= 0; + m_rows_examined= 0; + m_created_tmp_disk_tables= 0; + m_created_tmp_tables= 0; + m_select_full_join= 0; + m_select_full_range_join= 0; + m_select_range= 0; + m_select_range_check= 0; + m_select_scan= 0; + m_sort_merge_passes= 0; + m_sort_range= 0; + m_sort_rows= 0; + m_sort_scan= 0; + m_no_index_used= 0; + m_no_good_index_used= 0; + } + + inline void reset(void) + { + m_timer1_stat.reset(); + m_error_count= 0; + m_warning_count= 0; + m_rows_affected= 0; + m_lock_time= 0; + m_rows_sent= 0; + m_rows_examined= 0; + m_created_tmp_disk_tables= 0; + m_created_tmp_tables= 0; + m_select_full_join= 0; + m_select_full_range_join= 0; + m_select_range= 0; + m_select_range_check= 0; + m_select_scan= 0; + m_sort_merge_passes= 0; + m_sort_range= 0; + m_sort_rows= 0; + m_sort_scan= 0; + m_no_index_used= 0; + m_no_good_index_used= 0; + } + + inline void aggregate_counted() + { m_timer1_stat.aggregate_counted(); } + + inline void aggregate_value(ulonglong value) + { m_timer1_stat.aggregate_value(value); } + + inline void aggregate(PFS_statement_stat *stat) + { + m_timer1_stat.aggregate(& stat->m_timer1_stat); + + m_error_count+= stat->m_error_count; + m_warning_count+= stat->m_warning_count; + m_rows_affected+= stat->m_rows_affected; + m_lock_time+= stat->m_lock_time; + m_rows_sent+= stat->m_rows_sent; + m_rows_examined+= stat->m_rows_examined; + m_created_tmp_disk_tables+= stat->m_created_tmp_disk_tables; + m_created_tmp_tables+= stat->m_created_tmp_tables; + m_select_full_join+= stat->m_select_full_join; + m_select_full_range_join+= stat->m_select_full_range_join; + m_select_range+= stat->m_select_range; + m_select_range_check+= stat->m_select_range_check; + m_select_scan+= stat->m_select_scan; + m_sort_merge_passes+= stat->m_sort_merge_passes; + m_sort_range+= stat->m_sort_range; + m_sort_rows+= stat->m_sort_rows; + m_sort_scan+= stat->m_sort_scan; + m_no_index_used+= stat->m_no_index_used; + m_no_good_index_used+= stat->m_no_good_index_used; + } +}; + +/** Single table io statistic. */ +struct PFS_table_io_stat { - stat->m_open_count= 0; - stat->m_count_read= 0; - stat->m_count_write= 0; - stat->m_read_bytes= 0; - stat->m_write_bytes= 0; -} + /** FETCH statistics */ + PFS_single_stat m_fetch; + /** INSERT statistics */ + PFS_single_stat m_insert; + /** UPDATE statistics */ + PFS_single_stat m_update; + /** DELETE statistics */ + PFS_single_stat m_delete; + + inline void reset(void) + { + m_fetch.reset(); + m_insert.reset(); + m_update.reset(); + m_delete.reset(); + } + + inline void aggregate(const PFS_table_io_stat *stat) + { + m_fetch.aggregate(&stat->m_fetch); + m_insert.aggregate(&stat->m_insert); + m_update.aggregate(&stat->m_update); + m_delete.aggregate(&stat->m_delete); + } + + inline void sum(PFS_single_stat *result) + { + result->aggregate(& m_fetch); + result->aggregate(& m_insert); + result->aggregate(& m_update); + result->aggregate(& m_delete); + } +}; + +enum PFS_TL_LOCK_TYPE +{ + /* Locks from enum thr_lock */ + PFS_TL_READ= 0, + PFS_TL_READ_WITH_SHARED_LOCKS= 1, + PFS_TL_READ_HIGH_PRIORITY= 2, + PFS_TL_READ_NO_INSERT= 3, + PFS_TL_WRITE_ALLOW_WRITE= 4, + PFS_TL_WRITE_CONCURRENT_INSERT= 5, + PFS_TL_WRITE_DELAYED= 6, + PFS_TL_WRITE_LOW_PRIORITY= 7, + PFS_TL_WRITE= 8, + + /* Locks for handler::ha_external_lock() */ + PFS_TL_READ_EXTERNAL= 9, + PFS_TL_WRITE_EXTERNAL= 10 +}; + +#define COUNT_PFS_TL_LOCK_TYPE 11 + +/** Statistics for table locks. */ +struct PFS_table_lock_stat +{ + PFS_single_stat m_stat[COUNT_PFS_TL_LOCK_TYPE]; + + inline void reset(void) + { + PFS_single_stat *pfs= & m_stat[0]; + PFS_single_stat *pfs_last= & m_stat[COUNT_PFS_TL_LOCK_TYPE]; + for ( ; pfs < pfs_last ; pfs++) + pfs->reset(); + } + + inline void aggregate(const PFS_table_lock_stat *stat) + { + PFS_single_stat *pfs= & m_stat[0]; + PFS_single_stat *pfs_last= & m_stat[COUNT_PFS_TL_LOCK_TYPE]; + const PFS_single_stat *pfs_from= & stat->m_stat[0]; + for ( ; pfs < pfs_last ; pfs++, pfs_from++) + pfs->aggregate(pfs_from); + } + + inline void sum(PFS_single_stat *result) + { + PFS_single_stat *pfs= & m_stat[0]; + PFS_single_stat *pfs_last= & m_stat[COUNT_PFS_TL_LOCK_TYPE]; + for ( ; pfs < pfs_last ; pfs++) + result->aggregate(pfs); + } +}; + +/** Statistics for TABLE usage. */ +struct PFS_table_stat +{ + /** + Statistics, per index. + Each index stat is in [0, MAX_KEY-1], + stats when using no index are in [MAX_KEY]. + */ + PFS_table_io_stat m_index_stat[MAX_KEY + 1]; + + /** + Statistics, per lock type. + */ + PFS_table_lock_stat m_lock_stat; + + /** Reset table io statistic. */ + inline void reset_io(void) + { + PFS_table_io_stat *stat= & m_index_stat[0]; + PFS_table_io_stat *stat_last= & m_index_stat[MAX_KEY + 1]; + for ( ; stat < stat_last ; stat++) + stat->reset(); + } + + /** Reset table lock statistic. */ + inline void reset_lock(void) + { + m_lock_stat.reset(); + } + + /** Reset table statistic. */ + inline void reset(void) + { + reset_io(); + reset_lock(); + } + + inline void fast_reset_io(void) + { + memcpy(& m_index_stat, & g_reset_template.m_index_stat, sizeof(m_index_stat)); + } + + inline void fast_reset_lock(void) + { + memcpy(& m_lock_stat, & g_reset_template.m_lock_stat, sizeof(m_lock_stat)); + } + + inline void fast_reset(void) + { + memcpy(this, & g_reset_template, sizeof(*this)); + } + + inline void aggregate_io(const PFS_table_stat *stat) + { + PFS_table_io_stat *to_stat= & m_index_stat[0]; + PFS_table_io_stat *to_stat_last= & m_index_stat[MAX_KEY + 1]; + const PFS_table_io_stat *from_stat= & stat->m_index_stat[0]; + for ( ; to_stat < to_stat_last ; from_stat++, to_stat++) + to_stat->aggregate(from_stat); + } + + inline void aggregate_lock(const PFS_table_stat *stat) + { + m_lock_stat.aggregate(& stat->m_lock_stat); + } + + inline void aggregate(const PFS_table_stat *stat) + { + aggregate_io(stat); + aggregate_lock(stat); + } + + inline void sum_io(PFS_single_stat *result) + { + PFS_table_io_stat *stat= & m_index_stat[0]; + PFS_table_io_stat *stat_last= & m_index_stat[MAX_KEY + 1]; + for ( ; stat < stat_last ; stat++) + stat->sum(result); + } + + inline void sum_lock(PFS_single_stat *result) + { + m_lock_stat.sum(result); + } + + inline void sum(PFS_single_stat *result) + { + sum_io(result); + sum_lock(result); + } + + static struct PFS_table_stat g_reset_template; +}; + +/** Statistics for SOCKET IO. Used for both waits and byte counts. */ +struct PFS_socket_io_stat +{ + /** READ statistics */ + PFS_byte_stat m_read; + /** WRITE statistics */ + PFS_byte_stat m_write; + /** Miscelleanous statistics */ + PFS_byte_stat m_misc; + + inline void reset(void) + { + m_read.reset(); + m_write.reset(); + m_misc.reset(); + } + + inline void aggregate(const PFS_socket_io_stat *stat) + { + m_read.aggregate(&stat->m_read); + m_write.aggregate(&stat->m_write); + m_misc.aggregate(&stat->m_misc); + } + + /* Sum waits and byte counts */ + inline void sum(PFS_byte_stat *stat) + { + stat->aggregate(&m_read); + stat->aggregate(&m_write); + stat->aggregate(&m_misc); + } + + /* Sum waits only */ + inline void sum_waits(PFS_single_stat *stat) + { + stat->aggregate(&m_read); + stat->aggregate(&m_write); + stat->aggregate(&m_misc); + } +}; + +/** Statistics for SOCKET usage. */ +struct PFS_socket_stat +{ + /** Socket timing and byte count statistics per operation */ + PFS_socket_io_stat m_io_stat; + + /** Reset socket statistics. */ + inline void reset(void) + { + m_io_stat.reset(); + } +}; + +struct PFS_connection_stat +{ + PFS_connection_stat() + : m_current_connections(0), + m_total_connections(0) + {} + + ulonglong m_current_connections; + ulonglong m_total_connections; + + inline void aggregate_active(ulonglong active) + { + m_current_connections+= active; + m_total_connections+= active; + } + + inline void aggregate_disconnected(ulonglong disconnected) + { + m_total_connections+= disconnected; + } +}; /** @} */ #endif diff --git a/storage/perfschema/pfs_timer.cc b/storage/perfschema/pfs_timer.cc index 302548c97c2..3d8d2e07ce5 100644 --- a/storage/perfschema/pfs_timer.cc +++ b/storage/perfschema/pfs_timer.cc @@ -1,5 +1,4 @@ -/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc. - Use is subject to license terms. +/* 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 @@ -23,7 +22,10 @@ #include "pfs_timer.h" #include "my_rdtsc.h" +enum_timer_name idle_timer= TIMER_NAME_MICROSEC; enum_timer_name wait_timer= TIMER_NAME_CYCLE; +enum_timer_name stage_timer= TIMER_NAME_NANOSEC; +enum_timer_name statement_timer= TIMER_NAME_NANOSEC; MY_TIMER_INFO pfs_timer_info; static ulonglong cycle_v0; @@ -38,6 +40,17 @@ static ulong microsec_to_pico; /* In theory, 1 000 000 */ static ulong millisec_to_pico; /* In theory, 1 000 000 000, fits in uint32 */ static ulonglong tick_to_pico; /* 1e10 at 100 Hz, 1.666e10 at 60 Hz */ +/* Indexed by enum enum_timer_name */ +static struct time_normalizer to_pico_data[FIRST_TIMER_NAME + COUNT_TIMER_NAME]= +{ + { 0, 0}, /* unused */ + { 0, 0}, /* cycle */ + { 0, 0}, /* nanosec */ + { 0, 0}, /* microsec */ + { 0, 0}, /* millisec */ + { 0, 0} /* tick */ +}; + static inline ulong round_to_ulong(double value) { return (ulong) (value + 0.5); @@ -89,13 +102,75 @@ void init_timers(void) (double)pfs_timer_info.ticks.frequency); else tick_to_pico= 0; + + to_pico_data[TIMER_NAME_CYCLE].m_v0= cycle_v0; + to_pico_data[TIMER_NAME_CYCLE].m_factor= cycle_to_pico; + + to_pico_data[TIMER_NAME_NANOSEC].m_v0= nanosec_v0; + to_pico_data[TIMER_NAME_NANOSEC].m_factor= nanosec_to_pico; + + to_pico_data[TIMER_NAME_MICROSEC].m_v0= microsec_v0; + to_pico_data[TIMER_NAME_MICROSEC].m_factor= microsec_to_pico; + + to_pico_data[TIMER_NAME_MILLISEC].m_v0= millisec_v0; + to_pico_data[TIMER_NAME_MILLISEC].m_factor= millisec_to_pico; + + to_pico_data[TIMER_NAME_TICK].m_v0= tick_v0; + to_pico_data[TIMER_NAME_TICK].m_factor= tick_to_pico; +} + +ulonglong get_timer_raw_value(enum_timer_name timer_name) +{ + switch (timer_name) + { + case TIMER_NAME_CYCLE: + return my_timer_cycles(); + case TIMER_NAME_NANOSEC: + return my_timer_nanoseconds(); + case TIMER_NAME_MICROSEC: + return my_timer_microseconds(); + case TIMER_NAME_MILLISEC: + return my_timer_milliseconds(); + case TIMER_NAME_TICK: + return my_timer_ticks(); + default: + DBUG_ASSERT(false); + } + return 0; +} + +ulonglong get_timer_raw_value_and_function(enum_timer_name timer_name, timer_fct_t *fct) +{ + switch (timer_name) + { + case TIMER_NAME_CYCLE: + *fct= my_timer_cycles; + return my_timer_cycles(); + case TIMER_NAME_NANOSEC: + *fct= my_timer_nanoseconds; + return my_timer_nanoseconds(); + case TIMER_NAME_MICROSEC: + *fct= my_timer_microseconds; + return my_timer_microseconds(); + case TIMER_NAME_MILLISEC: + *fct= my_timer_milliseconds; + return my_timer_milliseconds(); + case TIMER_NAME_TICK: + *fct= my_timer_ticks; + return my_timer_ticks(); + default: + *fct= NULL; + DBUG_ASSERT(false); + } + return 0; } -ulonglong get_timer_value(enum_timer_name timer_name) +ulonglong get_timer_pico_value(enum_timer_name timer_name) { ulonglong result; - switch (timer_name) { + switch (timer_name) + { case TIMER_NAME_CYCLE: result= (my_timer_cycles() - cycle_v0) * cycle_to_pico; break; @@ -118,3 +193,38 @@ ulonglong get_timer_value(enum_timer_name timer_name) return result; } +time_normalizer* time_normalizer::get(enum_timer_name timer_name) +{ + uint index= static_cast<uint> (timer_name); + + DBUG_ASSERT(index >= FIRST_TIMER_NAME); + DBUG_ASSERT(index <= LAST_TIMER_NAME); + + return & to_pico_data[index]; +} + +void time_normalizer::to_pico(ulonglong start, ulonglong end, + ulonglong *pico_start, ulonglong *pico_end, ulonglong *pico_wait) +{ + if (start == 0) + { + *pico_start= 0; + *pico_end= 0; + *pico_wait= 0; + } + else + { + *pico_start= (start - m_v0) * m_factor; + if (end == 0) + { + *pico_end= 0; + *pico_wait= 0; + } + else + { + *pico_end= (end - m_v0) * m_factor; + *pico_wait= (end - start) * m_factor; + } + } +} + diff --git a/storage/perfschema/pfs_timer.h b/storage/perfschema/pfs_timer.h index 6736a977ab9..1cae20e89dd 100644 --- a/storage/perfschema/pfs_timer.h +++ b/storage/perfschema/pfs_timer.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc. - Use is subject to license terms. +/* 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 @@ -24,12 +23,118 @@ #include <my_rdtsc.h> #include "pfs_column_types.h" +/** Conversion factor, from micro seconds to pico seconds. */ +#define MICROSEC_TO_PICOSEC 1000000 + +/** + A time normalizer. + A time normalizer consist of a transformation that + converts raw timer values (expressed in the timer unit) + to normalized values, expressed in picoseconds. +*/ +struct time_normalizer +{ + /** + Get a time normalizer for a given timer. + @param timer_name the timer name + @return the normalizer for the timer + */ + static time_normalizer* get(enum_timer_name timer_name); + + /** Timer value at server statup. */ + ulonglong m_v0; + /** Conversion factor from timer values to pico seconds. */ + ulonglong m_factor; + + /** + Convert a wait from timer units to pico seconds. + @param wait a wait, expressed in timer units + @return the wait, expressed in pico seconds + */ + inline ulonglong wait_to_pico(ulonglong wait) + { + return wait * m_factor; + } + + /** + Convert a time from timer units to pico seconds. + @param t a time, expressed in timer units + @return the time, expressed in pico seconds + */ + inline ulonglong time_to_pico(ulonglong t) + { + return (t == 0 ? 0 : (t - m_v0) * m_factor); + } + + /** + Convert start / end times from timer units to pico seconds. + @param start start time, expressed in timer units + @param end end time, expressed in timer units + @param[out] pico_start start time, expressed in pico seconds + @param[out] pico_end end time, expressed in pico seconds + @param[out] pico_wait wait time, expressed in pico seconds + */ + void to_pico(ulonglong start, ulonglong end, + ulonglong *pico_start, ulonglong *pico_end, ulonglong *pico_wait); +}; + +/** + Idle timer. + The timer used to measure all idle events. +*/ +extern enum_timer_name idle_timer; +/** + Wait timer. + The timer used to measure all wait events. +*/ extern enum_timer_name wait_timer; +/** + Stage timer. + The timer used to measure all stage events. +*/ +extern enum_timer_name stage_timer; +/** + Statement timer. + The timer used to measure all statement events. +*/ +extern enum_timer_name statement_timer; +/** + Timer information data. + Characteristics about each suported timer. +*/ extern MY_TIMER_INFO pfs_timer_info; +/** Initialize the timer component. */ void init_timers(); -ulonglong get_timer_value(enum_timer_name timer_name); +extern "C" +{ + /** A timer function. */ + typedef ulonglong (*timer_fct_t)(void); +} + +/** + Get a timer value, in pico seconds. + @param timer_name the timer to use + @return timer value, in pico seconds +*/ +ulonglong get_timer_pico_value(enum_timer_name timer_name); +/** + Get a timer value, in timer units. + @param timer_name the timer to use + @return timer value, in timer units +*/ +ulonglong get_timer_raw_value(enum_timer_name timer_name); +/** + Get a timer value and function, in timer units. + This function is useful when code needs to call the same timer several times. + The returned timer function can be invoked directly, which avoids having to + resolve the timer by name for each call. + @param timer_name the timer to use + @param[out] fct the timer function + @return timer value, in timer units +*/ +ulonglong get_timer_raw_value_and_function(enum_timer_name timer_name, timer_fct_t *fct); #endif diff --git a/storage/perfschema/pfs_user.cc b/storage/perfschema/pfs_user.cc new file mode 100644 index 00000000000..d7794a131a1 --- /dev/null +++ b/storage/perfschema/pfs_user.cc @@ -0,0 +1,381 @@ +/* Copyright (c) 2010, 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 + 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_user.cc + Performance schema user (implementation). +*/ + +#include "my_global.h" +#include "my_sys.h" +#include "pfs.h" +#include "pfs_stat.h" +#include "pfs_instr.h" +#include "pfs_setup_actor.h" +#include "pfs_user.h" +#include "pfs_global.h" +#include "pfs_instr_class.h" + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +ulong user_max; +ulong user_lost; + +PFS_user *user_array= NULL; + +static PFS_single_stat *user_instr_class_waits_array= NULL; +static PFS_stage_stat *user_instr_class_stages_array= NULL; +static PFS_statement_stat *user_instr_class_statements_array= NULL; + +static LF_HASH user_hash; +static bool user_hash_inited= false; + +/** + Initialize the user buffers. + @param param sizing parameters + @return 0 on success +*/ +int init_user(const PFS_global_param *param) +{ + uint index; + + user_max= param->m_user_sizing; + + user_array= NULL; + user_instr_class_waits_array= NULL; + user_instr_class_stages_array= NULL; + user_instr_class_statements_array= NULL; + uint waits_sizing= user_max * wait_class_max; + uint stages_sizing= user_max * stage_class_max; + uint statements_sizing= user_max * statement_class_max; + + if (user_max > 0) + { + user_array= PFS_MALLOC_ARRAY(user_max, PFS_user, + MYF(MY_ZEROFILL)); + if (unlikely(user_array == NULL)) + return 1; + } + + if (waits_sizing > 0) + { + user_instr_class_waits_array= + PFS_connection_slice::alloc_waits_slice(waits_sizing); + if (unlikely(user_instr_class_waits_array == NULL)) + return 1; + } + + if (stages_sizing > 0) + { + user_instr_class_stages_array= + PFS_connection_slice::alloc_stages_slice(stages_sizing); + if (unlikely(user_instr_class_stages_array == NULL)) + return 1; + } + + if (statements_sizing > 0) + { + user_instr_class_statements_array= + PFS_connection_slice::alloc_statements_slice(statements_sizing); + if (unlikely(user_instr_class_statements_array == NULL)) + return 1; + } + + for (index= 0; index < user_max; index++) + { + user_array[index].m_instr_class_waits_stats= + &user_instr_class_waits_array[index * wait_class_max]; + user_array[index].m_instr_class_stages_stats= + &user_instr_class_stages_array[index * stage_class_max]; + user_array[index].m_instr_class_statements_stats= + &user_instr_class_statements_array[index * statement_class_max]; + } + + return 0; +} + +/** Cleanup all the user buffers. */ +void cleanup_user(void) +{ + pfs_free(user_array); + user_array= NULL; + pfs_free(user_instr_class_waits_array); + user_instr_class_waits_array= NULL; + pfs_free(user_instr_class_stages_array); + user_instr_class_stages_array= NULL; + pfs_free(user_instr_class_statements_array); + user_instr_class_statements_array= NULL; + user_max= 0; +} + +C_MODE_START +static uchar *user_hash_get_key(const uchar *entry, size_t *length, + my_bool) +{ + const PFS_user * const *typed_entry; + const PFS_user *user; + const void *result; + typed_entry= reinterpret_cast<const PFS_user* const *> (entry); + DBUG_ASSERT(typed_entry != NULL); + user= *typed_entry; + DBUG_ASSERT(user != NULL); + *length= user->m_key.m_key_length; + result= user->m_key.m_hash_key; + return const_cast<uchar*> (reinterpret_cast<const uchar*> (result)); +} +C_MODE_END + +/** + Initialize the user hash. + @return 0 on success +*/ +int init_user_hash(void) +{ + if (! user_hash_inited) + { + lf_hash_init(&user_hash, sizeof(PFS_user*), LF_HASH_UNIQUE, + 0, 0, user_hash_get_key, &my_charset_bin); + user_hash_inited= true; + } + return 0; +} + +/** Cleanup the user hash. */ +void cleanup_user_hash(void) +{ + if (user_hash_inited) + { + lf_hash_destroy(&user_hash); + user_hash_inited= false; + } +} + +static LF_PINS* get_user_hash_pins(PFS_thread *thread) +{ + if (unlikely(thread->m_user_hash_pins == NULL)) + { + if (! user_hash_inited) + return NULL; + thread->m_user_hash_pins= lf_hash_get_pins(&user_hash); + } + return thread->m_user_hash_pins; +} + +static void set_user_key(PFS_user_key *key, + const char *user, uint user_length) +{ + DBUG_ASSERT(user_length <= USERNAME_LENGTH); + + char *ptr= &key->m_hash_key[0]; + if (user_length > 0) + { + memcpy(ptr, user, user_length); + ptr+= user_length; + } + ptr[0]= 0; + ptr++; + key->m_key_length= ptr - &key->m_hash_key[0]; +} + +PFS_user * +find_or_create_user(PFS_thread *thread, + const char *username, uint username_length) +{ + if (user_max == 0) + { + user_lost++; + return NULL; + } + + LF_PINS *pins= get_user_hash_pins(thread); + if (unlikely(pins == NULL)) + { + user_lost++; + return NULL; + } + + PFS_user_key key; + set_user_key(&key, username, username_length); + + PFS_user **entry; + uint retry_count= 0; + const uint retry_max= 3; + +search: + entry= reinterpret_cast<PFS_user**> + (lf_hash_search(&user_hash, pins, + key.m_hash_key, key.m_key_length)); + if (entry && (entry != MY_ERRPTR)) + { + PFS_user *pfs; + pfs= *entry; + pfs->inc_refcount(); + lf_hash_search_unpin(pins); + return pfs; + } + + lf_hash_search_unpin(pins); + + PFS_scan scan; + uint random= randomized_index(username, user_max); + + for (scan.init(random, user_max); + scan.has_pass(); + scan.next_pass()) + { + PFS_user *pfs= user_array + scan.first(); + PFS_user *pfs_last= user_array + scan.last(); + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_free()) + { + if (pfs->m_lock.free_to_dirty()) + { + pfs->m_key= key; + if (username_length > 0) + pfs->m_username= &pfs->m_key.m_hash_key[0]; + else + pfs->m_username= NULL; + pfs->m_username_length= username_length; + + pfs->init_refcount(); + pfs->reset_stats(); + pfs->m_disconnected_count= 0; + + int res; + res= lf_hash_insert(&user_hash, pins, &pfs); + if (likely(res == 0)) + { + pfs->m_lock.dirty_to_allocated(); + return pfs; + } + + pfs->m_lock.dirty_to_free(); + + if (res > 0) + { + if (++retry_count > retry_max) + { + user_lost++; + return NULL; + } + goto search; + } + + user_lost++; + return NULL; + } + } + } + } + + user_lost++; + return NULL; +} + +void PFS_user::aggregate() +{ + aggregate_waits(); + aggregate_stages(); + aggregate_statements(); + aggregate_stats(); +} + +void PFS_user::aggregate_waits() +{ + /* No parent to aggregate to, clean the stats */ + reset_waits_stats(); +} + +void PFS_user::aggregate_stages() +{ + /* No parent to aggregate to, clean the stats */ + reset_stages_stats(); +} + +void PFS_user::aggregate_statements() +{ + /* No parent to aggregate to, clean the stats */ + reset_statements_stats(); +} + +void PFS_user::aggregate_stats() +{ + /* No parent to aggregate to, clean the stats */ + m_disconnected_count= 0; +} + +void PFS_user::release() +{ + dec_refcount(); +} + +PFS_user *sanitize_user(PFS_user *unsafe) +{ + if ((&user_array[0] <= unsafe) && + (unsafe < &user_array[user_max])) + return unsafe; + return NULL; +} + +void purge_user(PFS_thread *thread, PFS_user *user) +{ + LF_PINS *pins= get_user_hash_pins(thread); + if (unlikely(pins == NULL)) + return; + + PFS_user **entry; + entry= reinterpret_cast<PFS_user**> + (lf_hash_search(&user_hash, pins, + user->m_key.m_hash_key, user->m_key.m_key_length)); + if (entry && (entry != MY_ERRPTR)) + { + DBUG_ASSERT(*entry == user); + if (user->get_refcount() == 0) + { + lf_hash_delete(&user_hash, pins, + user->m_key.m_hash_key, user->m_key.m_key_length); + user->m_lock.allocated_to_free(); + } + } + + lf_hash_search_unpin(pins); +} + +/** Purge non connected users, reset stats of connected users. */ +void purge_all_user(void) +{ + PFS_thread *thread= PFS_thread::get_current_thread(); + if (unlikely(thread == NULL)) + return; + + PFS_user *pfs= user_array; + PFS_user *pfs_last= user_array + user_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + { + pfs->aggregate(); + if (pfs->get_refcount() == 0) + purge_user(thread, pfs); + } + } +} + +/** @} */ diff --git a/storage/perfschema/pfs_user.h b/storage/perfschema/pfs_user.h new file mode 100644 index 00000000000..0f937c6c927 --- /dev/null +++ b/storage/perfschema/pfs_user.h @@ -0,0 +1,113 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef PFS_USER_H +#define PFS_USER_H + +/** + @file storage/perfschema/pfs_user.h + Performance schema user (declarations). +*/ + +#include "pfs_lock.h" +#include "lf.h" +#include "pfs_con_slice.h" + +struct PFS_global_param; +struct PFS_thread; + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +struct PFS_user_key +{ + /** + Hash search key. + This has to be a string for LF_HASH, + the format is "<username><0x00>" + */ + char m_hash_key[USERNAME_LENGTH + 1]; + uint m_key_length; +}; + +struct PFS_user : public PFS_connection_slice +{ +public: + inline void init_refcount(void) + { + PFS_atomic::store_32(& m_refcount, 1); + } + + inline int get_refcount(void) + { + return PFS_atomic::load_32(& m_refcount); + } + + inline void inc_refcount(void) + { + PFS_atomic::add_32(& m_refcount, 1); + } + + inline void dec_refcount(void) + { + PFS_atomic::add_32(& m_refcount, -1); + } + + void aggregate(void); + void aggregate_waits(void); + void aggregate_stages(void); + void aggregate_statements(void); + void aggregate_stats(void); + void release(void); + + /** Internal lock. */ + pfs_lock m_lock; + PFS_user_key m_key; + const char *m_username; + uint m_username_length; + + ulonglong m_disconnected_count; + +private: + int m_refcount; +}; + +int init_user(const PFS_global_param *param); +void cleanup_user(void); +int init_user_hash(void); +void cleanup_user_hash(void); + +PFS_user * +find_or_create_user(PFS_thread *thread, + const char *username, uint username_length); + +PFS_user *sanitize_user(PFS_user *unsafe); +void purge_all_user(void); + + +/* For iterators and show status. */ + +extern ulong user_max; +extern ulong user_lost; + +/* Exposing the data directly, for iterators. */ + +extern PFS_user *user_array; + +/** @} */ +#endif + diff --git a/storage/perfschema/pfs_visitor.cc b/storage/perfschema/pfs_visitor.cc new file mode 100644 index 00000000000..fe2b16a2f76 --- /dev/null +++ b/storage/perfschema/pfs_visitor.cc @@ -0,0 +1,1161 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include "my_global.h" +#include "my_sys.h" +#include "pfs_visitor.h" +#include "pfs_instr.h" +#include "pfs_instr_class.h" +#include "pfs_user.h" +#include "pfs_host.h" +#include "pfs_account.h" + +/** + @file storage/perfschema/pfs_visitor.cc + Visitors (implementation). +*/ + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +/** Connection iterator */ +void PFS_connection_iterator::visit_global(bool with_hosts, bool with_users, + bool with_accounts, bool with_threads, + PFS_connection_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_global(); + + if (with_hosts) + { + PFS_host *pfs= host_array; + PFS_host *pfs_last= pfs + host_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + visitor->visit_host(pfs); + } + } + + if (with_users) + { + PFS_user *pfs= user_array; + PFS_user *pfs_last= pfs + user_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + visitor->visit_user(pfs); + } + } + + if (with_accounts) + { + PFS_account *pfs= account_array; + PFS_account *pfs_last= pfs + account_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + visitor->visit_account(pfs); + } + } + + if (with_threads) + { + PFS_thread *pfs= thread_array; + PFS_thread *pfs_last= pfs + thread_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + visitor->visit_thread(pfs); + } + } +} + +void PFS_connection_iterator::visit_host(PFS_host *host, + bool with_accounts, bool with_threads, + PFS_connection_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_host(host); + + if (with_accounts) + { + PFS_account *pfs= account_array; + PFS_account *pfs_last= pfs + account_max; + for ( ; pfs < pfs_last; pfs++) + { + if ((pfs->m_host == host) && pfs->m_lock.is_populated()) + { + visitor->visit_account(pfs); + } + } + } + + if (with_threads) + { + PFS_thread *pfs= thread_array; + PFS_thread *pfs_last= pfs + thread_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + { + PFS_account *safe_account= sanitize_account(pfs->m_account); + if ((safe_account != NULL) && (safe_account->m_host == host)) + { + /* + If the thread belongs to a known user@host that belongs to this host, + process it. + */ + visitor->visit_thread(pfs); + } + else if (pfs->m_host == host) + { + /* + If the thread belongs to a 'lost' user@host that belong to this host, + process it. + */ + visitor->visit_thread(pfs); + } + } + } + } +} + +void PFS_connection_iterator::visit_user(PFS_user *user, + bool with_accounts, bool with_threads, + PFS_connection_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_user(user); + + if (with_accounts) + { + PFS_account *pfs= account_array; + PFS_account *pfs_last= pfs + account_max; + for ( ; pfs < pfs_last; pfs++) + { + if ((pfs->m_user == user) && pfs->m_lock.is_populated()) + { + visitor->visit_account(pfs); + } + } + } + + if (with_threads) + { + PFS_thread *pfs= thread_array; + PFS_thread *pfs_last= pfs + thread_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + { + PFS_account *safe_account= sanitize_account(pfs->m_account); + if ((safe_account != NULL) && (safe_account->m_user == user)) + { + /* + If the thread belongs to a known user@host that belongs to this user, + process it. + */ + visitor->visit_thread(pfs); + } + else if (pfs->m_user == user) + { + /* + If the thread belongs to a 'lost' user@host that belong to this user, + process it. + */ + visitor->visit_thread(pfs); + } + } + } + } +} + +void PFS_connection_iterator::visit_account(PFS_account *account, + bool with_threads, + PFS_connection_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_account(account); + + if (with_threads) + { + PFS_thread *pfs= thread_array; + PFS_thread *pfs_last= pfs + thread_max; + for ( ; pfs < pfs_last; pfs++) + { + if ((pfs->m_account == account) && pfs->m_lock.is_populated()) + { + visitor->visit_thread(pfs); + } + } + } +} + +void PFS_instance_iterator::visit_all(PFS_instance_visitor *visitor) +{ + visit_all_mutex(visitor); + visit_all_rwlock(visitor); + visit_all_cond(visitor); + visit_all_file(visitor); +} + +void PFS_instance_iterator::visit_all_mutex(PFS_instance_visitor *visitor) +{ + visit_all_mutex_classes(visitor); + visit_all_mutex_instances(visitor); +} + +void PFS_instance_iterator::visit_all_mutex_classes(PFS_instance_visitor *visitor) +{ + PFS_mutex_class *pfs= mutex_class_array; + PFS_mutex_class *pfs_last= pfs + mutex_class_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_name_length != 0) + { + visitor->visit_mutex_class(pfs); + } + } +} + +void PFS_instance_iterator::visit_all_mutex_instances(PFS_instance_visitor *visitor) +{ + PFS_mutex *pfs= mutex_array; + PFS_mutex *pfs_last= pfs + mutex_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + { + visitor->visit_mutex(pfs); + } + } +} + +void PFS_instance_iterator::visit_all_rwlock(PFS_instance_visitor *visitor) +{ + visit_all_rwlock_classes(visitor); + visit_all_rwlock_instances(visitor); +} + +void PFS_instance_iterator::visit_all_rwlock_classes(PFS_instance_visitor *visitor) +{ + PFS_rwlock_class *pfs= rwlock_class_array; + PFS_rwlock_class *pfs_last= pfs + rwlock_class_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_name_length != 0) + { + visitor->visit_rwlock_class(pfs); + } + } +} + +void PFS_instance_iterator::visit_all_rwlock_instances(PFS_instance_visitor *visitor) +{ + PFS_rwlock *pfs= rwlock_array; + PFS_rwlock *pfs_last= pfs + rwlock_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + { + visitor->visit_rwlock(pfs); + } + } +} + +void PFS_instance_iterator::visit_all_cond(PFS_instance_visitor *visitor) +{ + visit_all_cond_classes(visitor); + visit_all_cond_instances(visitor); +} + +void PFS_instance_iterator::visit_all_cond_classes(PFS_instance_visitor *visitor) +{ + PFS_cond_class *pfs= cond_class_array; + PFS_cond_class *pfs_last= pfs + cond_class_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_name_length != 0) + { + visitor->visit_cond_class(pfs); + } + } +} + +void PFS_instance_iterator::visit_all_cond_instances(PFS_instance_visitor *visitor) +{ + PFS_cond *pfs= cond_array; + PFS_cond *pfs_last= pfs + cond_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + { + visitor->visit_cond(pfs); + } + } +} + +void PFS_instance_iterator::visit_all_file(PFS_instance_visitor *visitor) +{ + visit_all_file_classes(visitor); + visit_all_file_instances(visitor); +} + +void PFS_instance_iterator::visit_all_file_classes(PFS_instance_visitor *visitor) +{ + PFS_file_class *pfs= file_class_array; + PFS_file_class *pfs_last= pfs + file_class_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_name_length != 0) + { + visitor->visit_file_class(pfs); + } + } +} + +void PFS_instance_iterator::visit_all_file_instances(PFS_instance_visitor *visitor) +{ + PFS_file *pfs= file_array; + PFS_file *pfs_last= pfs + file_max; + for ( ; pfs < pfs_last; pfs++) + { + if (pfs->m_lock.is_populated()) + { + visitor->visit_file(pfs); + } + } +} + +/** Instance iterator */ + +void PFS_instance_iterator::visit_mutex_instances(PFS_mutex_class *klass, + PFS_instance_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_mutex_class(klass); + + if (klass->is_singleton()) + { + PFS_mutex *pfs= sanitize_mutex(klass->m_singleton); + if (likely(pfs != NULL)) + { + if (likely(pfs->m_lock.is_populated())) + { + visitor->visit_mutex(pfs); + } + } + } + else + { + PFS_mutex *pfs= mutex_array; + PFS_mutex *pfs_last= pfs + mutex_max; + for ( ; pfs < pfs_last; pfs++) + { + if ((pfs->m_class == klass) && pfs->m_lock.is_populated()) + { + visitor->visit_mutex(pfs); + } + } + } +} + +void PFS_instance_iterator::visit_rwlock_instances(PFS_rwlock_class *klass, + PFS_instance_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_rwlock_class(klass); + + if (klass->is_singleton()) + { + PFS_rwlock *pfs= sanitize_rwlock(klass->m_singleton); + if (likely(pfs != NULL)) + { + if (likely(pfs->m_lock.is_populated())) + { + visitor->visit_rwlock(pfs); + } + } + } + else + { + PFS_rwlock *pfs= rwlock_array; + PFS_rwlock *pfs_last= pfs + rwlock_max; + for ( ; pfs < pfs_last; pfs++) + { + if ((pfs->m_class == klass) && pfs->m_lock.is_populated()) + { + visitor->visit_rwlock(pfs); + } + } + } +} + +void PFS_instance_iterator::visit_cond_instances(PFS_cond_class *klass, + PFS_instance_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_cond_class(klass); + + if (klass->is_singleton()) + { + PFS_cond *pfs= sanitize_cond(klass->m_singleton); + if (likely(pfs != NULL)) + { + if (likely(pfs->m_lock.is_populated())) + { + visitor->visit_cond(pfs); + } + } + } + else + { + PFS_cond *pfs= cond_array; + PFS_cond *pfs_last= pfs + cond_max; + for ( ; pfs < pfs_last; pfs++) + { + if ((pfs->m_class == klass) && pfs->m_lock.is_populated()) + { + visitor->visit_cond(pfs); + } + } + } +} + +void PFS_instance_iterator::visit_file_instances(PFS_file_class *klass, + PFS_instance_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_file_class(klass); + + if (klass->is_singleton()) + { + PFS_file *pfs= sanitize_file(klass->m_singleton); + if (likely(pfs != NULL)) + { + if (likely(pfs->m_lock.is_populated())) + { + visitor->visit_file(pfs); + } + } + } + else + { + PFS_file *pfs= file_array; + PFS_file *pfs_last= pfs + file_max; + for ( ; pfs < pfs_last; pfs++) + { + if ((pfs->m_class == klass) && pfs->m_lock.is_populated()) + { + visitor->visit_file(pfs); + } + } + } +} + +/** Socket instance iterator visting a socket class and all instances */ + +void PFS_instance_iterator::visit_socket_instances(PFS_socket_class *klass, + PFS_instance_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_socket_class(klass); + + if (klass->is_singleton()) + { + PFS_socket *pfs= sanitize_socket(klass->m_singleton); + if (likely(pfs != NULL)) + { + if (likely(pfs->m_lock.is_populated())) + { + visitor->visit_socket(pfs); + } + } + } + else + { + PFS_socket *pfs= socket_array; + PFS_socket *pfs_last= pfs + socket_max; + for ( ; pfs < pfs_last; pfs++) + { + if ((pfs->m_class == klass) && pfs->m_lock.is_populated()) + { + visitor->visit_socket(pfs); + } + } + } +} + +/** Socket instance iterator visting sockets owned by PFS_thread. */ + +void PFS_instance_iterator::visit_socket_instances(PFS_socket_class *klass, + PFS_instance_visitor *visitor, + PFS_thread *thread, + bool visit_class) +{ + DBUG_ASSERT(visitor != NULL); + DBUG_ASSERT(thread != NULL); + + if (visit_class) + visitor->visit_socket_class(klass); + + if (klass->is_singleton()) + { + PFS_socket *pfs= sanitize_socket(klass->m_singleton); + if (likely(pfs != NULL)) + { + if (unlikely(pfs->m_thread_owner == thread)) + visitor->visit_socket(pfs); + } + } + else + { + /* Get current socket stats from each socket instance owned by this thread */ + PFS_socket *pfs= socket_array; + PFS_socket *pfs_last= pfs + socket_max; + + for ( ; pfs < pfs_last; pfs++) + { + if (unlikely((pfs->m_class == klass) && + (pfs->m_thread_owner == thread))) + { + visitor->visit_socket(pfs); + } + } + } +} + +/** Generic instance iterator with PFS_thread as matching criteria */ + +void PFS_instance_iterator::visit_instances(PFS_instr_class *klass, + PFS_instance_visitor *visitor, + PFS_thread *thread, + bool visit_class) +{ + DBUG_ASSERT(visitor != NULL); + DBUG_ASSERT(klass != NULL); + + switch (klass->m_type) + { + case PFS_CLASS_SOCKET: + { + PFS_socket_class *socket_class= reinterpret_cast<PFS_socket_class*>(klass); + PFS_instance_iterator::visit_socket_instances(socket_class, visitor, + thread, visit_class); + } + break; + default: + break; + } +} + +/** Object iterator */ +void PFS_object_iterator::visit_all(PFS_object_visitor *visitor) +{ + visit_all_tables(visitor); +} + +void PFS_object_iterator::visit_all_tables(PFS_object_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_global(); + + /* For all the table shares ... */ + PFS_table_share *share= table_share_array; + PFS_table_share *share_last= table_share_array + table_share_max; + for ( ; share < share_last; share++) + { + if (share->m_lock.is_populated()) + { + visitor->visit_table_share(share); + } + } + + /* For all the table handles ... */ + PFS_table *table= table_array; + PFS_table *table_last= table_array + table_max; + for ( ; table < table_last; table++) + { + if (table->m_lock.is_populated()) + { + visitor->visit_table(table); + } + } +} + +void PFS_object_iterator::visit_tables(PFS_table_share *share, + PFS_object_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_table_share(share); + + /* For all the table handles ... */ + PFS_table *table= table_array; + PFS_table *table_last= table_array + table_max; + for ( ; table < table_last; table++) + { + if ((table->m_share == share) && table->m_lock.is_populated()) + { + visitor->visit_table(table); + } + } +} + +void PFS_object_iterator::visit_table_indexes(PFS_table_share *share, + uint index, + PFS_object_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_table_share_index(share, index); + + /* For all the table handles ... */ + PFS_table *table= table_array; + PFS_table *table_last= table_array + table_max; + for ( ; table < table_last; table++) + { + if ((table->m_share == share) && table->m_lock.is_populated()) + { + visitor->visit_table_index(table, index); + } + } +} + +/** Connection wait visitor */ + +PFS_connection_wait_visitor +::PFS_connection_wait_visitor(PFS_instr_class *klass) +{ + m_index= klass->m_event_name_index; +} + +PFS_connection_wait_visitor::~PFS_connection_wait_visitor() +{} + +void PFS_connection_wait_visitor::visit_global() +{ + /* + This visitor is used only for idle instruments. + For waits, do not sum by connection but by instances, + it is more efficient. + */ + DBUG_ASSERT(m_index == global_idle_class.m_event_name_index); + m_stat.aggregate(& global_instr_class_waits_array[m_index]); +} + +void PFS_connection_wait_visitor::visit_host(PFS_host *pfs) +{ + m_stat.aggregate(& pfs->m_instr_class_waits_stats[m_index]); +} + +void PFS_connection_wait_visitor::visit_user(PFS_user *pfs) +{ + m_stat.aggregate(& pfs->m_instr_class_waits_stats[m_index]); +} + +void PFS_connection_wait_visitor::visit_account(PFS_account *pfs) +{ + m_stat.aggregate(& pfs->m_instr_class_waits_stats[m_index]); +} + +void PFS_connection_wait_visitor::visit_thread(PFS_thread *pfs) +{ + m_stat.aggregate(& pfs->m_instr_class_waits_stats[m_index]); +} + +PFS_connection_all_wait_visitor +::PFS_connection_all_wait_visitor() +{} + +PFS_connection_all_wait_visitor::~PFS_connection_all_wait_visitor() +{} + +void PFS_connection_all_wait_visitor::visit_global() +{ + /* Sum by instances, not by connection */ + DBUG_ASSERT(false); +} + +void PFS_connection_all_wait_visitor::visit_connection_slice(PFS_connection_slice *pfs) +{ + PFS_single_stat *stat= pfs->m_instr_class_waits_stats; + PFS_single_stat *stat_last= stat + wait_class_max; + for ( ; stat < stat_last; stat++) + { + m_stat.aggregate(stat); + } +} + +void PFS_connection_all_wait_visitor::visit_host(PFS_host *pfs) +{ + visit_connection_slice(pfs); +} + +void PFS_connection_all_wait_visitor::visit_user(PFS_user *pfs) +{ + visit_connection_slice(pfs); +} + +void PFS_connection_all_wait_visitor::visit_account(PFS_account *pfs) +{ + visit_connection_slice(pfs); +} + +void PFS_connection_all_wait_visitor::visit_thread(PFS_thread *pfs) +{ + visit_connection_slice(pfs); +} + +PFS_connection_stage_visitor::PFS_connection_stage_visitor(PFS_stage_class *klass) +{ + m_index= klass->m_event_name_index; +} + +PFS_connection_stage_visitor::~PFS_connection_stage_visitor() +{} + +void PFS_connection_stage_visitor::visit_global() +{ + m_stat.aggregate(& global_instr_class_stages_array[m_index]); +} + +void PFS_connection_stage_visitor::visit_host(PFS_host *pfs) +{ + m_stat.aggregate(& pfs->m_instr_class_stages_stats[m_index]); +} + +void PFS_connection_stage_visitor::visit_user(PFS_user *pfs) +{ + m_stat.aggregate(& pfs->m_instr_class_stages_stats[m_index]); +} + +void PFS_connection_stage_visitor::visit_account(PFS_account *pfs) +{ + m_stat.aggregate(& pfs->m_instr_class_stages_stats[m_index]); +} + +void PFS_connection_stage_visitor::visit_thread(PFS_thread *pfs) +{ + m_stat.aggregate(& pfs->m_instr_class_stages_stats[m_index]); +} + +PFS_connection_statement_visitor +::PFS_connection_statement_visitor(PFS_statement_class *klass) +{ + m_index= klass->m_event_name_index; +} + +PFS_connection_statement_visitor::~PFS_connection_statement_visitor() +{} + +void PFS_connection_statement_visitor::visit_global() +{ + m_stat.aggregate(& global_instr_class_statements_array[m_index]); +} + +void PFS_connection_statement_visitor::visit_host(PFS_host *pfs) +{ + m_stat.aggregate(& pfs->m_instr_class_statements_stats[m_index]); +} + +void PFS_connection_statement_visitor::visit_user(PFS_user *pfs) +{ + m_stat.aggregate(& pfs->m_instr_class_statements_stats[m_index]); +} + +void PFS_connection_statement_visitor::visit_account(PFS_account *pfs) +{ + m_stat.aggregate(& pfs->m_instr_class_statements_stats[m_index]); +} + +void PFS_connection_statement_visitor::visit_thread(PFS_thread *pfs) +{ + m_stat.aggregate(& pfs->m_instr_class_statements_stats[m_index]); +} + +/** Instance wait visitor */ +PFS_connection_all_statement_visitor +::PFS_connection_all_statement_visitor() +{} + +PFS_connection_all_statement_visitor::~PFS_connection_all_statement_visitor() +{} + +void PFS_connection_all_statement_visitor::visit_global() +{ + PFS_statement_stat *stat= global_instr_class_statements_array; + PFS_statement_stat *stat_last= stat + statement_class_max; + for ( ; stat < stat_last; stat++) + { + m_stat.aggregate(stat); + } +} + +void PFS_connection_all_statement_visitor::visit_connection_slice(PFS_connection_slice *pfs) +{ + PFS_statement_stat *stat= pfs->m_instr_class_statements_stats; + PFS_statement_stat *stat_last= stat + statement_class_max; + for ( ; stat < stat_last; stat++) + { + m_stat.aggregate(stat); + } +} + +void PFS_connection_all_statement_visitor::visit_host(PFS_host *pfs) +{ + visit_connection_slice(pfs); +} + +void PFS_connection_all_statement_visitor::visit_user(PFS_user *pfs) +{ + visit_connection_slice(pfs); +} + +void PFS_connection_all_statement_visitor::visit_account(PFS_account *pfs) +{ + visit_connection_slice(pfs); +} + +void PFS_connection_all_statement_visitor::visit_thread(PFS_thread *pfs) +{ + visit_connection_slice(pfs); +} + +PFS_connection_stat_visitor::PFS_connection_stat_visitor() +{} + +PFS_connection_stat_visitor::~PFS_connection_stat_visitor() +{} + +void PFS_connection_stat_visitor::visit_global() +{} + +void PFS_connection_stat_visitor::visit_host(PFS_host *pfs) +{ + m_stat.aggregate_disconnected(pfs->m_disconnected_count); +} + +void PFS_connection_stat_visitor::visit_user(PFS_user *pfs) +{ + m_stat.aggregate_disconnected(pfs->m_disconnected_count); +} + +void PFS_connection_stat_visitor::visit_account(PFS_account *pfs) +{ + m_stat.aggregate_disconnected(pfs->m_disconnected_count); +} + +void PFS_connection_stat_visitor::visit_thread(PFS_thread *) +{ + m_stat.aggregate_active(1); +} + +PFS_instance_wait_visitor::PFS_instance_wait_visitor() +{ +} + +PFS_instance_wait_visitor::~PFS_instance_wait_visitor() +{} + +void PFS_instance_wait_visitor::visit_mutex_class(PFS_mutex_class *pfs) +{ + uint index= pfs->m_event_name_index; + m_stat.aggregate(& global_instr_class_waits_array[index]); +} + +void PFS_instance_wait_visitor::visit_rwlock_class(PFS_rwlock_class *pfs) +{ + uint index= pfs->m_event_name_index; + m_stat.aggregate(& global_instr_class_waits_array[index]); +} + +void PFS_instance_wait_visitor::visit_cond_class(PFS_cond_class *pfs) +{ + uint index= pfs->m_event_name_index; + m_stat.aggregate(& global_instr_class_waits_array[index]); +} + +void PFS_instance_wait_visitor::visit_file_class(PFS_file_class *pfs) +{ + uint index= pfs->m_event_name_index; + m_stat.aggregate(& global_instr_class_waits_array[index]); +} + +void PFS_instance_wait_visitor::visit_socket_class(PFS_socket_class *pfs) +{ + /* Collect global wait stats */ + uint index= pfs->m_event_name_index; + m_stat.aggregate(&global_instr_class_waits_array[index]); + + /* If deferred, then pull wait stats directly from the socket class. */ + if (pfs->is_deferred()) + pfs->m_socket_stat.m_io_stat.sum_waits(&m_stat); +} + +void PFS_instance_wait_visitor::visit_mutex(PFS_mutex *pfs) +{ + m_stat.aggregate(& pfs->m_wait_stat); +} + +void PFS_instance_wait_visitor::visit_rwlock(PFS_rwlock *pfs) +{ + m_stat.aggregate(& pfs->m_wait_stat); +} + +void PFS_instance_wait_visitor::visit_cond(PFS_cond *pfs) +{ + m_stat.aggregate(& pfs->m_wait_stat); +} + +void PFS_instance_wait_visitor::visit_file(PFS_file *pfs) +{ + /* Combine per-operation file wait stats before aggregating */ + PFS_single_stat stat; + pfs->m_file_stat.m_io_stat.sum_waits(&stat); + m_stat.aggregate(&stat); +} + +void PFS_instance_wait_visitor::visit_socket(PFS_socket *pfs) +{ + /* Combine per-operation socket wait stats before aggregating */ + PFS_single_stat stat; + pfs->m_socket_stat.m_io_stat.sum_waits(&stat); + m_stat.aggregate(&stat); +} + +/** Table IO wait visitor */ + +PFS_object_wait_visitor::PFS_object_wait_visitor() +{} + +PFS_object_wait_visitor::~PFS_object_wait_visitor() +{} + +void PFS_object_wait_visitor::visit_global() +{ + uint index; + + index= global_table_io_class.m_event_name_index; + m_stat.aggregate(& global_instr_class_waits_array[index]); + + index= global_table_lock_class.m_event_name_index; + m_stat.aggregate(& global_instr_class_waits_array[index]); +} + +void PFS_object_wait_visitor::visit_table_share(PFS_table_share *pfs) +{ + pfs->m_table_stat.sum(& m_stat); +} + +void PFS_object_wait_visitor::visit_table(PFS_table *pfs) +{ + pfs->m_table_stat.sum(& m_stat); +} + +PFS_table_io_wait_visitor::PFS_table_io_wait_visitor() +{} + +PFS_table_io_wait_visitor::~PFS_table_io_wait_visitor() +{} + +void PFS_table_io_wait_visitor::visit_global() +{ + uint index= global_table_io_class.m_event_name_index; + m_stat.aggregate(& global_instr_class_waits_array[index]); +} + +void PFS_table_io_wait_visitor::visit_table_share(PFS_table_share *pfs) +{ + PFS_table_io_stat io_stat; + uint index; + + /* Aggregate index stats */ + for (index= 0; index < pfs->m_key_count; index++) + io_stat.aggregate(& pfs->m_table_stat.m_index_stat[index]); + + /* Aggregate global stats */ + io_stat.aggregate(& pfs->m_table_stat.m_index_stat[MAX_KEY]); + + io_stat.sum(& m_stat); +} + +void PFS_table_io_wait_visitor::visit_table(PFS_table *pfs) +{ + PFS_table_share *safe_share= sanitize_table_share(pfs->m_share); + + if (likely(safe_share != NULL)) + { + PFS_table_io_stat io_stat; + uint index; + + /* Aggregate index stats */ + for (index= 0; index < safe_share->m_key_count; index++) + io_stat.aggregate(& pfs->m_table_stat.m_index_stat[index]); + + /* Aggregate global stats */ + io_stat.aggregate(& pfs->m_table_stat.m_index_stat[MAX_KEY]); + + io_stat.sum(& m_stat); + } +} + +/** Table IO stat visitor */ + +PFS_table_io_stat_visitor::PFS_table_io_stat_visitor() +{} + +PFS_table_io_stat_visitor::~PFS_table_io_stat_visitor() +{} + +void PFS_table_io_stat_visitor::visit_table_share(PFS_table_share *pfs) +{ + uint index; + + /* Aggregate index stats */ + for (index= 0; index < pfs->m_key_count; index++) + m_stat.aggregate(& pfs->m_table_stat.m_index_stat[index]); + + /* Aggregate global stats */ + m_stat.aggregate(& pfs->m_table_stat.m_index_stat[MAX_KEY]); +} + +void PFS_table_io_stat_visitor::visit_table(PFS_table *pfs) +{ + PFS_table_share *safe_share= sanitize_table_share(pfs->m_share); + + if (likely(safe_share != NULL)) + { + uint index; + + /* Aggregate index stats */ + for (index= 0; index < safe_share->m_key_count; index++) + m_stat.aggregate(& pfs->m_table_stat.m_index_stat[index]); + + /* Aggregate global stats */ + m_stat.aggregate(& pfs->m_table_stat.m_index_stat[MAX_KEY]); + } +} + +/** Index IO stat visitor */ + +PFS_index_io_stat_visitor::PFS_index_io_stat_visitor() +{} + +PFS_index_io_stat_visitor::~PFS_index_io_stat_visitor() +{} + +void PFS_index_io_stat_visitor::visit_table_share_index(PFS_table_share *pfs, uint index) +{ + m_stat.aggregate(& pfs->m_table_stat.m_index_stat[index]); +} + +void PFS_index_io_stat_visitor::visit_table_index(PFS_table *pfs, uint index) +{ + m_stat.aggregate(& pfs->m_table_stat.m_index_stat[index]); +} + +/** Table lock wait visitor */ + +PFS_table_lock_wait_visitor::PFS_table_lock_wait_visitor() +{} + +PFS_table_lock_wait_visitor::~PFS_table_lock_wait_visitor() +{} + +void PFS_table_lock_wait_visitor::visit_global() +{ + uint index= global_table_lock_class.m_event_name_index; + m_stat.aggregate(& global_instr_class_waits_array[index]); +} + +void PFS_table_lock_wait_visitor::visit_table_share(PFS_table_share *pfs) +{ + pfs->m_table_stat.sum_lock(& m_stat); +} + +void PFS_table_lock_wait_visitor::visit_table(PFS_table *pfs) +{ + pfs->m_table_stat.sum_lock(& m_stat); +} + +/** Table lock stat visitor */ + +PFS_table_lock_stat_visitor::PFS_table_lock_stat_visitor() +{} + +PFS_table_lock_stat_visitor::~PFS_table_lock_stat_visitor() +{} + +void PFS_table_lock_stat_visitor::visit_table_share(PFS_table_share *pfs) +{ + m_stat.aggregate(& pfs->m_table_stat.m_lock_stat); +} + +void PFS_table_lock_stat_visitor::visit_table(PFS_table *pfs) +{ + m_stat.aggregate(& pfs->m_table_stat.m_lock_stat); +} + +PFS_instance_socket_io_stat_visitor::PFS_instance_socket_io_stat_visitor() +{} + +PFS_instance_socket_io_stat_visitor::~PFS_instance_socket_io_stat_visitor() +{} + +void PFS_instance_socket_io_stat_visitor::visit_socket_class(PFS_socket_class *pfs) +{ + /* Aggregate wait times, event counts and byte counts */ + m_socket_io_stat.aggregate(&pfs->m_socket_stat.m_io_stat); +} + +void PFS_instance_socket_io_stat_visitor::visit_socket(PFS_socket *pfs) +{ + /* Aggregate wait times, event counts and byte counts */ + m_socket_io_stat.aggregate(&pfs->m_socket_stat.m_io_stat); +} + + +PFS_instance_file_io_stat_visitor::PFS_instance_file_io_stat_visitor() +{} + +PFS_instance_file_io_stat_visitor::~PFS_instance_file_io_stat_visitor() +{} + +void PFS_instance_file_io_stat_visitor::visit_file_class(PFS_file_class *pfs) +{ + /* Aggregate wait times, event counts and byte counts */ + m_file_io_stat.aggregate(&pfs->m_file_stat.m_io_stat); +} + +void PFS_instance_file_io_stat_visitor::visit_file(PFS_file *pfs) +{ + /* Aggregate wait times, event counts and byte counts */ + m_file_io_stat.aggregate(&pfs->m_file_stat.m_io_stat); +} +/** @} */ diff --git a/storage/perfschema/pfs_visitor.h b/storage/perfschema/pfs_visitor.h new file mode 100644 index 00000000000..4ec63d00636 --- /dev/null +++ b/storage/perfschema/pfs_visitor.h @@ -0,0 +1,568 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef PFS_VISITOR_H +#define PFS_VISITOR_H + +#include "pfs_stat.h" + +/** + @file storage/perfschema/pfs_visitor.h + Visitors (declarations). +*/ + +/** + @addtogroup Performance_schema_buffers + @{ +*/ + +struct PFS_user; +struct PFS_account; +struct PFS_host; +struct PFS_thread; +struct PFS_instr_class; +struct PFS_mutex_class; +struct PFS_rwlock_class; +struct PFS_cond_class; +struct PFS_file_class; +struct PFS_socket_class; +struct PFS_table_share; +struct PFS_mutex; +struct PFS_rwlock; +struct PFS_cond; +struct PFS_file; +struct PFS_table; +struct PFS_stage_class; +struct PFS_statement_class; +struct PFS_socket; +struct PFS_connection_slice; + +/** + Interface class to visit groups of connections. + @sa PFS_connection_iterator +*/ +class PFS_connection_visitor +{ +public: + PFS_connection_visitor() {} + virtual ~PFS_connection_visitor() {} + /** Visit all connections. */ + virtual void visit_global() {} + /** Visit all connections of a host. */ + virtual void visit_host(PFS_host *pfs) {} + /** Visit all connections of a user+host. */ + virtual void visit_account(PFS_account *pfs) {} + /** Visit all connections of a user. */ + virtual void visit_user(PFS_user *pfs) {} + /** Visit a thread. */ + virtual void visit_thread(PFS_thread *pfs) {} +}; + +/** + Iterator over groups of connections. + @sa PFS_connection_visitor +*/ +class PFS_connection_iterator +{ +public: + /** + Visit all connections. + @param with_hosts when true, visit also all hosts. + @param with_users when true, visit also all users. + @param with_accounts when true, visit also all user+host. + @param with_threads when true, visit also all threads. + @param visitor the visitor to call + */ + static void visit_global(bool with_hosts, bool with_users, + bool with_accounts, bool with_threads, + PFS_connection_visitor *visitor); + /** + Visit all connections of a host. + @param host the host to visit. + @param with_accounts when true, visit also all related user+host. + @param with_threads when true, visit also all related threads. + @param visitor the visitor to call + */ + static void visit_host(PFS_host *host, bool with_accounts, bool with_threads, + PFS_connection_visitor *visitor); + /** + Visit all connections of a user. + @param user the user to visit. + @param with_accounts when true, visit also all related user+host. + @param with_threads when true, visit also all related threads. + @param visitor the visitor to call + */ + static void visit_user(PFS_user *user, bool with_accounts, bool with_threads, + PFS_connection_visitor *visitor); + /** + Visit all connections of a user+host. + @param account the user+host to visit. + @param with_threads when true, visit also all related threads. + @param visitor the visitor to call + */ + static void visit_account(PFS_account *account, bool with_threads, + PFS_connection_visitor *visitor); + /** + Visit a thread or connection. + @param thread the thread to visit. + @param visitor the visitor to call + */ + static inline void visit_thread(PFS_thread *thread, + PFS_connection_visitor *visitor) + { visitor->visit_thread(thread); } +}; + +/** + Interface class to visit groups of instrumentation point instances. + @sa PFS_instance_iterator +*/ +class PFS_instance_visitor +{ +public: + PFS_instance_visitor() {} + virtual ~PFS_instance_visitor() {} + /** Visit a mutex class. */ + virtual void visit_mutex_class(PFS_mutex_class *pfs) {} + /** Visit a rwlock class. */ + virtual void visit_rwlock_class(PFS_rwlock_class *pfs) {} + /** Visit a cond class. */ + virtual void visit_cond_class(PFS_cond_class *pfs) {} + /** Visit a file class. */ + virtual void visit_file_class(PFS_file_class *pfs) {} + /** Visit a socket class. */ + virtual void visit_socket_class(PFS_socket_class *pfs) {} + /** Visit a mutex instance. */ + virtual void visit_mutex(PFS_mutex *pfs) {} + /** Visit a rwlock instance. */ + virtual void visit_rwlock(PFS_rwlock *pfs) {} + /** Visit a cond instance. */ + virtual void visit_cond(PFS_cond *pfs) {} + /** Visit a file instance. */ + virtual void visit_file(PFS_file *pfs) {} + /** Visit a socket instance. */ + virtual void visit_socket(PFS_socket *pfs) {} +}; + +/** + Iterator over groups of instrumentation point instances. + @sa PFS_instance_visitor +*/ +class PFS_instance_iterator +{ +public: + static void visit_all(PFS_instance_visitor *visitor); + static void visit_all_mutex(PFS_instance_visitor *visitor); + static void visit_all_mutex_classes(PFS_instance_visitor *visitor); + static void visit_all_mutex_instances(PFS_instance_visitor *visitor); + static void visit_all_rwlock(PFS_instance_visitor *visitor); + static void visit_all_rwlock_classes(PFS_instance_visitor *visitor); + static void visit_all_rwlock_instances(PFS_instance_visitor *visitor); + static void visit_all_cond(PFS_instance_visitor *visitor); + static void visit_all_cond_classes(PFS_instance_visitor *visitor); + static void visit_all_cond_instances(PFS_instance_visitor *visitor); + static void visit_all_file(PFS_instance_visitor *visitor); + static void visit_all_file_classes(PFS_instance_visitor *visitor); + static void visit_all_file_instances(PFS_instance_visitor *visitor); + + /** + Visit a mutex class and related instances. + @param klass the klass to visit. + @param visitor the visitor to call + */ + static void visit_mutex_instances(PFS_mutex_class *klass, + PFS_instance_visitor *visitor); + /** + Visit a rwlock class and related instances. + @param klass the klass to visit. + @param visitor the visitor to call + */ + static void visit_rwlock_instances(PFS_rwlock_class *klass, + PFS_instance_visitor *visitor); + /** + Visit a cond class and related instances. + @param klass the klass to visit. + @param visitor the visitor to call + */ + static void visit_cond_instances(PFS_cond_class *klass, + PFS_instance_visitor *visitor); + /** + Visit a file class and related instances. + @param klass the klass to visit. + @param visitor the visitor to call + */ + static void visit_file_instances(PFS_file_class *klass, + PFS_instance_visitor *visitor); + /** + Visit a socket class and related instances. + @param klass the klass to visit. + @param visitor the visitor to call + */ + static void visit_socket_instances(PFS_socket_class *klass, + PFS_instance_visitor *visitor); + /** + Visit a socket class and related instances. + @param klass the klass to visit. + @param visitor the visitor to call + @param thread the owning thread to match + @param visit_class if true then visit the socket class + */ + static void visit_socket_instances(PFS_socket_class *klass, + PFS_instance_visitor *visitor, + PFS_thread *thread, + bool visit_class= true); + /** + Visit an instrument class and related instances. + @param klass the klass to visit. + @param visitor the visitor to call + @param thread comparison criteria + @param visit_class if true then visit the class + */ + static void visit_instances(PFS_instr_class *klass, + PFS_instance_visitor *visitor, + PFS_thread *thread, + bool visit_class= true); +}; + +/** + Interface class to visit groups of SQL objects. + @sa PFS_object_iterator +*/ +class PFS_object_visitor +{ +public: + PFS_object_visitor() {} + virtual ~PFS_object_visitor() {} + /** Visit global data. */ + virtual void visit_global() {} + /** Visit a table share. */ + virtual void visit_table_share(PFS_table_share *pfs) {} + /** Visit a table share index. */ + virtual void visit_table_share_index(PFS_table_share *pfs, uint index) {} + /** Visit a table. */ + virtual void visit_table(PFS_table *pfs) {} + /** Visit a table index. */ + virtual void visit_table_index(PFS_table *pfs, uint index) {} +}; + +/** + Iterator over groups of SQL objects. + @sa PFS_object_visitor +*/ +class PFS_object_iterator +{ +public: + /** Visit all objects. */ + static void visit_all(PFS_object_visitor *visitor); + /** Visit all tables and related handles. */ + static void visit_all_tables(PFS_object_visitor *visitor); + /** Visit a table and related table handles. */ + static void visit_tables(PFS_table_share *share, + PFS_object_visitor *visitor); + /** Visit a table index and related table handles indexes. */ + static void visit_table_indexes(PFS_table_share *share, + uint index, + PFS_object_visitor *visitor); +}; + +/** + A concrete connection visitor that aggregates + wait statistics for a given event_name. +*/ +class PFS_connection_wait_visitor : public PFS_connection_visitor +{ +public: + /** Constructor. */ + PFS_connection_wait_visitor(PFS_instr_class *klass); + virtual ~PFS_connection_wait_visitor(); + virtual void visit_global(); + virtual void visit_host(PFS_host *pfs); + virtual void visit_account(PFS_account *pfs); + virtual void visit_user(PFS_user *pfs); + virtual void visit_thread(PFS_thread *pfs); + + /** EVENT_NAME instrument index. */ + uint m_index; + /** Wait statistic collected. */ + PFS_single_stat m_stat; +}; + +/** + A concrete connection visitor that aggregates + wait statistics for all events. +*/ +class PFS_connection_all_wait_visitor : public PFS_connection_visitor +{ +public: + /** Constructor. */ + PFS_connection_all_wait_visitor(); + virtual ~PFS_connection_all_wait_visitor(); + virtual void visit_global(); + virtual void visit_host(PFS_host *pfs); + virtual void visit_account(PFS_account *pfs); + virtual void visit_user(PFS_user *pfs); + virtual void visit_thread(PFS_thread *pfs); + + /** Wait statistic collected. */ + PFS_single_stat m_stat; + +private: + void visit_connection_slice(PFS_connection_slice *pfs); +}; + +/** + A concrete connection visitor that aggregates + stage statistics. +*/ +class PFS_connection_stage_visitor : public PFS_connection_visitor +{ +public: + /** Constructor. */ + PFS_connection_stage_visitor(PFS_stage_class *klass); + virtual ~PFS_connection_stage_visitor(); + virtual void visit_global(); + virtual void visit_host(PFS_host *pfs); + virtual void visit_account(PFS_account *pfs); + virtual void visit_user(PFS_user *pfs); + virtual void visit_thread(PFS_thread *pfs); + + /** EVENT_NAME instrument index. */ + uint m_index; + /** Stage statistic collected. */ + PFS_stage_stat m_stat; +}; + +/** + A concrete connection visitor that aggregates + statement statistics for a given event_name. +*/ +class PFS_connection_statement_visitor : public PFS_connection_visitor +{ +public: + /** Constructor. */ + PFS_connection_statement_visitor(PFS_statement_class *klass); + virtual ~PFS_connection_statement_visitor(); + virtual void visit_global(); + virtual void visit_host(PFS_host *pfs); + virtual void visit_account(PFS_account *pfs); + virtual void visit_user(PFS_user *pfs); + virtual void visit_thread(PFS_thread *pfs); + + /** EVENT_NAME instrument index. */ + uint m_index; + /** Statement statistic collected. */ + PFS_statement_stat m_stat; +}; + +/** + A concrete connection visitor that aggregates + statement statistics for all events. +*/ +class PFS_connection_all_statement_visitor : public PFS_connection_visitor +{ +public: + /** Constructor. */ + PFS_connection_all_statement_visitor(); + virtual ~PFS_connection_all_statement_visitor(); + virtual void visit_global(); + virtual void visit_host(PFS_host *pfs); + virtual void visit_account(PFS_account *pfs); + virtual void visit_user(PFS_user *pfs); + virtual void visit_thread(PFS_thread *pfs); + + /** Statement statistic collected. */ + PFS_statement_stat m_stat; + +private: + void visit_connection_slice(PFS_connection_slice *pfs); +}; + +/** + A concrete connection visitor that aggregates + connection statistics. +*/ +class PFS_connection_stat_visitor : public PFS_connection_visitor +{ +public: + /** Constructor. */ + PFS_connection_stat_visitor(); + virtual ~PFS_connection_stat_visitor(); + virtual void visit_global(); + virtual void visit_host(PFS_host *pfs); + virtual void visit_account(PFS_account *pfs); + virtual void visit_user(PFS_user *pfs); + virtual void visit_thread(PFS_thread *pfs); + + /** Connection statistic collected. */ + PFS_connection_stat m_stat; +}; + +/** + A concrete instance visitor that aggregates + wait statistics. +*/ +class PFS_instance_wait_visitor : public PFS_instance_visitor +{ +public: + PFS_instance_wait_visitor(); + virtual ~PFS_instance_wait_visitor(); + virtual void visit_mutex_class(PFS_mutex_class *pfs); + virtual void visit_rwlock_class(PFS_rwlock_class *pfs); + virtual void visit_cond_class(PFS_cond_class *pfs); + virtual void visit_file_class(PFS_file_class *pfs); + virtual void visit_socket_class(PFS_socket_class *pfs); + virtual void visit_mutex(PFS_mutex *pfs); + virtual void visit_rwlock(PFS_rwlock *pfs); + virtual void visit_cond(PFS_cond *pfs); + virtual void visit_file(PFS_file *pfs); + virtual void visit_socket(PFS_socket *pfs); + + /** Wait statistic collected. */ + PFS_single_stat m_stat; +}; + +/** + A concrete object visitor that aggregates + object wait statistics. +*/ +class PFS_object_wait_visitor : public PFS_object_visitor +{ +public: + PFS_object_wait_visitor(); + virtual ~PFS_object_wait_visitor(); + virtual void visit_global(); + virtual void visit_table_share(PFS_table_share *pfs); + virtual void visit_table(PFS_table *pfs); + + /** Object wait statistic collected. */ + PFS_single_stat m_stat; +}; + +/** + A concrete object visitor that aggregates + table io wait statistics. +*/ +class PFS_table_io_wait_visitor : public PFS_object_visitor +{ +public: + PFS_table_io_wait_visitor(); + virtual ~PFS_table_io_wait_visitor(); + virtual void visit_global(); + virtual void visit_table_share(PFS_table_share *pfs); + virtual void visit_table(PFS_table *pfs); + + /** Table io wait statistic collected. */ + PFS_single_stat m_stat; +}; + +/** + A concrete object visitor that aggregates + table io statistics. +*/ +class PFS_table_io_stat_visitor : public PFS_object_visitor +{ +public: + PFS_table_io_stat_visitor(); + virtual ~PFS_table_io_stat_visitor(); + virtual void visit_table_share(PFS_table_share *pfs); + virtual void visit_table(PFS_table *pfs); + + /** Table io statistic collected. */ + PFS_table_io_stat m_stat; +}; + +/** + A concrete object visitor that aggregates + index io statistics. +*/ +class PFS_index_io_stat_visitor : public PFS_object_visitor +{ +public: + PFS_index_io_stat_visitor(); + virtual ~PFS_index_io_stat_visitor(); + virtual void visit_table_share_index(PFS_table_share *pfs, uint index); + virtual void visit_table_index(PFS_table *pfs, uint index); + + /** Index io statistic collected. */ + PFS_table_io_stat m_stat; +}; + +/** + A concrete object visitor that aggregates + table lock wait statistics. +*/ +class PFS_table_lock_wait_visitor : public PFS_object_visitor +{ +public: + PFS_table_lock_wait_visitor(); + virtual ~PFS_table_lock_wait_visitor(); + virtual void visit_global(); + virtual void visit_table_share(PFS_table_share *pfs); + virtual void visit_table(PFS_table *pfs); + + /** Table lock wait statistic collected. */ + PFS_single_stat m_stat; +}; + +/** + A concrete object visitor that aggregates + table lock statistics. +*/ +class PFS_table_lock_stat_visitor : public PFS_object_visitor +{ +public: + PFS_table_lock_stat_visitor(); + virtual ~PFS_table_lock_stat_visitor(); + virtual void visit_table_share(PFS_table_share *pfs); + virtual void visit_table(PFS_table *pfs); + + /** Table lock statistic collected. */ + PFS_table_lock_stat m_stat; +}; + +/** + A concrete instance visitor that aggregates + socket wait and byte count statistics. +*/ +class PFS_instance_socket_io_stat_visitor : public PFS_instance_visitor +{ +public: + PFS_instance_socket_io_stat_visitor(); + virtual ~PFS_instance_socket_io_stat_visitor(); + virtual void visit_socket_class(PFS_socket_class *pfs); + virtual void visit_socket(PFS_socket *pfs); + + /** Wait and byte count statistics collected. */ + PFS_socket_io_stat m_socket_io_stat; +}; + +/** + A concrete instance visitor that aggregates + file wait and byte count statistics. +*/ +class PFS_instance_file_io_stat_visitor : public PFS_instance_visitor +{ +public: + PFS_instance_file_io_stat_visitor(); + virtual ~PFS_instance_file_io_stat_visitor(); + virtual void visit_file_class(PFS_file_class *pfs); + virtual void visit_file(PFS_file *pfs); + + /** Wait and byte count statistics collected. */ + PFS_file_io_stat m_file_io_stat; +}; + +/** @} */ +#endif + diff --git a/storage/perfschema/table_accounts.cc b/storage/perfschema/table_accounts.cc new file mode 100644 index 00000000000..92a5d264a44 --- /dev/null +++ b/storage/perfschema/table_accounts.cc @@ -0,0 +1,148 @@ +/* Copyright (c) 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include "my_global.h" +#include "my_pthread.h" +#include "table_accounts.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_account.h" +#include "pfs_visitor.h" + +THR_LOCK table_accounts::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("USER") }, + { C_STRING_WITH_LEN("char(16)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("HOST") }, + { C_STRING_WITH_LEN("char(60)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("CURRENT_CONNECTIONS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("TOTAL_CONNECTIONS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_accounts::m_field_def= +{ 4, field_types }; + +PFS_engine_table_share +table_accounts::m_share= +{ + { C_STRING_WITH_LEN("accounts") }, + &pfs_truncatable_acl, + &table_accounts::create, + NULL, /* write_row */ + table_accounts::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), /* ref length */ + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* table_accounts::create() +{ + return new table_accounts(); +} + +int +table_accounts::delete_all_rows(void) +{ + reset_events_waits_by_thread(); + reset_events_waits_by_account(); + reset_events_stages_by_thread(); + reset_events_stages_by_account(); + reset_events_statements_by_thread(); + reset_events_statements_by_account(); + purge_all_account(); + return 0; +} + +table_accounts::table_accounts() + : cursor_by_account(& m_share), + m_row_exists(false) +{} + +void table_accounts::make_row(PFS_account *pfs) +{ + pfs_lock lock; + + m_row_exists= false; + pfs->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_account.make_row(pfs)) + return; + + PFS_connection_stat_visitor visitor; + PFS_connection_iterator::visit_account(pfs, true, & visitor); + + if (! pfs->m_lock.end_optimistic_lock(& lock)) + return; + + m_row.m_connection_stat.set(& visitor.m_stat); + m_row_exists= true; +} + +int table_accounts::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* USER */ + case 1: /* HOST */ + m_row.m_account.set_field(f->field_index, f); + break; + case 2: /* CURRENT_CONNECTIONS */ + case 3: /* TOTAL_CONNECTIONS */ + m_row.m_connection_stat.set_field(f->field_index - 2, f); + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} + diff --git a/storage/perfschema/table_accounts.h b/storage/perfschema/table_accounts.h new file mode 100644 index 00000000000..232cb9d9b36 --- /dev/null +++ b/storage/perfschema/table_accounts.h @@ -0,0 +1,80 @@ +/* Copyright (c) 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_ACCOUNTS_H +#define TABLE_ACCOUNTS_H + +#include "pfs_column_types.h" +#include "cursor_by_account.h" +#include "table_helper.h" + +struct PFS_account; + +/** + \addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of PERFORMANCE_SCHEMA.ACCOUNTS. +*/ +struct row_accounts +{ + /** Column USER, HOST. */ + PFS_account_row m_account; + /** Columns CURRENT_CONNECTIONS, TOTAL_CONNECTIONS. */ + PFS_connection_stat_row m_connection_stat; +}; + +/** Table PERFORMANCE_SCHEMA.ACCOUNTS. */ +class table_accounts : public cursor_by_account +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + /** Table builder */ + static PFS_engine_table* create(); + static int delete_all_rows(); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + +protected: + table_accounts(); + +public: + ~table_accounts() + {} + +private: + virtual void make_row(PFS_account *pfs); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_accounts m_row; + /** True if the current row exists. */ + bool m_row_exists; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_all_instr.cc b/storage/perfschema/table_all_instr.cc index f29a006107a..ae8988d3a93 100644 --- a/storage/perfschema/table_all_instr.cc +++ b/storage/perfschema/table_all_instr.cc @@ -40,6 +40,7 @@ int table_all_instr::rnd_next(void) PFS_rwlock *rwlock; PFS_cond *cond; PFS_file *file; + PFS_socket *socket; for (m_pos.set_at(&m_next_pos); m_pos.has_more_view(); @@ -94,6 +95,18 @@ int table_all_instr::rnd_next(void) } } break; + case pos_all_instr::VIEW_SOCKET: + for ( ; m_pos.m_index_2 < socket_max; m_pos.m_index_2++) + { + socket= &socket_array[m_pos.m_index_2]; + if (socket->m_lock.is_populated()) + { + make_socket_row(socket); + m_next_pos.set_after(&m_pos); + return 0; + } + } + break; } } @@ -106,6 +119,7 @@ int table_all_instr::rnd_pos(const void *pos) PFS_rwlock *rwlock; PFS_cond *cond; PFS_file *file; + PFS_socket *socket; set_position(pos); @@ -146,115 +160,12 @@ int table_all_instr::rnd_pos(const void *pos) return 0; } break; - } - - return HA_ERR_RECORD_DELETED; -} - -table_all_instr_class::table_all_instr_class -(const PFS_engine_table_share *share) - : PFS_engine_table(share, &m_pos), - m_pos(), m_next_pos() -{} - -void table_all_instr_class::reset_position(void) -{ - m_pos.reset(); - m_next_pos.reset(); -} - -int table_all_instr_class::rnd_next(void) -{ - PFS_mutex_class *mutex_class; - PFS_rwlock_class *rwlock_class; - PFS_cond_class *cond_class; - PFS_file_class *file_class; - - for (m_pos.set_at(&m_next_pos); - m_pos.has_more_view(); - m_pos.next_view()) - { - switch (m_pos.m_index_1) { - case pos_all_instr_class::VIEW_MUTEX: - mutex_class= find_mutex_class(m_pos.m_index_2); - if (mutex_class) - { - make_instr_row(mutex_class); - m_next_pos.set_after(&m_pos); - return 0; - } - break; - case pos_all_instr_class::VIEW_RWLOCK: - rwlock_class= find_rwlock_class(m_pos.m_index_2); - if (rwlock_class) - { - make_instr_row(rwlock_class); - m_next_pos.set_after(&m_pos); - return 0; - } - break; - case pos_all_instr_class::VIEW_COND: - cond_class= find_cond_class(m_pos.m_index_2); - if (cond_class) - { - make_instr_row(cond_class); - m_next_pos.set_after(&m_pos); - return 0; - } - break; - case pos_all_instr_class::VIEW_FILE: - file_class= find_file_class(m_pos.m_index_2); - if (file_class) - { - make_instr_row(file_class); - m_next_pos.set_after(&m_pos); - return 0; - } - break; - } - } - - return HA_ERR_END_OF_FILE; -} - -int table_all_instr_class::rnd_pos(const void *pos) -{ - PFS_mutex_class *mutex_class; - PFS_rwlock_class *rwlock_class; - PFS_cond_class *cond_class; - PFS_file_class *file_class; - - set_position(pos); - switch (m_pos.m_index_1) { - case pos_all_instr_class::VIEW_MUTEX: - mutex_class= find_mutex_class(m_pos.m_index_2); - if (mutex_class) - { - make_instr_row(mutex_class); - return 0; - } - break; - case pos_all_instr_class::VIEW_RWLOCK: - rwlock_class= find_rwlock_class(m_pos.m_index_2); - if (rwlock_class) + case pos_all_instr::VIEW_SOCKET: + DBUG_ASSERT(m_pos.m_index_2 < socket_max); + socket= &socket_array[m_pos.m_index_2]; + if (socket->m_lock.is_populated()) { - make_instr_row(rwlock_class); - return 0; - } - break; - case pos_all_instr_class::VIEW_COND: - cond_class= find_cond_class(m_pos.m_index_2); - if (cond_class) - { - make_instr_row(cond_class); - return 0; - } - break; - case pos_all_instr_class::VIEW_FILE: - file_class= find_file_class(m_pos.m_index_2); - if (file_class) - { - make_instr_row(file_class); + make_socket_row(socket); return 0; } break; @@ -262,4 +173,3 @@ int table_all_instr_class::rnd_pos(const void *pos) return HA_ERR_RECORD_DELETED; } - diff --git a/storage/perfschema/table_all_instr.h b/storage/perfschema/table_all_instr.h index 6e404659030..f78f8cee3ba 100644 --- a/storage/perfschema/table_all_instr.h +++ b/storage/perfschema/table_all_instr.h @@ -24,88 +24,29 @@ #include "pfs_instr_class.h" #include "pfs_instr.h" #include "pfs_engine_table.h" +#include "table_helper.h" /** @addtogroup Performance_schema_tables @{ */ -/** Position of a cursor on table_all_instr_class. */ -struct pos_all_instr_class : public PFS_double_index, - public PFS_instrument_view_constants -{ - pos_all_instr_class() - : PFS_double_index(VIEW_MUTEX, 1) - {} - - inline void reset(void) - { - m_index_1= VIEW_MUTEX; - m_index_2= 1; - } - - inline bool has_more_view(void) - { return (m_index_1 <= VIEW_FILE); } - - inline void next_view(void) - { - m_index_1++; - /* Instrument keys start at 1, not 0. */ - m_index_2= 1; - } -}; - -/** - Abstract table, a union of all instrumentations class metadata. - This table is a union of: - - a view on all mutex classes, - - a view on all rwlock classes, - - a view on all cond classes, - - a view on all file classes -*/ -class table_all_instr_class : public PFS_engine_table -{ -public: - virtual int rnd_next(); - virtual int rnd_pos(const void *pos); - virtual void reset_position(void); - -protected: - table_all_instr_class(const PFS_engine_table_share *share); - -public: - ~table_all_instr_class() - {} - -protected: - /** - Build a row. - @param klass the instrument class - */ - virtual void make_instr_row(PFS_instr_class *klass)= 0; - - /** Current position. */ - pos_all_instr_class m_pos; - /** Next position. */ - pos_all_instr_class m_next_pos; -}; - /** Position of a cursor on table_all_instr. */ struct pos_all_instr : public PFS_double_index, public PFS_instrument_view_constants { pos_all_instr() - : PFS_double_index(VIEW_MUTEX, 0) + : PFS_double_index(FIRST_VIEW, 0) {} inline void reset(void) { - m_index_1= VIEW_MUTEX; + m_index_1= FIRST_VIEW; m_index_2= 0; } inline bool has_more_view(void) - { return (m_index_1 <= VIEW_FILE); } + { return (m_index_1 <= LAST_VIEW); } inline void next_view(void) { @@ -120,7 +61,8 @@ struct pos_all_instr : public PFS_double_index, - a view on all mutex instances, - a view on all rwlock instances, - a view on all cond instances, - - a view on all file instances + - a view on all file instances, + - a view on all socket instances */ class table_all_instr : public PFS_engine_table { @@ -157,6 +99,11 @@ protected: @param pfs the file instance */ virtual void make_file_row(PFS_file *pfs)= 0; + /** + Build a row in the socket instance view. + @param pfs the socket instance + */ + virtual void make_socket_row(PFS_socket *pfs)= 0; /** Current position. */ pos_all_instr m_pos; diff --git a/storage/perfschema/table_esgs_by_account_by_event_name.cc b/storage/perfschema/table_esgs_by_account_by_event_name.cc new file mode 100644 index 00000000000..e36a0d0d00a --- /dev/null +++ b/storage/perfschema/table_esgs_by_account_by_event_name.cc @@ -0,0 +1,233 @@ +/* Copyright (c) 2010, 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 + 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/table_esgs_by_account_by_event_name.cc + Table EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_esgs_by_account_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" + +THR_LOCK table_esgs_by_account_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("USER") }, + { C_STRING_WITH_LEN("char(16)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("HOST") }, + { C_STRING_WITH_LEN("char(60)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_esgs_by_account_by_event_name::m_field_def= +{ 8, field_types }; + +PFS_engine_table_share +table_esgs_by_account_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_stages_summary_by_account_by_event_name") }, + &pfs_truncatable_acl, + table_esgs_by_account_by_event_name::create, + NULL, /* write_row */ + table_esgs_by_account_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_esgs_by_account_by_event_name), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_esgs_by_account_by_event_name::create(void) +{ + return new table_esgs_by_account_by_event_name(); +} + +int +table_esgs_by_account_by_event_name::delete_all_rows(void) +{ + reset_events_stages_by_thread(); + reset_events_stages_by_account(); + return 0; +} + +table_esgs_by_account_by_event_name::table_esgs_by_account_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_esgs_by_account_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_esgs_by_account_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(stage_timer); + return 0; +} + +int table_esgs_by_account_by_event_name::rnd_next(void) +{ + PFS_account *account; + PFS_stage_class *stage_class; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_account(); + m_pos.next_account()) + { + account= &account_array[m_pos.m_index_1]; + if (account->m_lock.is_populated()) + { + stage_class= find_stage_class(m_pos.m_index_2); + if (stage_class) + { + make_row(account, stage_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_esgs_by_account_by_event_name::rnd_pos(const void *pos) +{ + PFS_account *account; + PFS_stage_class *stage_class; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < account_max); + + account= &account_array[m_pos.m_index_1]; + if (! account->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + stage_class= find_stage_class(m_pos.m_index_2); + if (stage_class) + { + make_row(account, stage_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_esgs_by_account_by_event_name +::make_row(PFS_account *account, PFS_stage_class *klass) +{ + pfs_lock lock; + m_row_exists= false; + + account->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_account.make_row(account)) + return; + + m_row.m_event_name.make_row(klass); + + PFS_connection_stage_visitor visitor(klass); + PFS_connection_iterator::visit_account(account, true, & visitor); + + if (! account->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(m_normalizer, & visitor.m_stat); +} + +int table_esgs_by_account_by_event_name +::read_row_values(TABLE *table, unsigned char *buf, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* USER */ + case 1: /* HOST */ + m_row.m_account.set_field(f->field_index, f); + break; + case 2: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 3, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 3, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_esgs_by_account_by_event_name.h b/storage/perfschema/table_esgs_by_account_by_event_name.h new file mode 100644 index 00000000000..c20f129de1e --- /dev/null +++ b/storage/perfschema/table_esgs_by_account_by_event_name.h @@ -0,0 +1,125 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_ESGS_BY_ACCOUNT_BY_EVENT_NAME_H +#define TABLE_ESGS_BY_ACCOUNT_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_esgs_by_account_by_event_name.h + Table EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_account.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. +*/ +struct row_esgs_by_account_by_event_name +{ + /** Column USER, HOST. */ + PFS_account_row m_account; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_stage_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + Index 1 on user@host (0 based) + Index 2 on stage class (1 based) +*/ +struct pos_esgs_by_account_by_event_name +: public PFS_double_index +{ + pos_esgs_by_account_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline bool has_more_account(void) + { return (m_index_1 < account_max); } + + inline void next_account(void) + { + m_index_1++; + m_index_2= 1; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. */ +class table_esgs_by_account_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_esgs_by_account_by_event_name(); + +public: + ~table_esgs_by_account_by_event_name() + {} + +protected: + void make_row(PFS_account *account, PFS_stage_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_esgs_by_account_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_esgs_by_account_by_event_name m_pos; + /** Next position. */ + pos_esgs_by_account_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_esgs_by_host_by_event_name.cc b/storage/perfschema/table_esgs_by_host_by_event_name.cc new file mode 100644 index 00000000000..2357d899116 --- /dev/null +++ b/storage/perfschema/table_esgs_by_host_by_event_name.cc @@ -0,0 +1,229 @@ +/* Copyright (c) 2010, 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 + 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/table_esgs_by_host_by_event_name.cc + Table EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_esgs_by_host_by_event_name.h" +#include "pfs_global.h" +#include "pfs_account.h" +#include "pfs_visitor.h" + +THR_LOCK table_esgs_by_host_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("HOST") }, + { C_STRING_WITH_LEN("char(60)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_esgs_by_host_by_event_name::m_field_def= +{ 7, field_types }; + +PFS_engine_table_share +table_esgs_by_host_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_stages_summary_by_host_by_event_name") }, + &pfs_truncatable_acl, + table_esgs_by_host_by_event_name::create, + NULL, /* write_row */ + table_esgs_by_host_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_esgs_by_host_by_event_name), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_esgs_by_host_by_event_name::create(void) +{ + return new table_esgs_by_host_by_event_name(); +} + +int +table_esgs_by_host_by_event_name::delete_all_rows(void) +{ + reset_events_stages_by_thread(); + reset_events_stages_by_account(); + reset_events_stages_by_host(); + return 0; +} + +table_esgs_by_host_by_event_name::table_esgs_by_host_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_esgs_by_host_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_esgs_by_host_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(stage_timer); + return 0; +} + +int table_esgs_by_host_by_event_name::rnd_next(void) +{ + PFS_host *host; + PFS_stage_class *stage_class; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_host(); + m_pos.next_host()) + { + host= &host_array[m_pos.m_index_1]; + if (host->m_lock.is_populated()) + { + stage_class= find_stage_class(m_pos.m_index_2); + if (stage_class) + { + make_row(host, stage_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_esgs_by_host_by_event_name::rnd_pos(const void *pos) +{ + PFS_host *host; + PFS_stage_class *stage_class; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < host_max); + + host= &host_array[m_pos.m_index_1]; + if (! host->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + stage_class= find_stage_class(m_pos.m_index_2); + if (stage_class) + { + make_row(host, stage_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_esgs_by_host_by_event_name +::make_row(PFS_host *host, PFS_stage_class *klass) +{ + pfs_lock lock; + m_row_exists= false; + + host->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_host.make_row(host)) + return; + + m_row.m_event_name.make_row(klass); + + PFS_connection_stage_visitor visitor(klass); + PFS_connection_iterator::visit_host(host, true, true, & visitor); + + if (! host->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(m_normalizer, & visitor.m_stat); +} + +int table_esgs_by_host_by_event_name +::read_row_values(TABLE *table, unsigned char *buf, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* HOST */ + m_row.m_host.set_field(f); + break; + case 1: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_esgs_by_host_by_event_name.h b/storage/perfschema/table_esgs_by_host_by_event_name.h new file mode 100644 index 00000000000..223923f3026 --- /dev/null +++ b/storage/perfschema/table_esgs_by_host_by_event_name.h @@ -0,0 +1,125 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_ESGS_BY_HOST_BY_EVENT_NAME_H +#define TABLE_ESGS_BY_HOST_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_esgs_by_host_by_event_name.h + Table EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_host.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME. +*/ +struct row_esgs_by_host_by_event_name +{ + /** Column HOST. */ + PFS_host_row m_host; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_stage_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME. + Index 1 on host (0 based) + Index 2 on stage class (1 based). +*/ +struct pos_esgs_by_host_by_event_name +: public PFS_double_index +{ + pos_esgs_by_host_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline bool has_more_host(void) + { return (m_index_1 < host_max); } + + inline void next_host(void) + { + m_index_1++; + m_index_2= 1; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME. */ +class table_esgs_by_host_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_esgs_by_host_by_event_name(); + +public: + ~table_esgs_by_host_by_event_name() + {} + +protected: + void make_row(PFS_host *host, PFS_stage_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_esgs_by_host_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_esgs_by_host_by_event_name m_pos; + /** Next position. */ + pos_esgs_by_host_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_esgs_by_thread_by_event_name.cc b/storage/perfschema/table_esgs_by_thread_by_event_name.cc new file mode 100644 index 00000000000..2a69ec24277 --- /dev/null +++ b/storage/perfschema/table_esgs_by_thread_by_event_name.cc @@ -0,0 +1,229 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_esgs_by_thread_by_event_name.cc + Table EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_esgs_by_thread_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" + +THR_LOCK table_esgs_by_thread_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("THREAD_ID") }, + { C_STRING_WITH_LEN("int(11)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_esgs_by_thread_by_event_name::m_field_def= +{ 7, field_types }; + +PFS_engine_table_share +table_esgs_by_thread_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_stages_summary_by_thread_by_event_name") }, + &pfs_truncatable_acl, + table_esgs_by_thread_by_event_name::create, + NULL, /* write_row */ + table_esgs_by_thread_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_esgs_by_thread_by_event_name), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_esgs_by_thread_by_event_name::create(void) +{ + return new table_esgs_by_thread_by_event_name(); +} + +int +table_esgs_by_thread_by_event_name::delete_all_rows(void) +{ + reset_events_stages_by_thread(); + return 0; +} + +table_esgs_by_thread_by_event_name::table_esgs_by_thread_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_esgs_by_thread_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_esgs_by_thread_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(stage_timer); + return 0; +} + +int table_esgs_by_thread_by_event_name::rnd_next(void) +{ + PFS_thread *thread; + PFS_stage_class *stage_class; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_thread(); + m_pos.next_thread()) + { + thread= &thread_array[m_pos.m_index_1]; + + /* + Important note: the thread scan is the outer loop (index 1), + to minimize the number of calls to atomic operations. + */ + if (thread->m_lock.is_populated()) + { + stage_class= find_stage_class(m_pos.m_index_2); + if (stage_class) + { + make_row(thread, stage_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_esgs_by_thread_by_event_name::rnd_pos(const void *pos) +{ + PFS_thread *thread; + PFS_stage_class *stage_class; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < thread_max); + + thread= &thread_array[m_pos.m_index_1]; + if (! thread->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + stage_class= find_stage_class(m_pos.m_index_2); + if (stage_class) + { + make_row(thread, stage_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_esgs_by_thread_by_event_name +::make_row(PFS_thread *thread, PFS_stage_class *klass) +{ + pfs_lock lock; + m_row_exists= false; + + /* Protect this reader against a thread termination */ + thread->m_lock.begin_optimistic_lock(&lock); + + m_row.m_thread_internal_id= thread->m_thread_internal_id; + + m_row.m_event_name.make_row(klass); + + PFS_connection_stage_visitor visitor(klass); + PFS_connection_iterator::visit_thread(thread, & visitor); + + if (thread->m_lock.end_optimistic_lock(&lock)) + m_row_exists= true; + + m_row.m_stat.set(m_normalizer, & visitor.m_stat); +} + +int table_esgs_by_thread_by_event_name +::read_row_values(TABLE *table, unsigned char *, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 0); + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* THREAD_ID */ + set_field_ulong(f, m_row.m_thread_internal_id); + break; + case 1: /* NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_esgs_by_thread_by_event_name.h b/storage/perfschema/table_esgs_by_thread_by_event_name.h new file mode 100644 index 00000000000..049c8997396 --- /dev/null +++ b/storage/perfschema/table_esgs_by_thread_by_event_name.h @@ -0,0 +1,129 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_ESGS_BY_THREAD_BY_EVENT_NAME_H +#define TABLE_ESGS_BY_THREAD_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_esgs_by_thread_by_event_name.h + Table EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME. +*/ +struct row_esgs_by_thread_by_event_name +{ + /** Column THREAD_ID. */ + ulong m_thread_internal_id; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_stage_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME. + Index 1 on thread (0 based). + Index 2 on stage class (1 based). +*/ +struct pos_esgs_by_thread_by_event_name +: public PFS_double_index +{ + pos_esgs_by_thread_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline bool has_more_thread(void) + { return (m_index_1 < thread_max); } + + inline void next_thread(void) + { + m_index_1++; + m_index_2= 1; + } + + inline void next_stage(void) + { + m_index_2++; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_THREAD_BY_EVENT_NAME. */ +class table_esgs_by_thread_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_esgs_by_thread_by_event_name(); + +public: + ~table_esgs_by_thread_by_event_name() + {} + +protected: + void make_row(PFS_thread *thread, PFS_stage_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_esgs_by_thread_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_esgs_by_thread_by_event_name m_pos; + /** Next position. */ + pos_esgs_by_thread_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_esgs_by_user_by_event_name.cc b/storage/perfschema/table_esgs_by_user_by_event_name.cc new file mode 100644 index 00000000000..c7aff6fdb8d --- /dev/null +++ b/storage/perfschema/table_esgs_by_user_by_event_name.cc @@ -0,0 +1,229 @@ +/* Copyright (c) 2010, 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 + 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/table_esgs_by_user_by_event_name.cc + Table EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_esgs_by_user_by_event_name.h" +#include "pfs_global.h" +#include "pfs_account.h" +#include "pfs_visitor.h" + +THR_LOCK table_esgs_by_user_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("USER") }, + { C_STRING_WITH_LEN("char(16)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_esgs_by_user_by_event_name::m_field_def= +{ 7, field_types }; + +PFS_engine_table_share +table_esgs_by_user_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_stages_summary_by_user_by_event_name") }, + &pfs_truncatable_acl, + table_esgs_by_user_by_event_name::create, + NULL, /* write_row */ + table_esgs_by_user_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_esgs_by_user_by_event_name), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_esgs_by_user_by_event_name::create(void) +{ + return new table_esgs_by_user_by_event_name(); +} + +int +table_esgs_by_user_by_event_name::delete_all_rows(void) +{ + reset_events_stages_by_thread(); + reset_events_stages_by_account(); + reset_events_stages_by_user(); + return 0; +} + +table_esgs_by_user_by_event_name::table_esgs_by_user_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_esgs_by_user_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_esgs_by_user_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(stage_timer); + return 0; +} + +int table_esgs_by_user_by_event_name::rnd_next(void) +{ + PFS_user *user; + PFS_stage_class *stage_class; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_user(); + m_pos.next_user()) + { + user= &user_array[m_pos.m_index_1]; + if (user->m_lock.is_populated()) + { + stage_class= find_stage_class(m_pos.m_index_2); + if (stage_class) + { + make_row(user, stage_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_esgs_by_user_by_event_name::rnd_pos(const void *pos) +{ + PFS_user *user; + PFS_stage_class *stage_class; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < user_max); + + user= &user_array[m_pos.m_index_1]; + if (! user->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + stage_class= find_stage_class(m_pos.m_index_2); + if (stage_class) + { + make_row(user, stage_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_esgs_by_user_by_event_name +::make_row(PFS_user *user, PFS_stage_class *klass) +{ + pfs_lock lock; + m_row_exists= false; + + user->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_user.make_row(user)) + return; + + m_row.m_event_name.make_row(klass); + + PFS_connection_stage_visitor visitor(klass); + PFS_connection_iterator::visit_user(user, true, true, & visitor); + + if (! user->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(m_normalizer, & visitor.m_stat); +} + +int table_esgs_by_user_by_event_name +::read_row_values(TABLE *table, unsigned char *buf, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* USER */ + m_row.m_user.set_field(f); + break; + case 1: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_esgs_by_user_by_event_name.h b/storage/perfschema/table_esgs_by_user_by_event_name.h new file mode 100644 index 00000000000..565e633e386 --- /dev/null +++ b/storage/perfschema/table_esgs_by_user_by_event_name.h @@ -0,0 +1,130 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_ESGS_BY_USER_BY_EVENT_NAME_H +#define TABLE_ESGS_BY_USER_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_esgs_by_user_by_event_name.h + Table EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_user.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME. +*/ +struct row_esgs_by_user_by_event_name +{ + /** Column USER. */ + PFS_user_row m_user; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_stage_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME. + Index 1 on user (0 based) + Index 2 on stage class (1 based) +*/ +struct pos_esgs_by_user_by_event_name +: public PFS_double_index +{ + pos_esgs_by_user_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline bool has_more_user(void) + { return (m_index_1 < user_max); } + + inline void next_user(void) + { + m_index_1++; + m_index_2= 1; + } + + inline void next_stage(void) + { + m_index_2++; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME. */ +class table_esgs_by_user_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_esgs_by_user_by_event_name(); + +public: + ~table_esgs_by_user_by_event_name() + {} + +protected: + void make_row(PFS_user *user, PFS_stage_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_esgs_by_user_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_esgs_by_user_by_event_name m_pos; + /** Next position. */ + pos_esgs_by_user_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_esgs_global_by_event_name.cc b/storage/perfschema/table_esgs_global_by_event_name.cc new file mode 100644 index 00000000000..2ac22fb1551 --- /dev/null +++ b/storage/perfschema/table_esgs_global_by_event_name.cc @@ -0,0 +1,204 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_esgs_global_by_event_name.cc + Table EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_esgs_global_by_event_name.h" +#include "pfs_global.h" +#include "pfs_instr.h" +#include "pfs_timer.h" +#include "pfs_visitor.h" + +THR_LOCK table_esgs_global_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_esgs_global_by_event_name::m_field_def= +{ 6, field_types }; + +PFS_engine_table_share +table_esgs_global_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_stages_summary_global_by_event_name") }, + &pfs_truncatable_acl, + table_esgs_global_by_event_name::create, + NULL, /* write_row */ + table_esgs_global_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_esgs_global_by_event_name::create(void) +{ + return new table_esgs_global_by_event_name(); +} + +int +table_esgs_global_by_event_name::delete_all_rows(void) +{ + reset_events_stages_by_thread(); + reset_events_stages_global(); + return 0; +} + +table_esgs_global_by_event_name::table_esgs_global_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(1), m_next_pos(1) +{} + +void table_esgs_global_by_event_name::reset_position(void) +{ + m_pos= 1; + m_next_pos= 1; +} + +int table_esgs_global_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(stage_timer); + return 0; +} + +int table_esgs_global_by_event_name::rnd_next(void) +{ + PFS_stage_class *stage_class; + + if (global_instr_class_stages_array == NULL) + return HA_ERR_END_OF_FILE; + + m_pos.set_at(&m_next_pos); + + stage_class= find_stage_class(m_pos.m_index); + if (stage_class) + { + make_row(stage_class); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int +table_esgs_global_by_event_name::rnd_pos(const void *pos) +{ + PFS_stage_class *stage_class; + + set_position(pos); + + if (global_instr_class_stages_array == NULL) + return HA_ERR_END_OF_FILE; + + stage_class=find_stage_class(m_pos.m_index); + if (stage_class) + { + make_row(stage_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + + +void table_esgs_global_by_event_name +::make_row(PFS_stage_class *klass) +{ + m_row.m_event_name.make_row(klass); + + PFS_connection_stage_visitor visitor(klass); + PFS_connection_iterator::visit_global(true, /* hosts */ + false, /* users */ + true, true, & visitor); + + m_row.m_stat.set(m_normalizer, & visitor.m_stat); + m_row_exists= true; +} + +int table_esgs_global_by_event_name +::read_row_values(TABLE *table, unsigned char *, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 0); + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 1, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 1, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_esgs_global_by_event_name.h b/storage/perfschema/table_esgs_global_by_event_name.h new file mode 100644 index 00000000000..a9c1456e9b1 --- /dev/null +++ b/storage/perfschema/table_esgs_global_by_event_name.h @@ -0,0 +1,93 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_ESGS_GLOBAL_BY_EVENT_NAME_H +#define TABLE_ESGS_GLOBAL_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_esgs_global_by_event_name.h + Table EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME. +*/ +struct row_esgs_global_by_event_name +{ + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_stage_stat_row m_stat; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME. */ +class table_esgs_global_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_esgs_global_by_event_name(); + +public: + ~table_esgs_global_by_event_name() + {} + +protected: + void make_row(PFS_stage_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_esgs_global_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_esms_by_account_by_event_name.cc b/storage/perfschema/table_esms_by_account_by_event_name.cc new file mode 100644 index 00000000000..77f87182945 --- /dev/null +++ b/storage/perfschema/table_esms_by_account_by_event_name.cc @@ -0,0 +1,328 @@ +/* Copyright (c) 2010, 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 + 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/table_esms_by_account_by_event_name.cc + Table EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_esms_by_account_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" + +THR_LOCK table_esms_by_account_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("USER") }, + { C_STRING_WITH_LEN("char(16)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("HOST") }, + { C_STRING_WITH_LEN("char(60)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_LOCK_TIME") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_WARNINGS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_SENT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_RANGE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_SCAN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_RANGE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_ROWS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_SCAN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_esms_by_account_by_event_name::m_field_def= +{ 27, field_types }; + +PFS_engine_table_share +table_esms_by_account_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_statements_summary_by_account_by_event_name") }, + &pfs_truncatable_acl, + table_esms_by_account_by_event_name::create, + NULL, /* write_row */ + table_esms_by_account_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_esms_by_account_by_event_name), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_esms_by_account_by_event_name::create(void) +{ + return new table_esms_by_account_by_event_name(); +} + +int +table_esms_by_account_by_event_name::delete_all_rows(void) +{ + reset_events_statements_by_thread(); + reset_events_statements_by_account(); + return 0; +} + +table_esms_by_account_by_event_name::table_esms_by_account_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_esms_by_account_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_esms_by_account_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(statement_timer); + return 0; +} + +int table_esms_by_account_by_event_name::rnd_next(void) +{ + PFS_account *account; + PFS_statement_class *statement_class; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_account(); + m_pos.next_account()) + { + account= &account_array[m_pos.m_index_1]; + if (account->m_lock.is_populated()) + { + statement_class= find_statement_class(m_pos.m_index_2); + if (statement_class) + { + make_row(account, statement_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_esms_by_account_by_event_name::rnd_pos(const void *pos) +{ + PFS_account *account; + PFS_statement_class *statement_class; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < account_max); + + account= &account_array[m_pos.m_index_1]; + if (! account->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + statement_class= find_statement_class(m_pos.m_index_2); + if (statement_class) + { + make_row(account, statement_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_esms_by_account_by_event_name +::make_row(PFS_account *account, PFS_statement_class *klass) +{ + pfs_lock lock; + m_row_exists= false; + + account->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_account.make_row(account)) + return; + + m_row.m_event_name.make_row(klass); + + PFS_connection_statement_visitor visitor(klass); + PFS_connection_iterator::visit_account(account, true, & visitor); + + if (! account->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(m_normalizer, & visitor.m_stat); +} + +int table_esms_by_account_by_event_name +::read_row_values(TABLE *table, unsigned char *buf, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* USER */ + case 1: /* HOST */ + m_row.m_account.set_field(f->field_index, f); + break; + case 2: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 3, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 3, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_esms_by_account_by_event_name.h b/storage/perfschema/table_esms_by_account_by_event_name.h new file mode 100644 index 00000000000..d58bf9e5763 --- /dev/null +++ b/storage/perfschema/table_esms_by_account_by_event_name.h @@ -0,0 +1,125 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_ESMS_BY_ACCOUNT_BY_EVENT_NAME_H +#define TABLE_ESMS_BY_ACCOUNT_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_esms_by_account_by_event_name.h + Table EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_account.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. +*/ +struct row_esms_by_account_by_event_name +{ + /** Column USER, HOST. */ + PFS_account_row m_account; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_statement_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + Index 1 on user@host (0 based) + Index 2 on statement class (1 based) +*/ +struct pos_esms_by_account_by_event_name +: public PFS_double_index +{ + pos_esms_by_account_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline bool has_more_account(void) + { return (m_index_1 < account_max); } + + inline void next_account(void) + { + m_index_1++; + m_index_2= 1; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. */ +class table_esms_by_account_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_esms_by_account_by_event_name(); + +public: + ~table_esms_by_account_by_event_name() + {} + +protected: + void make_row(PFS_account *account, PFS_statement_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_esms_by_account_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_esms_by_account_by_event_name m_pos; + /** Next position. */ + pos_esms_by_account_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_esms_by_digest.cc b/storage/perfschema/table_esms_by_digest.cc new file mode 100644 index 00000000000..dac8d3b01dc --- /dev/null +++ b/storage/perfschema/table_esms_by_digest.cc @@ -0,0 +1,325 @@ +/* Copyright (c) 2010, 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 + 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/table_esms_by_digest.cc + Table EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_DIGEST (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_esms_by_digest.h" +#include "pfs_global.h" +#include "pfs_instr.h" +#include "pfs_timer.h" +#include "pfs_visitor.h" +#include "table_esms_by_digest.h" +#include "pfs_digest.h" + +THR_LOCK table_esms_by_digest::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("DIGEST") }, + { C_STRING_WITH_LEN("varchar(32)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("DIGEST_TEXT") }, + { C_STRING_WITH_LEN("longtext") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_LOCK_TIME") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_WARNINGS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_SENT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_RANGE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_SCAN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_RANGE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_ROWS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_SCAN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("FIRST_SEEN") }, + { C_STRING_WITH_LEN("timestamp") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("LAST_SEEN") }, + { C_STRING_WITH_LEN("timestamp") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_esms_by_digest::m_field_def= +{ 28, field_types }; + +PFS_engine_table_share +table_esms_by_digest::m_share= +{ + { C_STRING_WITH_LEN("events_statements_summary_by_digest") }, + &pfs_truncatable_acl, + table_esms_by_digest::create, + NULL, /* write_row */ + table_esms_by_digest::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_esms_by_digest::create(void) +{ + return new table_esms_by_digest(); +} + +int +table_esms_by_digest::delete_all_rows(void) +{ + reset_esms_by_digest(); + return 0; +} + +table_esms_by_digest::table_esms_by_digest() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_esms_by_digest::reset_position(void) +{ + m_pos= 0; + m_next_pos= 0; +} + +int table_esms_by_digest::rnd_next(void) +{ + PFS_statements_digest_stat* digest_stat; + + if (statements_digest_stat_array == NULL) + return HA_ERR_END_OF_FILE; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < digest_max; + m_pos.next()) + { + digest_stat= &statements_digest_stat_array[m_pos.m_index]; + if (digest_stat->m_first_seen != 0) + { + make_row(digest_stat); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_esms_by_digest::rnd_pos(const void *pos) +{ + PFS_statements_digest_stat* digest_stat; + + if (statements_digest_stat_array == NULL) + return HA_ERR_END_OF_FILE; + + set_position(pos); + digest_stat= &statements_digest_stat_array[m_pos.m_index]; + + if (digest_stat->m_first_seen != 0) + { + make_row(digest_stat); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + + +void table_esms_by_digest::make_row(PFS_statements_digest_stat* digest_stat) +{ + m_row_exists= false; + m_row.m_first_seen= digest_stat->m_first_seen; + m_row.m_last_seen= digest_stat->m_last_seen; + m_row.m_digest.make_row(digest_stat); + + /* + Get statements stats. + */ + time_normalizer *normalizer= time_normalizer::get(statement_timer); + m_row.m_stat.set(normalizer, & digest_stat->m_stat); + + m_row_exists= true; +} + +int table_esms_by_digest +::read_row_values(TABLE *table, unsigned char *buf, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* + Set the null bits. It indicates how many fields could be null + in the table. + */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* DIGEST */ + case 1: /* DIGEST_TEXT */ + m_row.m_digest.set_field(f->field_index, f); + break; + case 26: /* FIRST_SEEN */ + set_field_timestamp(f, m_row.m_first_seen); + break; + case 27: /* LAST_SEEN */ + set_field_timestamp(f, m_row.m_last_seen); + break; + default: /* 1, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_esms_by_digest.h b/storage/perfschema/table_esms_by_digest.h new file mode 100644 index 00000000000..2e2e595c056 --- /dev/null +++ b/storage/perfschema/table_esms_by_digest.h @@ -0,0 +1,95 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_ESMS_BY_DIGEST_H +#define TABLE_ESMS_BY_DIGEST_H + +/** + @file storage/perfschema/table_esms_by_digest.h + Table EVENTS_STATEMENTS_SUMMARY_BY_DIGEST (declarations). +*/ + +#include "table_helper.h" +#include "pfs_digest.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_DIGEST. +*/ +struct row_esms_by_digest +{ + /** Columns DIGEST/DIGEST_TEXT. */ + PFS_digest_row m_digest; + + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_statement_stat_row m_stat; + + /** Column FIRST_SEEN. */ + ulonglong m_first_seen; + /** Column LAST_SEEN. */ + ulonglong m_last_seen; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_DIGEST. */ +class table_esms_by_digest : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_esms_by_digest(); + +public: + ~table_esms_by_digest() + {} + +protected: + void make_row(PFS_statements_digest_stat*); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_esms_by_digest m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_esms_by_host_by_event_name.cc b/storage/perfschema/table_esms_by_host_by_event_name.cc new file mode 100644 index 00000000000..57aaf7602c4 --- /dev/null +++ b/storage/perfschema/table_esms_by_host_by_event_name.cc @@ -0,0 +1,324 @@ +/* Copyright (c) 2010, 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 + 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/table_esms_by_host_by_event_name.cc + Table EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_esms_by_host_by_event_name.h" +#include "pfs_global.h" +#include "pfs_account.h" +#include "pfs_visitor.h" + +THR_LOCK table_esms_by_host_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("HOST") }, + { C_STRING_WITH_LEN("char(60)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_LOCK_TIME") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_WARNINGS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_SENT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_RANGE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_SCAN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_RANGE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_ROWS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_SCAN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_esms_by_host_by_event_name::m_field_def= +{ 26, field_types }; + +PFS_engine_table_share +table_esms_by_host_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_statements_summary_by_host_by_event_name") }, + &pfs_truncatable_acl, + table_esms_by_host_by_event_name::create, + NULL, /* write_row */ + table_esms_by_host_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_esms_by_host_by_event_name), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_esms_by_host_by_event_name::create(void) +{ + return new table_esms_by_host_by_event_name(); +} + +int +table_esms_by_host_by_event_name::delete_all_rows(void) +{ + reset_events_statements_by_thread(); + reset_events_statements_by_account(); + reset_events_statements_by_host(); + return 0; +} + +table_esms_by_host_by_event_name::table_esms_by_host_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_esms_by_host_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_esms_by_host_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(statement_timer); + return 0; +} + +int table_esms_by_host_by_event_name::rnd_next(void) +{ + PFS_host *host; + PFS_statement_class *statement_class; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_host(); + m_pos.next_host()) + { + host= &host_array[m_pos.m_index_1]; + if (host->m_lock.is_populated()) + { + statement_class= find_statement_class(m_pos.m_index_2); + if (statement_class) + { + make_row(host, statement_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_esms_by_host_by_event_name::rnd_pos(const void *pos) +{ + PFS_host *host; + PFS_statement_class *statement_class; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < host_max); + + host= &host_array[m_pos.m_index_1]; + if (! host->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + statement_class= find_statement_class(m_pos.m_index_2); + if (statement_class) + { + make_row(host, statement_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_esms_by_host_by_event_name +::make_row(PFS_host *host, PFS_statement_class *klass) +{ + pfs_lock lock; + m_row_exists= false; + + host->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_host.make_row(host)) + return; + + m_row.m_event_name.make_row(klass); + + PFS_connection_statement_visitor visitor(klass); + PFS_connection_iterator::visit_host(host, true, true, & visitor); + + if (! host->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(m_normalizer, & visitor.m_stat); +} + +int table_esms_by_host_by_event_name +::read_row_values(TABLE *table, unsigned char *buf, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* HOST */ + m_row.m_host.set_field(f); + break; + case 1: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_esms_by_host_by_event_name.h b/storage/perfschema/table_esms_by_host_by_event_name.h new file mode 100644 index 00000000000..00c6beee561 --- /dev/null +++ b/storage/perfschema/table_esms_by_host_by_event_name.h @@ -0,0 +1,125 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_ESMS_BY_HOST_BY_EVENT_NAME_H +#define TABLE_ESMS_BY_HOST_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_esms_by_host_by_event_name.h + Table EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_host.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME. +*/ +struct row_esms_by_host_by_event_name +{ + /** Column HOST */ + PFS_host_row m_host; + /** Column EVENT_NAME */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_statement_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME. + Index 1 on host (0 based) + Index 2 on statement class (1 based) +*/ +struct pos_esms_by_host_by_event_name +: public PFS_double_index +{ + pos_esms_by_host_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline bool has_more_host(void) + { return (m_index_1 < host_max); } + + inline void next_host(void) + { + m_index_1++; + m_index_2= 1; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME. */ +class table_esms_by_host_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_esms_by_host_by_event_name(); + +public: + ~table_esms_by_host_by_event_name() + {} + +protected: + void make_row(PFS_host *host, PFS_statement_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_esms_by_host_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_esms_by_host_by_event_name m_pos; + /** Next position. */ + pos_esms_by_host_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_esms_by_thread_by_event_name.cc b/storage/perfschema/table_esms_by_thread_by_event_name.cc new file mode 100644 index 00000000000..5a7faca1b79 --- /dev/null +++ b/storage/perfschema/table_esms_by_thread_by_event_name.cc @@ -0,0 +1,325 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_esms_by_thread_by_event_name.cc + Table EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_esms_by_thread_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" + +THR_LOCK table_esms_by_thread_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("THREAD_ID") }, + { C_STRING_WITH_LEN("int(11)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_LOCK_TIME") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_WARNINGS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_SENT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_RANGE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_SCAN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_RANGE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_ROWS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_SCAN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_esms_by_thread_by_event_name::m_field_def= +{ 26, field_types }; + +PFS_engine_table_share +table_esms_by_thread_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_statements_summary_by_thread_by_event_name") }, + &pfs_truncatable_acl, + table_esms_by_thread_by_event_name::create, + NULL, /* write_row */ + table_esms_by_thread_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_esms_by_thread_by_event_name), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_esms_by_thread_by_event_name::create(void) +{ + return new table_esms_by_thread_by_event_name(); +} + +int +table_esms_by_thread_by_event_name::delete_all_rows(void) +{ + reset_events_statements_by_thread(); + return 0; +} + +table_esms_by_thread_by_event_name::table_esms_by_thread_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_esms_by_thread_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_esms_by_thread_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(statement_timer); + return 0; +} + +int table_esms_by_thread_by_event_name::rnd_next(void) +{ + PFS_thread *thread; + PFS_statement_class *statement_class; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_thread(); + m_pos.next_thread()) + { + thread= &thread_array[m_pos.m_index_1]; + + /* + Important note: the thread scan is the outer loop (index 1), + to minimize the number of calls to atomic operations. + */ + if (thread->m_lock.is_populated()) + { + statement_class= find_statement_class(m_pos.m_index_2); + if (statement_class) + { + make_row(thread, statement_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_esms_by_thread_by_event_name::rnd_pos(const void *pos) +{ + PFS_thread *thread; + PFS_statement_class *statement_class; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < thread_max); + + thread= &thread_array[m_pos.m_index_1]; + if (! thread->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + statement_class= find_statement_class(m_pos.m_index_2); + if (statement_class) + { + make_row(thread, statement_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_esms_by_thread_by_event_name +::make_row(PFS_thread *thread, PFS_statement_class *klass) +{ + pfs_lock lock; + m_row_exists= false; + + /* Protect this reader against a thread termination */ + thread->m_lock.begin_optimistic_lock(&lock); + + m_row.m_thread_internal_id= thread->m_thread_internal_id; + + m_row.m_event_name.make_row(klass); + + PFS_connection_statement_visitor visitor(klass); + PFS_connection_iterator::visit_thread(thread, & visitor); + + if (! thread->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(m_normalizer, & visitor.m_stat); +} + +int table_esms_by_thread_by_event_name +::read_row_values(TABLE *table, unsigned char *, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 0); + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* THREAD_ID */ + set_field_ulong(f, m_row.m_thread_internal_id); + break; + case 1: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_esms_by_thread_by_event_name.h b/storage/perfschema/table_esms_by_thread_by_event_name.h new file mode 100644 index 00000000000..2f36606a5e1 --- /dev/null +++ b/storage/perfschema/table_esms_by_thread_by_event_name.h @@ -0,0 +1,129 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_ESMS_BY_THREAD_BY_EVENT_NAME_H +#define TABLE_ESMS_BY_THREAD_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_esms_by_thread_by_event_name.h + Table EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME. +*/ +struct row_esms_by_thread_by_event_name +{ + /** Column THREAD_ID. */ + ulong m_thread_internal_id; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_statement_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME. + Index 1 on thread (0 based). + Index 2 on statement class (1 based). +*/ +struct pos_esms_by_thread_by_event_name +: public PFS_double_index, public PFS_instrument_view_constants +{ + pos_esms_by_thread_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline bool has_more_thread(void) + { return (m_index_1 < thread_max); } + + inline void next_thread(void) + { + m_index_1++; + m_index_2= 1; + } + + inline void next_statement(void) + { + m_index_2++; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME. */ +class table_esms_by_thread_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_esms_by_thread_by_event_name(); + +public: + ~table_esms_by_thread_by_event_name() + {} + +protected: + void make_row(PFS_thread *thread, PFS_statement_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_esms_by_thread_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_esms_by_thread_by_event_name m_pos; + /** Next position. */ + pos_esms_by_thread_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_esms_by_user_by_event_name.cc b/storage/perfschema/table_esms_by_user_by_event_name.cc new file mode 100644 index 00000000000..d65a255e280 --- /dev/null +++ b/storage/perfschema/table_esms_by_user_by_event_name.cc @@ -0,0 +1,324 @@ +/* Copyright (c) 2010, 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 + 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/table_esms_by_user_by_event_name.cc + Table EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_esms_by_user_by_event_name.h" +#include "pfs_global.h" +#include "pfs_account.h" +#include "pfs_visitor.h" + +THR_LOCK table_esms_by_user_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("USER") }, + { C_STRING_WITH_LEN("char(16)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_LOCK_TIME") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_WARNINGS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_SENT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_RANGE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_SCAN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_RANGE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_ROWS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_SCAN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_esms_by_user_by_event_name::m_field_def= +{ 26, field_types }; + +PFS_engine_table_share +table_esms_by_user_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_statements_summary_by_user_by_event_name") }, + &pfs_truncatable_acl, + table_esms_by_user_by_event_name::create, + NULL, /* write_row */ + table_esms_by_user_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_esms_by_user_by_event_name), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_esms_by_user_by_event_name::create(void) +{ + return new table_esms_by_user_by_event_name(); +} + +int +table_esms_by_user_by_event_name::delete_all_rows(void) +{ + reset_events_statements_by_thread(); + reset_events_statements_by_account(); + reset_events_statements_by_user(); + return 0; +} + +table_esms_by_user_by_event_name::table_esms_by_user_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_esms_by_user_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_esms_by_user_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(statement_timer); + return 0; +} + +int table_esms_by_user_by_event_name::rnd_next(void) +{ + PFS_user *user; + PFS_statement_class *statement_class; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_user(); + m_pos.next_user()) + { + user= &user_array[m_pos.m_index_1]; + if (user->m_lock.is_populated()) + { + statement_class= find_statement_class(m_pos.m_index_2); + if (statement_class) + { + make_row(user, statement_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_esms_by_user_by_event_name::rnd_pos(const void *pos) +{ + PFS_user *user; + PFS_statement_class *statement_class; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < user_max); + + user= &user_array[m_pos.m_index_1]; + if (! user->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + statement_class= find_statement_class(m_pos.m_index_2); + if (statement_class) + { + make_row(user, statement_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_esms_by_user_by_event_name +::make_row(PFS_user *user, PFS_statement_class *klass) +{ + pfs_lock lock; + m_row_exists= false; + + user->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_user.make_row(user)) + return; + + m_row.m_event_name.make_row(klass); + + PFS_connection_statement_visitor visitor(klass); + PFS_connection_iterator::visit_user(user, true, true, & visitor); + + if (! user->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(m_normalizer, & visitor.m_stat); +} + +int table_esms_by_user_by_event_name +::read_row_values(TABLE *table, unsigned char *buf, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* USER */ + m_row.m_user.set_field(f); + break; + case 1: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_esms_by_user_by_event_name.h b/storage/perfschema/table_esms_by_user_by_event_name.h new file mode 100644 index 00000000000..4f52b64b6b8 --- /dev/null +++ b/storage/perfschema/table_esms_by_user_by_event_name.h @@ -0,0 +1,125 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_ESMS_BY_USER_BY_EVENT_NAME_H +#define TABLE_ESMS_BY_USER_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_esms_by_user_by_event_name.h + Table EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_user.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME. +*/ +struct row_esms_by_user_by_event_name +{ + /** Column USER. */ + PFS_user_row m_user; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_statement_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME. + Index 1 on user (0 based) + Index 2 on statement class (1 based) +*/ +struct pos_esms_by_user_by_event_name +: public PFS_double_index +{ + pos_esms_by_user_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline bool has_more_user(void) + { return (m_index_1 < user_max); } + + inline void next_user(void) + { + m_index_1++; + m_index_2= 1; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME. */ +class table_esms_by_user_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_esms_by_user_by_event_name(); + +public: + ~table_esms_by_user_by_event_name() + {} + +protected: + void make_row(PFS_user *user, PFS_statement_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_esms_by_user_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_esms_by_user_by_event_name m_pos; + /** Next position. */ + pos_esms_by_user_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_esms_global_by_event_name.cc b/storage/perfschema/table_esms_global_by_event_name.cc new file mode 100644 index 00000000000..22c87f09137 --- /dev/null +++ b/storage/perfschema/table_esms_global_by_event_name.cc @@ -0,0 +1,299 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_esms_global_by_event_name.cc + Table EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_esms_global_by_event_name.h" +#include "pfs_global.h" +#include "pfs_instr.h" +#include "pfs_timer.h" +#include "pfs_visitor.h" + +THR_LOCK table_esms_global_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_LOCK_TIME") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_WARNINGS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_AFFECTED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_SENT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_ROWS_EXAMINED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CREATED_TMP_DISK_TABLES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CREATED_TMP_TABLES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_FULL_JOIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_FULL_RANGE_JOIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_RANGE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_RANGE_CHECK") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SELECT_SCAN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_MERGE_PASSES") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_RANGE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_ROWS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_SORT_SCAN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NO_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NO_GOOD_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_esms_global_by_event_name::m_field_def= +{ 25, field_types }; + +PFS_engine_table_share +table_esms_global_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_statements_summary_global_by_event_name") }, + &pfs_truncatable_acl, + table_esms_global_by_event_name::create, + NULL, /* write_row */ + table_esms_global_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_esms_global_by_event_name::create(void) +{ + return new table_esms_global_by_event_name(); +} + +int +table_esms_global_by_event_name::delete_all_rows(void) +{ + reset_events_statements_by_thread(); + reset_events_statements_global(); + return 0; +} + +table_esms_global_by_event_name::table_esms_global_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(1), m_next_pos(1) +{} + +void table_esms_global_by_event_name::reset_position(void) +{ + m_pos= 1; + m_next_pos= 1; +} + +int table_esms_global_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(statement_timer); + return 0; +} + +int table_esms_global_by_event_name::rnd_next(void) +{ + PFS_statement_class *statement_class; + + if (global_instr_class_statements_array == NULL) + return HA_ERR_END_OF_FILE; + + m_pos.set_at(&m_next_pos); + + statement_class= find_statement_class(m_pos.m_index); + if (statement_class) + { + make_row(statement_class); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int +table_esms_global_by_event_name::rnd_pos(const void *pos) +{ + PFS_statement_class *statement_class; + + set_position(pos); + + if (global_instr_class_statements_array == NULL) + return HA_ERR_END_OF_FILE; + + statement_class=find_statement_class(m_pos.m_index); + if (statement_class) + { + make_row(statement_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + + +void table_esms_global_by_event_name +::make_row(PFS_statement_class *klass) +{ + m_row.m_event_name.make_row(klass); + + PFS_connection_statement_visitor visitor(klass); + PFS_connection_iterator::visit_global(true, /* hosts */ + false, /* users */ + true, true, & visitor); + + m_row.m_stat.set(m_normalizer, & visitor.m_stat); + m_row_exists= true; +} + +int table_esms_global_by_event_name +::read_row_values(TABLE *table, unsigned char *, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 0); + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 1, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 1, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_esms_global_by_event_name.h b/storage/perfschema/table_esms_global_by_event_name.h new file mode 100644 index 00000000000..ed07e2b9062 --- /dev/null +++ b/storage/perfschema/table_esms_global_by_event_name.h @@ -0,0 +1,93 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_ESMS_GLOBAL_BY_EVENT_NAME_H +#define TABLE_ESMS_GLOBAL_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_esms_global_by_event_name.h + Table EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME. +*/ +struct row_esms_global_by_event_name +{ + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_statement_stat_row m_stat; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME. */ +class table_esms_global_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_esms_global_by_event_name(); + +public: + ~table_esms_global_by_event_name() + {} + +protected: + void make_row(PFS_statement_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_esms_global_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_events_stages.cc b/storage/perfschema/table_events_stages.cc new file mode 100644 index 00000000000..e438249fbd3 --- /dev/null +++ b/storage/perfschema/table_events_stages.cc @@ -0,0 +1,523 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_events_stages.cc + Table EVENTS_STAGES_xxx (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "table_events_stages.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_events_stages.h" +#include "pfs_timer.h" + +THR_LOCK table_events_stages_current::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("THREAD_ID") }, + { C_STRING_WITH_LEN("int(11)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_ID") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("END_EVENT_ID") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SOURCE") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("TIMER_START") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("TIMER_END") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("NESTING_EVENT_ID") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("NESTING_EVENT_TYPE") }, + { C_STRING_WITH_LEN("enum(\'STATEMENT\',\'STAGE\',\'WAIT\'") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_events_stages_current::m_field_def= +{10 , field_types }; + +PFS_engine_table_share +table_events_stages_current::m_share= +{ + { C_STRING_WITH_LEN("events_stages_current") }, + &pfs_truncatable_acl, + &table_events_stages_current::create, + NULL, /* write_row */ + &table_events_stages_current::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), /* ref length */ + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +THR_LOCK table_events_stages_history::m_table_lock; + +PFS_engine_table_share +table_events_stages_history::m_share= +{ + { C_STRING_WITH_LEN("events_stages_history") }, + &pfs_truncatable_acl, + &table_events_stages_history::create, + NULL, /* write_row */ + &table_events_stages_history::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_events_stages_history), /* ref length */ + &m_table_lock, + &table_events_stages_current::m_field_def, + false /* checked */ +}; + +THR_LOCK table_events_stages_history_long::m_table_lock; + +PFS_engine_table_share +table_events_stages_history_long::m_share= +{ + { C_STRING_WITH_LEN("events_stages_history_long") }, + &pfs_truncatable_acl, + &table_events_stages_history_long::create, + NULL, /* write_row */ + &table_events_stages_history_long::delete_all_rows, + NULL, /* get_row_count */ + 10000, /* records */ + sizeof(PFS_simple_index), /* ref length */ + &m_table_lock, + &table_events_stages_current::m_field_def, + false /* checked */ +}; + +table_events_stages_common::table_events_stages_common +(const PFS_engine_table_share *share, void *pos) + : PFS_engine_table(share, pos), + m_row_exists(false) +{} + +/** + Build a row. + @param stage the stage the cursor is reading +*/ +void table_events_stages_common::make_row(PFS_events_stages *stage) +{ + const char *base; + const char *safe_source_file; + + m_row_exists= false; + + PFS_stage_class *unsafe= (PFS_stage_class*) stage->m_class; + PFS_stage_class *klass= sanitize_stage_class(unsafe); + if (unlikely(klass == NULL)) + return; + + m_row.m_thread_internal_id= stage->m_thread_internal_id; + m_row.m_event_id= stage->m_event_id; + m_row.m_end_event_id= stage->m_end_event_id; + m_row.m_nesting_event_id= stage->m_nesting_event_id; + m_row.m_nesting_event_type= stage->m_nesting_event_type; + + m_normalizer->to_pico(stage->m_timer_start, stage->m_timer_end, + & m_row.m_timer_start, & m_row.m_timer_end, & m_row.m_timer_wait); + + m_row.m_name= klass->m_name; + m_row.m_name_length= klass->m_name_length; + + safe_source_file= stage->m_source_file; + if (unlikely(safe_source_file == NULL)) + return; + + base= base_name(safe_source_file); + m_row.m_source_length= my_snprintf(m_row.m_source, sizeof(m_row.m_source), + "%s:%d", base, stage->m_source_line); + if (m_row.m_source_length > sizeof(m_row.m_source)) + m_row.m_source_length= sizeof(m_row.m_source); + + m_row_exists= true; + return; +} + +int table_events_stages_common::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* THREAD_ID */ + set_field_ulong(f, m_row.m_thread_internal_id); + break; + case 1: /* EVENT_ID */ + set_field_ulonglong(f, m_row.m_event_id); + break; + case 2: /* END_EVENT_ID */ + if (m_row.m_end_event_id > 0) + set_field_ulonglong(f, m_row.m_end_event_id - 1); + else + f->set_null(); + break; + case 3: /* EVENT_NAME */ + set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length); + break; + case 4: /* SOURCE */ + set_field_varchar_utf8(f, m_row.m_source, m_row.m_source_length); + break; + case 5: /* TIMER_START */ + if (m_row.m_timer_start != 0) + set_field_ulonglong(f, m_row.m_timer_start); + else + f->set_null(); + break; + case 6: /* TIMER_END */ + if (m_row.m_timer_end != 0) + set_field_ulonglong(f, m_row.m_timer_end); + else + f->set_null(); + break; + case 7: /* TIMER_WAIT */ + if (m_row.m_timer_wait != 0) + set_field_ulonglong(f, m_row.m_timer_wait); + else + f->set_null(); + break; + case 8: /* NESTING_EVENT_ID */ + if (m_row.m_nesting_event_id != 0) + set_field_ulonglong(f, m_row.m_nesting_event_id); + else + f->set_null(); + break; + case 9: /* NESTING_EVENT_TYPE */ + if (m_row.m_nesting_event_id != 0) + set_field_enum(f, m_row.m_nesting_event_type); + else + f->set_null(); + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} + +PFS_engine_table* table_events_stages_current::create(void) +{ + return new table_events_stages_current(); +} + +table_events_stages_current::table_events_stages_current() + : table_events_stages_common(&m_share, &m_pos), + m_pos(0), m_next_pos(0) +{} + +void table_events_stages_current::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_events_stages_current::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(stage_timer); + return 0; +} + +int table_events_stages_current::rnd_next(void) +{ + PFS_thread *pfs_thread; + PFS_events_stages *stage; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < thread_max; + m_pos.next()) + { + pfs_thread= &thread_array[m_pos.m_index]; + + if (! pfs_thread->m_lock.is_populated()) + { + /* This thread does not exist */ + continue; + } + + stage= &pfs_thread->m_stage_current; + + make_row(stage); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int table_events_stages_current::rnd_pos(const void *pos) +{ + PFS_thread *pfs_thread; + PFS_events_stages *stage; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < thread_max); + pfs_thread= &thread_array[m_pos.m_index]; + + if (! pfs_thread->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + stage= &pfs_thread->m_stage_current; + make_row(stage); + return 0; +} + +int table_events_stages_current::delete_all_rows(void) +{ + reset_events_stages_current(); + return 0; +} + +PFS_engine_table* table_events_stages_history::create(void) +{ + return new table_events_stages_history(); +} + +table_events_stages_history::table_events_stages_history() + : table_events_stages_common(&m_share, &m_pos), + m_pos(), m_next_pos() +{} + +void table_events_stages_history::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_events_stages_history::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(stage_timer); + return 0; +} + +int table_events_stages_history::rnd_next(void) +{ + PFS_thread *pfs_thread; + PFS_events_stages *stage; + + if (events_stages_history_per_thread == 0) + return HA_ERR_END_OF_FILE; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index_1 < thread_max; + m_pos.next_thread()) + { + pfs_thread= &thread_array[m_pos.m_index_1]; + + if (! pfs_thread->m_lock.is_populated()) + { + /* This thread does not exist */ + continue; + } + + if (m_pos.m_index_2 >= events_stages_history_per_thread) + { + /* This thread does not have more (full) history */ + continue; + } + + if ( ! pfs_thread->m_stages_history_full && + (m_pos.m_index_2 >= pfs_thread->m_stages_history_index)) + { + /* This thread does not have more (not full) history */ + continue; + } + + stage= &pfs_thread->m_stages_history[m_pos.m_index_2]; + + if (stage->m_class != NULL) + { + make_row(stage); + /* Next iteration, look for the next history in this thread */ + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_events_stages_history::rnd_pos(const void *pos) +{ + PFS_thread *pfs_thread; + PFS_events_stages *stage; + + DBUG_ASSERT(events_stages_history_per_thread != 0); + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < thread_max); + pfs_thread= &thread_array[m_pos.m_index_1]; + + if (! pfs_thread->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + DBUG_ASSERT(m_pos.m_index_2 < events_stages_history_per_thread); + + if ( ! pfs_thread->m_stages_history_full && + (m_pos.m_index_2 >= pfs_thread->m_stages_history_index)) + return HA_ERR_RECORD_DELETED; + + stage= &pfs_thread->m_stages_history[m_pos.m_index_2]; + + if (stage->m_class == NULL) + return HA_ERR_RECORD_DELETED; + + make_row(stage); + return 0; +} + +int table_events_stages_history::delete_all_rows(void) +{ + reset_events_stages_history(); + return 0; +} + +PFS_engine_table* table_events_stages_history_long::create(void) +{ + return new table_events_stages_history_long(); +} + +table_events_stages_history_long::table_events_stages_history_long() + : table_events_stages_common(&m_share, &m_pos), + m_pos(0), m_next_pos(0) +{} + +void table_events_stages_history_long::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_events_stages_history_long::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(stage_timer); + return 0; +} + +int table_events_stages_history_long::rnd_next(void) +{ + PFS_events_stages *stage; + uint limit; + + if (events_stages_history_long_size == 0) + return HA_ERR_END_OF_FILE; + + if (events_stages_history_long_full) + limit= events_stages_history_long_size; + else + limit= events_stages_history_long_index % events_stages_history_long_size; + + for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next()) + { + stage= &events_stages_history_long_array[m_pos.m_index]; + + if (stage->m_class != NULL) + { + make_row(stage); + /* Next iteration, look for the next entry */ + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_events_stages_history_long::rnd_pos(const void *pos) +{ + PFS_events_stages *stage; + uint limit; + + if (events_stages_history_long_size == 0) + return HA_ERR_RECORD_DELETED; + + set_position(pos); + + if (events_stages_history_long_full) + limit= events_stages_history_long_size; + else + limit= events_stages_history_long_index % events_stages_history_long_size; + + if (m_pos.m_index > limit) + return HA_ERR_RECORD_DELETED; + + stage= &events_stages_history_long_array[m_pos.m_index]; + + if (stage->m_class == NULL) + return HA_ERR_RECORD_DELETED; + + make_row(stage); + return 0; +} + +int table_events_stages_history_long::delete_all_rows(void) +{ + reset_events_stages_history_long(); + return 0; +} + diff --git a/storage/perfschema/table_events_stages.h b/storage/perfschema/table_events_stages.h new file mode 100644 index 00000000000..6bc712c15a5 --- /dev/null +++ b/storage/perfschema/table_events_stages.h @@ -0,0 +1,212 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_EVENTS_STAGES_H +#define TABLE_EVENTS_STAGES_H + +/** + @file storage/perfschema/table_events_stages.h + Table EVENTS_STAGES_xxx (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_events_stages.h" + +struct PFS_thread; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of table_events_stages_common. */ +struct row_events_stages +{ + /** Column THREAD_ID. */ + ulong m_thread_internal_id; + /** Column EVENT_ID. */ + ulonglong m_event_id; + /** Column END_EVENT_ID. */ + ulonglong m_end_event_id; + /** Column NESTING_EVENT_ID. */ + ulonglong m_nesting_event_id; + /** Column NESTING_EVENT_TYPE. */ + enum_event_type m_nesting_event_type; + /** Column EVENT_NAME. */ + const char *m_name; + /** Length in bytes of @c m_name. */ + uint m_name_length; + /** Column TIMER_START. */ + ulonglong m_timer_start; + /** Column TIMER_END. */ + ulonglong m_timer_end; + /** Column TIMER_WAIT. */ + ulonglong m_timer_wait; + /** Column SOURCE. */ + char m_source[COL_SOURCE_SIZE]; + /** Length in bytes of @c m_source. */ + uint m_source_length; +}; + +/** Position of a cursor on PERFORMANCE_SCHEMA.EVENTS_STAGES_HISTORY. */ +struct pos_events_stages_history : public PFS_double_index +{ + pos_events_stages_history() + : PFS_double_index(0, 0) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 0; + } + + inline void next_thread(void) + { + m_index_1++; + m_index_2= 0; + } +}; + +/** + Adapter, for table sharing the structure of + PERFORMANCE_SCHEMA.EVENTS_STAGES_CURRENT. +*/ +class table_events_stages_common : public PFS_engine_table +{ +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_events_stages_common(const PFS_engine_table_share *share, void *pos); + + ~table_events_stages_common() + {} + + void make_row(PFS_events_stages *stage); + + /** Current row. */ + row_events_stages m_row; + /** True if the current row exists. */ + bool m_row_exists; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STAGES_CURRENT. */ +class table_events_stages_current : public table_events_stages_common +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + table_events_stages_current(); + +public: + ~table_events_stages_current() + {} + +private: + friend class table_events_stages_history; + friend class table_events_stages_history_long; + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** + Fields definition. + Also used by table_events_stages_history + and table_events_stages_history_long. + */ + static TABLE_FIELD_DEF m_field_def; + + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STAGES_HISTORY. */ +class table_events_stages_history : public table_events_stages_common +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + table_events_stages_history(); + +public: + ~table_events_stages_history() + {} + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + + /** Current position. */ + pos_events_stages_history m_pos; + /** Next position. */ + pos_events_stages_history m_next_pos; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STAGES_HISTORY_LONG. */ +class table_events_stages_history_long : public table_events_stages_common +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + table_events_stages_history_long(); + +public: + ~table_events_stages_history_long() + {} + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_events_statements.cc b/storage/perfschema/table_events_statements.cc new file mode 100644 index 00000000000..d453b14470f --- /dev/null +++ b/storage/perfschema/table_events_statements.cc @@ -0,0 +1,886 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_events_statements.cc + Table EVENTS_STATEMENTS_xxx (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "table_events_statements.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_events_statements.h" +#include "pfs_timer.h" +#include "sp_head.h" /* TYPE_ENUM_FUNCTION, ... */ +#include "table_helper.h" +#include "my_md5.h" + +THR_LOCK table_events_statements_current::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("THREAD_ID") }, + { C_STRING_WITH_LEN("int(11)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_ID") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("END_EVENT_ID") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SOURCE") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("TIMER_START") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("TIMER_END") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("LOCK_TIME") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SQL_TEXT") }, + { C_STRING_WITH_LEN("longtext") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("DIGEST") }, + { C_STRING_WITH_LEN("varchar(32)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("DIGEST_TEXT") }, + { C_STRING_WITH_LEN("longtext") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("CURRENT_SCHEMA") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_TYPE") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_NAME") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MYSQL_ERRNO") }, + { C_STRING_WITH_LEN("int(11)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("RETURNED_SQLSTATE") }, + { C_STRING_WITH_LEN("varchar(5)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MESSAGE_TEXT") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("ERRORS") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("WARNINGS") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("ROWS_AFFECTED") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("ROWS_SENT") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("ROWS_EXAMINED") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("CREATED_TMP_DISK_TABLES") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("CREATED_TMP_TABLES") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SELECT_FULL_JOIN") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SELECT_FULL_RANGE_JOIN") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SELECT_RANGE") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SELECT_RANGE_CHECK") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SELECT_SCAN") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SORT_MERGE_PASSES") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SORT_RANGE") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SORT_ROWS") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SORT_SCAN") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("NO_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("NO_GOOD_INDEX_USED") }, + { C_STRING_WITH_LEN("bigint") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("NESTING_EVENT_ID") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("NESTING_EVENT_TYPE") }, + { C_STRING_WITH_LEN("enum(\'STATEMENT\',\'STAGE\',\'WAIT\'") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_events_statements_current::m_field_def= +{40 , field_types }; + +PFS_engine_table_share +table_events_statements_current::m_share= +{ + { C_STRING_WITH_LEN("events_statements_current") }, + &pfs_truncatable_acl, + &table_events_statements_current::create, + NULL, /* write_row */ + &table_events_statements_current::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), /* ref length */ + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +THR_LOCK table_events_statements_history::m_table_lock; + +PFS_engine_table_share +table_events_statements_history::m_share= +{ + { C_STRING_WITH_LEN("events_statements_history") }, + &pfs_truncatable_acl, + &table_events_statements_history::create, + NULL, /* write_row */ + &table_events_statements_history::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_events_statements_history), /* ref length */ + &m_table_lock, + &table_events_statements_current::m_field_def, + false /* checked */ +}; + +THR_LOCK table_events_statements_history_long::m_table_lock; + +PFS_engine_table_share +table_events_statements_history_long::m_share= +{ + { C_STRING_WITH_LEN("events_statements_history_long") }, + &pfs_truncatable_acl, + &table_events_statements_history_long::create, + NULL, /* write_row */ + &table_events_statements_history_long::delete_all_rows, + NULL, /* get_row_count */ + 10000, /* records */ + sizeof(PFS_simple_index), /* ref length */ + &m_table_lock, + &table_events_statements_current::m_field_def, + false /* checked */ +}; + +table_events_statements_common::table_events_statements_common +(const PFS_engine_table_share *share, void *pos) + : PFS_engine_table(share, pos), + m_row_exists(false) +{} + +/** + Build a row. + @param statement the statement the cursor is reading +*/ +void table_events_statements_common::make_row(PFS_events_statements *statement) +{ + const char *base; + const char *safe_source_file; + + m_row_exists= false; + + PFS_statement_class *unsafe= (PFS_statement_class*) statement->m_class; + PFS_statement_class *klass= sanitize_statement_class(unsafe); + if (unlikely(klass == NULL)) + return; + + m_row.m_thread_internal_id= statement->m_thread_internal_id; + m_row.m_event_id= statement->m_event_id; + m_row.m_end_event_id= statement->m_end_event_id; + m_row.m_nesting_event_id= statement->m_nesting_event_id; + m_row.m_nesting_event_type= statement->m_nesting_event_type; + + m_normalizer->to_pico(statement->m_timer_start, statement->m_timer_end, + & m_row.m_timer_start, & m_row.m_timer_end, & m_row.m_timer_wait); + m_row.m_lock_time= statement->m_lock_time * MICROSEC_TO_PICOSEC; + + m_row.m_name= klass->m_name; + m_row.m_name_length= klass->m_name_length; + + m_row.m_sqltext_length= statement->m_sqltext_length; + if (m_row.m_sqltext_length > 0) + memcpy(m_row.m_sqltext, statement->m_sqltext, m_row.m_sqltext_length); + + m_row.m_current_schema_name_length= statement->m_current_schema_name_length; + if (m_row.m_current_schema_name_length > 0) + memcpy(m_row.m_current_schema_name, statement->m_current_schema_name, m_row.m_current_schema_name_length); + + safe_source_file= statement->m_source_file; + if (unlikely(safe_source_file == NULL)) + return; + + base= base_name(safe_source_file); + m_row.m_source_length= my_snprintf(m_row.m_source, sizeof(m_row.m_source), + "%s:%d", base, statement->m_source_line); + if (m_row.m_source_length > sizeof(m_row.m_source)) + m_row.m_source_length= sizeof(m_row.m_source); + + memcpy(m_row.m_message_text, statement->m_message_text, sizeof(m_row.m_message_text)); + m_row.m_sql_errno= statement->m_sql_errno; + memcpy(m_row.m_sqlstate, statement->m_sqlstate, SQLSTATE_LENGTH); + m_row.m_error_count= statement->m_error_count; + m_row.m_warning_count= statement->m_warning_count; + m_row.m_rows_affected= statement->m_rows_affected; + + m_row.m_rows_sent= statement->m_rows_sent; + m_row.m_rows_examined= statement->m_rows_examined; + m_row.m_created_tmp_disk_tables= statement->m_created_tmp_disk_tables; + m_row.m_created_tmp_tables= statement->m_created_tmp_tables; + m_row.m_select_full_join= statement->m_select_full_join; + m_row.m_select_full_range_join= statement->m_select_full_range_join; + m_row.m_select_range= statement->m_select_range; + m_row.m_select_range_check= statement->m_select_range_check; + m_row.m_select_scan= statement->m_select_scan; + m_row.m_sort_merge_passes= statement->m_sort_merge_passes; + m_row.m_sort_range= statement->m_sort_range; + m_row.m_sort_rows= statement->m_sort_rows; + m_row.m_sort_scan= statement->m_sort_scan; + m_row.m_no_index_used= statement->m_no_index_used; + m_row.m_no_good_index_used= statement->m_no_good_index_used; + /* + Filling up statement digest information. + */ + PSI_digest_storage *digest= & statement->m_digest_storage; + if (digest->m_byte_count > 0) + { + PFS_digest_hash md5; + compute_md5_hash((char *) md5.m_md5, + (char *) digest->m_token_array, + digest->m_byte_count); + + /* Generate the DIGEST string from the MD5 digest */ + MD5_HASH_TO_STRING(md5.m_md5, + m_row.m_digest.m_digest); + m_row.m_digest.m_digest_length= MD5_HASH_TO_STRING_LENGTH; + + /* Generate the DIGEST_TEXT string from the token array */ + get_digest_text(m_row.m_digest.m_digest_text, digest); + m_row.m_digest.m_digest_text_length= strlen(m_row.m_digest.m_digest_text); + } + else + { + m_row.m_digest.m_digest_length= 0; + m_row.m_digest.m_digest_text_length= 0; + } + + m_row_exists= true; + return; +} + +int table_events_statements_common::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + uint len; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 3); + buf[0]= 0; + buf[1]= 0; + buf[2]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* THREAD_ID */ + set_field_ulong(f, m_row.m_thread_internal_id); + break; + case 1: /* EVENT_ID */ + set_field_ulonglong(f, m_row.m_event_id); + break; + case 2: /* END_EVENT_ID */ + if (m_row.m_end_event_id > 0) + set_field_ulonglong(f, m_row.m_end_event_id - 1); + else + f->set_null(); + break; + case 3: /* EVENT_NAME */ + set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length); + break; + case 4: /* SOURCE */ + set_field_varchar_utf8(f, m_row.m_source, m_row.m_source_length); + break; + case 5: /* TIMER_START */ + if (m_row.m_timer_start != 0) + set_field_ulonglong(f, m_row.m_timer_start); + else + f->set_null(); + break; + case 6: /* TIMER_END */ + if (m_row.m_timer_end != 0) + set_field_ulonglong(f, m_row.m_timer_end); + else + f->set_null(); + break; + case 7: /* TIMER_WAIT */ + if (m_row.m_timer_wait != 0) + set_field_ulonglong(f, m_row.m_timer_wait); + else + f->set_null(); + break; + case 8: /* LOCK_TIME */ + if (m_row.m_lock_time != 0) + set_field_ulonglong(f, m_row.m_lock_time); + else + f->set_null(); + break; + case 9: /* SQL_TEXT */ + if (m_row.m_sqltext_length) + set_field_longtext_utf8(f, m_row.m_sqltext, m_row.m_sqltext_length); + else + f->set_null(); + break; + case 10: /* DIGEST */ + if (m_row.m_digest.m_digest_length > 0) + set_field_varchar_utf8(f, m_row.m_digest.m_digest, + m_row.m_digest.m_digest_length); + else + f->set_null(); + break; + case 11: /* DIGEST_TEXT */ + if (m_row.m_digest.m_digest_text_length > 0) + set_field_longtext_utf8(f, m_row.m_digest.m_digest_text, + m_row.m_digest.m_digest_text_length); + else + f->set_null(); + break; + case 12: /* CURRENT_SCHEMA */ + if (m_row.m_current_schema_name_length) + set_field_varchar_utf8(f, m_row.m_current_schema_name, m_row.m_current_schema_name_length); + else + f->set_null(); + break; + case 13: /* OBJECT_TYPE */ + f->set_null(); + break; + case 14: /* OBJECT_SCHEMA */ + f->set_null(); + break; + case 15: /* OBJECT_NAME */ + f->set_null(); + break; + case 16: /* OBJECT_INSTANCE_BEGIN */ + f->set_null(); + break; + case 17: /* MYSQL_ERRNO */ + set_field_ulong(f, m_row.m_sql_errno); + break; + case 18: /* RETURNED_SQLSTATE */ + if (m_row.m_sqlstate[0] != 0) + set_field_varchar_utf8(f, m_row.m_sqlstate, SQLSTATE_LENGTH); + else + f->set_null(); + break; + case 19: /* MESSAGE_TEXT */ + len= strlen(m_row.m_message_text); + if (len) + set_field_varchar_utf8(f, m_row.m_message_text, len); + else + f->set_null(); + break; + case 20: /* ERRORS */ + set_field_ulonglong(f, m_row.m_error_count); + break; + case 21: /* WARNINGS */ + set_field_ulonglong(f, m_row.m_warning_count); + break; + case 22: /* ROWS_AFFECTED */ + set_field_ulonglong(f, m_row.m_rows_affected); + break; + case 23: /* ROWS_SENT */ + set_field_ulonglong(f, m_row.m_rows_sent); + break; + case 24: /* ROWS_EXAMINED */ + set_field_ulonglong(f, m_row.m_rows_examined); + break; + case 25: /* CREATED_TMP_DISK_TABLES */ + set_field_ulonglong(f, m_row.m_created_tmp_disk_tables); + break; + case 26: /* CREATED_TMP_TABLES */ + set_field_ulonglong(f, m_row.m_created_tmp_tables); + break; + case 27: /* SELECT_FULL_JOIN */ + set_field_ulonglong(f, m_row.m_select_full_join); + break; + case 28: /* SELECT_FULL_RANGE_JOIN */ + set_field_ulonglong(f, m_row.m_select_full_range_join); + break; + case 29: /* SELECT_RANGE */ + set_field_ulonglong(f, m_row.m_select_range); + break; + case 30: /* SELECT_RANGE_CHECK */ + set_field_ulonglong(f, m_row.m_select_range_check); + break; + case 31: /* SELECT_SCAN */ + set_field_ulonglong(f, m_row.m_select_scan); + break; + case 32: /* SORT_MERGE_PASSES */ + set_field_ulonglong(f, m_row.m_sort_merge_passes); + break; + case 33: /* SORT_RANGE */ + set_field_ulonglong(f, m_row.m_sort_range); + break; + case 34: /* SORT_ROWS */ + set_field_ulonglong(f, m_row.m_sort_rows); + break; + case 35: /* SORT_SCAN */ + set_field_ulonglong(f, m_row.m_sort_scan); + break; + case 36: /* NO_INDEX_USED */ + set_field_ulonglong(f, m_row.m_no_index_used); + break; + case 37: /* NO_GOOD_INDEX_USED */ + set_field_ulonglong(f, m_row.m_no_good_index_used); + break; + case 38: /* NESTING_EVENT_ID */ + if (m_row.m_nesting_event_id != 0) + set_field_ulonglong(f, m_row.m_nesting_event_id); + else + f->set_null(); + break; + case 39: /* NESTING_EVENT_TYPE */ + if (m_row.m_nesting_event_id != 0) + set_field_enum(f, m_row.m_nesting_event_type); + else + f->set_null(); + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} + +PFS_engine_table* table_events_statements_current::create(void) +{ + return new table_events_statements_current(); +} + +table_events_statements_current::table_events_statements_current() + : table_events_statements_common(&m_share, &m_pos), + m_pos(), m_next_pos() +{} + +void table_events_statements_current::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_events_statements_current::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(statement_timer); + return 0; +} + +int table_events_statements_current::rnd_next(void) +{ + PFS_thread *pfs_thread; + PFS_events_statements *statement; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index_1 < thread_max; + m_pos.next_thread()) + { + pfs_thread= &thread_array[m_pos.m_index_1]; + + if (! pfs_thread->m_lock.is_populated()) + { + /* This thread does not exist */ + continue; + } + + uint safe_events_statements_count= pfs_thread->m_events_statements_count; + + if (safe_events_statements_count == 0) + { + /* Display the last top level statement, when completed */ + if (m_pos.m_index_2 >= 1) + continue; + } + else + { + /* Display all pending statements, when in progress */ + if (m_pos.m_index_2 >= safe_events_statements_count) + continue; + } + + statement= &pfs_thread->m_statement_stack[m_pos.m_index_2]; + + make_row(statement); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int table_events_statements_current::rnd_pos(const void *pos) +{ + PFS_thread *pfs_thread; + PFS_events_statements *statement; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < thread_max); + pfs_thread= &thread_array[m_pos.m_index_1]; + + if (! pfs_thread->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + uint safe_events_statements_count= pfs_thread->m_events_statements_count; + + if (safe_events_statements_count == 0) + { + /* Display the last top level statement, when completed */ + if (m_pos.m_index_2 >= 1) + return HA_ERR_RECORD_DELETED; + } + else + { + /* Display all pending statements, when in progress */ + if (m_pos.m_index_2 >= safe_events_statements_count) + return HA_ERR_RECORD_DELETED; + } + + DBUG_ASSERT(m_pos.m_index_2 < statement_stack_max); + + statement= &pfs_thread->m_statement_stack[m_pos.m_index_2]; + + if (statement->m_class == NULL) + return HA_ERR_RECORD_DELETED; + + make_row(statement); + return 0; +} + +int table_events_statements_current::delete_all_rows(void) +{ + reset_events_statements_current(); + return 0; +} + +PFS_engine_table* table_events_statements_history::create(void) +{ + return new table_events_statements_history(); +} + +table_events_statements_history::table_events_statements_history() + : table_events_statements_common(&m_share, &m_pos), + m_pos(), m_next_pos() +{} + +void table_events_statements_history::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_events_statements_history::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(statement_timer); + return 0; +} + +int table_events_statements_history::rnd_next(void) +{ + PFS_thread *pfs_thread; + PFS_events_statements *statement; + + if (events_statements_history_per_thread == 0) + return HA_ERR_END_OF_FILE; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index_1 < thread_max; + m_pos.next_thread()) + { + pfs_thread= &thread_array[m_pos.m_index_1]; + + if (! pfs_thread->m_lock.is_populated()) + { + /* This thread does not exist */ + continue; + } + + if (m_pos.m_index_2 >= events_statements_history_per_thread) + { + /* This thread does not have more (full) history */ + continue; + } + + if ( ! pfs_thread->m_statements_history_full && + (m_pos.m_index_2 >= pfs_thread->m_statements_history_index)) + { + /* This thread does not have more (not full) history */ + continue; + } + + statement= &pfs_thread->m_statements_history[m_pos.m_index_2]; + + if (statement->m_class != NULL) + { + make_row(statement); + /* Next iteration, look for the next history in this thread */ + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_events_statements_history::rnd_pos(const void *pos) +{ + PFS_thread *pfs_thread; + PFS_events_statements *statement; + + DBUG_ASSERT(events_statements_history_per_thread != 0); + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < thread_max); + pfs_thread= &thread_array[m_pos.m_index_1]; + + if (! pfs_thread->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + DBUG_ASSERT(m_pos.m_index_2 < events_statements_history_per_thread); + + if ( ! pfs_thread->m_statements_history_full && + (m_pos.m_index_2 >= pfs_thread->m_statements_history_index)) + return HA_ERR_RECORD_DELETED; + + statement= &pfs_thread->m_statements_history[m_pos.m_index_2]; + + if (statement->m_class == NULL) + return HA_ERR_RECORD_DELETED; + + make_row(statement); + return 0; +} + +int table_events_statements_history::delete_all_rows(void) +{ + reset_events_statements_history(); + return 0; +} + +PFS_engine_table* table_events_statements_history_long::create(void) +{ + return new table_events_statements_history_long(); +} + +table_events_statements_history_long::table_events_statements_history_long() + : table_events_statements_common(&m_share, &m_pos), + m_pos(0), m_next_pos(0) +{} + +void table_events_statements_history_long::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_events_statements_history_long::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(statement_timer); + return 0; +} + +int table_events_statements_history_long::rnd_next(void) +{ + PFS_events_statements *statement; + uint limit; + + if (events_statements_history_long_size == 0) + return HA_ERR_END_OF_FILE; + + if (events_statements_history_long_full) + limit= events_statements_history_long_size; + else + limit= events_statements_history_long_index % events_statements_history_long_size; + + for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next()) + { + statement= &events_statements_history_long_array[m_pos.m_index]; + + if (statement->m_class != NULL) + { + make_row(statement); + /* Next iteration, look for the next entry */ + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_events_statements_history_long::rnd_pos(const void *pos) +{ + PFS_events_statements *statement; + uint limit; + + if (events_statements_history_long_size == 0) + return HA_ERR_RECORD_DELETED; + + set_position(pos); + + if (events_statements_history_long_full) + limit= events_statements_history_long_size; + else + limit= events_statements_history_long_index % events_statements_history_long_size; + + if (m_pos.m_index >= limit) + return HA_ERR_RECORD_DELETED; + + statement= &events_statements_history_long_array[m_pos.m_index]; + + if (statement->m_class == NULL) + return HA_ERR_RECORD_DELETED; + + make_row(statement); + return 0; +} + +int table_events_statements_history_long::delete_all_rows(void) +{ + reset_events_statements_history_long(); + return 0; +} + diff --git a/storage/perfschema/table_events_statements.h b/storage/perfschema/table_events_statements.h new file mode 100644 index 00000000000..acd82de4fcf --- /dev/null +++ b/storage/perfschema/table_events_statements.h @@ -0,0 +1,288 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_EVENTS_STATEMENTS_H +#define TABLE_EVENTS_STATEMENTS_H + +/** + @file storage/perfschema/table_events_statements.h + Table EVENTS_STATEMENTS_xxx (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_events_statements.h" +#include "table_helper.h" + +struct PFS_thread; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of table_events_statements_common. */ +struct row_events_statements +{ + /** Column THREAD_ID. */ + ulong m_thread_internal_id; + /** Column EVENT_ID. */ + ulonglong m_event_id; + /** Column END_EVENT_ID. */ + ulonglong m_end_event_id; + /** Column NESTING_EVENT_ID. */ + ulonglong m_nesting_event_id; + /** Column NESTING_EVENT_TYPE. */ + enum_event_type m_nesting_event_type; + /** Column EVENT_NAME. */ + const char *m_name; + /** Length in bytes of @c m_name. */ + uint m_name_length; + /** Column TIMER_START. */ + ulonglong m_timer_start; + /** Column TIMER_END. */ + ulonglong m_timer_end; + /** Column TIMER_WAIT. */ + ulonglong m_timer_wait; + /** Column LOCK_TIME. */ + ulonglong m_lock_time; + /** Column SOURCE. */ + char m_source[COL_SOURCE_SIZE]; + /** Length in bytes of @c m_source. */ + uint m_source_length; + /** Column SQL_TEXT. */ + char m_sqltext[COL_INFO_SIZE]; + /** Column DIGEST and DIGEST_TEXT. */ + PFS_digest_row m_digest; + /** Length in bytes of @c m_info. */ + uint m_sqltext_length; + /** Column CURRENT_SCHEMA. */ + char m_current_schema_name[NAME_LEN]; + /** Length in bytes of @c m_current_schema_name. */ + uint m_current_schema_name_length; + + /** Column MESSAGE_TEXT. */ + char m_message_text[MYSQL_ERRMSG_SIZE+1]; + /** Column MYSQL_ERRNO. */ + uint m_sql_errno; + /** Column RETURNED_SQLSTATE. */ + char m_sqlstate[SQLSTATE_LENGTH]; + /** Column ERRORS. */ + uint m_error_count; + /** Column WARNINGS. */ + uint m_warning_count; + /** Column ROWS_AFFECTED. */ + ulonglong m_rows_affected; + /** Column ROWS_SENT. */ + ulonglong m_rows_sent; + /** Column ROWS_EXAMINED. */ + ulonglong m_rows_examined; + /** Column CREATED_TMP_DISK_TABLES. */ + ulonglong m_created_tmp_disk_tables; + /** Column CREATED_TMP_TABLES. */ + ulonglong m_created_tmp_tables; + /** Column SELECT_FULL_JOIN. */ + ulonglong m_select_full_join; + /** Column SELECT_FULL_RANGE_JOIN. */ + ulonglong m_select_full_range_join; + /** Column SELECT_RANGE. */ + ulonglong m_select_range; + /** Column SELECT_RANGE_CHECK. */ + ulonglong m_select_range_check; + /** Column SELECT_SCAN. */ + ulonglong m_select_scan; + /** Column SORT_MERGE_PASSES. */ + ulonglong m_sort_merge_passes; + /** Column SORT_RANGE. */ + ulonglong m_sort_range; + /** Column SORT_ROWS. */ + ulonglong m_sort_rows; + /** Column SORT_SCAN. */ + ulonglong m_sort_scan; + /** Column NO_INDEX_USED. */ + ulonglong m_no_index_used; + /** Column NO_GOOD_INDEX_USED. */ + ulonglong m_no_good_index_used; +}; + +/** Position of a cursor on PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_CURRENT. */ +struct pos_events_statements_current : public PFS_double_index +{ + pos_events_statements_current() + : PFS_double_index(0, 0) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 0; + } + + inline void next_thread(void) + { + m_index_1++; + m_index_2= 0; + } +}; + +/** Position of a cursor on PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_HISTORY. */ +struct pos_events_statements_history : public PFS_double_index +{ + pos_events_statements_history() + : PFS_double_index(0, 0) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 0; + } + + inline void next_thread(void) + { + m_index_1++; + m_index_2= 0; + } +}; + +/** + Adapter, for table sharing the structure of + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_CURRENT. +*/ +class table_events_statements_common : public PFS_engine_table +{ +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_events_statements_common(const PFS_engine_table_share *share, void *pos); + + ~table_events_statements_common() + {} + + void make_row(PFS_events_statements *statement); + + /** Current row. */ + row_events_statements m_row; + /** True if the current row exists. */ + bool m_row_exists; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_CURRENT. */ +class table_events_statements_current : public table_events_statements_common +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + table_events_statements_current(); + +public: + ~table_events_statements_current() + {} + +private: + friend class table_events_statements_history; + friend class table_events_statements_history_long; + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** + Fields definition. + Also used by table_events_statements_history + and table_events_statements_history_long. + */ + static TABLE_FIELD_DEF m_field_def; + + /** Current position. */ + pos_events_statements_current m_pos; + /** Next position. */ + pos_events_statements_current m_next_pos; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_HISTORY. */ +class table_events_statements_history : public table_events_statements_common +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + table_events_statements_history(); + +public: + ~table_events_statements_history() + {} + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + + /** Current position. */ + pos_events_statements_history m_pos; + /** Next position. */ + pos_events_statements_history m_next_pos; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_HISTORY_LONG. */ +class table_events_statements_history_long : public table_events_statements_common +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + table_events_statements_history_long(); + +public: + ~table_events_statements_history_long() + {} + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_events_waits.cc b/storage/perfschema/table_events_waits.cc index 8408cc55975..d1c82e81f75 100644 --- a/storage/perfschema/table_events_waits.cc +++ b/storage/perfschema/table_events_waits.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 @@ -21,9 +21,12 @@ #include "my_global.h" #include "my_pthread.h" #include "table_events_waits.h" +#include "pfs_global.h" #include "pfs_instr_class.h" #include "pfs_instr.h" #include "pfs_events_waits.h" +#include "pfs_timer.h" +#include "m_string.h" THR_LOCK table_events_waits_current::m_table_lock; @@ -40,6 +43,11 @@ static const TABLE_FIELD_TYPE field_types[]= { NULL, 0} }, { + { C_STRING_WITH_LEN("END_EVENT_ID") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { { C_STRING_WITH_LEN("EVENT_NAME") }, { C_STRING_WITH_LEN("varchar(128)") }, { NULL, 0} @@ -80,6 +88,11 @@ static const TABLE_FIELD_TYPE field_types[]= { NULL, 0} }, { + { C_STRING_WITH_LEN("INDEX_NAME") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { { C_STRING_WITH_LEN("OBJECT_TYPE") }, { C_STRING_WITH_LEN("varchar(64)") }, { NULL, 0} @@ -95,8 +108,13 @@ static const TABLE_FIELD_TYPE field_types[]= { NULL, 0} }, { + { C_STRING_WITH_LEN("NESTING_EVENT_TYPE") }, + { C_STRING_WITH_LEN("enum(\'STATEMENT\',\'STAGE\',\'WAIT\'") }, + { NULL, 0} + }, + { { C_STRING_WITH_LEN("OPERATION") }, - { C_STRING_WITH_LEN("varchar(16)") }, + { C_STRING_WITH_LEN("varchar(32)") }, { NULL, 0} }, { @@ -113,7 +131,7 @@ static const TABLE_FIELD_TYPE field_types[]= TABLE_FIELD_DEF table_events_waits_current::m_field_def= -{ 16, field_types }; +{ 19, field_types }; PFS_engine_table_share table_events_waits_current::m_share= @@ -123,6 +141,7 @@ table_events_waits_current::m_share= &table_events_waits_current::create, NULL, /* write_row */ &table_events_waits_current::delete_all_rows, + NULL, /* get_row_count */ 1000, /* records */ sizeof(pos_events_waits_current), /* ref length */ &m_table_lock, @@ -140,6 +159,7 @@ table_events_waits_history::m_share= &table_events_waits_history::create, NULL, /* write_row */ &table_events_waits_history::delete_all_rows, + NULL, /* get_row_count */ 1000, /* records */ sizeof(pos_events_waits_history), /* ref length */ &m_table_lock, @@ -157,6 +177,7 @@ table_events_waits_history_long::m_share= &table_events_waits_history_long::create, NULL, /* write_row */ &table_events_waits_history_long::delete_all_rows, + NULL, /* get_row_count */ 10000, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, @@ -176,6 +197,153 @@ void table_events_waits_common::clear_object_columns() m_row.m_object_type_length= 0; m_row.m_object_schema_length= 0; m_row.m_object_name_length= 0; + m_row.m_index_name_length= 0; + m_row.m_object_instance_addr= 0; +} + +int table_events_waits_common::make_table_object_columns(volatile PFS_events_waits *wait) +{ + uint safe_index; + PFS_table_share *safe_table_share; + + safe_table_share= sanitize_table_share(wait->m_weak_table_share); + if (unlikely(safe_table_share == NULL)) + return 1; + + if (wait->m_object_type == OBJECT_TYPE_TABLE) + { + m_row.m_object_type= "TABLE"; + m_row.m_object_type_length= 5; + } + else + { + m_row.m_object_type= "TEMPORARY TABLE"; + m_row.m_object_type_length= 15; + } + + if (safe_table_share->get_version() == wait->m_weak_version) + { + /* OBJECT SCHEMA */ + m_row.m_object_schema_length= safe_table_share->m_schema_name_length; + if (unlikely((m_row.m_object_schema_length == 0) || + (m_row.m_object_schema_length > sizeof(m_row.m_object_schema)))) + return 1; + memcpy(m_row.m_object_schema, safe_table_share->m_schema_name, m_row.m_object_schema_length); + + /* OBJECT NAME */ + m_row.m_object_name_length= safe_table_share->m_table_name_length; + if (unlikely((m_row.m_object_name_length == 0) || + (m_row.m_object_name_length > sizeof(m_row.m_object_name)))) + return 1; + memcpy(m_row.m_object_name, safe_table_share->m_table_name, m_row.m_object_name_length); + + /* INDEX NAME */ + safe_index= wait->m_index; + if (safe_index < MAX_KEY && safe_index < safe_table_share->m_key_count) + { + PFS_table_key *key= & safe_table_share->m_keys[safe_index]; + m_row.m_index_name_length= key->m_name_length; + if (unlikely((m_row.m_index_name_length == 0) || + (m_row.m_index_name_length > sizeof(m_row.m_index_name)))) + return 1; + memcpy(m_row.m_index_name, key->m_name, m_row.m_index_name_length); + } + else + m_row.m_index_name_length= 0; + } + else + { + m_row.m_object_schema_length= 0; + m_row.m_object_name_length= 0; + m_row.m_index_name_length= 0; + } + + m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; + return 0; +} + +int table_events_waits_common::make_file_object_columns(volatile PFS_events_waits *wait) +{ + PFS_file *safe_file; + + safe_file= sanitize_file(wait->m_weak_file); + if (unlikely(safe_file == NULL)) + return 1; + + m_row.m_object_type= "FILE"; + m_row.m_object_type_length= 4; + m_row.m_object_schema_length= 0; + m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; + + if (safe_file->get_version() == wait->m_weak_version) + { + /* OBJECT NAME */ + m_row.m_object_name_length= safe_file->m_filename_length; + if (unlikely((m_row.m_object_name_length == 0) || + (m_row.m_object_name_length > sizeof(m_row.m_object_name)))) + return 1; + memcpy(m_row.m_object_name, safe_file->m_filename, m_row.m_object_name_length); + } + else + { + m_row.m_object_name_length= 0; + } + + m_row.m_index_name_length= 0; + + return 0; +} + +int table_events_waits_common::make_socket_object_columns(volatile PFS_events_waits *wait) +{ + PFS_socket *safe_socket; + + safe_socket= sanitize_socket(wait->m_weak_socket); + if (unlikely(safe_socket == NULL)) + return 1; + + m_row.m_object_type= "SOCKET"; + m_row.m_object_type_length= 6; + m_row.m_object_schema_length= 0; + m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; + + if (safe_socket->get_version() == wait->m_weak_version) + { + /* Convert port number to string, include delimiter in port name length */ + + uint port; + char port_str[128]; + char ip_str[INET6_ADDRSTRLEN+1]; + uint ip_len= 0; + port_str[0]= ':'; + + /* Get the IP address and port number */ + ip_len= pfs_get_socket_address(ip_str, sizeof(ip_str), &port, + &safe_socket->m_sock_addr, + safe_socket->m_addr_len); + + /* Convert port number to a string (length includes ':') */ + int port_len= int10_to_str(port, (port_str+1), 10) - port_str + 1; + + /* OBJECT NAME */ + m_row.m_object_name_length= ip_len + port_len; + + if (unlikely((m_row.m_object_name_length == 0) || + (m_row.m_object_name_length > sizeof(m_row.m_object_name)))) + return 1; + + char *name= m_row.m_object_name; + memcpy(name, ip_str, ip_len); + memcpy(name + ip_len, port_str, port_len); + } + else + { + m_row.m_object_name_length= 0; + } + + m_row.m_index_name_length= 0; + + return 0; } /** @@ -194,9 +362,6 @@ void table_events_waits_common::make_row(bool thread_own_wait, PFS_instr_class *safe_class; const char *base; const char *safe_source_file; - const char *safe_table_schema_name; - const char *safe_table_object_name; - const char *safe_file_name; m_row_exists= false; safe_thread= sanitize_thread(pfs_thread); @@ -224,13 +389,6 @@ void table_events_waits_common::make_row(bool thread_own_wait, and sanitizes all the data before returning a row. */ - m_row.m_thread_internal_id= safe_thread->m_thread_internal_id; - m_row.m_event_id= wait->m_event_id; - m_row.m_timer_state= wait->m_timer_state; - m_row.m_timer_start= wait->m_timer_start; - m_row.m_timer_end= wait->m_timer_end; - m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; - /* PFS_events_waits::m_class needs to be sanitized, for race conditions when this code: @@ -239,6 +397,10 @@ void table_events_waits_common::make_row(bool thread_own_wait, */ switch (wait->m_wait_class) { + case WAIT_CLASS_IDLE: + clear_object_columns(); + safe_class= sanitize_idle_class(wait->m_class); + break; case WAIT_CLASS_MUTEX: clear_object_columns(); safe_class= sanitize_mutex_class((PFS_mutex_class*) wait->m_class); @@ -252,43 +414,38 @@ void table_events_waits_common::make_row(bool thread_own_wait, safe_class= sanitize_cond_class((PFS_cond_class*) wait->m_class); break; case WAIT_CLASS_TABLE: - m_row.m_object_type= "TABLE"; - m_row.m_object_type_length= 5; - m_row.m_object_schema_length= wait->m_schema_name_length; - safe_table_schema_name= sanitize_table_schema_name(wait->m_schema_name); - if (unlikely((m_row.m_object_schema_length == 0) || - (m_row.m_object_schema_length > sizeof(m_row.m_object_schema)) || - (safe_table_schema_name == NULL))) - return; - memcpy(m_row.m_object_schema, safe_table_schema_name, m_row.m_object_schema_length); - m_row.m_object_name_length= wait->m_object_name_length; - safe_table_object_name= sanitize_table_object_name(wait->m_object_name); - if (unlikely((m_row.m_object_name_length == 0) || - (m_row.m_object_name_length > sizeof(m_row.m_object_name)) || - (safe_table_object_name == NULL))) + if (make_table_object_columns(wait)) return; - memcpy(m_row.m_object_name, safe_table_object_name, m_row.m_object_name_length); - safe_class= &global_table_class; + safe_class= sanitize_table_class(wait->m_class); break; case WAIT_CLASS_FILE: - m_row.m_object_type= "FILE"; - m_row.m_object_type_length= 4; - m_row.m_object_schema_length= 0; - m_row.m_object_name_length= wait->m_object_name_length; - safe_file_name= sanitize_file_name(wait->m_object_name); - if (unlikely((m_row.m_object_name_length == 0) || - (m_row.m_object_name_length > sizeof(m_row.m_object_name)) || - (safe_file_name == NULL))) + if (make_file_object_columns(wait)) return; - memcpy(m_row.m_object_name, safe_file_name, m_row.m_object_name_length); safe_class= sanitize_file_class((PFS_file_class*) wait->m_class); break; + case WAIT_CLASS_SOCKET: + if (make_socket_object_columns(wait)) + return; + safe_class= sanitize_socket_class((PFS_socket_class*) wait->m_class); + break; case NO_WAIT_CLASS: default: return; } + if (unlikely(safe_class == NULL)) return; + + m_row.m_thread_internal_id= safe_thread->m_thread_internal_id; + m_row.m_event_id= wait->m_event_id; + m_row.m_end_event_id= wait->m_end_event_id; + m_row.m_nesting_event_id= wait->m_nesting_event_id; + m_row.m_nesting_event_type= wait->m_nesting_event_type; + + get_normalizer(safe_class); + m_normalizer->to_pico(wait->m_timer_start, wait->m_timer_end, + & m_row.m_timer_start, & m_row.m_timer_end, & m_row.m_timer_wait); + m_row.m_name= safe_class->m_name; m_row.m_name_length= safe_class->m_name_length; @@ -307,7 +464,7 @@ void table_events_waits_common::make_row(bool thread_own_wait, m_row.m_source_length= sizeof(m_row.m_source); m_row.m_operation= wait->m_operation; m_row.m_number_of_bytes= wait->m_number_of_bytes; - m_row.m_flags= 0; + m_row.m_flags= wait->m_flags; if (thread_own_wait) { @@ -368,7 +525,46 @@ static const LEX_STRING operation_names_map[]= { C_STRING_WITH_LEN("chsize") }, { C_STRING_WITH_LEN("delete") }, { C_STRING_WITH_LEN("rename") }, - { C_STRING_WITH_LEN("sync") } + { C_STRING_WITH_LEN("sync") }, + + /* Table io operations */ + { C_STRING_WITH_LEN("fetch") }, + { C_STRING_WITH_LEN("insert") }, /* write row */ + { C_STRING_WITH_LEN("update") }, /* update row */ + { C_STRING_WITH_LEN("delete") }, /* delete row */ + + /* Table lock operations */ + { C_STRING_WITH_LEN("read normal") }, + { C_STRING_WITH_LEN("read with shared locks") }, + { C_STRING_WITH_LEN("read high priority") }, + { C_STRING_WITH_LEN("read no inserts") }, + { C_STRING_WITH_LEN("write allow write") }, + { C_STRING_WITH_LEN("write concurrent insert") }, + { C_STRING_WITH_LEN("write delayed") }, + { C_STRING_WITH_LEN("write low priority") }, + { C_STRING_WITH_LEN("write normal") }, + { C_STRING_WITH_LEN("read external") }, + { C_STRING_WITH_LEN("write external") }, + + /* Socket operations */ + { C_STRING_WITH_LEN("create") }, + { C_STRING_WITH_LEN("connect") }, + { C_STRING_WITH_LEN("bind") }, + { C_STRING_WITH_LEN("close") }, + { C_STRING_WITH_LEN("send") }, + { C_STRING_WITH_LEN("recv") }, + { C_STRING_WITH_LEN("sendto") }, + { C_STRING_WITH_LEN("recvfrom") }, + { C_STRING_WITH_LEN("sendmsg") }, + { C_STRING_WITH_LEN("recvmsg") }, + { C_STRING_WITH_LEN("seek") }, + { C_STRING_WITH_LEN("opt") }, + { C_STRING_WITH_LEN("stat") }, + { C_STRING_WITH_LEN("shutdown") }, + { C_STRING_WITH_LEN("select") }, + + /* Idle operations */ + { C_STRING_WITH_LEN("idle") } }; @@ -411,35 +607,40 @@ int table_events_waits_common::read_row_values(TABLE *table, case 1: /* EVENT_ID */ set_field_ulonglong(f, m_row.m_event_id); break; - case 2: /* EVENT_NAME */ + case 2: /* END_EVENT_ID */ + if (m_row.m_end_event_id > 0) + set_field_ulonglong(f, m_row.m_end_event_id - 1); + else + f->set_null(); + break; + case 3: /* EVENT_NAME */ set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length); break; - case 3: /* SOURCE */ + case 4: /* SOURCE */ set_field_varchar_utf8(f, m_row.m_source, m_row.m_source_length); break; - case 4: /* TIMER_START */ - if ((m_row.m_timer_state == TIMER_STATE_STARTED) || - (m_row.m_timer_state == TIMER_STATE_TIMED)) + case 5: /* TIMER_START */ + if (m_row.m_timer_start != 0) set_field_ulonglong(f, m_row.m_timer_start); else f->set_null(); break; - case 5: /* TIMER_END */ - if (m_row.m_timer_state == TIMER_STATE_TIMED) + case 6: /* TIMER_END */ + if (m_row.m_timer_end != 0) set_field_ulonglong(f, m_row.m_timer_end); else f->set_null(); break; - case 6: /* TIMER_WAIT */ - if (m_row.m_timer_state == TIMER_STATE_TIMED) - set_field_ulonglong(f, m_row.m_timer_end - m_row.m_timer_start); + case 7: /* TIMER_WAIT */ + if (m_row.m_timer_wait != 0) + set_field_ulonglong(f, m_row.m_timer_wait); else f->set_null(); break; - case 7: /* SPINS */ + case 8: /* SPINS */ f->set_null(); break; - case 8: /* OBJECT_SCHEMA */ + case 9: /* OBJECT_SCHEMA */ if (m_row.m_object_schema_length > 0) { set_field_varchar_utf8(f, m_row.m_object_schema, @@ -448,7 +649,7 @@ int table_events_waits_common::read_row_values(TABLE *table, else f->set_null(); break; - case 9: /* OBJECT_NAME */ + case 10: /* OBJECT_NAME */ if (m_row.m_object_name_length > 0) { set_field_varchar_utf8(f, m_row.m_object_name, @@ -457,7 +658,16 @@ int table_events_waits_common::read_row_values(TABLE *table, else f->set_null(); break; - case 10: /* OBJECT_TYPE */ + case 11: /* INDEX_NAME */ + if (m_row.m_index_name_length > 0) + { + set_field_varchar_utf8(f, m_row.m_index_name, + m_row.m_index_name_length); + } + else + f->set_null(); + break; + case 12: /* OBJECT_TYPE */ if (m_row.m_object_type) { set_field_varchar_utf8(f, m_row.m_object_type, @@ -466,26 +676,39 @@ int table_events_waits_common::read_row_values(TABLE *table, else f->set_null(); break; - case 11: /* OBJECT_INSTANCE */ + case 13: /* OBJECT_INSTANCE */ set_field_ulonglong(f, m_row.m_object_instance_addr); break; - case 12: /* NESTING_EVENT_ID */ - f->set_null(); + case 14: /* NESTING_EVENT_ID */ + if (m_row.m_nesting_event_id != 0) + set_field_ulonglong(f, m_row.m_nesting_event_id); + else + f->set_null(); + break; + case 15: /* NESTING_EVENT_TYPE */ + if (m_row.m_nesting_event_id != 0) + set_field_enum(f, m_row.m_nesting_event_type); + else + f->set_null(); break; - case 13: /* OPERATION */ + case 16: /* OPERATION */ operation= &operation_names_map[(int) m_row.m_operation - 1]; set_field_varchar_utf8(f, operation->str, operation->length); break; - case 14: /* NUMBER_OF_BYTES */ + case 17: /* NUMBER_OF_BYTES */ if ((m_row.m_operation == OPERATION_TYPE_FILEREAD) || (m_row.m_operation == OPERATION_TYPE_FILEWRITE) || - (m_row.m_operation == OPERATION_TYPE_FILECHSIZE)) + (m_row.m_operation == OPERATION_TYPE_FILECHSIZE) || + (m_row.m_operation == OPERATION_TYPE_SOCKETSEND) || + (m_row.m_operation == OPERATION_TYPE_SOCKETRECV) || + (m_row.m_operation == OPERATION_TYPE_SOCKETSENDTO) || + (m_row.m_operation == OPERATION_TYPE_SOCKETRECVFROM)) set_field_ulonglong(f, m_row.m_number_of_bytes); else f->set_null(); break; - case 15: /* FLAGS */ - set_field_ulong(f, m_row.m_flags); + case 18: /* FLAGS */ + f->set_null(); break; default: DBUG_ASSERT(false); @@ -532,17 +755,31 @@ int table_events_waits_current::rnd_next(void) We do not show nested events for now, this will be revised with TABLE io */ -#define ONLY_SHOW_ONE_WAIT +// #define ONLY_SHOW_ONE_WAIT #ifdef ONLY_SHOW_ONE_WAIT if (m_pos.m_index_2 >= 1) continue; #else - if (m_pos.m_index_2 >= pfs_thread->m_wait_locker_count) - continue; -#endif + /* m_events_waits_stack[0] is a dummy record */ + PFS_events_waits *top_wait = &pfs_thread->m_events_waits_stack[WAIT_STACK_BOTTOM]; + wait= &pfs_thread->m_events_waits_stack[m_pos.m_index_2 + WAIT_STACK_BOTTOM]; - wait= &pfs_thread->m_wait_locker_stack[m_pos.m_index_2].m_waits_current; + PFS_events_waits *safe_current = pfs_thread->m_events_waits_current; + + if (safe_current == top_wait) + { + /* Display the last top level wait, when completed */ + if (m_pos.m_index_2 >= 1) + continue; + } + else + { + /* Display all pending waits, when in progress */ + if (wait >= safe_current) + continue; + } +#endif if (wait->m_wait_class == NO_WAIT_CLASS) { @@ -574,14 +811,31 @@ int table_events_waits_current::rnd_pos(const void *pos) if (! pfs_thread->m_lock.is_populated()) return HA_ERR_RECORD_DELETED; -#ifdef ONLY_SHOW_CURRENT_WAITS - if (m_pos.m_index_2 >= pfs_thread->m_wait_locker_count) +#ifdef ONLY_SHOW_ONE_WAIT + if (m_pos.m_index_2 >= 1) return HA_ERR_RECORD_DELETED; -#endif +#else + /* m_events_waits_stack[0] is a dummy record */ + PFS_events_waits *top_wait = &pfs_thread->m_events_waits_stack[WAIT_STACK_BOTTOM]; + wait= &pfs_thread->m_events_waits_stack[m_pos.m_index_2 + WAIT_STACK_BOTTOM]; - DBUG_ASSERT(m_pos.m_index_2 < LOCKER_STACK_SIZE); + PFS_events_waits *safe_current = pfs_thread->m_events_waits_current; + + if (safe_current == top_wait) + { + /* Display the last top level wait, when completed */ + if (m_pos.m_index_2 >= 1) + return HA_ERR_RECORD_DELETED; + } + else + { + /* Display all pending waits, when in progress */ + if (wait >= safe_current) + return HA_ERR_RECORD_DELETED; + } +#endif - wait= &pfs_thread->m_wait_locker_stack[m_pos.m_index_2].m_waits_current; + DBUG_ASSERT(m_pos.m_index_2 < WAIT_STACK_LOGICAL_SIZE); if (wait->m_wait_class == NO_WAIT_CLASS) return HA_ERR_RECORD_DELETED; @@ -685,12 +939,11 @@ int table_events_waits_history::rnd_pos(const void *pos) (m_pos.m_index_2 >= pfs_thread->m_waits_history_index)) return HA_ERR_RECORD_DELETED; - if (pfs_thread->m_waits_history[m_pos.m_index_2].m_wait_class - == NO_WAIT_CLASS) - return HA_ERR_RECORD_DELETED; - wait= &pfs_thread->m_waits_history[m_pos.m_index_2]; + if (wait->m_wait_class == NO_WAIT_CLASS) + return HA_ERR_RECORD_DELETED; + make_row(true, pfs_thread, wait); return 0; } diff --git a/storage/perfschema/table_events_waits.h b/storage/perfschema/table_events_waits.h index aa4edb4a368..72065c765ca 100644 --- a/storage/perfschema/table_events_waits.h +++ b/storage/perfschema/table_events_waits.h @@ -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 @@ -39,18 +39,22 @@ struct row_events_waits ulong m_thread_internal_id; /** Column EVENT_ID. */ ulonglong m_event_id; + /** Column END_EVENT_ID. */ + ulonglong m_end_event_id; + /** Column NESTING_EVENT_ID. */ + ulonglong m_nesting_event_id; + /** Column NESTING_EVENT_TYPE. */ + enum_event_type m_nesting_event_type; /** Column EVENT_NAME. */ const char *m_name; /** Length in bytes of @c m_name. */ uint m_name_length; - /** Timer state. */ - enum timer_state m_timer_state; /** Column TIMER_START. */ ulonglong m_timer_start; - /** True if TIMER_END is null. */ - bool m_timer_end_null; /** Column TIMER_END. */ ulonglong m_timer_end; + /** Column TIMER_WAIT. */ + ulonglong m_timer_wait; /** Column OBJECT_TYPE. */ const char *m_object_type; /** Length in bytes of @c m_object_type. */ @@ -63,6 +67,10 @@ struct row_events_waits char m_object_name[COL_OBJECT_NAME_EXTENDED_SIZE]; /** Length in bytes of @c m_object_name. */ uint m_object_name_length; + /** Column INDEX_NAME. */ + char m_index_name[COL_INDEX_NAME_SIZE]; + /** Length in bytes of @c m_index_name. */ + uint m_index_name_length; /** Column OBJECT_INSTANCE_BEGIN. */ intptr m_object_instance_addr; /** Column SOURCE. */ @@ -135,13 +143,16 @@ protected: {} void clear_object_columns(); + int make_table_object_columns(volatile PFS_events_waits *wait); + int make_file_object_columns(volatile PFS_events_waits *wait); + int make_socket_object_columns(volatile PFS_events_waits *wait); void make_row(bool thread_own_wait, PFS_thread *pfs_thread, volatile PFS_events_waits *wait); /** Current row. */ row_events_waits m_row; - /** True is the current row exists. */ + /** True if the current row exists. */ bool m_row_exists; }; diff --git a/storage/perfschema/table_events_waits_summary.cc b/storage/perfschema/table_events_waits_summary.cc index 05f280f8521..2a144a07344 100644 --- a/storage/perfschema/table_events_waits_summary.cc +++ b/storage/perfschema/table_events_waits_summary.cc @@ -26,318 +26,6 @@ #include "table_events_waits_summary.h" #include "pfs_global.h" -THR_LOCK table_events_waits_summary_by_thread_by_event_name::m_table_lock; - -static const TABLE_FIELD_TYPE ews_by_thread_by_event_name_field_types[]= -{ - { - { C_STRING_WITH_LEN("THREAD_ID") }, - { C_STRING_WITH_LEN("int(11)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("EVENT_NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("COUNT_STAR") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - }, - { - { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, - { C_STRING_WITH_LEN("bigint(20)") }, - { NULL, 0} - } -}; - -TABLE_FIELD_DEF -table_events_waits_summary_by_thread_by_event_name::m_field_def= -{ 7, ews_by_thread_by_event_name_field_types }; - -PFS_engine_table_share -table_events_waits_summary_by_thread_by_event_name::m_share= -{ - { C_STRING_WITH_LEN("events_waits_summary_by_thread_by_event_name") }, - &pfs_truncatable_acl, - &table_events_waits_summary_by_thread_by_event_name::create, - NULL, /* write_row */ - &table_events_waits_summary_by_thread_by_event_name::delete_all_rows, - 1000, /* records */ - sizeof(pos_events_waits_summary_by_thread_by_event_name), - &m_table_lock, - &m_field_def, - false /* checked */ -}; - -PFS_engine_table* -table_events_waits_summary_by_thread_by_event_name::create(void) -{ - return new table_events_waits_summary_by_thread_by_event_name(); -} - -int -table_events_waits_summary_by_thread_by_event_name::delete_all_rows(void) -{ - reset_per_thread_wait_stat(); - return 0; -} - -table_events_waits_summary_by_thread_by_event_name -::table_events_waits_summary_by_thread_by_event_name() - : PFS_engine_table(&m_share, &m_pos), - m_row_exists(false), m_pos(), m_next_pos() -{} - -void table_events_waits_summary_by_thread_by_event_name::reset_position(void) -{ - m_pos.reset(); - m_next_pos.reset(); -} - -int table_events_waits_summary_by_thread_by_event_name::rnd_next(void) -{ - PFS_thread *thread; - PFS_mutex_class *mutex_class; - PFS_rwlock_class *rwlock_class; - PFS_cond_class *cond_class; - PFS_file_class *file_class; - - for (m_pos.set_at(&m_next_pos); - m_pos.has_more_thread(); - m_pos.next_thread()) - { - thread= &thread_array[m_pos.m_index_1]; - if (thread->m_lock.is_populated()) - { - for ( ; m_pos.has_more_view(); m_pos.next_view()) - { - switch (m_pos.m_index_2) { - case pos_events_waits_summary_by_thread_by_event_name::VIEW_MUTEX: - mutex_class= find_mutex_class(m_pos.m_index_3); - if (mutex_class) - { - make_mutex_row(thread, mutex_class); - m_next_pos.set_after(&m_pos); - return 0; - } - break; - case pos_events_waits_summary_by_thread_by_event_name::VIEW_RWLOCK: - rwlock_class= find_rwlock_class(m_pos.m_index_3); - if (rwlock_class) - { - make_rwlock_row(thread, rwlock_class); - m_next_pos.set_after(&m_pos); - return 0; - } - break; - case pos_events_waits_summary_by_thread_by_event_name::VIEW_COND: - cond_class= find_cond_class(m_pos.m_index_3); - if (cond_class) - { - make_cond_row(thread, cond_class); - m_next_pos.set_after(&m_pos); - return 0; - } - break; - case pos_events_waits_summary_by_thread_by_event_name::VIEW_FILE: - file_class= find_file_class(m_pos.m_index_3); - if (file_class) - { - make_file_row(thread, file_class); - m_next_pos.set_after(&m_pos); - return 0; - } - break; - } - } - } - } - - return HA_ERR_END_OF_FILE; -} - -int -table_events_waits_summary_by_thread_by_event_name::rnd_pos(const void *pos) -{ - PFS_thread *thread; - PFS_mutex_class *mutex_class; - PFS_rwlock_class *rwlock_class; - PFS_cond_class *cond_class; - PFS_file_class *file_class; - - set_position(pos); - DBUG_ASSERT(m_pos.m_index_1 < thread_max); - - thread= &thread_array[m_pos.m_index_1]; - if (! thread->m_lock.is_populated()) - return HA_ERR_RECORD_DELETED; - - switch (m_pos.m_index_2) { - case pos_events_waits_summary_by_thread_by_event_name::VIEW_MUTEX: - mutex_class= find_mutex_class(m_pos.m_index_3); - if (mutex_class) - { - make_mutex_row(thread, mutex_class); - return 0; - } - break; - case pos_events_waits_summary_by_thread_by_event_name::VIEW_RWLOCK: - rwlock_class= find_rwlock_class(m_pos.m_index_3); - if (rwlock_class) - { - make_rwlock_row(thread, rwlock_class); - return 0; - } - break; - case pos_events_waits_summary_by_thread_by_event_name::VIEW_COND: - cond_class= find_cond_class(m_pos.m_index_3); - if (cond_class) - { - make_cond_row(thread, cond_class); - return 0; - } - break; - case pos_events_waits_summary_by_thread_by_event_name::VIEW_FILE: - file_class= find_file_class(m_pos.m_index_3); - if (file_class) - { - make_file_row(thread, file_class); - return 0; - } - break; - } - return HA_ERR_RECORD_DELETED; -} - -void table_events_waits_summary_by_thread_by_event_name -::make_instr_row(PFS_thread *thread, PFS_instr_class *klass, - PFS_single_stat_chain *stat) -{ - pfs_lock lock; - - m_row_exists= false; - - /* Protect this reader against a thread termination */ - thread->m_lock.begin_optimistic_lock(&lock); - - m_row.m_thread_internal_id= thread->m_thread_internal_id; - m_row.m_name= klass->m_name; - m_row.m_name_length= klass->m_name_length; - - m_row.m_count= stat->m_count; - m_row.m_sum= stat->m_sum; - m_row.m_min= stat->m_min; - m_row.m_max= stat->m_max; - - if (m_row.m_count) - m_row.m_avg= m_row.m_sum / m_row.m_count; - else - { - m_row.m_min= 0; - m_row.m_avg= 0; - } - - if (thread->m_lock.end_optimistic_lock(&lock)) - m_row_exists= true; -} - -void table_events_waits_summary_by_thread_by_event_name -::make_mutex_row(PFS_thread *thread, PFS_mutex_class *klass) -{ - PFS_single_stat_chain *stat; - stat= find_per_thread_mutex_class_wait_stat(thread, klass); - make_instr_row(thread, klass, stat); -} - -void table_events_waits_summary_by_thread_by_event_name -::make_rwlock_row(PFS_thread *thread, PFS_rwlock_class *klass) -{ - PFS_single_stat_chain *stat; - stat= find_per_thread_rwlock_class_wait_stat(thread, klass); - make_instr_row(thread, klass, stat); -} - -void table_events_waits_summary_by_thread_by_event_name -::make_cond_row(PFS_thread *thread, PFS_cond_class *klass) -{ - PFS_single_stat_chain *stat; - stat= find_per_thread_cond_class_wait_stat(thread, klass); - make_instr_row(thread, klass, stat); -} - -void table_events_waits_summary_by_thread_by_event_name -::make_file_row(PFS_thread *thread, PFS_file_class *klass) -{ - PFS_single_stat_chain *stat; - stat= find_per_thread_file_class_wait_stat(thread, klass); - make_instr_row(thread, klass, stat); -} - -int table_events_waits_summary_by_thread_by_event_name -::read_row_values(TABLE *table, unsigned char *, Field **fields, - bool read_all) -{ - Field *f; - - if (unlikely(! m_row_exists)) - return HA_ERR_RECORD_DELETED; - - /* Set the null bits */ - DBUG_ASSERT(table->s->null_bytes == 0); - - for (; (f= *fields) ; fields++) - { - if (read_all || bitmap_is_set(table->read_set, f->field_index)) - { - switch(f->field_index) - { - case 0: /* THREAD_ID */ - set_field_ulong(f, m_row.m_thread_internal_id); - break; - case 1: /* NAME */ - set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length); - break; - case 2: /* COUNT */ - set_field_ulonglong(f, m_row.m_count); - break; - case 3: /* SUM */ - set_field_ulonglong(f, m_row.m_sum); - break; - case 4: /* MIN */ - set_field_ulonglong(f, m_row.m_min); - break; - case 5: /* AVG */ - set_field_ulonglong(f, m_row.m_avg); - break; - case 6: /* MAX */ - set_field_ulonglong(f, m_row.m_max); - break; - default: - DBUG_ASSERT(false); - } - } - } - - return 0; -} - THR_LOCK table_events_waits_summary_by_instance::m_table_lock; static const TABLE_FIELD_TYPE ews_by_instance_field_types[]= @@ -391,6 +79,7 @@ table_events_waits_summary_by_instance::m_share= &table_events_waits_summary_by_instance::create, NULL, /* write_row */ &table_events_waits_summary_by_instance::delete_all_rows, + NULL, /* get_row_count */ 1000, /* records */ sizeof(pos_all_instr), &m_table_lock, @@ -416,10 +105,10 @@ table_events_waits_summary_by_instance void table_events_waits_summary_by_instance ::make_instr_row(PFS_instr *pfs, PFS_instr_class *klass, - const void *object_instance_begin) + const void *object_instance_begin, + PFS_single_stat *pfs_stat) { pfs_lock lock; - m_row_exists= false; /* @@ -432,18 +121,8 @@ void table_events_waits_summary_by_instance m_row.m_name_length= klass->m_name_length; m_row.m_object_instance_addr= (intptr) object_instance_begin; - m_row.m_count= pfs->m_wait_stat.m_count; - m_row.m_sum= pfs->m_wait_stat.m_sum; - m_row.m_min= pfs->m_wait_stat.m_min; - m_row.m_max= pfs->m_wait_stat.m_max; - - if (m_row.m_count) - m_row.m_avg= m_row.m_sum / m_row.m_count; - else - { - m_row.m_min= 0; - m_row.m_avg= 0; - } + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, pfs_stat); if (pfs->m_lock.end_optimistic_lock(&lock)) m_row_exists= true; @@ -460,7 +139,7 @@ void table_events_waits_summary_by_instance::make_mutex_row(PFS_mutex *pfs) if (unlikely(safe_class == NULL)) return; - make_instr_row(pfs, safe_class, pfs->m_identity); + make_instr_row(pfs, safe_class, pfs->m_identity, &pfs->m_wait_stat); } /** @@ -474,7 +153,7 @@ void table_events_waits_summary_by_instance::make_rwlock_row(PFS_rwlock *pfs) if (unlikely(safe_class == NULL)) return; - make_instr_row(pfs, safe_class, pfs->m_identity); + make_instr_row(pfs, safe_class, pfs->m_identity, &pfs->m_wait_stat); } /** @@ -488,7 +167,7 @@ void table_events_waits_summary_by_instance::make_cond_row(PFS_cond *pfs) if (unlikely(safe_class == NULL)) return; - make_instr_row(pfs, safe_class, pfs->m_identity); + make_instr_row(pfs, safe_class, pfs->m_identity, &pfs->m_wait_stat); } /** @@ -506,7 +185,32 @@ void table_events_waits_summary_by_instance::make_file_row(PFS_file *pfs) Files don't have a in memory structure associated to it, so we use the address of the PFS_file buffer as object_instance_begin */ - make_instr_row(pfs, safe_class, pfs); + make_instr_row(pfs, safe_class, pfs, &pfs->m_wait_stat); +} + +/** + Build a row, for socket statistics in a thread. + @param pfs the socket this cursor is reading +*/ +void table_events_waits_summary_by_instance::make_socket_row(PFS_socket *pfs) +{ + PFS_socket_class *safe_class; + safe_class= sanitize_socket_class(pfs->m_class); + if (unlikely(safe_class == NULL)) + return; + + /* + Consolidate wait times and byte counts for individual operations. This is + done by the consumer in order to reduce overhead on the socket instrument. + */ + PFS_byte_stat pfs_stat; + pfs->m_socket_stat.m_io_stat.sum(&pfs_stat); + + /* + Sockets don't have an associated in-memory structure, so use the address of + the PFS_socket buffer as object_instance_begin. + */ + make_instr_row(pfs, safe_class, pfs, &pfs_stat); } int table_events_waits_summary_by_instance @@ -534,19 +238,19 @@ int table_events_waits_summary_by_instance set_field_ulonglong(f, m_row.m_object_instance_addr); break; case 2: /* COUNT */ - set_field_ulonglong(f, m_row.m_count); + set_field_ulonglong(f, m_row.m_stat.m_count); break; case 3: /* SUM */ - set_field_ulonglong(f, m_row.m_sum); + set_field_ulonglong(f, m_row.m_stat.m_sum); break; case 4: /* MIN */ - set_field_ulonglong(f, m_row.m_min); + set_field_ulonglong(f, m_row.m_stat.m_min); break; case 5: /* AVG */ - set_field_ulonglong(f, m_row.m_avg); + set_field_ulonglong(f, m_row.m_stat.m_avg); break; case 6: /* MAX */ - set_field_ulonglong(f, m_row.m_max); + set_field_ulonglong(f, m_row.m_stat.m_max); break; default: DBUG_ASSERT(false); diff --git a/storage/perfschema/table_events_waits_summary.h b/storage/perfschema/table_events_waits_summary.h index 628bb75553f..7463ace3eb6 100644 --- a/storage/perfschema/table_events_waits_summary.h +++ b/storage/perfschema/table_events_waits_summary.h @@ -26,124 +26,13 @@ #include "pfs_instr_class.h" #include "pfs_instr.h" #include "table_all_instr.h" +#include "table_helper.h" /** @addtogroup Performance_schema_tables @{ */ -/** - A row of table - PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME. -*/ -struct row_events_waits_summary_by_thread_by_event_name -{ - /** Column THREAD_ID. */ - ulong m_thread_internal_id; - /** Column EVENT_NAME. */ - const char *m_name; - /** Length in bytes of @c m_name. */ - uint m_name_length; - /** Column COUNT_STAR. */ - ulonglong m_count; - /** Column SUM_TIMER_WAIT. */ - ulonglong m_sum; - /** Column MIN_TIMER_WAIT. */ - ulonglong m_min; - /** Column AVG_TIMER_WAIT. */ - ulonglong m_avg; - /** Column MAX_TIMER_WAIT. */ - ulonglong m_max; -}; - -/** - Position of a cursor on - PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME. -*/ -struct pos_events_waits_summary_by_thread_by_event_name -: public PFS_triple_index, public PFS_instrument_view_constants -{ - pos_events_waits_summary_by_thread_by_event_name() - : PFS_triple_index(0, VIEW_MUTEX, 1) - {} - - inline void reset(void) - { - m_index_1= 0; - m_index_2= VIEW_MUTEX; - m_index_3= 1; - } - - inline bool has_more_thread(void) - { return (m_index_1 < thread_max); } - - inline bool has_more_view(void) - { return (m_index_2 <= VIEW_FILE); } - - inline void next_thread(void) - { - m_index_1++; - m_index_2= VIEW_MUTEX; - m_index_3= 1; - } - - inline void next_view(void) - { - m_index_2++; - m_index_3= 1; - } -}; - -/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME. */ -class table_events_waits_summary_by_thread_by_event_name - : public PFS_engine_table -{ -public: - /** Table share */ - static PFS_engine_table_share m_share; - static PFS_engine_table* create(); - static int delete_all_rows(); - - virtual int rnd_next(); - virtual int rnd_pos(const void *pos); - virtual void reset_position(void); - -protected: - virtual int read_row_values(TABLE *table, - unsigned char *buf, - Field **fields, - bool read_all); - - table_events_waits_summary_by_thread_by_event_name(); - -public: - ~table_events_waits_summary_by_thread_by_event_name() - {} - -protected: - void make_instr_row(PFS_thread *thread, PFS_instr_class *klass, - PFS_single_stat_chain *stat); - void make_mutex_row(PFS_thread *thread, PFS_mutex_class *klass); - void make_rwlock_row(PFS_thread *thread, PFS_rwlock_class *klass); - void make_cond_row(PFS_thread *thread, PFS_cond_class *klass); - void make_file_row(PFS_thread *thread, PFS_file_class *klass); - -private: - /** Table share lock. */ - static THR_LOCK m_table_lock; - /** Fields definition. */ - static TABLE_FIELD_DEF m_field_def; - - /** Current row. */ - row_events_waits_summary_by_thread_by_event_name m_row; - /** True is the current row exists. */ - bool m_row_exists; - /** Current position. */ - pos_events_waits_summary_by_thread_by_event_name m_pos; - /** Next position. */ - pos_events_waits_summary_by_thread_by_event_name m_next_pos; -}; - /** A row of PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_INSTANCE. */ struct row_events_waits_summary_by_instance { @@ -153,16 +42,8 @@ struct row_events_waits_summary_by_instance uint m_name_length; /** Column OBJECT_INSTANCE_BEGIN. */ intptr m_object_instance_addr; - /** Column COUNT_STAR. */ - ulonglong m_count; - /** Column SUM_TIMER_WAIT. */ - ulonglong m_sum; - /** Column MIN_TIMER_WAIT. */ - ulonglong m_min; - /** Column AVG_TIMER_WAIT. */ - ulonglong m_avg; - /** Column MAX_TIMER_WAIT. */ - ulonglong m_max; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_stat_row m_stat; }; /** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_INSTANCE. */ @@ -176,11 +57,13 @@ public: protected: void make_instr_row(PFS_instr *pfs, PFS_instr_class *klass, - const void *object_instance_begin); + const void *object_instance_begin, + PFS_single_stat *pfs_stat); virtual void make_mutex_row(PFS_mutex *pfs); virtual void make_rwlock_row(PFS_rwlock *pfs); virtual void make_cond_row(PFS_cond *pfs); virtual void make_file_row(PFS_file *pfs); + virtual void make_socket_row(PFS_socket *pfs); virtual int read_row_values(TABLE *table, unsigned char *buf, @@ -201,7 +84,7 @@ private: /** Current row. */ row_events_waits_summary_by_instance m_row; - /** True is the current row exists. */ + /** True if the current row exists. */ bool m_row_exists; }; diff --git a/storage/perfschema/table_ews_by_account_by_event_name.cc b/storage/perfschema/table_ews_by_account_by_event_name.cc new file mode 100644 index 00000000000..992e7c18f17 --- /dev/null +++ b/storage/perfschema/table_ews_by_account_by_event_name.cc @@ -0,0 +1,288 @@ +/* Copyright (c) 2010, 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 + 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/table_ews_by_account_by_event_name.cc + Table EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_ews_by_account_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" + +THR_LOCK table_ews_by_account_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("USER") }, + { C_STRING_WITH_LEN("char(16)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("HOST") }, + { C_STRING_WITH_LEN("char(60)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_ews_by_account_by_event_name::m_field_def= +{ 8, field_types }; + +PFS_engine_table_share +table_ews_by_account_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_waits_summary_by_account_by_event_name") }, + &pfs_truncatable_acl, + table_ews_by_account_by_event_name::create, + NULL, /* write_row */ + table_ews_by_account_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_ews_by_account_by_event_name), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_ews_by_account_by_event_name::create(void) +{ + return new table_ews_by_account_by_event_name(); +} + +int +table_ews_by_account_by_event_name::delete_all_rows(void) +{ + reset_events_waits_by_thread(); + reset_events_waits_by_account(); + return 0; +} + +table_ews_by_account_by_event_name::table_ews_by_account_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_ews_by_account_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_ews_by_account_by_event_name::rnd_next(void) +{ + PFS_account *account; + PFS_instr_class *instr_class; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_account(); + m_pos.next_account()) + { + account= &account_array[m_pos.m_index_1]; + if (account->m_lock.is_populated()) + { + for ( ; + m_pos.has_more_view(); + m_pos.next_view()) + { + switch (m_pos.m_index_2) + { + case pos_ews_by_account_by_event_name::VIEW_MUTEX: + instr_class= find_mutex_class(m_pos.m_index_3); + break; + case pos_ews_by_account_by_event_name::VIEW_RWLOCK: + instr_class= find_rwlock_class(m_pos.m_index_3); + break; + case pos_ews_by_account_by_event_name::VIEW_COND: + instr_class= find_cond_class(m_pos.m_index_3); + break; + case pos_ews_by_account_by_event_name::VIEW_FILE: + instr_class= find_file_class(m_pos.m_index_3); + break; + case pos_ews_by_account_by_event_name::VIEW_TABLE: + instr_class= find_table_class(m_pos.m_index_3); + break; + case pos_ews_by_account_by_event_name::VIEW_SOCKET: + instr_class= find_socket_class(m_pos.m_index_3); + break; + case pos_ews_by_account_by_event_name::VIEW_IDLE: + instr_class= find_idle_class(m_pos.m_index_3); + break; + default: + instr_class= NULL; + DBUG_ASSERT(false); + break; + } + + if (instr_class) + { + make_row(account, instr_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_ews_by_account_by_event_name::rnd_pos(const void *pos) +{ + PFS_account *account; + PFS_instr_class *instr_class; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < account_max); + + account= &account_array[m_pos.m_index_1]; + if (! account->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + switch (m_pos.m_index_2) + { + case pos_ews_by_account_by_event_name::VIEW_MUTEX: + instr_class= find_mutex_class(m_pos.m_index_3); + break; + case pos_ews_by_account_by_event_name::VIEW_RWLOCK: + instr_class= find_rwlock_class(m_pos.m_index_3); + break; + case pos_ews_by_account_by_event_name::VIEW_COND: + instr_class= find_cond_class(m_pos.m_index_3); + break; + case pos_ews_by_account_by_event_name::VIEW_FILE: + instr_class= find_file_class(m_pos.m_index_3); + break; + case pos_ews_by_account_by_event_name::VIEW_TABLE: + instr_class= find_table_class(m_pos.m_index_3); + break; + case pos_ews_by_account_by_event_name::VIEW_SOCKET: + instr_class= find_socket_class(m_pos.m_index_3); + break; + case pos_ews_by_account_by_event_name::VIEW_IDLE: + instr_class= find_idle_class(m_pos.m_index_3); + break; + default: + instr_class= NULL; + DBUG_ASSERT(false); + } + if (instr_class) + { + make_row(account, instr_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_ews_by_account_by_event_name +::make_row(PFS_account *account, PFS_instr_class *klass) +{ + pfs_lock lock; + m_row_exists= false; + + account->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_account.make_row(account)) + return; + + m_row.m_event_name.make_row(klass); + + PFS_connection_wait_visitor visitor(klass); + PFS_connection_iterator::visit_account(account, true, & visitor); + + if (! account->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, & visitor.m_stat); +} + +int table_ews_by_account_by_event_name +::read_row_values(TABLE *table, unsigned char *buf, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* USER */ + case 1: /* HOST */ + m_row.m_account.set_field(f->field_index, f); + break; + case 2: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 3, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 3, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_ews_by_account_by_event_name.h b/storage/perfschema/table_ews_by_account_by_event_name.h new file mode 100644 index 00000000000..0a0ca83131a --- /dev/null +++ b/storage/perfschema/table_ews_by_account_by_event_name.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_EWS_BY_ACCOUNT_BY_EVENT_NAME_H +#define TABLE_EWS_BY_ACCOUNT_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_ews_by_account_by_event_name.h + Table EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_account.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. +*/ +struct row_ews_by_account_by_event_name +{ + /** Column USER, HOST. */ + PFS_account_row m_account; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + Index 1 on user@host (0 based) + Index 2 on instrument view + Index 3 on instrument class (1 based) +*/ +struct pos_ews_by_account_by_event_name +: public PFS_triple_index, public PFS_instrument_view_constants +{ + pos_ews_by_account_by_event_name() + : PFS_triple_index(0, FIRST_VIEW, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= VIEW_MUTEX; + m_index_3= 1; + } + + inline bool has_more_account(void) + { return (m_index_1 < account_max); } + + inline void next_account(void) + { + m_index_1++; + m_index_2= FIRST_VIEW; + m_index_3= 1; + } + + inline bool has_more_view(void) + { return (m_index_2 <= LAST_VIEW); } + + inline void next_view(void) + { + m_index_2++; + m_index_3= 1; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. */ +class table_ews_by_account_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_ews_by_account_by_event_name(); + +public: + ~table_ews_by_account_by_event_name() + {} + +protected: + void make_row(PFS_account *account, PFS_instr_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_ews_by_account_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_ews_by_account_by_event_name m_pos; + /** Next position. */ + pos_ews_by_account_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_ews_by_host_by_event_name.cc b/storage/perfschema/table_ews_by_host_by_event_name.cc new file mode 100644 index 00000000000..8a62990c8ed --- /dev/null +++ b/storage/perfschema/table_ews_by_host_by_event_name.cc @@ -0,0 +1,285 @@ +/* Copyright (c) 2010, 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 + 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/table_ews_by_host_by_event_name.cc + Table EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_ews_by_host_by_event_name.h" +#include "pfs_global.h" +#include "pfs_account.h" +#include "pfs_visitor.h" + +THR_LOCK table_ews_by_host_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("HOST") }, + { C_STRING_WITH_LEN("char(60)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_ews_by_host_by_event_name::m_field_def= +{ 7, field_types }; + +PFS_engine_table_share +table_ews_by_host_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_waits_summary_by_host_by_event_name") }, + &pfs_truncatable_acl, + table_ews_by_host_by_event_name::create, + NULL, /* write_row */ + table_ews_by_host_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_ews_by_host_by_event_name), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_ews_by_host_by_event_name::create(void) +{ + return new table_ews_by_host_by_event_name(); +} + +int +table_ews_by_host_by_event_name::delete_all_rows(void) +{ + reset_events_waits_by_thread(); + reset_events_waits_by_account(); + reset_events_waits_by_host(); + return 0; +} + +table_ews_by_host_by_event_name::table_ews_by_host_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_ews_by_host_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_ews_by_host_by_event_name::rnd_next(void) +{ + PFS_host *host; + PFS_instr_class *instr_class; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_host(); + m_pos.next_host()) + { + host= &host_array[m_pos.m_index_1]; + if (host->m_lock.is_populated()) + { + for ( ; + m_pos.has_more_view(); + m_pos.next_view()) + { + switch (m_pos.m_index_2) + { + case pos_ews_by_host_by_event_name::VIEW_MUTEX: + instr_class= find_mutex_class(m_pos.m_index_3); + break; + case pos_ews_by_host_by_event_name::VIEW_RWLOCK: + instr_class= find_rwlock_class(m_pos.m_index_3); + break; + case pos_ews_by_host_by_event_name::VIEW_COND: + instr_class= find_cond_class(m_pos.m_index_3); + break; + case pos_ews_by_host_by_event_name::VIEW_FILE: + instr_class= find_file_class(m_pos.m_index_3); + break; + case pos_ews_by_host_by_event_name::VIEW_TABLE: + instr_class= find_table_class(m_pos.m_index_3); + break; + case pos_ews_by_host_by_event_name::VIEW_SOCKET: + instr_class= find_socket_class(m_pos.m_index_3); + break; + case pos_ews_by_host_by_event_name::VIEW_IDLE: + instr_class= find_idle_class(m_pos.m_index_3); + break; + default: + instr_class= NULL; + DBUG_ASSERT(false); + break; + } + + if (instr_class) + { + make_row(host, instr_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_ews_by_host_by_event_name::rnd_pos(const void *pos) +{ + PFS_host *host; + PFS_instr_class *instr_class; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < host_max); + + host= &host_array[m_pos.m_index_1]; + if (! host->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + switch (m_pos.m_index_2) + { + case pos_ews_by_host_by_event_name::VIEW_MUTEX: + instr_class= find_mutex_class(m_pos.m_index_3); + break; + case pos_ews_by_host_by_event_name::VIEW_RWLOCK: + instr_class= find_rwlock_class(m_pos.m_index_3); + break; + case pos_ews_by_host_by_event_name::VIEW_COND: + instr_class= find_cond_class(m_pos.m_index_3); + break; + case pos_ews_by_host_by_event_name::VIEW_FILE: + instr_class= find_file_class(m_pos.m_index_3); + break; + case pos_ews_by_host_by_event_name::VIEW_TABLE: + instr_class= find_table_class(m_pos.m_index_3); + break; + case pos_ews_by_host_by_event_name::VIEW_SOCKET: + instr_class= find_socket_class(m_pos.m_index_3); + break; + case pos_ews_by_host_by_event_name::VIEW_IDLE: + instr_class= find_idle_class(m_pos.m_index_3); + break; + default: + instr_class= NULL; + DBUG_ASSERT(false); + break; + } + if (instr_class) + { + make_row(host, instr_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_ews_by_host_by_event_name +::make_row(PFS_host *host, PFS_instr_class *klass) +{ + pfs_lock lock; + m_row_exists= false; + + host->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_host.make_row(host)) + return; + + m_row.m_event_name.make_row(klass); + + PFS_connection_wait_visitor visitor(klass); + PFS_connection_iterator::visit_host(host, true, true, & visitor); + + if (! host->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, &visitor.m_stat); +} + +int table_ews_by_host_by_event_name +::read_row_values(TABLE *table, unsigned char *buf, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* HOST */ + m_row.m_host.set_field(f); + break; + case 1: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_ews_by_host_by_event_name.h b/storage/perfschema/table_ews_by_host_by_event_name.h new file mode 100644 index 00000000000..28b8d0250c2 --- /dev/null +++ b/storage/perfschema/table_ews_by_host_by_event_name.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_EWS_BY_HOST_BY_EVENT_NAME_H +#define TABLE_EWS_BY_HOST_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_ews_by_host_by_event_name.h + Table EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_host.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME. +*/ +struct row_ews_by_host_by_event_name +{ + /** Column HOST. */ + PFS_host_row m_host; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME. + Index 1 on host (0 based) + Index 2 on instrument view + Index 3 on instrument class (1 based) +*/ +struct pos_ews_by_host_by_event_name +: public PFS_triple_index, public PFS_instrument_view_constants +{ + pos_ews_by_host_by_event_name() + : PFS_triple_index(0, FIRST_VIEW, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= FIRST_VIEW; + m_index_3= 1; + } + + inline bool has_more_host(void) + { return (m_index_1 < host_max); } + + inline void next_host(void) + { + m_index_1++; + m_index_2= FIRST_VIEW; + m_index_3= 1; + } + + inline bool has_more_view(void) + { return (m_index_2 <= LAST_VIEW); } + + inline void next_view(void) + { + m_index_2++; + m_index_3= 1; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME. */ +class table_ews_by_host_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_ews_by_host_by_event_name(); + +public: + ~table_ews_by_host_by_event_name() + {} + +protected: + void make_row(PFS_host *host, PFS_instr_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_ews_by_host_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_ews_by_host_by_event_name m_pos; + /** Next position. */ + pos_ews_by_host_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_ews_by_thread_by_event_name.cc b/storage/perfschema/table_ews_by_thread_by_event_name.cc new file mode 100644 index 00000000000..25e3cf395c4 --- /dev/null +++ b/storage/perfschema/table_ews_by_thread_by_event_name.cc @@ -0,0 +1,299 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_ews_by_thread_by_event_name.cc + Table EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_ews_by_thread_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" + +THR_LOCK table_ews_by_thread_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("THREAD_ID") }, + { C_STRING_WITH_LEN("int(11)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_ews_by_thread_by_event_name::m_field_def= +{ 7, field_types }; + +PFS_engine_table_share +table_ews_by_thread_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_waits_summary_by_thread_by_event_name") }, + &pfs_truncatable_acl, + table_ews_by_thread_by_event_name::create, + NULL, /* write_row */ + table_ews_by_thread_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_ews_by_thread_by_event_name), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_ews_by_thread_by_event_name::create(void) +{ + return new table_ews_by_thread_by_event_name(); +} + +int +table_ews_by_thread_by_event_name::delete_all_rows(void) +{ + reset_events_waits_by_thread(); + return 0; +} + +table_ews_by_thread_by_event_name::table_ews_by_thread_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_ews_by_thread_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_ews_by_thread_by_event_name::rnd_next(void) +{ + PFS_thread *thread; + PFS_instr_class *instr_class; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_thread(); + m_pos.next_thread()) + { + thread= &thread_array[m_pos.m_index_1]; + + /* + Important note: the thread scan is the outer loop (index 1), + to minimize the number of calls to atomic operations. + */ + if (thread->m_lock.is_populated()) + { + for ( ; + m_pos.has_more_view(); + m_pos.next_view()) + { + switch (m_pos.m_index_2) + { + case pos_ews_by_thread_by_event_name::VIEW_MUTEX: + instr_class= find_mutex_class(m_pos.m_index_3); + break; + case pos_ews_by_thread_by_event_name::VIEW_RWLOCK: + instr_class= find_rwlock_class(m_pos.m_index_3); + break; + case pos_ews_by_thread_by_event_name::VIEW_COND: + instr_class= find_cond_class(m_pos.m_index_3); + break; + case pos_ews_by_thread_by_event_name::VIEW_FILE: + instr_class= find_file_class(m_pos.m_index_3); + break; + case pos_ews_by_thread_by_event_name::VIEW_TABLE: + instr_class= find_table_class(m_pos.m_index_3); + break; + case pos_ews_by_thread_by_event_name::VIEW_SOCKET: + instr_class= find_socket_class(m_pos.m_index_3); + break; + case pos_ews_by_thread_by_event_name::VIEW_IDLE: + instr_class= find_idle_class(m_pos.m_index_3); + break; + default: + DBUG_ASSERT(false); + instr_class= NULL; + break; + } + + if (instr_class != NULL) + { + make_row(thread, instr_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_ews_by_thread_by_event_name::rnd_pos(const void *pos) +{ + PFS_thread *thread; + PFS_instr_class *instr_class; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < thread_max); + + thread= &thread_array[m_pos.m_index_1]; + if (! thread->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + switch (m_pos.m_index_2) + { + case pos_ews_by_thread_by_event_name::VIEW_MUTEX: + instr_class= find_mutex_class(m_pos.m_index_3); + break; + case pos_ews_by_thread_by_event_name::VIEW_RWLOCK: + instr_class= find_rwlock_class(m_pos.m_index_3); + break; + case pos_ews_by_thread_by_event_name::VIEW_COND: + instr_class= find_cond_class(m_pos.m_index_3); + break; + case pos_ews_by_thread_by_event_name::VIEW_FILE: + instr_class= find_file_class(m_pos.m_index_3); + break; + case pos_ews_by_thread_by_event_name::VIEW_TABLE: + instr_class= find_table_class(m_pos.m_index_3); + break; + case pos_ews_by_thread_by_event_name::VIEW_SOCKET: + instr_class= find_socket_class(m_pos.m_index_3); + break; + case pos_ews_by_thread_by_event_name::VIEW_IDLE: + instr_class= find_idle_class(m_pos.m_index_3); + break; + default: + DBUG_ASSERT(false); + instr_class= NULL; + } + + if (instr_class) + { + make_row(thread, instr_class); + return 0; + } + return HA_ERR_RECORD_DELETED; +} + +void table_ews_by_thread_by_event_name +::make_row(PFS_thread *thread, PFS_instr_class *klass) +{ + pfs_lock lock; + m_row_exists= false; + + /* Protect this reader against a thread termination */ + thread->m_lock.begin_optimistic_lock(&lock); + + m_row.m_thread_internal_id= thread->m_thread_internal_id; + + m_row.m_event_name.make_row(klass); + + PFS_connection_wait_visitor visitor(klass); + PFS_connection_iterator::visit_thread(thread, &visitor); + + /* + If the aggregation for this class is deferred, then we must pull the + current wait stats from the instances associated with this thread. + */ + if (klass->is_deferred()) + { + /* Visit instances owned by this thread. Do not visit the class. */ + PFS_instance_wait_visitor inst_visitor; + PFS_instance_iterator::visit_instances(klass, &inst_visitor, + thread, false); + /* Combine the deferred stats and global stats */ + visitor.m_stat.aggregate(&inst_visitor.m_stat); + } + + if (! thread->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, & visitor.m_stat); +} + +int table_ews_by_thread_by_event_name +::read_row_values(TABLE *table, unsigned char *, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 0); + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* THREAD_ID */ + set_field_ulong(f, m_row.m_thread_internal_id); + break; + case 1: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_ews_by_thread_by_event_name.h b/storage/perfschema/table_ews_by_thread_by_event_name.h new file mode 100644 index 00000000000..b0710bb8a57 --- /dev/null +++ b/storage/perfschema/table_ews_by_thread_by_event_name.h @@ -0,0 +1,135 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_EWS_BY_THREAD_BY_EVENT_NAME_H +#define TABLE_EWS_BY_THREAD_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_ews_by_thread_by_event_name.h + Table EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME. +*/ +struct row_ews_by_thread_by_event_name +{ + /** Column THREAD_ID. */ + ulong m_thread_internal_id; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME. + Index 1 on thread (0 based) + Index 2 on instrument view + Index 3 on instrument class (1 based) +*/ +struct pos_ews_by_thread_by_event_name +: public PFS_triple_index, public PFS_instrument_view_constants +{ + pos_ews_by_thread_by_event_name() + : PFS_triple_index(0, FIRST_VIEW, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= FIRST_VIEW; + m_index_3= 1; + } + + inline bool has_more_thread(void) + { return (m_index_1 < thread_max); } + + inline void next_thread(void) + { + m_index_1++; + m_index_2= FIRST_VIEW; + m_index_3= 1; + } + + inline bool has_more_view(void) + { return (m_index_2 <= LAST_VIEW); } + + inline void next_view(void) + { + m_index_2++; + m_index_3= 1; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME. */ +class table_ews_by_thread_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_ews_by_thread_by_event_name(); + +public: + ~table_ews_by_thread_by_event_name() + {} + +protected: + void make_row(PFS_thread *thread, PFS_instr_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_ews_by_thread_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_ews_by_thread_by_event_name m_pos; + /** Next position. */ + pos_ews_by_thread_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_ews_by_user_by_event_name.cc b/storage/perfschema/table_ews_by_user_by_event_name.cc new file mode 100644 index 00000000000..8a169019e87 --- /dev/null +++ b/storage/perfschema/table_ews_by_user_by_event_name.cc @@ -0,0 +1,285 @@ +/* Copyright (c) 2010, 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 + 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/table_ews_by_user_by_event_name.cc + Table EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_ews_by_user_by_event_name.h" +#include "pfs_global.h" +#include "pfs_account.h" +#include "pfs_visitor.h" + +THR_LOCK table_ews_by_user_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("USER") }, + { C_STRING_WITH_LEN("char(16)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_ews_by_user_by_event_name::m_field_def= +{ 7, field_types }; + +PFS_engine_table_share +table_ews_by_user_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_waits_summary_by_user_by_event_name") }, + &pfs_truncatable_acl, + table_ews_by_user_by_event_name::create, + NULL, /* write_row */ + table_ews_by_user_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_ews_by_user_by_event_name), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_ews_by_user_by_event_name::create(void) +{ + return new table_ews_by_user_by_event_name(); +} + +int +table_ews_by_user_by_event_name::delete_all_rows(void) +{ + reset_events_waits_by_thread(); + reset_events_waits_by_account(); + reset_events_waits_by_user(); + return 0; +} + +table_ews_by_user_by_event_name::table_ews_by_user_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_ews_by_user_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_ews_by_user_by_event_name::rnd_next(void) +{ + PFS_user *user; + PFS_instr_class *instr_class; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_user(); + m_pos.next_user()) + { + user= &user_array[m_pos.m_index_1]; + if (user->m_lock.is_populated()) + { + for ( ; + m_pos.has_more_view(); + m_pos.next_view()) + { + switch (m_pos.m_index_2) + { + case pos_ews_by_user_by_event_name::VIEW_MUTEX: + instr_class= find_mutex_class(m_pos.m_index_3); + break; + case pos_ews_by_user_by_event_name::VIEW_RWLOCK: + instr_class= find_rwlock_class(m_pos.m_index_3); + break; + case pos_ews_by_user_by_event_name::VIEW_COND: + instr_class= find_cond_class(m_pos.m_index_3); + break; + case pos_ews_by_user_by_event_name::VIEW_FILE: + instr_class= find_file_class(m_pos.m_index_3); + break; + case pos_ews_by_user_by_event_name::VIEW_TABLE: + instr_class= find_table_class(m_pos.m_index_3); + break; + case pos_ews_by_user_by_event_name::VIEW_SOCKET: + instr_class= find_socket_class(m_pos.m_index_3); + break; + case pos_ews_by_user_by_event_name::VIEW_IDLE: + instr_class= find_idle_class(m_pos.m_index_3); + break; + default: + instr_class= NULL; + DBUG_ASSERT(false); + break; + } + + if (instr_class) + { + make_row(user, instr_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_ews_by_user_by_event_name::rnd_pos(const void *pos) +{ + PFS_user *user; + PFS_instr_class *instr_class; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < user_max); + + user= &user_array[m_pos.m_index_1]; + if (! user->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + switch (m_pos.m_index_2) + { + case pos_ews_by_user_by_event_name::VIEW_MUTEX: + instr_class= find_mutex_class(m_pos.m_index_3); + break; + case pos_ews_by_user_by_event_name::VIEW_RWLOCK: + instr_class= find_rwlock_class(m_pos.m_index_3); + break; + case pos_ews_by_user_by_event_name::VIEW_COND: + instr_class= find_cond_class(m_pos.m_index_3); + break; + case pos_ews_by_user_by_event_name::VIEW_FILE: + instr_class= find_file_class(m_pos.m_index_3); + break; + case pos_ews_by_user_by_event_name::VIEW_TABLE: + instr_class= find_table_class(m_pos.m_index_3); + break; + case pos_ews_by_user_by_event_name::VIEW_SOCKET: + instr_class= find_socket_class(m_pos.m_index_3); + break; + case pos_ews_by_user_by_event_name::VIEW_IDLE: + instr_class= find_idle_class(m_pos.m_index_3); + break; + default: + instr_class= NULL; + DBUG_ASSERT(false); + break; + } + if (instr_class) + { + make_row(user, instr_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_ews_by_user_by_event_name +::make_row(PFS_user *user, PFS_instr_class *klass) +{ + pfs_lock lock; + m_row_exists= false; + + user->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_user.make_row(user)) + return; + + m_row.m_event_name.make_row(klass); + + PFS_connection_wait_visitor visitor(klass); + PFS_connection_iterator::visit_user(user, true, true, & visitor); + + if (! user->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, &visitor.m_stat); +} + +int table_ews_by_user_by_event_name +::read_row_values(TABLE *table, unsigned char *buf, Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* USER */ + m_row.m_user.set_field(f); + break; + case 1: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 2, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_ews_by_user_by_event_name.h b/storage/perfschema/table_ews_by_user_by_event_name.h new file mode 100644 index 00000000000..88b78a1ed7a --- /dev/null +++ b/storage/perfschema/table_ews_by_user_by_event_name.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_EWS_BY_USER_BY_EVENT_NAME_H +#define TABLE_EWS_BY_USER_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_ews_by_user_by_event_name.h + Table EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_user.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME. +*/ +struct row_ews_by_user_by_event_name +{ + /** Column USER. */ + PFS_user_row m_user; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME. + Index 1 on user (0 based) + Index 2 on instrument view + Index 3 on instrument class (1 based) +*/ +struct pos_ews_by_user_by_event_name +: public PFS_triple_index, public PFS_instrument_view_constants +{ + pos_ews_by_user_by_event_name() + : PFS_triple_index(0, FIRST_VIEW, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= FIRST_VIEW; + m_index_3= 1; + } + + inline bool has_more_user(void) + { return (m_index_1 < user_max); } + + inline void next_user(void) + { + m_index_1++; + m_index_2= FIRST_VIEW; + m_index_3= 1; + } + + inline bool has_more_view(void) + { return (m_index_2 <= LAST_VIEW); } + + inline void next_view(void) + { + m_index_2++; + m_index_3= 1; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME. */ +class table_ews_by_user_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_ews_by_user_by_event_name(); + +public: + ~table_ews_by_user_by_event_name() + {} + +protected: + void make_row(PFS_user *user, PFS_instr_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_ews_by_user_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_ews_by_user_by_event_name m_pos; + /** Next position. */ + pos_ews_by_user_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_ews_global_by_event_name.cc b/storage/perfschema/table_ews_global_by_event_name.cc index 3177584231d..c71a1ed479e 100644 --- a/storage/perfschema/table_ews_global_by_event_name.cc +++ b/storage/perfschema/table_ews_global_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 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 @@ -10,8 +10,8 @@ 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, - 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /** @file storage/perfschema/table_ews_global_by_event_name.cc @@ -25,6 +25,9 @@ #include "pfs_column_values.h" #include "table_ews_global_by_event_name.h" #include "pfs_global.h" +#include "pfs_instr.h" +#include "pfs_timer.h" +#include "pfs_visitor.h" THR_LOCK table_ews_global_by_event_name::m_table_lock; @@ -71,50 +74,320 @@ table_ews_global_by_event_name::m_share= { { C_STRING_WITH_LEN("events_waits_summary_global_by_event_name") }, &pfs_truncatable_acl, - &table_ews_global_by_event_name::create, + table_ews_global_by_event_name::create, NULL, /* write_row */ - &table_ews_global_by_event_name::delete_all_rows, + table_ews_global_by_event_name::delete_all_rows, + NULL, /* get_row_count */ 1000, /* records */ - sizeof(pos_all_instr_class), + sizeof(pos_ews_global_by_event_name), &m_table_lock, &m_field_def, false /* checked */ }; -PFS_engine_table* table_ews_global_by_event_name::create(void) +PFS_engine_table* +table_ews_global_by_event_name::create(void) { return new table_ews_global_by_event_name(); } -int table_ews_global_by_event_name::delete_all_rows(void) +int +table_ews_global_by_event_name::delete_all_rows(void) { - reset_instrument_class_waits(); + reset_events_waits_by_instance(); + reset_table_waits_by_table_handle(); + reset_table_waits_by_table(); + reset_events_waits_global(); return 0; } -table_ews_global_by_event_name -::table_ews_global_by_event_name() - : table_all_instr_class(&m_share) +table_ews_global_by_event_name::table_ews_global_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() {} -void table_ews_global_by_event_name -::make_instr_row(PFS_instr_class *klass) +void table_ews_global_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_ews_global_by_event_name::rnd_next(void) +{ + PFS_mutex_class *mutex_class; + PFS_rwlock_class *rwlock_class; + PFS_cond_class *cond_class; + PFS_file_class *file_class; + PFS_socket_class *socket_class; + PFS_instr_class *instr_class; + + if (global_instr_class_waits_array == NULL) + return HA_ERR_END_OF_FILE; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_view(); + m_pos.next_view()) + { + switch (m_pos.m_index_1) + { + case pos_ews_global_by_event_name::VIEW_MUTEX: + mutex_class= find_mutex_class(m_pos.m_index_2); + if (mutex_class) + { + make_mutex_row(mutex_class); + m_next_pos.set_after(&m_pos); + return 0; + } + break; + case pos_ews_global_by_event_name::VIEW_RWLOCK: + rwlock_class= find_rwlock_class(m_pos.m_index_2); + if (rwlock_class) + { + make_rwlock_row(rwlock_class); + m_next_pos.set_after(&m_pos); + return 0; + } + break; + case pos_ews_global_by_event_name::VIEW_COND: + cond_class= find_cond_class(m_pos.m_index_2); + if (cond_class) + { + make_cond_row(cond_class); + m_next_pos.set_after(&m_pos); + return 0; + } + break; + case pos_ews_global_by_event_name::VIEW_FILE: + file_class= find_file_class(m_pos.m_index_2); + if (file_class) + { + make_file_row(file_class); + m_next_pos.set_after(&m_pos); + return 0; + } + break; + case pos_ews_global_by_event_name::VIEW_TABLE: + if (m_pos.m_index_2 == 1) + { + make_table_io_row(&global_table_io_class); + m_next_pos.set_after(&m_pos); + return 0; + } + if (m_pos.m_index_2 == 2) + { + make_table_lock_row(&global_table_lock_class); + m_next_pos.set_after(&m_pos); + return 0; + } + break; + case pos_ews_global_by_event_name::VIEW_SOCKET: + socket_class= find_socket_class(m_pos.m_index_2); + if (socket_class) + { + make_socket_row(socket_class); + m_next_pos.set_after(&m_pos); + return 0; + } + break; + case pos_ews_global_by_event_name::VIEW_IDLE: + instr_class= find_idle_class(m_pos.m_index_2); + if (instr_class) + { + make_idle_row(instr_class); + m_next_pos.set_after(&m_pos); + return 0; + } + break; + default: + break; + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_ews_global_by_event_name::rnd_pos(const void *pos) { - m_row.m_name= klass->m_name; - m_row.m_name_length= klass->m_name_length; + PFS_mutex_class *mutex_class; + PFS_rwlock_class *rwlock_class; + PFS_cond_class *cond_class; + PFS_file_class *file_class; + PFS_socket_class *socket_class; + PFS_instr_class *instr_class; - m_row.m_count= klass->m_wait_stat.m_count; - m_row.m_sum= klass->m_wait_stat.m_sum; - m_row.m_min= klass->m_wait_stat.m_min; - m_row.m_max= klass->m_wait_stat.m_max; + set_position(pos); - if (m_row.m_count) - m_row.m_avg= m_row.m_sum / m_row.m_count; - else + if (global_instr_class_waits_array == NULL) + return HA_ERR_END_OF_FILE; + + switch (m_pos.m_index_1) { - m_row.m_min= 0; - m_row.m_avg= 0; + case pos_ews_global_by_event_name::VIEW_MUTEX: + mutex_class= find_mutex_class(m_pos.m_index_2); + if (mutex_class) + { + make_mutex_row(mutex_class); + return 0; + } + break; + case pos_ews_global_by_event_name::VIEW_RWLOCK: + rwlock_class= find_rwlock_class(m_pos.m_index_2); + if (rwlock_class) + { + make_rwlock_row(rwlock_class); + return 0; + } + break; + case pos_ews_global_by_event_name::VIEW_COND: + cond_class= find_cond_class(m_pos.m_index_2); + if (cond_class) + { + make_cond_row(cond_class); + return 0; + } + break; + case pos_ews_global_by_event_name::VIEW_FILE: + file_class= find_file_class(m_pos.m_index_2); + if (file_class) + { + make_file_row(file_class); + return 0; + } + break; + case pos_ews_global_by_event_name::VIEW_TABLE: + DBUG_ASSERT(m_pos.m_index_2 >= 1); + DBUG_ASSERT(m_pos.m_index_2 <= 2); + if (m_pos.m_index_2 == 1) + make_table_io_row(&global_table_io_class); + else + make_table_lock_row(&global_table_lock_class); + break; + case pos_ews_global_by_event_name::VIEW_SOCKET: + socket_class= find_socket_class(m_pos.m_index_2); + if (socket_class) + { + make_socket_row(socket_class); + return 0; + } + break; + case pos_ews_global_by_event_name::VIEW_IDLE: + instr_class= find_idle_class(m_pos.m_index_2); + if (instr_class) + { + make_idle_row(instr_class); + return 0; + } + break; } + + return HA_ERR_RECORD_DELETED; +} + +void table_ews_global_by_event_name +::make_mutex_row(PFS_mutex_class *klass) +{ + m_row.m_event_name.make_row(klass); + + PFS_instance_wait_visitor visitor; + PFS_instance_iterator::visit_mutex_instances(klass, & visitor); + + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, & visitor.m_stat); + m_row_exists= true; +} + +void table_ews_global_by_event_name +::make_rwlock_row(PFS_rwlock_class *klass) +{ + m_row.m_event_name.make_row(klass); + + PFS_instance_wait_visitor visitor; + PFS_instance_iterator::visit_rwlock_instances(klass, & visitor); + + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, & visitor.m_stat); + m_row_exists= true; +} + +void table_ews_global_by_event_name +::make_cond_row(PFS_cond_class *klass) +{ + m_row.m_event_name.make_row(klass); + + PFS_instance_wait_visitor visitor; + PFS_instance_iterator::visit_cond_instances(klass, & visitor); + + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, & visitor.m_stat); + m_row_exists= true; +} + +void table_ews_global_by_event_name +::make_file_row(PFS_file_class *klass) +{ + m_row.m_event_name.make_row(klass); + + PFS_instance_wait_visitor visitor; + PFS_instance_iterator::visit_file_instances(klass, & visitor); + + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, & visitor.m_stat); + m_row_exists= true; +} + +void table_ews_global_by_event_name +::make_table_io_row(PFS_instr_class *klass) +{ + m_row.m_event_name.make_row(klass); + + PFS_table_io_wait_visitor visitor; + PFS_object_iterator::visit_all_tables(& visitor); + + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, & visitor.m_stat); + m_row_exists= true; +} + +void table_ews_global_by_event_name +::make_table_lock_row(PFS_instr_class *klass) +{ + m_row.m_event_name.make_row(klass); + + PFS_table_lock_wait_visitor visitor; + PFS_object_iterator::visit_all_tables(& visitor); + + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, & visitor.m_stat); + m_row_exists= true; +} + +void table_ews_global_by_event_name +::make_socket_row(PFS_socket_class *klass) +{ + m_row.m_event_name.make_row(klass); + + PFS_instance_wait_visitor visitor; + PFS_instance_iterator::visit_socket_instances(klass, &visitor); + + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, &visitor.m_stat); + m_row_exists= true; +} + +void table_ews_global_by_event_name +::make_idle_row(PFS_instr_class *klass) +{ + m_row.m_event_name.make_row(klass); + + PFS_connection_wait_visitor visitor(klass); + PFS_connection_iterator::visit_global(false, /* hosts */ + false, /* users */ + false, /* accts */ + true, /* threads */ &visitor); + get_normalizer(klass); + m_row.m_stat.set(m_normalizer, &visitor.m_stat); + m_row_exists= true; } int table_ews_global_by_event_name @@ -123,40 +396,24 @@ int table_ews_global_by_event_name { Field *f; + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + /* Set the null bits */ DBUG_ASSERT(table->s->null_bytes == 0); - /* - The row always exist, - the instrument classes are static and never disappear. - */ - for (; (f= *fields) ; fields++) { if (read_all || bitmap_is_set(table->read_set, f->field_index)) { switch(f->field_index) { - case 0: /* NAME */ - set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length); - break; - case 1: /* COUNT */ - set_field_ulonglong(f, m_row.m_count); - break; - case 2: /* SUM */ - set_field_ulonglong(f, m_row.m_sum); - break; - case 3: /* MIN */ - set_field_ulonglong(f, m_row.m_min); - break; - case 4: /* AVG */ - set_field_ulonglong(f, m_row.m_avg); + case 0: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); break; - case 5: /* MAX */ - set_field_ulonglong(f, m_row.m_max); + default: /* 1, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stat.set_field(f->field_index - 1, f); break; - default: - DBUG_ASSERT(false); } } } diff --git a/storage/perfschema/table_ews_global_by_event_name.h b/storage/perfschema/table_ews_global_by_event_name.h index 7e66448e96c..a118e536b6a 100644 --- a/storage/perfschema/table_ews_global_by_event_name.h +++ b/storage/perfschema/table_ews_global_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 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 @@ -10,11 +10,11 @@ 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, - 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef TABLE_EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME_H -#define TABLE_EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME_H +#ifndef TABLE_EWS_GLOBAL_BY_EVENT_NAME_H +#define TABLE_EWS_GLOBAL_BY_EVENT_NAME_H /** @file storage/perfschema/table_ews_global_by_event_name.h @@ -25,34 +25,56 @@ #include "pfs_engine_table.h" #include "pfs_instr_class.h" #include "pfs_instr.h" -#include "table_all_instr.h" +#include "table_helper.h" /** @addtogroup Performance_schema_tables @{ */ -/** A row of PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME. */ +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME. +*/ struct row_ews_global_by_event_name { /** Column EVENT_NAME. */ - const char *m_name; - /** Length in bytes of @c m_name. */ - uint m_name_length; - /** Column COUNT_STAR. */ - ulonglong m_count; - /** Column SUM_TIMER_WAIT. */ - ulonglong m_sum; - /** Column MIN_TIMER_WAIT. */ - ulonglong m_min; - /** Column AVG_TIMER_WAIT. */ - ulonglong m_avg; - /** Column MAX_TIMER_WAIT. */ - ulonglong m_max; + PFS_event_name_row m_event_name; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME. + Index 1 on instrument view + Index 2 on instrument class (1 based) +*/ +struct pos_ews_global_by_event_name +: public PFS_double_index, public PFS_instrument_view_constants +{ + pos_ews_global_by_event_name() + : PFS_double_index(FIRST_VIEW, 1) + {} + + inline void reset(void) + { + m_index_1= FIRST_VIEW; + m_index_2= 1; + } + + inline bool has_more_view(void) + { return (m_index_1 <= LAST_VIEW); } + + inline void next_view(void) + { + m_index_1++; + m_index_2= 1; + } }; /** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME. */ -class table_ews_global_by_event_name : public table_all_instr_class +class table_ews_global_by_event_name : public PFS_engine_table { public: /** Table share */ @@ -60,9 +82,11 @@ public: static PFS_engine_table* create(); static int delete_all_rows(); -protected: - virtual void make_instr_row(PFS_instr_class *klass); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); +protected: virtual int read_row_values(TABLE *table, unsigned char *buf, Field **fields, @@ -74,6 +98,16 @@ public: ~table_ews_global_by_event_name() {} +protected: + void make_mutex_row(PFS_mutex_class *klass); + void make_rwlock_row(PFS_rwlock_class *klass); + void make_cond_row(PFS_cond_class *klass); + void make_file_row(PFS_file_class *klass); + void make_table_io_row(PFS_instr_class *klass); + void make_table_lock_row(PFS_instr_class *klass); + void make_socket_row(PFS_socket_class *klass); + void make_idle_row(PFS_instr_class *klass); + private: /** Table share lock. */ static THR_LOCK m_table_lock; @@ -82,6 +116,12 @@ private: /** Current row. */ row_ews_global_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_ews_global_by_event_name m_pos; + /** Next position. */ + pos_ews_global_by_event_name m_next_pos; }; /** @} */ diff --git a/storage/perfschema/table_file_instances.cc b/storage/perfschema/table_file_instances.cc index 9ae732a0e1c..a3d2fc454bb 100644 --- a/storage/perfschema/table_file_instances.cc +++ b/storage/perfschema/table_file_instances.cc @@ -59,6 +59,7 @@ table_file_instances::m_share= &table_file_instances::create, NULL, /* write_row */ NULL, /* delete_all_rows */ + NULL, /* get_row_count */ 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, diff --git a/storage/perfschema/table_file_instances.h b/storage/perfschema/table_file_instances.h index 7365000b21f..f7ec16715f3 100644 --- a/storage/perfschema/table_file_instances.h +++ b/storage/perfschema/table_file_instances.h @@ -78,7 +78,7 @@ private: /** Current row. */ row_file_instances m_row; - /** True is the current row exists. */ + /** True if the current row exists. */ bool m_row_exists; /** Current position. */ PFS_simple_index m_pos; diff --git a/storage/perfschema/table_file_summary_by_event_name.cc b/storage/perfschema/table_file_summary_by_event_name.cc new file mode 100644 index 00000000000..7e72f4d4158 --- /dev/null +++ b/storage/perfschema/table_file_summary_by_event_name.cc @@ -0,0 +1,352 @@ +/* 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_file_summary.cc + Table FILE_SUMMARY_BY_EVENT_NAME(implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_file_summary_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" + +THR_LOCK table_file_summary_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + + /** Read */ + { + { C_STRING_WITH_LEN("COUNT_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + + /** Write */ + { + { C_STRING_WITH_LEN("COUNT_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + + /** Misc */ + { + { C_STRING_WITH_LEN("COUNT_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_file_summary_by_event_name::m_field_def= +{ 23, field_types }; + +PFS_engine_table_share +table_file_summary_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("file_summary_by_event_name") }, + &pfs_truncatable_acl, + &table_file_summary_by_event_name::create, + NULL, /* write_row */ + table_file_summary_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* table_file_summary_by_event_name::create(void) +{ + return new table_file_summary_by_event_name(); +} + +int table_file_summary_by_event_name::delete_all_rows(void) +{ + reset_file_instance_io(); + reset_file_class_io(); + return 0; +} + +table_file_summary_by_event_name::table_file_summary_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_pos(1), m_next_pos(1) +{} + +void table_file_summary_by_event_name::reset_position(void) +{ + m_pos.m_index= 1; + m_next_pos.m_index= 1; +} + +int table_file_summary_by_event_name::rnd_next(void) +{ + PFS_file_class *file_class; + + m_pos.set_at(&m_next_pos); + + file_class= find_file_class(m_pos.m_index); + if (file_class) + { + make_row(file_class); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int table_file_summary_by_event_name::rnd_pos(const void *pos) +{ + PFS_file_class *file_class; + + set_position(pos); + + file_class= find_file_class(m_pos.m_index); + if (file_class) + { + make_row(file_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +/** + Build a row. + @param klass the file class the cursor is reading +*/ +void table_file_summary_by_event_name::make_row(PFS_file_class *file_class) +{ + m_row.m_event_name.make_row(file_class); + + PFS_instance_file_io_stat_visitor visitor; + PFS_instance_iterator::visit_file_instances(file_class, &visitor); + + time_normalizer *normalizer= time_normalizer::get(wait_timer); + + /* Collect timer and byte count stats */ + m_row.m_io_stat.set(normalizer, &visitor.m_file_io_stat); + m_row_exists= true; + +} + +int table_file_summary_by_event_name::read_row_values(TABLE *table, + unsigned char *, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(!m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 0); + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + case 1: /* COUNT_STAR */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_count); + break; + case 2: /* SUM_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_sum); + break; + case 3: /* MIN_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_min); + break; + case 4: /* AVG_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_avg); + break; + case 5: /* MAX_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_max); + break; + + case 6: /* COUNT_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_count); + break; + case 7: /* SUM_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_sum); + break; + case 8: /* MIN_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_min); + break; + case 9: /* AVG_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_avg); + break; + case 10: /* MAX_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_max); + break; + case 11: /* SUM_NUMBER_OF_BYTES_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_bytes); + break; + + case 12: /* COUNT_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_count); + break; + case 13: /* SUM_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_sum); + break; + case 14: /* MIN_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_min); + break; + case 15: /* AVG_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_avg); + break; + case 16: /* MAX_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_max); + break; + case 17: /* SUM_NUMBER_OF_BYTES_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_bytes); + break; + + case 18: /* COUNT_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_count); + break; + case 19: /* SUM_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_sum); + break; + case 20: /* MIN_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_min); + break; + case 21: /* AVG_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_avg); + break; + case 22: /* MAX_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_max); + break; + + default: + DBUG_ASSERT(false); + break; + } + } // if + } // for + + return 0; +} diff --git a/storage/perfschema/table_file_summary_by_event_name.h b/storage/perfschema/table_file_summary_by_event_name.h new file mode 100644 index 00000000000..8a51dffad65 --- /dev/null +++ b/storage/perfschema/table_file_summary_by_event_name.h @@ -0,0 +1,91 @@ +/* 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_FILE_SUMMARY_H +#define TABLE_FILE_SUMMARY_H + +/** + @file storage/perfschema/table_file_summary_by_event_name.h + Table FILE_SUMMARY_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of PERFORMANCE_SCHEMA.FILE_SUMMARY_BY_EVENT_NAME. */ +struct row_file_summary_by_event_name +{ + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER and NUMBER_OF_BYTES + for READ, WRITE and MISC operation types. + */ + PFS_file_io_stat_row m_io_stat; +}; + +/** Table PERFORMANCE_SCHEMA.FILE_SUMMARY_BY_EVENT_NAME. */ +class table_file_summary_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +private: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_file_summary_by_event_name(); + +public: + ~table_file_summary_by_event_name() + {} + +private: + void make_row(PFS_file_class *klass); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_file_summary_by_event_name m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_file_summary_by_instance.cc b/storage/perfschema/table_file_summary_by_instance.cc new file mode 100644 index 00000000000..40478647f5b --- /dev/null +++ b/storage/perfschema/table_file_summary_by_instance.cc @@ -0,0 +1,381 @@ +/* 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_file_summary.cc + Table FILE_SUMMARY_BY_INSTANCE (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_file_summary_by_instance.h" +#include "pfs_global.h" + +THR_LOCK table_file_summary_by_instance::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("FILE_NAME") }, + { C_STRING_WITH_LEN("varchar(512)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + + /** Read */ + { + { C_STRING_WITH_LEN("COUNT_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + + /** Write */ + { + { C_STRING_WITH_LEN("COUNT_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + + /** Misc */ + { + { C_STRING_WITH_LEN("COUNT_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_file_summary_by_instance::m_field_def= +{ 25, field_types }; + +PFS_engine_table_share +table_file_summary_by_instance::m_share= +{ + { C_STRING_WITH_LEN("file_summary_by_instance") }, + &pfs_truncatable_acl, + &table_file_summary_by_instance::create, + NULL, /* write_row */ + table_file_summary_by_instance::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* table_file_summary_by_instance::create(void) +{ + return new table_file_summary_by_instance(); +} + +int table_file_summary_by_instance::delete_all_rows(void) +{ + reset_file_instance_io(); + return 0; +} + +table_file_summary_by_instance::table_file_summary_by_instance() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_file_summary_by_instance::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_file_summary_by_instance::rnd_next(void) +{ + PFS_file *pfs; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < file_max; + m_pos.next()) + { + pfs= &file_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_file_summary_by_instance::rnd_pos(const void *pos) +{ + PFS_file *pfs; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < file_max); + pfs= &file_array[m_pos.m_index]; + + if (! pfs->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + make_row(pfs); + return 0; +} + +/** + Build a row. + @param pfs the file the cursor is reading +*/ +void table_file_summary_by_instance::make_row(PFS_file *pfs) +{ + pfs_lock lock; + PFS_file_class *safe_class; + + m_row_exists= false; + + /* Protect this reader against a file delete */ + pfs->m_lock.begin_optimistic_lock(&lock); + + safe_class= sanitize_file_class(pfs->m_class); + if (unlikely(safe_class == NULL)) + return; + + m_row.m_filename= pfs->m_filename; + m_row.m_filename_length= pfs->m_filename_length; + m_row.m_event_name.make_row(safe_class); + m_row.m_identity= pfs->m_identity; + + time_normalizer *normalizer= time_normalizer::get(wait_timer); + + /* Collect timer and byte count stats */ + m_row.m_io_stat.set(normalizer, &pfs->m_file_stat.m_io_stat); + + if (pfs->m_lock.end_optimistic_lock(&lock)) + m_row_exists= true; +} + +int table_file_summary_by_instance::read_row_values(TABLE *table, + unsigned char *, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 0); + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* FILE_NAME */ + set_field_varchar_utf8(f, m_row.m_filename, m_row.m_filename_length); + break; + case 1: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + case 2: /* OBJECT_INSTANCE */ + set_field_ulonglong(f, (ulonglong)m_row.m_identity); + break; + + case 3:/* COUNT_STAR */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_count); + break; + case 4:/* SUM_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_sum); + break; + case 5: /* MIN_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_min); + break; + case 6: /* AVG_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_avg); + break; + case 7: /* MAX_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_max); + break; + + case 8: /* COUNT_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_count); + break; + case 9: /* SUM_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_sum); + break; + case 10: /* MIN_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_min); + break; + case 11: /* AVG_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_avg); + break; + case 12: /* MAX_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_max); + break; + case 13: /* SUM_NUMBER_OF_BYTES_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_bytes); + break; + + case 14: /* COUNT_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_count); + break; + case 15: /* SUM_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_sum); + break; + case 16: /* MIN_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_min); + break; + case 17: /* AVG_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_avg); + break; + case 18: /* MAX_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_max); + break; + case 19: /* SUM_NUMBER_OF_BYTES_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_bytes); + break; + + case 20: /* COUNT_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_count); + break; + case 21: /* SUM_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_sum); + break; + case 22: /* MIN_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_min); + break; + case 23: /* AVG_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_avg); + break; + case 24: /* MAX_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_max); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_file_summary_by_instance.h b/storage/perfschema/table_file_summary_by_instance.h new file mode 100644 index 00000000000..d9f406966db --- /dev/null +++ b/storage/perfschema/table_file_summary_by_instance.h @@ -0,0 +1,99 @@ +/* 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_FILE_SUMMARY_BY_INSTANCE_H +#define TABLE_FILE_SUMMARY_BY_INSTANCE_H + +/** + @file storage/perfschema/table_file_summary_by_instance.h + Table FILE_SUMMARY_BY_INSTANCE (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of PERFORMANCE_SCHEMA.FILE_SUMMARY_BY_INSTANCE. */ +struct row_file_summary_by_instance +{ + /** Column FILE_NAME. */ + const char *m_filename; + /** Length in bytes of @c m_filename. */ + uint m_filename_length; + + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + + /** Column OBJECT_INSTANCE_BEGIN */ + const void *m_identity; + /** + Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER and NUMBER_OF_BYTES for READ, + WRITE and MISC operation types. + */ + PFS_file_io_stat_row m_io_stat; +}; + +/** Table PERFORMANCE_SCHEMA.FILE_SUMMARY_BY_INSTANCE. */ +class table_file_summary_by_instance : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +private: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_file_summary_by_instance(); + +public: + ~table_file_summary_by_instance() + {} + +private: + void make_row(PFS_file *pfs); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_file_summary_by_instance m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_helper.cc b/storage/perfschema/table_helper.cc new file mode 100644 index 00000000000..d3954179539 --- /dev/null +++ b/storage/perfschema/table_helper.cc @@ -0,0 +1,340 @@ +/* Copyright (c) 2010, 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 + 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/table_helper.cc + Performance schema table helpers (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_engine_table.h" +#include "table_helper.h" +#include "pfs_host.h" +#include "pfs_user.h" +#include "pfs_account.h" + +int PFS_host_row::make_row(PFS_host *pfs) +{ + m_hostname_length= pfs->m_hostname_length; + if (m_hostname_length > sizeof(m_hostname)) + return 1; + if (m_hostname_length > 0) + memcpy(m_hostname, pfs->m_hostname, sizeof(m_hostname)); + return 0; +} + +void PFS_host_row::set_field(Field *f) +{ + if (m_hostname_length > 0) + PFS_engine_table::set_field_char_utf8(f, m_hostname, m_hostname_length); + else + f->set_null(); +} + +int PFS_user_row::make_row(PFS_user *pfs) +{ + m_username_length= pfs->m_username_length; + if (m_username_length > sizeof(m_username)) + return 1; + if (m_username_length > 0) + memcpy(m_username, pfs->m_username, sizeof(m_username)); + return 0; +} + +void PFS_user_row::set_field(Field *f) +{ + if (m_username_length > 0) + PFS_engine_table::set_field_char_utf8(f, m_username, m_username_length); + else + f->set_null(); +} + +int PFS_account_row::make_row(PFS_account *pfs) +{ + m_username_length= pfs->m_username_length; + if (m_username_length > sizeof(m_username)) + return 1; + if (m_username_length > 0) + memcpy(m_username, pfs->m_username, sizeof(m_username)); + + m_hostname_length= pfs->m_hostname_length; + if (m_hostname_length > sizeof(m_hostname)) + return 1; + if (m_hostname_length > 0) + memcpy(m_hostname, pfs->m_hostname, sizeof(m_hostname)); + + return 0; +} + +void PFS_account_row::set_field(uint index, Field *f) +{ + switch (index) + { + case 0: /* USER */ + if (m_username_length > 0) + PFS_engine_table::set_field_char_utf8(f, m_username, m_username_length); + else + f->set_null(); + break; + case 1: /* HOST */ + if (m_hostname_length > 0) + PFS_engine_table::set_field_char_utf8(f, m_hostname, m_hostname_length); + else + f->set_null(); + break; + default: + DBUG_ASSERT(false); + break; + } +} + +int PFS_digest_row::make_row(PFS_statements_digest_stat* pfs) +{ + /* + "0" value for byte_count indicates special entry i.e. aggregated + stats at index 0 of statements_digest_stat_array. So do not calculate + digest/digest_text as it should always be "NULL". + */ + if (pfs->m_digest_storage.m_byte_count != 0) + { + /* + Calculate digest from MD5 HASH collected to be shown as + DIGEST in this row. + */ + MD5_HASH_TO_STRING(pfs->m_digest_hash.m_md5, m_digest); + m_digest_length= MD5_HASH_TO_STRING_LENGTH; + + /* + Caclulate digest_text information from the token array collected + to be shown as DIGEST_TEXT column. + */ + get_digest_text(m_digest_text, &pfs->m_digest_storage); + m_digest_text_length= strlen(m_digest_text); + } + else + { + m_digest_length= 0; + m_digest_text_length= 0; + } + + return 0; +} + +void PFS_digest_row::set_field(uint index, Field *f) +{ + switch (index) + { + case 0: /* DIGEST */ + if (m_digest_length > 0) + PFS_engine_table::set_field_varchar_utf8(f, m_digest, + m_digest_length); + else + f->set_null(); + break; + case 1: /* DIGEST_TEXT */ + if (m_digest_text_length > 0) + PFS_engine_table::set_field_longtext_utf8(f, m_digest_text, + m_digest_text_length); + else + f->set_null(); + break; + default: + DBUG_ASSERT(false); + break; + } +} + +int PFS_object_row::make_row(PFS_table_share *pfs) +{ + m_object_type= pfs->get_object_type(); + + m_schema_name_length= pfs->m_schema_name_length; + if (m_schema_name_length > sizeof(m_schema_name)) + return 1; + if (m_schema_name_length > 0) + memcpy(m_schema_name, pfs->m_schema_name, sizeof(m_schema_name)); + + m_object_name_length= pfs->m_table_name_length; + if (m_object_name_length > sizeof(m_object_name)) + return 1; + if (m_object_name_length > 0) + memcpy(m_object_name, pfs->m_table_name, sizeof(m_object_name)); + + return 0; +} + +void PFS_object_row::set_field(uint index, Field *f) +{ + switch(index) + { + case 0: /* OBJECT_TYPE */ + set_field_object_type(f, m_object_type); + break; + case 1: /* SCHEMA_NAME */ + PFS_engine_table::set_field_varchar_utf8(f, m_schema_name, m_schema_name_length); + break; + case 2: /* OBJECT_NAME */ + PFS_engine_table::set_field_varchar_utf8(f, m_object_name, m_object_name_length); + break; + default: + DBUG_ASSERT(false); + } +} + +int PFS_index_row::make_row(PFS_table_share *pfs, uint table_index) +{ + if (m_object_row.make_row(pfs)) + return 1; + + if (table_index < MAX_KEY) + { + PFS_table_key *key= &pfs->m_keys[table_index]; + m_index_name_length= key->m_name_length; + if (m_index_name_length > sizeof(m_index_name)) + return 1; + memcpy(m_index_name, key->m_name, sizeof(m_index_name)); + } + else + m_index_name_length= 0; + + return 0; +} + +void PFS_index_row::set_field(uint index, Field *f) +{ + switch(index) + { + case 0: /* OBJECT_TYPE */ + case 1: /* SCHEMA_NAME */ + case 2: /* OBJECT_NAME */ + m_object_row.set_field(index, f); + break; + case 3: /* INDEX_NAME */ + if (m_index_name_length > 0) + PFS_engine_table::set_field_varchar_utf8(f, m_index_name, m_index_name_length); + else + f->set_null(); + break; + default: + DBUG_ASSERT(false); + } +} + +void PFS_statement_stat_row::set_field(uint index, Field *f) +{ + switch (index) + { + case 0: /* COUNT_STAR */ + case 1: /* SUM_TIMER_WAIT */ + case 2: /* MIN_TIMER_WAIT */ + case 3: /* AVG_TIMER_WAIT */ + case 4: /* MAX_TIMER_WAIT */ + m_timer1_row.set_field(index, f); + break; + case 5: /* SUM_LOCK_TIME */ + PFS_engine_table::set_field_ulonglong(f, m_lock_time); + break; + case 6: /* SUM_ERRORS */ + PFS_engine_table::set_field_ulonglong(f, m_error_count); + break; + case 7: /* SUM_WARNINGS */ + PFS_engine_table::set_field_ulonglong(f, m_warning_count); + break; + case 8: /* SUM_ROWS_AFFECTED */ + PFS_engine_table::set_field_ulonglong(f, m_rows_affected); + break; + case 9: /* SUM_ROWS_SENT */ + PFS_engine_table::set_field_ulonglong(f, m_rows_sent); + break; + case 10: /* SUM_ROWS_EXAMINED */ + PFS_engine_table::set_field_ulonglong(f, m_rows_examined); + break; + case 11: /* SUM_CREATED_TMP_DISK_TABLES */ + PFS_engine_table::set_field_ulonglong(f, m_created_tmp_disk_tables); + break; + case 12: /* SUM_CREATED_TMP_TABLES */ + PFS_engine_table::set_field_ulonglong(f, m_created_tmp_tables); + break; + case 13: /* SUM_SELECT_FULL_JOIN */ + PFS_engine_table::set_field_ulonglong(f, m_select_full_join); + break; + case 14: /* SUM_SELECT_FULL_RANGE_JOIN */ + PFS_engine_table::set_field_ulonglong(f, m_select_full_range_join); + break; + case 15: /* SUM_SELECT_RANGE */ + PFS_engine_table::set_field_ulonglong(f, m_select_range); + break; + case 16: /* SUM_SELECT_RANGE_CHECK */ + PFS_engine_table::set_field_ulonglong(f, m_select_range_check); + break; + case 17: /* SUM_SELECT_SCAN */ + PFS_engine_table::set_field_ulonglong(f, m_select_scan); + break; + case 18: /* SUM_SORT_MERGE_PASSES */ + PFS_engine_table::set_field_ulonglong(f, m_sort_merge_passes); + break; + case 19: /* SUM_SORT_RANGE */ + PFS_engine_table::set_field_ulonglong(f, m_sort_range); + break; + case 20: /* SUM_SORT_ROWS */ + PFS_engine_table::set_field_ulonglong(f, m_sort_rows); + break; + case 21: /* SUM_SORT_SCAN */ + PFS_engine_table::set_field_ulonglong(f, m_sort_scan); + break; + case 22: /* SUM_NO_INDEX_USED */ + PFS_engine_table::set_field_ulonglong(f, m_no_index_used); + break; + case 23: /* SUM_NO_GOOD_INDEX_USED */ + PFS_engine_table::set_field_ulonglong(f, m_no_good_index_used); + break; + default: + DBUG_ASSERT(false); + break; + } +} + +void PFS_connection_stat_row::set_field(uint index, Field *f) +{ + switch (index) + { + case 0: /* CURRENT_CONNECTIONS */ + PFS_engine_table::set_field_ulonglong(f, m_current_connections); + break; + case 1: /* TOTAL_CONNECTIONS */ + PFS_engine_table::set_field_ulonglong(f, m_total_connections); + break; + default: + DBUG_ASSERT(false); + break; + } +} + +void set_field_object_type(Field *f, enum_object_type object_type) +{ + switch (object_type) + { + case OBJECT_TYPE_TABLE: + PFS_engine_table::set_field_varchar_utf8(f, "TABLE", 5); + break; + case OBJECT_TYPE_TEMPORARY_TABLE: + PFS_engine_table::set_field_varchar_utf8(f, "TEMPORARY TABLE", 15); + break; + default: + DBUG_ASSERT(false); + } +} + diff --git a/storage/perfschema/table_helper.h b/storage/perfschema/table_helper.h new file mode 100644 index 00000000000..798ff16f4e5 --- /dev/null +++ b/storage/perfschema/table_helper.h @@ -0,0 +1,518 @@ +/* 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 + 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 */ + +#ifndef PFS_TABLE_HELPER_H +#define PFS_TABLE_HELPER_H + +#include "pfs_column_types.h" +#include "pfs_stat.h" +#include "pfs_timer.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_digest.h" + +/* + Write MD5 hash value in a string to be used + as DIGEST for the statement. +*/ +#define MD5_HASH_TO_STRING(_hash, _str) \ + sprintf(_str, "%02x%02x%02x%02x%02x%02x%02x%02x" \ + "%02x%02x%02x%02x%02x%02x%02x%02x", \ + _hash[0], _hash[1], _hash[2], _hash[3], \ + _hash[4], _hash[5], _hash[6], _hash[7], \ + _hash[8], _hash[9], _hash[10], _hash[11], \ + _hash[12], _hash[13], _hash[14], _hash[15]) + +#define MD5_HASH_TO_STRING_LENGTH 32 + +struct PFS_host; +struct PFS_user; +struct PFS_account; + +/** + @file storage/perfschema/table_helper.h + Performance schema table helpers (declarations). +*/ + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** Namespace, internal views used within table setup_instruments. */ +struct PFS_instrument_view_constants +{ + static const uint FIRST_VIEW= 1; + static const uint VIEW_MUTEX= 1; + static const uint VIEW_RWLOCK= 2; + static const uint VIEW_COND= 3; + static const uint VIEW_FILE= 4; + static const uint VIEW_TABLE= 5; + static const uint VIEW_SOCKET= 6; + static const uint VIEW_IDLE= 7; + static const uint LAST_VIEW= 7; +}; + +/** Namespace, internal views used within object summaries. */ +struct PFS_object_view_constants +{ + static const uint FIRST_VIEW= 1; + static const uint VIEW_TABLE= 1; + static const uint LAST_VIEW= 1; + + /* Future use */ + static const uint VIEW_EVENT= 2; + static const uint VIEW_PROCEDURE= 3; + static const uint VIEW_FUNCTION= 4; +}; + +/** Row fragment for column HOST. */ +struct PFS_host_row +{ + /** Column HOST. */ + char m_hostname[HOSTNAME_LENGTH]; + /** Length in bytes of @c m_hostname. */ + uint m_hostname_length; + + /** Build a row from a memory buffer. */ + int make_row(PFS_host *pfs); + /** Set a table field from the row. */ + void set_field(Field *f); +}; + +/** Row fragment for column USER. */ +struct PFS_user_row +{ + /** Column USER. */ + char m_username[USERNAME_LENGTH]; + /** Length in bytes of @c m_username. */ + uint m_username_length; + + /** Build a row from a memory buffer. */ + int make_row(PFS_user *pfs); + /** Set a table field from the row. */ + void set_field(Field *f); +}; + +/** Row fragment for columns USER, HOST. */ +struct PFS_account_row +{ + /** Column USER. */ + char m_username[USERNAME_LENGTH]; + /** Length in bytes of @c m_username. */ + uint m_username_length; + /** Column HOST. */ + char m_hostname[HOSTNAME_LENGTH]; + /** Length in bytes of @c m_hostname. */ + uint m_hostname_length; + + /** Build a row from a memory buffer. */ + int make_row(PFS_account *pfs); + /** Set a table field from the row. */ + void set_field(uint index, Field *f); +}; + +/** Row fragment for columns DIGEST, DIGEST_TEXT. */ +struct PFS_digest_row +{ + /** Column DIGEST. */ + char m_digest[COL_DIGEST_SIZE]; + /** Length in bytes of @c m_digest. */ + uint m_digest_length; + /** Column DIGEST_TEXT. */ + char m_digest_text[COL_DIGEST_TEXT_SIZE]; + /** Length in bytes of @c m_digest_text. */ + uint m_digest_text_length; + + /** Build a row from a memory buffer. */ + int make_row(PFS_statements_digest_stat*); + /** Set a table field from the row. */ + void set_field(uint index, Field *f); +}; + +/** Row fragment for column EVENT_NAME. */ +struct PFS_event_name_row +{ + /** Column EVENT_NAME. */ + const char *m_name; + /** Length in bytes of @c m_name. */ + uint m_name_length; + + /** Build a row from a memory buffer. */ + inline void make_row(PFS_instr_class *pfs) + { + m_name= pfs->m_name; + m_name_length= pfs->m_name_length; + } + + /** Set a table field from the row. */ + inline void set_field(Field *f) + { + PFS_engine_table::set_field_varchar_utf8(f, m_name, m_name_length); + } +}; + +/** Row fragment for columns OBJECT_TYPE, SCHEMA_NAME, OBJECT_NAME. */ +struct PFS_object_row +{ + /** Column OBJECT_TYPE. */ + enum_object_type m_object_type; + /** Column SCHEMA_NAME. */ + char m_schema_name[NAME_LEN]; + /** Length in bytes of @c m_schema_name. */ + uint m_schema_name_length; + /** Column OBJECT_NAME. */ + char m_object_name[NAME_LEN]; + /** Length in bytes of @c m_object_name. */ + uint m_object_name_length; + + /** Build a row from a memory buffer. */ + int make_row(PFS_table_share *pfs); + /** Set a table field from the row. */ + void set_field(uint index, Field *f); +}; + +/** Row fragment for columns OBJECT_TYPE, SCHEMA_NAME, OBJECT_NAME, INDEX_NAME. */ +struct PFS_index_row +{ + PFS_object_row m_object_row; + /** Column INDEX_NAME. */ + char m_index_name[NAME_LEN]; + /** Length in bytes of @c m_index_name. */ + uint m_index_name_length; + + /** Build a row from a memory buffer. */ + int make_row(PFS_table_share *pfs, uint table_index); + /** Set a table field from the row. */ + void set_field(uint index, Field *f); +}; + +/** Row fragment for single statistics columns (COUNT, SUM, MIN, AVG, MAX) */ +struct PFS_stat_row +{ + /** Column COUNT_STAR. */ + ulonglong m_count; + /** Column SUM_TIMER_WAIT. */ + ulonglong m_sum; + /** Column MIN_TIMER_WAIT. */ + ulonglong m_min; + /** Column AVG_TIMER_WAIT. */ + ulonglong m_avg; + /** Column MAX_TIMER_WAIT. */ + ulonglong m_max; + + /** Build a row with timer fields from a memory buffer. */ + inline void set(time_normalizer *normalizer, const PFS_single_stat *stat) + { + m_count= stat->m_count; + + if (m_count) + { + m_sum= normalizer->wait_to_pico(stat->m_sum); + m_min= normalizer->wait_to_pico(stat->m_min); + m_max= normalizer->wait_to_pico(stat->m_max); + m_avg= normalizer->wait_to_pico(stat->m_sum / m_count); + } + else + { + m_sum= 0; + m_min= 0; + m_avg= 0; + m_max= 0; + } + } + + /** Set a table field from the row. */ + void set_field(uint index, Field *f) + { + switch (index) + { + case 0: /* COUNT */ + PFS_engine_table::set_field_ulonglong(f, m_count); + break; + case 1: /* SUM */ + PFS_engine_table::set_field_ulonglong(f, m_sum); + break; + case 2: /* MIN */ + PFS_engine_table::set_field_ulonglong(f, m_min); + break; + case 3: /* AVG */ + PFS_engine_table::set_field_ulonglong(f, m_avg); + break; + case 4: /* MAX */ + PFS_engine_table::set_field_ulonglong(f, m_max); + break; + default: + DBUG_ASSERT(false); + } + } +}; + +/** Row fragment for timer and byte count stats. Corresponds to PFS_byte_stat */ +struct PFS_byte_stat_row +{ + PFS_stat_row m_waits; + ulonglong m_bytes; + + /** Build a row with timer and byte count fields from a memory buffer. */ + inline void set(time_normalizer *normalizer, const PFS_byte_stat *stat) + { + m_waits.set(normalizer, stat); + m_bytes= stat->m_bytes; + } +}; + +/** Row fragment for table io statistics columns. */ +struct PFS_table_io_stat_row +{ + PFS_stat_row m_all; + PFS_stat_row m_all_read; + PFS_stat_row m_all_write; + PFS_stat_row m_fetch; + PFS_stat_row m_insert; + PFS_stat_row m_update; + PFS_stat_row m_delete; + + /** Build a row from a memory buffer. */ + inline void set(time_normalizer *normalizer, const PFS_table_io_stat *stat) + { + PFS_single_stat all_read; + PFS_single_stat all_write; + PFS_single_stat all; + + m_fetch.set(normalizer, & stat->m_fetch); + + all_read.aggregate(& stat->m_fetch); + + m_insert.set(normalizer, & stat->m_insert); + m_update.set(normalizer, & stat->m_update); + m_delete.set(normalizer, & stat->m_delete); + + all_write.aggregate(& stat->m_insert); + all_write.aggregate(& stat->m_update); + all_write.aggregate(& stat->m_delete); + + all.aggregate(& all_read); + all.aggregate(& all_write); + + m_all_read.set(normalizer, & all_read); + m_all_write.set(normalizer, & all_write); + m_all.set(normalizer, & all); + } +}; + +/** Row fragment for table lock statistics columns. */ +struct PFS_table_lock_stat_row +{ + PFS_stat_row m_all; + PFS_stat_row m_all_read; + PFS_stat_row m_all_write; + PFS_stat_row m_read_normal; + PFS_stat_row m_read_with_shared_locks; + PFS_stat_row m_read_high_priority; + PFS_stat_row m_read_no_insert; + PFS_stat_row m_read_external; + PFS_stat_row m_write_allow_write; + PFS_stat_row m_write_concurrent_insert; + PFS_stat_row m_write_delayed; + PFS_stat_row m_write_low_priority; + PFS_stat_row m_write_normal; + PFS_stat_row m_write_external; + + /** Build a row from a memory buffer. */ + inline void set(time_normalizer *normalizer, const PFS_table_lock_stat *stat) + { + PFS_single_stat all_read; + PFS_single_stat all_write; + PFS_single_stat all; + + m_read_normal.set(normalizer, & stat->m_stat[PFS_TL_READ]); + m_read_with_shared_locks.set(normalizer, & stat->m_stat[PFS_TL_READ_WITH_SHARED_LOCKS]); + m_read_high_priority.set(normalizer, & stat->m_stat[PFS_TL_READ_HIGH_PRIORITY]); + m_read_no_insert.set(normalizer, & stat->m_stat[PFS_TL_READ_NO_INSERT]); + m_read_external.set(normalizer, & stat->m_stat[PFS_TL_READ_EXTERNAL]); + + all_read.aggregate(& stat->m_stat[PFS_TL_READ]); + all_read.aggregate(& stat->m_stat[PFS_TL_READ_WITH_SHARED_LOCKS]); + all_read.aggregate(& stat->m_stat[PFS_TL_READ_HIGH_PRIORITY]); + all_read.aggregate(& stat->m_stat[PFS_TL_READ_NO_INSERT]); + all_read.aggregate(& stat->m_stat[PFS_TL_READ_EXTERNAL]); + + m_write_allow_write.set(normalizer, & stat->m_stat[PFS_TL_WRITE_ALLOW_WRITE]); + m_write_concurrent_insert.set(normalizer, & stat->m_stat[PFS_TL_WRITE_CONCURRENT_INSERT]); + m_write_delayed.set(normalizer, & stat->m_stat[PFS_TL_WRITE_DELAYED]); + m_write_low_priority.set(normalizer, & stat->m_stat[PFS_TL_WRITE_LOW_PRIORITY]); + m_write_normal.set(normalizer, & stat->m_stat[PFS_TL_WRITE]); + m_write_external.set(normalizer, & stat->m_stat[PFS_TL_WRITE_EXTERNAL]); + + all_write.aggregate(& stat->m_stat[PFS_TL_WRITE_ALLOW_WRITE]); + all_write.aggregate(& stat->m_stat[PFS_TL_WRITE_CONCURRENT_INSERT]); + all_write.aggregate(& stat->m_stat[PFS_TL_WRITE_DELAYED]); + all_write.aggregate(& stat->m_stat[PFS_TL_WRITE_LOW_PRIORITY]); + all_write.aggregate(& stat->m_stat[PFS_TL_WRITE]); + all_write.aggregate(& stat->m_stat[PFS_TL_WRITE_EXTERNAL]); + + all.aggregate(& all_read); + all.aggregate(& all_write); + + m_all_read.set(normalizer, & all_read); + m_all_write.set(normalizer, & all_write); + m_all.set(normalizer, & all); + } +}; + +/** Row fragment for stage statistics columns. */ +struct PFS_stage_stat_row +{ + PFS_stat_row m_timer1_row; + + /** Build a row from a memory buffer. */ + inline void set(time_normalizer *normalizer, const PFS_stage_stat *stat) + { + m_timer1_row.set(normalizer, & stat->m_timer1_stat); + } + + /** Set a table field from the row. */ + void set_field(uint index, Field *f) + { + m_timer1_row.set_field(index, f); + } +}; + +/** Row fragment for statement statistics columns. */ +struct PFS_statement_stat_row +{ + PFS_stat_row m_timer1_row; + ulonglong m_error_count; + ulonglong m_warning_count; + ulonglong m_rows_affected; + ulonglong m_lock_time; + ulonglong m_rows_sent; + ulonglong m_rows_examined; + ulonglong m_created_tmp_disk_tables; + ulonglong m_created_tmp_tables; + ulonglong m_select_full_join; + ulonglong m_select_full_range_join; + ulonglong m_select_range; + ulonglong m_select_range_check; + ulonglong m_select_scan; + ulonglong m_sort_merge_passes; + ulonglong m_sort_range; + ulonglong m_sort_rows; + ulonglong m_sort_scan; + ulonglong m_no_index_used; + ulonglong m_no_good_index_used; + + /** Build a row from a memory buffer. */ + inline void set(time_normalizer *normalizer, const PFS_statement_stat *stat) + { + m_timer1_row.set(normalizer, & stat->m_timer1_stat); + + m_error_count= stat->m_error_count; + m_warning_count= stat->m_warning_count; + m_lock_time= stat->m_lock_time * MICROSEC_TO_PICOSEC; + m_rows_affected= stat->m_rows_affected; + m_rows_sent= stat->m_rows_sent; + m_rows_examined= stat->m_rows_examined; + m_created_tmp_disk_tables= stat->m_created_tmp_disk_tables; + m_created_tmp_tables= stat->m_created_tmp_tables; + m_select_full_join= stat->m_select_full_join; + m_select_full_range_join= stat->m_select_full_range_join; + m_select_range= stat->m_select_range; + m_select_range_check= stat->m_select_range_check; + m_select_scan= stat->m_select_scan; + m_sort_merge_passes= stat->m_sort_range; + m_sort_range= stat->m_sort_range; + m_sort_rows= stat->m_sort_rows; + m_sort_scan= stat->m_sort_scan; + m_no_index_used= stat->m_no_index_used; + m_no_good_index_used= stat->m_no_good_index_used; + } + + /** Set a table field from the row. */ + void set_field(uint index, Field *f); +}; + +struct PFS_connection_stat_row +{ + ulonglong m_current_connections; + ulonglong m_total_connections; + + inline void set(const PFS_connection_stat *stat) + { + m_current_connections= stat->m_current_connections; + m_total_connections= stat->m_total_connections; + } + + /** Set a table field from the row. */ + void set_field(uint index, Field *f); +}; + +void set_field_object_type(Field *f, enum_object_type object_type); + +/** Row fragment for socket io statistics columns. */ +struct PFS_socket_io_stat_row +{ + PFS_byte_stat_row m_read; + PFS_byte_stat_row m_write; + PFS_byte_stat_row m_misc; + PFS_byte_stat_row m_all; + + inline void set(time_normalizer *normalizer, const PFS_socket_io_stat *stat) + { + PFS_byte_stat all; + + m_read.set(normalizer, &stat->m_read); + m_write.set(normalizer, &stat->m_write); + m_misc.set(normalizer, &stat->m_misc); + + /* Combine stats for all operations */ + all.aggregate(&stat->m_read); + all.aggregate(&stat->m_write); + all.aggregate(&stat->m_misc); + + m_all.set(normalizer, &all); + } +}; + +/** Row fragment for file io statistics columns. */ +struct PFS_file_io_stat_row +{ + PFS_byte_stat_row m_read; + PFS_byte_stat_row m_write; + PFS_byte_stat_row m_misc; + PFS_byte_stat_row m_all; + + inline void set(time_normalizer *normalizer, const PFS_file_io_stat *stat) + { + PFS_byte_stat all; + + m_read.set(normalizer, &stat->m_read); + m_write.set(normalizer, &stat->m_write); + m_misc.set(normalizer, &stat->m_misc); + + /* Combine stats for all operations */ + all.aggregate(&stat->m_read); + all.aggregate(&stat->m_write); + all.aggregate(&stat->m_misc); + + m_all.set(normalizer, &all); + } +}; + +/** @} */ + +#endif + diff --git a/storage/perfschema/table_host_cache.cc b/storage/perfschema/table_host_cache.cc new file mode 100644 index 00000000000..d243204ddcd --- /dev/null +++ b/storage/perfschema/table_host_cache.cc @@ -0,0 +1,484 @@ +/* Copyright (c) 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_host_cache.cc + Table HOST_CACHE (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "table_host_cache.h" +#include "hostname.h" + +#ifdef NOT_YET_PORTED + +THR_LOCK table_host_cache::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("IP") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("HOST") }, + { C_STRING_WITH_LEN("varchar(255)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("HOST_VALIDATED") }, + { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_CONNECT_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_HOST_BLOCKED_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_NAMEINFO_TRANSIENT_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_NAMEINFO_PERMANENT_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_FORMAT_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_ADDRINFO_TRANSIENT_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_ADDRINFO_PERMANENT_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_FCRDNS_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_HOST_ACL_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_NO_AUTH_PLUGIN_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_AUTH_PLUGIN_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_HANDSHAKE_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_PROXY_USER_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_PROXY_USER_ACL_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_AUTHENTICATION_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_SSL_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_MAX_USER_CONNECTIONS_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_DEFAULT_DATABASE_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_INIT_CONNECT_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_LOCAL_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_UNKNOWN_ERRORS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("FIRST_SEEN") }, + { C_STRING_WITH_LEN("timestamp") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("LAST_SEEN") }, + { C_STRING_WITH_LEN("timestamp") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("FIRST_ERROR_SEEN") }, + { C_STRING_WITH_LEN("timestamp") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("LAST_ERROR_SEEN") }, + { C_STRING_WITH_LEN("timestamp") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_host_cache::m_field_def= +{ 29, field_types }; + +PFS_engine_table_share +table_host_cache::m_share= +{ + { C_STRING_WITH_LEN("host_cache") }, + &pfs_truncatable_acl, + &table_host_cache::create, + NULL, /* write_row */ + table_host_cache::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), /* ref length */ + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* table_host_cache::create(void) +{ + table_host_cache *t= new table_host_cache(); + if (t != NULL) + { + THD *thd= current_thd; + DBUG_ASSERT(thd != NULL); + t->materialize(thd); + } + return t; +} + +int +table_host_cache::delete_all_rows(void) +{ + /* + TRUNCATE TABLE performance_schema.host_cache + is an alternate syntax for + FLUSH HOSTS + */ + hostname_cache_refresh(); + return 0; +} + +table_host_cache::table_host_cache() + : PFS_engine_table(&m_share, &m_pos), + m_all_rows(NULL), m_row_count(0), + m_row(NULL), m_pos(0), m_next_pos(0) +{} + +void table_host_cache::materialize(THD *thd) +{ + Host_entry *current; + Host_entry *first; + uint size; + uint index; + row_host_cache *rows; + row_host_cache *row; + + DBUG_ASSERT(m_all_rows == NULL); + DBUG_ASSERT(m_row_count == 0); + + hostname_cache_lock(); + + size= hostname_cache_size(); + if (size == 0) + { + /* Normal case, the cache is empty. */ + goto end; + } + + rows= (row_host_cache*) thd->alloc(size * sizeof(row_host_cache)); + if (rows == NULL) + { + /* Out of memory, this thread will error out. */ + goto end; + } + + index= 0; + row= rows; + + first= hostname_cache_first(); + current= first; + + while ((current != NULL) && (index < size)) + { + make_row(current, row); + index++; + row++; + current= current->next(); + /* Host cache is a circular linked list. */ + if (current == first) + break; + } + + m_all_rows= rows; + m_row_count= index; + +end: + hostname_cache_unlock(); +} + +void table_host_cache::make_row(Host_entry *entry, row_host_cache *row) +{ + row->m_ip_length= strlen(entry->ip_key); + strcpy(row->m_ip, entry->ip_key); + row->m_hostname_length= entry->m_hostname_length; + if (row->m_hostname_length > 0) + strncpy(row->m_hostname, entry->m_hostname, row->m_hostname_length); + row->m_host_validated= entry->m_host_validated; + row->m_sum_connect_errors= entry->m_errors.m_connect; + row->m_count_host_blocked_errors= entry->m_errors.m_host_blocked; + row->m_count_nameinfo_transient_errors= entry->m_errors.m_nameinfo_transient; + row->m_count_nameinfo_permanent_errors= entry->m_errors.m_nameinfo_permanent; + row->m_count_format_errors= entry->m_errors.m_format; + row->m_count_addrinfo_transient_errors= entry->m_errors.m_addrinfo_transient; + row->m_count_addrinfo_permanent_errors= entry->m_errors.m_addrinfo_permanent; + row->m_count_fcrdns_errors= entry->m_errors.m_FCrDNS; + row->m_count_host_acl_errors= entry->m_errors.m_host_acl; + row->m_count_no_auth_plugin_errors= entry->m_errors.m_no_auth_plugin; + row->m_count_auth_plugin_errors= entry->m_errors.m_auth_plugin; + row->m_count_handshake_errors= entry->m_errors.m_handshake; + row->m_count_proxy_user_errors= entry->m_errors.m_proxy_user; + row->m_count_proxy_user_acl_errors= entry->m_errors.m_proxy_user_acl; + row->m_count_authentication_errors= entry->m_errors.m_authentication; + row->m_count_ssl_errors= entry->m_errors.m_ssl; + row->m_count_max_user_connection_errors= entry->m_errors.m_max_user_connection; + row->m_count_max_user_connection_per_hour_errors= entry->m_errors.m_max_user_connection_per_hour; + row->m_count_default_database_errors= entry->m_errors.m_default_database; + row->m_count_init_connect_errors= entry->m_errors.m_init_connect; + row->m_count_local_errors= entry->m_errors.m_local; + + /* + Reserved for future use, to help with backward compatibility. + When new errors are added in entry->m_errors.m_xxx, + report them in this column (GA releases), + until the table HOST_CACHE structure can be extended (next development version). + */ + row->m_count_unknown_errors= 0; + + row->m_first_seen= entry->m_first_seen; + row->m_last_seen= entry->m_last_seen; + row->m_first_error_seen= entry->m_first_error_seen; + row->m_last_error_seen= entry->m_last_error_seen; +} + +void table_host_cache::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_host_cache::rnd_next(void) +{ + int result; + + m_pos.set_at(&m_next_pos); + + if (m_pos.m_index < m_row_count) + { + m_row= &m_all_rows[m_pos.m_index]; + m_next_pos.set_after(&m_pos); + result= 0; + } + else + { + m_row= NULL; + result= HA_ERR_END_OF_FILE; + } + + return result; +} + +int table_host_cache::rnd_pos(const void *pos) +{ + set_position(pos); + DBUG_ASSERT(m_pos.m_index < m_row_count); + m_row= &m_all_rows[m_pos.m_index]; + return 0; +} + +int table_host_cache::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + + DBUG_ASSERT(m_row); + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* IP */ + set_field_varchar_utf8(f, m_row->m_ip, m_row->m_ip_length); + break; + case 1: /* HOST */ + if (m_row->m_hostname_length > 0) + set_field_varchar_utf8(f, m_row->m_hostname, m_row->m_hostname_length); + else + f->set_null(); + break; + case 2: /* HOST_VALIDATED */ + set_field_enum(f, m_row->m_host_validated ? ENUM_YES : ENUM_NO); + break; + case 3: /* SUM_CONNECT_ERRORS */ + set_field_ulonglong(f, m_row->m_sum_connect_errors); + break; + case 4: /* COUNT_HOST_BLOCKED_ERRORS. */ + set_field_ulonglong(f, m_row->m_count_host_blocked_errors); + break; + case 5: /* COUNT_NAMEINFO_TRANSIENT_ERRORS */ + set_field_ulonglong(f, m_row->m_count_nameinfo_transient_errors); + break; + case 6: /* COUNT_NAMEINFO_PERSISTENT_ERRORS */ + set_field_ulonglong(f, m_row->m_count_nameinfo_permanent_errors); + break; + case 7: /* COUNT_FORMAT_ERRORS */ + set_field_ulonglong(f, m_row->m_count_format_errors); + break; + case 8: /* COUNT_ADDRINFO_TRANSIENT_ERRORS */ + set_field_ulonglong(f, m_row->m_count_addrinfo_transient_errors); + break; + case 9: /* COUNT_ADDRINFO_PERSISTENT_ERRORS */ + set_field_ulonglong(f, m_row->m_count_addrinfo_permanent_errors); + break; + case 10: /* COUNT_FCRDNS_ERRORS */ + set_field_ulonglong(f, m_row->m_count_fcrdns_errors); + break; + case 11: /* COUNT_HOST_ACL_ERRORS */ + set_field_ulonglong(f, m_row->m_count_host_acl_errors); + break; + case 12: /* COUNT_NO_AUTH_PLUGIN_ERRORS */ + set_field_ulonglong(f, m_row->m_count_no_auth_plugin_errors); + break; + case 13: /* COUNT_AUTH_PLUGIN_ERRORS */ + set_field_ulonglong(f, m_row->m_count_auth_plugin_errors); + break; + case 14: /* COUNT_HANDSHAKE_ERRORS */ + set_field_ulonglong(f, m_row->m_count_handshake_errors); + break; + case 15: /* COUNT_PROXY_USER_ERRORS */ + set_field_ulonglong(f, m_row->m_count_proxy_user_errors); + break; + case 16: /* COUNT_PROXY_USER_ACL_ERRORS */ + set_field_ulonglong(f, m_row->m_count_proxy_user_acl_errors); + break; + case 17: /* COUNT_AUTHENTICATION_ERRORS */ + set_field_ulonglong(f, m_row->m_count_authentication_errors); + break; + case 18: /* COUNT_SSL_ERRORS */ + set_field_ulonglong(f, m_row->m_count_ssl_errors); + break; + case 19: /* COUNT_MAX_USER_CONNECTION_ERRORS */ + set_field_ulonglong(f, m_row->m_count_max_user_connection_errors); + break; + case 20: /* COUNT_MAX_USER_CONNECTION_PER_HOUR_ERRORS */ + set_field_ulonglong(f, m_row->m_count_max_user_connection_per_hour_errors); + break; + case 21: /* COUNT_DEFAULT_DATABASE_ERRORS */ + set_field_ulonglong(f, m_row->m_count_default_database_errors); + break; + case 22: /* COUNT_INIT_CONNECT_ERRORS */ + set_field_ulonglong(f, m_row->m_count_init_connect_errors); + break; + case 23: /* COUNT_LOCAL_ERRORS */ + set_field_ulonglong(f, m_row->m_count_local_errors); + break; + case 24: /* COUNT_UNKNOWN_ERRORS */ + set_field_ulonglong(f, m_row->m_count_unknown_errors); + break; + case 25: /* FIRST_SEEN */ + set_field_timestamp(f, m_row->m_first_seen); + break; + case 26: /* LAST_SEEN */ + set_field_timestamp(f, m_row->m_last_seen); + break; + case 27: /* FIRST_ERROR_SEEN */ + if (m_row->m_first_error_seen != 0) + set_field_timestamp(f, m_row->m_first_error_seen); + else + f->set_null(); + break; + case 28: /* LAST_ERROR_SEEN */ + if (m_row->m_last_error_seen != 0) + set_field_timestamp(f, m_row->m_last_error_seen); + else + f->set_null(); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + +#endif /* NOT_YET_PORTED */ diff --git a/storage/perfschema/table_host_cache.h b/storage/perfschema/table_host_cache.h new file mode 100644 index 00000000000..543da1274e9 --- /dev/null +++ b/storage/perfschema/table_host_cache.h @@ -0,0 +1,144 @@ +/* Copyright (c) 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_HOST_CACHE_H +#define TABLE_HOST_CACHE_H + +/** + @file storage/perfschema/table_host_cache.h + Table HOST_CACHE (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" + +class Host_entry; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of PERFORMANCE_SCHEMA.HOST_CACHE. */ +struct row_host_cache +{ + /** Column IP. */ + char m_ip[64]; + uint m_ip_length; + /** Column HOST. */ + char m_hostname[255]; + uint m_hostname_length; + /** Column HOST_VALIDATED. */ + bool m_host_validated; + /** Column SUM_CONNECT_ERRORS. */ + ulonglong m_sum_connect_errors; + /** Column COUNT_HOST_BLOCKED_ERRORS. */ + ulonglong m_count_host_blocked_errors; + /** Column COUNT_NAMEINFO_TRANSIENT_ERRORS. */ + ulonglong m_count_nameinfo_transient_errors; + /** Column COUNT_NAMEINFO_PERMANENT_ERRORS. */ + ulonglong m_count_nameinfo_permanent_errors; + /** Column COUNT_FORMAT_ERRORS. */ + ulonglong m_count_format_errors; + /** Column COUNT_ADDRINFO_TRANSIENT_ERRORS. */ + ulonglong m_count_addrinfo_transient_errors; + /** Column COUNT_ADDRINFO_PERMANENT_ERRORS. */ + ulonglong m_count_addrinfo_permanent_errors; + /** Column COUNT_FCRDNS_ERRORS. */ + ulonglong m_count_fcrdns_errors; + /** Column COUNT_HOST_ACL_ERRORS. */ + ulonglong m_count_host_acl_errors; + /** Column COUNT_NO_AUTH_PLUGIN_ERRORS. */ + ulonglong m_count_no_auth_plugin_errors; + /** Column COUNT_AUTH_PLUGIN_ERRORS. */ + ulonglong m_count_auth_plugin_errors; + /** Column COUNT_HANDSHAKE_ERRORS. */ + ulonglong m_count_handshake_errors; + /** Column COUNT_PROXY_USER_ERRORS. */ + ulonglong m_count_proxy_user_errors; + /** Column COUNT_PROXY_USER_ACL_ERRORS. */ + ulonglong m_count_proxy_user_acl_errors; + /** Column COUNT_AUTHENTICATION_ERRORS. */ + ulonglong m_count_authentication_errors; + /** Column COUNT_SSL_ERRORS. */ + ulonglong m_count_ssl_errors; + /** Column COUNT_MAX_USER_CONNECTION_ERRORS. */ + ulonglong m_count_max_user_connection_errors; + /** Column COUNT_MAX_USER_CONNECTION_PER_HOUR_ERRORS. */ + ulonglong m_count_max_user_connection_per_hour_errors; + /** Column COUNT_DEFAULT_DATABASE_ERRORS. */ + ulonglong m_count_default_database_errors; + /** Column COUNT_INIT_CONNECT_ERRORS. */ + ulonglong m_count_init_connect_errors; + /** Column COUNT_LOCAL_ERRORS. */ + ulonglong m_count_local_errors; + /** Column COUNT_UNKNOWN_ERRORS. */ + ulonglong m_count_unknown_errors; + /** Column FIRST_SEEN. */ + ulonglong m_first_seen; + /** Column LAST_SEEN. */ + ulonglong m_last_seen; + /** Column FIRST_ERROR_SEEN. */ + ulonglong m_first_error_seen; + /** Column LAST_ERROR_SEEN. */ + ulonglong m_last_error_seen; +}; + +/** Table PERFORMANCE_SCHEMA.HOST_CACHE. */ +class table_host_cache : public PFS_engine_table +{ +public: + /** Table share. */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_host_cache(); + +public: + ~table_host_cache() + {} + +private: + void materialize(THD *thd); + static void make_row(Host_entry *entry, row_host_cache *row); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + row_host_cache *m_all_rows; + uint m_row_count; + /** Current row. */ + row_host_cache *m_row; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_hosts.cc b/storage/perfschema/table_hosts.cc new file mode 100644 index 00000000000..8e919ec0724 --- /dev/null +++ b/storage/perfschema/table_hosts.cc @@ -0,0 +1,147 @@ +/* Copyright (c) 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include "my_global.h" +#include "my_pthread.h" +#include "table_hosts.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_account.h" +#include "pfs_host.h" +#include "pfs_visitor.h" + +THR_LOCK table_hosts::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("HOST") }, + { C_STRING_WITH_LEN("char(60)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("CURRENT_CONNECTIONS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("TOTAL_CONNECTIONS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_hosts::m_field_def= +{ 3, field_types }; + +PFS_engine_table_share +table_hosts::m_share= +{ + { C_STRING_WITH_LEN("hosts") }, + &pfs_truncatable_acl, + &table_hosts::create, + NULL, /* write_row */ + table_hosts::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), /* ref length */ + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* table_hosts::create() +{ + return new table_hosts(); +} + +int +table_hosts::delete_all_rows(void) +{ + reset_events_waits_by_thread(); + reset_events_waits_by_account(); + reset_events_waits_by_host(); + reset_events_stages_by_thread(); + reset_events_stages_by_account(); + reset_events_stages_by_host(); + reset_events_statements_by_thread(); + reset_events_statements_by_account(); + reset_events_statements_by_host(); + purge_all_account(); + purge_all_host(); + return 0; +} + +table_hosts::table_hosts() + : cursor_by_host(& m_share), + m_row_exists(false) +{} + +void table_hosts::make_row(PFS_host *pfs) +{ + pfs_lock lock; + + m_row_exists= false; + pfs->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_host.make_row(pfs)) + return; + + PFS_connection_stat_visitor visitor; + PFS_connection_iterator::visit_host(pfs, true, true, & visitor); + + if (! pfs->m_lock.end_optimistic_lock(& lock)) + return; + + m_row.m_connection_stat.set(& visitor.m_stat); + m_row_exists= true; +} + +int table_hosts::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* HOST */ + m_row.m_host.set_field(f); + break; + case 1: /* CURRENT_CONNECTIONS */ + case 2: /* TOTAL_CONNECTIONS */ + m_row.m_connection_stat.set_field(f->field_index - 1, f); + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} + diff --git a/storage/perfschema/table_hosts.h b/storage/perfschema/table_hosts.h new file mode 100644 index 00000000000..6fdbf1bb0d9 --- /dev/null +++ b/storage/perfschema/table_hosts.h @@ -0,0 +1,80 @@ +/* Copyright (c) 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_HOSTS_H +#define TABLE_HOSTS_H + +#include "pfs_column_types.h" +#include "cursor_by_host.h" +#include "table_helper.h" + +struct PFS_host; + +/** + \addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of PERFORMANCE_SCHEMA.HOSTS. +*/ +struct row_hosts +{ + /** Column HOST. */ + PFS_host_row m_host; + /** Columns CURRENT_CONNECTIONS, TOTAL_CONNECTIONS. */ + PFS_connection_stat_row m_connection_stat; +}; + +/** Table PERFORMANCE_SCHEMA.THREADS. */ +class table_hosts : public cursor_by_host +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + /** Table builder */ + static PFS_engine_table* create(); + static int delete_all_rows(); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + +protected: + table_hosts(); + +public: + ~table_hosts() + {} + +private: + virtual void make_row(PFS_host *pfs); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_hosts m_row; + /** True if the current row exists. */ + bool m_row_exists; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_os_global_by_type.cc b/storage/perfschema/table_os_global_by_type.cc new file mode 100644 index 00000000000..82d176cd5b2 --- /dev/null +++ b/storage/perfschema/table_os_global_by_type.cc @@ -0,0 +1,270 @@ +/* Copyright (c) 2010, 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 + 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/table_os_global_by_type.cc + Table OBJECTS_SUMMARY_GLOBAL_BY_TYPE (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_os_global_by_type.h" +#include "pfs_global.h" + +THR_LOCK table_os_global_by_type::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("OBJECT_TYPE") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_NAME") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_os_global_by_type::m_field_def= +{ 8, field_types }; + +PFS_engine_table_share +table_os_global_by_type::m_share= +{ + { C_STRING_WITH_LEN("objects_summary_global_by_type") }, + &pfs_truncatable_acl, + table_os_global_by_type::create, + NULL, /* write_row */ + table_os_global_by_type::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_os_global_by_type), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_os_global_by_type::create(void) +{ + return new table_os_global_by_type(); +} + +int +table_os_global_by_type::delete_all_rows(void) +{ + reset_table_waits_by_table_handle(); + reset_table_waits_by_table(); + return 0; +} + +table_os_global_by_type::table_os_global_by_type() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_os_global_by_type::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_os_global_by_type::rnd_next(void) +{ + PFS_table_share *table_share; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_view(); + m_pos.next_view()) + { + switch (m_pos.m_index_1) { + case pos_os_global_by_type::VIEW_TABLE: + for ( ; m_pos.m_index_2 < table_share_max; m_pos.m_index_2++) + { + table_share= &table_share_array[m_pos.m_index_2]; + if (table_share->m_lock.is_populated()) + { + make_row(table_share); + m_next_pos.set_after(&m_pos); + return 0; + } + } + break; + default: + break; + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_os_global_by_type::rnd_pos(const void *pos) +{ + PFS_table_share *table_share; + + set_position(pos); + + switch (m_pos.m_index_1) { + case pos_os_global_by_type::VIEW_TABLE: + DBUG_ASSERT(m_pos.m_index_2 < table_share_max); + table_share= &table_share_array[m_pos.m_index_2]; + if (table_share->m_lock.is_populated()) + { + make_row(table_share); + return 0; + } + break; + default: + break; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_os_global_by_type::make_row(PFS_table_share *share) +{ + pfs_lock lock; + PFS_single_stat cumulated_stat; + + m_row_exists= false; + + share->m_lock.begin_optimistic_lock(&lock); + + m_row.m_object_type= share->get_object_type(); + memcpy(m_row.m_schema_name, share->m_schema_name, share->m_schema_name_length); + m_row.m_schema_name_length= share->m_schema_name_length; + memcpy(m_row.m_object_name, share->m_table_name, share->m_table_name_length); + m_row.m_object_name_length= share->m_table_name_length; + share->m_table_stat.sum(& cumulated_stat); + + if (! share->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + + if (share->get_refcount() > 0) + { + /* For all the table handles still opened ... */ + PFS_table *table= table_array; + PFS_table *table_last= table_array + table_max; + for ( ; table < table_last ; table++) + { + if ((table->m_share == share) && (table->m_lock.is_populated())) + { + /* + If the opened table handle is for this table share, + aggregate the table handle statistics. + */ + table->m_table_stat.sum(& cumulated_stat); + } + } + } + + time_normalizer *normalizer= time_normalizer::get(wait_timer); + m_row.m_stat.set(normalizer, &cumulated_stat); +} + +int table_os_global_by_type::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* OBJECT_TYPE */ + set_field_object_type(f, m_row.m_object_type); + break; + case 1: /* SCHEMA_NAME */ + set_field_varchar_utf8(f, m_row.m_schema_name, + m_row.m_schema_name_length); + break; + case 2: /* OBJECT_NAME */ + set_field_varchar_utf8(f, m_row.m_object_name, + m_row.m_object_name_length); + break; + case 3: /* COUNT */ + set_field_ulonglong(f, m_row.m_stat.m_count); + break; + case 4: /* SUM */ + set_field_ulonglong(f, m_row.m_stat.m_sum); + break; + case 5: /* MIN */ + set_field_ulonglong(f, m_row.m_stat.m_min); + break; + case 6: /* AVG */ + set_field_ulonglong(f, m_row.m_stat.m_avg); + break; + case 7: /* MAX */ + set_field_ulonglong(f, m_row.m_stat.m_max); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_os_global_by_type.h b/storage/perfschema/table_os_global_by_type.h new file mode 100644 index 00000000000..585bf6bbca5 --- /dev/null +++ b/storage/perfschema/table_os_global_by_type.h @@ -0,0 +1,130 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_OBJECTS_SUMMARY_GLOBAL_BY_TYPE_H +#define TABLE_OBJECTS_SUMMARY_GLOBAL_BY_TYPE_H + +/** + @file storage/perfschema/table_os_global_by_type.h + Table OBJECTS_SUMMARY_GLOBAL_BY_TYPE (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.OBJECTS_SUMMARY_GLOBAL_BY_TYPE. +*/ +struct row_os_global_by_type +{ + /** Column OBJECT_TYPE. */ + enum_object_type m_object_type; + /** Column SCHEMA_NAME. */ + char m_schema_name[NAME_LEN]; + /** Length in bytes of @c m_schema_name. */ + uint m_schema_name_length; + /** Column OBJECT_NAME. */ + char m_object_name[NAME_LEN]; + /** Length in bytes of @c m_object_name. */ + uint m_object_name_length; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ + PFS_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.OBJECTS_SUMMARY_GLOBAL_BY_TYPE. + Index 1 on object type + Index 2 on object instance (0 based) +*/ +struct pos_os_global_by_type : public PFS_double_index, + public PFS_object_view_constants +{ + pos_os_global_by_type() + : PFS_double_index(FIRST_VIEW, 0) + {} + + inline void reset(void) + { + m_index_1= FIRST_VIEW; + m_index_2= 0; + } + + inline bool has_more_view(void) + { return (m_index_1 <= LAST_VIEW); } + + inline void next_view(void) + { + m_index_1++; + m_index_2= 0; + } +}; + +/** Table PERFORMANCE_SCHEMA.OBJECTS_SUMMARY_GLOBAL_BY_TYPE. */ +class table_os_global_by_type : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_os_global_by_type(); + +public: + ~table_os_global_by_type() + {} + +protected: + void make_row(PFS_table_share *table_share); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_os_global_by_type m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_os_global_by_type m_pos; + /** Next position. */ + pos_os_global_by_type m_next_pos; +}; + + +/** @} */ +#endif diff --git a/storage/perfschema/table_performance_timers.cc b/storage/perfschema/table_performance_timers.cc index acd379bc57b..a891d2f04cd 100644 --- a/storage/perfschema/table_performance_timers.cc +++ b/storage/perfschema/table_performance_timers.cc @@ -63,6 +63,7 @@ table_performance_timers::m_share= &table_performance_timers::create, NULL, /* write_row */ NULL, /* delete_all_rows */ + NULL, /* get_row_count */ COUNT_TIMER_NAME, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, diff --git a/storage/perfschema/table_setup_actors.cc b/storage/perfschema/table_setup_actors.cc new file mode 100644 index 00000000000..15d3d9d22a8 --- /dev/null +++ b/storage/perfschema/table_setup_actors.cc @@ -0,0 +1,302 @@ +/* Copyright (c) 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_setup_actors.cc + Table SETUP_ACTORS (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_setup_actor.h" +#include "table_setup_actors.h" +#include "pfs_global.h" + +THR_LOCK table_setup_actors::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("HOST") }, + { C_STRING_WITH_LEN("char(60)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("USER") }, + { C_STRING_WITH_LEN("char(16)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("ROLE") }, + { C_STRING_WITH_LEN("char(16)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_setup_actors::m_field_def= +{ 3, field_types }; + +PFS_engine_table_share +table_setup_actors::m_share= +{ + { C_STRING_WITH_LEN("setup_actors") }, + &pfs_editable_acl, + table_setup_actors::create, + table_setup_actors::write_row, + table_setup_actors::delete_all_rows, + table_setup_actors::get_row_count, + 1000, /* records */ + sizeof(PFS_simple_index), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* table_setup_actors::create() +{ + return new table_setup_actors(); +} + +int table_setup_actors::write_row(TABLE *table, unsigned char *buf, + Field **fields) +{ + Field *f; + String user_data("%", 1, &my_charset_utf8_bin); + String host_data("%", 1, &my_charset_utf8_bin); + String role_data("%", 1, &my_charset_utf8_bin); + String *user= &user_data; + String *host= &host_data; + String *role= &role_data; + + for (; (f= *fields) ; fields++) + { + if (bitmap_is_set(table->write_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* HOST */ + host= get_field_char_utf8(f, &host_data); + break; + case 1: /* USER */ + user= get_field_char_utf8(f, &user_data); + break; + case 2: /* ROLE */ + role= get_field_char_utf8(f, &role_data); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return insert_setup_actor(user, host, role); +} + +int table_setup_actors::delete_all_rows(void) +{ + return reset_setup_actor(); +} + +ha_rows table_setup_actors::get_row_count(void) +{ + return setup_actor_count(); +} + +table_setup_actors::table_setup_actors() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_setup_actors::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_setup_actors::rnd_next() +{ + PFS_setup_actor *pfs; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < setup_actor_max; + m_pos.next()) + { + pfs= &setup_actor_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_setup_actors::rnd_pos(const void *pos) +{ + PFS_setup_actor *pfs; + + set_position(pos); + + DBUG_ASSERT(m_pos.m_index < setup_actor_max); + pfs= &setup_actor_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_setup_actors::make_row(PFS_setup_actor *pfs) +{ + pfs_lock lock; + + m_row_exists= false; + + pfs->m_lock.begin_optimistic_lock(&lock); + + m_row.m_hostname_length= pfs->m_hostname_length; + if (unlikely((m_row.m_hostname_length == 0) || + (m_row.m_hostname_length > sizeof(m_row.m_hostname)))) + return; + memcpy(m_row.m_hostname, pfs->m_hostname, m_row.m_hostname_length); + + m_row.m_username_length= pfs->m_username_length; + if (unlikely((m_row.m_username_length == 0) || + (m_row.m_username_length > sizeof(m_row.m_username)))) + return; + memcpy(m_row.m_username, pfs->m_username, m_row.m_username_length); + + m_row.m_rolename_length= pfs->m_rolename_length; + if (unlikely((m_row.m_rolename_length == 0) || + (m_row.m_rolename_length > sizeof(m_row.m_rolename)))) + return; + memcpy(m_row.m_rolename, pfs->m_rolename, m_row.m_rolename_length); + + if (pfs->m_lock.end_optimistic_lock(&lock)) + m_row_exists= true; +} + +int table_setup_actors::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* HOST */ + set_field_char_utf8(f, m_row.m_hostname, m_row.m_hostname_length); + break; + case 1: /* USER */ + set_field_char_utf8(f, m_row.m_username, m_row.m_username_length); + break; + case 2: /* ROLE */ + set_field_char_utf8(f, m_row.m_rolename, m_row.m_rolename_length); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + +int table_setup_actors::update_row_values(TABLE *table, + const unsigned char *old_buf, + unsigned char *new_buf, + Field **fields) +{ + Field *f; + + for (; (f= *fields) ; fields++) + { + if (bitmap_is_set(table->write_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* HOST */ + case 1: /* USER */ + case 2: /* ROLE */ + return HA_ERR_WRONG_COMMAND; + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + +int table_setup_actors::delete_row_values(TABLE *table, + const unsigned char *buf, + Field **fields) +{ + Field *f; + String user_data("", 0, &my_charset_utf8_bin); + String host_data("", 0, &my_charset_utf8_bin); + String role_data("", 0, &my_charset_utf8_bin); + String *user= NULL; + String *host= NULL; + String *role= NULL; + + for (; (f= *fields) ; fields++) + { + if (bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* HOST */ + host= get_field_char_utf8(f, &host_data); + break; + case 1: /* USER */ + user= get_field_char_utf8(f, &user_data); + break; + case 2: /* ROLE */ + role= get_field_char_utf8(f, &role_data); + break; + default: + DBUG_ASSERT(false); + } + } + } + + DBUG_ASSERT(user != NULL); + DBUG_ASSERT(host != NULL); + DBUG_ASSERT(role != NULL); + + return delete_setup_actor(user, host, role); +} + diff --git a/storage/perfschema/table_setup_actors.h b/storage/perfschema/table_setup_actors.h new file mode 100644 index 00000000000..be3ab1bdf0d --- /dev/null +++ b/storage/perfschema/table_setup_actors.h @@ -0,0 +1,106 @@ +/* Copyright (c) 2008, 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_SETUP_ACTORS_H +#define TABLE_SETUP_ACTORS_H + +/** + @file storage/perfschema/table_setup_actors.h + Table SETUP_ACTORS (declarations). +*/ + +#include "pfs_engine_table.h" + +struct PFS_setup_actor; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of PERFORMANCE_SCHEMA.SETUP_ACTORS. */ +struct row_setup_actors +{ + /** Column HOST. */ + char m_hostname[HOSTNAME_LENGTH]; + /** Length in bytes of @c m_hostname. */ + uint m_hostname_length; + /** Column USER. */ + char m_username[USERNAME_LENGTH]; + /** Length in bytes of @c m_username. */ + uint m_username_length; + /** Column ROLE. */ + char m_rolename[16]; + /** Length in bytes of @c m_rolename. */ + uint m_rolename_length; +}; + +/** Table PERFORMANCE_SCHEMA.SETUP_ACTORS. */ +class table_setup_actors : public PFS_engine_table +{ +public: + /** Table share. */ + static PFS_engine_table_share m_share; + /** Table builder. */ + static PFS_engine_table* create(); + static int write_row(TABLE *table, unsigned char *buf, Field **fields); + static int delete_all_rows(); + static ha_rows get_row_count(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + virtual int update_row_values(TABLE *table, + const unsigned char *old_buf, + unsigned char *new_buf, + Field **fields); + + virtual int delete_row_values(TABLE *table, + const unsigned char *buf, + Field **fields); + + table_setup_actors(); + +public: + ~table_setup_actors() + {} + +private: + void make_row(PFS_setup_actor *actor); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_setup_actors m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_setup_consumers.cc b/storage/perfschema/table_setup_consumers.cc index 601e0483b14..7b5441b684a 100644 --- a/storage/perfschema/table_setup_consumers.cc +++ b/storage/perfschema/table_setup_consumers.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 @@ -23,41 +23,70 @@ #include "table_setup_consumers.h" #include "pfs_instr.h" #include "pfs_events_waits.h" +#include "pfs_digest.h" -#define COUNT_SETUP_CONSUMERS 8 +#define COUNT_SETUP_CONSUMERS 12 static row_setup_consumers all_setup_consumers_data[COUNT_SETUP_CONSUMERS]= { { - { C_STRING_WITH_LEN("events_waits_current") }, - &flag_events_waits_current + { C_STRING_WITH_LEN("events_stages_current") }, + &flag_events_stages_current, + false }, { - { C_STRING_WITH_LEN("events_waits_history") }, - &flag_events_waits_history + { C_STRING_WITH_LEN("events_stages_history") }, + &flag_events_stages_history, + false }, { - { C_STRING_WITH_LEN("events_waits_history_long") }, - &flag_events_waits_history_long + { C_STRING_WITH_LEN("events_stages_history_long") }, + &flag_events_stages_history_long, + false + }, + { + { C_STRING_WITH_LEN("events_statements_current") }, + &flag_events_statements_current, + false }, { - { C_STRING_WITH_LEN("events_waits_summary_by_thread_by_event_name") }, - &flag_events_waits_summary_by_thread_by_event_name + { C_STRING_WITH_LEN("events_statements_history") }, + &flag_events_statements_history, + false }, { - { C_STRING_WITH_LEN("events_waits_summary_by_event_name") }, - &flag_events_waits_summary_by_event_name + { C_STRING_WITH_LEN("events_statements_history_long") }, + &flag_events_statements_history_long, + false }, { - { C_STRING_WITH_LEN("events_waits_summary_by_instance") }, - &flag_events_waits_summary_by_instance + { C_STRING_WITH_LEN("events_waits_current") }, + &flag_events_waits_current, + false }, { - { C_STRING_WITH_LEN("file_summary_by_event_name") }, - &flag_file_summary_by_event_name + { C_STRING_WITH_LEN("events_waits_history") }, + &flag_events_waits_history, + false }, { - { C_STRING_WITH_LEN("file_summary_by_instance") }, - &flag_file_summary_by_instance + { C_STRING_WITH_LEN("events_waits_history_long") }, + &flag_events_waits_history_long, + false + }, + { + { C_STRING_WITH_LEN("global_instrumentation") }, + &flag_global_instrumentation, + true + }, + { + { C_STRING_WITH_LEN("thread_instrumentation") }, + &flag_thread_instrumentation, + false + }, + { + { C_STRING_WITH_LEN("statements_digest") }, + &flag_statements_digest, + false } }; @@ -89,6 +118,7 @@ table_setup_consumers::m_share= &table_setup_consumers::create, NULL, /* write_row */ NULL, /* delete_all_rows */ + NULL, /* get_row_count */ COUNT_SETUP_CONSUMERS, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, @@ -205,6 +235,9 @@ int table_setup_consumers::update_row_values(TABLE *table, } } + if (m_row->m_refresh) + update_instruments_derived_flags(); + return 0; } diff --git a/storage/perfschema/table_setup_consumers.h b/storage/perfschema/table_setup_consumers.h index 3ef85f6914b..bc7e9d553bb 100644 --- a/storage/perfschema/table_setup_consumers.h +++ b/storage/perfschema/table_setup_consumers.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc. - Use is subject to license terms. +/* Copyright (c) 2008, 2010, 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 @@ -37,6 +36,8 @@ struct row_setup_consumers LEX_STRING m_name; /** Column ENABLED. */ bool *m_enabled_ptr; + /** Hidden column, refresh. */ + bool m_refresh; }; /** Table PERFORMANCE_SCHEMA.SETUP_CONSUMERS. */ diff --git a/storage/perfschema/table_setup_instruments.cc b/storage/perfschema/table_setup_instruments.cc index 480c0dbc13f..31e2adb0f62 100644 --- a/storage/perfschema/table_setup_instruments.cc +++ b/storage/perfschema/table_setup_instruments.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 @@ -21,10 +21,12 @@ #include "my_global.h" #include "my_pthread.h" #include "pfs_instr_class.h" +#include "pfs_instr.h" #include "pfs_column_types.h" #include "pfs_column_values.h" #include "table_setup_instruments.h" #include "pfs_global.h" +#include "pfs_setup_object.h" THR_LOCK table_setup_instruments::m_table_lock; @@ -59,6 +61,7 @@ table_setup_instruments::m_share= &table_setup_instruments::create, NULL, /* write_row */ NULL, /* delete_all_rows */ + NULL, /* get_row_count */ 1000, /* records */ sizeof(pos_setup_instruments), &m_table_lock, @@ -84,56 +87,55 @@ void table_setup_instruments::reset_position(void) int table_setup_instruments::rnd_next(void) { - PFS_mutex_class *mutex_class; - PFS_rwlock_class *rwlock_class; - PFS_cond_class *cond_class; - PFS_file_class *file_class; + PFS_instr_class *instr_class= NULL; + + /* Do not advertise hard coded instruments when disabled. */ + if (! pfs_initialized) + return HA_ERR_END_OF_FILE; for (m_pos.set_at(&m_next_pos); m_pos.has_more_view(); m_pos.next_view()) { - switch (m_pos.m_index_1) { + switch (m_pos.m_index_1) + { case pos_setup_instruments::VIEW_MUTEX: - mutex_class= find_mutex_class(m_pos.m_index_2); - if (mutex_class) - { - make_row(mutex_class); - m_next_pos.set_after(&m_pos); - return 0; - } + instr_class= find_mutex_class(m_pos.m_index_2); break; case pos_setup_instruments::VIEW_RWLOCK: - rwlock_class= find_rwlock_class(m_pos.m_index_2); - if (rwlock_class) - { - make_row(rwlock_class); - m_next_pos.set_after(&m_pos); - return 0; - } + instr_class= find_rwlock_class(m_pos.m_index_2); break; case pos_setup_instruments::VIEW_COND: - cond_class= find_cond_class(m_pos.m_index_2); - if (cond_class) - { - make_row(cond_class); - m_next_pos.set_after(&m_pos); - return 0; - } + instr_class= find_cond_class(m_pos.m_index_2); break; case pos_setup_instruments::VIEW_THREAD: - /* Reserved for WL#4674, PERFORMANCE_SCHEMA Setup For Actors. */ + /* Not used yet */ break; case pos_setup_instruments::VIEW_FILE: - file_class= find_file_class(m_pos.m_index_2); - if (file_class) - { - make_row(file_class); - m_next_pos.set_after(&m_pos); - return 0; - } + instr_class= find_file_class(m_pos.m_index_2); + break; + case pos_setup_instruments::VIEW_TABLE: + instr_class= find_table_class(m_pos.m_index_2); + break; + case pos_setup_instruments::VIEW_STAGE: + instr_class= find_stage_class(m_pos.m_index_2); + break; + case pos_setup_instruments::VIEW_STATEMENT: + instr_class= find_statement_class(m_pos.m_index_2); + break; + case pos_setup_instruments::VIEW_SOCKET: + instr_class= find_socket_class(m_pos.m_index_2); + break; + case pos_setup_instruments::VIEW_IDLE: + instr_class= find_idle_class(m_pos.m_index_2); break; } + if (instr_class) + { + make_row(instr_class); + m_next_pos.set_after(&m_pos); + return 0; + } } return HA_ERR_END_OF_FILE; @@ -141,60 +143,59 @@ int table_setup_instruments::rnd_next(void) int table_setup_instruments::rnd_pos(const void *pos) { - PFS_mutex_class *mutex_class; - PFS_rwlock_class *rwlock_class; - PFS_cond_class *cond_class; - PFS_file_class *file_class; + PFS_instr_class *instr_class= NULL; + + /* Do not advertise hard coded instruments when disabled. */ + if (! pfs_initialized) + return HA_ERR_END_OF_FILE; set_position(pos); - switch (m_pos.m_index_1) { + switch (m_pos.m_index_1) + { case pos_setup_instruments::VIEW_MUTEX: - mutex_class= find_mutex_class(m_pos.m_index_2); - if (mutex_class) - { - make_row(mutex_class); - return 0; - } + instr_class= find_mutex_class(m_pos.m_index_2); break; case pos_setup_instruments::VIEW_RWLOCK: - rwlock_class= find_rwlock_class(m_pos.m_index_2); - if (rwlock_class) - { - make_row(rwlock_class); - return 0; - } + instr_class= find_rwlock_class(m_pos.m_index_2); break; case pos_setup_instruments::VIEW_COND: - cond_class= find_cond_class(m_pos.m_index_2); - if (cond_class) - { - make_row(cond_class); - return 0; - } + instr_class= find_cond_class(m_pos.m_index_2); break; case pos_setup_instruments::VIEW_THREAD: - /* Reserved for WL#4674, PERFORMANCE_SCHEMA Setup For Actors. */ + /* Not used yet */ break; case pos_setup_instruments::VIEW_FILE: - file_class= find_file_class(m_pos.m_index_2); - if (file_class) - { - make_row(file_class); - return 0; - } + instr_class= find_file_class(m_pos.m_index_2); + break; + case pos_setup_instruments::VIEW_TABLE: + instr_class= find_table_class(m_pos.m_index_2); + break; + case pos_setup_instruments::VIEW_STAGE: + instr_class= find_stage_class(m_pos.m_index_2); + break; + case pos_setup_instruments::VIEW_STATEMENT: + instr_class= find_statement_class(m_pos.m_index_2); + break; + case pos_setup_instruments::VIEW_SOCKET: + instr_class= find_socket_class(m_pos.m_index_2); + break; + case pos_setup_instruments::VIEW_IDLE: + instr_class= find_idle_class(m_pos.m_index_2); break; } + if (instr_class) + { + make_row(instr_class); + return 0; + } return HA_ERR_RECORD_DELETED; } void table_setup_instruments::make_row(PFS_instr_class *klass) { - m_row.m_name= &klass->m_name[0]; - m_row.m_name_length= klass->m_name_length; - m_row.m_enabled_ptr= &klass->m_enabled; - m_row.m_timed_ptr= &klass->m_timed; + m_row.m_instr_class= klass; } int table_setup_instruments::read_row_values(TABLE *table, @@ -218,16 +219,13 @@ int table_setup_instruments::read_row_values(TABLE *table, switch(f->field_index) { case 0: /* NAME */ - set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length); + set_field_varchar_utf8(f, m_row.m_instr_class->m_name, m_row.m_instr_class->m_name_length); break; case 1: /* ENABLED */ - set_field_enum(f, (*m_row.m_enabled_ptr) ? ENUM_YES : ENUM_NO); + set_field_enum(f, m_row.m_instr_class->m_enabled ? ENUM_YES : ENUM_NO); break; case 2: /* TIMED */ - if (m_row.m_timed_ptr) - set_field_enum(f, (*m_row.m_timed_ptr) ? ENUM_YES : ENUM_NO); - else - set_field_enum(f, ENUM_NO); + set_field_enum(f, m_row.m_instr_class->m_timed ? ENUM_YES : ENUM_NO); break; default: DBUG_ASSERT(false); @@ -256,14 +254,11 @@ int table_setup_instruments::update_row_values(TABLE *table, return HA_ERR_WRONG_COMMAND; case 1: /* ENABLED */ value= (enum_yes_no) get_field_enum(f); - *m_row.m_enabled_ptr= (value == ENUM_YES) ? true : false; + m_row.m_instr_class->m_enabled= (value == ENUM_YES) ? true : false; break; case 2: /* TIMED */ - if (m_row.m_timed_ptr) - { - value= (enum_yes_no) get_field_enum(f); - *m_row.m_timed_ptr= (value == ENUM_YES) ? true : false; - } + value= (enum_yes_no) get_field_enum(f); + m_row.m_instr_class->m_timed= (value == ENUM_YES) ? true : false; break; default: DBUG_ASSERT(false); @@ -271,6 +266,41 @@ int table_setup_instruments::update_row_values(TABLE *table, } } + switch (m_pos.m_index_1) + { + case pos_setup_instruments::VIEW_MUTEX: + update_mutex_derived_flags(); + break; + case pos_setup_instruments::VIEW_RWLOCK: + update_rwlock_derived_flags(); + break; + case pos_setup_instruments::VIEW_COND: + update_cond_derived_flags(); + break; + case pos_setup_instruments::VIEW_THREAD: + /* Not used yet */ + break; + case pos_setup_instruments::VIEW_FILE: + update_file_derived_flags(); + break; + case pos_setup_instruments::VIEW_TABLE: + update_table_derived_flags(); + break; + case pos_setup_instruments::VIEW_STAGE: + case pos_setup_instruments::VIEW_STATEMENT: + /* No flag to update. */ + break; + case pos_setup_instruments::VIEW_SOCKET: + update_socket_derived_flags(); + break; + case pos_setup_instruments::VIEW_IDLE: + /* No flag to update. */ + break; + default: + DBUG_ASSERT(false); + break; + } + return 0; } diff --git a/storage/perfschema/table_setup_instruments.h b/storage/perfschema/table_setup_instruments.h index 42b1a6122c8..cb4c6a06de1 100644 --- a/storage/perfschema/table_setup_instruments.h +++ b/storage/perfschema/table_setup_instruments.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc. - Use is subject to license terms. +/* 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 @@ -33,38 +32,38 @@ /** A row of PERFORMANCE_SCHEMA.SETUP_INSTRUMENTS. */ struct row_setup_instruments { - /** Column NAME. */ - const char *m_name; - /** Length in bytes of @c m_name. */ - uint m_name_length; - /** Column ENABLED. */ - bool *m_enabled_ptr; - /** Column TIMED. */ - bool *m_timed_ptr; + /** Columns NAME, ENABLED, TIMED. */ + PFS_instr_class *m_instr_class; }; /** Position of a cursor on PERFORMANCE_SCHEMA.SETUP_INSTRUMENTS. */ struct pos_setup_instruments : public PFS_double_index { + static const uint FIRST_VIEW= 1; static const uint VIEW_MUTEX= 1; static const uint VIEW_RWLOCK= 2; static const uint VIEW_COND= 3; - /** Reverved for WL#4674, PERFORMANCE_SCHEMA Setup For Actors. */ static const uint VIEW_THREAD= 4; static const uint VIEW_FILE= 5; + static const uint VIEW_TABLE= 6; + static const uint VIEW_STAGE= 7; + static const uint VIEW_STATEMENT= 8; + static const uint VIEW_SOCKET= 9; + static const uint VIEW_IDLE= 10; + static const uint LAST_VIEW= 10; pos_setup_instruments() - : PFS_double_index(VIEW_MUTEX, 1) + : PFS_double_index(FIRST_VIEW, 1) {} inline void reset(void) { - m_index_1= VIEW_MUTEX; + m_index_1= FIRST_VIEW; m_index_2= 1; } inline bool has_more_view(void) - { return (m_index_1 <= VIEW_FILE); } + { return (m_index_1 <= LAST_VIEW); } inline void next_view(void) { diff --git a/storage/perfschema/table_setup_objects.cc b/storage/perfschema/table_setup_objects.cc new file mode 100644 index 00000000000..33e360e989b --- /dev/null +++ b/storage/perfschema/table_setup_objects.cc @@ -0,0 +1,382 @@ +/* Copyright (c) 2008, 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_setup_objects.cc + Table SETUP_OBJECTS (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_setup_object.h" +#include "table_setup_objects.h" +#include "table_helper.h" +#include "pfs_global.h" + +THR_LOCK table_setup_objects::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("OBJECT_TYPE") }, + { C_STRING_WITH_LEN("enum(\'TABLE\')") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_NAME") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("ENABLED") }, + { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("TIMED") }, + { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_setup_objects::m_field_def= +{ 5, field_types }; + +PFS_engine_table_share +table_setup_objects::m_share= +{ + { C_STRING_WITH_LEN("setup_objects") }, + &pfs_editable_acl, + table_setup_objects::create, + table_setup_objects::write_row, + table_setup_objects::delete_all_rows, + table_setup_objects::get_row_count, + 1000, /* records */ + sizeof(PFS_simple_index), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +int update_derived_flags() +{ + PFS_thread *thread= PFS_thread::get_current_thread(); + if (unlikely(thread == NULL)) + return HA_ERR_OUT_OF_MEM; + + update_table_share_derived_flags(thread); + update_table_derived_flags(); + return 0; +} + +PFS_engine_table* table_setup_objects::create(void) +{ + return new table_setup_objects(); +} + +int table_setup_objects::write_row(TABLE *table, unsigned char *buf, + Field **fields) +{ + int result; + Field *f; + enum_object_type object_type= OBJECT_TYPE_TABLE; + String object_schema_data("%", 1, &my_charset_utf8_bin); + String object_name_data("%", 1, &my_charset_utf8_bin); + String *object_schema= &object_schema_data; + String *object_name= &object_name_data; + enum_yes_no enabled_value= ENUM_YES; + enum_yes_no timed_value= ENUM_YES; + bool enabled= true; + bool timed= true; + + for (; (f= *fields) ; fields++) + { + if (bitmap_is_set(table->write_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* OBJECT_TYPE */ + object_type= (enum_object_type) get_field_enum(f); + break; + case 1: /* OBJECT_SCHEMA */ + object_schema= get_field_varchar_utf8(f, &object_schema_data); + break; + case 2: /* OBJECT_NAME */ + object_name= get_field_varchar_utf8(f, &object_name_data); + break; + case 3: /* ENABLED */ + enabled_value= (enum_yes_no) get_field_enum(f); + break; + case 4: /* TIMED */ + timed_value= (enum_yes_no) get_field_enum(f); + break; + default: + DBUG_ASSERT(false); + } + } + } + + /* Reject illegal enum values in OBJECT_TYPE */ + if (object_type != OBJECT_TYPE_TABLE) + return HA_ERR_NO_REFERENCED_ROW; + + /* Reject illegal enum values in ENABLED */ + if ((enabled_value != ENUM_YES) && (enabled_value != ENUM_NO)) + return HA_ERR_NO_REFERENCED_ROW; + + /* Reject illegal enum values in TIMED */ + if ((timed_value != ENUM_YES) && (timed_value != ENUM_NO)) + return HA_ERR_NO_REFERENCED_ROW; + + enabled= (enabled_value == ENUM_YES) ? true : false; + timed= (timed_value == ENUM_YES) ? true : false; + + result= insert_setup_object(object_type, object_schema, object_name, + enabled, timed); + if (result == 0) + result= update_derived_flags(); + return result; +} + +int table_setup_objects::delete_all_rows(void) +{ + int result= reset_setup_object(); + if (result == 0) + result= update_derived_flags(); + return result; +} + +ha_rows table_setup_objects::get_row_count(void) +{ + return setup_object_count(); +} + +table_setup_objects::table_setup_objects() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_setup_objects::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_setup_objects::rnd_next(void) +{ + PFS_setup_object *pfs; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < setup_object_max; + m_pos.next()) + { + pfs= &setup_object_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_setup_objects::rnd_pos(const void *pos) +{ + PFS_setup_object *pfs; + + set_position(pos); + + DBUG_ASSERT(m_pos.m_index < setup_object_max); + pfs= &setup_object_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_setup_objects::make_row(PFS_setup_object *pfs) +{ + pfs_lock lock; + + m_row_exists= false; + + pfs->m_lock.begin_optimistic_lock(&lock); + + m_row.m_object_type= pfs->get_object_type(); + memcpy(m_row.m_schema_name, pfs->m_schema_name, pfs->m_schema_name_length); + m_row.m_schema_name_length= pfs->m_schema_name_length; + memcpy(m_row.m_object_name, pfs->m_object_name, pfs->m_object_name_length); + m_row.m_object_name_length= pfs->m_object_name_length; + m_row.m_enabled_ptr= &pfs->m_enabled; + m_row.m_timed_ptr= &pfs->m_timed; + + if (pfs->m_lock.end_optimistic_lock(&lock)) + m_row_exists= true; +} + +int table_setup_objects::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* OBJECT_TYPE */ + set_field_enum(f, m_row.m_object_type); + break; + case 1: /* OBJECT_SCHEMA */ + if (m_row.m_schema_name_length) + set_field_varchar_utf8(f, m_row.m_schema_name, + m_row.m_schema_name_length); + else + f->set_null(); + break; + case 2: /* OBJECT_NAME */ + if (m_row.m_object_name_length) + set_field_varchar_utf8(f, m_row.m_object_name, + m_row.m_object_name_length); + else + f->set_null(); + break; + case 3: /* ENABLED */ + set_field_enum(f, (*m_row.m_enabled_ptr) ? ENUM_YES : ENUM_NO); + break; + case 4: /* TIMED */ + set_field_enum(f, (*m_row.m_timed_ptr) ? ENUM_YES : ENUM_NO); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + +int table_setup_objects::update_row_values(TABLE *table, + const unsigned char *, + unsigned char *, + Field **fields) +{ + int result; + Field *f; + enum_yes_no value; + + for (; (f= *fields) ; fields++) + { + if (bitmap_is_set(table->write_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* OBJECT_TYPE */ + case 1: /* OBJECT_SCHEMA */ + case 2: /* OBJECT_NAME */ + return HA_ERR_WRONG_COMMAND; + case 3: /* ENABLED */ + value= (enum_yes_no) get_field_enum(f); + /* Reject illegal enum values in ENABLED */ + if ((value != ENUM_YES) && (value != ENUM_NO)) + return HA_ERR_NO_REFERENCED_ROW; + *m_row.m_enabled_ptr= (value == ENUM_YES) ? true : false; + break; + case 4: /* TIMED */ + value= (enum_yes_no) get_field_enum(f); + /* Reject illegal enum values in TIMED */ + if ((value != ENUM_YES) && (value != ENUM_NO)) + return HA_ERR_NO_REFERENCED_ROW; + *m_row.m_timed_ptr= (value == ENUM_YES) ? true : false; + break; + default: + DBUG_ASSERT(false); + } + } + } + + result= update_derived_flags(); + return result; +} + +int table_setup_objects::delete_row_values(TABLE *table, + const unsigned char *buf, + Field **fields) +{ + int result; + Field *f; + enum_object_type object_type= OBJECT_TYPE_TABLE; + String object_schema_data("", 0, &my_charset_utf8_bin); + String object_name_data("", 0, &my_charset_utf8_bin); + String *object_schema= NULL; + String *object_name= NULL; + + for (; (f= *fields) ; fields++) + { + if (bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* OBJECT_TYPE */ + object_type= (enum_object_type) get_field_enum(f); + break; + case 1: /* OBJECT_SCHEMA */ + object_schema= get_field_varchar_utf8(f, &object_schema_data); + break; + case 2: /* OBJECT_NAME */ + object_name= get_field_varchar_utf8(f, &object_name_data); + break; + case 3: /* ENABLED */ + case 4: /* TIMED */ + break; + default: + DBUG_ASSERT(false); + } + } + } + + DBUG_ASSERT(object_schema != NULL); + DBUG_ASSERT(object_name != NULL); + + result= delete_setup_object(object_type, object_schema, object_name); + if (result == 0) + result= update_derived_flags(); + return result; +} + diff --git a/storage/perfschema/table_setup_objects.h b/storage/perfschema/table_setup_objects.h new file mode 100644 index 00000000000..4b31fa6a8a6 --- /dev/null +++ b/storage/perfschema/table_setup_objects.h @@ -0,0 +1,109 @@ +/* Copyright (c) 2008, 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_SETUP_OBJECTS_H +#define TABLE_SETUP_OBJECTS_H + +/** + @file storage/perfschema/table_setup_objects.h + Table SETUP_OBJECTS (declarations). +*/ + +#include "pfs_engine_table.h" +#include "table_helper.h" + +struct PFS_setup_object; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of PERFORMANCE_SCHEMA.SETUP_OBJECTS. */ +struct row_setup_objects +{ + /** Column OBJECT_TYPE. */ + enum_object_type m_object_type; + /** Column SCHEMA_NAME. */ + char m_schema_name[NAME_LEN]; + /** Length in bytes of @c m_schema_name. */ + uint m_schema_name_length; + /** Column OBJECT_NAME. */ + char m_object_name[NAME_LEN]; + /** Length in bytes of @c m_object_name. */ + uint m_object_name_length; + /** Column ENABLED. */ + bool *m_enabled_ptr; + /** Column TIMED. */ + bool *m_timed_ptr; +}; + +/** Table PERFORMANCE_SCHEMA.SETUP_OBJECTS. */ +class table_setup_objects : public PFS_engine_table +{ +public: + /** Table share. */ + static PFS_engine_table_share m_share; + /** Table builder. */ + static PFS_engine_table* create(); + static int write_row(TABLE *table, unsigned char *buf, Field **fields); + static int delete_all_rows(); + static ha_rows get_row_count(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + virtual int update_row_values(TABLE *table, + const unsigned char *old_buf, + unsigned char *new_buf, + Field **fields); + + virtual int delete_row_values(TABLE *table, + const unsigned char *buf, + Field **fields); + + table_setup_objects(); + +public: + ~table_setup_objects() + {} + +private: + void make_row(PFS_setup_object *pfs); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_setup_objects m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_setup_timers.cc b/storage/perfschema/table_setup_timers.cc index f8b1bfa4fe2..a6a8a52b7e5 100644 --- a/storage/perfschema/table_setup_timers.cc +++ b/storage/perfschema/table_setup_timers.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 @@ -24,12 +24,25 @@ #include "pfs_column_values.h" #include "pfs_timer.h" -#define COUNT_SETUP_TIMERS 1 +#define COUNT_SETUP_TIMERS 4 + static row_setup_timers all_setup_timers_data[COUNT_SETUP_TIMERS]= { { + { C_STRING_WITH_LEN("idle") }, + &idle_timer + }, + { { C_STRING_WITH_LEN("wait") }, &wait_timer + }, + { + { C_STRING_WITH_LEN("stage") }, + &stage_timer + }, + { + { C_STRING_WITH_LEN("statement") }, + &statement_timer } }; @@ -62,6 +75,7 @@ table_setup_timers::m_share= &table_setup_timers::create, NULL, /* write_row */ NULL, /* delete_all_rows */ + NULL, /* get_row_count */ COUNT_SETUP_TIMERS, sizeof(PFS_simple_index), &m_table_lock, diff --git a/storage/perfschema/table_setup_timers.h b/storage/perfschema/table_setup_timers.h index c147de63a21..a81e6fefaaf 100644 --- a/storage/perfschema/table_setup_timers.h +++ b/storage/perfschema/table_setup_timers.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc. - Use is subject to license terms. +/* Copyright (c) 2008, 2010, 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 diff --git a/storage/perfschema/table_socket_instances.cc b/storage/perfschema/table_socket_instances.cc new file mode 100644 index 00000000000..f913c8fcc65 --- /dev/null +++ b/storage/perfschema/table_socket_instances.cc @@ -0,0 +1,232 @@ +/* Copyright (c) 2008, 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_socket_instances.cc + Table SOCKET_INSTANCES (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_socket_instances.h" +#include "pfs_global.h" + +THR_LOCK table_socket_instances::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("THREAD_ID") }, + { C_STRING_WITH_LEN("int(11)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SOCKET_ID") }, + { C_STRING_WITH_LEN("int(11)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("IP") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("PORT") }, + { C_STRING_WITH_LEN("int(11)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("STATE") }, + { C_STRING_WITH_LEN("enum('IDLE','ACTIVE')") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_socket_instances::m_field_def= +{ 7, field_types }; + +PFS_engine_table_share +table_socket_instances::m_share= +{ + { C_STRING_WITH_LEN("socket_instances") }, + &pfs_readonly_acl, + &table_socket_instances::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* table_socket_instances::create(void) +{ + return new table_socket_instances(); +} + +table_socket_instances::table_socket_instances() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_socket_instances::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_socket_instances::rnd_next(void) +{ + PFS_socket *pfs; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < socket_max; + m_pos.next()) + { + pfs= &socket_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_socket_instances::rnd_pos(const void *pos) +{ + PFS_socket *pfs; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < socket_max); + pfs= &socket_array[m_pos.m_index]; + + if (! pfs->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + make_row(pfs); + return 0; +} + +void table_socket_instances::make_row(PFS_socket *pfs) +{ + pfs_lock lock; + PFS_socket_class *safe_class; + + m_row_exists= false; + + /* Protect this reader against a socket delete */ + pfs->m_lock.begin_optimistic_lock(&lock); + + safe_class= sanitize_socket_class(pfs->m_class); + if (unlikely(safe_class == NULL)) + return; + + /** Extract ip address and port from raw address */ + m_row.m_ip_length= pfs_get_socket_address(m_row.m_ip, sizeof(m_row.m_ip), + &m_row.m_port, + &pfs->m_sock_addr, pfs->m_addr_len); + m_row.m_event_name= safe_class->m_name; + m_row.m_event_name_length= safe_class->m_name_length; + m_row.m_identity= pfs->m_identity; + m_row.m_fd= pfs->m_fd; + m_row.m_state= (pfs->m_idle ? PSI_SOCKET_STATE_IDLE + : PSI_SOCKET_STATE_ACTIVE); + PFS_thread *safe_thread= sanitize_thread(pfs->m_thread_owner); + + if (safe_thread != NULL) + { + m_row.m_thread_id= safe_thread->m_thread_internal_id; + m_row.m_thread_id_set= true; + } + else + m_row.m_thread_id_set= false; + + + if (pfs->m_lock.end_optimistic_lock(&lock)) + m_row_exists= true; +} + +int table_socket_instances::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(!m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* EVENT_NAME */ + set_field_varchar_utf8(f, m_row.m_event_name, m_row.m_event_name_length); + break; + case 1: /* OBJECT_INSTANCE_BEGIN */ + set_field_ulonglong(f, (intptr)m_row.m_identity); + break; + case 2: /* THREAD_ID */ + if (m_row.m_thread_id_set) + set_field_ulong(f, m_row.m_thread_id); + else + f->set_null(); + break; + case 3: /* SOCKET_ID */ + set_field_ulong(f, m_row.m_fd); + break; + case 4: /* IP */ + set_field_varchar_utf8(f, m_row.m_ip, m_row.m_ip_length); + break; + case 5: /* PORT */ + set_field_ulong(f, m_row.m_port); + break; + case 6: /* STATE */ + set_field_enum(f, m_row.m_state); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_socket_instances.h b/storage/perfschema/table_socket_instances.h new file mode 100644 index 00000000000..2a80aeaa76a --- /dev/null +++ b/storage/perfschema/table_socket_instances.h @@ -0,0 +1,102 @@ +/* Copyright (c) 2008, 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_SOCKET_INSTANCES_H +#define TABLE_SOCKET_INSTANCES_H + +/** + @file storage/perfschema/table_socket_instances.h + Table SOCKET_INSTANCES (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of PERFORMANCE_SCHEMA.SOCKET_INSTANCES. */ +struct row_socket_instances +{ + /** Column EVENT_NAME. */ + const char *m_event_name; + /** Length in bytes of @c m_event_name. */ + uint m_event_name_length; + /** Column OBJECT_INSTANCE_BEGIN */ + const void *m_identity; + /** Column THREAD_ID */ + uint m_thread_id; + /** True if thread_is is set */ + bool m_thread_id_set; + /** Column SOCKET_ID */ + uint m_fd; + /** Socket ip address, IPV4 or IPV6 */ + char m_ip[INET6_ADDRSTRLEN+1]; + /** Length in bytes of @c m_ip. */ + uint m_ip_length; + /** Column PORT */ + uint m_port; + /** Socket state: ACTIVE or IDLE */ + PSI_socket_state m_state; + + row_socket_instances() {m_thread_id_set= false;} +}; + +/** Table PERFORMANCE_SCHEMA.SOCKET_INSTANCES. */ +class table_socket_instances : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +private: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_socket_instances(); + +public: + ~table_socket_instances() + {} + +private: + void make_row(PFS_socket *pfs); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_socket_instances m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_socket_summary_by_event_name.cc b/storage/perfschema/table_socket_summary_by_event_name.cc new file mode 100644 index 00000000000..0262178e5b5 --- /dev/null +++ b/storage/perfschema/table_socket_summary_by_event_name.cc @@ -0,0 +1,348 @@ +/* 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_socket_summary_by_event_name.cc + Table SOCKET_EVENT_NAMES (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_socket_summary_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" + +THR_LOCK table_socket_summary_by_event_name::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + + /** Read */ + { + { C_STRING_WITH_LEN("COUNT_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + + /** Write */ + { + { C_STRING_WITH_LEN("COUNT_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + + /** Misc */ + { + { C_STRING_WITH_LEN("COUNT_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_socket_summary_by_event_name::m_field_def= +{ 23, field_types }; + +PFS_engine_table_share +table_socket_summary_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("socket_summary_by_event_name") }, + &pfs_readonly_acl, + &table_socket_summary_by_event_name::create, + NULL, /* write_row */ + table_socket_summary_by_event_name::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* table_socket_summary_by_event_name::create(void) +{ + return new table_socket_summary_by_event_name(); +} + +table_socket_summary_by_event_name::table_socket_summary_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(1), m_next_pos(1) +{} + +int table_socket_summary_by_event_name::delete_all_rows(void) +{ + reset_socket_instance_io(); + reset_socket_class_io(); + return 0; +} + +void table_socket_summary_by_event_name::reset_position(void) +{ + m_pos.m_index= 1; + m_next_pos.m_index= 1; +} + +int table_socket_summary_by_event_name::rnd_next(void) +{ + PFS_socket_class *socket_class; + + m_pos.set_at(&m_next_pos); + + socket_class= find_socket_class(m_pos.m_index); + if (socket_class) + { + make_row(socket_class); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int table_socket_summary_by_event_name::rnd_pos(const void *pos) +{ + PFS_socket_class *socket_class; + + set_position(pos); + + socket_class= find_socket_class(m_pos.m_index); + if (socket_class) + { + make_row(socket_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_socket_summary_by_event_name::make_row(PFS_socket_class *socket_class) +{ + m_row.m_event_name.make_row(socket_class); + + PFS_instance_socket_io_stat_visitor visitor; + PFS_instance_iterator::visit_socket_instances(socket_class, &visitor); + + time_normalizer *normalizer= time_normalizer::get(wait_timer); + + /* Collect timer and byte count stats */ + m_row.m_io_stat.set(normalizer, &visitor.m_socket_io_stat); + m_row_exists= true; +} + +int table_socket_summary_by_event_name::read_row_values(TABLE *table, + unsigned char *, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(!m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 0); + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + case 1: /* COUNT_STAR */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_count); + break; + case 2: /* SUM_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_sum); + break; + case 3: /* MIN_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_min); + break; + case 4: /* AVG_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_avg); + break; + case 5: /* MAX_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_max); + break; + + case 6: /* COUNT_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_count); + break; + case 7: /* SUM_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_sum); + break; + case 8: /* MIN_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_min); + break; + case 9: /* AVG_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_avg); + break; + case 10: /* MAX_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_max); + break; + case 11: /* SUM_NUMBER_OF_BYTES_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_bytes); + break; + + case 12: /* COUNT_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_count); + break; + case 13: /* SUM_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_sum); + break; + case 14: /* MIN_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_min); + break; + case 15: /* AVG_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_avg); + break; + case 16: /* MAX_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_max); + break; + case 17: /* SUM_NUMBER_OF_BYTES_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_bytes); + break; + + case 18: /* COUNT_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_count); + break; + case 19: /* SUM_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_sum); + break; + case 20: /* MIN_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_min); + break; + case 21: /* AVG_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_avg); + break; + case 22: /* MAX_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_max); + break; + + default: + DBUG_ASSERT(false); + break; + } + } // if + } // for + + return 0; +} + diff --git a/storage/perfschema/table_socket_summary_by_event_name.h b/storage/perfschema/table_socket_summary_by_event_name.h new file mode 100644 index 00000000000..b34bed41f83 --- /dev/null +++ b/storage/perfschema/table_socket_summary_by_event_name.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2008, 2010, 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_SOCKET_SUMMARY_BY_EVENT_NAME_H +#define TABLE_SOCKET_SUMMARY_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_socket_summary_by_event_name.h + Table SOCKET_SUMMARY_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.SOCKET_SUMMARY_BY_EVENT_NAME. +*/ +struct row_socket_summary_by_event_name +{ + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER and NUMBER_OF_BYTES for each operation. */ + PFS_socket_io_stat_row m_io_stat; +}; + +/** Table PERFORMANCE_SCHEMA.SOCKET_SUMMARY_BY_EVENT_NAME. */ +class table_socket_summary_by_event_name : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +private: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_socket_summary_by_event_name(); + +public: + ~table_socket_summary_by_event_name() + {} + +private: + void make_row(PFS_socket_class *socket_class); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_socket_summary_by_event_name m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_socket_summary_by_instance.cc b/storage/perfschema/table_socket_summary_by_instance.cc new file mode 100644 index 00000000000..5b177cb3dce --- /dev/null +++ b/storage/perfschema/table_socket_summary_by_instance.cc @@ -0,0 +1,369 @@ +/* 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_socket_summary_by_instance.cc + Table SOCKET_SUMMARY_BY_INSTANCE (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_socket_summary_by_instance.h" +#include "pfs_global.h" + +THR_LOCK table_socket_summary_by_instance::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("EVENT_NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + + /** Read */ + { + { C_STRING_WITH_LEN("COUNT_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + + /** Write */ + { + { C_STRING_WITH_LEN("COUNT_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_NUMBER_OF_BYTES_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + + /** Misc */ + { + { C_STRING_WITH_LEN("COUNT_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_MISC") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_socket_summary_by_instance::m_field_def= +{ 24, field_types }; + +PFS_engine_table_share +table_socket_summary_by_instance::m_share= +{ + { C_STRING_WITH_LEN("socket_summary_by_instance") }, + &pfs_readonly_acl, + &table_socket_summary_by_instance::create, + NULL, /* write_row */ + table_socket_summary_by_instance::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* table_socket_summary_by_instance::create(void) +{ + return new table_socket_summary_by_instance(); +} + +table_socket_summary_by_instance::table_socket_summary_by_instance() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +int table_socket_summary_by_instance::delete_all_rows(void) +{ + reset_socket_instance_io(); + return 0; +} + +void table_socket_summary_by_instance::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_socket_summary_by_instance::rnd_next(void) +{ + PFS_socket *pfs; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < socket_max; + m_pos.next()) + { + pfs= &socket_array[m_pos.m_index]; + if (pfs->m_lock.is_populated()) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_socket_summary_by_instance::rnd_pos(const void *pos) +{ + PFS_socket *pfs; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < socket_max); + pfs= &socket_array[m_pos.m_index]; + + if (! pfs->m_lock.is_populated()) + return HA_ERR_RECORD_DELETED; + + make_row(pfs); + return 0; +} + +void table_socket_summary_by_instance::make_row(PFS_socket *pfs) +{ + pfs_lock lock; + PFS_socket_class *safe_class; + + m_row_exists= false; + + /* Protect this reader against a socket delete */ + pfs->m_lock.begin_optimistic_lock(&lock); + + safe_class= sanitize_socket_class(pfs->m_class); + if (unlikely(safe_class == NULL)) + return; + + m_row.m_event_name.make_row(safe_class); + m_row.m_identity= pfs->m_identity; + + time_normalizer *normalizer= time_normalizer::get(wait_timer); + + /* Collect timer and byte count stats */ + m_row.m_io_stat.set(normalizer, &pfs->m_socket_stat.m_io_stat); + + if (!pfs->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; +} + +int table_socket_summary_by_instance::read_row_values(TABLE *table, + unsigned char *, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(!m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 0); + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + case 1: /* OBJECT_INSTANCE */ + set_field_ulonglong(f, (ulonglong)m_row.m_identity); + break; + + case 2:/* COUNT_STAR */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_count); + break; + case 3:/* SUM_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_sum); + break; + case 4: /* MIN_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_min); + break; + case 5: /* AVG_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_avg); + break; + case 6: /* MAX_TIMER_WAIT */ + set_field_ulonglong(f, m_row.m_io_stat.m_all.m_waits.m_max); + break; + + case 7: /* COUNT_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_count); + break; + case 8: /* SUM_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_sum); + break; + case 9: /* MIN_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_min); + break; + case 10: /* AVG_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_avg); + break; + case 11: /* MAX_TIMER_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_waits.m_max); + break; + case 12: /* SUM_NUMBER_OF_BYTES_READ */ + set_field_ulonglong(f, m_row.m_io_stat.m_read.m_bytes); + break; + + case 13: /* COUNT_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_count); + break; + case 14: /* SUM_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_sum); + break; + case 15: /* MIN_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_min); + break; + case 16: /* AVG_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_avg); + break; + case 17: /* MAX_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_waits.m_max); + break; + case 18: /* SUM_NUMBER_OF_BYTES_WRITE */ + set_field_ulonglong(f, m_row.m_io_stat.m_write.m_bytes); + break; + + case 19: /* COUNT_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_count); + break; + case 20: /* SUM_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_sum); + break; + case 21: /* MIN_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_min); + break; + case 22: /* AVG_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_avg); + break; + case 23: /* MAX_TIMER_MISC */ + set_field_ulonglong(f, m_row.m_io_stat.m_misc.m_waits.m_max); + break; + default: + DBUG_ASSERT(false); + break; + } + } + } + + return 0; +} diff --git a/storage/perfschema/table_socket_summary_by_instance.h b/storage/perfschema/table_socket_summary_by_instance.h new file mode 100644 index 00000000000..f4c8ea41d8c --- /dev/null +++ b/storage/perfschema/table_socket_summary_by_instance.h @@ -0,0 +1,95 @@ +/* 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_SOCKET_SUMMARY_BY_INSTANCE_H +#define TABLE_SOCKET_SUMMARY_BY_INSTANCE_H + +/** + @file storage/perfschema/table_socket_summary_by_instance.h + Table SOCKET_SUMMARY_BY_INSTANCE (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.SOCKET_SUMMARY_BY_INSTANCE. +*/ +struct row_socket_summary_by_instance +{ + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + + /** Column OBJECT_INSTANCE_BEGIN */ + const void *m_identity; + + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER and NUMBER_OF_BYTES for each operation. */ + PFS_socket_io_stat_row m_io_stat; +}; + +/** Table PERFORMANCE_SCHEMA.SOCKET_SUMMARY_BY_INSTANCE. */ +class table_socket_summary_by_instance : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +private: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_socket_summary_by_instance(); + +public: + ~table_socket_summary_by_instance() + {} + +private: + void make_row(PFS_socket *pfs); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_socket_summary_by_instance m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_sync_instances.cc b/storage/perfschema/table_sync_instances.cc index f2bd9fa1a28..9631c5fb205 100644 --- a/storage/perfschema/table_sync_instances.cc +++ b/storage/perfschema/table_sync_instances.cc @@ -60,6 +60,7 @@ table_mutex_instances::m_share= &table_mutex_instances::create, NULL, /* write_row */ NULL, /* delete_all_rows */ + NULL, /* get_row_count */ 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, @@ -228,6 +229,7 @@ table_rwlock_instances::m_share= &table_rwlock_instances::create, NULL, /* write_row */ NULL, /* delete_all_rows */ + NULL, /* get_row_count */ 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, @@ -393,6 +395,7 @@ table_cond_instances::m_share= &table_cond_instances::create, NULL, /* write_row */ NULL, /* delete_all_rows */ + NULL, /* get_row_count */ 1000, /* records */ sizeof(PFS_simple_index), &m_table_lock, diff --git a/storage/perfschema/table_sync_instances.h b/storage/perfschema/table_sync_instances.h index 3c359852338..b6fc78e1cd5 100644 --- a/storage/perfschema/table_sync_instances.h +++ b/storage/perfschema/table_sync_instances.h @@ -82,7 +82,7 @@ private: /** Current row. */ row_mutex_instances m_row; - /** True is the current row exists. */ + /** True if the current row exists. */ bool m_row_exists; /** Current position. */ PFS_simple_index m_pos; @@ -141,7 +141,7 @@ private: /** Current row. */ row_rwlock_instances m_row; - /** True is the current row exists. */ + /** True if the current row exists. */ bool m_row_exists; /** Current position. */ PFS_simple_index m_pos; @@ -194,7 +194,7 @@ private: /** Current row. */ row_cond_instances m_row; - /** True is the current row exists. */ + /** True if the current row exists. */ bool m_row_exists; /** Current position. */ PFS_simple_index m_pos; diff --git a/storage/perfschema/table_threads.cc b/storage/perfschema/table_threads.cc index 541ba860386..91300d6b67e 100644 --- a/storage/perfschema/table_threads.cc +++ b/storage/perfschema/table_threads.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 @@ -13,14 +13,10 @@ along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ -/** - @file storage/perfschema/table_threads.cc - Table THREADS (implementation). -*/ - #include "my_global.h" #include "my_pthread.h" #include "table_threads.h" +#include "sql_parse.h" #include "pfs_instr_class.h" #include "pfs_instr.h" @@ -34,29 +30,85 @@ static const TABLE_FIELD_TYPE field_types[]= { NULL, 0} }, { + { C_STRING_WITH_LEN("NAME") }, + { C_STRING_WITH_LEN("varchar(128)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("TYPE") }, + { C_STRING_WITH_LEN("varchar(10)") }, + { NULL, 0} + }, + { { C_STRING_WITH_LEN("PROCESSLIST_ID") }, { C_STRING_WITH_LEN("int(11)") }, { NULL, 0} }, { - { C_STRING_WITH_LEN("NAME") }, - { C_STRING_WITH_LEN("varchar(128)") }, + { C_STRING_WITH_LEN("PROCESSLIST_USER") }, + { C_STRING_WITH_LEN("varchar(16)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("PROCESSLIST_HOST") }, + { C_STRING_WITH_LEN("varchar(60)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("PROCESSLIST_DB") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("PROCESSLIST_COMMAND") }, + { C_STRING_WITH_LEN("varchar(16)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("PROCESSLIST_TIME") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("PROCESSLIST_STATE") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("PROCESSLIST_INFO") }, + { C_STRING_WITH_LEN("longtext") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("PARENT_THREAD_ID") }, + { C_STRING_WITH_LEN("int(11)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("ROLE") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("INSTRUMENTED") }, + { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") }, { NULL, 0} } }; TABLE_FIELD_DEF table_threads::m_field_def= -{ 3, field_types }; +{ 14, field_types }; PFS_engine_table_share table_threads::m_share= { { C_STRING_WITH_LEN("threads") }, - &pfs_readonly_acl, + &pfs_updatable_acl, &table_threads::create, NULL, /* write_row */ NULL, /* delete_all_rows */ + NULL, /* get_row_count */ 1000, /* records */ sizeof(PFS_simple_index), /* ref length */ &m_table_lock, @@ -64,58 +116,16 @@ table_threads::m_share= false /* checked */ }; -PFS_engine_table* table_threads::create(void) +PFS_engine_table* table_threads::create() { return new table_threads(); } table_threads::table_threads() - : PFS_engine_table(&m_share, &m_pos), - m_row_exists(false), m_pos(0), m_next_pos(0) + : cursor_by_thread(& m_share), + m_row_exists(false) {} -void table_threads::reset_position(void) -{ - m_pos.m_index= 0; - m_next_pos.m_index= 0; -} - -int table_threads::rnd_next(void) -{ - PFS_thread *pfs; - - for (m_pos.set_at(&m_next_pos); - m_pos.m_index < thread_max; - m_pos.next()) - { - pfs= &thread_array[m_pos.m_index]; - if (pfs->m_lock.is_populated()) - { - make_row(pfs); - m_next_pos.set_after(&m_pos); - return 0; - } - } - - return HA_ERR_END_OF_FILE; -} - -int table_threads::rnd_pos(const void *pos) -{ - PFS_thread *pfs; - - set_position(pos); - DBUG_ASSERT(m_pos.m_index < thread_max); - pfs= &thread_array[m_pos.m_index]; - if (pfs->m_lock.is_populated()) - { - make_row(pfs); - return 0; - } - - return HA_ERR_RECORD_DELETED; -} - void table_threads::make_row(PFS_thread *pfs) { pfs_lock lock; @@ -131,11 +141,40 @@ void table_threads::make_row(PFS_thread *pfs) return; m_row.m_thread_internal_id= pfs->m_thread_internal_id; + m_row.m_parent_thread_internal_id= pfs->m_parent_thread_internal_id; m_row.m_thread_id= pfs->m_thread_id; m_row.m_name= safe_class->m_name; m_row.m_name_length= safe_class->m_name_length; - if (pfs->m_lock.end_optimistic_lock(&lock)) + m_row.m_username_length= pfs->m_username_length; + if (unlikely(m_row.m_username_length > sizeof(m_row.m_username))) + return; + if (m_row.m_username_length != 0) + memcpy(m_row.m_username, pfs->m_username, m_row.m_username_length); + + m_row.m_hostname_length= pfs->m_hostname_length; + if (unlikely(m_row.m_hostname_length > sizeof(m_row.m_hostname))) + return; + if (m_row.m_hostname_length != 0) + memcpy(m_row.m_hostname, pfs->m_hostname, m_row.m_hostname_length); + + m_row.m_dbname_length= pfs->m_dbname_length; + if (unlikely(m_row.m_dbname_length > sizeof(m_row.m_dbname))) + return; + if (m_row.m_dbname_length != 0) + memcpy(m_row.m_dbname, pfs->m_dbname, m_row.m_dbname_length); + + m_row.m_command= pfs->m_command; + m_row.m_start_time= pfs->m_start_time; + /* FIXME: need to copy it ? */ + m_row.m_processlist_state_ptr= pfs->m_processlist_state_ptr; + m_row.m_processlist_state_length= pfs->m_processlist_state_length; + /* FIXME: need to copy it ? */ + m_row.m_processlist_info_ptr= pfs->m_processlist_info_ptr; + m_row.m_processlist_info_length= pfs->m_processlist_info_length; + m_row.m_enabled_ptr= &pfs->m_enabled; + + if (pfs->m_lock.end_optimistic_lock(& lock)) m_row_exists= true; } @@ -150,8 +189,9 @@ int table_threads::read_row_values(TABLE *table, return HA_ERR_RECORD_DELETED; /* Set the null bits */ - DBUG_ASSERT(table->s->null_bytes == 1); + DBUG_ASSERT(table->s->null_bytes == 2); buf[0]= 0; + buf[1]= 0; for (; (f= *fields) ; fields++) { @@ -162,12 +202,125 @@ int table_threads::read_row_values(TABLE *table, case 0: /* THREAD_ID */ set_field_ulong(f, m_row.m_thread_internal_id); break; - case 1: /* PROCESSLIST_ID */ - set_field_ulong(f, m_row.m_thread_id); - break; - case 2: /* NAME */ + case 1: /* NAME */ set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length); break; + case 2: /* TYPE */ + if (m_row.m_thread_id != 0) + set_field_varchar_utf8(f, "FOREGROUND", 10); + else + set_field_varchar_utf8(f, "BACKGROUND", 10); + break; + case 3: /* PROCESSLIST_ID */ + if (m_row.m_thread_id != 0) + set_field_ulong(f, m_row.m_thread_id); + else + f->set_null(); + break; + case 4: /* PROCESSLIST_USER */ + if (m_row.m_username_length > 0) + set_field_varchar_utf8(f, m_row.m_username, + m_row.m_username_length); + else + f->set_null(); + break; + case 5: /* PROCESSLIST_HOST */ + if (m_row.m_hostname_length > 0) + set_field_varchar_utf8(f, m_row.m_hostname, + m_row.m_hostname_length); + else + f->set_null(); + break; + case 6: /* PROCESSLIST_DB */ + if (m_row.m_dbname_length > 0) + set_field_varchar_utf8(f, m_row.m_dbname, + m_row.m_dbname_length); + else + f->set_null(); + break; + case 7: /* PROCESSLIST_COMMAND */ + if (m_row.m_thread_id != 0) + set_field_varchar_utf8(f, command_name[m_row.m_command].str, + command_name[m_row.m_command].length); + else + f->set_null(); + break; + case 8: /* PROCESSLIST_TIME */ + if (m_row.m_start_time) + { + time_t now= my_time(0); + ulonglong elapsed= (now > m_row.m_start_time ? now - m_row.m_start_time : 0); + set_field_ulonglong(f, elapsed); + } + else + f->set_null(); + break; + case 9: /* PROCESSLIST_STATE */ + if (m_row.m_processlist_state_length > 0) + set_field_varchar_utf8(f, m_row.m_processlist_state_ptr, + m_row.m_processlist_state_length); + else + f->set_null(); + break; + case 10: /* PROCESSLIST_INFO */ + if (m_row.m_processlist_info_length > 0) + set_field_longtext_utf8(f, m_row.m_processlist_info_ptr, + m_row.m_processlist_info_length); + else + f->set_null(); + break; + case 11: /* PARENT_THREAD_ID */ + if (m_row.m_parent_thread_internal_id != 0) + set_field_ulong(f, m_row.m_parent_thread_internal_id); + else + f->set_null(); + break; + case 12: /* ROLE */ + f->set_null(); + break; + case 13: /* INSTRUMENTED */ + set_field_enum(f, (*m_row.m_enabled_ptr) ? ENUM_YES : ENUM_NO); + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} + +int table_threads::update_row_values(TABLE *table, + const unsigned char *old_buf, + unsigned char *new_buf, + Field **fields) +{ + Field *f; + enum_yes_no value; + + for (; (f= *fields) ; fields++) + { + if (bitmap_is_set(table->write_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* THREAD_ID */ + case 1: /* NAME */ + case 2: /* TYPE */ + case 3: /* PROCESSLIST_ID */ + case 4: /* PROCESSLIST_USER */ + case 5: /* PROCESSLIST_HOST */ + case 6: /* PROCESSLIST_DB */ + case 7: /* PROCESSLIST_COMMAND */ + case 8: /* PROCESSLIST_TIME */ + case 9: /* PROCESSLIST_STATE */ + case 10: /* PROCESSLIST_INFO */ + case 11: /* PARENT_THREAD_ID */ + case 12: /* ROLE */ + return HA_ERR_WRONG_COMMAND; + case 13: /* INSTRUMENTED */ + value= (enum_yes_no) get_field_enum(f); + *m_row.m_enabled_ptr= (value == ENUM_YES) ? true : false; + break; default: DBUG_ASSERT(false); } diff --git a/storage/perfschema/table_threads.h b/storage/perfschema/table_threads.h index fb239007069..9819822f8c8 100644 --- a/storage/perfschema/table_threads.h +++ b/storage/perfschema/table_threads.h @@ -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 @@ -16,22 +16,19 @@ #ifndef TABLE_THREADS_H #define TABLE_THREADS_H -/** - @file storage/perfschema/table_threads.h - Table THREADS (declarations). -*/ - #include "pfs_column_types.h" -#include "pfs_engine_table.h" +#include "cursor_by_thread.h" struct PFS_thread; /** - @addtogroup Performance_schema_tables + \addtogroup Performance_schema_tables @{ */ -/** A row of PERFORMANCE_SCHEMA.THREADS. */ +/** + A row of PERFORMANCE_SCHEMA.THREADS. +*/ struct row_threads { /** Column THREAD_ID. */ @@ -39,29 +36,60 @@ struct row_threads /** Column PROCESSLIST_ID. */ ulong m_thread_id; /** Column NAME. */ - const char *m_name; + const char* m_name; /** Length in bytes of @c m_name. */ uint m_name_length; + /** Column PROCESSLIST_USER. */ + char m_username[USERNAME_LENGTH]; + /** Length in bytes of @c m_username. */ + uint m_username_length; + /** Column PROCESSLIST_HOST. */ + char m_hostname[HOSTNAME_LENGTH]; + /** Length in bytes of @c m_hostname. */ + uint m_hostname_length; + /** Column PROCESSLIST_DB. */ + char m_dbname[NAME_LEN]; + /** Length in bytes of @c m_dbname. */ + uint m_dbname_length; + /** Column PROCESSLIST_COMMAND. */ + int m_command; + /** Column PROCESSLIST_TIME. */ + time_t m_start_time; + /** Column PROCESSLIST_STATE. */ + const char* m_processlist_state_ptr; + /** Length in bytes of @c m_processlist_state_ptr. */ + uint m_processlist_state_length; + /** Column PROCESSLIST_INFO. */ + const char* m_processlist_info_ptr; + /** Length in bytes of @c m_processlist_info_ptr. */ + uint m_processlist_info_length; + /** Column INSTRUMENTED. */ + bool *m_enabled_ptr; + /** Column PARENT_THREAD_ID. */ + ulong m_parent_thread_internal_id; }; /** Table PERFORMANCE_SCHEMA.THREADS. */ -class table_threads : public PFS_engine_table +class table_threads : public cursor_by_thread { public: - /** Table share. */ + /** Table share */ static PFS_engine_table_share m_share; + /** Table builder */ static PFS_engine_table* create(); - virtual int rnd_next(); - virtual int rnd_pos(const void *pos); - virtual void reset_position(void); - protected: virtual int read_row_values(TABLE *table, unsigned char *buf, Field **fields, bool read_all); + + virtual int update_row_values(TABLE *table, + const unsigned char *old_buf, + unsigned char *new_buf, + Field **fields); + protected: table_threads(); @@ -70,7 +98,7 @@ public: {} private: - void make_row(PFS_thread *pfs); + virtual void make_row(PFS_thread *pfs); /** Table share lock. */ static THR_LOCK m_table_lock; @@ -81,10 +109,6 @@ private: row_threads m_row; /** True if the current row exists. */ bool m_row_exists; - /** Current position. */ - PFS_simple_index m_pos; - /** Next position. */ - PFS_simple_index m_next_pos; }; /** @} */ diff --git a/storage/perfschema/table_tiws_by_index_usage.cc b/storage/perfschema/table_tiws_by_index_usage.cc new file mode 100644 index 00000000000..d354c40d3ed --- /dev/null +++ b/storage/perfschema/table_tiws_by_index_usage.cc @@ -0,0 +1,497 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_tiws_by_index_usage.cc + Table TABLE_IO_WAITS_SUMMARY_BY_INDEX_USAGE (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_tiws_by_index_usage.h" +#include "pfs_global.h" +#include "pfs_visitor.h" + +THR_LOCK table_tiws_by_index_usage::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("OBJECT_TYPE") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_NAME") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("INDEX_NAME") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_FETCH") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_FETCH") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_FETCH") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_FETCH") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_FETCH") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_UPDATE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_UPDATE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_UPDATE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_UPDATE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_UPDATE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_DELETE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_DELETE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_DELETE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_DELETE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_DELETE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_tiws_by_index_usage::m_field_def= +{ 39, field_types }; + +PFS_engine_table_share +table_tiws_by_index_usage::m_share= +{ + { C_STRING_WITH_LEN("table_io_waits_summary_by_index_usage") }, + &pfs_truncatable_acl, + table_tiws_by_index_usage::create, + NULL, /* write_row */ + table_tiws_by_index_usage::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(pos_tiws_by_index_usage), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_tiws_by_index_usage::create(void) +{ + return new table_tiws_by_index_usage(); +} + +int +table_tiws_by_index_usage::delete_all_rows(void) +{ + reset_table_io_waits_by_table_handle(); + reset_table_io_waits_by_table(); + return 0; +} + +table_tiws_by_index_usage::table_tiws_by_index_usage() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_tiws_by_index_usage::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_tiws_by_index_usage::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(wait_timer); + return 0; +} + +int table_tiws_by_index_usage::rnd_next(void) +{ + PFS_table_share *table_share; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_table(); + m_pos.next_table()) + { + table_share= &table_share_array[m_pos.m_index_1]; + if (table_share->m_lock.is_populated()) + { + if (m_pos.m_index_2 < table_share->m_key_count) + { + make_row(table_share, m_pos.m_index_2); + m_next_pos.set_after(&m_pos); + return 0; + } + if (m_pos.m_index_2 <= MAX_KEY) + { + m_pos.m_index_2= MAX_KEY; + make_row(table_share, m_pos.m_index_2); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_tiws_by_index_usage::rnd_pos(const void *pos) +{ + PFS_table_share *table_share; + + set_position(pos); + + table_share= &table_share_array[m_pos.m_index_1]; + if (table_share->m_lock.is_populated()) + { + if (m_pos.m_index_2 < table_share->m_key_count) + { + make_row(table_share, m_pos.m_index_2); + return 0; + } + if (m_pos.m_index_2 == MAX_KEY) + { + make_row(table_share, m_pos.m_index_2); + return 0; + } + } + + return HA_ERR_RECORD_DELETED; +} + +void table_tiws_by_index_usage::make_row(PFS_table_share *share, uint index) +{ + pfs_lock lock; + + m_row_exists= false; + + share->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_index.make_row(share, index)) + return; + + PFS_index_io_stat_visitor visitor; + PFS_object_iterator::visit_table_indexes(share, index, & visitor); + + if (! share->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(m_normalizer, & visitor.m_stat); +} + +int table_tiws_by_index_usage::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* OBJECT_TYPE */ + case 1: /* SCHEMA_NAME */ + case 2: /* OBJECT_NAME */ + case 3: /* INDEX_NAME */ + m_row.m_index.set_field(f->field_index, f); + break; + case 4: /* COUNT_STAR */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_count); + break; + case 5: /* SUM */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_sum); + break; + case 6: /* MIN */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_min); + break; + case 7: /* AVG */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_avg); + break; + case 8: /* MAX */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_max); + break; + case 9: /* COUNT_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_count); + break; + case 10: /* SUM_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_sum); + break; + case 11: /* MIN_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_min); + break; + case 12: /* AVG_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_avg); + break; + case 13: /* MAX_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_max); + break; + case 14: /* COUNT_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_count); + break; + case 15: /* SUM_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_sum); + break; + case 16: /* MIN_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_min); + break; + case 17: /* AVG_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_avg); + break; + case 18: /* MAX_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_max); + break; + case 19: /* COUNT_FETCH */ + set_field_ulonglong(f, m_row.m_stat.m_fetch.m_count); + break; + case 20: /* SUM_FETCH */ + set_field_ulonglong(f, m_row.m_stat.m_fetch.m_sum); + break; + case 21: /* MIN_FETCH */ + set_field_ulonglong(f, m_row.m_stat.m_fetch.m_min); + break; + case 22: /* AVG_FETCH */ + set_field_ulonglong(f, m_row.m_stat.m_fetch.m_avg); + break; + case 23: /* MAX_FETCH */ + set_field_ulonglong(f, m_row.m_stat.m_fetch.m_max); + break; + case 24: /* COUNT_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_insert.m_count); + break; + case 25: /* SUM_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_insert.m_sum); + break; + case 26: /* MIN_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_insert.m_min); + break; + case 27: /* AVG_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_insert.m_avg); + break; + case 28: /* MAX_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_insert.m_max); + break; + case 29: /* COUNT_UPDATE */ + set_field_ulonglong(f, m_row.m_stat.m_update.m_count); + break; + case 30: /* SUM_UPDATE */ + set_field_ulonglong(f, m_row.m_stat.m_update.m_sum); + break; + case 31: /* MIN_UPDATE */ + set_field_ulonglong(f, m_row.m_stat.m_update.m_min); + break; + case 32: /* AVG_UPDATE */ + set_field_ulonglong(f, m_row.m_stat.m_update.m_avg); + break; + case 33: /* MAX_UPDATE */ + set_field_ulonglong(f, m_row.m_stat.m_update.m_max); + break; + case 34: /* COUNT_DELETE */ + set_field_ulonglong(f, m_row.m_stat.m_delete.m_count); + break; + case 35: /* SUM_DELETE */ + set_field_ulonglong(f, m_row.m_stat.m_delete.m_sum); + break; + case 36: /* MIN_DELETE */ + set_field_ulonglong(f, m_row.m_stat.m_delete.m_min); + break; + case 37: /* AVG_DELETE */ + set_field_ulonglong(f, m_row.m_stat.m_delete.m_avg); + break; + case 38: /* MAX_DELETE */ + set_field_ulonglong(f, m_row.m_stat.m_delete.m_max); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_tiws_by_index_usage.h b/storage/perfschema/table_tiws_by_index_usage.h new file mode 100644 index 00000000000..b5f589d0cea --- /dev/null +++ b/storage/perfschema/table_tiws_by_index_usage.h @@ -0,0 +1,123 @@ +/* Copyright (c) 2010, 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 + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_IO_WAIT_SUMMARY_BY_INDEX_USAGE_H +#define TABLE_IO_WAIT_SUMMARY_BY_INDEX_USAGE_H + +/** + @file storage/perfschema/table_tiws_by_index_usage.h + Table TABLE_IO_WAIT_SUMMARY_BY_INDEX_USAGE (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.TABLE_IO_WAIT_SUMMARY_BY_INDEX. +*/ +struct row_tiws_by_index_usage +{ + /** Column OBJECT_TYPE, SCHEMA_NAME, OBJECT_NAME, INDEX_NAME. */ + PFS_index_row m_index; + /** Columns COUNT/SUM/MIN/AVG/MAX (+_READ, +WRITE). */ + PFS_table_io_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.TABLE_IO_WAIT_SUMMARY_BY_INDEX. + Index 1 on table_share_array (0 based) + Index 2 on index (0 based) +*/ +struct pos_tiws_by_index_usage : public PFS_double_index +{ + pos_tiws_by_index_usage() + : PFS_double_index(0, 0) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 0; + } + + inline bool has_more_table(void) + { + return (m_index_1 < table_share_max); + } + + inline void next_table(void) + { + m_index_1++; + m_index_2= 0; + } +}; + +/** Table PERFORMANCE_SCHEMA.TABLE_IO_WAIT_SUMMARY_BY_INDEX. */ +class table_tiws_by_index_usage : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_tiws_by_index_usage(); + +public: + ~table_tiws_by_index_usage() + {} + +protected: + void make_row(PFS_table_share *table_share, uint index); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_tiws_by_index_usage m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_tiws_by_index_usage m_pos; + /** Next position. */ + pos_tiws_by_index_usage m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_tiws_by_table.cc b/storage/perfschema/table_tiws_by_table.cc new file mode 100644 index 00000000000..f793b5654a2 --- /dev/null +++ b/storage/perfschema/table_tiws_by_table.cc @@ -0,0 +1,473 @@ +/* Copyright (c) 2010, 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 + 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/table_tiws_by_table.cc + Table TABLE_IO_WAITS_SUMMARY_BY_TABLE (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_tiws_by_table.h" +#include "pfs_global.h" +#include "pfs_visitor.h" + +THR_LOCK table_tiws_by_table::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("OBJECT_TYPE") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_NAME") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_FETCH") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_FETCH") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_FETCH") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_FETCH") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_FETCH") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_UPDATE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_UPDATE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_UPDATE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_UPDATE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_UPDATE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_DELETE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_DELETE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_DELETE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_DELETE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_DELETE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_tiws_by_table::m_field_def= +{ 38, field_types }; + +PFS_engine_table_share +table_tiws_by_table::m_share= +{ + { C_STRING_WITH_LEN("table_io_waits_summary_by_table") }, + &pfs_truncatable_acl, + table_tiws_by_table::create, + NULL, /* write_row */ + table_tiws_by_table::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_tiws_by_table::create(void) +{ + return new table_tiws_by_table(); +} + +int +table_tiws_by_table::delete_all_rows(void) +{ + reset_table_io_waits_by_table_handle(); + reset_table_io_waits_by_table(); + return 0; +} + +table_tiws_by_table::table_tiws_by_table() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_tiws_by_table::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_tiws_by_table::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(wait_timer); + return 0; +} + +int table_tiws_by_table::rnd_next(void) +{ + PFS_table_share *table_share; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < table_share_max; + m_pos.m_index++) + { + table_share= &table_share_array[m_pos.m_index]; + if (table_share->m_lock.is_populated()) + { + make_row(table_share); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_tiws_by_table::rnd_pos(const void *pos) +{ + PFS_table_share *table_share; + + set_position(pos); + + table_share= &table_share_array[m_pos.m_index]; + if (table_share->m_lock.is_populated()) + { + make_row(table_share); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_tiws_by_table::make_row(PFS_table_share *share) +{ + pfs_lock lock; + + m_row_exists= false; + + share->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_object.make_row(share)) + return; + + PFS_table_io_stat_visitor visitor; + PFS_object_iterator::visit_tables(share, & visitor); + + if (! share->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(m_normalizer, &visitor.m_stat); +} + +int table_tiws_by_table::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* OBJECT_TYPE */ + case 1: /* SCHEMA_NAME */ + case 2: /* OBJECT_NAME */ + m_row.m_object.set_field(f->field_index, f); + break; + case 3: /* COUNT_STAR */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_count); + break; + case 4: /* SUM */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_sum); + break; + case 5: /* MIN */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_min); + break; + case 6: /* AVG */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_avg); + break; + case 7: /* MAX */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_max); + break; + case 8: /* COUNT_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_count); + break; + case 9: /* SUM_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_sum); + break; + case 10: /* MIN_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_min); + break; + case 11: /* AVG_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_avg); + break; + case 12: /* MAX_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_max); + break; + case 13: /* COUNT_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_count); + break; + case 14: /* SUM_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_sum); + break; + case 15: /* MIN_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_min); + break; + case 16: /* AVG_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_avg); + break; + case 17: /* MAX_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_max); + break; + case 18: /* COUNT_FETCH */ + set_field_ulonglong(f, m_row.m_stat.m_fetch.m_count); + break; + case 19: /* SUM_FETCH */ + set_field_ulonglong(f, m_row.m_stat.m_fetch.m_sum); + break; + case 20: /* MIN_FETCH */ + set_field_ulonglong(f, m_row.m_stat.m_fetch.m_min); + break; + case 21: /* AVG_FETCH */ + set_field_ulonglong(f, m_row.m_stat.m_fetch.m_avg); + break; + case 22: /* MAX_FETCH */ + set_field_ulonglong(f, m_row.m_stat.m_fetch.m_max); + break; + case 23: /* COUNT_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_insert.m_count); + break; + case 24: /* SUM_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_insert.m_sum); + break; + case 25: /* MIN_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_insert.m_min); + break; + case 26: /* AVG_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_insert.m_avg); + break; + case 27: /* MAX_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_insert.m_max); + break; + case 28: /* COUNT_UPDATE */ + set_field_ulonglong(f, m_row.m_stat.m_update.m_count); + break; + case 29: /* SUM_UPDATE */ + set_field_ulonglong(f, m_row.m_stat.m_update.m_sum); + break; + case 30: /* MIN_UPDATE */ + set_field_ulonglong(f, m_row.m_stat.m_update.m_min); + break; + case 31: /* AVG_UPDATE */ + set_field_ulonglong(f, m_row.m_stat.m_update.m_avg); + break; + case 32: /* MAX_UPDATE */ + set_field_ulonglong(f, m_row.m_stat.m_update.m_max); + break; + case 33: /* COUNT_DELETE */ + set_field_ulonglong(f, m_row.m_stat.m_delete.m_count); + break; + case 34: /* SUM_DELETE */ + set_field_ulonglong(f, m_row.m_stat.m_delete.m_sum); + break; + case 35: /* MIN_DELETE */ + set_field_ulonglong(f, m_row.m_stat.m_delete.m_min); + break; + case 36: /* AVG_DELETE */ + set_field_ulonglong(f, m_row.m_stat.m_delete.m_avg); + break; + case 37: /* MAX_DELETE */ + set_field_ulonglong(f, m_row.m_stat.m_delete.m_max); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_tiws_by_table.h b/storage/perfschema/table_tiws_by_table.h new file mode 100644 index 00000000000..747b1958c8e --- /dev/null +++ b/storage/perfschema/table_tiws_by_table.h @@ -0,0 +1,93 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_IO_WAITS_SUMMARY_BY_TABLE_H +#define TABLE_IO_WAITS_SUMMARY_BY_TABLE_H + +/** + @file storage/perfschema/table_tiws_by_table.h + Table TABLE_IO_WAITS_SUMMARY_BY_TABLE (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.TABLE_IO_WAITS_SUMMARY_BY_TABLE. +*/ +struct row_tiws_by_table +{ + /** Column OBJECT_TYPE, SCHEMA_NAME, OBJECT_NAME. */ + PFS_object_row m_object; + /** Columns COUNT/SUM/MIN/AVG/MAX (+_READ, +WRITE). */ + PFS_table_io_stat_row m_stat; +}; + +/** Table PERFORMANCE_SCHEMA.TABLE_IO_WAITS_SUMMARY_BY_TABLE. */ +class table_tiws_by_table : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_tiws_by_table(); + +public: + ~table_tiws_by_table() + {} + +protected: + void make_row(PFS_table_share *table_share); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_tiws_by_table m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_tlws_by_table.cc b/storage/perfschema/table_tlws_by_table.cc new file mode 100644 index 00000000000..c6f454ac178 --- /dev/null +++ b/storage/perfschema/table_tlws_by_table.cc @@ -0,0 +1,765 @@ +/* Copyright (c) 2010, 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 + 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/table_tlws_by_table.cc + Table TABLE_LOCK_WAITS_SUMMARY_BY_TABLE (implementation). +*/ + +#include "my_global.h" +#include "my_pthread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_tlws_by_table.h" +#include "pfs_global.h" +#include "pfs_visitor.h" + +THR_LOCK table_tlws_by_table::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("OBJECT_TYPE") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_SCHEMA") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("OBJECT_NAME") }, + { C_STRING_WITH_LEN("varchar(64)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_STAR") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WAIT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_READ") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_READ_NORMAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_READ_NORMAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_READ_NORMAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_READ_NORMAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_READ_NORMAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_READ_WITH_SHARED_LOCKS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_READ_WITH_SHARED_LOCKS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_READ_WITH_SHARED_LOCKS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_READ_WITH_SHARED_LOCKS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_READ_WITH_SHARED_LOCKS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_READ_HIGH_PRIORITY") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_READ_HIGH_PRIORITY") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_READ_HIGH_PRIORITY") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_READ_HIGH_PRIORITY") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_READ_HIGH_PRIORITY") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_READ_NO_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_READ_NO_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_READ_NO_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_READ_NO_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_READ_NO_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_READ_EXTERNAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_READ_EXTERNAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_READ_EXTERNAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_READ_EXTERNAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_READ_EXTERNAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_WRITE_ALLOW_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE_ALLOW_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE_ALLOW_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE_ALLOW_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE_ALLOW_WRITE") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_WRITE_CONCURRENT_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE_CONCURRENT_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE_CONCURRENT_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE_CONCURRENT_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE_CONCURRENT_INSERT") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_WRITE_DELAYED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE_DELAYED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE_DELAYED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE_DELAYED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE_DELAYED") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_WRITE_LOW_PRIORITY") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE_LOW_PRIORITY") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE_LOW_PRIORITY") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE_LOW_PRIORITY") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE_LOW_PRIORITY") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_WRITE_NORMAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE_NORMAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE_NORMAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE_NORMAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE_NORMAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("COUNT_WRITE_EXTERNAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("SUM_TIMER_WRITE_EXTERNAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MIN_TIMER_WRITE_EXTERNAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("AVG_TIMER_WRITE_EXTERNAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("MAX_TIMER_WRITE_EXTERNAL") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_tlws_by_table::m_field_def= +{ 73, field_types }; + +PFS_engine_table_share +table_tlws_by_table::m_share= +{ + { C_STRING_WITH_LEN("table_lock_waits_summary_by_table") }, + &pfs_truncatable_acl, + table_tlws_by_table::create, + NULL, /* write_row */ + table_tlws_by_table::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* +table_tlws_by_table::create(void) +{ + return new table_tlws_by_table(); +} + +int +table_tlws_by_table::delete_all_rows(void) +{ + reset_table_lock_waits_by_table_handle(); + reset_table_lock_waits_by_table(); + return 0; +} + +table_tlws_by_table::table_tlws_by_table() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_tlws_by_table::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_tlws_by_table::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(wait_timer); + return 0; +} + +int table_tlws_by_table::rnd_next(void) +{ + PFS_table_share *table_share; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < table_share_max; + m_pos.m_index++) + { + table_share= &table_share_array[m_pos.m_index]; + if (table_share->m_lock.is_populated()) + { + make_row(table_share); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_tlws_by_table::rnd_pos(const void *pos) +{ + PFS_table_share *table_share; + + set_position(pos); + + table_share= &table_share_array[m_pos.m_index]; + if (table_share->m_lock.is_populated()) + { + make_row(table_share); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_tlws_by_table::make_row(PFS_table_share *share) +{ + pfs_lock lock; + + m_row_exists= false; + + share->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_object.make_row(share)) + return; + + PFS_table_lock_stat_visitor visitor; + PFS_object_iterator::visit_tables(share, & visitor); + + if (! share->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(m_normalizer, &visitor.m_stat); +} + +int table_tlws_by_table::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* OBJECT_TYPE */ + case 1: /* SCHEMA_NAME */ + case 2: /* OBJECT_NAME */ + m_row.m_object.set_field(f->field_index, f); + break; + case 3: /* COUNT_STAR */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_count); + break; + case 4: /* SUM_TIMER */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_sum); + break; + case 5: /* MIN_TIMER */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_min); + break; + case 6: /* AVG_TIMER */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_avg); + break; + case 7: /* MAX_TIMER */ + set_field_ulonglong(f, m_row.m_stat.m_all.m_max); + break; + case 8: /* COUNT_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_count); + break; + case 9: /* SUM_TIMER_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_sum); + break; + case 10: /* MIN_TIMER_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_min); + break; + case 11: /* AVG_TIMER_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_avg); + break; + case 12: /* MAX_TIMER_READ */ + set_field_ulonglong(f, m_row.m_stat.m_all_read.m_max); + break; + case 13: /* COUNT_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_count); + break; + case 14: /* SUM_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_sum); + break; + case 15: /* MIN_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_min); + break; + case 16: /* AVG_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_avg); + break; + case 17: /* MAX_TIMER_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_all_write.m_max); + break; + + case 18: /* COUNT_READ_NORMAL */ + set_field_ulonglong(f, m_row.m_stat.m_read_normal.m_count); + break; + case 19: /* SUM_TIMER_READ_NORMAL */ + set_field_ulonglong(f, m_row.m_stat.m_read_normal.m_sum); + break; + case 20: /* MIN_TIMER_READ_NORMAL */ + set_field_ulonglong(f, m_row.m_stat.m_read_normal.m_min); + break; + case 21: /* AVG_TIMER_READ_NORMAL */ + set_field_ulonglong(f, m_row.m_stat.m_read_normal.m_avg); + break; + case 22: /* MAX_TIMER_READ_NORMAL */ + set_field_ulonglong(f, m_row.m_stat.m_read_normal.m_max); + break; + + case 23: /* COUNT_READ_WITH_SHARED_LOCKS */ + set_field_ulonglong(f, m_row.m_stat.m_read_with_shared_locks.m_count); + break; + case 24: /* SUM_TIMER_READ_WITH_SHARED_LOCKS */ + set_field_ulonglong(f, m_row.m_stat.m_read_with_shared_locks.m_sum); + break; + case 25: /* MIN_TIMER_READ_WITH_SHARED_LOCKS */ + set_field_ulonglong(f, m_row.m_stat.m_read_with_shared_locks.m_min); + break; + case 26: /* AVG_TIMER_READ_WITH_SHARED_LOCKS */ + set_field_ulonglong(f, m_row.m_stat.m_read_with_shared_locks.m_avg); + break; + case 27: /* MAX_TIMER_READ_WITH_SHARED_LOCKS */ + set_field_ulonglong(f, m_row.m_stat.m_read_with_shared_locks.m_max); + break; + + case 28: /* COUNT_READ_HIGH_PRIORITY */ + set_field_ulonglong(f, m_row.m_stat.m_read_high_priority.m_count); + break; + case 29: /* SUM_TIMER_READ_HIGH_PRIORITY */ + set_field_ulonglong(f, m_row.m_stat.m_read_high_priority.m_sum); + break; + case 30: /* MIN_TIMER_READ_HIGH_PRIORITY */ + set_field_ulonglong(f, m_row.m_stat.m_read_high_priority.m_min); + break; + case 31: /* AVG_TIMER_READ_HIGH_PRIORITY */ + set_field_ulonglong(f, m_row.m_stat.m_read_high_priority.m_avg); + break; + case 32: /* MAX_TIMER_READ_HIGH_PRIORITY */ + set_field_ulonglong(f, m_row.m_stat.m_read_high_priority.m_max); + break; + + case 33: /* COUNT_READ_NO_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_read_no_insert.m_count); + break; + case 34: /* SUM_TIMER_READ_NO_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_read_no_insert.m_sum); + break; + case 35: /* MIN_TIMER_READ_NO_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_read_no_insert.m_min); + break; + case 36: /* AVG_TIMER_READ_NO_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_read_no_insert.m_avg); + break; + case 37: /* MAX_TIMER_READ_NO_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_read_no_insert.m_max); + break; + + case 38: /* COUNT_READ_EXTERNAL */ + set_field_ulonglong(f, m_row.m_stat.m_read_external.m_count); + break; + case 39: /* SUM_TIMER_READ_EXTERNAL */ + set_field_ulonglong(f, m_row.m_stat.m_read_external.m_sum); + break; + case 40: /* MIN_TIMER_READ_EXTERNAL */ + set_field_ulonglong(f, m_row.m_stat.m_read_external.m_min); + break; + case 41: /* AVG_TIMER_READ_EXTERNAL */ + set_field_ulonglong(f, m_row.m_stat.m_read_external.m_avg); + break; + case 42: /* MAX_TIMER_READ_EXTERNAL */ + set_field_ulonglong(f, m_row.m_stat.m_read_external.m_max); + break; + + case 43: /* COUNT_WRITE_ALLOW_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_write_allow_write.m_count); + break; + case 44: /* SUM_TIMER_WRITE_ALLOW_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_write_allow_write.m_sum); + break; + case 45: /* MIN_TIMER_WRITE_ALLOW_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_write_allow_write.m_min); + break; + case 46: /* AVG_TIMER_WRITE_ALLOW_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_write_allow_write.m_avg); + break; + case 47: /* MAX_TIMER_WRITE_ALLOW_WRITE */ + set_field_ulonglong(f, m_row.m_stat.m_write_allow_write.m_max); + break; + + case 48: /* COUNT_WRITE_CONCURRENT_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_write_concurrent_insert.m_count); + break; + case 49: /* SUM_TIMER_WRITE_CONCURRENT_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_write_concurrent_insert.m_sum); + break; + case 50: /* MIN_TIMER_WRITE_CONCURRENT_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_write_concurrent_insert.m_min); + break; + case 51: /* AVG_TIMER_WRITE_CONCURRENT_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_write_concurrent_insert.m_avg); + break; + case 52: /* MAX_TIMER_WRITE_CONCURRENT_INSERT */ + set_field_ulonglong(f, m_row.m_stat.m_write_concurrent_insert.m_max); + break; + + case 53: /* COUNT_WRITE_DELAYED */ + set_field_ulonglong(f, m_row.m_stat.m_write_delayed.m_count); + break; + case 54: /* SUM_TIMER_WRITE_DELAYED */ + set_field_ulonglong(f, m_row.m_stat.m_write_delayed.m_sum); + break; + case 55: /* MIN_TIMER_WRITE_DELAYED */ + set_field_ulonglong(f, m_row.m_stat.m_write_delayed.m_min); + break; + case 56: /* AVG_TIMER_WRITE_DELAYED */ + set_field_ulonglong(f, m_row.m_stat.m_write_delayed.m_avg); + break; + case 57: /* MAX_TIMER_WRITE_DELAYED */ + set_field_ulonglong(f, m_row.m_stat.m_write_delayed.m_max); + break; + + case 58: /* COUNT_WRITE_LOW_PRIORITY */ + set_field_ulonglong(f, m_row.m_stat.m_write_low_priority.m_count); + break; + case 59: /* SUM_TIMER_WRITE_LOW_PRIORITY */ + set_field_ulonglong(f, m_row.m_stat.m_write_low_priority.m_sum); + break; + case 60: /* MIN_TIMER_WRITE_LOW_PRIORITY */ + set_field_ulonglong(f, m_row.m_stat.m_write_low_priority.m_min); + break; + case 61: /* AVG_TIMER_WRITE_LOW_PRIORITY */ + set_field_ulonglong(f, m_row.m_stat.m_write_low_priority.m_avg); + break; + case 62: /* MAX_TIMER_WRITE_LOW_PRIORITY */ + set_field_ulonglong(f, m_row.m_stat.m_write_low_priority.m_max); + break; + + case 63: /* COUNT_WRITE_NORMAL */ + set_field_ulonglong(f, m_row.m_stat.m_write_normal.m_count); + break; + case 64: /* SUM_TIMER_WRITE_NORMAL */ + set_field_ulonglong(f, m_row.m_stat.m_write_normal.m_sum); + break; + case 65: /* MIN_TIMER_WRITE_NORMAL */ + set_field_ulonglong(f, m_row.m_stat.m_write_normal.m_min); + break; + case 66: /* AVG_TIMER_WRITE_NORMAL */ + set_field_ulonglong(f, m_row.m_stat.m_write_normal.m_avg); + break; + case 67: /* MAX_TIMER_WRITE_NORMAL */ + set_field_ulonglong(f, m_row.m_stat.m_write_normal.m_max); + break; + + case 68: /* COUNT_WRITE_EXTERNAL */ + set_field_ulonglong(f, m_row.m_stat.m_write_external.m_count); + break; + case 69: /* SUM_TIMER_WRITE_EXTERNAL */ + set_field_ulonglong(f, m_row.m_stat.m_write_external.m_sum); + break; + case 70: /* MIN_TIMER_WRITE_EXTERNAL */ + set_field_ulonglong(f, m_row.m_stat.m_write_external.m_min); + break; + case 71: /* AVG_TIMER_WRITE_EXTERNAL */ + set_field_ulonglong(f, m_row.m_stat.m_write_external.m_avg); + break; + case 72: /* MAX_TIMER_WRITE_EXTERNAL */ + set_field_ulonglong(f, m_row.m_stat.m_write_external.m_max); + break; + + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_tlws_by_table.h b/storage/perfschema/table_tlws_by_table.h new file mode 100644 index 00000000000..c5521c72470 --- /dev/null +++ b/storage/perfschema/table_tlws_by_table.h @@ -0,0 +1,93 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#ifndef TABLE_LOCK_WAITS_SUMMARY_BY_TABLE_H +#define TABLE_LOCK_WAITS_SUMMARY_BY_TABLE_H + +/** + @file storage/perfschema/table_tlws_by_table.h + Table TABLE_LOCK_WAITS_SUMMARY_BY_TABLE (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.TABLE_LOCK_WAITS_SUMMARY_BY_TABLE. +*/ +struct row_tlws_by_table +{ + /** Column OBJECT_TYPE, SCHEMA_NAME, OBJECT_NAME. */ + PFS_object_row m_object; + /** Columns COUNT/SUM/MIN/AVG/MAX READ/WRITE/READ_NORMAL/etc. */ + PFS_table_lock_stat_row m_stat; +}; + +/** Table PERFORMANCE_SCHEMA.TABLE_LOCK_WAITS_SUMMARY_BY_TABLE. */ +class table_tlws_by_table : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + + virtual int rnd_init(bool scan); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_tlws_by_table(); + +public: + ~table_tlws_by_table() + {} + +protected: + void make_row(PFS_table_share *table_share); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_tlws_by_table m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_users.cc b/storage/perfschema/table_users.cc new file mode 100644 index 00000000000..c0d85017ebc --- /dev/null +++ b/storage/perfschema/table_users.cc @@ -0,0 +1,147 @@ +/* Copyright (c) 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include "my_global.h" +#include "my_pthread.h" +#include "table_users.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_account.h" +#include "pfs_user.h" +#include "pfs_visitor.h" + +THR_LOCK table_users::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + { C_STRING_WITH_LEN("USER") }, + { C_STRING_WITH_LEN("char(16)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("CURRENT_CONNECTIONS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + }, + { + { C_STRING_WITH_LEN("TOTAL_CONNECTIONS") }, + { C_STRING_WITH_LEN("bigint(20)") }, + { NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_users::m_field_def= +{ 3, field_types }; + +PFS_engine_table_share +table_users::m_share= +{ + { C_STRING_WITH_LEN("users") }, + &pfs_truncatable_acl, + &table_users::create, + NULL, /* write_row */ + table_users::delete_all_rows, + NULL, /* get_row_count */ + 1000, /* records */ + sizeof(PFS_simple_index), /* ref length */ + &m_table_lock, + &m_field_def, + false /* checked */ +}; + +PFS_engine_table* table_users::create() +{ + return new table_users(); +} + +int +table_users::delete_all_rows(void) +{ + reset_events_waits_by_thread(); + reset_events_waits_by_account(); + reset_events_waits_by_user(); + reset_events_stages_by_thread(); + reset_events_stages_by_account(); + reset_events_stages_by_user(); + reset_events_statements_by_thread(); + reset_events_statements_by_account(); + reset_events_statements_by_user(); + purge_all_account(); + purge_all_user(); + return 0; +} + +table_users::table_users() + : cursor_by_user(& m_share), + m_row_exists(false) +{} + +void table_users::make_row(PFS_user *pfs) +{ + pfs_lock lock; + + m_row_exists= false; + pfs->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_user.make_row(pfs)) + return; + + PFS_connection_stat_visitor visitor; + PFS_connection_iterator::visit_user(pfs, true, true, & visitor); + + if (! pfs->m_lock.end_optimistic_lock(& lock)) + return; + + m_row.m_connection_stat.set(& visitor.m_stat); + m_row_exists= true; +} + +int table_users::read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 1); + buf[0]= 0; + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* USER */ + m_row.m_user.set_field(f); + break; + case 1: /* CURRENT_CONNECTIONS */ + case 2: /* TOTAL_CONNECTIONS */ + m_row.m_connection_stat.set_field(f->field_index - 1, f); + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} + diff --git a/storage/perfschema/table_users.h b/storage/perfschema/table_users.h new file mode 100644 index 00000000000..94ea44832d1 --- /dev/null +++ b/storage/perfschema/table_users.h @@ -0,0 +1,80 @@ +/* Copyright (c) 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_USERS_H +#define TABLE_USERS_H + +#include "pfs_column_types.h" +#include "cursor_by_user.h" +#include "table_helper.h" + +struct PFS_user; + +/** + \addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of PERFORMANCE_SCHEMA.USERS. +*/ +struct row_users +{ + /** Column USER. */ + PFS_user_row m_user; + /** Columns CURRENT_CONNECTIONS, TOTAL_CONNECTIONS. */ + PFS_connection_stat_row m_connection_stat; +}; + +/** Table PERFORMANCE_SCHEMA.USERS. */ +class table_users : public cursor_by_user +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + /** Table builder */ + static PFS_engine_table* create(); + static int delete_all_rows(); + +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + +protected: + table_users(); + +public: + ~table_users() + {} + +private: + virtual void make_row(PFS_user *pfs); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_users m_row; + /** True if the current row exists. */ + bool m_row_exists; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/unittest/CMakeLists.txt b/storage/perfschema/unittest/CMakeLists.txt index a9bb1c3f4f2..757bc24c566 100644 --- a/storage/perfschema/unittest/CMakeLists.txt +++ b/storage/perfschema/unittest/CMakeLists.txt @@ -24,5 +24,5 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ADD_DEFINITIONS(-DMYSQL_SERVER) -MY_ADD_TESTS(pfs_instr_class pfs_instr_class-oom pfs_instr pfs_instr-oom pfs +MY_ADD_TESTS(pfs_instr_class pfs_instr_class-oom pfs_instr pfs_instr-oom pfs_account-oom pfs_host-oom pfs_user-oom pfs EXT "cc" LINK_LIBRARIES perfschema mysys) diff --git a/storage/perfschema/unittest/conf.txt b/storage/perfschema/unittest/conf.txt index 6d262854330..8afd0b4dca7 100644 --- a/storage/perfschema/unittest/conf.txt +++ b/storage/perfschema/unittest/conf.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2009, 2010 Sun Microsystems, Inc. +# Copyright (c) 2009, 2010, 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 diff --git a/storage/perfschema/unittest/pfs-t.cc b/storage/perfschema/unittest/pfs-t.cc index ea3e1aab5ec..6b30c0cc498 100644 --- a/storage/perfschema/unittest/pfs-t.cc +++ b/storage/perfschema/unittest/pfs-t.cc @@ -25,6 +25,7 @@ #include <memory.h> #include "stub_print_error.h" +#include "stub_pfs_defaults.h" #include "stub_server_misc.h" /* test helpers, to simulate the setup */ @@ -79,6 +80,7 @@ void test_bootstrap() diag("test_bootstrap"); + memset(& param, 0xFF, sizeof(param)); param.m_enabled= true; param.m_mutex_class_sizing= 0; param.m_rwlock_class_sizing= 0; @@ -86,6 +88,7 @@ void test_bootstrap() param.m_thread_class_sizing= 0; param.m_table_share_sizing= 0; param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 0; param.m_mutex_sizing= 0; param.m_rwlock_sizing= 0; param.m_cond_sizing= 0; @@ -93,8 +96,21 @@ void test_bootstrap() param.m_table_sizing= 0; param.m_file_sizing= 0; param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; param.m_events_waits_history_sizing= 0; param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_host_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + param.m_digest_sizing= 0; boot= initialize_performance_schema(& param); ok(boot != NULL, "boot"); @@ -121,6 +137,7 @@ PSI * load_perfschema() PSI_bootstrap *boot; PFS_global_param param; + memset(& param, 0xFF, sizeof(param)); param.m_enabled= true; param.m_mutex_class_sizing= 10; param.m_rwlock_class_sizing= 10; @@ -128,6 +145,7 @@ PSI * load_perfschema() param.m_thread_class_sizing= 10; param.m_table_share_sizing= 10; param.m_file_class_sizing= 10; + param.m_socket_class_sizing= 10; param.m_mutex_sizing= 10; param.m_rwlock_sizing= 10; param.m_cond_sizing= 10; @@ -135,13 +153,30 @@ PSI * load_perfschema() param.m_table_sizing= 10; param.m_file_sizing= 10; param.m_file_handle_sizing= 50; + param.m_socket_sizing= 10; param.m_events_waits_history_sizing= 10; param.m_events_waits_history_long_sizing= 10; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_host_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + param.m_digest_sizing= 0; /* test_bootstrap() covered this, assuming it just works */ boot= initialize_performance_schema(& param); psi= boot->get_interface(PSI_VERSION_1); + /* Reset every consumer to a known state */ + flag_global_instrumentation= true; + flag_thread_instrumentation= true; + return (PSI*) psi; } @@ -478,6 +513,72 @@ void test_bad_registration() psi->register_file("X", bad_file_3, 1); ok(dummy_file_key == 2, "assigned key"); + /* + Test that length('wait/io/socket/' (15) + category + '/' (1)) < 32 + --> category can be up to 15 chars for a socket. + */ + + PSI_socket_key dummy_socket_key= 9999; + PSI_socket_info bad_socket_1[]= + { + { & dummy_socket_key, "X", 0} + }; + + psi->register_socket("/", bad_socket_1, 1); + ok(dummy_socket_key == 0, "zero key"); + dummy_socket_key= 9999; + psi->register_socket("a/", bad_socket_1, 1); + ok(dummy_socket_key == 0, "zero key"); + dummy_socket_key= 9999; + psi->register_socket("/b", bad_socket_1, 1); + ok(dummy_socket_key == 0, "zero key"); + dummy_socket_key= 9999; + psi->register_socket("a/b", bad_socket_1, 1); + ok(dummy_socket_key == 0, "zero key"); + dummy_socket_key= 9999; + psi->register_socket("1234567890123456", bad_socket_1, 1); + ok(dummy_socket_key == 0, "zero key"); + dummy_socket_key= 9999; + psi->register_socket("123456789012345", bad_socket_1, 1); + ok(dummy_socket_key == 1, "assigned key"); + + /* + Test that length('wait/io/socket/' (15) + category + '/' (1) + name) <= 128 + --> category + name can be up to 112 chars for a socket. + */ + + dummy_socket_key= 9999; + PSI_socket_info bad_socket_2[]= + { + { & dummy_socket_key, + /* 112 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "123456789012", + 0} + }; + + psi->register_socket("X", bad_socket_2, 1); + ok(dummy_socket_key == 0, "zero key"); + + dummy_socket_key= 9999; + PSI_socket_info bad_socket_3[]= + { + { & dummy_socket_key, + /* 111 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678901", + 0} + }; + + psi->register_socket("XX", bad_socket_3, 1); + ok(dummy_socket_key == 0, "zero key"); + + psi->register_socket("X", bad_socket_3, 1); + ok(dummy_socket_key == 2, "assigned key"); + + shutdown_performance_schema(); } @@ -513,6 +614,12 @@ void test_init_disabled() { & file_key_A, "F-A", 0} }; + PSI_socket_key socket_key_A; + PSI_socket_info all_socket[]= + { + { & socket_key_A, "S-A", 0} + }; + PSI_thread_key thread_key_1; PSI_thread_info all_thread[]= { @@ -523,16 +630,19 @@ void test_init_disabled() psi->register_rwlock("test", all_rwlock, 1); psi->register_cond("test", all_cond, 1); psi->register_file("test", all_file, 1); + psi->register_socket("test", all_socket, 1); psi->register_thread("test", all_thread, 1); PFS_mutex_class *mutex_class_A; PFS_rwlock_class *rwlock_class_A; PFS_cond_class *cond_class_A; PFS_file_class *file_class_A; + PFS_socket_class *socket_class_A; PSI_mutex *mutex_A1; PSI_rwlock *rwlock_A1; PSI_cond *cond_A1; PFS_file *file_A1; + PSI_socket *socket_A1; PSI_thread *thread_1; /* Preparation */ @@ -553,8 +663,11 @@ void test_init_disabled() file_class_A= find_file_class(file_key_A); ok(file_class_A != NULL, "file class A"); - /* Pretend thread T-1 is running, and disabled */ - /* ------------------------------------------- */ + socket_class_A= find_socket_class(socket_key_A); + ok(socket_class_A != NULL, "socket class A"); + + /* Pretend thread T-1 is running, and disabled, with thread_instrumentation */ + /* ------------------------------------------------------------------------ */ psi->set_thread(thread_1); setup_thread(thread_1, false); @@ -563,61 +676,61 @@ void test_init_disabled() mutex_class_A->m_enabled= false; mutex_A1= psi->init_mutex(mutex_key_A, NULL); - ok(mutex_A1 == NULL, "not instrumented"); + ok(mutex_A1 == NULL, "mutex_A1 not instrumented"); - /* enabled M-A + disabled T-1: no instrumentation */ + /* enabled M-A + disabled T-1: instrumentation (for later) */ mutex_class_A->m_enabled= true; mutex_A1= psi->init_mutex(mutex_key_A, NULL); - ok(mutex_A1 == NULL, "not instrumented"); + ok(mutex_A1 != NULL, "mutex_A1 instrumented"); /* broken key + disabled T-1: no instrumentation */ mutex_class_A->m_enabled= true; mutex_A1= psi->init_mutex(0, NULL); - ok(mutex_A1 == NULL, "not instrumented"); + ok(mutex_A1 == NULL, "mutex key 0 not instrumented"); mutex_A1= psi->init_mutex(99, NULL); - ok(mutex_A1 == NULL, "not instrumented"); + ok(mutex_A1 == NULL, "broken mutex key not instrumented"); /* disabled RW-A + disabled T-1: no instrumentation */ rwlock_class_A->m_enabled= false; rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); - ok(rwlock_A1 == NULL, "not instrumented"); + ok(rwlock_A1 == NULL, "rwlock_A1 not instrumented"); - /* enabled RW-A + disabled T-1: no instrumentation */ + /* enabled RW-A + disabled T-1: instrumentation (for later) */ rwlock_class_A->m_enabled= true; rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); - ok(rwlock_A1 == NULL, "not instrumented"); + ok(rwlock_A1 != NULL, "rwlock_A1 instrumented"); /* broken key + disabled T-1: no instrumentation */ rwlock_class_A->m_enabled= true; rwlock_A1= psi->init_rwlock(0, NULL); - ok(rwlock_A1 == NULL, "not instrumented"); + ok(rwlock_A1 == NULL, "rwlock key 0 not instrumented"); rwlock_A1= psi->init_rwlock(99, NULL); - ok(rwlock_A1 == NULL, "not instrumented"); + ok(rwlock_A1 == NULL, "broken rwlock key not instrumented"); /* disabled C-A + disabled T-1: no instrumentation */ cond_class_A->m_enabled= false; cond_A1= psi->init_cond(cond_key_A, NULL); - ok(cond_A1 == NULL, "not instrumented"); + ok(cond_A1 == NULL, "cond_A1 not instrumented"); - /* enabled C-A + disabled T-1: no instrumentation */ + /* enabled C-A + disabled T-1: instrumentation (for later) */ cond_class_A->m_enabled= true; cond_A1= psi->init_cond(cond_key_A, NULL); - ok(cond_A1 == NULL, "not instrumented"); + ok(cond_A1 != NULL, "cond_A1 instrumented"); /* broken key + disabled T-1: no instrumentation */ cond_class_A->m_enabled= true; cond_A1= psi->init_cond(0, NULL); - ok(cond_A1 == NULL, "not instrumented"); + ok(cond_A1 == NULL, "cond key 0 not instrumented"); cond_A1= psi->init_cond(99, NULL); - ok(cond_A1 == NULL, "not instrumented"); + ok(cond_A1 == NULL, "broken cond key not instrumented"); /* disabled F-A + disabled T-1: no instrumentation */ @@ -643,6 +756,26 @@ void test_init_disabled() file_A1= lookup_file_by_name("foo"); ok(file_A1 == NULL, "not instrumented"); + /* disabled S-A + disabled T-1: no instrumentation */ + + socket_class_A->m_enabled= false; + socket_A1= psi->init_socket(socket_key_A, NULL); + ok(socket_A1 == NULL, "socket_A1 not instrumented"); + + /* enabled S-A + disabled T-1: instrumentation (for later) */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(socket_key_A, NULL); + ok(socket_A1 != NULL, "socket_A1 instrumented"); + + /* broken key + disabled T-1: no instrumentation */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(0, NULL); + ok(socket_A1 == NULL, "socket key 0 not instrumented"); + socket_A1= psi->init_socket(99, NULL); + ok(socket_A1 == NULL, "broken socket key not instrumented"); + /* Pretend thread T-1 is enabled */ /* ----------------------------- */ @@ -739,17 +872,37 @@ void test_init_disabled() file_class_A->m_enabled= true; psi->create_file(file_key_A, "foo-instrumented", (File) 12); file_A1= lookup_file_by_name("foo-instrumented"); - ok(file_A1 != NULL, "instrumented"); + ok(file_A1 != NULL, "file_A1 instrumented"); /* broken key + enabled T-1: no instrumentation */ file_class_A->m_enabled= true; psi->create_file(0, "foo", (File) 12); file_A1= lookup_file_by_name("foo"); - ok(file_A1 == NULL, "not instrumented"); + ok(file_A1 == NULL, "file key 0 not instrumented"); psi->create_file(99, "foo", (File) 12); file_A1= lookup_file_by_name("foo"); - ok(file_A1 == NULL, "not instrumented"); + ok(file_A1 == NULL, "broken file key not instrumented"); + + /* disabled S-A + enabled T-1: no instrumentation */ + + socket_class_A->m_enabled= false; + ok(socket_A1 == NULL, "not instrumented"); + + /* enabled S-A + enabled T-1: instrumentation */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(socket_key_A, NULL); + ok(socket_A1 != NULL, "instrumented"); + psi->destroy_socket(socket_A1); + + /* broken key + enabled T-1: no instrumentation */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(0, NULL); + ok(socket_A1 == NULL, "not instrumented"); + socket_A1= psi->init_socket(99, NULL); + ok(socket_A1 == NULL, "not instrumented"); /* Pretend the running thread is not instrumented */ /* ---------------------------------------------- */ @@ -760,61 +913,61 @@ void test_init_disabled() mutex_class_A->m_enabled= false; mutex_A1= psi->init_mutex(mutex_key_A, NULL); - ok(mutex_A1 == NULL, "not instrumented"); + ok(mutex_A1 == NULL, "mutex_A1 not instrumented"); - /* enabled M-A + unknown thread: no instrumentation */ + /* enabled M-A + unknown thread: instrumentation (for later) */ mutex_class_A->m_enabled= true; mutex_A1= psi->init_mutex(mutex_key_A, NULL); - ok(mutex_A1 == NULL, "not instrumented"); + ok(mutex_A1 != NULL, "mutex_A1 instrumented"); /* broken key + unknown thread: no instrumentation */ mutex_class_A->m_enabled= true; mutex_A1= psi->init_mutex(0, NULL); - ok(mutex_A1 == NULL, "not instrumented"); + ok(mutex_A1 == NULL, "mutex key 0 not instrumented"); mutex_A1= psi->init_mutex(99, NULL); - ok(mutex_A1 == NULL, "not instrumented"); + ok(mutex_A1 == NULL, "broken mutex key not instrumented"); /* disabled RW-A + unknown thread: no instrumentation */ rwlock_class_A->m_enabled= false; rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); - ok(rwlock_A1 == NULL, "not instrumented"); + ok(rwlock_A1 == NULL, "rwlock_A1 not instrumented"); - /* enabled RW-A + unknown thread: no instrumentation */ + /* enabled RW-A + unknown thread: instrumentation (for later) */ rwlock_class_A->m_enabled= true; rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); - ok(rwlock_A1 == NULL, "not instrumented"); + ok(rwlock_A1 != NULL, "rwlock_A1 instrumented"); /* broken key + unknown thread: no instrumentation */ rwlock_class_A->m_enabled= true; rwlock_A1= psi->init_rwlock(0, NULL); - ok(rwlock_A1 == NULL, "not instrumented"); + ok(rwlock_A1 == NULL, "rwlock key 0 not instrumented"); rwlock_A1= psi->init_rwlock(99, NULL); - ok(rwlock_A1 == NULL, "not instrumented"); + ok(rwlock_A1 == NULL, "broken rwlock key not instrumented"); /* disabled C-A + unknown thread: no instrumentation */ cond_class_A->m_enabled= false; cond_A1= psi->init_cond(cond_key_A, NULL); - ok(cond_A1 == NULL, "not instrumented"); + ok(cond_A1 == NULL, "cond_A1 not instrumented"); - /* enabled C-A + unknown thread: no instrumentation */ + /* enabled C-A + unknown thread: instrumentation (for later) */ cond_class_A->m_enabled= true; cond_A1= psi->init_cond(cond_key_A, NULL); - ok(cond_A1 == NULL, "not instrumented"); + ok(cond_A1 != NULL, "cond_A1 instrumented"); /* broken key + unknown thread: no instrumentation */ cond_class_A->m_enabled= true; cond_A1= psi->init_cond(0, NULL); - ok(cond_A1 == NULL, "not instrumented"); + ok(cond_A1 == NULL, "cond key 0 not instrumented"); cond_A1= psi->init_cond(99, NULL); - ok(cond_A1 == NULL, "not instrumented"); + ok(cond_A1 == NULL, "broken cond key not instrumented"); /* disabled F-A + unknown thread: no instrumentation */ @@ -840,6 +993,26 @@ void test_init_disabled() file_A1= lookup_file_by_name("foo"); ok(file_A1 == NULL, "not instrumented"); + /* disabled S-A + unknown thread: no instrumentation */ + + socket_class_A->m_enabled= false; + socket_A1= psi->init_socket(socket_key_A, NULL); + ok(socket_A1 == NULL, "socket_A1 not instrumented"); + + /* enabled S-A + unknown thread: instrumentation (for later) */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(socket_key_A, NULL); + ok(socket_A1 != NULL, "socket_A1 instrumented"); + + /* broken key + unknown thread: no instrumentation */ + + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(0, NULL); + ok(socket_A1 == NULL, "socket key 0 not instrumented"); + socket_A1= psi->init_socket(99, NULL); + ok(socket_A1 == NULL, "broken socket key not instrumented"); + shutdown_performance_schema(); } @@ -875,6 +1048,12 @@ void test_locker_disabled() { & file_key_A, "F-A", 0} }; + PSI_socket_key socket_key_A; + PSI_socket_info all_socket[]= + { + { & socket_key_A, "S-A", 0} + }; + PSI_thread_key thread_key_1; PSI_thread_info all_thread[]= { @@ -885,16 +1064,19 @@ void test_locker_disabled() psi->register_rwlock("test", all_rwlock, 1); psi->register_cond("test", all_cond, 1); psi->register_file("test", all_file, 1); + psi->register_socket("test", all_socket, 1); psi->register_thread("test", all_thread, 1); PFS_mutex_class *mutex_class_A; PFS_rwlock_class *rwlock_class_A; PFS_cond_class *cond_class_A; PFS_file_class *file_class_A; + PFS_socket_class *socket_class_A; PSI_mutex *mutex_A1; PSI_rwlock *rwlock_A1; PSI_cond *cond_A1; PSI_file *file_A1; + PSI_socket *socket_A1; PSI_thread *thread_1; /* Preparation */ @@ -915,6 +1097,9 @@ void test_locker_disabled() file_class_A= find_file_class(file_key_A); ok(file_class_A != NULL, "file info A"); + socket_class_A= find_socket_class(socket_key_A); + ok(socket_class_A != NULL, "socket info A"); + /* Pretend thread T-1 is running, and enabled */ /* ------------------------------------------ */ @@ -940,6 +1125,13 @@ void test_locker_disabled() file_A1= (PSI_file*) lookup_file_by_name("foo"); ok(file_A1 != NULL, "instrumented"); + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(socket_key_A, NULL); + ok(socket_A1 != NULL, "instrumented"); + + /* Socket lockers require a thread owner */ + psi->set_socket_thread_owner(socket_A1); + PSI_mutex_locker *mutex_locker; PSI_mutex_locker_state mutex_state; PSI_rwlock_locker *rwlock_locker; @@ -948,6 +1140,8 @@ void test_locker_disabled() PSI_cond_locker_state cond_state; PSI_file_locker *file_locker; PSI_file_locker_state file_state; + PSI_socket_locker *socket_locker; + PSI_socket_locker_state socket_state; /* Pretend thread T-1 is disabled */ /* ------------------------------ */ @@ -958,58 +1152,110 @@ void test_locker_disabled() rwlock_class_A->m_enabled= true; cond_class_A->m_enabled= true; file_class_A->m_enabled= true; - - mutex_locker= psi->get_thread_mutex_locker(&mutex_state, mutex_A1, PSI_MUTEX_LOCK); - ok(mutex_locker == NULL, "no locker"); - rwlock_locker= psi->get_thread_rwlock_locker(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK); - ok(rwlock_locker == NULL, "no locker"); - cond_locker= psi->get_thread_cond_locker(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT); - ok(cond_locker == NULL, "no locker"); + socket_class_A->m_enabled= true; + + mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12); + ok(mutex_locker == NULL, "no locker (T-1 disabled)"); + rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12); + ok(rwlock_locker == NULL, "no locker (T-1 disabled)"); + cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12); + ok(cond_locker == NULL, "no locker (T-1 disabled)"); file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL); - ok(file_locker == NULL, "no locker"); + ok(file_locker == NULL, "no locker (T-1 disabled)"); file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ); - ok(file_locker == NULL, "no locker"); + ok(file_locker == NULL, "no locker (T-1 disabled)"); file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ); - ok(file_locker == NULL, "no locker"); + ok(file_locker == NULL, "no locker (T-1 disabled)"); + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12); + ok(socket_locker == NULL, "no locker (T-1 disabled)"); - /* Pretend the consumer is disabled */ - /* -------------------------------- */ + /* Pretend the global consumer is disabled */ + /* --------------------------------------- */ setup_thread(thread_1, true); - flag_events_waits_current= false; + flag_global_instrumentation= false; mutex_class_A->m_enabled= true; rwlock_class_A->m_enabled= true; cond_class_A->m_enabled= true; file_class_A->m_enabled= true; + socket_class_A->m_enabled= true; + update_instruments_derived_flags(); + + mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12); + ok(mutex_locker == NULL, "no locker (global disabled)"); + rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12); + ok(rwlock_locker == NULL, "no locker (global disabled)"); + cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12); + ok(cond_locker == NULL, "no locker (global disabled)"); + file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL); + ok(file_locker == NULL, "no locker (global disabled)"); + file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ); + ok(file_locker == NULL, "no locker (global disabled)"); + file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ); + ok(file_locker == NULL, "no locker (global disabled)"); + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12); + ok(socket_locker == NULL, "no locker (global disabled)"); - mutex_locker= psi->get_thread_mutex_locker(&mutex_state, mutex_A1, PSI_MUTEX_LOCK); - ok(mutex_locker == NULL, "no locker"); - rwlock_locker= psi->get_thread_rwlock_locker(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK); - ok(rwlock_locker == NULL, "no locker"); - cond_locker= psi->get_thread_cond_locker(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT); - ok(cond_locker == NULL, "no locker"); + /* Pretend the mode is global, counted only */ + /* ---------------------------------------- */ + + setup_thread(thread_1, true); + flag_global_instrumentation= true; + flag_thread_instrumentation= false; + mutex_class_A->m_enabled= true; + mutex_class_A->m_timed= false; + rwlock_class_A->m_enabled= true; + rwlock_class_A->m_timed= false; + cond_class_A->m_enabled= true; + cond_class_A->m_timed= false; + file_class_A->m_enabled= true; + file_class_A->m_timed= false; + socket_class_A->m_enabled= true; + socket_class_A->m_timed= false; + update_instruments_derived_flags(); + + mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12); + ok(mutex_locker == NULL, "no locker (global counted)"); + rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12); + ok(rwlock_locker == NULL, "no locker (global counted)"); + cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12); + ok(cond_locker == NULL, "no locker (global counted)"); file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL); - ok(file_locker == NULL, "no locker"); + ok(file_locker != NULL, "locker (global counted)"); + psi->start_file_wait(file_locker, 10, __FILE__, __LINE__); + psi->end_file_wait(file_locker, 10); file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ); - ok(file_locker == NULL, "no locker"); + ok(file_locker != NULL, "locker (global counted)"); + psi->start_file_wait(file_locker, 10, __FILE__, __LINE__); + psi->end_file_wait(file_locker, 10); file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ); - ok(file_locker == NULL, "no locker"); + ok(file_locker != NULL, "locker (global counted)"); + psi->start_file_wait(file_locker, 10, __FILE__, __LINE__); + psi->end_file_wait(file_locker, 10); + /* The null locker shortcut applies only to socket ops with no byte count */ + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_BIND, 0, "foo.cc", 12); + ok(socket_locker == NULL, "no locker (global counted)"); + + /* TODO */ /* Pretend the instrument is disabled */ /* ---------------------------------- */ setup_thread(thread_1, true); + flag_global_instrumentation= true; flag_events_waits_current= true; mutex_class_A->m_enabled= false; rwlock_class_A->m_enabled= false; cond_class_A->m_enabled= false; file_class_A->m_enabled= false; + socket_class_A->m_enabled= false; + update_instruments_derived_flags(); - mutex_locker= psi->get_thread_mutex_locker(&mutex_state, mutex_A1, PSI_MUTEX_LOCK); + mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12); ok(mutex_locker == NULL, "no locker"); - rwlock_locker= psi->get_thread_rwlock_locker(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK); + rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12); ok(rwlock_locker == NULL, "no locker"); - cond_locker= psi->get_thread_cond_locker(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT); + cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12); ok(cond_locker == NULL, "no locker"); file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL); ok(file_locker == NULL, "no locker"); @@ -1017,28 +1263,36 @@ void test_locker_disabled() ok(file_locker == NULL, "no locker"); file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ); ok(file_locker == NULL, "no locker"); + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12); + ok(socket_locker == NULL, "no locker"); - /* Pretend everything is enabled */ - /* ----------------------------- */ + /* Pretend everything is enabled and timed */ + /* --------------------------------------- */ setup_thread(thread_1, true); + flag_global_instrumentation= true; + flag_thread_instrumentation= true; flag_events_waits_current= true; mutex_class_A->m_enabled= true; + mutex_class_A->m_timed= true; rwlock_class_A->m_enabled= true; + rwlock_class_A->m_timed= true; cond_class_A->m_enabled= true; + cond_class_A->m_timed= true; file_class_A->m_enabled= true; + file_class_A->m_timed= true; + socket_class_A->m_enabled= true; + socket_class_A->m_timed= true; + update_instruments_derived_flags(); - mutex_locker= psi->get_thread_mutex_locker(&mutex_state, mutex_A1, PSI_MUTEX_LOCK); + mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, __FILE__, __LINE__); ok(mutex_locker != NULL, "locker"); - psi->start_mutex_wait(mutex_locker, __FILE__, __LINE__); psi->end_mutex_wait(mutex_locker, 0); - rwlock_locker= psi->get_thread_rwlock_locker(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK); + rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, __FILE__, __LINE__); ok(rwlock_locker != NULL, "locker"); - psi->start_rwlock_rdwait(rwlock_locker, __FILE__, __LINE__); psi->end_rwlock_rdwait(rwlock_locker, 0); - cond_locker= psi->get_thread_cond_locker(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT); + cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, __FILE__, __LINE__); ok(cond_locker != NULL, "locker"); - psi->start_cond_wait(cond_locker, __FILE__, __LINE__); psi->end_cond_wait(cond_locker, 0); file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL); ok(file_locker != NULL, "locker"); @@ -1052,7 +1306,20 @@ void test_locker_disabled() ok(file_locker != NULL, "locker"); psi->start_file_wait(file_locker, 10, __FILE__, __LINE__); psi->end_file_wait(file_locker, 10); + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12); + ok(socket_locker != NULL, "locker"); + psi->end_socket_wait(socket_locker, 10); + + /* Pretend the socket does not have a thread owner */ + /* ---------------------------------------------- */ + socket_class_A->m_enabled= true; + socket_A1= psi->init_socket(socket_key_A, NULL); + ok(socket_A1 != NULL, "instrumented"); + /* Socket thread owner has not been set */ + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12); + ok(socket_locker == NULL, "no locker (no thread owner)"); + /* Pretend the running thread is not instrumented */ /* ---------------------------------------------- */ @@ -1062,12 +1329,14 @@ void test_locker_disabled() rwlock_class_A->m_enabled= true; cond_class_A->m_enabled= true; file_class_A->m_enabled= true; + socket_class_A->m_enabled= true; + update_instruments_derived_flags(); - mutex_locker= psi->get_thread_mutex_locker(&mutex_state, mutex_A1, PSI_MUTEX_LOCK); + mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12); ok(mutex_locker == NULL, "no locker"); - rwlock_locker= psi->get_thread_rwlock_locker(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK); + rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12); ok(rwlock_locker == NULL, "no locker"); - cond_locker= psi->get_thread_cond_locker(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT); + cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12); ok(cond_locker == NULL, "no locker"); file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL); ok(file_locker == NULL, "no locker"); @@ -1075,6 +1344,8 @@ void test_locker_disabled() ok(file_locker == NULL, "no locker"); file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ); ok(file_locker == NULL, "no locker"); + socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12); + ok(socket_locker == NULL, "no locker"); shutdown_performance_schema(); } @@ -1203,6 +1474,150 @@ void test_enabled() #endif } +void test_event_name_index() +{ + PSI *psi; + PSI_bootstrap *boot; + PFS_global_param param; + + diag("test_event_name_index"); + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + + /* Per mutex info waits should be at [0..9] */ + param.m_mutex_class_sizing= 10; + /* Per rwlock info waits should be at [10..29] */ + param.m_rwlock_class_sizing= 20; + /* Per cond info waits should be at [30..69] */ + param.m_cond_class_sizing= 40; + /* Per file info waits should be at [70..149] */ + param.m_file_class_sizing= 80; + /* Per socket info waits should be at [150..309] */ + param.m_socket_class_sizing= 160; + /* Per table info waits should be at [310] */ + param.m_table_share_sizing= 320; + + param.m_thread_class_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_host_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + param.m_digest_sizing= 0; + + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 0; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + + boot= initialize_performance_schema(& param); + ok(boot != NULL, "bootstrap"); + psi= (PSI*) boot->get_interface(PSI_VERSION_1); + ok(psi != NULL, "psi"); + + PFS_mutex_class *mutex_class; + PSI_mutex_key dummy_mutex_key_1; + PSI_mutex_key dummy_mutex_key_2; + PSI_mutex_info dummy_mutexes[]= + { + { & dummy_mutex_key_1, "M-1", 0}, + { & dummy_mutex_key_2, "M-2", 0} + }; + + psi->register_mutex("X", dummy_mutexes, 2); + mutex_class= find_mutex_class(dummy_mutex_key_1); + ok(mutex_class != NULL, "mutex class 1"); + ok(mutex_class->m_event_name_index == 0, "index 0"); + mutex_class= find_mutex_class(dummy_mutex_key_2); + ok(mutex_class != NULL, "mutex class 2"); + ok(mutex_class->m_event_name_index == 1, "index 1"); + + PFS_rwlock_class *rwlock_class; + PSI_rwlock_key dummy_rwlock_key_1; + PSI_rwlock_key dummy_rwlock_key_2; + PSI_rwlock_info dummy_rwlocks[]= + { + { & dummy_rwlock_key_1, "RW-1", 0}, + { & dummy_rwlock_key_2, "RW-2", 0} + }; + + psi->register_rwlock("X", dummy_rwlocks, 2); + rwlock_class= find_rwlock_class(dummy_rwlock_key_1); + ok(rwlock_class != NULL, "rwlock class 1"); + ok(rwlock_class->m_event_name_index == 10, "index 10"); + rwlock_class= find_rwlock_class(dummy_rwlock_key_2); + ok(rwlock_class != NULL, "rwlock class 2"); + ok(rwlock_class->m_event_name_index == 11, "index 11"); + + PFS_cond_class *cond_class; + PSI_cond_key dummy_cond_key_1; + PSI_cond_key dummy_cond_key_2; + PSI_cond_info dummy_conds[]= + { + { & dummy_cond_key_1, "C-1", 0}, + { & dummy_cond_key_2, "C-2", 0} + }; + + psi->register_cond("X", dummy_conds, 2); + cond_class= find_cond_class(dummy_cond_key_1); + ok(cond_class != NULL, "cond class 1"); + ok(cond_class->m_event_name_index == 30, "index 30"); + cond_class= find_cond_class(dummy_cond_key_2); + ok(cond_class != NULL, "cond class 2"); + ok(cond_class->m_event_name_index == 31, "index 31"); + + PFS_file_class *file_class; + PSI_file_key dummy_file_key_1; + PSI_file_key dummy_file_key_2; + PSI_file_info dummy_files[]= + { + { & dummy_file_key_1, "F-1", 0}, + { & dummy_file_key_2, "F-2", 0} + }; + + psi->register_file("X", dummy_files, 2); + file_class= find_file_class(dummy_file_key_1); + ok(file_class != NULL, "file class 1"); + ok(file_class->m_event_name_index == 70, "index 70"); + file_class= find_file_class(dummy_file_key_2); + ok(file_class != NULL, "file class 2"); + ok(file_class->m_event_name_index == 71, "index 71"); + + PFS_socket_class *socket_class; + PSI_socket_key dummy_socket_key_1; + PSI_socket_key dummy_socket_key_2; + PSI_socket_info dummy_sockets[]= + { + { & dummy_socket_key_1, "S-1", 0}, + { & dummy_socket_key_2, "S-2", 0} + }; + + psi->register_socket("X", dummy_sockets, 2); + socket_class= find_socket_class(dummy_socket_key_1); + ok(socket_class != NULL, "socket class 1"); + ok(socket_class->m_event_name_index == 150, "index 150"); + socket_class= find_socket_class(dummy_socket_key_2); + ok(socket_class != NULL, "socket class 2"); + ok(socket_class->m_event_name_index == 151, "index 151"); + + ok(global_table_io_class.m_event_name_index == 310, "index 310"); + ok(global_table_lock_class.m_event_name_index == 311, "index 311"); + ok(wait_class_max= 313, "313 event names"); // 3 global classes +} + void do_all_tests() { /* Using initialize_performance_schema(), no partial init needed. */ @@ -1212,14 +1627,14 @@ void do_all_tests() test_init_disabled(); test_locker_disabled(); test_file_instrumentation_leak(); + test_event_name_index(); } int main(int argc, char **argv) { - plan(153); + plan(216); MY_INIT(argv[0]); do_all_tests(); my_end(0); return 0; } - diff --git a/storage/perfschema/unittest/pfs_account-oom-t.cc b/storage/perfschema/unittest/pfs_account-oom-t.cc new file mode 100644 index 00000000000..e6fddead511 --- /dev/null +++ b/storage/perfschema/unittest/pfs_account-oom-t.cc @@ -0,0 +1,116 @@ +/* Copyright (c) 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_pthread.h> +#include <pfs_instr.h> +#include <pfs_stat.h> +#include <pfs_global.h> +#include <pfs_account.h> +#include <tap.h> + +#include "stub_pfs_global.h" +#include "stub_server_misc.h" + +#include <string.h> /* memset */ + +void test_oom() +{ + int rc; + PFS_global_param param; + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 10; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 1000; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_events_waits_history_sizing= 10; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 1000; + param.m_stage_class_sizing= 50; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 50; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + /* Setup */ + + stub_alloc_always_fails= false; + stub_alloc_fails_after_count= 1000; + + init_event_name_sizing(& param); + rc= init_stage_class(param.m_stage_class_sizing); + ok(rc == 0, "init stage class"); + rc= init_statement_class(param.m_statement_class_sizing); + ok(rc == 0, "init statement class"); + + /* Tests */ + + stub_alloc_fails_after_count= 1; + rc= init_account(& param); + ok(rc == 1, "oom (account)"); + cleanup_account(); + + stub_alloc_fails_after_count= 2; + rc= init_account(& param); + ok(rc == 1, "oom (account waits)"); + cleanup_account(); + + stub_alloc_fails_after_count= 3; + rc= init_account(& param); + ok(rc == 1, "oom (account stages)"); + cleanup_account(); + + stub_alloc_fails_after_count= 4; + rc= init_account(& param); + ok(rc == 1, "oom (account statements)"); + cleanup_account(); + + cleanup_statement_class(); + cleanup_stage_class(); +} + +void do_all_tests() +{ + PFS_atomic::init(); + + test_oom(); + + PFS_atomic::cleanup(); +} + +int main(int, char **) +{ + plan(6); + MY_INIT("pfs_account-oom-t"); + do_all_tests(); + return 0; +} + diff --git a/storage/perfschema/unittest/pfs_host-oom-t.cc b/storage/perfschema/unittest/pfs_host-oom-t.cc new file mode 100644 index 00000000000..075a2e6a07a --- /dev/null +++ b/storage/perfschema/unittest/pfs_host-oom-t.cc @@ -0,0 +1,116 @@ +/* Copyright (c) 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_pthread.h> +#include <pfs_instr.h> +#include <pfs_stat.h> +#include <pfs_global.h> +#include <pfs_host.h> +#include <tap.h> + +#include "stub_pfs_global.h" +#include "stub_server_misc.h" + +#include <string.h> /* memset */ + +void test_oom() +{ + int rc; + PFS_global_param param; + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 10; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 1000; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_events_waits_history_sizing= 10; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 1000; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 50; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 50; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + /* Setup */ + + stub_alloc_always_fails= false; + stub_alloc_fails_after_count= 1000; + + init_event_name_sizing(& param); + rc= init_stage_class(param.m_stage_class_sizing); + ok(rc == 0, "init stage class"); + rc= init_statement_class(param.m_statement_class_sizing); + ok(rc == 0, "init statement class"); + + /* Tests */ + + stub_alloc_fails_after_count= 1; + rc= init_host(& param); + ok(rc == 1, "oom (host)"); + cleanup_host(); + + stub_alloc_fails_after_count= 2; + rc= init_host(& param); + ok(rc == 1, "oom (host waits)"); + cleanup_host(); + + stub_alloc_fails_after_count= 3; + rc= init_host(& param); + ok(rc == 1, "oom (host stages)"); + cleanup_host(); + + stub_alloc_fails_after_count= 4; + rc= init_host(& param); + ok(rc == 1, "oom (host statements)"); + cleanup_host(); + + cleanup_statement_class(); + cleanup_stage_class(); +} + +void do_all_tests() +{ + PFS_atomic::init(); + + test_oom(); + + PFS_atomic::cleanup(); +} + +int main(int, char **) +{ + plan(6); + MY_INIT("pfs_host-oom-t"); + do_all_tests(); + return 0; +} + diff --git a/storage/perfschema/unittest/pfs_instr-oom-t.cc b/storage/perfschema/unittest/pfs_instr-oom-t.cc index 175c09bcd39..41bb4ed6c5a 100644 --- a/storage/perfschema/unittest/pfs_instr-oom-t.cc +++ b/storage/perfschema/unittest/pfs_instr-oom-t.cc @@ -18,11 +18,14 @@ #include <pfs_instr.h> #include <pfs_stat.h> #include <pfs_global.h> +#include <pfs_instr_class.h> #include <tap.h> #include "stub_pfs_global.h" #include "stub_server_misc.h" +#include <string.h> /* memset */ + void test_oom() { int rc; @@ -30,6 +33,7 @@ void test_oom() stub_alloc_always_fails= true; + memset(& param, 0xFF, sizeof(param)); param.m_enabled= true; param.m_mutex_class_sizing= 10; param.m_rwlock_class_sizing= 0; @@ -37,6 +41,7 @@ void test_oom() param.m_thread_class_sizing= 0; param.m_table_share_sizing= 0; param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 0; param.m_mutex_sizing= 1000; param.m_rwlock_sizing= 0; param.m_cond_sizing= 0; @@ -44,11 +49,25 @@ void test_oom() param.m_table_sizing= 0; param.m_file_sizing= 0; param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; param.m_events_waits_history_sizing= 0; param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + init_event_name_sizing(& param); rc= init_instruments(& param); ok(rc == 1, "oom (mutex)"); + cleanup_instruments(); param.m_enabled= true; param.m_mutex_class_sizing= 0; @@ -57,6 +76,7 @@ void test_oom() param.m_thread_class_sizing= 0; param.m_table_share_sizing= 0; param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 0; param.m_mutex_sizing= 0; param.m_rwlock_sizing= 1000; param.m_cond_sizing= 0; @@ -64,11 +84,25 @@ void test_oom() param.m_table_sizing= 0; param.m_file_sizing= 0; param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; param.m_events_waits_history_sizing= 0; param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + init_event_name_sizing(& param); rc= init_instruments(& param); ok(rc == 1, "oom (rwlock)"); + cleanup_instruments(); param.m_enabled= true; param.m_mutex_class_sizing= 0; @@ -77,6 +111,7 @@ void test_oom() param.m_thread_class_sizing= 0; param.m_table_share_sizing= 0; param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 0; param.m_mutex_sizing= 0; param.m_rwlock_sizing= 0; param.m_cond_sizing= 1000; @@ -84,11 +119,25 @@ void test_oom() param.m_table_sizing= 0; param.m_file_sizing= 0; param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; param.m_events_waits_history_sizing= 0; param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + init_event_name_sizing(& param); rc= init_instruments(& param); ok(rc == 1, "oom (cond)"); + cleanup_instruments(); param.m_enabled= true; param.m_mutex_class_sizing= 0; @@ -97,6 +146,7 @@ void test_oom() param.m_thread_class_sizing= 0; param.m_table_share_sizing= 0; param.m_file_class_sizing= 10; + param.m_socket_class_sizing= 0; param.m_mutex_sizing= 0; param.m_rwlock_sizing= 0; param.m_cond_sizing= 0; @@ -104,11 +154,58 @@ void test_oom() param.m_table_sizing= 0; param.m_file_sizing= 1000; param.m_file_handle_sizing= 1000; + param.m_socket_sizing= 0; param.m_events_waits_history_sizing= 0; param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + init_event_name_sizing(& param); rc= init_instruments(& param); ok(rc == 1, "oom (file)"); + cleanup_instruments(); + + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 0; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 0; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 1000; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + init_event_name_sizing(& param); + rc= init_instruments(& param); + ok(rc == 1, "oom (file handle)"); + cleanup_instruments(); param.m_enabled= true; param.m_mutex_class_sizing= 0; @@ -117,6 +214,7 @@ void test_oom() param.m_thread_class_sizing= 0; param.m_table_share_sizing= 10; param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 0; param.m_mutex_sizing= 0; param.m_rwlock_sizing= 0; param.m_cond_sizing= 0; @@ -124,11 +222,25 @@ void test_oom() param.m_table_sizing= 1000; param.m_file_sizing= 0; param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; param.m_events_waits_history_sizing= 0; param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + init_event_name_sizing(& param); rc= init_instruments(& param); ok(rc == 1, "oom (table)"); + cleanup_instruments(); param.m_enabled= true; param.m_mutex_class_sizing= 0; @@ -137,6 +249,7 @@ void test_oom() param.m_thread_class_sizing= 10; param.m_table_share_sizing= 0; param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 0; param.m_mutex_sizing= 0; param.m_rwlock_sizing= 0; param.m_cond_sizing= 0; @@ -144,11 +257,25 @@ void test_oom() param.m_table_sizing= 0; param.m_file_sizing= 0; param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; param.m_events_waits_history_sizing= 0; param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + init_event_name_sizing(& param); rc= init_instruments(& param); ok(rc == 1, "oom (thread)"); + cleanup_instruments(); stub_alloc_always_fails= false; @@ -159,6 +286,7 @@ void test_oom() param.m_thread_class_sizing= 10; param.m_table_share_sizing= 0; param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 0; param.m_mutex_sizing= 0; param.m_rwlock_sizing= 0; param.m_cond_sizing= 0; @@ -166,12 +294,26 @@ void test_oom() param.m_table_sizing= 0; param.m_file_sizing= 0; param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; param.m_events_waits_history_sizing= 10; param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; stub_alloc_fails_after_count= 2; + init_event_name_sizing(& param); rc= init_instruments(& param); - ok(rc == 1, "oom (thread history sizing)"); + ok(rc == 1, "oom (thread waits history sizing)"); + cleanup_instruments(); param.m_enabled= true; param.m_mutex_class_sizing= 50; @@ -180,6 +322,7 @@ void test_oom() param.m_thread_class_sizing= 10; param.m_table_share_sizing= 0; param.m_file_class_sizing= 50; + param.m_socket_class_sizing= 0; param.m_mutex_sizing= 0; param.m_rwlock_sizing= 0; param.m_cond_sizing= 0; @@ -187,14 +330,309 @@ void test_oom() param.m_table_sizing= 0; param.m_file_sizing= 0; param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; param.m_events_waits_history_sizing= 0; param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; stub_alloc_fails_after_count= 2; + init_event_name_sizing(& param); rc= init_instruments(& param); ok(rc == 1, "oom (per thread wait)"); + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 0; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 10; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 0; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_socket_sizing= 1000; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + + init_event_name_sizing(& param); + rc= init_instruments(& param); + ok(rc == 1, "oom (socket)"); + + cleanup_instruments(); + + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + stub_alloc_fails_after_count= 2; + init_event_name_sizing(& param); + rc= init_instruments(& param); + ok(rc == 1, "oom (per thread waits)"); + cleanup_instruments(); + + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 10; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 1000; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 10; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + stub_alloc_fails_after_count= 3; + init_event_name_sizing(& param); + rc= init_instruments(& param); + ok(rc == 1, "oom (thread stages history sizing)"); + cleanup_instruments(); + + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 10; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 1000; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 50; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + stub_alloc_fails_after_count= 2; + init_event_name_sizing(& param); + rc= init_instruments(& param); + ok(rc == 1, "oom (per thread stages)"); + cleanup_instruments(); + + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 10; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 1000; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 10; + param.m_events_statements_history_long_sizing= 0; + + stub_alloc_fails_after_count= 2; + init_event_name_sizing(& param); + rc= init_instruments(& param); + ok(rc == 1, "oom (thread statements history sizing)"); + cleanup_instruments(); + + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 10; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 1000; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 50; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + stub_alloc_fails_after_count= 2; + init_event_name_sizing(& param); + rc= init_instruments(& param); + ok(rc == 1, "oom (per thread statements)"); + cleanup_instruments(); + + param.m_enabled= true; + param.m_mutex_class_sizing= 10; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 0; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 0; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + stub_alloc_fails_after_count= 1; + init_event_name_sizing(& param); + rc= init_instruments(& param); + ok(rc == 1, "oom (global waits)"); + cleanup_instruments(); + + param.m_enabled= true; + param.m_mutex_class_sizing= 10; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 0; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 0; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 20; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + stub_alloc_fails_after_count= 3; + init_event_name_sizing(& param); + rc= init_stage_class(param.m_stage_class_sizing); + ok(rc == 0, "init stage class"); + rc= init_instruments(& param); + ok(rc == 1, "oom (global stages)"); + cleanup_instruments(); + cleanup_stage_class(); + + param.m_enabled= true; + param.m_mutex_class_sizing= 10; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 0; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 0; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_events_waits_history_sizing= 0; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 20; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + stub_alloc_fails_after_count= 3; + init_event_name_sizing(& param); + rc= init_statement_class(param.m_statement_class_sizing); + ok(rc == 0, "init statement class"); + rc= init_instruments(& param); + ok(rc == 1, "oom (global statements)"); cleanup_instruments(); + cleanup_statement_class(); } void do_all_tests() @@ -208,7 +646,7 @@ void do_all_tests() int main(int argc, char **argv) { - plan(8); + plan(20); MY_INIT(argv[0]); do_all_tests(); my_end(0); diff --git a/storage/perfschema/unittest/pfs_instr-t.cc b/storage/perfschema/unittest/pfs_instr-t.cc index 0daf38e5fc8..b0839de70b2 100644 --- a/storage/perfschema/unittest/pfs_instr-t.cc +++ b/storage/perfschema/unittest/pfs_instr-t.cc @@ -18,6 +18,7 @@ #include <pfs_instr.h> #include <pfs_stat.h> #include <pfs_global.h> +#include <pfs_instr_class.h> #include <tap.h> #include <memory.h> @@ -29,6 +30,7 @@ void test_no_instruments() int rc; PFS_global_param param; + memset(& param, 0xFF, sizeof(param)); param.m_enabled= true; param.m_mutex_class_sizing= 0; param.m_rwlock_class_sizing= 0; @@ -36,6 +38,7 @@ void test_no_instruments() param.m_thread_class_sizing= 0; param.m_table_share_sizing= 0; param.m_file_class_sizing= 0; + param.m_socket_class_sizing= 0; param.m_mutex_sizing= 0; param.m_rwlock_sizing= 0; param.m_cond_sizing= 0; @@ -43,9 +46,22 @@ void test_no_instruments() param.m_table_sizing= 0; param.m_file_sizing= 0; param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; param.m_events_waits_history_sizing= 0; param.m_events_waits_history_long_sizing= 0; - + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + init_event_name_sizing(& param); rc= init_instruments(& param); ok(rc == 0, "zero init"); @@ -61,14 +77,17 @@ void test_no_instances() PFS_thread_class dummy_thread_class; PFS_file_class dummy_file_class; PFS_table_share dummy_table_share; + PFS_socket_class dummy_socket_class; PFS_mutex *mutex; PFS_rwlock *rwlock; PFS_cond *cond; PFS_thread *thread; PFS_file *file; + PFS_socket *socket; PFS_table *table; PFS_global_param param; + memset(& param, 0xFF, sizeof(param)); param.m_enabled= true; param.m_mutex_class_sizing= 1; param.m_rwlock_class_sizing= 1; @@ -76,6 +95,7 @@ void test_no_instances() param.m_thread_class_sizing= 1; param.m_table_share_sizing= 1; param.m_file_class_sizing= 1; + param.m_socket_class_sizing= 0; param.m_mutex_sizing= 0; param.m_rwlock_sizing= 0; param.m_cond_sizing= 0; @@ -83,9 +103,22 @@ void test_no_instances() param.m_table_sizing= 0; param.m_file_sizing= 0; param.m_file_handle_sizing= 0; + param.m_socket_sizing= 0; param.m_events_waits_history_sizing= 0; param.m_events_waits_history_long_sizing= 0; - + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + init_event_name_sizing(& param); rc= init_instruments(& param); ok(rc == 0, "no instances init"); @@ -144,16 +177,23 @@ void test_no_instances() ok(file == NULL, "no file"); ok(file_lost == 5, "lost 5"); - table= create_table(& dummy_table_share, NULL); + table= create_table(& dummy_table_share, & fake_thread, NULL); ok(table == NULL, "no table"); ok(table_lost == 1, "lost 1"); - table= create_table(& dummy_table_share, NULL); + table= create_table(& dummy_table_share, & fake_thread, NULL); ok(table == NULL, "no table"); ok(table_lost == 2, "lost 2"); + socket= create_socket(& dummy_socket_class, NULL); + ok(socket == NULL, "no socket"); + ok(socket_lost == 1, "lost 1"); + socket= create_socket(& dummy_socket_class, NULL); + ok(socket == NULL, "no socket"); + ok(socket_lost == 2, "lost 2"); + /* No result to test, just make sure it does not crash */ reset_events_waits_by_instance(); - reset_per_thread_wait_stat(); + reset_events_waits_by_thread(); cleanup_file_hash(); cleanup_instruments(); @@ -167,6 +207,7 @@ void test_with_instances() PFS_cond_class dummy_cond_class; PFS_thread_class dummy_thread_class; PFS_file_class dummy_file_class; + PFS_socket_class dummy_socket_class; PFS_table_share dummy_table_share; PFS_mutex *mutex_1; PFS_mutex *mutex_2; @@ -178,10 +219,13 @@ void test_with_instances() PFS_thread *thread_2; PFS_file *file_1; PFS_file *file_2; + PFS_socket *socket_1; + PFS_socket *socket_2; PFS_table *table_1; PFS_table *table_2; PFS_global_param param; + memset(& param, 0xFF, sizeof(param)); param.m_enabled= true; param.m_mutex_class_sizing= 1; param.m_rwlock_class_sizing= 1; @@ -189,6 +233,7 @@ void test_with_instances() param.m_thread_class_sizing= 1; param.m_table_share_sizing= 1; param.m_file_class_sizing= 1; + param.m_socket_class_sizing= 1; param.m_mutex_sizing= 2; param.m_rwlock_sizing= 2; param.m_cond_sizing= 2; @@ -196,12 +241,31 @@ void test_with_instances() param.m_table_sizing= 2; param.m_file_sizing= 2; param.m_file_handle_sizing= 100; + param.m_socket_sizing= 2; param.m_events_waits_history_sizing= 10; param.m_events_waits_history_long_sizing= 10000; - + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 0; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 0; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 0; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + init_event_name_sizing(& param); rc= init_instruments(& param); ok(rc == 0, "instances init"); + dummy_mutex_class.m_event_name_index= 0; + dummy_rwlock_class.m_event_name_index= 1; + dummy_cond_class.m_event_name_index= 2; + dummy_file_class.m_event_name_index= 3; + dummy_socket_class.m_event_name_index= 4; + mutex_1= create_mutex(& dummy_mutex_class, NULL); ok(mutex_1 != NULL, "mutex"); ok(mutex_lost == 0, "not lost"); @@ -294,110 +358,42 @@ void test_with_instances() ok(file_2 == NULL, "no file"); ok(file_lost == 2, "lost"); - table_1= create_table(& dummy_table_share, NULL); + socket_1= create_socket(& dummy_socket_class, NULL); + ok(socket_1 != NULL, "socket"); + ok(socket_lost == 0, "not lost"); + socket_2= create_socket(& dummy_socket_class, NULL); + ok(socket_2 != NULL, "socket"); + ok(socket_lost == 0, "not lost"); + socket_2= create_socket(& dummy_socket_class, NULL); + ok(socket_2 == NULL, "no socket"); + ok(socket_lost == 1, "lost 1"); + destroy_socket(socket_1); + socket_2= create_socket(& dummy_socket_class, NULL); + ok(socket_2 != NULL, "socket"); + ok(socket_lost == 1, "no new loss"); + + table_1= create_table(& dummy_table_share, & fake_thread, NULL); ok(table_1 != NULL, "table"); ok(table_lost == 0, "not lost"); - table_2= create_table(& dummy_table_share, NULL); + table_2= create_table(& dummy_table_share, & fake_thread, NULL); ok(table_2 != NULL, "table"); ok(table_lost == 0, "not lost"); - table_2= create_table(& dummy_table_share, NULL); + table_2= create_table(& dummy_table_share, & fake_thread, NULL); ok(table_2 == NULL, "no table"); ok(table_lost == 1, "lost 1"); destroy_table(table_1); - table_2= create_table(& dummy_table_share, NULL); + table_2= create_table(& dummy_table_share, & fake_thread, NULL); ok(table_2 != NULL, "table"); ok(table_lost == 1, "no new loss"); //TODO: test that cleanup works reset_events_waits_by_instance(); - reset_per_thread_wait_stat(); + reset_events_waits_by_thread(); cleanup_file_hash(); cleanup_instruments(); } -void test_per_thread_wait() -{ - int rc; - PFS_mutex_class dummy_mutex_class; - PFS_rwlock_class dummy_rwlock_class; - PFS_cond_class dummy_cond_class; - PFS_thread_class dummy_thread_class; - PFS_file_class dummy_file_class; - PFS_thread *thread; - PFS_single_stat_chain *base; - PFS_single_stat_chain *stat; - PFS_global_param param; - - - /* Per mutex info waits should be at [0..9] */ - mutex_class_max= 10; - /* Per rwlock info waits should be at [10..29] */ - rwlock_class_max= 20; - /* Per cond info waits should be at [30..69] */ - cond_class_max= 40; - /* Per file info waits should be at [70..149] */ - file_class_max= 80; - /* Per table info waits should be at [150..309] */ - table_share_max= 160; - - param.m_enabled= true; - param.m_mutex_class_sizing= mutex_class_max; - param.m_rwlock_class_sizing= rwlock_class_max; - param.m_cond_class_sizing= cond_class_max; - param.m_thread_class_sizing= 2; - param.m_table_share_sizing= table_share_max; - param.m_file_class_sizing= file_class_max; - param.m_mutex_sizing= 0; - param.m_rwlock_sizing= 0; - param.m_cond_sizing= 0; - param.m_thread_sizing= 2; - param.m_table_sizing= 0; - param.m_file_sizing= 0; - param.m_file_handle_sizing= 0; - param.m_events_waits_history_sizing= 10; - param.m_events_waits_history_long_sizing= 10000; - - rc= init_instruments(& param); - ok(rc == 0, "instances init"); - - thread= create_thread(& dummy_thread_class, NULL, 0); - ok(thread != NULL, "thread"); - ok(thread_lost == 0, "not lost"); - - base= & thread->m_instr_class_wait_stats[0]; - - dummy_mutex_class.m_index= 0; - stat= find_per_thread_mutex_class_wait_stat(thread, & dummy_mutex_class); - ok(base + 0 == stat, "fist mutex info slot at 0"); - dummy_mutex_class.m_index= mutex_class_max - 1; - stat= find_per_thread_mutex_class_wait_stat(thread, & dummy_mutex_class); - ok(base + 9 == stat, "last mutex info slot at 9"); - - dummy_rwlock_class.m_index= 0; - stat= find_per_thread_rwlock_class_wait_stat(thread, & dummy_rwlock_class); - ok(base + 10 == stat, "fist rwlock info slot at 10"); - dummy_rwlock_class.m_index= rwlock_class_max - 1; - stat= find_per_thread_rwlock_class_wait_stat(thread, & dummy_rwlock_class); - ok(base + 29 == stat, "last rwlock info slot at 29"); - - dummy_cond_class.m_index= 0; - stat= find_per_thread_cond_class_wait_stat(thread, & dummy_cond_class); - ok(base + 30 == stat, "fist cond info slot at 30"); - dummy_cond_class.m_index= cond_class_max - 1; - stat= find_per_thread_cond_class_wait_stat(thread, & dummy_cond_class); - ok(base + 69 == stat, "last cond info slot at 69"); - - dummy_file_class.m_index= 0; - stat= find_per_thread_file_class_wait_stat(thread, & dummy_file_class); - ok(base + 70 == stat, "fist file info slot at 70"); - dummy_file_class.m_index= file_class_max - 1; - stat= find_per_thread_file_class_wait_stat(thread, & dummy_file_class); - ok(base + 149 == stat, "last file info slot at 149"); - - cleanup_instruments(); -} - void do_all_tests() { PFS_atomic::init(); @@ -405,14 +401,13 @@ void do_all_tests() test_no_instruments(); test_no_instances(); test_with_instances(); - test_per_thread_wait(); PFS_atomic::cleanup(); } int main(int argc, char **argv) { - plan(102); + plan(103); MY_INIT(argv[0]); do_all_tests(); my_end(0); diff --git a/storage/perfschema/unittest/pfs_instr_class-oom-t.cc b/storage/perfschema/unittest/pfs_instr_class-oom-t.cc index 49f229015b8..2de83e654c5 100644 --- a/storage/perfschema/unittest/pfs_instr_class-oom-t.cc +++ b/storage/perfschema/unittest/pfs_instr_class-oom-t.cc @@ -38,11 +38,20 @@ void test_oom() ok(rc == 1, "oom (file)"); rc= init_table_share(1000); ok(rc == 1, "oom (cond)"); + rc= init_socket_class(1000); + ok(rc == 1, "oom (socket)"); + rc= init_stage_class(1000); + ok(rc == 1, "oom (stage)"); + rc= init_statement_class(1000); + ok(rc == 1, "oom (statement)"); cleanup_sync_class(); cleanup_thread_class(); cleanup_file_class(); cleanup_table_share(); + cleanup_socket_class(); + cleanup_stage_class(); + cleanup_statement_class(); } void do_all_tests() @@ -56,11 +65,10 @@ void do_all_tests() int main(int argc, char **argv) { - plan(6); + plan(9); MY_INIT(argv[0]); do_all_tests(); my_end(0); return 0; } - diff --git a/storage/perfschema/unittest/pfs_instr_class-t.cc b/storage/perfschema/unittest/pfs_instr_class-t.cc index ea50f0647d9..9e3efde656e 100644 --- a/storage/perfschema/unittest/pfs_instr_class-t.cc +++ b/storage/perfschema/unittest/pfs_instr_class-t.cc @@ -29,12 +29,14 @@ void test_no_registration() PFS_sync_key key; PFS_thread_key thread_key; PFS_file_key file_key; + PFS_socket_key socket_key; PFS_mutex_class *mutex; PFS_rwlock_class *rwlock; PFS_cond_class *cond; PFS_thread_class *thread; PFS_file_class *file; - PFS_table_share *table; + PFS_socket_class *socket; + /* PFS_table_share *table; */ rc= init_sync_class(0, 0, 0); ok(rc == 0, "zero init (sync)"); @@ -42,6 +44,8 @@ void test_no_registration() ok(rc == 0, "zero init (thread)"); rc= init_file_class(0); ok(rc == 0, "zero init (file)"); + rc= init_socket_class(0); + ok(rc == 0, "zero init (socket)"); rc= init_table_share(0); ok(rc == 0, "zero init (table)"); @@ -80,15 +84,24 @@ void test_no_registration() file_key= register_file_class("FOO", 3, 0); ok(file_key == 0, "no file registered"); + socket_key= register_socket_class("FOO", 3, 0); + ok(socket_key == 0, "no socket registered"); + socket_key= register_socket_class("BAR", 3, 0); + ok(socket_key == 0, "no socket registered"); + socket_key= register_socket_class("FOO", 3, 0); + ok(socket_key == 0, "no socket registered"); + +#ifdef LATER PFS_thread fake_thread; fake_thread.m_table_share_hash_pins= NULL; - table= find_or_create_table_share(& fake_thread, "foo_db", 6, "foo_table", 9); + table= find_or_create_table_share(& fake_thread, false, "foo_db", 6, "foo_table", 9); ok(table == NULL, "not created"); - table= find_or_create_table_share(& fake_thread, "bar_db", 6, "bar_table", 9); + table= find_or_create_table_share(& fake_thread, false, "bar_db", 6, "bar_table", 9); ok(table == NULL, "not created"); - table= find_or_create_table_share(& fake_thread, "foo_db", 6, "foo_table", 9); + table= find_or_create_table_share(& fake_thread, false, "foo_db", 6, "foo_table", 9); ok(table == NULL, "not created"); +#endif mutex= find_mutex_class(0); ok(mutex == NULL, "no mutex key 0"); @@ -125,9 +138,17 @@ void test_no_registration() file= find_file_class(9999); ok(file == NULL, "no file key 9999"); + socket= find_socket_class(0); + ok(socket == NULL, "no socket key 0"); + socket= find_socket_class(1); + ok(socket == NULL, "no socket key 1"); + socket= find_socket_class(9999); + ok(socket == NULL, "no socket key 9999"); + cleanup_sync_class(); cleanup_thread_class(); cleanup_file_class(); + cleanup_socket_class(); cleanup_table_share(); } @@ -346,8 +367,56 @@ void test_file_registration() cleanup_file_class(); } +void test_socket_registration() +{ + int rc; + PFS_socket_key key; + PFS_socket_class *socket; + + rc= init_socket_class(5); + ok(rc == 0, "room for 5 socket"); + + key= register_socket_class("FOO", 3, 0); + ok(key == 1, "foo registered"); + key= register_socket_class("BAR", 3, 0); + ok(key == 2, "bar registered"); + key= register_socket_class("FOO", 3, 0); + ok(key == 1, "foo re registered"); + key= register_socket_class("Socket-3", 8, 0); + ok(key == 3, "Socket-3 registered"); + key= register_socket_class("Socket-4", 8, 0); + ok(key == 4, "Socket-4 registered"); + key= register_socket_class("Socket-5", 8, 0); + ok(key == 5, "Socket-5 registered"); + ok(socket_class_lost == 0, "lost nothing"); + key= register_socket_class("Socket-6", 8, 0); + ok(key == 0, "Socket-6 not registered"); + ok(socket_class_lost == 1, "lost 1 socket"); + key= register_socket_class("Socket-7", 8, 0); + ok(key == 0, "Socket-7 not registered"); + ok(socket_class_lost == 2, "lost 2 socket"); + key= register_socket_class("Socket-3", 8, 0); + ok(key == 3, "Socket-3 re registered"); + ok(socket_class_lost == 2, "lost 2 socket"); + key= register_socket_class("Socket-5", 8, 0); + ok(key == 5, "Socket-5 re registered"); + ok(socket_class_lost == 2, "lost 2 socket"); + + socket= find_socket_class(0); + ok(socket == NULL, "no key 0"); + socket= find_socket_class(3); + ok(socket != NULL, "found key 3"); + ok(strncmp(socket->m_name, "Socket-3", 8) == 0, "key 3 is Socket-3"); + ok(socket->m_name_length == 8, "name length 3"); + socket= find_socket_class(9999); + ok(socket == NULL, "no key 9999"); + + cleanup_socket_class(); +} + void test_table_registration() { +#ifdef LATER PFS_table_share *table_share; PFS_table_share *table_share_2; @@ -355,7 +424,7 @@ void test_table_registration() fake_thread.m_table_share_hash_pins= NULL; table_share_lost= 0; - table_share= find_or_create_table_share(& fake_thread, "db1", 3, "t1", 2); + table_share= find_or_create_table_share(& fake_thread, false, "db1", 3, "t1", 2); ok(table_share == NULL, "not created"); ok(table_share_lost == 1, "lost the table"); @@ -363,37 +432,37 @@ void test_table_registration() init_table_share(5); init_table_share_hash(); - table_share= find_or_create_table_share(& fake_thread, "db1", 3, "t1", 2); + table_share= find_or_create_table_share(& fake_thread, false, "db1", 3, "t1", 2); ok(table_share != NULL, "created db1.t1"); ok(table_share_lost == 0, "not lost"); - table_share_2= find_or_create_table_share(& fake_thread, "db1", 3, "t1", 2); + table_share_2= find_or_create_table_share(& fake_thread, false, "db1", 3, "t1", 2); ok(table_share_2 != NULL, "found db1.t1"); ok(table_share_lost == 0, "not lost"); ok(table_share == table_share_2, "same table"); - table_share_2= find_or_create_table_share(& fake_thread, "db1", 3, "t2", 2); + table_share_2= find_or_create_table_share(& fake_thread, false, "db1", 3, "t2", 2); ok(table_share_2 != NULL, "created db1.t2"); ok(table_share_lost == 0, "not lost"); - table_share_2= find_or_create_table_share(& fake_thread, "db2", 3, "t1", 2); + table_share_2= find_or_create_table_share(& fake_thread, false, "db2", 3, "t1", 2); ok(table_share_2 != NULL, "created db2.t1"); ok(table_share_lost == 0, "not lost"); - table_share_2= find_or_create_table_share(& fake_thread, "db2", 3, "t2", 2); + table_share_2= find_or_create_table_share(& fake_thread, false, "db2", 3, "t2", 2); ok(table_share_2 != NULL, "created db2.t2"); ok(table_share_lost == 0, "not lost"); - table_share_2= find_or_create_table_share(& fake_thread, "db3", 3, "t3", 2); + table_share_2= find_or_create_table_share(& fake_thread, false, "db3", 3, "t3", 2); ok(table_share_2 != NULL, "created db3.t3"); ok(table_share_lost == 0, "not lost"); - table_share_2= find_or_create_table_share(& fake_thread, "db4", 3, "t4", 2); + table_share_2= find_or_create_table_share(& fake_thread, false, "db4", 3, "t4", 2); ok(table_share_2 == NULL, "lost db4.t4"); ok(table_share_lost == 1, "lost"); table_share_lost= 0; - table_share_2= find_or_create_table_share(& fake_thread, "db1", 3, "t2", 2); + table_share_2= find_or_create_table_share(& fake_thread, false, "db1", 3, "t2", 2); ok(table_share_2 != NULL, "found db1.t2"); ok(table_share_lost == 0, "not lost"); ok(strncmp(table_share_2->m_schema_name, "db1", 3) == 0 , "schema db1"); @@ -403,18 +472,25 @@ void test_table_registration() cleanup_table_share_hash(); cleanup_table_share(); +#endif } -void set_wait_stat(PFS_single_stat_chain *stat) +void set_wait_stat(PFS_instr_class *klass) { + PFS_single_stat *stat; + stat= & global_instr_class_waits_array[klass->m_event_name_index]; + stat->m_count= 12; stat->m_min= 5; stat->m_max= 120; stat->m_sum= 999; } -bool is_empty_stat(PFS_single_stat_chain *stat) +bool is_empty_stat(PFS_instr_class *klass) { + PFS_single_stat *stat; + stat= & global_instr_class_waits_array[klass->m_event_name_index]; + if (stat->m_count != 0) return false; if (stat->m_min != (ulonglong) -1) @@ -431,6 +507,7 @@ void test_instruments_reset() int rc; PFS_sync_key key; PFS_file_key file_key; + PFS_socket_key socket_key; PFS_mutex_class *mutex_1; PFS_mutex_class *mutex_2; PFS_mutex_class *mutex_3; @@ -443,6 +520,9 @@ void test_instruments_reset() PFS_file_class *file_1; PFS_file_class *file_2; PFS_file_class *file_3; + PFS_socket_class *socket_1; + PFS_socket_class *socket_2; + PFS_socket_class *socket_3; rc= init_sync_class(3, 3, 3); ok(rc == 0, "init (sync)"); @@ -450,6 +530,8 @@ void test_instruments_reset() ok(rc == 0, "init (thread)"); rc= init_file_class(3); ok(rc == 0, "init (file)"); + rc= init_socket_class(3); + ok(rc == 0, "init (socket)"); key= register_mutex_class("M-1", 3, 0); ok(key == 1, "mutex registered"); @@ -479,6 +561,13 @@ void test_instruments_reset() file_key= register_file_class("F-3", 3, 0); ok(file_key == 3, "file registered"); + socket_key= register_socket_class("S-1", 3, 0); + ok(socket_key == 1, "socket registered"); + socket_key= register_socket_class("S-2", 3, 0); + ok(socket_key == 2, "socket registered"); + socket_key= register_socket_class("S-3", 3, 0); + ok(socket_key == 3, "socket registered"); + mutex_1= find_mutex_class(1); ok(mutex_1 != NULL, "mutex key 1"); mutex_2= find_mutex_class(2); @@ -507,49 +596,59 @@ void test_instruments_reset() file_3= find_file_class(3); ok(file_3 != NULL, "file key 3"); - set_wait_stat(& mutex_1->m_wait_stat); - set_wait_stat(& mutex_2->m_wait_stat); - set_wait_stat(& mutex_3->m_wait_stat); - set_wait_stat(& rwlock_1->m_wait_stat); - set_wait_stat(& rwlock_2->m_wait_stat); - set_wait_stat(& rwlock_3->m_wait_stat); - set_wait_stat(& cond_1->m_wait_stat); - set_wait_stat(& cond_2->m_wait_stat); - set_wait_stat(& cond_3->m_wait_stat); - set_wait_stat(& file_1->m_wait_stat); - set_wait_stat(& file_2->m_wait_stat); - set_wait_stat(& file_3->m_wait_stat); - - ok(! is_empty_stat(& mutex_1->m_wait_stat), "mutex_1 stat is populated"); - ok(! is_empty_stat(& mutex_2->m_wait_stat), "mutex_2 stat is populated"); - ok(! is_empty_stat(& mutex_3->m_wait_stat), "mutex_3 stat is populated"); - ok(! is_empty_stat(& rwlock_1->m_wait_stat), "rwlock_1 stat is populated"); - ok(! is_empty_stat(& rwlock_2->m_wait_stat), "rwlock_2 stat is populated"); - ok(! is_empty_stat(& rwlock_3->m_wait_stat), "rwlock_3 stat is populated"); - ok(! is_empty_stat(& cond_1->m_wait_stat), "cond_1 stat is populated"); - ok(! is_empty_stat(& cond_2->m_wait_stat), "cond_2 stat is populated"); - ok(! is_empty_stat(& cond_3->m_wait_stat), "cond_3 stat is populated"); - ok(! is_empty_stat(& file_1->m_wait_stat), "file_1 stat is populated"); - ok(! is_empty_stat(& file_2->m_wait_stat), "file_2 stat is populated"); - ok(! is_empty_stat(& file_3->m_wait_stat), "file_3 stat is populated"); - - reset_instrument_class_waits(); - - ok(is_empty_stat(& mutex_1->m_wait_stat), "mutex_1 stat is cleared"); - ok(is_empty_stat(& mutex_2->m_wait_stat), "mutex_2 stat is cleared"); - ok(is_empty_stat(& mutex_3->m_wait_stat), "mutex_3 stat is cleared"); - ok(is_empty_stat(& rwlock_1->m_wait_stat), "rwlock_1 stat is cleared"); - ok(is_empty_stat(& rwlock_2->m_wait_stat), "rwlock_2 stat is cleared"); - ok(is_empty_stat(& rwlock_3->m_wait_stat), "rwlock_3 stat is cleared"); - ok(is_empty_stat(& cond_1->m_wait_stat), "cond_1 stat is cleared"); - ok(is_empty_stat(& cond_2->m_wait_stat), "cond_2 stat is cleared"); - ok(is_empty_stat(& cond_3->m_wait_stat), "cond_3 stat is cleared"); - ok(is_empty_stat(& file_1->m_wait_stat), "file_1 stat is cleared"); - ok(is_empty_stat(& file_2->m_wait_stat), "file_2 stat is cleared"); - ok(is_empty_stat(& file_3->m_wait_stat), "file_3 stat is cleared"); + socket_1= find_socket_class(1); + ok(socket_1 != NULL, "socket key 1"); + socket_2= find_socket_class(2); + ok(socket_2 != NULL, "socket key 2"); + socket_3= find_socket_class(3); + ok(socket_3 != NULL, "socket key 3"); + +#ifdef LATER + set_wait_stat(mutex_1); + set_wait_stat(mutex_2); + set_wait_stat(mutex_3); + set_wait_stat(rwlock_1); + set_wait_stat(rwlock_2); + set_wait_stat(rwlock_3); + set_wait_stat(cond_1); + set_wait_stat(cond_2); + set_wait_stat(cond_3); + set_wait_stat(file_1); + set_wait_stat(file_2); + set_wait_stat(file_3); + + ok(! is_empty_stat(mutex_1), "mutex_1 stat is populated"); + ok(! is_empty_stat(mutex_2), "mutex_2 stat is populated"); + ok(! is_empty_stat(mutex_3), "mutex_3 stat is populated"); + ok(! is_empty_stat(rwlock_1), "rwlock_1 stat is populated"); + ok(! is_empty_stat(rwlock_2), "rwlock_2 stat is populated"); + ok(! is_empty_stat(rwlock_3), "rwlock_3 stat is populated"); + ok(! is_empty_stat(cond_1), "cond_1 stat is populated"); + ok(! is_empty_stat(cond_2), "cond_2 stat is populated"); + ok(! is_empty_stat(cond_3), "cond_3 stat is populated"); + ok(! is_empty_stat(file_1), "file_1 stat is populated"); + ok(! is_empty_stat(file_2), "file_2 stat is populated"); + ok(! is_empty_stat(file_3), "file_3 stat is populated"); + + reset_global_wait_stat(); + + ok(is_empty_stat(mutex_1), "mutex_1 stat is cleared"); + ok(is_empty_stat(mutex_2), "mutex_2 stat is cleared"); + ok(is_empty_stat(mutex_3), "mutex_3 stat is cleared"); + ok(is_empty_stat(rwlock_1), "rwlock_1 stat is cleared"); + ok(is_empty_stat(rwlock_2), "rwlock_2 stat is cleared"); + ok(is_empty_stat(rwlock_3), "rwlock_3 stat is cleared"); + ok(is_empty_stat(cond_1), "cond_1 stat is cleared"); + ok(is_empty_stat(cond_2), "cond_2 stat is cleared"); + ok(is_empty_stat(cond_3), "cond_3 stat is cleared"); + ok(is_empty_stat(file_1), "file_1 stat is cleared"); + ok(is_empty_stat(file_2), "file_2 stat is cleared"); + ok(is_empty_stat(file_3), "file_3 stat is cleared"); +#endif cleanup_sync_class(); cleanup_file_class(); + cleanup_socket_class(); } void do_all_tests() @@ -562,6 +661,7 @@ void do_all_tests() test_cond_registration(); test_thread_registration(); test_file_registration(); + test_socket_registration(); test_table_registration(); test_instruments_reset(); @@ -570,11 +670,9 @@ void do_all_tests() int main(int argc, char **argv) { - plan(196); + plan(181); MY_INIT(argv[0]); do_all_tests(); my_end(0); return 0; } - - diff --git a/storage/perfschema/unittest/pfs_timer-t.cc b/storage/perfschema/unittest/pfs_timer-t.cc index 9a1c743f642..9c9ae0f75f1 100644 --- a/storage/perfschema/unittest/pfs_timer-t.cc +++ b/storage/perfschema/unittest/pfs_timer-t.cc @@ -34,26 +34,26 @@ void test_timers() init_timers(); - t1_a= get_timer_value(TIMER_NAME_CYCLE); + t1_a= get_timer_pico_value(TIMER_NAME_CYCLE); /* Wait 5 seconds */ my_sleep(5000000); - t1_b= get_timer_value(TIMER_NAME_CYCLE); + t1_b= get_timer_pico_value(TIMER_NAME_CYCLE); - t2_a= get_timer_value(TIMER_NAME_NANOSEC); + t2_a= get_timer_pico_value(TIMER_NAME_NANOSEC); my_sleep(5000000); - t2_b= get_timer_value(TIMER_NAME_NANOSEC); + t2_b= get_timer_pico_value(TIMER_NAME_NANOSEC); - t3_a= get_timer_value(TIMER_NAME_MICROSEC); + t3_a= get_timer_pico_value(TIMER_NAME_MICROSEC); my_sleep(5000000); - t3_b= get_timer_value(TIMER_NAME_MICROSEC); + t3_b= get_timer_pico_value(TIMER_NAME_MICROSEC); - t4_a= get_timer_value(TIMER_NAME_MILLISEC); + t4_a= get_timer_pico_value(TIMER_NAME_MILLISEC); my_sleep(5000000); - t4_b= get_timer_value(TIMER_NAME_MILLISEC); + t4_b= get_timer_pico_value(TIMER_NAME_MILLISEC); - t5_a= get_timer_value(TIMER_NAME_TICK); + t5_a= get_timer_pico_value(TIMER_NAME_TICK); my_sleep(5000000); - t5_b= get_timer_value(TIMER_NAME_TICK); + t5_b= get_timer_pico_value(TIMER_NAME_TICK); /* Print the timer values, for manual inspection by a human. diff --git a/storage/perfschema/unittest/pfs_user-oom-t.cc b/storage/perfschema/unittest/pfs_user-oom-t.cc new file mode 100644 index 00000000000..1faf29b753a --- /dev/null +++ b/storage/perfschema/unittest/pfs_user-oom-t.cc @@ -0,0 +1,116 @@ +/* Copyright (c) 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 + 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, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_pthread.h> +#include <pfs_instr.h> +#include <pfs_stat.h> +#include <pfs_global.h> +#include <pfs_user.h> +#include <tap.h> + +#include "stub_pfs_global.h" +#include "stub_server_misc.h" + +#include <string.h> /* memset */ + +void test_oom() +{ + int rc; + PFS_global_param param; + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 0; + param.m_rwlock_class_sizing= 0; + param.m_cond_class_sizing= 0; + param.m_thread_class_sizing= 10; + param.m_table_share_sizing= 0; + param.m_file_class_sizing= 0; + param.m_mutex_sizing= 0; + param.m_rwlock_sizing= 0; + param.m_cond_sizing= 0; + param.m_thread_sizing= 1000; + param.m_table_sizing= 0; + param.m_file_sizing= 0; + param.m_file_handle_sizing= 0; + param.m_events_waits_history_sizing= 10; + param.m_events_waits_history_long_sizing= 0; + param.m_setup_actor_sizing= 0; + param.m_setup_object_sizing= 0; + param.m_host_sizing= 0; + param.m_user_sizing= 1000; + param.m_account_sizing= 0; + param.m_stage_class_sizing= 50; + param.m_events_stages_history_sizing= 0; + param.m_events_stages_history_long_sizing= 0; + param.m_statement_class_sizing= 50; + param.m_events_statements_history_sizing= 0; + param.m_events_statements_history_long_sizing= 0; + + /* Setup */ + + stub_alloc_always_fails= false; + stub_alloc_fails_after_count= 1000; + + init_event_name_sizing(& param); + rc= init_stage_class(param.m_stage_class_sizing); + ok(rc == 0, "init stage class"); + rc= init_statement_class(param.m_statement_class_sizing); + ok(rc == 0, "init statement class"); + + /* Tests */ + + stub_alloc_fails_after_count= 1; + rc= init_user(& param); + ok(rc == 1, "oom (user)"); + cleanup_user(); + + stub_alloc_fails_after_count= 2; + rc= init_user(& param); + ok(rc == 1, "oom (user waits)"); + cleanup_user(); + + stub_alloc_fails_after_count= 3; + rc= init_user(& param); + ok(rc == 1, "oom (user stages)"); + cleanup_user(); + + stub_alloc_fails_after_count= 4; + rc= init_user(& param); + ok(rc == 1, "oom (user statements)"); + cleanup_user(); + + cleanup_statement_class(); + cleanup_stage_class(); +} + +void do_all_tests() +{ + PFS_atomic::init(); + + test_oom(); + + PFS_atomic::cleanup(); +} + +int main(int, char **) +{ + plan(6); + MY_INIT("pfs_user-oom-t"); + do_all_tests(); + return 0; +} + diff --git a/storage/perfschema/unittest/stub_pfs_defaults.h b/storage/perfschema/unittest/stub_pfs_defaults.h new file mode 100644 index 00000000000..042d069b367 --- /dev/null +++ b/storage/perfschema/unittest/stub_pfs_defaults.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2010, 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 + 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 */ + +#include <my_global.h> +#include <pfs.h> +#include <pfs_defaults.h> + +void install_default_setup(PSI_bootstrap *) +{ +} + diff --git a/storage/perfschema/unittest/stub_pfs_global.h b/storage/perfschema/unittest/stub_pfs_global.h index 2b581f22645..34c52e18b5a 100644 --- a/storage/perfschema/unittest/stub_pfs_global.h +++ b/storage/perfschema/unittest/stub_pfs_global.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc. - Use is subject to license terms. +/* Copyright (c) 2008, 2010, 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 @@ -17,26 +16,34 @@ #include <my_global.h> #include <my_sys.h> #include <pfs_global.h> +#include <string.h> bool pfs_initialized= false; bool stub_alloc_always_fails= true; int stub_alloc_fails_after_count= 0; -void *pfs_malloc(size_t, myf) +void *pfs_malloc(size_t size, myf) { - static char garbage[100]; - if (stub_alloc_always_fails) return NULL; if (--stub_alloc_fails_after_count <= 0) return NULL; - return garbage; + void *ptr= malloc(size); + if (ptr != NULL) + memset(ptr, 0, size); + return ptr; +} + +void pfs_free(void *ptr) +{ + if (ptr != NULL) + free(ptr); } -void pfs_free(void *) +void pfs_print_error(const char *format, ...) { } diff --git a/storage/perfschema/unittest/stub_print_error.h b/storage/perfschema/unittest/stub_print_error.h index adfa3a62d8c..caad24e5257 100644 --- a/storage/perfschema/unittest/stub_print_error.h +++ b/storage/perfschema/unittest/stub_print_error.h @@ -1,5 +1,4 @@ -/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc. - Use is subject to license terms. +/* Copyright (c) 2008, 2010, 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 diff --git a/storage/perfschema/unittest/stub_server_misc.h b/storage/perfschema/unittest/stub_server_misc.h index 17beadbb104..8b008273bd8 100644 --- a/storage/perfschema/unittest/stub_server_misc.h +++ b/storage/perfschema/unittest/stub_server_misc.h @@ -19,3 +19,10 @@ volatile bool ready_to_exit= false; +uint lower_case_table_names= 0; +CHARSET_INFO *files_charset_info= NULL; + +extern "C" void compute_md5_hash(char *, const char *, int) +{ +} + |