summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2014-05-06 23:20:50 +0200
committerSergei Golubchik <sergii@pisem.net>2014-05-06 23:20:50 +0200
commitd74414399d8a5a944b47eff95e0796c56c3428a3 (patch)
tree7daccc9917352d383662de6d3af4b456bb341a50 /storage
downloadmariadb-git-d74414399d8a5a944b47eff95e0796c56c3428a3.tar.gz
perfschema 5.6.10 initial commit.
10.0 files
Diffstat (limited to 'storage')
-rw-r--r--storage/perfschema/CMakeLists.txt207
-rw-r--r--storage/perfschema/cursor_by_account.cc72
-rw-r--r--storage/perfschema/cursor_by_account.h59
-rw-r--r--storage/perfschema/cursor_by_host.cc72
-rw-r--r--storage/perfschema/cursor_by_host.h59
-rw-r--r--storage/perfschema/cursor_by_thread.cc72
-rw-r--r--storage/perfschema/cursor_by_thread.h59
-rw-r--r--storage/perfschema/cursor_by_thread_connect_attr.cc71
-rw-r--r--storage/perfschema/cursor_by_thread_connect_attr.h81
-rw-r--r--storage/perfschema/cursor_by_user.cc72
-rw-r--r--storage/perfschema/cursor_by_user.h59
-rw-r--r--storage/perfschema/gen_pfs_lex_token.cc265
-rw-r--r--storage/perfschema/ha_perfschema.cc470
-rw-r--r--storage/perfschema/ha_perfschema.h212
-rw-r--r--storage/perfschema/pfs.cc5223
-rw-r--r--storage/perfschema/pfs.h41
-rw-r--r--storage/perfschema/pfs_account.cc576
-rw-r--r--storage/perfschema/pfs_account.h122
-rw-r--r--storage/perfschema/pfs_atomic.cc78
-rw-r--r--storage/perfschema/pfs_atomic.h249
-rw-r--r--storage/perfschema/pfs_autosize.cc366
-rw-r--r--storage/perfschema/pfs_check.cc63
-rw-r--r--storage/perfschema/pfs_column_types.h222
-rw-r--r--storage/perfschema/pfs_column_values.cc50
-rw-r--r--storage/perfschema/pfs_column_values.h47
-rw-r--r--storage/perfschema/pfs_con_slice.cc116
-rw-r--r--storage/perfschema/pfs_con_slice.h103
-rw-r--r--storage/perfschema/pfs_defaults.cc63
-rw-r--r--storage/perfschema/pfs_defaults.h32
-rw-r--r--storage/perfschema/pfs_digest.cc728
-rw-r--r--storage/perfschema/pfs_digest.h219
-rw-r--r--storage/perfschema/pfs_engine_table.cc1447
-rw-r--r--storage/perfschema/pfs_engine_table.h465
-rw-r--r--storage/perfschema/pfs_events.h62
-rw-r--r--storage/perfschema/pfs_events_stages.cc238
-rw-r--r--storage/perfschema/pfs_events_stages.h65
-rw-r--r--storage/perfschema/pfs_events_statements.cc242
-rw-r--r--storage/perfschema/pfs_events_statements.h123
-rw-r--r--storage/perfschema/pfs_events_waits.cc304
-rw-r--r--storage/perfschema/pfs_events_waits.h146
-rw-r--r--storage/perfschema/pfs_global.cc186
-rw-r--r--storage/perfschema/pfs_global.h138
-rw-r--r--storage/perfschema/pfs_host.cc383
-rw-r--r--storage/perfschema/pfs_host.h112
-rw-r--r--storage/perfschema/pfs_instr.cc2187
-rw-r--r--storage/perfschema/pfs_instr.h637
-rw-r--r--storage/perfschema/pfs_instr_class.cc1475
-rw-r--r--storage/perfschema/pfs_instr_class.h504
-rw-r--r--storage/perfschema/pfs_lock.h240
-rw-r--r--storage/perfschema/pfs_server.cc299
-rw-r--r--storage/perfschema/pfs_server.h249
-rw-r--r--storage/perfschema/pfs_setup_actor.cc337
-rw-r--r--storage/perfschema/pfs_setup_actor.h99
-rw-r--r--storage/perfschema/pfs_setup_object.cc345
-rw-r--r--storage/perfschema/pfs_setup_object.h103
-rw-r--r--storage/perfschema/pfs_stat.h706
-rw-r--r--storage/perfschema/pfs_timer.cc299
-rw-r--r--storage/perfschema/pfs_timer.h140
-rw-r--r--storage/perfschema/pfs_user.cc384
-rw-r--r--storage/perfschema/pfs_user.h115
-rw-r--r--storage/perfschema/pfs_visitor.cc1154
-rw-r--r--storage/perfschema/pfs_visitor.h568
-rw-r--r--storage/perfschema/table_accounts.cc148
-rw-r--r--storage/perfschema/table_accounts.h80
-rw-r--r--storage/perfschema/table_all_instr.cc175
-rw-r--r--storage/perfschema/table_all_instr.h115
-rw-r--r--storage/perfschema/table_esgs_by_account_by_event_name.cc233
-rw-r--r--storage/perfschema/table_esgs_by_account_by_event_name.h125
-rw-r--r--storage/perfschema/table_esgs_by_host_by_event_name.cc229
-rw-r--r--storage/perfschema/table_esgs_by_host_by_event_name.h125
-rw-r--r--storage/perfschema/table_esgs_by_thread_by_event_name.cc229
-rw-r--r--storage/perfschema/table_esgs_by_thread_by_event_name.h129
-rw-r--r--storage/perfschema/table_esgs_by_user_by_event_name.cc229
-rw-r--r--storage/perfschema/table_esgs_by_user_by_event_name.h130
-rw-r--r--storage/perfschema/table_esgs_global_by_event_name.cc207
-rw-r--r--storage/perfschema/table_esgs_global_by_event_name.h93
-rw-r--r--storage/perfschema/table_esms_by_account_by_event_name.cc328
-rw-r--r--storage/perfschema/table_esms_by_account_by_event_name.h125
-rw-r--r--storage/perfschema/table_esms_by_digest.cc331
-rw-r--r--storage/perfschema/table_esms_by_digest.h95
-rw-r--r--storage/perfschema/table_esms_by_host_by_event_name.cc324
-rw-r--r--storage/perfschema/table_esms_by_host_by_event_name.h125
-rw-r--r--storage/perfschema/table_esms_by_thread_by_event_name.cc325
-rw-r--r--storage/perfschema/table_esms_by_thread_by_event_name.h129
-rw-r--r--storage/perfschema/table_esms_by_user_by_event_name.cc324
-rw-r--r--storage/perfschema/table_esms_by_user_by_event_name.h125
-rw-r--r--storage/perfschema/table_esms_global_by_event_name.cc302
-rw-r--r--storage/perfschema/table_esms_global_by_event_name.h93
-rw-r--r--storage/perfschema/table_events_stages.cc523
-rw-r--r--storage/perfschema/table_events_stages.h212
-rw-r--r--storage/perfschema/table_events_statements.cc886
-rw-r--r--storage/perfschema/table_events_statements.h288
-rw-r--r--storage/perfschema/table_events_waits.cc1035
-rw-r--r--storage/perfschema/table_events_waits.h259
-rw-r--r--storage/perfschema/table_events_waits_summary.cc265
-rw-r--r--storage/perfschema/table_events_waits_summary.h92
-rw-r--r--storage/perfschema/table_ews_by_account_by_event_name.cc288
-rw-r--r--storage/perfschema/table_ews_by_account_by_event_name.h136
-rw-r--r--storage/perfschema/table_ews_by_host_by_event_name.cc285
-rw-r--r--storage/perfschema/table_ews_by_host_by_event_name.h136
-rw-r--r--storage/perfschema/table_ews_by_thread_by_event_name.cc299
-rw-r--r--storage/perfschema/table_ews_by_thread_by_event_name.h135
-rw-r--r--storage/perfschema/table_ews_by_user_by_event_name.cc285
-rw-r--r--storage/perfschema/table_ews_by_user_by_event_name.h136
-rw-r--r--storage/perfschema/table_ews_global_by_event_name.cc417
-rw-r--r--storage/perfschema/table_ews_global_by_event_name.h128
-rw-r--r--storage/perfschema/table_file_instances.cc182
-rw-r--r--storage/perfschema/table_file_instances.h90
-rw-r--r--storage/perfschema/table_file_summary_by_event_name.cc352
-rw-r--r--storage/perfschema/table_file_summary_by_event_name.h91
-rw-r--r--storage/perfschema/table_file_summary_by_instance.cc381
-rw-r--r--storage/perfschema/table_file_summary_by_instance.h99
-rw-r--r--storage/perfschema/table_helper.cc351
-rw-r--r--storage/perfschema/table_helper.h522
-rw-r--r--storage/perfschema/table_host_cache.cc478
-rw-r--r--storage/perfschema/table_host_cache.h144
-rw-r--r--storage/perfschema/table_hosts.cc147
-rw-r--r--storage/perfschema/table_hosts.h80
-rw-r--r--storage/perfschema/table_os_global_by_type.cc275
-rw-r--r--storage/perfschema/table_os_global_by_type.h130
-rw-r--r--storage/perfschema/table_performance_timers.cc189
-rw-r--r--storage/perfschema/table_performance_timers.h86
-rw-r--r--storage/perfschema/table_session_account_connect_attrs.cc70
-rw-r--r--storage/perfschema/table_session_account_connect_attrs.h50
-rw-r--r--storage/perfschema/table_session_connect.cc268
-rw-r--r--storage/perfschema/table_session_connect.h77
-rw-r--r--storage/perfschema/table_session_connect_attrs.cc43
-rw-r--r--storage/perfschema/table_session_connect_attrs.h47
-rw-r--r--storage/perfschema/table_setup_actors.cc279
-rw-r--r--storage/perfschema/table_setup_actors.h106
-rw-r--r--storage/perfschema/table_setup_consumers.cc244
-rw-r--r--storage/perfschema/table_setup_consumers.h87
-rw-r--r--storage/perfschema/table_setup_instruments.cc306
-rw-r--r--storage/perfschema/table_setup_instruments.h121
-rw-r--r--storage/perfschema/table_setup_objects.cc355
-rw-r--r--storage/perfschema/table_setup_objects.h109
-rw-r--r--storage/perfschema/table_setup_timers.cc197
-rw-r--r--storage/perfschema/table_setup_timers.h85
-rw-r--r--storage/perfschema/table_socket_instances.cc232
-rw-r--r--storage/perfschema/table_socket_instances.h102
-rw-r--r--storage/perfschema/table_socket_summary_by_event_name.cc348
-rw-r--r--storage/perfschema/table_socket_summary_by_event_name.h92
-rw-r--r--storage/perfschema/table_socket_summary_by_instance.cc369
-rw-r--r--storage/perfschema/table_socket_summary_by_instance.h95
-rw-r--r--storage/perfschema/table_sync_instances.cc511
-rw-r--r--storage/perfschema/table_sync_instances.h206
-rw-r--r--storage/perfschema/table_threads.cc350
-rw-r--r--storage/perfschema/table_threads.h115
-rw-r--r--storage/perfschema/table_tiws_by_index_usage.cc499
-rw-r--r--storage/perfschema/table_tiws_by_index_usage.h123
-rw-r--r--storage/perfschema/table_tiws_by_table.cc473
-rw-r--r--storage/perfschema/table_tiws_by_table.h93
-rw-r--r--storage/perfschema/table_tlws_by_table.cc765
-rw-r--r--storage/perfschema/table_tlws_by_table.h93
-rw-r--r--storage/perfschema/table_users.cc147
-rw-r--r--storage/perfschema/table_users.h80
-rw-r--r--storage/perfschema/unittest/CMakeLists.txt70
-rw-r--r--storage/perfschema/unittest/conf.txt420
-rw-r--r--storage/perfschema/unittest/pfs-t.cc1645
-rw-r--r--storage/perfschema/unittest/pfs_account-oom-t.cc117
-rw-r--r--storage/perfschema/unittest/pfs_connect_attr-t.cc345
-rw-r--r--storage/perfschema/unittest/pfs_host-oom-t.cc117
-rw-r--r--storage/perfschema/unittest/pfs_instr-oom-t.cc671
-rw-r--r--storage/perfschema/unittest/pfs_instr-t.cc421
-rw-r--r--storage/perfschema/unittest/pfs_instr_class-oom-t.cc73
-rw-r--r--storage/perfschema/unittest/pfs_instr_class-t.cc680
-rw-r--r--storage/perfschema/unittest/pfs_timer-t.cc122
-rw-r--r--storage/perfschema/unittest/pfs_user-oom-t.cc116
-rw-r--r--storage/perfschema/unittest/stub_pfs_defaults.h23
-rw-r--r--storage/perfschema/unittest/stub_pfs_global.h49
-rw-r--r--storage/perfschema/unittest/stub_print_error.h40
-rw-r--r--storage/perfschema/unittest/stub_server_misc.h28
172 files changed, 50229 insertions, 0 deletions
diff --git a/storage/perfschema/CMakeLists.txt b/storage/perfschema/CMakeLists.txt
new file mode 100644
index 00000000000..b8f910a9539
--- /dev/null
+++ b/storage/perfschema/CMakeLists.txt
@@ -0,0 +1,207 @@
+# 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
+# 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_DIRECTORIES(${CMAKE_SOURCE_DIR}
+ ${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/sql
+ ${CMAKE_SOURCE_DIR}/regex
+ ${CMAKE_SOURCE_DIR}/extra/yassl/include)
+
+ADD_DEFINITIONS(-DMYSQL_SERVER)
+
+# 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_thread_connect_attr.h
+table_session_connect.h
+table_session_connect_attrs.h
+table_session_account_connect_attrs.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_autosize.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
+cursor_by_thread_connect_attr.cc
+table_session_connect.cc
+table_session_connect_attrs.cc
+table_session_account_connect_attrs.cc
+)
+
+MYSQL_ADD_PLUGIN(perfschema ${PERFSCHEMA_SOURCES} STORAGE_ENGINE DEFAULT STATIC_ONLY)
+IF(WITH_PERFSCHEMA_STORAGE_ENGINE AND WITH_UNIT_TESTS)
+ ENABLE_TESTING()
+ ADD_SUBDIRECTORY(unittest)
+ENDIF()
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_thread_connect_attr.cc b/storage/perfschema/cursor_by_thread_connect_attr.cc
new file mode 100644
index 00000000000..7a0dd04119d
--- /dev/null
+++ b/storage/perfschema/cursor_by_thread_connect_attr.cc
@@ -0,0 +1,71 @@
+/* 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 */
+
+#include "my_global.h"
+#include "cursor_by_thread_connect_attr.h"
+
+cursor_by_thread_connect_attr::cursor_by_thread_connect_attr(
+ const PFS_engine_table_share *share) :
+ PFS_engine_table(share, &m_pos), m_row_exists(false)
+{}
+
+int cursor_by_thread_connect_attr::rnd_next(void)
+{
+ PFS_thread *thread;
+
+ 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())
+ {
+ make_row(thread, m_pos.m_index_2);
+ if (m_row_exists)
+ {
+ m_next_pos.set_after(&m_pos);
+ return 0;
+ }
+ }
+ }
+ return HA_ERR_END_OF_FILE;
+}
+
+
+int cursor_by_thread_connect_attr::rnd_pos(const void *pos)
+{
+ PFS_thread *thread;
+
+ 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;
+
+ make_row(thread, m_pos.m_index_2);
+ if (m_row_exists)
+ return 0;
+
+ return HA_ERR_RECORD_DELETED;
+}
+
+
+void cursor_by_thread_connect_attr::reset_position(void)
+{
+ m_pos.reset();
+ m_next_pos.reset();
+}
diff --git a/storage/perfschema/cursor_by_thread_connect_attr.h b/storage/perfschema/cursor_by_thread_connect_attr.h
new file mode 100644
index 00000000000..fbce56f208d
--- /dev/null
+++ b/storage/perfschema/cursor_by_thread_connect_attr.h
@@ -0,0 +1,81 @@
+/* Copyright (c) 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 CURSOR_BY_THREAD_CONNECT_ATTR_H
+#define CURSOR_BY_THREAD_CONNECT_ATTR_H
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+#include "pfs_instr.h"
+
+/**
+ \addtogroup Performance_schema_tables
+ @{
+*/
+
+struct pos_connect_attr_by_thread_by_attr
+: public PFS_double_index
+{
+ pos_connect_attr_by_thread_by_attr()
+ : PFS_double_index(0, 0)
+ {}
+
+ inline bool has_more_thread(void)
+ {
+ return (m_index_1 < thread_max);
+ }
+
+ inline void next_thread(void)
+ {
+ m_index_1++;
+ m_index_2= 0;
+ }
+
+ inline void reset(void)
+ {
+ m_index_1= 0;
+ m_index_2= 0;
+ }
+};
+
+/** Cursor CURSOR_BY_THREAD_CONNECT_ATTR. */
+class cursor_by_thread_connect_attr : 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_connect_attr(const PFS_engine_table_share *share);
+
+public:
+ ~cursor_by_thread_connect_attr()
+ {}
+
+protected:
+ virtual void make_row(PFS_thread *thread, uint ordinal)= 0;
+ /** True if row exists */
+ bool m_row_exists;
+
+private:
+ /** Current position. */
+ pos_connect_attr_by_thread_by_attr m_pos;
+ /** Next position. */
+ pos_connect_attr_by_thread_by_attr 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.cc b/storage/perfschema/gen_pfs_lex_token.cc
new file mode 100644
index 00000000000..7581255b284
--- /dev/null
+++ b/storage/perfschema/gen_pfs_lex_token.cc
@@ -0,0 +1,265 @@
+/*
+ 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 */
+
+#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"));
+ 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
new file mode 100644
index 00000000000..3f9c9cf6081
--- /dev/null
+++ b/storage/perfschema/ha_perfschema.cc
@@ -0,0 +1,470 @@
+/* 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/ha_perfschema.cc
+ Performance schema storage engine (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "my_atomic.h"
+#include "sql_plugin.h"
+#include "mysql/plugin.h"
+#include "ha_perfschema.h"
+#include "pfs_engine_table.h"
+#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
+/*
+ The performance schema can can not function with MY_ATOMIC_MODE_DUMMY,
+ a fully functional implementation of MY_ATOMIC should be used instead.
+ If the build fails with this error message:
+ - either use a different ./configure --with-atomic-ops option
+ - or do not build with the performance schema.
+*/
+#error "The performance schema needs a functional MY_ATOMIC implementation."
+#endif
+
+handlerton *pfs_hton= NULL;
+
+static handler* pfs_create_handler(handlerton *hton,
+ TABLE_SHARE *table,
+ MEM_ROOT *mem_root)
+{
+ return new (mem_root) ha_perfschema(hton, table);
+}
+
+static int compare_database_names(const char *name1, const char *name2)
+{
+ if (lower_case_table_names)
+ return strcasecmp(name1, name2);
+ return strcmp(name1, name2);
+}
+
+static const PFS_engine_table_share*
+find_table_share(const char *db, const char *name)
+{
+ DBUG_ENTER("find_table_share");
+
+ if (compare_database_names(db, PERFORMANCE_SCHEMA_str.str) != 0)
+ DBUG_RETURN(NULL);
+
+ const PFS_engine_table_share* result;
+ result= PFS_engine_table::find_engine_table_share(name);
+ DBUG_RETURN(result);
+}
+
+static int pfs_init_func(void *p)
+{
+ DBUG_ENTER("pfs_init_func");
+
+ pfs_hton= reinterpret_cast<handlerton *> (p);
+
+ pfs_hton->state= SHOW_OPTION_YES;
+ pfs_hton->create= pfs_create_handler;
+ pfs_hton->show_status= pfs_show_status;
+ pfs_hton->flags= HTON_ALTER_NOT_SUPPORTED |
+ HTON_TEMPORARY_NOT_SUPPORTED |
+ HTON_NO_PARTITION |
+ HTON_NO_BINLOG_ROW_OPT;
+
+ /*
+ As long as the server implementation keeps using legacy_db_type,
+ as for example in mysql_truncate(),
+ we can not rely on the fact that different mysqld process will assign
+ consistently the same legacy_db_type for a given storage engine name.
+ In particular, using different --loose-skip-xxx options between
+ ./mysqld --bootstrap
+ ./mysqld
+ creates bogus .frm forms when bootstrapping the performance schema,
+ if we rely on ha_initialize_handlerton to assign a really dynamic value.
+ To fix this, a dedicated DB_TYPE is officially assigned to
+ the performance schema. See Bug#43039.
+ */
+ pfs_hton->db_type= DB_TYPE_PERFORMANCE_SCHEMA;
+
+ PFS_engine_table_share::init_all_locks();
+
+ DBUG_RETURN(0);
+}
+
+static int pfs_done_func(void *p)
+{
+ DBUG_ENTER("pfs_done_func");
+
+ pfs_hton= NULL;
+
+ PFS_engine_table_share::delete_all_locks();
+
+ DBUG_RETURN(0);
+}
+
+static struct st_mysql_show_var pfs_status_vars[]=
+{
+ {"Performance_schema_mutex_classes_lost",
+ (char*) &mutex_class_lost, SHOW_LONG_NOFLUSH},
+ {"Performance_schema_rwlock_classes_lost",
+ (char*) &rwlock_class_lost, SHOW_LONG_NOFLUSH},
+ {"Performance_schema_cond_classes_lost",
+ (char*) &cond_class_lost, SHOW_LONG_NOFLUSH},
+ {"Performance_schema_thread_classes_lost",
+ (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",
+ (char*) &rwlock_lost, SHOW_LONG},
+ {"Performance_schema_cond_instances_lost",
+ (char*) &cond_lost, SHOW_LONG},
+ {"Performance_schema_thread_instances_lost",
+ (char*) &thread_lost, SHOW_LONG},
+ {"Performance_schema_file_instances_lost",
+ (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 */
+ {"Performance_schema_table_instances_lost",
+ (char*) &table_share_lost, SHOW_LONG},
+ /* 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},
+ {"Performance_schema_session_connect_attrs_lost",
+ (char*) &session_connect_attrs_lost, SHOW_LONG},
+ {NullS, NullS, SHOW_LONG}
+};
+
+struct st_mysql_storage_engine pfs_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+
+const char* pfs_engine_name= "PERFORMANCE_SCHEMA";
+
+mysql_declare_plugin(perfschema)
+{
+ MYSQL_STORAGE_ENGINE_PLUGIN,
+ &pfs_storage_engine,
+ pfs_engine_name,
+ "Marc Alff, Oracle", /* Formerly Sun Microsystems, formerly MySQL */
+ "Performance Schema",
+ PLUGIN_LICENSE_GPL,
+ pfs_init_func, /* Plugin Init */
+ pfs_done_func, /* Plugin Deinit */
+ 0x0001 /* 0.1 */,
+ pfs_status_vars, /* status variables */
+ NULL, /* system variables */
+ NULL, /* config options */
+ 0, /* flags */
+}
+mysql_declare_plugin_end;
+
+ha_perfschema::ha_perfschema(handlerton *hton, TABLE_SHARE *share)
+ : handler(hton, share), m_table_share(NULL), m_table(NULL)
+{}
+
+ha_perfschema::~ha_perfschema()
+{}
+
+static const char *ha_pfs_exts[]= {
+ NullS
+};
+
+const char **ha_perfschema::bas_ext() const
+{
+ return ha_pfs_exts;
+}
+
+int ha_perfschema::open(const char *name, int mode, uint test_if_locked)
+{
+ DBUG_ENTER("ha_perfschema::open");
+
+ m_table_share= find_table_share(table_share->db.str,
+ table_share->table_name.str);
+ if (! m_table_share)
+ DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
+
+ thr_lock_data_init(m_table_share->m_thr_lock_ptr, &m_thr_lock, NULL);
+ ref_length= m_table_share->m_ref_length;
+
+ DBUG_RETURN(0);
+}
+
+int ha_perfschema::close(void)
+{
+ DBUG_ENTER("ha_perfschema::close");
+ m_table_share= NULL;
+ delete m_table;
+ m_table= NULL;
+
+ DBUG_RETURN(0);
+}
+
+int ha_perfschema::write_row(uchar *buf)
+{
+ int result;
+
+ DBUG_ENTER("ha_perfschema::write_row");
+ if (!pfs_initialized)
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+
+ DBUG_ASSERT(m_table_share);
+ ha_statistic_increment(&SSV::ha_write_count);
+ result= m_table_share->write_row(table, buf, table->field);
+ DBUG_RETURN(result);
+}
+
+void ha_perfschema::use_hidden_primary_key(void)
+{
+ /*
+ This is also called in case of row based replication,
+ see TABLE::mark_columns_needed_for_update().
+ Add all columns to the read set, but do not touch the write set,
+ as some columns in the SETUP_ tables are not writable.
+ */
+ table->column_bitmaps_set_no_signal(&table->s->all_set, table->write_set);
+}
+
+int ha_perfschema::update_row(const uchar *old_data, uchar *new_data)
+{
+ DBUG_ENTER("ha_perfschema::update_row");
+ if (!pfs_initialized)
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+
+ 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");
+ if (!pfs_initialized)
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+
+ 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;
+ DBUG_ENTER("ha_perfschema::rnd_init");
+
+ DBUG_ASSERT(m_table_share);
+ DBUG_ASSERT(m_table_share->m_open_table != NULL);
+
+ stats.records= 0;
+ if (m_table == NULL)
+ m_table= m_table_share->m_open_table();
+ 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);
+}
+
+int ha_perfschema::rnd_end(void)
+{
+ DBUG_ENTER("ha_perfschema::rnd_end");
+ DBUG_ASSERT(m_table);
+ delete m_table;
+ m_table= NULL;
+ DBUG_RETURN(0);
+}
+
+int ha_perfschema::rnd_next(uchar *buf)
+{
+ DBUG_ENTER("ha_perfschema::rnd_next");
+ if (!pfs_initialized)
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+
+ DBUG_ASSERT(m_table);
+ ha_statistic_increment(&SSV::ha_read_rnd_next_count);
+
+ int result= m_table->rnd_next();
+ if (result == 0)
+ {
+ result= m_table->read_row(table, buf, table->field);
+ if (result == 0)
+ stats.records++;
+ }
+ DBUG_RETURN(result);
+}
+
+void ha_perfschema::position(const uchar *record)
+{
+ DBUG_ENTER("ha_perfschema::position");
+
+ DBUG_ASSERT(m_table);
+ m_table->get_position(ref);
+ DBUG_VOID_RETURN;
+}
+
+int ha_perfschema::rnd_pos(uchar *buf, uchar *pos)
+{
+ DBUG_ENTER("ha_perfschema::rnd_pos");
+ if (!pfs_initialized)
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+
+ 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);
+ DBUG_RETURN(result);
+}
+
+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->get_row_count();
+ if (flag & HA_STATUS_CONST)
+ ref_length= m_table_share->m_ref_length;
+ DBUG_RETURN(0);
+}
+
+int ha_perfschema::delete_all_rows(void)
+{
+ int result;
+
+ DBUG_ENTER("ha_perfschema::delete_all_rows");
+ if (!pfs_initialized)
+ DBUG_RETURN(0);
+
+ DBUG_ASSERT(m_table_share);
+ if (m_table_share->m_delete_all_rows)
+ result= m_table_share->m_delete_all_rows();
+ else
+ {
+ result= HA_ERR_WRONG_COMMAND;
+ }
+ DBUG_RETURN(result);
+}
+
+int ha_perfschema::truncate()
+{
+ return delete_all_rows();
+}
+
+THR_LOCK_DATA **ha_perfschema::store_lock(THD *thd,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ if (lock_type != TL_IGNORE && m_thr_lock.type == TL_UNLOCK)
+ m_thr_lock.type= lock_type;
+ *to++= &m_thr_lock;
+ m_thr_lock.m_psi= m_psi;
+ return to;
+}
+
+int ha_perfschema::delete_table(const char *name)
+{
+ DBUG_ENTER("ha_perfschema::delete_table");
+ DBUG_RETURN(0);
+}
+
+int ha_perfschema::rename_table(const char * from, const char * to)
+{
+ DBUG_ENTER("ha_perfschema::rename_table ");
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+}
+
+int ha_perfschema::create(const char *name, TABLE *table_arg,
+ HA_CREATE_INFO *create_info)
+{
+ DBUG_ENTER("ha_perfschema::create");
+ DBUG_ASSERT(table_arg);
+ DBUG_ASSERT(table_arg->s);
+ if (find_table_share(table_arg->s->db.str,
+ table_arg->s->table_name.str))
+ {
+ /*
+ Attempting to create a known performance schema table.
+ Allowing the create, to create .FRM files,
+ for the initial database install, and mysql_upgrade.
+ This should fail once .FRM are removed.
+ */
+ DBUG_RETURN(0);
+ }
+ /*
+ This is not a general purpose engine.
+ Failure to CREATE TABLE is the expected result.
+ */
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+}
+
+void ha_perfschema::print_error(int error, myf errflag)
+{
+ switch (error)
+ {
+ case HA_ERR_TABLE_NEEDS_UPGRADE:
+ /*
+ The error message for ER_TABLE_NEEDS_UPGRADE refers to REPAIR table,
+ which does not apply to performance schema tables.
+ */
+ my_error(ER_WRONG_NATIVE_TABLE_STRUCTURE, MYF(0),
+ table_share->db.str, table_share->table_name.str);
+ break;
+ case HA_ERR_WRONG_COMMAND:
+ /*
+ The performance schema is not a general purpose storage engine,
+ some operations are not supported, by design.
+ We do not want to print "Command not supported",
+ which gives the impression that a command implementation is missing,
+ and that the failure should be considered a bug.
+ We print "Invalid performance_schema usage." instead,
+ to emphasise that the operation attempted is not meant to be legal,
+ and that the failure returned is indeed the expected result.
+ */
+ my_error(ER_WRONG_PERFSCHEMA_USAGE, MYF(0));
+ break;
+ default:
+ handler::print_error(error, errflag);
+ break;
+ }
+}
+
diff --git a/storage/perfschema/ha_perfschema.h b/storage/perfschema/ha_perfschema.h
new file mode 100644
index 00000000000..8e98341a790
--- /dev/null
+++ b/storage/perfschema/ha_perfschema.h
@@ -0,0 +1,212 @@
+/* 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 HA_PERFSCHEMA_H
+#define HA_PERFSCHEMA_H
+
+#include "handler.h" /* class handler */
+
+/**
+ @file storage/perfschema/ha_perfschema.h
+ Performance schema storage engine (declarations).
+
+ @defgroup Performance_schema_engine Performance Schema Engine
+ @ingroup Performance_schema_implementation
+ @{
+*/
+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();
+
+ const char *table_type(void) const { return pfs_engine_name; }
+
+ const char *index_type(uint) { return ""; }
+
+ const char **bas_ext(void) const;
+
+ /** Capabilities of the performance schema tables. */
+ ulonglong table_flags(void) const
+ {
+ /*
+ About HA_FAST_KEY_READ:
+
+ The storage engine ::rnd_pos() method is fast to locate records by key,
+ so HA_FAST_KEY_READ is technically true, but the record content can be
+ overwritten between ::rnd_next() and ::rnd_pos(), because all the P_S
+ data is volatile.
+ The HA_FAST_KEY_READ flag is not advertised, to force the optimizer
+ to cache records instead, to provide more consistent records.
+ For example, consider the following statement:
+ - select * from P_S.EVENTS_WAITS_HISTORY_LONG where THREAD_ID=<n>
+ order by ...
+ With HA_FAST_KEY_READ, it can return records where "THREAD_ID=<n>"
+ is false, because the where clause was evaluated to true after
+ ::rnd_pos(), then the content changed, then the record was fetched by
+ key using ::rnd_pos().
+ 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.
+ */
+ return HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_NO_AUTO_INCREMENT |
+ HA_PRIMARY_KEY_REQUIRED_FOR_DELETE;
+ }
+
+ /**
+ Operations supported by indexes.
+ None, there are no indexes.
+ */
+ ulong index_flags(uint , uint , bool ) const
+ { return 0; }
+
+ uint max_supported_record_length(void) const
+ { return HA_MAX_REC_LENGTH; }
+
+ uint max_supported_keys(void) const
+ { return 0; }
+
+ uint max_supported_key_parts(void) const
+ { return 0; }
+
+ uint max_supported_key_length(void) const
+ { return 0; }
+
+ ha_rows estimate_rows_upper_bound(void)
+ { return HA_POS_ERROR; }
+
+ 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);
+
+ int delete_all_rows(void);
+
+ int truncate();
+
+ int delete_table(const char *from);
+
+ int rename_table(const char * from, const char * to);
+
+ int create(const char *name, TABLE *form,
+ HA_CREATE_INFO *create_info);
+
+ THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type);
+
+ virtual uint8 table_cache_type(void)
+ { return HA_CACHE_TBL_NOCACHE; }
+
+ virtual my_bool register_query_cache_table
+ (THD *, char *, uint , qc_engine_callback *engine_callback, ulonglong *)
+ {
+ *engine_callback= 0;
+ return FALSE;
+ }
+
+ virtual void print_error(int error, myf errflags);
+
+private:
+ /** MySQL lock */
+ THR_LOCK_DATA m_thr_lock;
+ /** Performance schema table share for this table handler. */
+ const PFS_engine_table_share *m_table_share;
+ /** Performance schema table cursor. */
+ PFS_engine_table *m_table;
+};
+
+/** @} */
+#endif
+
diff --git a/storage/perfschema/pfs.cc b/storage/perfschema/pfs.cc
new file mode 100644
index 00000000000..4a0973698ac
--- /dev/null
+++ b/storage/perfschema/pfs.cc
@@ -0,0 +1,5223 @@
+/* Copyright (c) 2008, 2013, 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.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"
+#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
+ MySQL PERFORMANCE_SCHEMA implementation.
+
+ @section INTRO Introduction
+ The PERFORMANCE_SCHEMA is a way to introspect the internal execution of
+ the server at runtime.
+ The performance schema focuses primarily on performance data,
+ as opposed to the INFORMATION_SCHEMA whose purpose is to inspect metadata.
+
+ From a user point of view, the performance schema consists of:
+ - a dedicated database schema, named PERFORMANCE_SCHEMA,
+ - SQL tables, used to query the server internal state or change
+ configuration settings.
+
+ From an implementation point of view, the performance schema is a dedicated
+ Storage Engine which exposes data collected by 'Instrumentation Points'
+ placed in the server code.
+
+ @section INTERFACES Multiple interfaces
+
+ The performance schema exposes many different interfaces,
+ for different components, and for different purposes.
+
+ @subsection INT_INSTRUMENTING Instrumenting interface
+
+ All the data representing the server internal state exposed
+ in the performance schema must be first collected:
+ this is the role of the instrumenting interface.
+ The instrumenting interface is a coding interface provided
+ by implementors (of the performance schema) to implementors
+ (of the server or server components).
+
+ This interface is available to:
+ - C implementations
+ - C++ implementations
+ - the core SQL layer (/sql)
+ - the mysys library (/mysys)
+ - MySQL plugins, including storage engines,
+ - third party plugins, including third party storage engines.
+
+ For details, see the @ref PAGE_INSTRUMENTATION_INTERFACE
+ "instrumentation interface page".
+
+ @subsection INT_COMPILING Compiling interface
+
+ The implementation of the performance schema can be enabled or disabled at
+ build time, when building MySQL from the source code.
+
+ When building with the performance schema code, some compilation flags
+ are available to change the default values used in the code, if required.
+
+ For more details, see:
+ @verbatim ./configure --help @endverbatim
+
+ To compile with the performance schema:
+ @verbatim ./configure --with-perfschema @endverbatim
+
+ The implementation of all the compiling options is located in
+ @verbatim ./storage/perfschema/plug.in @endverbatim
+
+ @subsection INT_STARTUP Server startup interface
+
+ The server startup interface consists of the "./mysqld ..."
+ command line used to start the server.
+ When the performance schema is compiled in the server binary,
+ extra command line options are available.
+
+ These extra start options allow the DBA to:
+ - enable or disable the performance schema
+ - specify some sizing parameters.
+
+ To see help for the performance schema startup options, see:
+ @verbatim ./sql/mysqld --verbose --help @endverbatim
+
+ The implementation of all the startup options is located in
+ @verbatim ./sql/mysqld.cc, my_long_options[] @endverbatim
+
+ @subsection INT_BOOTSTRAP Server bootstrap interface
+
+ The bootstrap interface is a private interface exposed by
+ the performance schema, and used by the SQL layer.
+ Its role is to advertise all the SQL tables natively
+ supported by the performance schema to the SQL server.
+ The code consists of creating MySQL tables for the
+ performance schema itself, and is used in './mysql --bootstrap'
+ mode when a server is installed.
+
+ The implementation of the database creation script is located in
+ @verbatim ./scripts/mysql_system_tables.sql @endverbatim
+
+ @subsection INT_CONFIG Runtime configuration interface
+
+ When the performance schema is used at runtime, various configuration
+ parameters can be used to specify what kind of data is collected,
+ what kind of aggregations are computed, what kind of timers are used,
+ what events are timed, etc.
+
+ For all these capabilities, not a single statement or special syntax
+ was introduced in the parser.
+ Instead of new SQL statements, the interface consists of DML
+ (SELECT, INSERT, UPDATE, DELETE) against special "SETUP" tables.
+
+ For example:
+ @verbatim mysql> update performance_schema.SETUP_INSTRUMENTS
+ set ENABLED='YES', TIMED='YES';
+ Query OK, 234 rows affected (0.00 sec)
+ Rows matched: 234 Changed: 234 Warnings: 0 @endverbatim
+
+ @subsection INT_STATUS Internal audit interface
+
+ The internal audit interface is provided to the DBA to inspect if the
+ performance schema code itself is functioning properly.
+ This interface is necessary because a failure caused while
+ instrumenting code in the server should not cause failures in the
+ MySQL server itself, so that the performance schema implementation
+ never raises errors during runtime execution.
+
+ This auditing interface consists of:
+ @verbatim SHOW ENGINE PERFORMANCE_SCHEMA STATUS; @endverbatim
+ It displays data related to the memory usage of the performance schema,
+ as well as statistics about lost events, if any.
+
+ The SHOW STATUS command is implemented in
+ @verbatim ./storage/perfschema/pfs_engine_table.cc @endverbatim
+
+ @subsection INT_QUERY Query interface
+
+ The query interface is used to query the internal state of a running server.
+ It is provided as SQL tables.
+
+ For example:
+ @verbatim mysql> select * from performance_schema.EVENTS_WAITS_CURRENT;
+ @endverbatim
+
+ @section DESIGN_PRINCIPLES Design principles
+
+ @subsection PRINCIPLE_BEHAVIOR No behavior changes
+
+ The primary goal of the performance schema is to measure (instrument) the
+ execution of the server. A good measure should not cause any change
+ in behavior.
+
+ To achieve this, the overall design of the performance schema complies
+ with the following very severe design constraints:
+
+ The parser is unchanged. There are no new keywords, no new statements.
+ This guarantees that existing applications will run the same way with or
+ without the performance schema.
+
+ All the instrumentation points return "void", there are no error codes.
+ Even if the performance schema internally fails, execution of the server
+ code will proceed.
+
+ None of the instrumentation points allocate memory.
+ All the memory used by the performance schema is pre-allocated at startup,
+ and is considered "static" during the server life time.
+
+ None of the instrumentation points use any pthread_mutex, pthread_rwlock,
+ or pthread_cond (or platform equivalents).
+ Executing the instrumentation point should not cause thread scheduling to
+ change in the server.
+
+ In other words, the implementation of the instrumentation points,
+ including all the code called by the instrumentation points, is:
+ - malloc free
+ - mutex free
+ - rwlock free
+
+ TODO: All the code located in storage/perfschema is malloc free,
+ but unfortunately the usage of LF_HASH introduces some memory allocation.
+ This should be revised if possible, to use a lock-free,
+ malloc-free hash code table.
+
+ @subsection PRINCIPLE_PERFORMANCE No performance hit
+
+ The instrumentation of the server should be as fast as possible.
+ In cases when there are choices between:
+ - doing some processing when recording the performance data
+ in the instrumentation,
+ - doing some processing when retrieving the performance data,
+
+ priority is given in the design to make the instrumentation faster,
+ pushing some complexity to data retrieval.
+
+ As a result, some parts of the design, related to:
+ - the setup code path,
+ - the query code path,
+
+ might appear to be sub-optimal.
+
+ The criterion used here is to optimize primarily the critical path (data
+ collection), possibly at the expense of non-critical code paths.
+
+ @subsection PRINCIPLE_NOT_INTRUSIVE Unintrusive instrumentation
+
+ For the performance schema in general to be successful, the barrier
+ of entry for a developer should be low, so it's easy to instrument code.
+
+ In particular, the instrumentation interface:
+ - is available for C and C++ code (so it's a C interface),
+ - does not require parameters that the calling code can't easily provide,
+ - supports partial instrumentation (for example, instrumenting mutexes does
+ not require that every mutex is instrumented)
+
+ @subsection PRINCIPLE_EXTENDABLE Extendable instrumentation
+
+ As the content of the performance schema improves,
+ with more tables exposed and more data collected,
+ the instrumentation interface will also be augmented
+ to support instrumenting new concepts.
+ Existing instrumentations should not be affected when additional
+ instrumentation is made available, and making a new instrumentation
+ available should not require existing instrumented code to support it.
+
+ @subsection PRINCIPLE_VERSIONED Versioned instrumentation
+
+ Given that the instrumentation offered by the performance schema will
+ be augmented with time, when more features are implemented,
+ the interface itself should be versioned, to keep compatibility
+ with previous instrumented code.
+
+ For example, after both plugin-A and plugin-B have been instrumented for
+ mutexes, read write locks and conditions, using the instrumentation
+ interface, we can anticipate that the instrumentation interface
+ is expanded to support file based operations.
+
+ Plugin-A, a file based storage engine, will most likely use the expanded
+ interface and instrument its file usage, using the version 2
+ interface, while Plugin-B, a network based storage engine, will not change
+ its code and not release a new binary.
+
+ When later the instrumentation interface is expanded to support network
+ based operations (which will define interface version 3), the Plugin-B code
+ can then be changed to make use of it.
+
+ Note, this is just an example to illustrate the design concept here.
+ Both mutexes and file instrumentation are already available
+ since version 1 of the instrumentation interface.
+
+ @subsection PRINCIPLE_DEPLOYMENT Easy deployment
+
+ Internally, we might want every plugin implementation to upgrade the
+ instrumented code to the latest available, but this will cause additional
+ work and this is not practical if the code change is monolithic.
+
+ Externally, for third party plugin implementors, asking implementors to
+ always stay aligned to the latest instrumentation and make new releases,
+ even when the change does not provide new functionality for them,
+ is a bad idea.
+
+ For example, requiring a network based engine to re-release because the
+ instrumentation interface changed for file based operations, will create
+ too many deployment issues.
+
+ So, the performance schema implementation must support concurrently,
+ in the same deployment, multiple versions of the instrumentation
+ interface, and ensure binary compatibility with each version.
+
+ In addition to this, the performance schema can be included or excluded
+ from the server binary, using build time configuration options.
+
+ Regardless, the following types of deployment are valid:
+ - a server supporting the performance schema + a storage engine
+ that is not instrumented
+ - a server not supporting the performance schema + a storage engine
+ that is instrumented
+*/
+
+/**
+ @page PAGE_INSTRUMENTATION_INTERFACE Performance schema: instrumentation interface page.
+ MySQL performance schema instrumentation interface.
+
+ @section INTRO Introduction
+
+ The instrumentation interface consist of two layers:
+ - a raw ABI (Application Binary Interface) layer, that exposes the primitive
+ instrumentation functions exported by the performance schema instrumentation
+ - an API (Application Programing Interface) layer,
+ that provides many helpers for a developer instrumenting some code,
+ to make the instrumentation as easy as possible.
+
+ The ABI layer consists of:
+@code
+#include "mysql/psi/psi.h"
+@endcode
+
+ The API layer consists of:
+@code
+#include "mysql/psi/mutex_mutex.h"
+#include "mysql/psi/mutex_file.h"
+@endcode
+
+ The first helper is for mutexes, rwlocks and conditions,
+ the second for file io.
+
+ The API layer exposes C macros and typedefs which will expand:
+ - either to non-instrumented code, when compiled without the performance
+ schema instrumentation
+ - or to instrumented code, that will issue the raw calls to the ABI layer
+ so that the implementation can collect data.
+
+ Note that all the names introduced (for example, @c mysql_mutex_lock) do not
+ collide with any other namespace.
+ In particular, the macro @c mysql_mutex_lock is on purpose not named
+ @c pthread_mutex_lock.
+ This is to:
+ - avoid overloading @c pthread_mutex_lock with yet another macro,
+ which is dangerous as it can affect user code and pollute
+ the end-user namespace.
+ - allow the developer instrumenting code to selectively instrument
+ some code but not all.
+
+ @section PRINCIPLES Design principles
+
+ The ABI part is designed as a facade, that exposes basic primitives.
+ The expectation is that each primitive will be very stable over time,
+ but the list will constantly grow when more instruments are supported.
+ To support binary compatibility with plugins compiled with a different
+ version of the instrumentation, the ABI itself is versioned
+ (see @c PSI_v1, @c PSI_v2).
+
+ For a given instrumentation point in the API, the basic coding pattern
+ used is:
+ - (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.
+
+ 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:
+
+@verbatim
+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)
+ locker= PSI_server->start_mutex_wait(&state, that->p_psi,
+ PSI_MUTEX_LOCK, locker, src_file, src_line);
+
+ ............... (b)
+ result= pthread_mutex_lock(&that->m_mutex);
+
+ ............... (c)
+ PSI_server->end_mutex_wait(locker, result);
+
+ return result;
+}
+@endverbatim
+
+ When the performance schema instrumentation is not compiled in,
+ the code becomes simply a wrapper, expanded in line by the compiler:
+
+@verbatim
+static inline int mysql_mutex_lock(...)
+{
+ int result;
+
+ ............... (b)
+ result= pthread_mutex_lock(&that->m_mutex);
+
+ return result;
+}
+@endverbatim
+*/
+
+/**
+ @page PAGE_AGGREGATES Performance schema: the aggregates page.
+ Performance schema aggregates.
+
+ @section INTRO Introduction
+
+ Aggregates tables are tables that can be formally defined as
+ SELECT ... from EVENTS_WAITS_HISTORY_INFINITE ... group by 'group clause'.
+
+ Each group clause defines a different kind of aggregate, and corresponds to
+ a different table exposed by the performance schema.
+
+ Aggregates can be either:
+ - computed on the fly,
+ - computed on demand, based on other available data.
+
+ 'EVENTS_WAITS_HISTORY_INFINITE' is a table that does not exist,
+ the best approximation is EVENTS_WAITS_HISTORY_LONG.
+ Aggregates computed on the fly in fact are based on EVENTS_WAITS_CURRENT,
+ while aggregates computed on demand are based on other
+ EVENTS_WAITS_SUMMARY_BY_xxx tables.
+
+ To better understand the implementation itself, a bit of math is
+ required first, to understand the model behind the code:
+ the code is deceptively simple, the real complexity resides
+ in the flyweight of pointers between various performance schema buffers.
+
+ @section DIMENSION Concept of dimension
+
+ An event measured by the instrumentation has many attributes.
+ An event is represented as a data point P(x1, x2, ..., xN),
+ where each x_i coordinate represents a given attribute value.
+
+ Examples of attributes are:
+ - the time waited
+ - the object waited on
+ - the instrument waited on
+ - the thread that waited
+ - the operation performed
+ - per object or per operation additional attributes, such as spins,
+ number of bytes, etc.
+
+ Computing an aggregate per thread is fundamentally different from
+ computing an aggregate by instrument, so the "_BY_THREAD" and
+ "_BY_EVENT_NAME" aggregates are different dimensions,
+ operating on different x_i and x_j coordinates.
+ These aggregates are "orthogonal".
+
+ @section PROJECTION Concept of projection
+
+ A given x_i attribute value can convey either just one basic information,
+ such as a number of bytes, or can convey implied information,
+ such as an object fully qualified name.
+
+ For example, from the value "test.t1", the name of the object schema
+ "test" can be separated from the object name "t1", so that now aggregates
+ by object schema can be implemented.
+
+ In math terms, that corresponds to defining a function:
+ F_i (x): x --> y
+ 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}, f_i(x_i), x{i+1}, ..., x_N)
+
+ That function defines in fact an aggregate !
+ In SQL terms, this aggregate would look like the following table:
+
+@verbatim
+ CREATE VIEW EVENTS_WAITS_SUMMARY_BY_Func_i AS
+ SELECT col_1, col_2, ..., col_{i-1},
+ Func_i(col_i),
+ COUNT(col_i),
+ MIN(col_i), AVG(col_i), MAX(col_i), -- if col_i is a numeric value
+ col_{i+1}, ..., col_N
+ FROM EVENTS_WAITS_HISTORY_INFINITE
+ group by col_1, col_2, ..., col_{i-1}, col{i+1}, ..., col_N.
+@endverbatim
+
+ Note that not all columns have to be included,
+ in particular some columns that are dependent on the x_i column should
+ be removed, so that in practice, MySQL's aggregation method tends to
+ remove many attributes at each aggregation steps.
+
+ For example, when aggregating wait events by object instances,
+ - the wait_time and number_of_bytes can be summed,
+ and sum(wait_time) now becomes an object instance attribute.
+ - the source, timer_start, timer_end columns are not in the
+ _BY_INSTANCE table, because these attributes are only
+ meaningful for a wait.
+
+ @section COMPOSITION Concept of composition
+
+ Now, the "test.t1" --> "test" example was purely theory,
+ just to explain the concept, and does not lead very far.
+ Let's look at a more interesting example of data that can be derived
+ from the row event.
+
+ An event creates a transient object, PFS_wait_locker, per operation.
+ This object's life cycle is extremely short: it's created just
+ before the start_wait() instrumentation call, and is destroyed in
+ the end_wait() call.
+
+ The wait locker itself contains a pointer to the object instance
+ waited on.
+ That allows to implement a wait_locker --> object instance projection,
+ with m_target.
+ The object instance life cycle depends on _init and _destroy calls
+ from the code, such as mysql_mutex_init()
+ and mysql_mutex_destroy() for a mutex.
+
+ The object instance waited on contains a pointer to the object class,
+ which is represented by the instrument name.
+ That allows to implement an object instance --> object class projection.
+ The object class life cycle is permanent, as instruments are loaded in
+ the server and never removed.
+
+ The object class is named in such a way
+ (for example, "wait/sync/mutex/sql/LOCK_open",
+ "wait/io/file/maria/data_file) that the component ("sql", "maria")
+ that it belongs to can be inferred.
+ That allows to implement an object class --> server component projection.
+
+ Back to math again, we have, for example for mutexes:
+
+ F1 (l) : PFS_wait_locker l --> PFS_mutex m = l->m_target.m_mutex
+
+ F1_to_2 (m) : PFS_mutex m --> PFS_mutex_class i = m->m_class
+
+ F2_to_3 (i) : PFS_mutex_class i --> const char *component =
+ substring(i->m_name, ...)
+
+ Per components aggregates are not implemented, this is just an illustration.
+
+ F1 alone defines this aggregate:
+
+ EVENTS_WAITS_HISTORY_INFINITE --> EVENTS_WAITS_SUMMARY_BY_INSTANCE
+ (or MUTEX_INSTANCE)
+
+ F1_to_2 alone could define this aggregate:
+
+ EVENTS_WAITS_SUMMARY_BY_INSTANCE --> EVENTS_WAITS_SUMMARY_BY_EVENT_NAME
+
+ Alternatively, using function composition, with
+ F2 = F1_to_2 o F1, F2 defines:
+
+ EVENTS_WAITS_HISTORY_INFINITE --> EVENTS_WAITS_SUMMARY_BY_EVENT_NAME
+
+ Likewise, F_2_to_3 defines:
+
+ EVENTS_WAITS_SUMMARY_BY_EVENT_NAME --> EVENTS_WAITS_SUMMARY_BY_COMPONENT
+
+ and F3 = F_2_to_3 o F_1_to_2 o F1 defines:
+
+ EVENTS_WAITS_HISTORY_INFINITE --> EVENTS_WAITS_SUMMARY_BY_COMPONENT
+
+ What has all this to do with the code ?
+
+ 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.
+
+ @section OBJECT_GRAPH Object graph
+
+ 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
+ is "wait/sync/mutex/sql/M"
+ - This mutex instrument has been instantiated twice,
+ mutex instances are noted M-1 and M-2
+ - Threads T-A and T-B are locking mutex instance M-1
+ - Threads T-C and T-D are locking mutex instance M-2
+
+ The performance schema will record the following data:
+ - EVENTS_WAITS_CURRENT has 4 rows, one for each mutex locker
+ - EVENTS_WAITS_SUMMARY_BY_INSTANCE shows 2 rows, for M-1 and M-2
+ - EVENTS_WAITS_SUMMARY_BY_EVENT_NAME shows 1 row, for M
+
+ The graph of structures will look like:
+
+@verbatim
+ PFS_wait_locker (T-A, M-1) ----------
+ |
+ v
+ PFS_mutex (M-1)
+ - m_wait_stat ------------
+ ^ |
+ | |
+ PFS_wait_locker (T-B, M-1) ---------- |
+ v
+ PFS_mutex_class (M)
+ - m_wait_stat
+ PFS_wait_locker (T-C, M-2) ---------- ^
+ | |
+ v |
+ PFS_mutex (M-2) |
+ - m_wait_stat ------------
+ ^
+ |
+ PFS_wait_locker (T-D, M-2) ----------
+
+ || || ||
+ || || ||
+ vv vv vv
+
+ EVENTS_WAITS_CURRENT ..._SUMMARY_BY_INSTANCE ..._SUMMARY_BY_EVENT_NAME
+@endverbatim
+
+ @section ON_THE_FLY On the fly aggregates
+
+ 'On the fly' aggregates are computed during the code execution.
+ 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
+
+ '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
+ - idle
+
+ 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, S)
+ |
+ | [1]
+ |
+ |-> pfs_socket(S) =====>> [A], [B], [C], [D], [E]
+ |
+ | [2]
+ |
+ |-> pfs_socket_class(S.class) =====>> [C], [D]
+ |
+ |-> pfs_thread(T).event_name(S) =====>> [A]
+ |
+ | [3]
+ |
+ 3a |-> pfs_account(U, H).event_name(S) =====>> [F], [G], [H]
+ . |
+ . | [4-RESET]
+ . |
+ 3b .....+-> pfs_user(U).event_name(S) =====>> [G]
+ . |
+ 3c .....+-> pfs_host(H).event_name(S) =====>> [H]
+@endverbatim
+
+ Implemented as:
+ - [1] @c start_socket_wait_v1(), @c end_socket_wait_v1().
+ - [2] @c close_socket_v1()
+ - [3] @c aggregate_thread_waits()
+ - [4] @c PFS_account::aggregate_waits()
+ - [5] @c PFS_host::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_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()
+ - [F] EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME,
+ @c table_ews_by_account_by_event_name::make_row()
+ - [G] EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME,
+ @c table_ews_by_user_by_event_name::make_row()
+ - [H] EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME,
+ @c table_ews_by_host_by_event_name::make_row()
+
+ @subsection IMPL_WAIT_TABLE Table waits
+
+@verbatim
+ table_locker(Thread Th, Table Tb, Event = io or lock)
+ |
+ | [1]
+ |
+1a |-> pfs_table(Tb) =====>> [A], [B], [C]
+ | |
+ | | [2]
+ | |
+ | |-> pfs_table_share(Tb.share) =====>> [B], [C]
+ | |
+ | | [3]
+ | |
+ | |-> global_table_io_stat =====>> [C]
+ | |
+ | |-> global_table_lock_stat =====>> [C]
+ |
+1b |-> pfs_thread(Th).event_name(E) =====>> [D], [E], [F], [G]
+ | |
+ | | [ 4-RESET]
+ | |
+ | |-> pfs_account(U, H).event_name(E) =====>> [E], [F], [G]
+ | . |
+ | . | [5-RESET]
+ | . |
+ | .....+-> pfs_user(U).event_name(E) =====>> [F]
+ | . |
+ | .....+-> pfs_host(H).event_name(E) =====>> [G]
+ |
+1c |-> pfs_thread(Th).waits_current(W) =====>> [H]
+ |
+1d |-> pfs_thread(Th).waits_history(W) =====>> [I]
+ |
+1e |-> waits_history_long(W) =====>> [J]
+@endverbatim
+
+ Implemented as:
+ - [1] @c start_table_io_wait_v1(), @c end_table_io_wait_v1()
+ - [2] @c close_table_v1()
+ - [3] @c drop_table_share_v1()
+ - [4] @c TRUNCATE TABLE EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
+ - [5] @c TRUNCATE TABLE EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME
+ - [A] EVENTS_WAITS_SUMMARY_BY_INSTANCE,
+ @c table_events_waits_summary_by_instance::make_table_row()
+ - [B] OBJECTS_SUMMARY_GLOBAL_BY_TYPE,
+ @c table_os_global_by_type::make_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] EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME,
+ @c table_ews_by_thread_by_event_name::make_row()
+ - [E] EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME,
+ @c table_ews_by_user_by_account_name::make_row()
+ - [F] EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME,
+ @c table_ews_by_user_by_event_name::make_row()
+ - [G] EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME,
+ @c table_ews_by_host_by_event_name::make_row()
+ - [H] EVENTS_WAITS_CURRENT,
+ @c table_events_waits_common::make_row()
+ - [I] EVENTS_WAITS_HISTORY,
+ @c table_events_waits_common::make_row()
+ - [J] EVENTS_WAITS_HISTORY_LONG,
+ @c table_events_waits_common::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()
+*/
+
+/**
+ @defgroup Performance_schema Performance Schema
+ The performance schema component.
+ For details, see the
+ @ref PAGE_PERFORMANCE_SCHEMA "performance schema main page".
+
+ @defgroup Performance_schema_implementation Performance Schema Implementation
+ @ingroup Performance_schema
+
+ @defgroup Performance_schema_tables Performance Schema Tables
+ @ingroup Performance_schema_implementation
+*/
+
+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,
+ OPERATION_TYPE_WRITELOCK,
+ OPERATION_TYPE_TRYREADLOCK,
+ 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,
+ OPERATION_TYPE_TIMEDWAIT
+};
+
+/**
+ Conversion map from PSI_file_operation to enum_operation_type.
+ Indexed by enum PSI_file_operation.
+*/
+static enum_operation_type file_operation_map[]=
+{
+ OPERATION_TYPE_FILECREATE,
+ OPERATION_TYPE_FILECREATETMP,
+ OPERATION_TYPE_FILEOPEN,
+ OPERATION_TYPE_FILESTREAMOPEN,
+ OPERATION_TYPE_FILECLOSE,
+ OPERATION_TYPE_FILESTREAMCLOSE,
+ OPERATION_TYPE_FILEREAD,
+ OPERATION_TYPE_FILEWRITE,
+ OPERATION_TYPE_FILESEEK,
+ OPERATION_TYPE_FILETELL,
+ OPERATION_TYPE_FILEFLUSH,
+ OPERATION_TYPE_FILESTAT,
+ OPERATION_TYPE_FILEFSTAT,
+ OPERATION_TYPE_FILECHSIZE,
+ OPERATION_TYPE_FILEDELETE,
+ OPERATION_TYPE_FILERENAME,
+ OPERATION_TYPE_FILESYNC
+};
+
+/**
+ 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'.
+ This prefix is used later to build each instrument name, such as
+ 'wait/sync/mutex/sql/LOCK_open'.
+ @param prefix Prefix for this class of instruments
+ @param category Category name
+ @param [out] output Buffer of length PFS_MAX_INFO_NAME_LENGTH.
+ @param [out] output_length Length of the resulting output string.
+ @return 0 for success, non zero for errors
+*/
+static int build_prefix(const LEX_STRING *prefix, const char *category,
+ char *output, int *output_length)
+{
+ int len= strlen(category);
+ char *out_ptr= output;
+ int prefix_length= prefix->length;
+
+ if (unlikely((prefix_length + len + 1) >=
+ PFS_MAX_FULL_PREFIX_NAME_LENGTH))
+ {
+ pfs_print_error("build_prefix: prefix+category is too long <%s> <%s>\n",
+ prefix->str, category);
+ return 1;
+ }
+
+ if (unlikely(strchr(category, '/') != NULL))
+ {
+ pfs_print_error("build_prefix: invalid category <%s>\n",
+ category);
+ return 1;
+ }
+
+ /* output = prefix + category + '/' */
+ memcpy(out_ptr, prefix->str, prefix_length);
+ out_ptr+= prefix_length;
+ memcpy(out_ptr, category, len);
+ out_ptr+= len;
+ *out_ptr= '/';
+ out_ptr++;
+ *output_length= out_ptr - output;
+
+ return 0;
+}
+
+#define REGISTER_BODY_V1(KEY_T, PREFIX, REGISTER_FUNC) \
+ KEY_T key; \
+ 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(&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_key != 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); \
+ key= REGISTER_FUNC(formatted_name, full_length, info->m_flags); \
+ } \
+ else \
+ { \
+ pfs_print_error("REGISTER_BODY_V1: name too long <%s> <%s>\n", \
+ category, info->m_name); \
+ key= 0; \
+ } \
+ \
+ *(info->m_key)= key; \
+ } \
+ return;
+
+/* Use C linkage for the interface functions. */
+
+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)
+{
+ REGISTER_BODY_V1(PSI_mutex_key,
+ mutex_instrument_prefix,
+ 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)
+{
+ REGISTER_BODY_V1(PSI_rwlock_key,
+ rwlock_instrument_prefix,
+ 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)
+{
+ REGISTER_BODY_V1(PSI_cond_key,
+ cond_instrument_prefix,
+ 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)
+{
+ REGISTER_BODY_V1(PSI_thread_key,
+ thread_instrument_prefix,
+ 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)
+{
+ REGISTER_BODY_V1(PSI_file_key,
+ file_instrument_prefix,
+ 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; \
+ klass= find_##T##_class(KEY); \
+ if (unlikely(klass == NULL)) \
+ return NULL; \
+ if (! klass->m_enabled) \
+ return NULL; \
+ 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(my_bool temporary, TABLE_SHARE *share)
+{
+ /* 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* 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)
+{
+ 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);
+
+ 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->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(! 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);
+
+ 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);
+ if (unlikely(pfs == NULL))
+ return;
+ pfs->aggregate();
+ destroy_table(pfs);
+}
+
+static PSI_socket*
+init_socket_v1(PSI_socket_key key, const my_socket *fd,
+ const struct sockaddr *addr, socklen_t addr_len)
+{
+ PFS_socket_class *klass;
+ PFS_socket *pfs;
+ klass= find_socket_class(key);
+ if (unlikely(klass == NULL))
+ return NULL;
+ if (! klass->m_enabled)
+ return NULL;
+ pfs= create_socket(klass, fd, addr, addr_len);
+ return reinterpret_cast<PSI_socket *> (pfs);
+}
+
+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_file_class *klass= find_file_class(key);
+ if (unlikely(klass == NULL))
+ return;
+ if (! klass->m_enabled)
+ return;
+
+ /* 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))
+ {
+ file_handle_lost++;
+ return;
+ }
+
+ uint len= strlen(name);
+ PFS_file *pfs_file= find_or_create_file(pfs_thread, klass, name, len, true);
+
+ 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;
+ PSI_thread_key m_child_key;
+ const void *m_child_identity;
+ void *(*m_user_start_routine)(void*);
+ void *m_user_arg;
+};
+
+void* pfs_spawn_thread(void *arg)
+{
+ PFS_spawn_thread_arg *typed_arg= (PFS_spawn_thread_arg*) arg;
+ void *user_arg;
+ void *(*user_start_routine)(void*);
+
+ PFS_thread *pfs;
+
+ /* 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);
+
+ /*
+ Secondly, free the memory allocated in spawn_thread_v1().
+ It is preferable to do this before invoking the user
+ routine, to avoid memory leaks at shutdown, in case
+ the server exits without waiting for this thread.
+ */
+ user_start_routine= typed_arg->m_user_start_routine;
+ user_arg= typed_arg->m_user_arg;
+ my_free(typed_arg);
+
+ /* Then, execute the user code for this thread. */
+ (*user_start_routine)(user_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)
+{
+ PFS_spawn_thread_arg *psi_arg;
+
+ /* psi_arg can not be global, and can not be a local variable. */
+ psi_arg= (PFS_spawn_thread_arg*) my_malloc(sizeof(PFS_spawn_thread_arg),
+ MYF(MY_WME));
+ if (unlikely(psi_arg == NULL))
+ return EAGAIN;
+
+ psi_arg->m_parent_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ psi_arg->m_child_key= key;
+ psi_arg->m_child_identity= (arg ? arg : thread);
+ psi_arg->m_user_start_routine= start_routine;
+ psi_arg->m_user_arg= arg;
+
+ int result= pthread_create(thread, attr, pfs_spawn_thread, psi_arg);
+ if (unlikely(result != 0))
+ my_free(psi_arg);
+ 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, ulonglong processlist_id)
+{
+ PFS_thread *pfs;
+
+ PFS_thread_class *klass= find_thread_class(key);
+ if (likely(klass != NULL))
+ pfs= create_thread(klass, identity, processlist_id);
+ else
+ pfs= NULL;
+
+ 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, ulonglong processlist_id)
+{
+ PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread);
+ if (unlikely(pfs == NULL))
+ return;
+ pfs->m_processlist_id= processlist_id;
+}
+
+/**
+ Implementation of the thread instrumentation interface.
+ @sa PSI_v1::get_thread_id.
+*/
+static PSI_thread*
+get_thread_v1(void)
+{
+ PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ 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_processlist_lock.allocated_to_dirty();
+ pfs->m_processlist_state_ptr= state;
+ pfs->m_processlist_state_length= state_len;
+ pfs->m_processlist_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);
+
+ DBUG_ASSERT((info != NULL) || (info_len == 0));
+
+ if (likely(pfs != NULL))
+ {
+ pfs->m_processlist_lock.allocated_to_dirty();
+ pfs->m_processlist_info_ptr= info;
+ pfs->m_processlist_info_length= info_len;
+ pfs->m_processlist_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*
+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 (! pfs_mutex->m_enabled)
+ return NULL;
+
+ 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_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
+ {
+ 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_mutex_stat.m_wait_stat.aggregate_counted();
+ return NULL;
+ }
+ }
+
+ 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*
+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 (! pfs_rwlock->m_enabled)
+ return NULL;
+
+ 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_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
+ {
+ 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_rwlock_stat.m_wait_stat.aggregate_counted();
+ return NULL;
+ }
+ }
+
+ 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*
+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:
+ In the pthread library, a call to pthread_cond_wait()
+ causes an unlock() + lock() on the mutex associated with the condition.
+ This mutex operation is not instrumented, so the mutex will still
+ appear as locked when a thread is waiting on a condition.
+ This has no impact now, as unlock_mutex() is not recording events.
+ When unlock_mutex() is implemented by later work logs,
+ this parameter here will be used to adjust the mutex state,
+ in start_cond_wait_v1() and end_cond_wait_v1().
+ */
+ 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 (! pfs_cond->m_enabled)
+ return NULL;
+
+ 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_cond_stat.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= pfs_table->m_thread_owner;
+
+ DBUG_ASSERT(pfs_thread ==
+ my_pthread_getspecific_ptr(PFS_thread*, THR_PFS));
+
+ register uint flags;
+ ulonglong timer_start= 0;
+
+ if (flag_thread_instrumentation)
+ {
+ if (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_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++;
+ }
+ }
+ else
+ {
+ 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;
+ }
+ }
+
+ 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*
+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 (! pfs_table->m_lock_enabled)
+ return NULL;
+
+ PFS_thread *pfs_thread= pfs_table->m_thread_owner;
+
+ PFS_TL_LOCK_TYPE lock_type;
+
+ switch (op)
+ {
+ 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);
+ }
+
+ DBUG_ASSERT((uint) lock_type < array_elements(table_lock_operation_map));
+
+ register uint flags;
+ ulonglong timer_start= 0;
+
+ if (flag_thread_instrumentation)
+ {
+ if (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_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++;
+ }
+ }
+ else
+ {
+ 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;
+ }
+ }
+
+ 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,
+ PSI_file_operation op,
+ const char *name, const void *identity)
+{
+ DBUG_ASSERT(static_cast<int> (op) >= 0);
+ DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map));
+ DBUG_ASSERT(state != NULL);
+
+ 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 (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;
+
+ 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= klass;
+ wait->m_timer_start= 0;
+ wait->m_timer_end= 0;
+ wait->m_object_instance_addr= NULL;
+ wait->m_weak_file= NULL;
+ wait->m_weak_version= 0;
+ 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++;
+ }
+
+ state->m_flags= flags;
+ state->m_file= NULL;
+ state->m_name= name;
+ state->m_class= klass;
+ 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(state != NULL);
+
+ if (unlikely(pfs_file == NULL))
+ return NULL;
+ DBUG_ASSERT(pfs_file->m_class != NULL);
+ PFS_file_class *klass= pfs_file->m_class;
+
+ 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= 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
+ {
+ state->m_thread= NULL;
+ if (pfs_file->m_timed)
+ {
+ flags= STATE_FLAG_TIMED;
+ }
+ else
+ {
+ /* TODO: consider a shortcut. */
+ flags= 0;
+ }
+ }
+
+ state->m_flags= flags;
+ state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
+ state->m_operation= op;
+ state->m_name= NULL;
+ state->m_class= klass;
+ 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 (unlikely((index < 0) || (index >= file_handle_max)))
+ return NULL;
+
+ 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;
+
+ if (! pfs_file->m_enabled)
+ return NULL;
+
+ DBUG_ASSERT(pfs_file->m_class != NULL);
+ PFS_file_class *klass= pfs_file->m_class;
+
+ 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= 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
+ {
+ state->m_thread= NULL;
+ if (pfs_file->m_timed)
+ {
+ flags= STATE_FLAG_TIMED;
+ }
+ else
+ {
+ /* TODO: consider a shortcut. */
+ flags= 0;
+ }
+ }
+
+ state->m_flags= flags;
+ state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
+ state->m_operation= op;
+ state->m_name= NULL;
+ state->m_class= klass;
+ return reinterpret_cast<PSI_file_locker*> (state);
+}
+
+/** 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;
+
+ 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_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)
+ {
+ 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;
+ }
+ }
+ }
+
+ 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);
+
+ /*
+ Note that this code is still protected by the instrumented mutex,
+ and therefore is thread safe. See inline_mysql_mutex_unlock().
+ */
+
+ /* Always update the instrumented state */
+ pfs_mutex->m_owner= NULL;
+ pfs_mutex->m_last_locked= 0;
+
+#ifdef LATER_WL2333
+ /*
+ See WL#2333: SHOW ENGINE ... LOCK STATUS.
+ PFS_mutex::m_lock_stat is not exposed in user visible tables
+ currently, so there is no point spending time computing it.
+ */
+ if (! pfs_mutex->m_enabled)
+ return;
+
+ if (! pfs_mutex->m_timed)
+ return;
+
+ ulonglong locked_time;
+ locked_time= get_timer_pico_value(wait_timer) - pfs_mutex->m_last_locked;
+ pfs_mutex->m_mutex_stat.m_lock_stat.aggregate_value(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;
+
+ /*
+ Note that this code is still protected by the instrumented rwlock,
+ and therefore is:
+ - thread safe for write locks
+ - almost thread safe for read locks (pfs_rwlock->m_readers is unsafe).
+ See inline_mysql_rwlock_unlock()
+ */
+
+ /* Always update the instrumented state */
+ if (pfs_rwlock->m_writer != NULL)
+ {
+ /* Nominal case, a writer is unlocking. */
+ last_writer= true;
+ pfs_rwlock->m_writer= NULL;
+ /* Reset the readers stats, they could be off */
+ pfs_rwlock->m_readers= 0;
+ }
+ else if (likely(pfs_rwlock->m_readers > 0))
+ {
+ /* Nominal case, a reader is unlocking. */
+ if (--(pfs_rwlock->m_readers) == 0)
+ last_reader= true;
+ }
+ else
+ {
+ /*
+ Edge case, we have no writer and no readers,
+ on an unlock event.
+ This is possible for:
+ - partial instrumentation
+ - instrumentation disabled at runtime,
+ see when get_thread_rwlock_locker_v1() returns NULL
+ No further action is taken here, the next
+ write lock will put the statistics is a valid state.
+ */
+ }
+
+#ifdef LATER_WL2333
+ /* See WL#2333: SHOW ENGINE ... LOCK STATUS. */
+
+ if (! pfs_rwlock->m_enabled)
+ return;
+
+ if (! pfs_rwlock->m_timed)
+ return;
+
+ ulonglong locked_time;
+ if (last_writer)
+ {
+ locked_time= get_timer_pico_value(wait_timer) - pfs_rwlock->m_last_written;
+ pfs_rwlock->m_rwlock_stat.m_write_lock_stat.aggregate_value(locked_time);
+ }
+ else if (last_reader)
+ {
+ locked_time= get_timer_pico_value(wait_timer) - pfs_rwlock->m_last_read;
+ pfs_rwlock->m_rwlock_stat.m_read_lock_stat.aggregate_value(locked_time);
+ }
+#else
+ (void) last_reader;
+ (void) last_writer;
+#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++;
+}
+
+/**
+ 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)
+{
+ 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;
+ }
+
+ 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
+ {
+ 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;
+ }
+ }
+
+ state->m_flags= flags;
+ return reinterpret_cast<PSI_idle_locker*> (state);
+}
+
+/**
+ Implementation of the mutex instrumentation interface.
+ @sa PSI_v1::end_idle_wait.
+*/
+static void end_idle_wait_v1(PSI_idle_locker* locker)
+{
+ 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 (flags & STATE_FLAG_TIMED)
+ {
+ timer_end= state->m_timer();
+ wait_time= timer_end - state->m_timer_start;
+ }
+
+ if (flags & STATE_FLAG_THREAD)
+ {
+ 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;
+
+ if (flags & STATE_FLAG_TIMED)
+ {
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
+ event_name_array[GLOBAL_IDLE_EVENT_INDEX].aggregate_value(wait_time);
+ }
+ else
+ {
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
+ event_name_array[GLOBAL_IDLE_EVENT_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--;
+ }
+ }
+
+ if (flags & STATE_FLAG_TIMED)
+ {
+ /* Aggregate to EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME (timed) */
+ global_idle_stat.aggregate_value(wait_time);
+ }
+ else
+ {
+ /* Aggregate to EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME (counted) */
+ global_idle_stat.aggregate_counted();
+ }
+}
+
+/**
+ Implementation of the mutex instrumentation interface.
+ @sa PSI_v1::end_mutex_wait.
+*/
+static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc)
+{
+ PSI_mutex_locker_state *state= reinterpret_cast<PSI_mutex_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
+
+ 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_mutex_stat.m_wait_stat.aggregate_value(wait_time);
+ }
+ else
+ {
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
+ mutex->m_mutex_stat.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--;
+ }
+ }
+}
+
+/**
+ Implementation of the rwlock instrumentation interface.
+ @sa PSI_v1::end_rwlock_rdwait.
+*/
+static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc)
+{
+ PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
+
+ ulonglong timer_end= 0;
+ ulonglong wait_time= 0;
+
+ 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_rwlock_stat.m_wait_stat.aggregate_value(wait_time);
+ }
+ else
+ {
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
+ rwlock->m_rwlock_stat.m_wait_stat.aggregate_counted();
+ }
+
+ if (rc == 0)
+ {
+ /*
+ Warning:
+ Multiple threads can execute this section concurrently
+ (since multiple readers can execute in parallel).
+ The statistics generated are not safe, which is why they are
+ just statistics, not facts.
+ */
+ if (rwlock->m_readers == 0)
+ 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 (state->m_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_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--;
+ }
+ }
+}
+
+/**
+ Implementation of the rwlock instrumentation interface.
+ @sa PSI_v1::end_rwlock_wrwait.
+*/
+static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc)
+{
+ PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
+
+ 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_rwlock_stat.m_wait_stat.aggregate_value(wait_time);
+ }
+ else
+ {
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
+ rwlock->m_rwlock_stat.m_wait_stat.aggregate_counted();
+ }
+
+ if (likely(rc == 0))
+ {
+ /* Thread safe : we are protected by the instrumented rwlock */
+ 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 (state->m_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_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--;
+ }
+ }
+}
+
+/**
+ Implementation of the cond instrumentation interface.
+ @sa PSI_v1::end_cond_wait.
+*/
+static void end_cond_wait_v1(PSI_cond_locker* locker, int rc)
+{
+ PSI_cond_locker_state *state= reinterpret_cast<PSI_cond_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
+
+ ulonglong timer_end= 0;
+ ulonglong wait_time= 0;
+
+ 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_cond_stat.m_wait_stat.aggregate_value(wait_time);
+ }
+ else
+ {
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
+ cond->m_cond_stat.m_wait_stat.aggregate_counted();
+ }
+
+ 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= cond->m_class->m_event_name_index;
+
+ if (state->m_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_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--;
+ }
+ }
+}
+
+/**
+ Implementation of the table instrumentation interface.
+ @sa PSI_v1::end_table_io_wait.
+*/
+static void end_table_io_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);
+
+ PFS_single_stat *stat;
+ PFS_table_io_stat *table_io_stat;
+
+ DBUG_ASSERT((state->m_index < table->m_share->m_key_count) ||
+ (state->m_index == MAX_INDEXES));
+
+ table_io_stat= & table->m_table_stat.m_index_stat[state->m_index];
+ table_io_stat->m_has_data= true;
+
+ switch (state->m_io_operation)
+ {
+ case PSI_TABLE_FETCH_ROW:
+ stat= & table_io_stat->m_fetch;
+ break;
+ case PSI_TABLE_WRITE_ROW:
+ stat= & table_io_stat->m_insert;
+ break;
+ case PSI_TABLE_UPDATE_ROW:
+ stat= & table_io_stat->m_update;
+ break;
+ case PSI_TABLE_DELETE_ROW:
+ stat= & table_io_stat->m_delete;
+ break;
+ default:
+ DBUG_ASSERT(false);
+ stat= NULL;
+ break;
+ }
+
+ 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 (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;
+
+ /*
+ Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
+ (for wait/io/table/sql/handler)
+ */
+ if (flags & STATE_FLAG_TIMED)
+ {
+ event_name_array[GLOBAL_TABLE_IO_EVENT_INDEX].aggregate_value(wait_time);
+ }
+ else
+ {
+ event_name_array[GLOBAL_TABLE_IO_EVENT_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--;
+ }
+ }
+
+ 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);
+
+ 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)
+ {
+ timer_end= state->m_timer();
+ wait_time= timer_end - state->m_timer_start;
+ stat->aggregate_value(wait_time);
+ }
+ else
+ {
+ stat->aggregate_counted();
+ }
+
+ if (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;
+
+ /*
+ Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
+ (for wait/lock/table/sql/handler)
+ */
+ if (flags & STATE_FLAG_TIMED)
+ {
+ event_name_array[GLOBAL_TABLE_LOCK_EVENT_INDEX].aggregate_value(wait_time);
+ }
+ else
+ {
+ event_name_array[GLOBAL_TABLE_LOCK_EVENT_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--;
+ }
+ }
+
+ table->m_has_lock_stats= true;
+}
+
+static void start_file_wait_v1(PSI_file_locker *locker,
+ size_t count,
+ const char *src_file,
+ uint src_line);
+
+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 void start_file_open_wait_v1(PSI_file_locker *locker,
+ const char *src_file,
+ uint src_line)
+{
+ start_file_wait_v1(locker, 0, src_file, src_line);
+
+ return;
+}
+
+/**
+ Implementation of the file instrumentation interface.
+ @sa PSI_v1::end_file_open_wait.
+*/
+static PSI_file* end_file_open_wait_v1(PSI_file_locker *locker,
+ void *result)
+{
+ PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
+
+ switch (state->m_operation)
+ {
+ case PSI_FILE_STAT:
+ break;
+ case PSI_FILE_STREAM_OPEN:
+ case PSI_FILE_CREATE:
+ if (result != NULL)
+ {
+ PFS_file_class *klass= reinterpret_cast<PFS_file_class*> (state->m_class);
+ PFS_thread *thread= reinterpret_cast<PFS_thread*> (state->m_thread);
+ const char *name= state->m_name;
+ uint len= strlen(name);
+ PFS_file *pfs_file= find_or_create_file(thread, klass, name, len, true);
+ state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
+ }
+ break;
+ case PSI_FILE_OPEN:
+ default:
+ DBUG_ASSERT(false);
+ break;
+ }
+
+ end_file_wait_v1(locker, 0);
+
+ return state->m_file;
+}
+
+/**
+ 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)
+{
+ PFS_file *pfs_file= NULL;
+ int index= (int) file;
+ PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
+
+ if (index >= 0)
+ {
+ PFS_file_class *klass= reinterpret_cast<PFS_file_class*> (state->m_class);
+ PFS_thread *thread= reinterpret_cast<PFS_thread*> (state->m_thread);
+ const char *name= state->m_name;
+ uint len= strlen(name);
+ pfs_file= find_or_create_file(thread, klass, name, len, true);
+ state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
+ }
+
+ end_file_wait_v1(locker, 0);
+
+ if (likely(index >= 0))
+ {
+ if (likely(index < file_handle_max))
+ file_handle_array[index]= pfs_file;
+ else
+ {
+ if (pfs_file != NULL)
+ release_file(pfs_file);
+ file_handle_lost++;
+ }
+ }
+}
+
+/**
+ 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)
+{
+ 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;
+
+ if (flags & STATE_FLAG_TIMED)
+ {
+ 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;
+ }
+}
+
+/**
+ Implementation of the file instrumentation interface.
+ @sa PSI_v1::end_file_wait.
+*/
+static void end_file_wait_v1(PSI_file_locker *locker,
+ size_t byte_count)
+{
+ 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);
+ PFS_file_class *klass= reinterpret_cast<PFS_file_class *> (state->m_class);
+ 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);
+
+ PFS_file_stat *file_stat;
+
+ if (file != NULL)
+ {
+ file_stat= & file->m_file_stat;
+ }
+ else
+ {
+ file_stat= & klass->m_file_stat;
+ }
+
+ switch (state->m_operation)
+ {
+ /* Group read operations */
+ case PSI_FILE_READ:
+ byte_stat= &file_stat->m_io_stat.m_read;
+ break;
+ /* Group write operations */
+ case PSI_FILE_WRITE:
+ byte_stat= &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_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 EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
+ byte_stat->aggregate(wait_time, bytes);
+ }
+ else
+ {
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
+ byte_stat->aggregate_counted(bytes);
+ }
+
+ 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= klass->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;
+ wait->m_object_instance_addr= file;
+ wait->m_weak_file= file;
+ wait->m_weak_version= (file ? file->get_version() : 0);
+
+ 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--;
+ }
+ }
+}
+
+/**
+ Implementation of the file instrumentation interface.
+ @sa PSI_v1::start_file_close_wait.
+*/
+static void start_file_close_wait_v1(PSI_file_locker *locker,
+ const char *src_file,
+ uint src_line)
+{
+ PFS_thread *thread;
+ const char *name;
+ uint len;
+ PFS_file *pfs_file;
+ PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
+
+ switch (state->m_operation)
+ {
+ case PSI_FILE_DELETE:
+ thread= reinterpret_cast<PFS_thread*> (state->m_thread);
+ name= state->m_name;
+ len= strlen(name);
+ pfs_file= find_or_create_file(thread, NULL, name, len, false);
+ state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
+ break;
+ case PSI_FILE_STREAM_CLOSE:
+ case PSI_FILE_CLOSE:
+ break;
+ default:
+ DBUG_ASSERT(false);
+ break;
+ }
+
+ start_file_wait_v1(locker, 0, src_file, src_line);
+
+ return;
+}
+
+/**
+ Implementation of the file instrumentation interface.
+ @sa PSI_v1::end_file_close_wait.
+*/
+static void end_file_close_wait_v1(PSI_file_locker *locker, int rc)
+{
+ PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
+
+ end_file_wait_v1(locker, 0);
+
+ if (rc == 0)
+ {
+ PFS_thread *thread= reinterpret_cast<PFS_thread*> (state->m_thread);
+ PFS_file *file= reinterpret_cast<PFS_file*> (state->m_file);
+
+ /* Release or destroy the file if necessary */
+ switch(state->m_operation)
+ {
+ case PSI_FILE_CLOSE:
+ case PSI_FILE_STREAM_CLOSE:
+ if (file != NULL)
+ release_file(file);
+ break;
+ case PSI_FILE_DELETE:
+ if (file != NULL)
+ destroy_file(thread, file);
+ break;
+ default:
+ DBUG_ASSERT(false);
+ break;
+ }
+ }
+ return;
+}
+
+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;
+
+ 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,
+ const void *charset)
+{
+ 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)
+ {
+ const CHARSET_INFO *cs= static_cast <const CHARSET_INFO*> (charset);
+ flags|= STATE_FLAG_DIGEST;
+ state->m_digest_state.m_last_id_index= 0;
+ digest_reset(& state->m_digest_state.m_digest_storage);
+ state->m_digest_state.m_digest_storage.m_charset_number= cs->number;
+ }
+
+ 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;
+
+ state->m_schema_name_length= 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;
+ }
+
+ compile_time_assert(PSI_SCHEMA_NAME_LEN == NAME_LEN);
+ DBUG_ASSERT(db_len <= sizeof(state->m_schema_name));
+
+ if (db_len > 0)
+ memcpy(state->m_schema_name, db, db_len);
+ state->m_schema_name_length= db_len;
+
+ 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,
+ state->m_schema_name,
+ state->m_schema_name_length);
+ }
+
+ 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 statements_digest_stat with computed digest information. */
+ digest_stat= find_or_create_digest(thread, digest_storage,
+ state->m_schema_name,
+ state->m_schema_name_length);
+ }
+ }
+
+ 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 thread attribute connection interface
+ @sa PSI_v1::set_thread_connect_attr.
+*/
+static int set_thread_connect_attrs_v1(const char *buffer, uint length,
+ const void *from_cs)
+{
+
+ PFS_thread *thd= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+
+ DBUG_ASSERT(buffer != NULL);
+
+ if (likely(thd != NULL) && session_connect_attrs_size_per_thread > 0)
+ {
+ /* copy from the input buffer as much as we can fit */
+ uint copy_size= (uint)(length < session_connect_attrs_size_per_thread ?
+ length : session_connect_attrs_size_per_thread);
+ thd->m_lock.allocated_to_dirty();
+ memcpy(thd->m_session_connect_attrs, buffer, copy_size);
+ thd->m_session_connect_attrs_length= copy_size;
+ thd->m_session_connect_attrs_cs= (const CHARSET_INFO *) from_cs;
+ thd->m_lock.dirty_to_allocated();
+
+ if (copy_size == length)
+ return 0;
+ else
+ {
+ session_connect_attrs_lost++;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ Implementation of the instrumentation interface.
+ @sa PSI_v1.
+*/
+PSI_v1 PFS_v1=
+{
+ register_mutex_v1,
+ register_rwlock_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_file_name_locker_v1,
+ get_thread_file_stream_locker_v1,
+ get_thread_file_descriptor_locker_v1,
+ unlock_mutex_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_wait_v1, /* read */
+ end_rwlock_rdwait_v1,
+ start_rwlock_wait_v1, /* write */
+ end_rwlock_wrwait_v1,
+ start_cond_wait_v1,
+ end_cond_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,
+ start_file_close_wait_v1,
+ end_file_close_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,
+ set_thread_connect_attrs_v1,
+};
+
+static void* get_interface(int version)
+{
+ switch (version)
+ {
+ case PSI_VERSION_1:
+ return &PFS_v1;
+ default:
+ return NULL;
+ }
+}
+
+C_MODE_END
+
+struct PSI_bootstrap PFS_bootstrap=
+{
+ get_interface
+};
diff --git a/storage/perfschema/pfs.h b/storage/perfschema/pfs.h
new file mode 100644
index 00000000000..5f543d80375
--- /dev/null
+++ b/storage/perfschema/pfs.h
@@ -0,0 +1,41 @@
+/* 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 PFS_H
+#define PFS_H
+
+/**
+ @file storage/perfschema/pfs.h
+ Performance schema instrumentation (declarations).
+*/
+
+#define HAVE_PSI_1
+
+#include <my_global.h>
+#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..d3e58ed90f8
--- /dev/null
+++ b/storage/perfschema/pfs_account.cc
@@ -0,0 +1,576 @@
+/* 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;
+
+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) && (account_max > 0))
+ {
+ lf_hash_init(&account_hash, sizeof(PFS_account*), LF_HASH_UNIQUE,
+ 0, 0, account_hash_get_key, &my_charset_bin);
+ account_hash.size= account_max;
+ 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))
+ {
+ PFS_account *pfs;
+ pfs= *entry;
+ DBUG_ASSERT(pfs == 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..1ac379e0fc9
--- /dev/null
+++ b/storage/perfschema/pfs_account.h
@@ -0,0 +1,122 @@
+/* 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_ALIGNED 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;
+
+extern LF_HASH account_hash;
+
+/** @} */
+#endif
+
diff --git a/storage/perfschema/pfs_atomic.cc b/storage/perfschema/pfs_atomic.cc
new file mode 100644
index 00000000000..06090accdc6
--- /dev/null
+++ b/storage/perfschema/pfs_atomic.cc
@@ -0,0 +1,78 @@
+/* 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
+ 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_atomic.cc
+ Atomic operations (implementation).
+*/
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include "pfs_atomic.h"
+
+/*
+ Using SAFE_MUTEX is impossible, because of recursion.
+ - code locks mutex X
+ - P_S records the event
+ - P_S needs an atomic counter A
+ - safe mutex called for m_mutex[hash(A)]
+ - safe mutex allocates/free memory
+ - safe mutex locks THR_LOCK_malloc
+ - P_S records the event
+ - P_S needs an atomic counter B
+ - safe mutex called for m_mutex[hash(B)]
+
+ When hash(A) == hash(B), safe_mutex complains rightly that
+ the mutex is already locked.
+ In some cases, A == B, in particular for events_waits_history_long_index.
+
+ In short, the implementation of PFS_atomic should not cause events
+ to be recorded in the performance schema.
+
+ Also, because SAFE_MUTEX redefines pthread_mutex_t, etc,
+ this code is not inlined in pfs_atomic.h, but located here in pfs_atomic.cc.
+
+ What is needed is a plain, unmodified, pthread_mutex_t.
+ This is provided by my_atomic_rwlock_t.
+*/
+
+/**
+ Internal rwlock array.
+ Using a single rwlock for all atomic operations would be a bottleneck.
+ Using a rwlock per performance schema structure would be too costly in
+ memory, and use too many rwlock.
+ The PFS_atomic implementation computes a hash value from the
+ atomic variable, to spread the bottleneck across 256 buckets,
+ while still providing --transparently for the caller-- an atomic
+ operation.
+*/
+my_atomic_rwlock_t PFS_atomic::m_rwlock_array[256];
+
+void PFS_atomic::init(void)
+{
+ uint i;
+
+ for (i=0; i< array_elements(m_rwlock_array); i++)
+ my_atomic_rwlock_init(&m_rwlock_array[i]);
+}
+
+void PFS_atomic::cleanup(void)
+{
+ uint i;
+
+ for (i=0; i< array_elements(m_rwlock_array); i++)
+ my_atomic_rwlock_destroy(&m_rwlock_array[i]);
+}
+
diff --git a/storage/perfschema/pfs_atomic.h b/storage/perfschema/pfs_atomic.h
new file mode 100644
index 00000000000..61b8c2b2804
--- /dev/null
+++ b/storage/perfschema/pfs_atomic.h
@@ -0,0 +1,249 @@
+/* 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
+ 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_ATOMIC_H
+#define PFS_ATOMIC_H
+
+/**
+ @file storage/perfschema/pfs_atomic.h
+ Atomic operations (declarations).
+*/
+
+#include <my_atomic.h>
+
+/** Helper for atomic operations. */
+class PFS_atomic
+{
+public:
+ /** Initialise the PFS_atomic component. */
+ static void init();
+ /** Cleanup the PFS_atomic component. */
+ static void cleanup();
+
+ /** Atomic load. */
+ static inline int32 load_32(volatile int32 *ptr)
+ {
+ int32 result;
+ rdlock(ptr);
+ result= my_atomic_load32(ptr);
+ rdunlock(ptr);
+ return result;
+ }
+
+ /** Atomic load. */
+ static inline int64 load_64(volatile int64 *ptr)
+ {
+ int64 result;
+ rdlock(ptr);
+ result= my_atomic_load64(ptr);
+ rdunlock(ptr);
+ return result;
+ }
+
+ /** Atomic load. */
+ static inline uint32 load_u32(volatile uint32 *ptr)
+ {
+ uint32 result;
+ rdlock(ptr);
+ result= (uint32) my_atomic_load32((int32*) ptr);
+ rdunlock(ptr);
+ return result;
+ }
+
+ /** Atomic load. */
+ static inline uint64 load_u64(volatile uint64 *ptr)
+ {
+ uint64 result;
+ rdlock(ptr);
+ result= (uint64) my_atomic_load64((int64*) ptr);
+ rdunlock(ptr);
+ return result;
+ }
+
+ /** Atomic store. */
+ static inline void store_32(volatile int32 *ptr, int32 value)
+ {
+ wrlock(ptr);
+ my_atomic_store32(ptr, value);
+ wrunlock(ptr);
+ }
+
+ /** Atomic store. */
+ static inline void store_64(volatile int64 *ptr, int64 value)
+ {
+ wrlock(ptr);
+ my_atomic_store64(ptr, value);
+ wrunlock(ptr);
+ }
+
+ /** Atomic store. */
+ static inline void store_u32(volatile uint32 *ptr, uint32 value)
+ {
+ wrlock(ptr);
+ my_atomic_store32((int32*) ptr, (int32) value);
+ wrunlock(ptr);
+ }
+
+ /** Atomic store. */
+ static inline void store_u64(volatile uint64 *ptr, uint64 value)
+ {
+ wrlock(ptr);
+ my_atomic_store64((int64*) ptr, (int64) value);
+ wrunlock(ptr);
+ }
+
+ /** Atomic add. */
+ static inline int32 add_32(volatile int32 *ptr, int32 value)
+ {
+ int32 result;
+ wrlock(ptr);
+ result= my_atomic_add32(ptr, value);
+ wrunlock(ptr);
+ return result;
+ }
+
+ /** Atomic add. */
+ static inline int64 add_64(volatile int64 *ptr, int64 value)
+ {
+ int64 result;
+ wrlock(ptr);
+ result= my_atomic_add64(ptr, value);
+ wrunlock(ptr);
+ return result;
+ }
+
+ /** Atomic add. */
+ static inline uint32 add_u32(volatile uint32 *ptr, uint32 value)
+ {
+ uint32 result;
+ wrlock(ptr);
+ result= (uint32) my_atomic_add32((int32*) ptr, (int32) value);
+ wrunlock(ptr);
+ return result;
+ }
+
+ /** Atomic add. */
+ static inline uint64 add_u64(volatile uint64 *ptr, uint64 value)
+ {
+ uint64 result;
+ wrlock(ptr);
+ result= (uint64) my_atomic_add64((int64*) ptr, (int64) value);
+ wrunlock(ptr);
+ return result;
+ }
+
+ /** Atomic compare and swap. */
+ static inline bool cas_32(volatile int32 *ptr, int32 *old_value,
+ int32 new_value)
+ {
+ bool result;
+ wrlock(ptr);
+ result= my_atomic_cas32(ptr, old_value, new_value);
+ wrunlock(ptr);
+ return result;
+ }
+
+ /** Atomic compare and swap. */
+ static inline bool cas_64(volatile int64 *ptr, int64 *old_value,
+ int64 new_value)
+ {
+ bool result;
+ wrlock(ptr);
+ result= my_atomic_cas64(ptr, old_value, new_value);
+ wrunlock(ptr);
+ return result;
+ }
+
+ /** Atomic compare and swap. */
+ static inline bool cas_u32(volatile uint32 *ptr, uint32 *old_value,
+ uint32 new_value)
+ {
+ bool result;
+ wrlock(ptr);
+ result= my_atomic_cas32((int32*) ptr, (int32*) old_value,
+ (uint32) new_value);
+ wrunlock(ptr);
+ return result;
+ }
+
+ /** Atomic compare and swap. */
+ static inline bool cas_u64(volatile uint64 *ptr, uint64 *old_value,
+ uint64 new_value)
+ {
+ bool result;
+ wrlock(ptr);
+ result= my_atomic_cas64((int64*) ptr, (int64*) old_value,
+ (uint64) new_value);
+ wrunlock(ptr);
+ return result;
+ }
+
+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)
+ {
+ /*
+ Divide an address by 8 to remove alignment,
+ modulo 256 to fall in the array.
+ */
+ uint index= (((intptr) ptr) >> 3) & 0xFF;
+ my_atomic_rwlock_t *result= &m_rwlock_array[index];
+ 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));
+ }
+};
+
+#endif
+
diff --git a/storage/perfschema/pfs_autosize.cc b/storage/perfschema/pfs_autosize.cc
new file mode 100644
index 00000000000..38bd36d8321
--- /dev/null
+++ b/storage/perfschema/pfs_autosize.cc
@@ -0,0 +1,366 @@
+/* Copyright (c) 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 */
+
+/**
+ @file storage/perfschema/pfs_autosize.cc
+ Private interface for the server (implementation).
+*/
+
+#include "my_global.h"
+#include "sql_const.h"
+#include "pfs_server.h"
+
+#include <algorithm>
+using std::min;
+using std::max;
+
+static const ulong fixed_mutex_instances= 500;
+static const ulong fixed_rwlock_instances= 200;
+static const ulong fixed_cond_instances= 50;
+static const ulong fixed_file_instances= 200;
+static const ulong fixed_socket_instances= 10;
+static const ulong fixed_thread_instances= 50;
+
+static const ulong mutex_per_connection= 3;
+static const ulong rwlock_per_connection= 1;
+static const ulong cond_per_connection= 2;
+static const ulong file_per_connection= 0;
+static const ulong socket_per_connection= 1;
+static const ulong thread_per_connection= 1;
+
+static const ulong mutex_per_handle= 0;
+static const ulong rwlock_per_handle= 0;
+static const ulong cond_per_handle= 0;
+static const ulong file_per_handle= 0;
+static const ulong socket_per_handle= 0;
+static const ulong thread_per_handle= 0;
+
+static const ulong mutex_per_share= 5;
+static const ulong rwlock_per_share= 3;
+static const ulong cond_per_share= 1;
+static const ulong file_per_share= 3;
+static const ulong socket_per_share= 0;
+static const ulong thread_per_share= 0;
+
+struct PFS_sizing_data
+{
+ /** Default value for @c PFS_param.m_account_sizing. */
+ ulong m_account_sizing;
+ /** Default value for @c PFS_param.m_user_sizing. */
+ ulong m_user_sizing;
+ /** Default value for @c PFS_param.m_host_sizing. */
+ ulong m_host_sizing;
+
+ /** Default value for @c PFS_param.m_events_waits_history_sizing. */
+ ulong m_events_waits_history_sizing;
+ /** Default value for @c PFS_param.m_events_waits_history_long_sizing. */
+ ulong m_events_waits_history_long_sizing;
+ /** Default value for @c PFS_param.m_events_stages_history_sizing. */
+ ulong m_events_stages_history_sizing;
+ /** Default value for @c PFS_param.m_events_stages_history_long_sizing. */
+ ulong m_events_stages_history_long_sizing;
+ /** Default value for @c PFS_param.m_events_statements_history_sizing. */
+ ulong m_events_statements_history_sizing;
+ /** Default value for @c PFS_param.m_events_statements_history_long_sizing. */
+ ulong m_events_statements_history_long_sizing;
+ /** Default value for @c PFS_param.m_digest_sizing. */
+ ulong m_digest_sizing;
+ /** Default value for @c PFS_param.m_session_connect_attrs_sizing. */
+ ulong m_session_connect_attrs_sizing;
+
+ /**
+ Minimum number of tables to keep statistics for.
+ On small deployments, all the tables can fit into the table definition cache,
+ and this value can be 0.
+ On big deployments, the table definition cache is only a subset of all the tables
+ in the database, which are accounted for here.
+ */
+ ulong m_min_number_of_tables;
+
+ /**
+ Load factor for 'volatile' objects (mutexes, table handles, ...).
+ Instrumented objects that:
+ - use little memory
+ - are created/destroyed very frequently
+ should be stored in a low density (mostly empty) memory buffer,
+ to optimize for speed.
+ */
+ float m_load_factor_volatile;
+ /**
+ Load factor for 'normal' objects (files).
+ Instrumented objects that:
+ - use a medium amount of memory
+ - are created/destroyed
+ should be stored in a medium density memory buffer,
+ as a trade off between space and speed.
+ */
+ float m_load_factor_normal;
+ /**
+ Load factor for 'static' objects (table shares).
+ Instrumented objects that:
+ - use a lot of memory
+ - are created/destroyed very rarely
+ can be stored in a high density (mostly packed) memory buffer,
+ to optimize for space.
+ */
+ float m_load_factor_static;
+};
+
+PFS_sizing_data small_data=
+{
+ /* Account / user / host */
+ 10, 5, 20,
+ /* History sizes */
+ 5, 100, 5, 100, 5, 100,
+ /* Digests */
+ 1000,
+ /* Session connect attrs. */
+ 512,
+ /* Min tables */
+ 200,
+ /* Load factors */
+ 0.90, 0.90, 0.90
+};
+
+PFS_sizing_data medium_data=
+{
+ /* Account / user / host */
+ 100, 100, 100,
+ /* History sizes */
+ 10, 1000, 10, 1000, 10, 1000,
+ /* Digests */
+ 5000,
+ /* Session connect attrs. */
+ 512,
+ /* Min tables */
+ 500,
+ /* Load factors */
+ 0.70, 0.80, 0.90
+};
+
+PFS_sizing_data large_data=
+{
+ /* Account / user / host */
+ 100, 100, 100,
+ /* History sizes */
+ 10, 10000, 10, 10000, 10, 10000,
+ /* Digests */
+ 10000,
+ /* Session connect attrs. */
+ 512,
+ /* Min tables */
+ 10000,
+ /* Load factors */
+ 0.50, 0.65, 0.80
+};
+
+static inline ulong apply_load_factor(ulong raw_value, float factor)
+{
+ float value = ((float) raw_value) / factor;
+ return (ulong) ceil(value);
+}
+
+PFS_sizing_data *estimate_hints(PFS_global_param *param)
+{
+ if ((param->m_hints.m_max_connections <= MAX_CONNECTIONS_DEFAULT) &&
+ (param->m_hints.m_table_definition_cache <= TABLE_DEF_CACHE_DEFAULT) &&
+ (param->m_hints.m_table_open_cache <= TABLE_OPEN_CACHE_DEFAULT))
+ {
+ /* The my.cnf used is either unchanged, or lower than factory defaults. */
+ return & small_data;
+ }
+
+ if ((param->m_hints.m_max_connections <= MAX_CONNECTIONS_DEFAULT * 2) &&
+ (param->m_hints.m_table_definition_cache <= TABLE_DEF_CACHE_DEFAULT * 2) &&
+ (param->m_hints.m_table_open_cache <= TABLE_OPEN_CACHE_DEFAULT * 2))
+ {
+ /* Some defaults have been increased, to "moderate" values. */
+ return & medium_data;
+ }
+
+ /* Looks like a server in production. */
+ return & large_data;
+}
+
+static void apply_heuristic(PFS_global_param *p, PFS_sizing_data *h)
+{
+ ulong count;
+ ulong con = p->m_hints.m_max_connections;
+ ulong handle = p->m_hints.m_table_open_cache;
+ ulong share = p->m_hints.m_table_definition_cache;
+ ulong file = p->m_hints.m_open_files_limit;
+
+ if (p->m_table_sizing < 0)
+ {
+ count= handle;
+
+ p->m_table_sizing= apply_load_factor(count, h->m_load_factor_volatile);
+ }
+
+ if (p->m_table_share_sizing < 0)
+ {
+ count= share;
+
+ count= max<ulong>(count, h->m_min_number_of_tables);
+ p->m_table_share_sizing= apply_load_factor(count, h->m_load_factor_static);
+ }
+
+ if (p->m_account_sizing < 0)
+ {
+ p->m_account_sizing= h->m_account_sizing;
+ }
+
+ if (p->m_user_sizing < 0)
+ {
+ p->m_user_sizing= h->m_user_sizing;
+ }
+
+ if (p->m_host_sizing < 0)
+ {
+ p->m_host_sizing= h->m_host_sizing;
+ }
+
+ if (p->m_events_waits_history_sizing < 0)
+ {
+ p->m_events_waits_history_sizing= h->m_events_waits_history_sizing;
+ }
+
+ if (p->m_events_waits_history_long_sizing < 0)
+ {
+ p->m_events_waits_history_long_sizing= h->m_events_waits_history_long_sizing;
+ }
+
+ if (p->m_events_stages_history_sizing < 0)
+ {
+ p->m_events_stages_history_sizing= h->m_events_stages_history_sizing;
+ }
+
+ if (p->m_events_stages_history_long_sizing < 0)
+ {
+ p->m_events_stages_history_long_sizing= h->m_events_stages_history_long_sizing;
+ }
+
+ if (p->m_events_statements_history_sizing < 0)
+ {
+ p->m_events_statements_history_sizing= h->m_events_statements_history_sizing;
+ }
+
+ if (p->m_events_statements_history_long_sizing < 0)
+ {
+ p->m_events_statements_history_long_sizing= h->m_events_statements_history_long_sizing;
+ }
+
+ if (p->m_digest_sizing < 0)
+ {
+ p->m_digest_sizing= h->m_digest_sizing;
+ }
+
+ if (p->m_session_connect_attrs_sizing < 0)
+ {
+ p->m_session_connect_attrs_sizing= h->m_session_connect_attrs_sizing;
+ }
+
+ if (p->m_mutex_sizing < 0)
+ {
+ count= fixed_mutex_instances
+ + con * mutex_per_connection
+ + handle * mutex_per_handle
+ + share * mutex_per_share;
+
+ p->m_mutex_sizing= apply_load_factor(count, h->m_load_factor_volatile);
+ }
+
+ if (p->m_rwlock_sizing < 0)
+ {
+ count= fixed_rwlock_instances
+ + con * rwlock_per_connection
+ + handle * rwlock_per_handle
+ + share * rwlock_per_share;
+
+ p->m_rwlock_sizing= apply_load_factor(count, h->m_load_factor_volatile);
+ }
+
+ if (p->m_cond_sizing < 0)
+ {
+ ulong count;
+ count= fixed_cond_instances
+ + con * cond_per_connection
+ + handle * cond_per_handle
+ + share * cond_per_share;
+
+ p->m_cond_sizing= apply_load_factor(count, h->m_load_factor_volatile);
+ }
+
+ if (p->m_file_sizing < 0)
+ {
+ count= fixed_file_instances
+ + con * file_per_connection
+ + handle * file_per_handle
+ + share * file_per_share;
+
+ count= max<ulong>(count, file);
+ p->m_file_sizing= apply_load_factor(count, h->m_load_factor_normal);
+ }
+
+ if (p->m_socket_sizing < 0)
+ {
+ count= fixed_socket_instances
+ + con * socket_per_connection
+ + handle * socket_per_handle
+ + share * socket_per_share;
+
+ p->m_socket_sizing= apply_load_factor(count, h->m_load_factor_volatile);
+ }
+
+ if (p->m_thread_sizing < 0)
+ {
+ count= fixed_thread_instances
+ + con * thread_per_connection
+ + handle * thread_per_handle
+ + share * thread_per_share;
+
+ p->m_thread_sizing= apply_load_factor(count, h->m_load_factor_volatile);
+ }
+}
+
+void pfs_automated_sizing(PFS_global_param *param)
+{
+ PFS_sizing_data *heuristic;
+ heuristic= estimate_hints(param);
+ apply_heuristic(param, heuristic);
+
+ DBUG_ASSERT(param->m_account_sizing >= 0);
+ DBUG_ASSERT(param->m_digest_sizing >= 0);
+ DBUG_ASSERT(param->m_host_sizing >= 0);
+ DBUG_ASSERT(param->m_user_sizing >= 0);
+
+ DBUG_ASSERT(param->m_events_waits_history_sizing >= 0);
+ DBUG_ASSERT(param->m_events_waits_history_long_sizing >= 0);
+ DBUG_ASSERT(param->m_events_stages_history_sizing >= 0);
+ DBUG_ASSERT(param->m_events_stages_history_long_sizing >= 0);
+ DBUG_ASSERT(param->m_events_statements_history_sizing >= 0);
+ DBUG_ASSERT(param->m_events_statements_history_long_sizing >= 0);
+ DBUG_ASSERT(param->m_session_connect_attrs_sizing >= 0);
+
+ DBUG_ASSERT(param->m_mutex_sizing >= 0);
+ DBUG_ASSERT(param->m_rwlock_sizing >= 0);
+ DBUG_ASSERT(param->m_cond_sizing >= 0);
+ DBUG_ASSERT(param->m_file_sizing >= 0);
+ DBUG_ASSERT(param->m_socket_sizing >= 0);
+ DBUG_ASSERT(param->m_thread_sizing >= 0);
+ DBUG_ASSERT(param->m_table_sizing >= 0);
+ DBUG_ASSERT(param->m_table_share_sizing >= 0);
+}
+
diff --git a/storage/perfschema/pfs_check.cc b/storage/perfschema/pfs_check.cc
new file mode 100644
index 00000000000..c9c557f3010
--- /dev/null
+++ b/storage/perfschema/pfs_check.cc
@@ -0,0 +1,63 @@
+/* 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
+ 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_check.cc
+ Check the performance schema table structure.
+ The code in this file is implemented in pfs_check.cc
+ instead of pfs_server.cc, to separate dependencies to server
+ structures (THD, ...) in a dedicated file.
+ This code organization helps a lot maintenance of the unit tests.
+*/
+
+#include "my_global.h"
+#include "pfs_server.h"
+#include "pfs_engine_table.h"
+
+/*
+*/
+
+/**
+ Check that the performance schema tables
+ have the expected structure.
+ Discrepancies are written in the server log,
+ but are not considered fatal, so this function does not
+ return an error code:
+ - some differences are compatible, and should not cause a failure
+ - some differences are not compatible, but then the DBA needs an operational
+ server to be able to DROP+CREATE the tables with the proper structure,
+ as part of the initial server installation or during an upgrade.
+ In case of discrepancies, later attempt to perform DML against
+ the performance schema will be rejected with an error.
+*/
+void check_performance_schema()
+{
+ DBUG_ENTER("check_performance_schema");
+
+ THD *thd= new THD();
+ if (thd == NULL)
+ DBUG_VOID_RETURN;
+
+ thd->thread_stack= (char*) &thd;
+ thd->store_globals();
+
+ PFS_engine_table_share::check_all_tables(thd);
+
+ delete thd;
+ /* Remember that we don't have a THD */
+ my_pthread_setspecific_ptr(THR_THD, 0);
+ DBUG_VOID_RETURN;
+}
+
diff --git a/storage/perfschema/pfs_column_types.h b/storage/perfschema/pfs_column_types.h
new file mode 100644
index 00000000000..23ef946ee82
--- /dev/null
+++ b/storage/perfschema/pfs_column_types.h
@@ -0,0 +1,222 @@
+/* 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 PFS_COLUMN_TYPES_H
+#define PFS_COLUMN_TYPES_H
+
+/**
+ @file storage/perfschema/pfs_column_types.h
+ Data types for columns used in the performance schema tables (declarations)
+*/
+
+/** Size of the OBJECT_SCHEMA columns. */
+#define COL_OBJECT_SCHEMA_SIZE 64
+
+/**
+ Size of the extended OBJECT_NAME columns.
+ 'Extended' columns are used when the object name also represents
+ the name of a non SQL object, such as a file name.
+ Size in bytes of:
+ - performance_schema.events_waits_current (OBJECT_NAME)
+ - performance_schema.events_waits_history (OBJECT_NAME)
+ - performance_schema.events_waits_history_long (OBJECT_NAME)
+*/
+#define COL_OBJECT_NAME_EXTENDED_SIZE 512
+
+/** 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:
+ - performance_schema.setup_timer (TIMER_NAME)
+ - performance_schema.performance_timer (TIMER_NAME)
+*/
+enum enum_timer_name
+{
+ TIMER_NAME_CYCLE= 1,
+ TIMER_NAME_NANOSEC= 2,
+ TIMER_NAME_MICROSEC= 3,
+ TIMER_NAME_MILLISEC= 4,
+ 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)
+
+/**
+ Enum values for the various YES/NO columns.
+ This enum is found in the following tables:
+ - performance_schema.setup_instruments (ENABLED)
+ - performance_schema.setup_instruments (TIMED)
+ - performance_schema.setup_consumers (ENABLED)
+*/
+enum enum_yes_no
+{
+ ENUM_YES= 1,
+ ENUM_NO= 2
+};
+
+/**
+ Enum values for the various OPERATION columns.
+ This enum is found in the following tables:
+ - performance_schema.events_waits_current (OPERATION)
+ - performance_schema.events_waits_history (OPERATION)
+ - performance_schema.events_waits_history_long (OPERATION)
+*/
+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,
+ OPERATION_TYPE_FILESTREAMOPEN= 12,
+ OPERATION_TYPE_FILECLOSE= 13,
+ OPERATION_TYPE_FILESTREAMCLOSE= 14,
+ OPERATION_TYPE_FILEREAD= 15,
+ OPERATION_TYPE_FILEWRITE= 16,
+ OPERATION_TYPE_FILESEEK= 17,
+ OPERATION_TYPE_FILETELL= 18,
+ OPERATION_TYPE_FILEFLUSH= 19,
+ OPERATION_TYPE_FILESTAT= 20,
+ OPERATION_TYPE_FILEFSTAT= 21,
+ OPERATION_TYPE_FILECHSIZE= 22,
+ OPERATION_TYPE_FILEDELETE= 23,
+ OPERATION_TYPE_FILERENAME= 24,
+ 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))
+/** 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
new file mode 100644
index 00000000000..65d0ae7171b
--- /dev/null
+++ b/storage/perfschema/pfs_column_values.cc
@@ -0,0 +1,50 @@
+/* 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_column_values.cc
+ Literal values for columns used in the performance
+ schema tables (implementation).
+*/
+
+#include "my_global.h"
+#include "pfs_column_values.h"
+
+LEX_STRING PERFORMANCE_SCHEMA_str=
+{ C_STRING_WITH_LEN("performance_schema") };
+
+LEX_STRING mutex_instrument_prefix=
+{ C_STRING_WITH_LEN("wait/synch/mutex/") };
+
+LEX_STRING rwlock_instrument_prefix=
+{ C_STRING_WITH_LEN("wait/synch/rwlock/") };
+
+LEX_STRING cond_instrument_prefix=
+{ C_STRING_WITH_LEN("wait/synch/cond/") };
+
+LEX_STRING thread_instrument_prefix=
+{ C_STRING_WITH_LEN("thread/") };
+
+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
new file mode 100644
index 00000000000..204d5230ddf
--- /dev/null
+++ b/storage/perfschema/pfs_column_values.h
@@ -0,0 +1,47 @@
+/* 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 PFS_COLUMN_VALUES_H
+#define PFS_COLUMN_VALUES_H
+
+#include "m_string.h" /* LEX_STRING */
+
+/**
+ @file storage/perfschema/pfs_column_values.h
+ Literal values for columns used in the
+ 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..0d95c0d410e
--- /dev/null
+++ b/storage/perfschema/pfs_digest.cc
@@ -0,0 +1,728 @@
+/* Copyright (c) 2008, 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 */
+
+/**
+ @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 "sql_get_diagnostics.h"
+#include "sql_string.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;
+
+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= sizeof (PFS_digest_key);
+ result= & digest->m_digest_key;
+ 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) && (digest_max > 0))
+ {
+ lf_hash_init(&digest_hash, sizeof(PFS_statements_digest_stat*),
+ LF_HASH_UNIQUE, 0, 0, digest_hash_get_key,
+ &my_charset_bin);
+ digest_hash.size= digest_max;
+ 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,
+ const char *schema_name,
+ uint schema_name_length)
+{
+ 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;
+
+ /*
+ Note: the LF_HASH key is a block of memory,
+ make sure to clean unused bytes,
+ so that memcmp() can compare keys.
+ */
+ PFS_digest_key hash_key;
+ memset(& hash_key, 0, sizeof(hash_key));
+ /* Compute MD5 Hash of the tokens received. */
+ compute_md5_hash((char *) hash_key.m_md5,
+ (char *) digest_storage->m_token_array,
+ digest_storage->m_byte_count);
+ /* Add the current schema to the key */
+ hash_key.m_schema_name_length= schema_name_length;
+ if (schema_name_length > 0)
+ memcpy(hash_key.m_schema_name, schema_name, schema_name_length);
+
+ 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= my_micro_time();
+
+search:
+
+ /* Lookup LF_HASH using this new key. */
+ entry= reinterpret_cast<PFS_statements_digest_stat**>
+ (lf_hash_search(&digest_hash, pins,
+ &hash_key, sizeof(PFS_digest_key)));
+
+ 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_key, &hash_key, sizeof(PFS_digest_key));
+
+ /*
+ 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, PFS_digest_key *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, sizeof(PFS_digest_key)));
+
+ if (entry && (entry != MY_ERRPTR))
+ {
+ lf_hash_delete(&digest_hash, pins,
+ hash_key, sizeof(PFS_digest_key));
+ }
+ 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_key);
+ }
+}
+
+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)
+{
+ DBUG_ASSERT(digest_storage != NULL);
+ bool truncated= false;
+ int byte_count= digest_storage->m_byte_count;
+ int bytes_needed= 0;
+ uint tok= 0;
+ int current_byte= 0;
+ lex_token_string *tok_data;
+ /* -4 is to make sure extra space for '...' and a '\0' at the end. */
+ int bytes_available= COL_DIGEST_TEXT_SIZE - 4;
+
+ /* Convert text to utf8 */
+ const CHARSET_INFO *from_cs= get_charset(digest_storage->m_charset_number, MYF(0));
+ const CHARSET_INFO *to_cs= &my_charset_utf8_bin;
+
+ if (from_cs == NULL)
+ {
+ /*
+ Can happen, as we do dirty reads on digest_storage,
+ which can be written to in another thread.
+ */
+ *digest_text= '\0';
+ return;
+ }
+
+ /*
+ Max converted size is number of characters * max multibyte length of the
+ target charset, which is 4 for UTF8.
+ */
+ const uint max_converted_size= PSI_MAX_DIGEST_STORAGE_SIZE * 4;
+ char id_buffer[max_converted_size];
+ char *id_string;
+ int id_length;
+ bool convert_text= !my_charset_same(from_cs, to_cs);
+
+ DBUG_ASSERT(byte_count <= PSI_MAX_DIGEST_STORAGE_SIZE);
+
+ while ((current_byte < byte_count) &&
+ (bytes_available > 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:
+ case IDENT_QUOTED:
+ {
+ char *id_ptr;
+ int id_len;
+ uint err_cs= 0;
+
+ /* Get the next identifier from the storage buffer. */
+ current_byte= read_identifier(digest_storage, current_byte,
+ &id_ptr, &id_len);
+ if (convert_text)
+ {
+ /* Verify that the converted text will fit. */
+ if (to_cs->mbmaxlen*id_len > max_converted_size)
+ {
+ truncated= true;
+ break;
+ }
+ /* Convert identifier string into the storage character set. */
+ id_length= my_convert(id_buffer, max_converted_size, to_cs,
+ id_ptr, id_len, from_cs, &err_cs);
+ id_string= id_buffer;
+ }
+ else
+ {
+ id_string= id_ptr;
+ id_length= id_len;
+ }
+
+ if (id_length == 0 || err_cs != 0)
+ {
+ truncated= true;
+ break;
+ }
+ /* Copy the converted identifier into the digest string. */
+ bytes_needed= id_length + (tok == IDENT ? 1 : 3);
+ if (bytes_needed <= bytes_available)
+ {
+ if (tok == IDENT_QUOTED)
+ *digest_text++= '`';
+ if (id_length > 0)
+ {
+ memcpy(digest_text, id_string, id_length);
+ digest_text+= id_length;
+ }
+ if (tok == IDENT_QUOTED)
+ *digest_text++= '`';
+ *digest_text++= ' ';
+ bytes_available-= bytes_needed;
+ }
+ else
+ {
+ truncated= true;
+ }
+ }
+ break;
+
+ /* Everything else is printed as is. */
+ default:
+ /*
+ Make sure not to overflow digest_text buffer.
+ +1 is to make sure extra space for ' '.
+ */
+ int tok_length= tok_data->m_token_length;
+ bytes_needed= tok_length + 1;
+
+ if (bytes_needed <= bytes_available)
+ {
+ strncpy(digest_text, tok_data->m_token_string, tok_length);
+ digest_text+= tok_length;
+ *digest_text++= ' ';
+ bytes_available-= bytes_needed;
+ }
+ else
+ {
+ truncated= true;
+ }
+ break;
+ }
+ }
+
+ /* 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;
+
+ /*
+ Stop collecting further tokens if digest storage is full or
+ if END token is received.
+ */
+ if (digest_storage->m_full || token == END_OF_INPUT)
+ 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;
+ }
+ /* fall through */
+ case NULL_SYM:
+ {
+ if ((last_token2 == TOK_PFS_GENERIC_VALUE ||
+ last_token2 == TOK_PFS_GENERIC_VALUE_LIST ||
+ last_token2 == NULL_SYM) &&
+ (last_token == ','))
+ {
+ /*
+ REDUCE:
+ TOK_PFS_GENERIC_VALUE_LIST :=
+ (TOK_PFS_GENERIC_VALUE|NULL_SYM) ',' (TOK_PFS_GENERIC_VALUE|NULL_SYM)
+
+ REDUCE:
+ TOK_PFS_GENERIC_VALUE_LIST :=
+ TOK_PFS_GENERIC_VALUE_LIST ',' (TOK_PFS_GENERIC_VALUE|NULL_SYM)
+ */
+ 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..d2453dc32c6
--- /dev/null
+++ b/storage/perfschema/pfs_digest.h
@@ -0,0 +1,219 @@
+/* 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_key
+{
+ unsigned char m_md5[PFS_MD5_SIZE];
+ char m_schema_name[NAME_LEN];
+ uint m_schema_name_length;
+};
+
+/** A statement digest stat record. */
+struct PFS_ALIGNED PFS_statements_digest_stat
+{
+ /** Digest Schema + MD5 Hash. */
+ PFS_digest_key m_digest_key;
+
+ /** Digest Storage. */
+ PSI_digest_storage m_digest_storage;
+
+ /** Statement stat. */
+ PFS_statement_stat m_stat;
+
+ /** First and last seen timestamps.*/
+ 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 *thread,
+ PSI_digest_storage *digest_storage,
+ const char *schema_name,
+ uint schema_name_length);
+
+void get_digest_text(char *digest_text, PSI_digest_storage *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;
+ digest->m_charset_number= 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;
+ to->m_charset_number= from->m_charset_number;
+ 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_byte_count == 0);
+ to->m_full= false;
+ to->m_byte_count= 0;
+ to->m_charset_number= 0;
+ }
+}
+
+/**
+ 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;
+}
+
+/**
+ 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;
+ }
+}
+
+/**
+ 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;
+}
+
+/**
+ 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)
+ memcpy((char *)(dest + 4), id_name, id_length);
+ digest_storage->m_byte_count+= bytes_needed;
+ }
+ else
+ {
+ digest_storage->m_full= true;
+ }
+}
+
+extern LF_HASH digest_hash;
+
+#endif
diff --git a/storage/perfschema/pfs_engine_table.cc b/storage/perfschema/pfs_engine_table.cc
new file mode 100644
index 00000000000..789047f4d11
--- /dev/null
+++ b/storage/perfschema/pfs_engine_table.cc
@@ -0,0 +1,1447 @@
+/* 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_engine_table.cc
+ Performance schema tables (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "hostname.h" /* For Host_entry */
+#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_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_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"
+#include "table_session_connect_attrs.h"
+#include "table_session_account_connect_attrs.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
+
+/**
+ @addtogroup Performance_schema_engine
+ @{
+*/
+
+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_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,
+ &table_host_cache::m_share,
+ &table_mutex_instances::m_share,
+ &table_os_global_by_type::m_share,
+ &table_performance_timers::m_share,
+ &table_rwlock_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,
+ &table_session_connect_attrs::m_share,
+ &table_session_account_connect_attrs::m_share,
+ NULL
+};
+
+/**
+ Check all the tables structure.
+ @param thd current thread
+*/
+void PFS_engine_table_share::check_all_tables(THD *thd)
+{
+ PFS_engine_table_share **current;
+
+ DBUG_EXECUTE_IF("tampered_perfschema_table1",
+ {
+ /* Hack SETUP_INSTRUMENT, incompatible change. */
+ 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:
+ virtual void report_error(uint code, const char *fmt, ...);
+
+public:
+ PFS_check_intact()
+ {}
+
+ ~PFS_check_intact()
+ {}
+};
+
+void PFS_check_intact::report_error(uint code, const char *fmt, ...)
+{
+ va_list args;
+ char buff[MYSQL_ERRMSG_SIZE];
+
+ va_start(args, fmt);
+ my_vsnprintf(buff, sizeof(buff), fmt, args);
+ va_end(args);
+
+ /*
+ This is an install/upgrade issue:
+ - do not report it in the user connection, there is none in main(),
+ - report it in the server error log.
+ */
+ sql_print_error("%s", buff);
+}
+
+/**
+ Check integrity of the actual table schema.
+ The actual table schema (.frm) is compared to the expected schema.
+ @param thd current thread
+*/
+void PFS_engine_table_share::check_one_table(THD *thd)
+{
+ TABLE_LIST tables;
+
+ tables.init_one_table(PERFORMANCE_SCHEMA_str.str,
+ PERFORMANCE_SCHEMA_str.length,
+ m_name.str, m_name.length,
+ m_name.str, TL_READ);
+
+ /* Work around until Bug#32115 is backported. */
+ LEX dummy_lex;
+ LEX *old_lex= thd->lex;
+ thd->lex= &dummy_lex;
+ lex_start(thd);
+
+ if (! open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
+ {
+ PFS_check_intact checker;
+
+ if (!checker.check(tables.table, m_field_def))
+ m_checked= true;
+ close_thread_tables(thd);
+ }
+ else
+ sql_print_error(ER(ER_WRONG_NATIVE_TABLE_STRUCTURE),
+ PERFORMANCE_SCHEMA_str.str, m_name.str);
+
+ lex_end(&dummy_lex);
+ thd->lex= old_lex;
+}
+
+/** Initialize all the table share locks. */
+void PFS_engine_table_share::init_all_locks(void)
+{
+ PFS_engine_table_share **current;
+
+ for (current= &all_shares[0]; (*current) != NULL; current++)
+ thr_lock_init((*current)->m_thr_lock_ptr);
+}
+
+/** Delete all the table share locks. */
+void PFS_engine_table_share::delete_all_locks(void)
+{
+ PFS_engine_table_share **current;
+
+ for (current= &all_shares[0]; (*current) != NULL; current++)
+ 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)
+{
+ /*
+ The performance schema is implemented as a storage engine, in memory.
+ The current storage engine interface exposed by the server,
+ and in particular handlerton::discover, uses 'FRM' files to describe a
+ table structure, which are later stored on disk, by the server,
+ in ha_create_table_from_engine().
+ Because the table metadata is stored on disk, the table naming rules
+ used by the performance schema then have to comply with the constraints
+ imposed by the disk storage, and in particular with lower_case_table_names.
+ Once the server is changed to be able to discover a table in a storage engine
+ and then open the table without storing a FRM file on disk, this constraint
+ on the performance schema will be lifted, and the naming logic can be relaxed
+ to be simply my_strcasecmp(system_charset_info, name1, name2).
+ */
+ if (lower_case_table_names)
+ return strcasecmp(name1, name2);
+ return strcmp(name1, name2);
+}
+
+/**
+ Find a table share by name.
+ @param name The table name
+ @return table share
+*/
+const PFS_engine_table_share*
+PFS_engine_table::find_engine_table_share(const char *name)
+{
+ DBUG_ENTER("PFS_engine_table::find_table_share");
+
+ PFS_engine_table_share **current;
+
+ for (current= &all_shares[0]; (*current) != NULL; current++)
+ {
+ if (compare_table_names(name, (*current)->m_name.str) == 0)
+ DBUG_RETURN(*current);
+ }
+
+ DBUG_RETURN(NULL);
+}
+
+/**
+ Read a table row.
+ @param table Table handle
+ @param buf Row buffer
+ @param fields Table fields
+ @return 0 on success
+*/
+int PFS_engine_table::read_row(TABLE *table,
+ unsigned char *buf,
+ Field **fields)
+{
+ my_bitmap_map *org_bitmap;
+ Field *f;
+ Field **fields_reset;
+
+ /*
+ Make sure the table structure is as expected before mapping
+ hard wired columns in read_row_values.
+ */
+ if (! m_share_ptr->m_checked)
+ {
+ return HA_ERR_TABLE_NEEDS_UPGRADE;
+ }
+
+ /* We must read all columns in case a table is opened for update */
+ bool read_all= !bitmap_is_clear_all(table->write_set);
+
+ /* We internally write to Fields to support the read interface */
+ org_bitmap= dbug_tmp_use_all_columns(table, table->write_set);
+
+ /*
+ Some callers of the storage engine interface do not honor the
+ f->is_null() flag, and will attempt to read the data itself.
+ A known offender is mysql_checksum_table().
+ For robustness, reset every field.
+ */
+ for (fields_reset= fields; (f= *fields_reset) ; fields_reset++)
+ f->reset();
+
+ int result= read_row_values(table, buf, fields, read_all);
+ dbug_tmp_restore_column_map(table->write_set, org_bitmap);
+
+ return result;
+}
+
+/**
+ Update a table row.
+ @param table Table handle
+ @param old_buf old row buffer
+ @param new_buf new row buffer
+ @param fields Table fields
+ @return 0 on success
+*/
+int PFS_engine_table::update_row(TABLE *table,
+ const unsigned char *old_buf,
+ unsigned char *new_buf,
+ Field **fields)
+{
+ my_bitmap_map *org_bitmap;
+
+ /*
+ Make sure the table structure is as expected before mapping
+ hard wired columns in update_row_values.
+ */
+ if (! m_share_ptr->m_checked)
+ {
+ return HA_ERR_TABLE_NEEDS_UPGRADE;
+ }
+
+ /* We internally read from Fields to support the write interface */
+ org_bitmap= dbug_tmp_use_all_columns(table, table->read_set);
+ int result= update_row_values(table, old_buf, new_buf, fields);
+ dbug_tmp_restore_column_map(table->read_set, org_bitmap);
+
+ 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
+*/
+void PFS_engine_table::get_position(void *ref)
+{
+ memcpy(ref, m_pos_ptr, m_share_ptr->m_ref_length);
+}
+
+/**
+ Set the table cursor at a given position.
+ @param [in] ref position
+*/
+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);
+ Field_long *f2= (Field_long*) f;
+ f2->store(value, true);
+}
+
+void PFS_engine_table::set_field_ulonglong(Field *f, ulonglong value)
+{
+ DBUG_ASSERT(f->real_type() == MYSQL_TYPE_LONGLONG);
+ Field_longlong *f2= (Field_longlong*) f;
+ 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)
+{
+ DBUG_ASSERT(f->real_type() == MYSQL_TYPE_VARCHAR);
+ Field_varstring *f2= (Field_varstring*) f;
+ 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);
+ Field_enum *f2= (Field_enum*) f;
+ f2->store_type(value);
+}
+
+void PFS_engine_table::set_field_timestamp(Field *f, ulonglong value)
+{
+ struct timeval tm;
+ tm.tv_sec= (long)(value / 1000000);
+ tm.tv_usec= (long)(value % 1000000);
+ DBUG_ASSERT(f->real_type() == MYSQL_TYPE_TIMESTAMP2);
+ Field_timestampf *f2= (Field_timestampf*) f;
+ f2->store_timestamp(& tm);
+}
+
+ulonglong PFS_engine_table::get_field_enum(Field *f)
+{
+ DBUG_ASSERT(f->real_type() == MYSQL_TYPE_ENUM);
+ Field_enum *f2= (Field_enum*) 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 *,
+ Field **)
+{
+ 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:
+ PFS_internal_schema_access()
+ {}
+
+ ~PFS_internal_schema_access()
+ {}
+
+ ACL_internal_access_result check(ulong want_access,
+ ulong *save_priv) const;
+
+ const ACL_internal_table_access *lookup(const char *name) const;
+};
+
+ACL_internal_access_result
+PFS_internal_schema_access::check(ulong want_access,
+ ulong *save_priv) const
+{
+ const ulong always_forbidden= /* CREATE_ACL | */ REFERENCES_ACL
+ | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL | EXECUTE_ACL
+ | CREATE_VIEW_ACL | SHOW_VIEW_ACL | CREATE_PROC_ACL | ALTER_PROC_ACL
+ | EVENT_ACL | TRIGGER_ACL ;
+
+ if (unlikely(want_access & always_forbidden))
+ return ACL_INTERNAL_ACCESS_DENIED;
+
+ /*
+ Proceed with regular grant tables,
+ to give administrative control to the DBA.
+ */
+ return ACL_INTERNAL_ACCESS_CHECK_GRANT;
+}
+
+const ACL_internal_table_access *
+PFS_internal_schema_access::lookup(const char *name) const
+{
+ const PFS_engine_table_share* share;
+ share= PFS_engine_table::find_engine_table_share(name);
+ if (share)
+ return share->m_acl;
+ /*
+ Do not return NULL, it would mean we are not interested
+ in privilege checks for unknown tables.
+ Instead, return an object that denies every actions,
+ to prevent users for creating their own tables in the
+ performance_schema database schema.
+ */
+ return &pfs_unknown_acl;
+}
+
+PFS_internal_schema_access pfs_internal_access;
+
+void initialize_performance_schema_acl(bool bootstrap)
+{
+ /*
+ ACL is always enforced, even if the performance schema
+ is not enabled (the tables are still visible).
+ */
+ if (! bootstrap)
+ {
+ ACL_internal_schema_registry::register_schema(&PERFORMANCE_SCHEMA_str,
+ &pfs_internal_access);
+ }
+}
+
+PFS_readonly_acl pfs_readonly_acl;
+
+ACL_internal_access_result
+PFS_readonly_acl::check(ulong want_access, ulong *save_priv) const
+{
+ const ulong always_forbidden= INSERT_ACL | UPDATE_ACL | DELETE_ACL
+ | /* CREATE_ACL | */ REFERENCES_ACL | INDEX_ACL | ALTER_ACL
+ | CREATE_VIEW_ACL | SHOW_VIEW_ACL | TRIGGER_ACL | LOCK_TABLES_ACL;
+
+ if (unlikely(want_access & always_forbidden))
+ return ACL_INTERNAL_ACCESS_DENIED;
+
+ return ACL_INTERNAL_ACCESS_CHECK_GRANT;
+}
+
+PFS_truncatable_acl pfs_truncatable_acl;
+
+ACL_internal_access_result
+PFS_truncatable_acl::check(ulong want_access, ulong *save_priv) const
+{
+ const ulong always_forbidden= INSERT_ACL | UPDATE_ACL | DELETE_ACL
+ | /* CREATE_ACL | */ REFERENCES_ACL | INDEX_ACL | ALTER_ACL
+ | CREATE_VIEW_ACL | SHOW_VIEW_ACL | TRIGGER_ACL | LOCK_TABLES_ACL;
+
+ if (unlikely(want_access & always_forbidden))
+ return ACL_INTERNAL_ACCESS_DENIED;
+
+ return ACL_INTERNAL_ACCESS_CHECK_GRANT;
+}
+
+PFS_updatable_acl pfs_updatable_acl;
+
+ACL_internal_access_result
+PFS_updatable_acl::check(ulong want_access, ulong *save_priv) const
+{
+ const ulong always_forbidden= INSERT_ACL | DELETE_ACL
+ | /* CREATE_ACL | */ REFERENCES_ACL | INDEX_ACL | ALTER_ACL
+ | CREATE_VIEW_ACL | SHOW_VIEW_ACL | TRIGGER_ACL;
+
+ if (unlikely(want_access & always_forbidden))
+ return ACL_INTERNAL_ACCESS_DENIED;
+
+ return ACL_INTERNAL_ACCESS_CHECK_GRANT;
+}
+
+PFS_editable_acl pfs_editable_acl;
+
+ACL_internal_access_result
+PFS_editable_acl::check(ulong want_access, ulong *save_priv) const
+{
+ const ulong always_forbidden= /* CREATE_ACL | */ REFERENCES_ACL
+ | INDEX_ACL | ALTER_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | TRIGGER_ACL;
+
+ if (unlikely(want_access & always_forbidden))
+ return ACL_INTERNAL_ACCESS_DENIED;
+
+ return ACL_INTERNAL_ACCESS_CHECK_GRANT;
+}
+
+PFS_unknown_acl pfs_unknown_acl;
+
+ACL_internal_access_result
+PFS_unknown_acl::check(ulong want_access, ulong *save_priv) const
+{
+ const ulong always_forbidden= CREATE_ACL
+ | REFERENCES_ACL | INDEX_ACL | ALTER_ACL
+ | CREATE_VIEW_ACL | TRIGGER_ACL;
+
+ if (unlikely(want_access & always_forbidden))
+ return ACL_INTERNAL_ACCESS_DENIED;
+
+ /*
+ There is no point in hiding (by enforcing ACCESS_DENIED for SELECT_ACL
+ on performance_schema.*) tables that do not exist anyway.
+ When SELECT_ACL is granted on performance_schema.* or *.*,
+ SELECT * from performance_schema.wrong_table
+ will fail with a more understandable ER_NO_SUCH_TABLE error,
+ instead of ER_TABLEACCESS_DENIED_ERROR.
+ The same goes for other DML (INSERT_ACL | UPDATE_ACL | DELETE_ACL),
+ for ease of use: error messages will be less surprising.
+ */
+ return ACL_INTERNAL_ACCESS_CHECK_GRANT;
+}
+
+/**
+ SHOW ENGINE PERFORMANCE_SCHEMA STATUS.
+ @param hton Storage engine handler
+ @param thd Current thread
+ @param print Print function
+ @param stat status to show
+*/
+bool pfs_show_status(handlerton *hton, THD *thd,
+ stat_print_fn *print, enum ha_stat_type stat)
+{
+ char buf[1024];
+ uint buflen;
+ const char *name;
+ int i;
+ uint size;
+
+ DBUG_ENTER("pfs_show_status");
+
+ /*
+ Note about naming conventions:
+ - Internal buffers exposed as a table in the performance schema are named
+ after the table, as in 'events_waits_current'
+ - Internal buffers not exposed by a table are named with parenthesis,
+ as in '(pfs_mutex_class)'.
+ */
+ if (stat != HA_ENGINE_STATUS)
+ DBUG_RETURN(false);
+
+ uint total_memory= 0;
+
+ for (i=0; /* empty */; i++)
+ {
+ switch (i){
+ case 0:
+ name= "events_waits_current.row_size";
+ size= sizeof(PFS_events_waits);
+ break;
+ case 1:
+ name= "events_waits_current.row_count";
+ size= WAIT_STACK_SIZE * thread_max;
+ break;
+ case 2:
+ name= "events_waits_history.row_size";
+ size= sizeof(PFS_events_waits);
+ break;
+ case 3:
+ name= "events_waits_history.row_count";
+ size= events_waits_history_per_thread * thread_max;
+ break;
+ case 4:
+ name= "events_waits_history.memory";
+ size= events_waits_history_per_thread * thread_max
+ * sizeof(PFS_events_waits);
+ total_memory+= size;
+ break;
+ case 5:
+ name= "events_waits_history_long.row_size";
+ size= sizeof(PFS_events_waits);
+ break;
+ case 6:
+ name= "events_waits_history_long.row_count";
+ size= events_waits_history_long_size;
+ break;
+ case 7:
+ name= "events_waits_history_long.memory";
+ size= events_waits_history_long_size * sizeof(PFS_events_waits);
+ total_memory+= size;
+ break;
+ case 8:
+ name= "(pfs_mutex_class).row_size";
+ size= sizeof(PFS_mutex_class);
+ break;
+ case 9:
+ name= "(pfs_mutex_class).row_count";
+ size= mutex_class_max;
+ break;
+ case 10:
+ name= "(pfs_mutex_class).memory";
+ size= mutex_class_max * sizeof(PFS_mutex_class);
+ total_memory+= size;
+ break;
+ case 11:
+ name= "(pfs_rwlock_class).row_size";
+ size= sizeof(PFS_rwlock_class);
+ break;
+ case 12:
+ name= "(pfs_rwlock_class).row_count";
+ size= rwlock_class_max;
+ break;
+ case 13:
+ name= "(pfs_rwlock_class).memory";
+ size= rwlock_class_max * sizeof(PFS_rwlock_class);
+ total_memory+= size;
+ break;
+ case 14:
+ name= "(pfs_cond_class).row_size";
+ size= sizeof(PFS_cond_class);
+ break;
+ case 15:
+ name= "(pfs_cond_class).row_count";
+ size= cond_class_max;
+ break;
+ case 16:
+ name= "(pfs_cond_class).memory";
+ size= cond_class_max * sizeof(PFS_cond_class);
+ total_memory+= size;
+ break;
+ case 17:
+ name= "(pfs_thread_class).row_size";
+ size= sizeof(PFS_thread_class);
+ break;
+ case 18:
+ name= "(pfs_thread_class).row_count";
+ size= thread_class_max;
+ break;
+ case 19:
+ name= "(pfs_thread_class).memory";
+ size= thread_class_max * sizeof(PFS_thread_class);
+ total_memory+= size;
+ break;
+ case 20:
+ name= "(pfs_file_class).row_size";
+ size= sizeof(PFS_file_class);
+ break;
+ case 21:
+ name= "(pfs_file_class).row_count";
+ size= file_class_max;
+ break;
+ case 22:
+ name= "(pfs_file_class).memory";
+ size= file_class_max * sizeof(PFS_file_class);
+ total_memory+= size;
+ break;
+ case 23:
+ name= "mutex_instances.row_size";
+ size= sizeof(PFS_mutex);
+ break;
+ case 24:
+ name= "mutex_instances.row_count";
+ size= mutex_max;
+ break;
+ case 25:
+ name= "mutex_instances.memory";
+ size= mutex_max * sizeof(PFS_mutex);
+ total_memory+= size;
+ break;
+ case 26:
+ name= "rwlock_instances.row_size";
+ size= sizeof(PFS_rwlock);
+ break;
+ case 27:
+ name= "rwlock_instances.row_count";
+ size= rwlock_max;
+ break;
+ case 28:
+ name= "rwlock_instances.memory";
+ size= rwlock_max * sizeof(PFS_rwlock);
+ total_memory+= size;
+ break;
+ case 29:
+ name= "cond_instances.row_size";
+ size= sizeof(PFS_cond);
+ break;
+ case 30:
+ name= "cond_instances.row_count";
+ size= cond_max;
+ break;
+ case 31:
+ name= "cond_instances.memory";
+ size= cond_max * sizeof(PFS_cond);
+ total_memory+= size;
+ break;
+ case 32:
+ name= "threads.row_size";
+ size= sizeof(PFS_thread);
+ break;
+ case 33:
+ name= "threads.row_count";
+ size= thread_max;
+ break;
+ case 34:
+ name= "threads.memory";
+ size= thread_max * sizeof(PFS_thread);
+ total_memory+= size;
+ break;
+ case 35:
+ name= "file_instances.row_size";
+ size= sizeof(PFS_file);
+ break;
+ case 36:
+ name= "file_instances.row_count";
+ size= file_max;
+ break;
+ case 37:
+ name= "file_instances.memory";
+ size= file_max * sizeof(PFS_file);
+ total_memory+= size;
+ break;
+ case 38:
+ name= "(pfs_file_handle).row_size";
+ size= sizeof(PFS_file*);
+ break;
+ case 39:
+ name= "(pfs_file_handle).row_count";
+ size= file_handle_max;
+ break;
+ case 40:
+ name= "(pfs_file_handle).memory";
+ size= file_handle_max * sizeof(PFS_file*);
+ total_memory+= size;
+ break;
+ case 41:
+ name= "events_waits_summary_by_thread_by_event_name.row_size";
+ size= sizeof(PFS_single_stat);
+ break;
+ case 42:
+ name= "events_waits_summary_by_thread_by_event_name.row_count";
+ size= thread_max * wait_class_max;
+ break;
+ case 43:
+ name= "events_waits_summary_by_thread_by_event_name.memory";
+ size= thread_max * wait_class_max * sizeof(PFS_single_stat);
+ total_memory+= size;
+ break;
+ case 44:
+ name= "(pfs_table_share).row_size";
+ size= sizeof(PFS_table_share);
+ break;
+ case 45:
+ name= "(pfs_table_share).row_count";
+ size= table_share_max;
+ break;
+ case 46:
+ name= "(pfs_table_share).memory";
+ size= table_share_max * sizeof(PFS_table_share);
+ total_memory+= size;
+ break;
+ case 47:
+ name= "(pfs_table).row_size";
+ size= sizeof(PFS_table);
+ break;
+ case 48:
+ name= "(pfs_table).row_count";
+ size= table_max;
+ break;
+ case 49:
+ name= "(pfs_table).memory";
+ 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= "(pfs_account).row_size";
+ size= sizeof(PFS_account);
+ break;
+ case 57:
+ name= "(pfs_account).row_count";
+ size= account_max;
+ break;
+ case 58:
+ name= "(pfs_account).memory";
+ size= account_max * sizeof(PFS_account);
+ total_memory+= size;
+ break;
+ case 59:
+ name= "events_waits_summary_by_account_by_event_name.row_size";
+ size= sizeof(PFS_single_stat);
+ break;
+ case 60:
+ name= "events_waits_summary_by_account_by_event_name.row_count";
+ size= account_max * wait_class_max;
+ break;
+ case 61:
+ 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 62:
+ name= "events_waits_summary_by_user_by_event_name.row_size";
+ size= sizeof(PFS_single_stat);
+ break;
+ case 63:
+ name= "events_waits_summary_by_user_by_event_name.row_count";
+ size= user_max * wait_class_max;
+ break;
+ case 64:
+ 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 65:
+ name= "events_waits_summary_by_host_by_event_name.row_size";
+ size= sizeof(PFS_single_stat);
+ break;
+ case 66:
+ name= "events_waits_summary_by_host_by_event_name.row_count";
+ size= host_max * wait_class_max;
+ break;
+ case 67:
+ 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 68:
+ name= "(pfs_user).row_size";
+ size= sizeof(PFS_user);
+ break;
+ case 69:
+ name= "(pfs_user).row_count";
+ size= user_max;
+ break;
+ case 70:
+ name= "(pfs_user).memory";
+ size= user_max * sizeof(PFS_user);
+ total_memory+= size;
+ break;
+ case 71:
+ name= "(pfs_host).row_size";
+ size= sizeof(PFS_host);
+ break;
+ case 72:
+ name= "(pfs_host).row_count";
+ size= host_max;
+ break;
+ case 73:
+ name= "(pfs_host).memory";
+ size= host_max * sizeof(PFS_host);
+ total_memory+= size;
+ break;
+ case 74:
+ name= "(pfs_stage_class).row_size";
+ size= sizeof(PFS_stage_class);
+ break;
+ case 75:
+ name= "(pfs_stage_class).row_count";
+ size= stage_class_max;
+ break;
+ case 76:
+ name= "(pfs_stage_class).memory";
+ size= stage_class_max * sizeof(PFS_stage_class);
+ total_memory+= size;
+ break;
+ case 77:
+ name= "events_stages_history.row_size";
+ size= sizeof(PFS_events_stages);
+ break;
+ case 78:
+ name= "events_stages_history.row_count";
+ size= events_stages_history_per_thread * thread_max;
+ break;
+ case 79:
+ name= "events_stages_history.memory";
+ size= events_stages_history_per_thread * thread_max
+ * sizeof(PFS_events_stages);
+ total_memory+= size;
+ break;
+ case 80:
+ name= "events_stages_history_long.row_size";
+ size= sizeof(PFS_events_stages);
+ break;
+ case 81:
+ name= "events_stages_history_long.row_count";
+ size= events_stages_history_long_size;
+ break;
+ case 82:
+ name= "events_stages_history_long.memory";
+ size= events_stages_history_long_size * sizeof(PFS_events_stages);
+ total_memory+= size;
+ break;
+ case 83:
+ name= "events_stages_summary_by_thread_by_event_name.row_size";
+ size= sizeof(PFS_stage_stat);
+ break;
+ case 84:
+ name= "events_stages_summary_by_thread_by_event_name.row_count";
+ size= thread_max * stage_class_max;
+ break;
+ case 85:
+ 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 86:
+ name= "events_stages_summary_global_by_event_name.row_size";
+ size= sizeof(PFS_stage_stat);
+ break;
+ case 87:
+ name= "events_stages_summary_global_by_event_name.row_count";
+ size= stage_class_max;
+ break;
+ case 88:
+ name= "events_stages_summary_global_by_event_name.memory";
+ size= stage_class_max * sizeof(PFS_stage_stat);
+ total_memory+= size;
+ break;
+ case 89:
+ name= "events_stages_summary_by_account_by_event_name.row_size";
+ size= sizeof(PFS_stage_stat);
+ break;
+ case 90:
+ name= "events_stages_summary_by_account_by_event_name.row_count";
+ size= account_max * stage_class_max;
+ break;
+ case 91:
+ 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 92:
+ name= "events_stages_summary_by_user_by_event_name.row_size";
+ size= sizeof(PFS_stage_stat);
+ break;
+ case 93:
+ name= "events_stages_summary_by_user_by_event_name.row_count";
+ size= user_max * stage_class_max;
+ break;
+ case 94:
+ 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 95:
+ name= "events_stages_summary_by_host_by_event_name.row_size";
+ size= sizeof(PFS_stage_stat);
+ break;
+ case 96:
+ name= "events_stages_summary_by_host_by_event_name.row_count";
+ size= host_max * stage_class_max;
+ break;
+ case 97:
+ 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 98:
+ name= "(pfs_statement_class).row_size";
+ size= sizeof(PFS_statement_class);
+ break;
+ case 99:
+ name= "(pfs_statement_class).row_count";
+ size= statement_class_max;
+ break;
+ case 100:
+ name= "(pfs_statement_class).memory";
+ size= statement_class_max * sizeof(PFS_statement_class);
+ total_memory+= size;
+ break;
+ case 101:
+ name= "events_statements_history.row_size";
+ size= sizeof(PFS_events_statements);
+ break;
+ case 102:
+ name= "events_statements_history.row_count";
+ size= events_statements_history_per_thread * thread_max;
+ break;
+ case 103:
+ name= "events_statements_history.memory";
+ size= events_statements_history_per_thread * thread_max
+ * sizeof(PFS_events_statements);
+ total_memory+= size;
+ break;
+ case 104:
+ name= "events_statements_history_long.row_size";
+ size= sizeof(PFS_events_statements);
+ break;
+ case 105:
+ name= "events_statements_history_long.row_count";
+ size= events_statements_history_long_size;
+ break;
+ case 106:
+ name= "events_statements_history_long.memory";
+ size= events_statements_history_long_size * sizeof(PFS_events_statements);
+ total_memory+= size;
+ break;
+ case 107:
+ name= "events_statements_summary_by_thread_by_event_name.row_size";
+ size= sizeof(PFS_statement_stat);
+ break;
+ case 108:
+ name= "events_statements_summary_by_thread_by_event_name.row_count";
+ size= thread_max * statement_class_max;
+ break;
+ case 109:
+ 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 110:
+ name= "events_statements_summary_global_by_event_name.row_size";
+ size= sizeof(PFS_statement_stat);
+ break;
+ case 111:
+ name= "events_statements_summary_global_by_event_name.row_count";
+ size= statement_class_max;
+ break;
+ case 112:
+ name= "events_statements_summary_global_by_event_name.memory";
+ size= statement_class_max * sizeof(PFS_statement_stat);
+ total_memory+= size;
+ break;
+ case 113:
+ name= "events_statements_summary_by_account_by_event_name.row_size";
+ size= sizeof(PFS_statement_stat);
+ break;
+ case 114:
+ name= "events_statements_summary_by_account_by_event_name.row_count";
+ size= account_max * statement_class_max;
+ break;
+ case 115:
+ 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 116:
+ name= "events_statements_summary_by_user_by_event_name.row_size";
+ size= sizeof(PFS_statement_stat);
+ break;
+ case 117:
+ name= "events_statements_summary_by_user_by_event_name.row_count";
+ size= user_max * statement_class_max;
+ break;
+ case 118:
+ 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 119:
+ name= "events_statements_summary_by_host_by_event_name.row_size";
+ size= sizeof(PFS_statement_stat);
+ break;
+ case 120:
+ name= "events_statements_summary_by_host_by_event_name.row_count";
+ size= host_max * statement_class_max;
+ break;
+ case 121:
+ 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 122:
+ name= "events_statements_current.row_size";
+ size= sizeof(PFS_events_statements);
+ break;
+ case 123:
+ name= "events_statements_current.row_count";
+ size= thread_max * statement_stack_max;
+ break;
+ case 124:
+ name= "events_statements_current.memory";
+ size= thread_max * statement_stack_max * sizeof(PFS_events_statements);
+ total_memory+= size;
+ break;
+ case 125:
+ name= "(pfs_socket_class).row_size";
+ size= sizeof(PFS_socket_class);
+ break;
+ case 126:
+ name= "(pfs_socket_class).row_count";
+ size= socket_class_max;
+ break;
+ case 127:
+ name= "(pfs_socket_class).memory";
+ size= socket_class_max * sizeof(PFS_socket_class);
+ total_memory+= size;
+ break;
+ case 128:
+ name= "socket_instances.row_size";
+ size= sizeof(PFS_socket);
+ break;
+ case 129:
+ name= "socket_instances.row_count";
+ size= socket_max;
+ break;
+ case 130:
+ name= "socket_instances.memory";
+ size= socket_max * sizeof(PFS_socket);
+ total_memory+= size;
+ break;
+ case 131:
+ name= "events_statements_summary_by_digest.row_size";
+ size= sizeof(PFS_statements_digest_stat);
+ break;
+ case 132:
+ name= "events_statements_summary_by_digest.row_count";
+ size= digest_max;
+ break;
+ case 133:
+ name= "events_statements_summary_by_digest.memory";
+ size= digest_max * sizeof(PFS_statements_digest_stat);
+ total_memory+= size;
+ break;
+ case 134:
+ name= "session_connect_attrs.row_size";
+ size= thread_max;
+ break;
+ case 135:
+ name= "session_connect_attrs.row_count";
+ size= session_connect_attrs_size_per_thread;
+ break;
+ case 136:
+ name= "session_connect_attrs.memory";
+ size= thread_max * session_connect_attrs_size_per_thread;
+ total_memory+= size;
+ break;
+
+ case 137:
+ name= "(account_hash).count";
+ size= account_hash.count;
+ break;
+ case 138:
+ name= "(account_hash).size";
+ size= account_hash.size;
+ break;
+ case 139:
+ name= "(digest_hash).count";
+ size= digest_hash.count;
+ break;
+ case 140:
+ name= "(digest_hash).size";
+ size= digest_hash.size;
+ break;
+ case 141:
+ name= "(filename_hash).count";
+ size= filename_hash.count;
+ break;
+ case 142:
+ name= "(filename_hash).size";
+ size= filename_hash.size;
+ break;
+ case 143:
+ name= "(host_hash).count";
+ size= host_hash.count;
+ break;
+ case 144:
+ name= "(host_hash).size";
+ size= host_hash.size;
+ break;
+ case 145:
+ name= "(setup_actor_hash).count";
+ size= setup_actor_hash.count;
+ break;
+ case 146:
+ name= "(setup_actor_hash).size";
+ size= setup_actor_hash.size;
+ break;
+ case 147:
+ name= "(setup_object_hash).count";
+ size= setup_object_hash.count;
+ break;
+ case 148:
+ name= "(setup_object_hash).size";
+ size= setup_object_hash.size;
+ break;
+ case 149:
+ name= "(table_share_hash).count";
+ size= table_share_hash.count;
+ break;
+ case 150:
+ name= "(table_share_hash).size";
+ size= table_share_hash.size;
+ break;
+ case 151:
+ name= "(user_hash).count";
+ size= user_hash.count;
+ break;
+ case 152:
+ name= "(user_hash).size";
+ size= user_hash.size;
+ break;
+ case 153:
+ /*
+ This is not a performance_schema buffer,
+ the data is maintained in the server,
+ in hostname_cache.
+ Print the size only, there are:
+ - no host_cache.count
+ - no host_cache.memory
+ */
+ name= "host_cache.size";
+ size= sizeof(Host_entry);
+ break;
+
+ /*
+ This case must be last,
+ for aggregation in total_memory.
+ */
+ case 154:
+ name= "performance_schema.memory";
+ size= total_memory;
+ /* This will fail if something is not advertised here */
+ DBUG_ASSERT(size == pfs_allocated_memory);
+ break;
+ default:
+ goto end;
+ break;
+ }
+
+ buflen= int10_to_str(size, buf, 10) - buf;
+ if (print(thd,
+ PERFORMANCE_SCHEMA_str.str, PERFORMANCE_SCHEMA_str.length,
+ name, strlen(name),
+ buf, buflen))
+ DBUG_RETURN(true);
+ }
+
+end:
+ DBUG_RETURN(false);
+}
+
+/** @} */
+
diff --git a/storage/perfschema/pfs_engine_table.h b/storage/perfschema/pfs_engine_table.h
new file mode 100644
index 00000000000..981d72ee19e
--- /dev/null
+++ b/storage/perfschema/pfs_engine_table.h
@@ -0,0 +1,465 @@
+/* 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 PFS_ENGINE_TABLE_H
+#define PFS_ENGINE_TABLE_H
+
+#include "sql_acl.h" /* struct ACL_* */
+/**
+ @file storage/perfschema/pfs_engine_table.h
+ Performance schema tables (declarations).
+*/
+
+#include "pfs_instr_class.h"
+class Field;
+struct PFS_engine_table_share;
+struct time_normalizer;
+
+/**
+ @addtogroup Performance_schema_engine
+ @{
+*/
+
+/**
+ An abstract PERFORMANCE_SCHEMA table.
+ Every table implemented in the performance schema schema and storage engine
+ derives from this class.
+*/
+class PFS_engine_table
+{
+public:
+ static const PFS_engine_table_share*
+ find_engine_table_share(const char *name);
+
+ int read_row(TABLE *table, unsigned char *buf, Field **fields);
+
+ 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;
+ /**
+ Fetch a row by position.
+ @param pos position to fetch
+ */
+ virtual int rnd_pos(const void *pos)= 0;
+
+ 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.
+ @param table Table handle
+ @param buf row buffer
+ @param fields Table fields
+ @param read_all true if all columns are read.
+ */
+ virtual int read_row_values(TABLE *table, unsigned char *buf,
+ Field **fields, bool read_all)= 0;
+
+ /**
+ Update the current row values.
+ @param table Table handle
+ @param old_buf old row buffer
+ @param new_buf new row buffer
+ @param fields Table fields
+ */
+ virtual int update_row_values(TABLE *table, const unsigned char *old_buf,
+ 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_normalizer(NULL), m_class_type(PFS_CLASS_NONE)
+ {}
+
+ /** 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. */
+typedef PFS_engine_table* (*pfs_open_table_t)(void);
+/** Callback to write a row. */
+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.
+ This data is shared by all the table handles opened on the same table.
+*/
+struct PFS_engine_table_share
+{
+ static void check_all_tables(THD *thd);
+ 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;
+ /** Table ACL. */
+ const ACL_internal_table_access *m_acl;
+ /** Open table function. */
+ pfs_open_table_t m_open_table;
+ /** Write row function. */
+ 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,
+ it is used by the optimizer to decide if the table
+ has 0, 1, or many records.
+ */
+ ha_rows m_records;
+ /** Length of the m_pos position structure. */
+ uint m_ref_length;
+ /** The lock, stored on behalf of the SQL layer. */
+ THR_LOCK *m_thr_lock_ptr;
+ /** Table fields definition. */
+ TABLE_FIELD_DEF *m_field_def;
+ /** Schema integrity flag. */
+ bool m_checked;
+};
+
+/**
+ Privileges for read only tables.
+ The only operation allowed is SELECT.
+*/
+class PFS_readonly_acl : public ACL_internal_table_access
+{
+public:
+ PFS_readonly_acl()
+ {}
+
+ ~PFS_readonly_acl()
+ {}
+
+ virtual 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:
+ PFS_truncatable_acl()
+ {}
+
+ ~PFS_truncatable_acl()
+ {}
+
+ 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:
+ PFS_updatable_acl()
+ {}
+
+ ~PFS_updatable_acl()
+ {}
+
+ 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:
+ PFS_editable_acl()
+ {}
+
+ ~PFS_editable_acl()
+ {}
+
+ 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:
+ PFS_unknown_acl()
+ {}
+
+ ~PFS_unknown_acl()
+ {}
+
+ 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. */
+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. */
+ uint m_index_1;
+ /** 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;
+ m_index_2= other->m_index_2 + 1;
+ }
+};
+
+/** Position of a triple cursor, for iterations using 3 nested loops. */
+struct PFS_triple_index
+{
+ /** Outer index. */
+ uint m_index_1;
+ /** Current index within index_1. */
+ uint m_index_2;
+ /** 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;
+ m_index_2= other->m_index_2;
+ 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;
+ m_index_2= other->m_index_2;
+ m_index_3= other->m_index_3 + 1;
+ }
+};
+
+bool pfs_show_status(handlerton *hton, THD *thd,
+ stat_print_fn *print, enum ha_stat_type stat);
+
+/** @} */
+#endif
diff --git a/storage/perfschema/pfs_events.h b/storage/perfschema/pfs_events.h
new file mode 100644
index 00000000000..97fb7e08d63
--- /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. */
+ ulonglong 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
new file mode 100644
index 00000000000..c8a9d20a2f1
--- /dev/null
+++ b/storage/perfschema/pfs_events_waits.cc
@@ -0,0 +1,304 @@
+/* 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_events_waits.cc
+ Events waits 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_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= false;
+/** Consumer flag for table EVENTS_WAITS_HISTORY. */
+bool flag_events_waits_history= false;
+/** Consumer flag for table EVENTS_WAITS_HISTORY_LONG. */
+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;
+/** Index in EVENTS_WAITS_HISTORY_LONG circular buffer. */
+volatile uint32 events_waits_history_long_index= 0;
+/** EVENTS_WAITS_HISTORY_LONG circular buffer. */
+PFS_events_waits *events_waits_history_long_array= NULL;
+
+/**
+ Initialize table EVENTS_WAITS_HISTORY_LONG.
+ @param events_waits_history_long_sizing table sizing
+*/
+int init_events_waits_history_long(uint events_waits_history_long_sizing)
+{
+ events_waits_history_long_size= events_waits_history_long_sizing;
+ events_waits_history_long_full= false;
+ PFS_atomic::store_u32(&events_waits_history_long_index, 0);
+
+ if (events_waits_history_long_size == 0)
+ return 0;
+
+ events_waits_history_long_array=
+ PFS_MALLOC_ARRAY(events_waits_history_long_size, PFS_events_waits,
+ MYF(MY_ZEROFILL));
+
+ return (events_waits_history_long_array ? 0 : 1);
+}
+
+/** Cleanup table EVENTS_WAITS_HISTORY_LONG. */
+void cleanup_events_waits_history_long(void)
+{
+ pfs_free(events_waits_history_long_array);
+ events_waits_history_long_array= NULL;
+}
+
+static inline void copy_events_waits(PFS_events_waits *dest,
+ const PFS_events_waits *source)
+{
+ memcpy(dest, source, sizeof(PFS_events_waits));
+}
+
+/**
+ Insert a wait record in table EVENTS_WAITS_HISTORY.
+ @param thread thread that executed the wait
+ @param wait record to insert
+*/
+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;
+
+ /*
+ A concurrent thread executing TRUNCATE TABLE EVENTS_WAITS_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_waits_history will filter this out.
+ */
+ copy_events_waits(&thread->m_waits_history[index], wait);
+
+ index++;
+ if (index >= events_waits_history_per_thread)
+ {
+ index= 0;
+ thread->m_waits_history_full= true;
+ }
+ thread->m_waits_history_index= index;
+}
+
+/**
+ Insert a wait record in table EVENTS_WAITS_HISTORY_LONG.
+ @param wait record to insert
+*/
+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;
+ if (index == 0)
+ events_waits_history_long_full= true;
+
+ /* See related comment in insert_events_waits_history. */
+ copy_events_waits(&events_waits_history_long_array[index], wait);
+}
+
+/** Reset table EVENTS_WAITS_CURRENT data. */
+void reset_events_waits_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_waits *pfs_wait= pfs_thread->m_events_waits_stack;
+ PFS_events_waits *pfs_wait_last= pfs_wait + WAIT_STACK_SIZE;
+
+ for ( ; pfs_wait < pfs_wait_last; pfs_wait++)
+ pfs_wait->m_wait_class= NO_WAIT_CLASS;
+ }
+}
+
+/** Reset table EVENTS_WAITS_HISTORY data. */
+void reset_events_waits_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_waits *wait= pfs_thread->m_waits_history;
+ PFS_events_waits *wait_last= wait + events_waits_history_per_thread;
+
+ pfs_thread->m_waits_history_index= 0;
+ pfs_thread->m_waits_history_full= false;
+ for ( ; wait < wait_last; wait++)
+ wait->m_wait_class= NO_WAIT_CLASS;
+ }
+}
+
+/** Reset table EVENTS_WAITS_HISTORY_LONG data. */
+void reset_events_waits_history_long(void)
+{
+ PFS_atomic::store_u32(&events_waits_history_long_index, 0);
+ events_waits_history_long_full= false;
+
+ PFS_events_waits *wait= events_waits_history_long_array;
+ PFS_events_waits *wait_last= wait + events_waits_history_long_size;
+ for ( ; wait < wait_last; wait++)
+ 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();
+ }
+}
+
+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
new file mode 100644
index 00000000000..a7f7a095b9f
--- /dev/null
+++ b/storage/perfschema/pfs_events_waits.h
@@ -0,0 +1,146 @@
+/* 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 PFS_EVENTS_WAITS_H
+#define PFS_EVENTS_WAITS_H
+
+/**
+ @file storage/perfschema/pfs_events_waits.h
+ Events waits data structures (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_lock.h"
+#include "pfs_events.h"
+
+struct PFS_mutex;
+struct PFS_rwlock;
+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
+{
+ NO_WAIT_CLASS= 0,
+ WAIT_CLASS_MUTEX,
+ WAIT_CLASS_RWLOCK,
+ WAIT_CLASS_COND,
+ WAIT_CLASS_TABLE,
+ WAIT_CLASS_FILE,
+ WAIT_CLASS_SOCKET,
+ WAIT_CLASS_IDLE
+};
+
+/** A wait event record. */
+struct PFS_events_waits : public PFS_events
+{
+ /**
+ The type of wait.
+ Readers:
+ - the consumer threads.
+ Writers:
+ - the producer threads, in the instrumentation.
+ Out of bound Writers:
+ - TRUNCATE EVENTS_WAITS_CURRENT
+ - TRUNCATE EVENTS_WAITS_HISTORY
+ - TRUNCATE EVENTS_WAITS_HISTORY_LONG
+ */
+ events_waits_class m_wait_class;
+ /** Executing thread. */
+ PFS_thread *m_thread;
+ /** 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;
+ /** Operation performed. */
+ enum_operation_type m_operation;
+ /**
+ Number of bytes read/written.
+ 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;
+};
+
+/** 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);
+
+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_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;
+extern ulong events_waits_history_long_size;
+
+int init_events_waits_history_long(uint events_waits_history_long_sizing);
+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
new file mode 100644
index 00000000000..d0dc26b1bf4
--- /dev/null
+++ b/storage/perfschema/pfs_global.cc
@@ -0,0 +1,186 @@
+/* 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/pfs_global.cc
+ Miscellaneous global dependencies (implementation).
+*/
+
+#include "my_global.h"
+#include "my_sys.h"
+#include "pfs_global.h"
+#include "my_net.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef __WIN__
+ #include <winsock2.h>
+#else
+ #include <arpa/inet.h>
+#endif
+
+bool pfs_initialized= false;
+ulonglong pfs_allocated_memory= 0;
+
+/**
+ Memory allocation for the performance schema.
+ The memory used internally in the performance schema implementation
+ is allocated once during startup, and considered static thereafter.
+*/
+void *pfs_malloc(size_t size, myf flags)
+{
+ DBUG_ASSERT(! pfs_initialized);
+ DBUG_ASSERT(size > 0);
+
+ void *ptr;
+
+#ifdef PFS_ALIGNEMENT
+#ifdef HAVE_POSIX_MEMALIGN
+ /* Linux */
+ if (unlikely(posix_memalign(& ptr, PFS_ALIGNEMENT, size)))
+ return NULL;
+#else
+#ifdef HAVE_MEMALIGN
+ /* Solaris */
+ ptr= memalign(PFS_ALIGNEMENT, size);
+ if (unlikely(ptr == NULL))
+ return NULL;
+#else
+#ifdef HAVE_ALIGNED_MALLOC
+ /* Windows */
+ ptr= _aligned_malloc(size, PFS_ALIGNEMENT);
+ if (unlikely(ptr == NULL))
+ return NULL;
+#else
+#error "Missing implementation for PFS_ALIGNENT"
+#endif /* HAVE_ALIGNED_MALLOC */
+#endif /* HAVE_MEMALIGN */
+#endif /* HAVE_POSIX_MEMALIGN */
+#else /* PFS_ALIGNMENT */
+ /* Everything else */
+ ptr= malloc(size);
+ if (unlikely(ptr == NULL))
+ return NULL;
+#endif
+
+ pfs_allocated_memory+= size;
+ if (flags & MY_ZEROFILL)
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+void pfs_free(void *ptr)
+{
+ if (ptr == NULL)
+ return;
+
+#ifdef HAVE_POSIX_MEMALIGN
+ /* Allocated with posix_memalign() */
+ free(ptr);
+#else
+#ifdef HAVE_MEMALIGN
+ /* Allocated with memalign() */
+ free(ptr);
+#else
+#ifdef HAVE_ALIGNED_MALLOC
+ /* Allocated with _aligned_malloc() */
+ _aligned_free(ptr);
+#else
+ /* Allocated with malloc() */
+ free(ptr);
+#endif /* HAVE_ALIGNED_MALLOC */
+#endif /* HAVE_MEMALIGN */
+#endif /* HAVE_POSIX_MEMALIGN */
+}
+
+void pfs_print_error(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ /*
+ Printing to anything else, like the error log, would generate even more
+ recursive calls to the performance schema implementation
+ (file io is instrumented), so that could lead to catastrophic results.
+ Printing to something safe, and low level: stderr only.
+ */
+ vfprintf(stderr, format, args);
+ va_end(args);
+ 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
new file mode 100644
index 00000000000..cddf688ddf4
--- /dev/null
+++ b/storage/perfschema/pfs_global.h
@@ -0,0 +1,138 @@
+/* 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 PFS_GLOBAL_H
+#define PFS_GLOBAL_H
+
+#include "my_global.h"
+#include "my_compiler.h"
+
+/**
+ @file storage/perfschema/pfs_global.h
+ 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;
+
+#if defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_MEMALIGN) || defined(HAVE_ALIGNED_MALLOC)
+#define PFS_ALIGNEMENT 64
+#define PFS_ALIGNED MY_ALIGNED(PFS_ALIGNEMENT)
+#else
+/*
+ Known platforms that do not provide aligned memory:
+ - MacOSX Darwin (osx10.5)
+ For these platforms, compile without the alignment optimization.
+*/
+#define PFS_ALIGNED
+#endif /* HAVE_POSIX_MEMALIGN || HAVE_MEMALIGN || HAVE_ALIGNED_MALLOC */
+
+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;
+ static uint seed2= 0;
+ uint result;
+ register intptr value;
+
+ if (unlikely(max_size == 0))
+ return 0;
+
+ /*
+ ptr is typically an aligned structure, and can be in an array.
+ - The last bits are not random because of alignment,
+ so we divide by 8.
+ - The high bits are mostly constant, especially with 64 bits architectures,
+ but we keep most of them anyway, by doing computation in intptr.
+ The high bits are significant depending on where the data is
+ stored (the data segment, the stack, the heap, ...).
+ - To spread consecutive cells in an array further, we multiply by
+ a factor A. This factor should not be too high, which would cause
+ an overflow and cause loss of randomness (droping the top high bits).
+ The factor is a prime number, to help spread the distribution.
+ - To add more noise, and to be more robust if the calling code is
+ passing a constant value instead of a random identity,
+ we add the previous results, for hysteresys, with a degree 2 polynom,
+ X^2 + X + 1.
+ - Last, a modulo is applied to be within the [0, max_size - 1] range.
+ Note that seed1 and seed2 are static, and are *not* thread safe,
+ which is even better.
+ Effect with arrays: T array[N]
+ - ptr(i) = & array[i] = & array[0] + i * sizeof(T)
+ - ptr(i+1) = ptr(i) + sizeof(T).
+ What we want here, is to have index(i) and index(i+1) fall into
+ very different areas in [0, max_size - 1], to avoid locality.
+ */
+ value= (reinterpret_cast<intptr> (ptr)) >> 3;
+ value*= 1789;
+ value+= seed2 + seed1 + 1;
+
+ result= (static_cast<uint> (value)) % max_size;
+
+ seed2= seed1*seed1;
+ seed1= result;
+
+ DBUG_ASSERT(result < max_size);
+ return result;
+}
+
+void pfs_print_error(const char *format, ...);
+
+/**
+ Given an array defined as T ARRAY[MAX],
+ check that an UNSAFE pointer actually points to an element
+ within the array.
+*/
+#define SANITIZE_ARRAY_BODY(T, ARRAY, MAX, UNSAFE) \
+ intptr offset; \
+ if ((&ARRAY[0] <= UNSAFE) && \
+ (UNSAFE < &ARRAY[MAX])) \
+ { \
+ offset= ((intptr) UNSAFE - (intptr) ARRAY) % sizeof(T); \
+ if (offset == 0) \
+ return UNSAFE; \
+ } \
+ return NULL
+
+#endif
+
diff --git a/storage/perfschema/pfs_host.cc b/storage/perfschema/pfs_host.cc
new file mode 100644
index 00000000000..735480b53db
--- /dev/null
+++ b/storage/perfschema/pfs_host.cc
@@ -0,0 +1,383 @@
+/* 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;
+
+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) && (host_max > 0))
+ {
+ lf_hash_init(&host_hash, sizeof(PFS_host*), LF_HASH_UNIQUE,
+ 0, 0, host_hash_get_key, &my_charset_bin);
+ host_hash.size= host_max;
+ 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))
+ {
+ PFS_host *pfs;
+ pfs= *entry;
+ DBUG_ASSERT(pfs == 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..eb0ff6efc6f
--- /dev/null
+++ b/storage/perfschema/pfs_host.h
@@ -0,0 +1,112 @@
+/* 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_ALIGNED 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;
+
+extern LF_HASH host_hash;
+
+/** @} */
+#endif
+
diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc
new file mode 100644
index 00000000000..335f85bd45e
--- /dev/null
+++ b/storage/perfschema/pfs_instr.cc
@@ -0,0 +1,2187 @@
+/* Copyright (c) 2008, 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 */
+
+/**
+ @file storage/perfschema/pfs_instr.cc
+ Performance schema instruments (implementation).
+*/
+
+#include <my_global.h>
+#include <string.h>
+
+#include "my_sys.h"
+#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
+ @{
+*/
+
+/** Size of the mutex instances array. @sa mutex_array */
+ulong mutex_max;
+/** Number of mutexes instance lost. @sa mutex_array */
+ulong mutex_lost;
+/** Size of the rwlock instances array. @sa rwlock_array */
+ulong rwlock_max;
+/** Number or rwlock instances lost. @sa rwlock_array */
+ulong rwlock_lost;
+/** Size of the conditions instances array. @sa cond_array */
+ulong cond_max;
+/** Number of conditions instances lost. @sa cond_array */
+ulong cond_lost;
+/** Size of the thread instances array. @sa thread_array */
+ulong thread_max;
+/** Number or thread instances lost. @sa thread_array */
+ulong thread_lost;
+/** Size of the file instances array. @sa file_array */
+ulong file_max;
+/** Number of file instances lost. @sa file_array */
+ulong file_lost;
+/**
+ Size of the file handle array. @sa file_handle_array.
+ Signed value, for easier comparisons with a file descriptor number.
+*/
+long file_handle_max;
+/** Number of file handle lost. @sa file_handle_array */
+ulong file_handle_lost;
+/** Size of the table instances array. @sa table_array */
+ulong table_max;
+/** Number of table instances lost. @sa table_array */
+ulong table_lost;
+/** 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 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;
+/** Size of connection attribute storage per thread */
+ulong session_connect_attrs_size_per_thread;
+/** Number of connection attributes lost */
+ulong session_connect_attrs_lost= 0;
+
+/**
+ Mutex instrumentation instances array.
+ @sa mutex_max
+ @sa mutex_lost
+*/
+PFS_mutex *mutex_array= NULL;
+
+/**
+ RWLock instrumentation instances array.
+ @sa rwlock_max
+ @sa rwlock_lost
+*/
+PFS_rwlock *rwlock_array= NULL;
+
+/**
+ Condition instrumentation instances array.
+ @sa cond_max
+ @sa cond_lost
+*/
+PFS_cond *cond_array= NULL;
+
+/**
+ Thread instrumentation instances array.
+ @sa thread_max
+ @sa thread_lost
+*/
+PFS_thread *thread_array= NULL;
+
+/**
+ File instrumentation instances array.
+ @sa file_max
+ @sa file_lost
+ @sa filename_hash
+*/
+PFS_file *file_array= NULL;
+
+/**
+ File instrumentation handle array.
+ @sa file_handle_max
+ @sa file_handle_lost
+*/
+PFS_file **file_handle_array= NULL;
+
+/**
+ Table instrumentation instances array.
+ @sa table_max
+ @sa table_lost
+*/
+PFS_table *table_array= NULL;
+
+/**
+ Socket instrumentation instances array.
+ @sa socket_max
+ @sa socket_lost
+*/
+PFS_socket *socket_array= NULL;
+
+PFS_stage_stat *global_instr_class_stages_array= NULL;
+PFS_statement_stat *global_instr_class_statements_array= NULL;
+
+static volatile uint64 thread_internal_id_counter= 0;
+
+static uint thread_instr_class_waits_sizing;
+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_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;
+static char *thread_session_connect_attrs_array= NULL;
+
+/** Hash table for instrumented files. */
+LF_HASH filename_hash;
+/** True if filename_hash is initialized. */
+static bool filename_hash_inited= false;
+
+/**
+ Initialize all the instruments instance buffers.
+ @param param sizing parameters
+ @return 0 on success
+*/
+int init_instruments(const PFS_global_param *param)
+{
+ uint thread_waits_history_sizing;
+ uint thread_stages_history_sizing;
+ uint thread_statements_history_sizing;
+ uint thread_statements_stack_sizing;
+ uint thread_session_connect_attrs_sizing;
+ uint index;
+
+ /* 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;
+ rwlock_lost= 0;
+ cond_max= param->m_cond_sizing;
+ cond_lost= 0;
+ file_max= param->m_file_sizing;
+ file_lost= 0;
+ file_handle_max= param->m_file_handle_sizing;
+ file_handle_lost= 0;
+ table_max= param->m_table_sizing;
+ table_lost= 0;
+ thread_max= param->m_thread_sizing;
+ thread_lost= 0;
+ socket_max= param->m_socket_sizing;
+ socket_lost= 0;
+
+ events_waits_history_per_thread= param->m_events_waits_history_sizing;
+ thread_waits_history_sizing= param->m_thread_sizing
+ * events_waits_history_per_thread;
+
+ thread_instr_class_waits_sizing= param->m_thread_sizing
+ * 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;
+
+ session_connect_attrs_size_per_thread= param->m_session_connect_attrs_sizing;
+ thread_session_connect_attrs_sizing= param->m_thread_sizing
+ * session_connect_attrs_size_per_thread;
+ session_connect_attrs_lost= 0;
+
+ mutex_array= NULL;
+ rwlock_array= NULL;
+ cond_array= NULL;
+ file_array= NULL;
+ file_handle_array= NULL;
+ table_array= NULL;
+ socket_array= NULL;
+ thread_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)
+ {
+ mutex_array= PFS_MALLOC_ARRAY(mutex_max, PFS_mutex, MYF(MY_ZEROFILL));
+ if (unlikely(mutex_array == NULL))
+ return 1;
+ }
+
+ if (rwlock_max > 0)
+ {
+ rwlock_array= PFS_MALLOC_ARRAY(rwlock_max, PFS_rwlock, MYF(MY_ZEROFILL));
+ if (unlikely(rwlock_array == NULL))
+ return 1;
+ }
+
+ if (cond_max > 0)
+ {
+ cond_array= PFS_MALLOC_ARRAY(cond_max, PFS_cond, MYF(MY_ZEROFILL));
+ if (unlikely(cond_array == NULL))
+ return 1;
+ }
+
+ if (file_max > 0)
+ {
+ file_array= PFS_MALLOC_ARRAY(file_max, PFS_file, MYF(MY_ZEROFILL));
+ if (unlikely(file_array == NULL))
+ return 1;
+ }
+
+ if (file_handle_max > 0)
+ {
+ file_handle_array= PFS_MALLOC_ARRAY(file_handle_max, PFS_file*, MYF(MY_ZEROFILL));
+ if (unlikely(file_handle_array == NULL))
+ return 1;
+ }
+
+ if (table_max > 0)
+ {
+ table_array= PFS_MALLOC_ARRAY(table_max, PFS_table, MYF(MY_ZEROFILL));
+ if (unlikely(table_array == NULL))
+ return 1;
+ }
+
+ if (socket_max > 0)
+ {
+ socket_array= PFS_MALLOC_ARRAY(socket_max, PFS_socket, MYF(MY_ZEROFILL));
+ if (unlikely(socket_array == NULL))
+ return 1;
+ }
+
+ if (thread_max > 0)
+ {
+ thread_array= PFS_MALLOC_ARRAY(thread_max, PFS_thread, MYF(MY_ZEROFILL));
+ if (unlikely(thread_array == NULL))
+ return 1;
+ }
+
+ if (thread_waits_history_sizing > 0)
+ {
+ thread_waits_history_array=
+ PFS_MALLOC_ARRAY(thread_waits_history_sizing, PFS_events_waits,
+ MYF(MY_ZEROFILL));
+ if (unlikely(thread_waits_history_array == NULL))
+ return 1;
+ }
+
+ if (thread_instr_class_waits_sizing > 0)
+ {
+ thread_instr_class_waits_array=
+ PFS_MALLOC_ARRAY(thread_instr_class_waits_sizing,
+ PFS_single_stat, MYF(MY_ZEROFILL));
+ if (unlikely(thread_instr_class_waits_array == NULL))
+ return 1;
+
+ for (index= 0; index < thread_instr_class_waits_sizing; index++)
+ thread_instr_class_waits_array[index].reset();
+ }
+
+ if (thread_stages_history_sizing > 0)
+ {
+ thread_stages_history_array=
+ PFS_MALLOC_ARRAY(thread_stages_history_sizing, PFS_events_stages,
+ MYF(MY_ZEROFILL));
+ if (unlikely(thread_stages_history_array == NULL))
+ return 1;
+ }
+
+ 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))
+ return 1;
+
+ for (index= 0; index < thread_instr_class_stages_sizing; index++)
+ thread_instr_class_stages_array[index].reset();
+ }
+
+ 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))
+ return 1;
+ }
+
+ 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))
+ return 1;
+ }
+
+ 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))
+ return 1;
+
+ for (index= 0; index < thread_instr_class_statements_sizing; index++)
+ thread_instr_class_statements_array[index].reset();
+ }
+
+ if (thread_session_connect_attrs_sizing > 0)
+ {
+ thread_session_connect_attrs_array=
+ (char *)pfs_malloc(thread_session_connect_attrs_sizing, MYF(MY_ZEROFILL));
+ if (unlikely(thread_session_connect_attrs_array == NULL))
+ return 1;
+ }
+
+ 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];
+ thread_array[index].m_session_connect_attrs=
+ &thread_session_connect_attrs_array[index * session_connect_attrs_size_per_thread];
+ }
+
+ 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))
+ return 1;
+
+ for (index= 0; index < stage_class_max; index++)
+ global_instr_class_stages_array[index].reset();
+ }
+
+ 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))
+ return 1;
+
+ for (index= 0; index < statement_class_max; index++)
+ global_instr_class_statements_array[index].reset();
+ }
+
+ return 0;
+}
+
+/** Cleanup all the instruments buffers. */
+void cleanup_instruments(void)
+{
+ pfs_free(mutex_array);
+ mutex_array= NULL;
+ mutex_max= 0;
+ pfs_free(rwlock_array);
+ rwlock_array= NULL;
+ rwlock_max= 0;
+ pfs_free(cond_array);
+ cond_array= NULL;
+ cond_max= 0;
+ pfs_free(file_array);
+ file_array= NULL;
+ file_max= 0;
+ pfs_free(file_handle_array);
+ file_handle_array= NULL;
+ file_handle_max= 0;
+ pfs_free(table_array);
+ table_array= NULL;
+ table_max= 0;
+ pfs_free(socket_array);
+ socket_array= NULL;
+ socket_max= 0;
+ pfs_free(thread_array);
+ thread_array= NULL;
+ thread_max= 0;
+ 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_stages_array);
+ global_instr_class_stages_array= NULL;
+ pfs_free(global_instr_class_statements_array);
+ global_instr_class_statements_array= NULL;
+ pfs_free(thread_session_connect_attrs_array);
+ thread_session_connect_attrs_array=NULL;
+}
+
+C_MODE_START
+/** Get hash table key for instrumented files. */
+static uchar *filename_hash_get_key(const uchar *entry, size_t *length,
+ my_bool)
+{
+ const PFS_file * const *typed_entry;
+ const PFS_file *file;
+ const void *result;
+ typed_entry= reinterpret_cast<const PFS_file* const *> (entry);
+ DBUG_ASSERT(typed_entry != NULL);
+ file= *typed_entry;
+ DBUG_ASSERT(file != NULL);
+ *length= file->m_filename_length;
+ result= file->m_filename;
+ return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
+}
+C_MODE_END
+
+/**
+ Initialize the file name hash.
+ @return 0 on success
+*/
+int init_file_hash(void)
+{
+ if ((! filename_hash_inited) && (file_max > 0))
+ {
+ lf_hash_init(&filename_hash, sizeof(PFS_file*), LF_HASH_UNIQUE,
+ 0, 0, filename_hash_get_key, &my_charset_bin);
+ filename_hash.size= file_max;
+ filename_hash_inited= true;
+ }
+ return 0;
+}
+
+/** Cleanup the file name hash. */
+void cleanup_file_hash(void)
+{
+ if (filename_hash_inited)
+ {
+ lf_hash_destroy(&filename_hash);
+ filename_hash_inited= false;
+ }
+}
+
+void PFS_scan::init(uint random, uint max_size)
+{
+ m_pass= 0;
+
+ if (max_size == 0)
+ {
+ /* Degenerated case, no buffer */
+ m_pass_max= 0;
+ return;
+ }
+
+ DBUG_ASSERT(random < max_size);
+
+ if (PFS_MAX_ALLOC_RETRY < max_size)
+ {
+ /*
+ The buffer is big compared to PFS_MAX_ALLOC_RETRY,
+ scan it only partially.
+ */
+ if (random + PFS_MAX_ALLOC_RETRY < max_size)
+ {
+ /*
+ Pass 1: [random, random + PFS_MAX_ALLOC_RETRY - 1]
+ Pass 2: not used.
+ */
+ m_pass_max= 1;
+ m_first[0]= random;
+ m_last[0]= random + PFS_MAX_ALLOC_RETRY;
+ m_first[1]= 0;
+ m_last[1]= 0;
+ }
+ else
+ {
+ /*
+ Pass 1: [random, max_size - 1]
+ Pass 2: [0, ...]
+ The combined length of pass 1 and 2 is PFS_MAX_ALLOC_RETRY.
+ */
+ m_pass_max= 2;
+ m_first[0]= random;
+ m_last[0]= max_size;
+ m_first[1]= 0;
+ m_last[1]= PFS_MAX_ALLOC_RETRY - (max_size - random);
+ }
+ }
+ else
+ {
+ /*
+ The buffer is small compared to PFS_MAX_ALLOC_RETRY,
+ scan it in full in two passes.
+ Pass 1: [random, max_size - 1]
+ Pass 2: [0, random - 1]
+ */
+ m_pass_max= 2;
+ m_first[0]= random;
+ m_last[0]= max_size;
+ m_first[1]= 0;
+ m_last[1]= random;
+ }
+
+ DBUG_ASSERT(m_first[0] < max_size);
+ DBUG_ASSERT(m_first[1] < max_size);
+ DBUG_ASSERT(m_last[1] <= max_size);
+ DBUG_ASSERT(m_last[1] <= max_size);
+ /* The combined length of all passes should not exceed PFS_MAX_ALLOC_RETRY. */
+ DBUG_ASSERT((m_last[0] - m_first[0]) +
+ (m_last[1] - m_first[1]) <= PFS_MAX_ALLOC_RETRY);
+}
+
+/**
+ Create instrumentation for a mutex instance.
+ @param klass the mutex class
+ @param identity the mutex address
+ @return a mutex instance, or NULL
+*/
+PFS_mutex* create_mutex(PFS_mutex_class *klass, const void *identity)
+{
+ static uint PFS_ALIGNED mutex_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_mutex *pfs;
+
+ while (++attempts <= mutex_max)
+ {
+ /*
+ 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.free_to_dirty())
+ {
+ 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_mutex_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;
+ return pfs;
+ }
+ }
+ }
+
+ mutex_lost++;
+ return NULL;
+}
+
+/**
+ Destroy instrumentation for a mutex instance.
+ @param pfs the mutex to destroy
+*/
+void destroy_mutex(PFS_mutex *pfs)
+{
+ DBUG_ASSERT(pfs != NULL);
+ PFS_mutex_class *klass= pfs->m_class;
+ /* Aggregate to EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME */
+ klass->m_mutex_stat.aggregate(& pfs->m_mutex_stat);
+ pfs->m_mutex_stat.reset();
+ if (klass->is_singleton())
+ klass->m_singleton= NULL;
+ pfs->m_lock.allocated_to_free();
+}
+
+/**
+ Create instrumentation for a rwlock instance.
+ @param klass the rwlock class
+ @param identity the rwlock address
+ @return a rwlock instance, or NULL
+*/
+PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity)
+{
+ static uint PFS_ALIGNED rwlock_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_rwlock *pfs;
+
+ while (++attempts <= rwlock_max)
+ {
+ /* 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.free_to_dirty())
+ {
+ 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_rwlock_stat.reset();
+ pfs->m_lock.dirty_to_allocated();
+ 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;
+ return pfs;
+ }
+ }
+ }
+
+ rwlock_lost++;
+ return NULL;
+}
+
+/**
+ Destroy instrumentation for a rwlock instance.
+ @param pfs the rwlock to destroy
+*/
+void destroy_rwlock(PFS_rwlock *pfs)
+{
+ DBUG_ASSERT(pfs != NULL);
+ PFS_rwlock_class *klass= pfs->m_class;
+ /* Aggregate to EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME */
+ klass->m_rwlock_stat.aggregate(& pfs->m_rwlock_stat);
+ pfs->m_rwlock_stat.reset();
+ if (klass->is_singleton())
+ klass->m_singleton= NULL;
+ pfs->m_lock.allocated_to_free();
+}
+
+/**
+ Create instrumentation for a condition instance.
+ @param klass the condition class
+ @param identity the condition address
+ @return a condition instance, or NULL
+*/
+PFS_cond* create_cond(PFS_cond_class *klass, const void *identity)
+{
+ static uint PFS_ALIGNED cond_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_cond *pfs;
+
+ while (++attempts <= cond_max)
+ {
+ /* 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.free_to_dirty())
+ {
+ 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;
+ return pfs;
+ }
+ }
+ }
+
+ cond_lost++;
+ return NULL;
+}
+
+/**
+ Destroy instrumentation for a condition instance.
+ @param pfs the condition to destroy
+*/
+void destroy_cond(PFS_cond *pfs)
+{
+ DBUG_ASSERT(pfs != NULL);
+ PFS_cond_class *klass= pfs->m_class;
+ /* Aggregate to EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME */
+ klass->m_cond_stat.aggregate(& pfs->m_cond_stat);
+ pfs->m_wait_stat.reset();
+ if (klass->is_singleton())
+ klass->m_singleton= NULL;
+ pfs->m_lock.allocated_to_free();
+}
+
+PFS_thread* PFS_thread::get_current_thread()
+{
+ PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ return pfs;
+}
+
+void PFS_thread::reset_session_connect_attrs()
+{
+ m_session_connect_attrs_length= 0;
+ m_session_connect_attrs_cs= NULL;
+
+ if ((m_session_connect_attrs != NULL) &&
+ (session_connect_attrs_size_per_thread > 0) )
+ {
+ /* Do not keep user data */
+ memset(m_session_connect_attrs, 0, session_connect_attrs_size_per_thread);
+ }
+}
+
+/**
+ Create instrumentation for a thread instance.
+ @param klass the thread class
+ @param identity the thread address,
+ or a value characteristic of this thread
+ @param processlist_id the PROCESSLIST id,
+ or 0 if unknown
+ @return a thread instance, or NULL
+*/
+PFS_thread* create_thread(PFS_thread_class *klass, const void *identity,
+ ulonglong processlist_id)
+{
+ static uint PFS_ALIGNED thread_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_thread *pfs;
+
+ while (++attempts <= thread_max)
+ {
+ /* 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.free_to_dirty())
+ {
+ pfs->m_thread_internal_id=
+ PFS_atomic::add_u64(&thread_internal_id_counter, 1);
+ pfs->m_parent_thread_internal_id= 0;
+ pfs->m_processlist_id= processlist_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->reset_session_connect_attrs();
+
+ 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_ptr= NULL;
+ pfs->m_processlist_state_length= 0;
+ pfs->m_processlist_info_ptr= NULL;
+ pfs->m_processlist_info_length= 0;
+ pfs->m_processlist_lock.set_allocated();
+
+ 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++)
+ {
+ 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();
+ return pfs;
+ }
+ }
+ }
+
+ thread_lost++;
+ 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.
+ Sanitizing data is required when the data can be
+ damaged with expected race conditions, for example
+ involving EVENTS_WAITS_HISTORY_LONG.
+ @param unsafe the pointer to sanitize
+ @return a valid pointer, or NULL
+*/
+PFS_thread *sanitize_thread(PFS_thread *unsafe)
+{
+ SANITIZE_ARRAY_BODY(PFS_thread, thread_array, thread_max, unsafe);
+}
+
+PFS_file *sanitize_file(PFS_file *unsafe)
+{
+ SANITIZE_ARRAY_BODY(PFS_file, file_array, file_max, unsafe);
+}
+
+PFS_socket *sanitize_socket(PFS_socket *unsafe)
+{
+ SANITIZE_ARRAY_BODY(PFS_socket, socket_array, socket_max, unsafe);
+}
+
+/**
+ Destroy instrumentation for a thread instance.
+ @param pfs the thread to destroy
+*/
+void destroy_thread(PFS_thread *pfs)
+{
+ DBUG_ASSERT(pfs != NULL);
+ pfs->reset_session_connect_attrs();
+ 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);
+ pfs->m_filename_hash_pins= NULL;
+ }
+ if (pfs->m_table_share_hash_pins)
+ {
+ lf_hash_put_pins(pfs->m_table_share_hash_pins);
+ pfs->m_table_share_hash_pins= NULL;
+ }
+ 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();
+}
+
+/**
+ Get the hash pins for @filename_hash.
+ @param thread The running thread.
+ @returns The LF_HASH pins for the thread.
+*/
+LF_PINS* get_filename_hash_pins(PFS_thread *thread)
+{
+ if (unlikely(thread->m_filename_hash_pins == NULL))
+ {
+ if (! filename_hash_inited)
+ return NULL;
+ thread->m_filename_hash_pins= lf_hash_get_pins(&filename_hash);
+ }
+ return thread->m_filename_hash_pins;
+}
+
+/**
+ Find or create instrumentation for a file instance by file name.
+ @param thread the executing instrumented thread
+ @param klass the file class
+ @param filename the file name
+ @param len the length in bytes of filename
+ @param create create a file instance if none found
+ @return a file instance, or NULL
+*/
+PFS_file*
+find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
+ const char *filename, uint len, bool create)
+{
+ PFS_file *pfs;
+
+ DBUG_ASSERT(klass != NULL || ! create);
+
+ LF_PINS *pins= get_filename_hash_pins(thread);
+ if (unlikely(pins == NULL))
+ {
+ file_lost++;
+ return NULL;
+ }
+
+ char safe_buffer[FN_REFLEN];
+ const char *safe_filename;
+
+ if (len >= FN_REFLEN)
+ {
+ /*
+ The instrumented code uses file names that exceeds FN_REFLEN.
+ This could be legal for instrumentation on non mysys APIs,
+ so we support it.
+ Truncate the file name so that:
+ - it fits into pfs->m_filename
+ - it is safe to use mysys apis to normalize the file name.
+ */
+ memcpy(safe_buffer, filename, FN_REFLEN - 1);
+ safe_buffer[FN_REFLEN - 1]= 0;
+ safe_filename= safe_buffer;
+ }
+ else
+ safe_filename= filename;
+
+ /*
+ Normalize the file name to avoid duplicates when using aliases:
+ - absolute or relative paths
+ - symbolic links
+ Names are resolved as follows:
+ - /real/path/to/real_file ==> same
+ - /path/with/link/to/real_file ==> /real/path/to/real_file
+ - real_file ==> /real/path/to/real_file
+ - ./real_file ==> /real/path/to/real_file
+ - /real/path/to/sym_link ==> same
+ - /path/with/link/to/sym_link ==> /real/path/to/sym_link
+ - sym_link ==> /real/path/to/sym_link
+ - ./sym_link ==> /real/path/to/sym_link
+ When the last component of a file is a symbolic link,
+ the last component is *not* resolved, so that all file io
+ operations on a link (create, read, write, delete) are counted
+ against the link itself, not the target file.
+ Resolving the name would lead to create counted against the link,
+ and read/write/delete counted against the target, leading to
+ incoherent results and instrumentation leaks.
+ Also note that, when creating files, this name resolution
+ works properly for files that do not exist (yet) on the file system.
+ */
+ char buffer[FN_REFLEN];
+ char dirbuffer[FN_REFLEN];
+ size_t dirlen;
+ const char *normalized_filename;
+ int normalized_length;
+
+ dirlen= dirname_length(safe_filename);
+ if (dirlen == 0)
+ {
+ dirbuffer[0]= FN_CURLIB;
+ dirbuffer[1]= FN_LIBCHAR;
+ dirbuffer[2]= '\0';
+ }
+ else
+ {
+ memcpy(dirbuffer, safe_filename, dirlen);
+ dirbuffer[dirlen]= '\0';
+ }
+
+ if (my_realpath(buffer, dirbuffer, MYF(0)) != 0)
+ {
+ file_lost++;
+ return NULL;
+ }
+
+ /* 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))
+ *ptr++= FN_LIBCHAR;
+ if (buf_end > ptr)
+ strncpy(ptr, safe_filename + dirlen, buf_end - ptr);
+ *buf_end= '\0';
+
+ normalized_filename= buffer;
+ normalized_length= strlen(normalized_filename);
+
+ PFS_file **entry;
+ uint retry_count= 0;
+ const uint retry_max= 3;
+ static uint PFS_ALIGNED 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));
+ if (entry && (entry != MY_ERRPTR))
+ {
+ pfs= *entry;
+ pfs->m_file_stat.m_open_count++;
+ lf_hash_search_unpin(pins);
+ return pfs;
+ }
+
+ lf_hash_search_unpin(pins);
+
+ if (! create)
+ {
+ /* No lost counter, just looking for the file existence. */
+ return NULL;
+ }
+
+ while (++attempts <= file_max)
+ {
+ /* 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.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_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_lock.dirty_to_allocated();
+ if (klass->is_singleton())
+ klass->m_singleton= pfs;
+ return pfs;
+ }
+
+ pfs->m_lock.dirty_to_free();
+
+ if (res > 0)
+ {
+ /* Duplicate insert by another thread */
+ if (++retry_count > retry_max)
+ {
+ /* Avoid infinite loops */
+ file_lost++;
+ return NULL;
+ }
+ goto search;
+ }
+
+ /* OOM in lf_hash_insert */
+ file_lost++;
+ return NULL;
+ }
+ }
+ }
+
+ file_lost++;
+ return NULL;
+}
+
+/**
+ Release instrumentation for a file instance.
+ @param pfs the file to release
+*/
+void release_file(PFS_file *pfs)
+{
+ DBUG_ASSERT(pfs != NULL);
+ pfs->m_file_stat.m_open_count--;
+}
+
+/**
+ Destroy instrumentation for a file instance.
+ @param thread the executing thread instrumentation
+ @param pfs the file to destroy
+*/
+void destroy_file(PFS_thread *thread, PFS_file *pfs)
+{
+ DBUG_ASSERT(thread != NULL);
+ DBUG_ASSERT(pfs != NULL);
+ PFS_file_class *klass= pfs->m_class;
+
+ /* Aggregate to FILE_SUMMARY_BY_EVENT_NAME */
+ klass->m_file_stat.aggregate(& pfs->m_file_stat);
+ pfs->m_file_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();
+}
+
+/**
+ 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, PFS_thread *opening_thread,
+ const void *identity)
+{
+ static uint PFS_ALIGNED table_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_table *pfs;
+
+ 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();
+ return pfs;
+ }
+ }
+ }
+
+ table_lost++;
+ 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);
+ if (safe_share != NULL)
+ {
+ if (m_has_io_stats && m_has_lock_stats)
+ {
+ safe_aggregate(& m_table_stat, safe_share);
+ m_has_io_stats= false;
+ m_has_lock_stats= false;
+ }
+ else if (m_has_io_stats)
+ {
+ safe_aggregate_io(& m_table_stat, safe_share);
+ m_has_io_stats= false;
+ }
+ else if (m_has_lock_stats)
+ {
+ safe_aggregate_lock(& m_table_stat, safe_share);
+ m_has_lock_stats= false;
+ }
+ }
+}
+
+void PFS_table::sanitized_aggregate_io(void)
+{
+ PFS_table_share *safe_share= sanitize_table_share(m_share);
+ if (safe_share != NULL && m_has_io_stats)
+ {
+ safe_aggregate_io(& m_table_stat, safe_share);
+ m_has_io_stats= false;
+ }
+}
+
+void PFS_table::sanitized_aggregate_lock(void)
+{
+ PFS_table_share *safe_share= sanitize_table_share(m_share);
+ if (safe_share != NULL && m_has_lock_stats)
+ {
+ safe_aggregate_lock(& m_table_stat, safe_share);
+ m_has_lock_stats= false;
+ }
+}
+
+void PFS_table::safe_aggregate(PFS_table_stat *table_stat,
+ PFS_table_share *table_share)
+{
+ DBUG_ASSERT(table_stat != NULL);
+ DBUG_ASSERT(table_share != NULL);
+
+ uint key_count= sanitize_index_count(table_share->m_key_count);
+
+ /* Aggregate to TABLE_IO_SUMMARY, TABLE_LOCK_SUMMARY */
+ table_share->m_table_stat.aggregate(table_stat, key_count);
+ table_stat->fast_reset();
+}
+
+void PFS_table::safe_aggregate_io(PFS_table_stat *table_stat,
+ PFS_table_share *table_share)
+{
+ DBUG_ASSERT(table_stat != NULL);
+ DBUG_ASSERT(table_share != NULL);
+
+ uint key_count= sanitize_index_count(table_share->m_key_count);
+
+ /* Aggregate to TABLE_IO_SUMMARY */
+ table_share->m_table_stat.aggregate_io(table_stat, key_count);
+ table_stat->fast_reset_io();
+}
+
+void PFS_table::safe_aggregate_lock(PFS_table_stat *table_stat,
+ PFS_table_share *table_share)
+{
+ DBUG_ASSERT(table_stat != NULL);
+ DBUG_ASSERT(table_share != NULL);
+
+ /* 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_ASSERT(pfs != NULL);
+ pfs->m_share->dec_refcount();
+ pfs->m_lock.allocated_to_free();
+}
+
+/**
+ 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 my_socket *fd,
+ const struct sockaddr *addr, socklen_t addr_len)
+{
+ static uint PFS_ALIGNED socket_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_socket *pfs;
+
+ uint fd_used= 0;
+ uint addr_len_used= addr_len;
+
+ if (fd != NULL)
+ fd_used= *fd;
+
+ if (addr_len_used > sizeof(sockaddr_storage))
+ addr_len_used= sizeof(sockaddr_storage);
+
+ while (++attempts <= socket_max)
+ {
+ index= PFS_atomic::add_u32(& socket_monotonic_index, 1) % socket_max;
+ pfs= socket_array + index;
+
+ if (pfs->m_lock.is_free())
+ {
+ if (pfs->m_lock.free_to_dirty())
+ {
+ pfs->m_fd= fd_used;
+ /* There is no socket object, so we use the instrumentation. */
+ 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_thread_owner= NULL;
+
+ pfs->m_addr_len= addr_len_used;
+ if ((addr != NULL) && (addr_len_used > 0))
+ {
+ pfs->m_addr_len= addr_len_used;
+ memcpy(&pfs->m_sock_addr, addr, addr_len_used);
+ }
+ else
+ {
+ pfs->m_addr_len= 0;
+ }
+
+ pfs->m_lock.dirty_to_allocated();
+
+ if (klass->is_singleton())
+ klass->m_singleton= pfs;
+ return pfs;
+ }
+ }
+ }
+
+ socket_lost++;
+ return NULL;
+}
+
+/**
+ Destroy instrumentation for a socket instance.
+ @param pfs the socket to destroy
+*/
+void destroy_socket(PFS_socket *pfs)
+{
+ DBUG_ASSERT(pfs != NULL);
+ PFS_socket_class *klass= pfs->m_class;
+
+ /* 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();
+}
+
+static void reset_mutex_waits_by_instance(void)
+{
+ PFS_mutex *pfs= mutex_array;
+ PFS_mutex *pfs_last= mutex_array + mutex_max;
+
+ for ( ; pfs < pfs_last; pfs++)
+ pfs->m_mutex_stat.reset();
+}
+
+static void reset_rwlock_waits_by_instance(void)
+{
+ PFS_rwlock *pfs= rwlock_array;
+ PFS_rwlock *pfs_last= rwlock_array + rwlock_max;
+
+ for ( ; pfs < pfs_last; pfs++)
+ pfs->m_rwlock_stat.reset();
+}
+
+static void reset_cond_waits_by_instance(void)
+{
+ PFS_cond *pfs= cond_array;
+ PFS_cond *pfs_last= cond_array + cond_max;
+
+ for ( ; pfs < pfs_last; pfs++)
+ pfs->m_cond_stat.reset();
+}
+
+static void reset_file_waits_by_instance(void)
+{
+ PFS_file *pfs= file_array;
+ PFS_file *pfs_last= file_array + file_max;
+
+ for ( ; pfs < pfs_last; pfs++)
+ pfs->m_file_stat.reset();
+}
+
+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)
+{
+ reset_mutex_waits_by_instance();
+ reset_rwlock_waits_by_instance();
+ reset_cond_waits_by_instance();
+ reset_file_waits_by_instance();
+ reset_socket_waits_by_instance();
+}
+
+/** Reset the io statistics per file instance. */
+void reset_file_instance_io(void)
+{
+ PFS_file *pfs= file_array;
+ PFS_file *pfs_last= file_array + file_max;
+
+ for ( ; pfs < pfs_last; pfs++)
+ pfs->m_file_stat.m_io_stat.reset();
+}
+
+/** 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;
+
+ for ( ; pfs < pfs_last; pfs++)
+ pfs->m_socket_stat.m_io_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
new file mode 100644
index 00000000000..2ea44830d2b
--- /dev/null
+++ b/storage/perfschema/pfs_instr.h
@@ -0,0 +1,637 @@
+/* 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 PFS_INSTR_H
+#define PFS_INSTR_H
+
+/**
+ @file storage/perfschema/pfs_instr.h
+ 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 "my_global.h"
+#include "my_compiler.h"
+#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
+ @{
+*/
+
+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;
+ /** Enabled flag. */
+ bool m_enabled;
+ /** Timed flag. */
+ bool m_timed;
+};
+
+/** Instrumented mutex implementation. @see PSI_mutex. */
+struct PFS_ALIGNED PFS_mutex : public PFS_instr
+{
+ /** Mutex identity, typically a pthread_mutex_t. */
+ const void *m_identity;
+ /** Mutex class. */
+ PFS_mutex_class *m_class;
+ /** Instrument statistics. */
+ PFS_mutex_stat m_mutex_stat;
+ /** Current owner. */
+ PFS_thread *m_owner;
+ /**
+ Timestamp of the last lock.
+ This statistic is not exposed in user visible tables yet.
+ */
+ ulonglong m_last_locked;
+};
+
+/** Instrumented rwlock implementation. @see PSI_rwlock. */
+struct PFS_ALIGNED PFS_rwlock : public PFS_instr
+{
+ /** RWLock identity, typically a pthread_rwlock_t. */
+ const void *m_identity;
+ /** RWLock class. */
+ PFS_rwlock_class *m_class;
+ /** Instrument statistics. */
+ PFS_rwlock_stat m_rwlock_stat;
+ /** Current writer thread. */
+ PFS_thread *m_writer;
+ /** Current count of readers. */
+ uint m_readers;
+ /**
+ Timestamp of the last write.
+ This statistic is not exposed in user visible tables yet.
+ */
+ ulonglong m_last_written;
+ /**
+ Timestamp of the last read.
+ This statistic is not exposed in user visible tables yet.
+ */
+ ulonglong m_last_read;
+};
+
+/** Instrumented cond implementation. @see PSI_cond. */
+struct PFS_ALIGNED PFS_cond : public PFS_instr
+{
+ /** Condition identity, typically a pthread_cond_t. */
+ 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;
+};
+
+/** Instrumented File and FILE implementation. @see PSI_file. */
+struct PFS_ALIGNED 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;
+ /** File usage statistics. */
+ PFS_file_stat m_file_stat;
+};
+
+/** Instrumented table implementation. @see PSI_table. */
+struct PFS_ALIGNED 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 (m_has_io_stats && m_has_lock_stats)
+ {
+ safe_aggregate(& m_table_stat, m_share);
+ m_has_io_stats= false;
+ m_has_lock_stats= false;
+ }
+ else if (m_has_io_stats)
+ {
+ safe_aggregate_io(& m_table_stat, m_share);
+ m_has_io_stats= false;
+ }
+ else if (m_has_lock_stats)
+ {
+ safe_aggregate_lock(& m_table_stat, m_share);
+ 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);
+ static void safe_aggregate_io(PFS_table_stat *stat,
+ PFS_table_share *safe_share);
+ static void safe_aggregate_lock(PFS_table_stat *stat,
+ PFS_table_share *safe_share);
+};
+
+/** Instrumented socket implementation. @see PSI_socket. */
+struct PFS_ALIGNED 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 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 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
+ Maximum number of times the code attempts to allocate an item
+ from internal buffers, before giving up.
+*/
+#define PFS_MAX_ALLOC_RETRY 1000
+
+/** The maximun number of passes in @sa PFS_scan. */
+#define PFS_MAX_SCAN_PASS 2
+
+/**
+ Helper to scan circular buffers.
+ Given a buffer of size [0, max_size - 1],
+ and a random starting point in the buffer,
+ this helper returns up to two [first, last -1] intervals that:
+ - fit into the [0, max_size - 1] range,
+ - have a maximum combined length of at most PFS_MAX_ALLOC_RETRY.
+*/
+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_ALIGNED 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;
+ /** 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. */
+ ulonglong m_thread_internal_id;
+ /** Parent internal thread identifier. */
+ ulonglong m_parent_thread_internal_id;
+ /** External (SHOW PROCESSLIST) thread identifier, not unique. */
+ ulong m_processlist_id;
+ /** Thread class. */
+ PFS_thread_class *m_class;
+ /**
+ 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_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. */
+ uint m_waits_history_index;
+ /**
+ Waits history circular buffer.
+ This member holds the data for the table
+ 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;
+ /**
+ Stages history circular buffer.
+ This member holds the data for the table
+ PERFORMANCE_SCHEMA.EVENTS_STAGES_HISTORY.
+ */
+ PFS_events_stages *m_stages_history;
+
+ /** 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;
+ /** Lock for Processlist state, Processlist info. */
+ pfs_lock m_processlist_lock;
+ /** 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;
+
+ /** Reset session connect attributes */
+ void reset_session_connect_attrs();
+
+ /** a buffer for the connection attributes */
+ char *m_session_connect_attrs;
+ /** length used by @c m_connect_attrs */
+ uint m_session_connect_attrs_length;
+ /** character set in which @c m_connect_attrs are encoded */
+ const CHARSET_INFO *m_session_connect_attrs_cs;
+};
+
+extern PFS_stage_stat *global_instr_class_stages_array;
+extern PFS_statement_stat *global_instr_class_statements_array;
+
+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();
+int init_file_hash();
+void cleanup_file_hash();
+PFS_mutex* create_mutex(PFS_mutex_class *mutex_class, const void *identity);
+void destroy_mutex(PFS_mutex *pfs);
+PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity);
+void destroy_rwlock(PFS_rwlock *pfs);
+PFS_cond* create_cond(PFS_cond_class *klass, const void *identity);
+void destroy_cond(PFS_cond *pfs);
+
+PFS_thread* create_thread(PFS_thread_class *klass, const void *identity,
+ ulonglong processlist_id);
+
+void destroy_thread(PFS_thread *pfs);
+
+PFS_file* find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
+ const char *filename, uint len, bool create);
+
+void release_file(PFS_file *pfs);
+void destroy_file(PFS_thread *thread, PFS_file *pfs);
+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 my_socket *fd,
+ const struct sockaddr *addr,
+ socklen_t addr_len);
+void destroy_socket(PFS_socket *pfs);
+
+/* For iterators and show status. */
+
+extern ulong mutex_max;
+extern ulong mutex_lost;
+extern ulong rwlock_max;
+extern ulong rwlock_lost;
+extern ulong cond_max;
+extern ulong cond_lost;
+extern ulong thread_max;
+extern ulong thread_lost;
+extern ulong file_max;
+extern ulong file_lost;
+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 events_stages_history_per_thread;
+extern ulong events_statements_history_per_thread;
+extern ulong locker_lost;
+extern ulong statement_lost;
+extern ulong session_connect_attrs_lost;
+extern ulong session_connect_attrs_size_per_thread;
+
+/* Exposing the data directly, for iterators. */
+
+extern PFS_mutex *mutex_array;
+extern PFS_rwlock *rwlock_array;
+extern PFS_cond *cond_array;
+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_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();
+
+extern LF_HASH filename_hash;
+
+/** @} */
+#endif
+
diff --git a/storage/perfschema/pfs_instr_class.cc b/storage/perfschema/pfs_instr_class.cc
new file mode 100644
index 00000000000..05c85104a94
--- /dev/null
+++ b/storage/perfschema/pfs_instr_class.cc
@@ -0,0 +1,1475 @@
+/* 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_instr_class.cc
+ Performance schema instruments meta data (implementation).
+*/
+
+#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"
+
+#include <string.h>
+
+/**
+ @defgroup Performance_schema_buffers Performance Schema Buffers
+ @ingroup Performance_schema_implementation
+ @{
+*/
+
+/**
+ Global performance schema flag.
+ Indicate if the performance schema is enabled.
+ This flag is set at startup, and never changes.
+*/
+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
+ - a plugin initialization
+*/
+static volatile uint32 mutex_class_dirty_count= 0;
+static volatile uint32 mutex_class_allocated_count= 0;
+static volatile uint32 rwlock_class_dirty_count= 0;
+static volatile uint32 rwlock_class_allocated_count= 0;
+static volatile uint32 cond_class_dirty_count= 0;
+static volatile uint32 cond_class_allocated_count= 0;
+
+/** Size of the mutex class array. @sa mutex_class_array */
+ulong mutex_class_max= 0;
+/** Number of mutex class lost. @sa mutex_class_array */
+ulong mutex_class_lost= 0;
+/** Size of the rwlock class array. @sa rwlock_class_array */
+ulong rwlock_class_max= 0;
+/** Number of rwlock class lost. @sa rwlock_class_array */
+ulong rwlock_class_lost= 0;
+/** Size of the condition class array. @sa cond_class_array */
+ulong cond_class_max= 0;
+/** Number of condition class lost. @sa cond_class_array */
+ulong cond_class_lost= 0;
+/** Size of the thread class array. @sa thread_class_array */
+ulong thread_class_max= 0;
+/** Number of thread class lost. @sa thread_class_array */
+ulong thread_class_lost= 0;
+/** Size of the file class array. @sa file_class_array */
+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;
+
+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.
+ This global variable is written to during:
+ - the performance schema initialization
+ - a plugin initialization
+*/
+static volatile uint32 thread_class_dirty_count= 0;
+static volatile uint32 thread_class_allocated_count= 0;
+
+static PFS_thread_class *thread_class_array= NULL;
+
+/**
+ Table instance array.
+ @sa table_share_max
+ @sa table_share_lost
+ @sa table_share_hash
+*/
+PFS_table_share *table_share_array= NULL;
+
+PFS_ALIGNED PFS_single_stat global_idle_stat;
+PFS_ALIGNED PFS_table_io_stat global_table_io_stat;
+PFS_ALIGNED PFS_table_lock_stat global_table_lock_stat;
+PFS_ALIGNED PFS_instr_class global_table_io_class;
+PFS_ALIGNED PFS_instr_class global_table_lock_class;
+PFS_ALIGNED 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 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
+*/
+LF_HASH table_share_hash;
+/** True if table_share_hash is initialized. */
+static bool table_share_hash_inited= false;
+
+static volatile uint32 file_class_dirty_count= 0;
+static volatile uint32 file_class_allocated_count= 0;
+
+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 wait_class_max= 0;
+uint socket_class_start= 0;
+
+void init_event_name_sizing(const PFS_global_param *param)
+{
+ mutex_class_start= 3; /* global table io, table lock, idle */
+ 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;
+ wait_class_max= socket_class_start + param->m_socket_class_sizing;
+}
+
+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= GLOBAL_TABLE_IO_EVENT_INDEX;
+ 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= GLOBAL_TABLE_LOCK_EVENT_INDEX;
+ 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= GLOBAL_IDLE_EVENT_INDEX;
+ configure_instr_class(&global_idle_class);
+}
+
+/**
+ Initialize the instrument synch class buffers.
+ @param mutex_class_sizing max number of mutex class
+ @param rwlock_class_sizing max number of rwlock class
+ @param cond_class_sizing max number of condition class
+ @return 0 on success
+*/
+int init_sync_class(uint mutex_class_sizing,
+ uint rwlock_class_sizing,
+ uint cond_class_sizing)
+{
+ mutex_class_dirty_count= mutex_class_allocated_count= 0;
+ rwlock_class_dirty_count= rwlock_class_allocated_count= 0;
+ cond_class_dirty_count= cond_class_allocated_count= 0;
+ mutex_class_max= mutex_class_sizing;
+ rwlock_class_max= rwlock_class_sizing;
+ cond_class_max= cond_class_sizing;
+ mutex_class_lost= rwlock_class_lost= cond_class_lost= 0;
+
+ mutex_class_array= NULL;
+ rwlock_class_array= NULL;
+ cond_class_array= NULL;
+
+ if (mutex_class_max > 0)
+ {
+ mutex_class_array= PFS_MALLOC_ARRAY(mutex_class_max, PFS_mutex_class,
+ MYF(MY_ZEROFILL));
+ if (unlikely(mutex_class_array == NULL))
+ return 1;
+ }
+
+ if (rwlock_class_max > 0)
+ {
+ rwlock_class_array= PFS_MALLOC_ARRAY(rwlock_class_max, PFS_rwlock_class,
+ MYF(MY_ZEROFILL));
+ if (unlikely(rwlock_class_array == NULL))
+ return 1;
+ }
+
+ if (cond_class_max > 0)
+ {
+ cond_class_array= PFS_MALLOC_ARRAY(cond_class_max, PFS_cond_class,
+ MYF(MY_ZEROFILL));
+ if (unlikely(cond_class_array == NULL))
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Cleanup the instrument synch class buffers. */
+void cleanup_sync_class(void)
+{
+ pfs_free(mutex_class_array);
+ mutex_class_array= NULL;
+ mutex_class_dirty_count= mutex_class_allocated_count= mutex_class_max= 0;
+ pfs_free(rwlock_class_array);
+ rwlock_class_array= NULL;
+ rwlock_class_dirty_count= rwlock_class_allocated_count= rwlock_class_max= 0;
+ pfs_free(cond_class_array);
+ cond_class_array= NULL;
+ cond_class_dirty_count= cond_class_allocated_count= cond_class_max= 0;
+}
+
+/**
+ Initialize the thread class buffer.
+ @param thread_class_sizing max number of thread class
+ @return 0 on success
+*/
+int init_thread_class(uint thread_class_sizing)
+{
+ int result= 0;
+ thread_class_dirty_count= thread_class_allocated_count= 0;
+ thread_class_max= thread_class_sizing;
+ thread_class_lost= 0;
+
+ if (thread_class_max > 0)
+ {
+ thread_class_array= PFS_MALLOC_ARRAY(thread_class_max, PFS_thread_class,
+ MYF(MY_ZEROFILL));
+ if (unlikely(thread_class_array == NULL))
+ result= 1;
+ }
+ else
+ thread_class_array= NULL;
+
+ return result;
+}
+
+/** Cleanup the thread class buffers. */
+void cleanup_thread_class(void)
+{
+ pfs_free(thread_class_array);
+ thread_class_array= NULL;
+ thread_class_dirty_count= thread_class_allocated_count= 0;
+ thread_class_max= 0;
+}
+
+/**
+ Initialize the table share buffer.
+ @param table_share_sizing max number of table share
+ @return 0 on success
+*/
+int init_table_share(uint table_share_sizing)
+{
+ int result= 0;
+ table_share_max= table_share_sizing;
+ table_share_lost= 0;
+
+ if (table_share_max > 0)
+ {
+ table_share_array= PFS_MALLOC_ARRAY(table_share_max, PFS_table_share,
+ MYF(MY_ZEROFILL));
+ if (unlikely(table_share_array == NULL))
+ result= 1;
+ }
+ else
+ table_share_array= NULL;
+
+ return result;
+}
+
+/** Cleanup the table share buffers. */
+void cleanup_table_share(void)
+{
+ pfs_free(table_share_array);
+ table_share_array= NULL;
+ 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)
+{
+ const PFS_table_share * const *typed_entry;
+ const PFS_table_share *share;
+ const void *result;
+ typed_entry= reinterpret_cast<const PFS_table_share* const *> (entry);
+ DBUG_ASSERT(typed_entry != NULL);
+ share= *typed_entry;
+ DBUG_ASSERT(share != NULL);
+ *length= share->m_key.m_key_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)
+{
+ if ((! table_share_hash_inited) && (table_share_max > 0))
+ {
+ lf_hash_init(&table_share_hash, sizeof(PFS_table_share*), LF_HASH_UNIQUE,
+ 0, 0, table_share_hash_get_key, &my_charset_bin);
+ table_share_hash.size= table_share_max;
+ table_share_hash_inited= true;
+ }
+ return 0;
+}
+
+/** Cleanup the table share hash table. */
+void cleanup_table_share_hash(void)
+{
+ if (table_share_hash_inited)
+ {
+ lf_hash_destroy(&table_share_hash);
+ table_share_hash_inited= false;
+ }
+}
+
+/**
+ 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
+*/
+int init_file_class(uint file_class_sizing)
+{
+ int result= 0;
+ file_class_dirty_count= file_class_allocated_count= 0;
+ file_class_max= file_class_sizing;
+ file_class_lost= 0;
+
+ if (file_class_max > 0)
+ {
+ file_class_array= PFS_MALLOC_ARRAY(file_class_max, PFS_file_class,
+ MYF(MY_ZEROFILL));
+ if (unlikely(file_class_array == NULL))
+ return 1;
+ }
+ else
+ file_class_array= NULL;
+
+ return result;
+}
+
+/** Cleanup the file class buffers. */
+void cleanup_file_class(void)
+{
+ pfs_free(file_class_array);
+ file_class_array= NULL;
+ file_class_dirty_count= file_class_allocated_count= 0;
+ 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,
+ PFS_class_type class_type)
+{
+ DBUG_ASSERT(name_length <= PFS_MAX_INFO_NAME_LENGTH);
+ memset(klass, 0, sizeof(PFS_instr_class));
+ strncpy(klass->m_name, name, name_length);
+ klass->m_name_length= name_length;
+ 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) \
+ for (INDEX= 0; INDEX < MAX; INDEX++) \
+ { \
+ entry= &ARRAY[INDEX]; \
+ if ((entry->m_name_length == NAME_LENGTH) && \
+ (strncmp(entry->m_name, NAME, NAME_LENGTH) == 0)) \
+ { \
+ DBUG_ASSERT(entry->m_flags == flags); \
+ return (INDEX + 1); \
+ } \
+ }
+
+/**
+ Register a mutex instrumentation metadata.
+ @param name the instrumented name
+ @param name_length length in bytes of name
+ @param flags the instrumentation flags
+ @return a mutex instrumentation key
+*/
+PFS_sync_key register_mutex_class(const char *name, uint name_length,
+ int flags)
+{
+ uint32 index;
+ PFS_mutex_class *entry;
+
+ /*
+ This is a full array scan, which is not optimal.
+ This is acceptable since this code is only used at startup,
+ or when a plugin is loaded.
+ */
+ REGISTER_CLASS_BODY_PART(index, mutex_class_array, mutex_class_max,
+ name, name_length)
+ /*
+ Note that:
+ mutex_class_dirty_count is incremented *before* an entry is added
+ mutex_class_allocated_count is incremented *after* an entry is added
+ */
+ index= PFS_atomic::add_u32(&mutex_class_dirty_count, 1);
+
+ if (index < mutex_class_max)
+ {
+ /*
+ The instrument was not found (from a possible previous
+ load / unload of a plugin), allocate it.
+ This code is safe when 2 threads execute in parallel
+ for different mutex classes:
+ - thread 1 registering class A
+ - thread 2 registering class B
+ will not collide in the same mutex_class_array[index] entry.
+ This code does not protect against 2 threads registering
+ in parallel the same class:
+ - thread 1 registering class A
+ - thread 2 registering class A
+ could lead to a duplicate class A entry.
+ This is ok, since this case can not happen in the caller:
+ - classes names are derived from a plugin name
+ ('wait/synch/mutex/<plugin>/xxx')
+ - 2 threads can not register concurrently the same plugin
+ in INSTALL PLUGIN.
+ */
+ entry= &mutex_class_array[index];
+ init_instr_class(entry, name, name_length, flags, PFS_CLASS_MUTEX);
+ entry->m_mutex_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
+
+ Technically, there is a small race condition here:
+ T0:
+ mutex_class_dirty_count= 10
+ mutex_class_allocated_count= 10
+ T1: Thread A increment mutex_class_dirty_count to 11
+ T2: Thread B increment mutex_class_dirty_count to 12
+ T3: Thread A populate entry 11
+ T4: Thread B populate entry 12
+ T5: Thread B increment mutex_class_allocated_count to 11,
+ advertise thread A incomplete record 11,
+ but does not advertise thread B complete record 12
+ T6: Thread A increment mutex_class_allocated_count to 12
+ This has no impact, and is acceptable.
+ A reader will not see record 12 for a short time.
+ A reader will see an incomplete record 11 for a short time,
+ which is ok: the mutex name / statistics will be temporarily
+ empty/NULL/zero, but this won't cause a crash
+ (mutex_class_array is initialized with MY_ZEROFILL).
+ */
+ PFS_atomic::add_u32(&mutex_class_allocated_count, 1);
+ return (index + 1);
+ }
+
+ /*
+ Out of space, report to SHOW STATUS that
+ the allocated memory was too small.
+ */
+ mutex_class_lost++;
+ return 0;
+}
+
+/**
+ Register a rwlock instrumentation metadata.
+ @param name the instrumented name
+ @param name_length length in bytes of name
+ @param flags the instrumentation flags
+ @return a rwlock instrumentation key
+*/
+PFS_sync_key register_rwlock_class(const char *name, uint name_length,
+ int flags)
+{
+ /* See comments in register_mutex_class */
+ uint32 index;
+ PFS_rwlock_class *entry;
+
+ REGISTER_CLASS_BODY_PART(index, rwlock_class_array, rwlock_class_max,
+ name, name_length)
+
+ index= PFS_atomic::add_u32(&rwlock_class_dirty_count, 1);
+
+ if (index < rwlock_class_max)
+ {
+ entry= &rwlock_class_array[index];
+ init_instr_class(entry, name, name_length, flags, PFS_CLASS_RWLOCK);
+ entry->m_rwlock_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);
+ }
+
+ rwlock_class_lost++;
+ return 0;
+}
+
+/**
+ Register a condition instrumentation metadata.
+ @param name the instrumented name
+ @param name_length length in bytes of name
+ @param flags the instrumentation flags
+ @return a condition instrumentation key
+*/
+PFS_sync_key register_cond_class(const char *name, uint name_length,
+ int flags)
+{
+ /* See comments in register_mutex_class */
+ uint32 index;
+ PFS_cond_class *entry;
+
+ REGISTER_CLASS_BODY_PART(index, cond_class_array, cond_class_max,
+ name, name_length)
+
+ index= PFS_atomic::add_u32(&cond_class_dirty_count, 1);
+
+ if (index < cond_class_max)
+ {
+ entry= &cond_class_array[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);
+ }
+
+ cond_class_lost++;
+ return 0;
+}
+
+#define FIND_CLASS_BODY(KEY, COUNT, ARRAY) \
+ if ((KEY == 0) || (KEY > COUNT)) \
+ return NULL; \
+ return &ARRAY[KEY - 1]
+
+/**
+ Find a mutex instrumentation class by key.
+ @param key the instrument key
+ @return the instrument class, or NULL
+*/
+PFS_mutex_class *find_mutex_class(PFS_sync_key key)
+{
+ FIND_CLASS_BODY(key, mutex_class_allocated_count, mutex_class_array);
+}
+
+PFS_mutex_class *sanitize_mutex_class(PFS_mutex_class *unsafe)
+{
+ SANITIZE_ARRAY_BODY(PFS_mutex_class, mutex_class_array, mutex_class_max, unsafe);
+}
+
+/**
+ Find a rwlock instrumentation class by key.
+ @param key the instrument key
+ @return the instrument class, or NULL
+*/
+PFS_rwlock_class *find_rwlock_class(PFS_sync_key key)
+{
+ FIND_CLASS_BODY(key, rwlock_class_allocated_count, rwlock_class_array);
+}
+
+PFS_rwlock_class *sanitize_rwlock_class(PFS_rwlock_class *unsafe)
+{
+ SANITIZE_ARRAY_BODY(PFS_rwlock_class, rwlock_class_array, rwlock_class_max, unsafe);
+}
+
+/**
+ Find a condition instrumentation class by key.
+ @param key the instrument key
+ @return the instrument class, or NULL
+*/
+PFS_cond_class *find_cond_class(PFS_sync_key key)
+{
+ FIND_CLASS_BODY(key, cond_class_allocated_count, cond_class_array);
+}
+
+PFS_cond_class *sanitize_cond_class(PFS_cond_class *unsafe)
+{
+ SANITIZE_ARRAY_BODY(PFS_cond_class, cond_class_array, cond_class_max, unsafe);
+}
+
+/**
+ Register a thread instrumentation metadata.
+ @param name the instrumented name
+ @param name_length length in bytes of name
+ @param flags the instrumentation flags
+ @return a thread instrumentation key
+*/
+PFS_thread_key register_thread_class(const char *name, uint name_length,
+ int flags)
+{
+ /* See comments in register_mutex_class */
+ uint32 index;
+ PFS_thread_class *entry;
+
+ for (index= 0; index < thread_class_max; index++)
+ {
+ entry= &thread_class_array[index];
+
+ if ((entry->m_name_length == name_length) &&
+ (strncmp(entry->m_name, name, name_length) == 0))
+ return (index + 1);
+ }
+
+ index= PFS_atomic::add_u32(&thread_class_dirty_count, 1);
+
+ if (index < thread_class_max)
+ {
+ entry= &thread_class_array[index];
+ DBUG_ASSERT(name_length <= PFS_MAX_INFO_NAME_LENGTH);
+ strncpy(entry->m_name, name, name_length);
+ entry->m_name_length= name_length;
+ entry->m_enabled= true;
+ PFS_atomic::add_u32(&thread_class_allocated_count, 1);
+ return (index + 1);
+ }
+
+ thread_class_lost++;
+ return 0;
+}
+
+/**
+ Find a thread instrumentation class by key.
+ @param key the instrument key
+ @return the instrument class, or NULL
+*/
+PFS_thread_class *find_thread_class(PFS_sync_key key)
+{
+ FIND_CLASS_BODY(key, thread_class_allocated_count, thread_class_array);
+}
+
+PFS_thread_class *sanitize_thread_class(PFS_thread_class *unsafe)
+{
+ SANITIZE_ARRAY_BODY(PFS_thread_class, thread_class_array, thread_class_max, unsafe);
+}
+
+/**
+ Register a file instrumentation metadata.
+ @param name the instrumented name
+ @param name_length length in bytes of name
+ @param flags the instrumentation flags
+ @return a file instrumentation key
+*/
+PFS_file_key register_file_class(const char *name, uint name_length,
+ int flags)
+{
+ /* See comments in register_mutex_class */
+ uint32 index;
+ PFS_file_class *entry;
+
+ REGISTER_CLASS_BODY_PART(index, file_class_array, file_class_max,
+ name, name_length)
+
+ index= PFS_atomic::add_u32(&file_class_dirty_count, 1);
+
+ if (index < file_class_max)
+ {
+ entry= &file_class_array[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);
+ }
+
+ file_class_lost++;
+ return 0;
+}
+
+/**
+ 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
+*/
+PFS_file_class *find_file_class(PFS_file_key key)
+{
+ FIND_CLASS_BODY(key, file_class_allocated_count, file_class_array);
+}
+
+PFS_file_class *sanitize_file_class(PFS_file_class *unsafe)
+{
+ SANITIZE_ARRAY_BODY(PFS_file_class, file_class_array, file_class_max, unsafe);
+}
+
+/**
+ 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_INDEXES;
+ 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 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,
+ bool temporary,
+ const TABLE_SHARE *share)
+{
+ /* See comments in register_mutex_class */
+ PFS_table_share_key key;
+
+ LF_PINS *pins= get_table_share_hash_pins(thread);
+ if (unlikely(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;
+
+ 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 PFS_ALIGNED 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, pins,
+ key.m_hash_key, key.m_key_length));
+ if (entry && (entry != MY_ERRPTR))
+ {
+ pfs= *entry;
+ 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;
+ }
+
+ lf_hash_search_unpin(pins);
+
+ 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)
+ {
+ /* See create_mutex() */
+ index= PFS_atomic::add_u32(& table_share_monotonic_index, 1) % table_share_max;
+ pfs= table_share_array + index;
+
+ if (pfs->m_lock.is_free())
+ {
+ 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_lock.dirty_to_allocated();
+ return pfs;
+ }
+
+ pfs->m_lock.dirty_to_free();
+
+ if (res > 0)
+ {
+ /* Duplicate insert by another thread */
+ if (++retry_count > retry_max)
+ {
+ /* Avoid infinite loops */
+ table_share_lost++;
+ return NULL;
+ }
+ goto search;
+ }
+
+ /* OOM in lf_hash_insert */
+ table_share_lost++;
+ return NULL;
+ }
+ }
+ }
+
+ table_share_lost++;
+ return NULL;
+}
+
+void PFS_table_share::aggregate_io(void)
+{
+ uint safe_key_count= sanitize_index_count(m_key_count);
+ PFS_table_io_stat *from_stat;
+ PFS_table_io_stat *from_stat_last;
+ PFS_table_io_stat sum_io;
+
+ /* Aggregate stats for each index, if any */
+ from_stat= & m_table_stat.m_index_stat[0];
+ from_stat_last= from_stat + safe_key_count;
+ for ( ; from_stat < from_stat_last ; from_stat++)
+ sum_io.aggregate(from_stat);
+
+ /* Aggregate stats for the table */
+ sum_io.aggregate(& m_table_stat.m_index_stat[MAX_INDEXES]);
+
+ /* Add this table stats to the global sink. */
+ global_table_io_stat.aggregate(& sum_io);
+ m_table_stat.fast_reset_io();
+}
+
+void PFS_table_share::aggregate_lock(void)
+{
+ global_table_lock_stat.aggregate(& m_table_stat.m_lock_stat);
+ m_table_stat.fast_reset_lock();
+}
+
+void release_table_share(PFS_table_share *pfs)
+{
+ DBUG_ASSERT(pfs->get_refcount() > 0);
+ pfs->dec_refcount();
+}
+
+/**
+ 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_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();
+ }
+
+ lf_hash_search_unpin(pins);
+}
+
+/**
+ 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)
+{
+ SANITIZE_ARRAY_BODY(PFS_table_share, table_share_array, table_share_max, unsafe);
+}
+
+/** Reset the wait statistics per instrument class. */
+void reset_events_waits_by_class()
+{
+ reset_file_class_io();
+ reset_socket_class_io();
+ global_idle_stat.reset();
+ global_table_io_stat.reset();
+ global_table_lock_stat.reset();
+}
+
+/** 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++)
+ pfs->m_file_stat.m_io_stat.reset();
+}
+
+/** Reset the io statistics per socket class. */
+void reset_socket_class_io(void)
+{
+ 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();
+}
+
+void update_table_share_derived_flags(PFS_thread *thread)
+{
+ PFS_table_share *pfs= table_share_array;
+ PFS_table_share *pfs_last= table_share_array + table_share_max;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ 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
new file mode 100644
index 00000000000..246c6ee0b76
--- /dev/null
+++ b/storage/perfschema/pfs_instr_class.h
@@ -0,0 +1,504 @@
+/* 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 PFS_INSTR_CLASS_H
+#define PFS_INSTR_CLASS_H
+
+#include "my_global.h"
+#include "mysql_com.h" /* NAME_LEN */
+#include "lf.h"
+#include "pfs_global.h"
+
+/**
+ @file storage/perfschema/pfs_instr_class.h
+ Performance schema instruments meta data (declarations).
+*/
+
+/**
+ Maximum length of an instrument name.
+ For example, 'wait/sync/mutex/sql/LOCK_open' is an instrument name.
+*/
+#define PFS_MAX_INFO_NAME_LENGTH 128
+
+/**
+ Maximum length of the 'full' prefix of an instrument name.
+ For example, for the instrument name 'wait/sync/mutex/sql/LOCK_open',
+ the full prefix is 'wait/sync/mutex/sql/', which in turn derives from
+ a prefix 'wait/sync/mutex' for mutexes, and a category of 'sql' for mutexes
+ of the sql layer in the server.
+*/
+#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
+ @{
+*/
+
+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;
+/** Key, naming a thread instrument. */
+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 socket_class_start;
+extern uint wait_class_max;
+
+/** Information for all instrumentation. */
+struct PFS_instr_class
+{
+ /** 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;
+ /** 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_ALIGNED PFS_mutex_class : public PFS_instr_class
+{
+ /** Mutex usage statistics. */
+ PFS_mutex_stat m_mutex_stat;
+ /** Singleton instance. */
+ PFS_mutex *m_singleton;
+};
+
+struct PFS_rwlock;
+
+/** Instrumentation metadata for a RWLOCK. */
+struct PFS_ALIGNED PFS_rwlock_class : public PFS_instr_class
+{
+ /** Rwlock usage statistics. */
+ PFS_rwlock_stat m_rwlock_stat;
+ /** Singleton instance. */
+ PFS_rwlock *m_singleton;
+};
+
+struct PFS_cond;
+
+/** Instrumentation metadata for a COND. */
+struct PFS_ALIGNED PFS_cond_class : public PFS_instr_class
+{
+ /**
+ Condition usage statistics.
+ This statistic is not exposed in user visible tables yet.
+ */
+ PFS_cond_stat m_cond_stat;
+ /** Singleton instance. */
+ PFS_cond *m_singleton;
+};
+
+/** Instrumentation metadata of a thread. */
+struct PFS_ALIGNED 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;
+};
+
+/** Key identifying a table share. */
+struct PFS_table_share_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>"
+ @see create_table_def_key
+ */
+ char m_hash_key[1 + NAME_LEN + 1 + NAME_LEN + 1];
+ /** Length in bytes of @c m_hash_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_ALIGNED 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. */
+ const char *m_schema_name;
+ /** Length in bytes of @c m_schema_name. */
+ uint m_schema_name_length;
+ /** Table name. */
+ const char *m_table_name;
+ /** Length in bytes of @c m_table_name. */
+ uint m_table_name_length;
+ /** Number of indexes. */
+ uint m_key_count;
+ /** Table statistics. */
+ PFS_table_stat m_table_stat;
+ /** Index names. */
+ PFS_table_key m_keys[MAX_INDEXES];
+
+private:
+ /** Number of opened table handles. */
+ int m_refcount;
+};
+
+/** Statistics for the IDLE instrument. */
+extern PFS_single_stat global_idle_stat;
+/** Statistics for dropped table io. */
+extern PFS_table_io_stat global_table_io_stat;
+/** Statistics for dropped table lock. */
+extern PFS_table_lock_stat global_table_lock_stat;
+
+inline uint sanitize_index_count(uint count)
+{
+ if (likely(count <= MAX_INDEXES))
+ return count;
+ return 0;
+}
+
+#define GLOBAL_TABLE_IO_EVENT_INDEX 0
+#define GLOBAL_TABLE_LOCK_EVENT_INDEX 1
+#define GLOBAL_IDLE_EVENT_INDEX 2
+
+/**
+ Instrument controlling all table io.
+ This instrument is used with table SETUP_OBJECTS.
+*/
+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_ALIGNED PFS_file_class : public PFS_instr_class
+{
+ /** File usage statistics. */
+ PFS_file_stat m_file_stat;
+ /** Singleton instance. */
+ PFS_file *m_singleton;
+};
+
+/** Instrumentation metadata for a stage. */
+struct PFS_ALIGNED PFS_stage_class : public PFS_instr_class
+{
+ /** Stage usage statistics. */
+ PFS_stage_stat m_stage_stat;
+};
+
+/** Instrumentation metadata for a statement. */
+struct PFS_ALIGNED PFS_statement_class : public PFS_instr_class
+{
+};
+
+struct PFS_socket;
+
+/** Instrumentation metadata for a socket. */
+struct PFS_ALIGNED 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);
+
+void cleanup_sync_class();
+int init_thread_class(uint thread_class_sizing);
+void cleanup_thread_class();
+int init_table_share(uint table_share_sizing);
+void cleanup_table_share();
+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);
+
+PFS_sync_key register_rwlock_class(const char *name, uint name_length,
+ int flags);
+
+PFS_sync_key register_cond_class(const char *name, uint name_length,
+ int flags);
+
+PFS_thread_key register_thread_class(const char *name, uint name_length,
+ int flags);
+
+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);
+PFS_rwlock_class *sanitize_rwlock_class(PFS_rwlock_class *unsafe);
+PFS_cond_class *find_cond_class(PSI_cond_key key);
+PFS_cond_class *sanitize_cond_class(PFS_cond_class *unsafe);
+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);
+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,
+ 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);
+
+extern ulong mutex_class_max;
+extern ulong mutex_class_lost;
+extern ulong rwlock_class_max;
+extern ulong rwlock_class_lost;
+extern ulong cond_class_max;
+extern ulong cond_class_lost;
+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_events_waits_by_class();
+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);
+
+extern LF_HASH table_share_hash;
+
+/** @} */
+#endif
+
diff --git a/storage/perfschema/pfs_lock.h b/storage/perfschema/pfs_lock.h
new file mode 100644
index 00000000000..c429d934702
--- /dev/null
+++ b/storage/perfschema/pfs_lock.h
@@ -0,0 +1,240 @@
+/* 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
+ 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_LOCK_H
+#define PFS_LOCK_H
+
+/**
+ @file storage/perfschema/pfs_lock.h
+ Performance schema internal locks (declarations).
+*/
+
+#include "pfs_atomic.h"
+
+/**
+ @addtogroup Performance_schema_buffers
+ @{
+*/
+
+/**
+ State of a free record.
+ Values of a free record should not be read by a reader.
+ Writers can concurrently attempt to allocate a free record.
+*/
+#define PFS_LOCK_FREE 0x00
+/**
+ State of a dirty record.
+ Values of a dirty record should not be read by a reader,
+ as the record is currently being modified.
+ Only one writer, the writer which owns the record, should
+ modify the record content.
+*/
+#define PFS_LOCK_DIRTY 0x01
+/**
+ State of an allocated record.
+ Values of an allocated record are safe to read by a reader.
+ A writer may modify some but not all properties of the record:
+ only modifying values that can never cause the reader to crash is allowed.
+*/
+#define PFS_LOCK_ALLOCATED 0x02
+
+#define VERSION_MASK 0xFFFFFFFC
+#define STATE_MASK 0x00000003
+#define VERSION_INC 4
+
+/**
+ A 'lock' protecting performance schema internal buffers.
+ This lock is used to mark the state of a record.
+ Access to the record is not enforced here,
+ it's up to the readers and writers to look at the record state
+ before making an actual read or write operation.
+*/
+struct pfs_lock
+{
+ /**
+ The record internal version and state
+ @sa PFS_LOCK_FREE
+ @sa PFS_LOCK_DIRTY
+ @sa PFS_LOCK_ALLOCATED
+ The version number is to transform the 'ABA' problem
+ (see http://en.wikipedia.org/wiki/ABA_problem)
+ into an 'A(n)BA(n + 1)' problem, where 'n' is the m_version number.
+ When the performance schema instrumentation deletes a record,
+ then create a different record reusing the same memory allocation,
+ the version number is incremented, so that a reader can detect that
+ the record was changed. Note that the version number is never
+ reset to zero when a new record is created.
+ The version number is stored in the high 30 bits.
+ The state is stored in the low 2 bits.
+ */
+ volatile uint32 m_version_state;
+
+ /** Returns true if the record is free. */
+ bool is_free(void)
+ {
+ uint32 copy= m_version_state; /* non volatile copy, and dirty read */
+ return ((copy & STATE_MASK) == PFS_LOCK_FREE);
+ }
+
+ /** Returns true if the record contains values that can be read. */
+ bool is_populated(void)
+ {
+ uint32 copy= m_version_state; /* non volatile copy, and dirty read */
+ return ((copy & STATE_MASK) == PFS_LOCK_ALLOCATED);
+ }
+
+ /**
+ Execute a free to dirty transition.
+ This transition is safe to execute concurrently by multiple writers.
+ Only one writer will succeed to acquire the record.
+ @return true if the operation succeed
+ */
+ bool free_to_dirty(void)
+ {
+ uint32 copy= m_version_state; /* non volatile copy, and dirty read */
+ uint32 old_val= (copy & VERSION_MASK) + PFS_LOCK_FREE;
+ uint32 new_val= (copy & VERSION_MASK) + PFS_LOCK_DIRTY;
+
+ return (PFS_atomic::cas_u32(&m_version_state, &old_val, new_val));
+ }
+
+ /**
+ 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)
+ {
+ uint32 copy= PFS_atomic::load_u32(&m_version_state);
+ /* Make sure the record was ALLOCATED. */
+ DBUG_ASSERT((copy & STATE_MASK) == PFS_LOCK_ALLOCATED);
+ /* Keep the same version, set the DIRTY state */
+ uint32 new_val= (copy & VERSION_MASK) + PFS_LOCK_DIRTY;
+ /* We own the record, no need to use compare and swap. */
+ PFS_atomic::store_u32(&m_version_state, new_val);
+ }
+
+ /**
+ 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.
+ */
+ void dirty_to_allocated(void)
+ {
+ uint32 copy= PFS_atomic::load_u32(&m_version_state);
+ /* Make sure the record was DIRTY. */
+ DBUG_ASSERT((copy & STATE_MASK) == PFS_LOCK_DIRTY);
+ /* Increment the version, set the ALLOCATED state */
+ uint32 new_val= (copy & VERSION_MASK) + VERSION_INC + PFS_LOCK_ALLOCATED;
+ PFS_atomic::store_u32(&m_version_state, new_val);
+ }
+
+ /**
+ Initialize a lock to allocated.
+ This transition should be executed by the writer that owns the record and the lock,
+ after the record is in a state ready to be read.
+ */
+ void set_allocated(void)
+ {
+ /* Do not set the version to 0, read the previous value. */
+ uint32 copy= PFS_atomic::load_u32(&m_version_state);
+ /* Increment the version, set the ALLOCATED state */
+ uint32 new_val= (copy & VERSION_MASK) + VERSION_INC + PFS_LOCK_ALLOCATED;
+ PFS_atomic::store_u32(&m_version_state, new_val);
+ }
+
+ /**
+ Execute a dirty to free transition.
+ This transition should be executed by the writer that owns the record.
+ */
+ void dirty_to_free(void)
+ {
+ uint32 copy= PFS_atomic::load_u32(&m_version_state);
+ /* Make sure the record was DIRTY. */
+ DBUG_ASSERT((copy & STATE_MASK) == PFS_LOCK_DIRTY);
+ /* Keep the same version, set the FREE state */
+ uint32 new_val= (copy & VERSION_MASK) + PFS_LOCK_FREE;
+ PFS_atomic::store_u32(&m_version_state, new_val);
+ }
+
+ /**
+ Execute an allocated to free transition.
+ This transition should be executed by the writer that owns the record.
+ */
+ void allocated_to_free(void)
+ {
+#ifndef DBUG_OFF
+ extern volatile bool ready_to_exit;
+#endif
+
+ /*
+ If this record is not in the ALLOCATED state and the caller is trying
+ to free it, this is a bug: the caller is confused,
+ and potentially damaging data owned by another thread or object.
+ The correct assert to use here to guarantee data integrity is simply:
+ DBUG_ASSERT(m_state == PFS_LOCK_ALLOCATED);
+ Now, because of Bug#56666 (Race condition between the server main thread
+ and the kill server thread), this assert actually fails during shutdown,
+ and the failure is legitimate, on concurrent calls to mysql_*_destroy(),
+ when destroying the instrumentation of an object ... twice.
+ During shutdown this has no consequences for the performance schema,
+ so the assert is relaxed with the "|| ready_to_exit" condition as a work
+ around until Bug#56666 is fixed.
+ */
+ uint32 copy= PFS_atomic::load_u32(&m_version_state);
+ /* Make sure the record was ALLOCATED. */
+ DBUG_ASSERT(((copy & STATE_MASK) == PFS_LOCK_ALLOCATED) || ready_to_exit);
+ /* Keep the same version, set the FREE state */
+ uint32 new_val= (copy & VERSION_MASK) + PFS_LOCK_FREE;
+ PFS_atomic::store_u32(&m_version_state, new_val);
+ }
+
+ /**
+ Start an optimistic read operation.
+ @sa end_optimist_lock.
+ */
+ void begin_optimistic_lock(struct pfs_lock *copy)
+ {
+ copy->m_version_state= PFS_atomic::load_u32(&m_version_state);
+ }
+
+ /**
+ End an optimistic read operation.
+ @sa begin_optimist_lock.
+ @return true if the data read is safe to use.
+ */
+ bool end_optimistic_lock(struct pfs_lock *copy)
+ {
+ /* Check there was valid data to look at. */
+ if ((copy->m_version_state & STATE_MASK) != PFS_LOCK_ALLOCATED)
+ return false;
+
+ /* Check the version + state has not changed. */
+ if (copy->m_version_state != PFS_atomic::load_u32(&m_version_state))
+ return false;
+
+ return true;
+ }
+
+ uint32 get_version()
+ {
+ return (PFS_atomic::load_u32(&m_version_state) & VERSION_MASK);
+ }
+};
+
+
+/** @} */
+#endif
+
diff --git a/storage/perfschema/pfs_server.cc b/storage/perfschema/pfs_server.cc
new file mode 100644
index 00000000000..093f772915a
--- /dev/null
+++ b/storage/perfschema/pfs_server.cc
@@ -0,0 +1,299 @@
+/* Copyright (c) 2008, 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 */
+
+/**
+ @file storage/perfschema/pfs_server.cc
+ Private interface for the server (implementation).
+*/
+
+#include "my_global.h"
+#include "my_sys.h"
+#include "mysys_err.h"
+#include "pfs_server.h"
+#include "pfs.h"
+#include "pfs_global.h"
+#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(PFS_global_param *param)
+{
+ pfs_initialized= false;
+
+ PFS_table_stat::g_reset_template.reset();
+ global_idle_stat.reset();
+ global_table_io_stat.reset();
+ global_table_lock_stat.reset();
+
+ pfs_automated_sizing(param);
+
+ if (! param->m_enabled)
+ {
+ /*
+ The performance schema is disabled in the startup command line.
+ All the instrumentation is turned off.
+ */
+ return NULL;
+ }
+
+ init_timers();
+ PFS_atomic::init();
+
+ init_event_name_sizing(param);
+ register_global_classes();
+
+ if (pthread_key_create(&THR_PFS, destroy_pfs_thread))
+ return NULL;
+
+ THR_PFS_initialized= true;
+
+ if (init_sync_class(param->m_mutex_class_sizing,
+ param->m_rwlock_class_sizing,
+ param->m_cond_class_sizing) ||
+ 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_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.
+ Free the memory used, and disable the instrumentation.
+ */
+ cleanup_performance_schema();
+ return NULL;
+ }
+
+ 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;
+}
+
+static void destroy_pfs_thread(void *key)
+{
+ PFS_thread* pfs= reinterpret_cast<PFS_thread*> (key);
+ DBUG_ASSERT(pfs);
+ /*
+ This automatic cleanup is a last resort and best effort to avoid leaks,
+ and may not work on windows due to the implementation of pthread_key_create().
+ Please either use:
+ - my_thread_end()
+ - or PSI_server->delete_current_thread()
+ in the instrumented code, to explicitly cleanup the instrumentation.
+
+ Avoid invalid writes when the main() thread completes after shutdown:
+ the memory pointed by pfs is already released.
+ */
+ if (pfs_initialized)
+ destroy_thread(pfs);
+}
+
+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,
+ */
+ if (THR_PFS_initialized)
+ {
+ my_pthread_setspecific_ptr(THR_PFS, NULL);
+ 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
new file mode 100644
index 00000000000..e0c782fde58
--- /dev/null
+++ b/storage/perfschema/pfs_server.h
@@ -0,0 +1,249 @@
+/* Copyright (c) 2008, 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_SERVER_H
+#define PFS_SERVER_H
+
+/**
+ @file storage/perfschema/pfs_server.h
+ Private interface for the server (declarations).
+*/
+
+#ifndef PFS_MAX_MUTEX_CLASS
+ #define PFS_MAX_MUTEX_CLASS 200
+#endif
+#ifndef PFS_MAX_RWLOCK_CLASS
+ #define PFS_MAX_RWLOCK_CLASS 30
+#endif
+#ifndef PFS_MAX_COND_CLASS
+ #define PFS_MAX_COND_CLASS 80
+#endif
+#ifndef PFS_MAX_THREAD_CLASS
+ #define PFS_MAX_THREAD_CLASS 50
+#endif
+#ifndef PFS_MAX_FILE_CLASS
+ #define PFS_MAX_FILE_CLASS 50
+#endif
+#ifndef PFS_MAX_FILE_HANDLE
+ #define PFS_MAX_FILE_HANDLE 32768
+#endif
+#ifndef PFS_MAX_SOCKET_CLASS
+ #define PFS_MAX_SOCKET_CLASS 10
+#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_STAGE_CLASS
+ #define PFS_MAX_STAGE_CLASS 150
+#endif
+#ifndef PFS_STATEMENTS_STACK_SIZE
+ #define PFS_STATEMENTS_STACK_SIZE 10
+#endif
+
+struct PFS_sizing_hints
+{
+ long m_table_definition_cache;
+ long m_table_open_cache;
+ long m_max_connections;
+ long m_open_files_limit;
+};
+
+/** Performance schema global sizing parameters. */
+struct PFS_global_param
+{
+ /** 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.
+ */
+ long 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.
+ */
+ long m_mutex_sizing;
+ /**
+ Maximum number of instrumented rwlock instances.
+ @sa rwlock_lost.
+ */
+ long m_rwlock_sizing;
+ /**
+ Maximum number of instrumented cond instances.
+ @sa cond_lost.
+ */
+ long m_cond_sizing;
+ /**
+ Maximum number of instrumented thread instances.
+ @sa thread_lost.
+ */
+ long m_thread_sizing;
+ /**
+ Maximum number of instrumented table handles.
+ @sa table_lost.
+ */
+ long m_table_sizing;
+ /**
+ Maximum number of instrumented file instances.
+ @sa file_lost.
+ */
+ long m_file_sizing;
+ /**
+ Maximum number of instrumented file handles.
+ @sa file_handle_lost.
+ */
+ long m_file_handle_sizing;
+ /**
+ Maxium number of instrumented socket instances
+ @sa socket_lost
+ */
+ long 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. */
+ long m_events_waits_history_sizing;
+ /** Maximum number of rows in table EVENTS_WAITS_HISTORY_LONG. */
+ long 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. */
+ long m_host_sizing;
+ /** Maximum number of rows in table USERS. */
+ long m_user_sizing;
+ /** Maximum number of rows in table ACCOUNTS. */
+ long 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. */
+ long m_events_stages_history_sizing;
+ /** Maximum number of rows in table EVENTS_STAGES_HISTORY_LONG. */
+ long 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. */
+ long m_events_statements_history_sizing;
+ /** Maximum number of rows in table EVENTS_STATEMENTS_HISTORY_LONG. */
+ long m_events_statements_history_long_sizing;
+ /** Maximum number of digests to be captured */
+ long m_digest_sizing;
+ /** Maximum number of session attribute strings per thread */
+ long m_session_connect_attrs_sizing;
+
+ /** Sizing hints, for auto tuning. */
+ PFS_sizing_hints m_hints;
+};
+
+/**
+ 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(PFS_global_param *param);
+
+void pfs_automated_sizing(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..943654ce1c9
--- /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. */
+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) && (setup_actor_max > 0))
+ {
+ 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.size= setup_actor_max;
+ 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 PFS_ALIGNED setup_actor_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_setup_actor *pfs;
+
+ while (++attempts <= setup_actor_max)
+ {
+ /* See create_mutex() */
+ index= PFS_atomic::add_u32(& setup_actor_monotonic_index, 1) % 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..baebd27f0ad
--- /dev/null
+++ b/storage/perfschema/pfs_setup_actor.h
@@ -0,0 +1,99 @@
+/* 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_ALIGNED 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;
+
+extern LF_HASH setup_actor_hash;
+
+/** @} */
+#endif
+
diff --git a/storage/perfschema/pfs_setup_object.cc b/storage/perfschema/pfs_setup_object.cc
new file mode 100644
index 00000000000..0ca7986e818
--- /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;
+
+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) && (setup_object_max > 0))
+ {
+ 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.size= setup_object_max;
+ 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 PFS_ALIGNED setup_object_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_setup_object *pfs;
+
+ while (++attempts <= setup_object_max)
+ {
+ /* See create_mutex() */
+ index= PFS_atomic::add_u32(& setup_object_monotonic_index, 1) % 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..2615802fe01
--- /dev/null
+++ b/storage/perfschema/pfs_setup_object.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_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_ALIGNED 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;
+
+extern LF_HASH setup_object_hash;
+
+/** @} */
+#endif
+
diff --git a/storage/perfschema/pfs_stat.h b/storage/perfschema/pfs_stat.h
new file mode 100644
index 00000000000..2a255a9e5b2
--- /dev/null
+++ b/storage/perfschema/pfs_stat.h
@@ -0,0 +1,706 @@
+/* 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 PFS_STAT_H
+#define PFS_STAT_H
+
+#include "sql_const.h"
+/* memcpy */
+#include "string.h"
+
+/**
+ @file storage/perfschema/pfs_stat.h
+ Statistics (declarations).
+*/
+
+/**
+ @addtogroup Performance_schema_buffers
+ @{
+*/
+
+/** Single statistic. */
+struct PFS_single_stat
+{
+ /** Count of values. */
+ ulonglong m_count;
+ /** Sum of values. */
+ ulonglong m_sum;
+ /** Minimum value. */
+ 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;
+ }
+};
+
+/** Combined statistic. */
+struct PFS_byte_stat : public PFS_single_stat
+{
+ /** Byte count statistics */
+ ulonglong m_bytes;
+
+ /* 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;
+ }
+
+ /* 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()
+ {
+ reset();
+ }
+
+ inline void reset(void)
+ {
+ PFS_single_stat::reset();
+ m_bytes= 0;
+ }
+};
+
+/** Statistics for mutex usage. */
+struct PFS_mutex_stat
+{
+ /** Wait statistics. */
+ PFS_single_stat m_wait_stat;
+ /**
+ Lock statistics.
+ This statistic is not exposed in user visible tables yet.
+ */
+ PFS_single_stat m_lock_stat;
+
+ inline void aggregate(const PFS_mutex_stat *stat)
+ {
+ m_wait_stat.aggregate(&stat->m_wait_stat);
+ m_lock_stat.aggregate(&stat->m_lock_stat);
+ }
+
+ inline void reset(void)
+ {
+ m_wait_stat.reset();
+ m_lock_stat.reset();
+ }
+};
+
+/** Statistics for rwlock usage. */
+struct PFS_rwlock_stat
+{
+ /** Wait statistics. */
+ PFS_single_stat m_wait_stat;
+ /**
+ RWLock read lock usage statistics.
+ This statistic is not exposed in user visible tables yet.
+ */
+ PFS_single_stat m_read_lock_stat;
+ /**
+ RWLock write lock usage statistics.
+ This statistic is not exposed in user visible tables yet.
+ */
+ PFS_single_stat m_write_lock_stat;
+
+ inline void aggregate(const PFS_rwlock_stat *stat)
+ {
+ m_wait_stat.aggregate(&stat->m_wait_stat);
+ m_read_lock_stat.aggregate(&stat->m_read_lock_stat);
+ m_write_lock_stat.aggregate(&stat->m_write_lock_stat);
+ }
+
+ inline void reset(void)
+ {
+ m_wait_stat.reset();
+ m_read_lock_stat.reset();
+ m_write_lock_stat.reset();
+ }
+};
+
+/** Statistics for COND usage. */
+struct PFS_cond_stat
+{
+ /** Wait statistics. */
+ PFS_single_stat m_wait_stat;
+ /**
+ Number of times a condition was signalled.
+ This statistic is not exposed in user visible tables yet.
+ */
+ ulonglong m_signal_count;
+ /**
+ Number of times a condition was broadcast.
+ This statistic is not exposed in user visible tables yet.
+ */
+ ulonglong m_broadcast_count;
+
+ inline void aggregate(const PFS_cond_stat *stat)
+ {
+ m_wait_stat.aggregate(&stat->m_wait_stat);
+ m_signal_count+= stat->m_signal_count;
+ m_broadcast_count+= stat->m_broadcast_count;
+ }
+
+ inline void reset(void)
+ {
+ m_wait_stat.reset();
+ m_signal_count= 0;
+ m_broadcast_count= 0;
+ }
+};
+
+/** 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;
+ /** File IO statistics. */
+ PFS_file_io_stat m_io_stat;
+
+ inline void aggregate(const PFS_file_stat *stat)
+ {
+ m_io_stat.aggregate(&stat->m_io_stat);
+ }
+
+ /** Reset file statistics. */
+ inline void reset(void)
+ {
+ m_io_stat.reset();
+ }
+};
+
+/** 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
+{
+ bool m_has_data;
+ /** 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;
+
+ PFS_table_io_stat()
+ {
+ m_has_data= false;
+ }
+
+ inline void reset(void)
+ {
+ m_has_data= false;
+ m_fetch.reset();
+ m_insert.reset();
+ m_update.reset();
+ m_delete.reset();
+ }
+
+ inline void aggregate(const PFS_table_io_stat *stat)
+ {
+ if (stat->m_has_data)
+ {
+ m_has_data= true;
+ 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)
+ {
+ if (m_has_data)
+ {
+ 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_INDEXES-1],
+ stats when using no index are in [MAX_INDEXES].
+ */
+ PFS_table_io_stat m_index_stat[MAX_INDEXES + 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_INDEXES + 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, uint key_count)
+ {
+ PFS_table_io_stat *to_stat;
+ PFS_table_io_stat *to_stat_last;
+ const PFS_table_io_stat *from_stat;
+
+ DBUG_ASSERT(key_count <= MAX_INDEXES);
+
+ /* Aggregate stats for each index, if any */
+ to_stat= & m_index_stat[0];
+ to_stat_last= to_stat + key_count;
+ from_stat= & stat->m_index_stat[0];
+ for ( ; to_stat < to_stat_last ; from_stat++, to_stat++)
+ to_stat->aggregate(from_stat);
+
+ /* Aggregate stats for the table */
+ to_stat= & m_index_stat[MAX_INDEXES];
+ from_stat= & stat->m_index_stat[MAX_INDEXES];
+ 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, uint key_count)
+ {
+ aggregate_io(stat, key_count);
+ aggregate_lock(stat);
+ }
+
+ inline void sum_io(PFS_single_stat *result, uint key_count)
+ {
+ PFS_table_io_stat *stat;
+ PFS_table_io_stat *stat_last;
+
+ DBUG_ASSERT(key_count <= MAX_INDEXES);
+
+ /* Sum stats for each index, if any */
+ stat= & m_index_stat[0];
+ stat_last= stat + key_count;
+ for ( ; stat < stat_last ; stat++)
+ stat->sum(result);
+
+ /* Sum stats for the table */
+ m_index_stat[MAX_INDEXES].sum(result);
+ }
+
+ inline void sum_lock(PFS_single_stat *result)
+ {
+ m_lock_stat.sum(result);
+ }
+
+ inline void sum(PFS_single_stat *result, uint key_count)
+ {
+ sum_io(result, key_count);
+ 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
new file mode 100644
index 00000000000..8c3553db2b2
--- /dev/null
+++ b/storage/perfschema/pfs_timer.cc
@@ -0,0 +1,299 @@
+/* Copyright (c) 2008, 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 */
+
+/**
+ @file storage/perfschema/pfs_timer.cc
+ Performance schema timers (implementation).
+*/
+
+#include "my_global.h"
+#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;
+static ulonglong nanosec_v0;
+static ulonglong microsec_v0;
+static ulonglong millisec_v0;
+static ulonglong tick_v0;
+
+static ulong cycle_to_pico; /* 1000 at 1 GHz, 333 at 3GHz, 250 at 4GHz */
+static ulong nanosec_to_pico; /* In theory, 1 000 */
+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);
+}
+
+static inline ulonglong round_to_ulonglong(double value)
+{
+ return (ulonglong) (value + 0.5);
+}
+
+void init_timers(void)
+{
+ double pico_frequency= 1.0e12;
+
+ my_timer_init(&pfs_timer_info);
+
+ cycle_v0= my_timer_cycles();
+ nanosec_v0= my_timer_nanoseconds();
+ microsec_v0= my_timer_microseconds();
+ millisec_v0= my_timer_milliseconds();
+ tick_v0= my_timer_ticks();
+
+ if (pfs_timer_info.cycles.frequency > 0)
+ cycle_to_pico= round_to_ulong(pico_frequency/
+ (double)pfs_timer_info.cycles.frequency);
+ else
+ cycle_to_pico= 0;
+
+ if (pfs_timer_info.nanoseconds.frequency > 0)
+ nanosec_to_pico= round_to_ulong(pico_frequency/
+ (double)pfs_timer_info.nanoseconds.frequency);
+ else
+ nanosec_to_pico= 0;
+
+ if (pfs_timer_info.microseconds.frequency > 0)
+ microsec_to_pico= round_to_ulong(pico_frequency/
+ (double)pfs_timer_info.microseconds.frequency);
+ else
+ microsec_to_pico= 0;
+
+ if (pfs_timer_info.milliseconds.frequency > 0)
+ millisec_to_pico= round_to_ulong(pico_frequency/
+ (double)pfs_timer_info.milliseconds.frequency);
+ else
+ millisec_to_pico= 0;
+
+ if (pfs_timer_info.ticks.frequency > 0)
+ tick_to_pico= round_to_ulonglong(pico_frequency/
+ (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;
+
+ /*
+ Depending on the platform and build options,
+ some timers may not be available.
+ Pick best replacements.
+ */
+
+ /*
+ For STAGE and STATEMENT, a timer with a fixed frequency is better.
+ The prefered timer is nanosecond, or lower resolutions.
+ */
+
+ if (nanosec_to_pico != 0)
+ {
+ /* Normal case. */
+ stage_timer= TIMER_NAME_NANOSEC;
+ statement_timer= TIMER_NAME_NANOSEC;
+ }
+ else if (microsec_to_pico != 0)
+ {
+ /* Windows. */
+ stage_timer= TIMER_NAME_MICROSEC;
+ statement_timer= TIMER_NAME_MICROSEC;
+ }
+ else if (millisec_to_pico != 0)
+ {
+ /* Robustness, no known cases. */
+ stage_timer= TIMER_NAME_MILLISEC;
+ statement_timer= TIMER_NAME_MILLISEC;
+ }
+ else if (tick_to_pico != 0)
+ {
+ /* Robustness, no known cases. */
+ stage_timer= TIMER_NAME_TICK;
+ statement_timer= TIMER_NAME_TICK;
+ }
+ else
+ {
+ /* Robustness, no known cases. */
+ stage_timer= TIMER_NAME_CYCLE;
+ statement_timer= TIMER_NAME_CYCLE;
+ }
+
+ /*
+ For IDLE, a timer with a fixed frequency is critical,
+ as the CPU clock may slow down a lot if the server is completely idle.
+ The prefered timer is microsecond, or lower resolutions.
+ */
+
+ if (microsec_to_pico != 0)
+ {
+ /* Normal case. */
+ idle_timer= TIMER_NAME_MICROSEC;
+ }
+ else if (millisec_to_pico != 0)
+ {
+ /* Robustness, no known cases. */
+ idle_timer= TIMER_NAME_MILLISEC;
+ }
+ else if (tick_to_pico != 0)
+ {
+ /* Robustness, no known cases. */
+ idle_timer= TIMER_NAME_TICK;
+ }
+ else
+ {
+ /* Robustness, no known cases. */
+ idle_timer= TIMER_NAME_CYCLE;
+ }
+}
+
+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_pico_value(enum_timer_name timer_name)
+{
+ ulonglong result;
+
+ switch (timer_name)
+ {
+ case TIMER_NAME_CYCLE:
+ result= (my_timer_cycles() - cycle_v0) * cycle_to_pico;
+ break;
+ case TIMER_NAME_NANOSEC:
+ result= (my_timer_nanoseconds() - nanosec_v0) * nanosec_to_pico;
+ break;
+ case TIMER_NAME_MICROSEC:
+ result= (my_timer_microseconds() - microsec_v0) * microsec_to_pico;
+ break;
+ case TIMER_NAME_MILLISEC:
+ result= (my_timer_milliseconds() - millisec_v0) * millisec_to_pico;
+ break;
+ case TIMER_NAME_TICK:
+ result= (my_timer_ticks() - tick_v0) * tick_to_pico;
+ break;
+ default:
+ result= 0;
+ DBUG_ASSERT(false);
+ }
+ 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
new file mode 100644
index 00000000000..1cae20e89dd
--- /dev/null
+++ b/storage/perfschema/pfs_timer.h
@@ -0,0 +1,140 @@
+/* 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 PFS_TIMER_H
+#define PFS_TIMER_H
+
+/**
+ @file storage/perfschema/pfs_timer.h
+ Performance schema timers (declarations).
+*/
+#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();
+
+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..6ae734c7d72
--- /dev/null
+++ b/storage/perfschema/pfs_user.cc
@@ -0,0 +1,384 @@
+/* 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;
+
+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) && (user_max > 0))
+ {
+ lf_hash_init(&user_hash, sizeof(PFS_user*), LF_HASH_UNIQUE,
+ 0, 0, user_hash_get_key, &my_charset_bin);
+ user_hash.size= user_max;
+ 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))
+ {
+ PFS_user *pfs;
+ pfs= *entry;
+ DBUG_ASSERT(pfs == 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..dda7e221ca8
--- /dev/null
+++ b/storage/perfschema/pfs_user.h
@@ -0,0 +1,115 @@
+/* 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_ALIGNED 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;
+
+extern LF_HASH user_hash;
+
+/** @} */
+#endif
+
diff --git a/storage/perfschema/pfs_visitor.cc b/storage/perfschema/pfs_visitor.cc
new file mode 100644
index 00000000000..616bc27900a
--- /dev/null
+++ b/storage/perfschema/pfs_visitor.cc
@@ -0,0 +1,1154 @@
+/* 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_idle_stat);
+}
+
+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)
+{
+ m_stat.aggregate(&pfs->m_mutex_stat.m_wait_stat);
+}
+
+void PFS_instance_wait_visitor::visit_rwlock_class(PFS_rwlock_class *pfs)
+{
+ m_stat.aggregate(&pfs->m_rwlock_stat.m_wait_stat);
+}
+
+void PFS_instance_wait_visitor::visit_cond_class(PFS_cond_class *pfs)
+{
+ m_stat.aggregate(&pfs->m_cond_stat.m_wait_stat);
+}
+
+void PFS_instance_wait_visitor::visit_file_class(PFS_file_class *pfs)
+{
+ pfs->m_file_stat.m_io_stat.sum_waits(&m_stat);
+}
+
+void PFS_instance_wait_visitor::visit_socket_class(PFS_socket_class *pfs)
+{
+ 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_mutex_stat.m_wait_stat);
+}
+
+void PFS_instance_wait_visitor::visit_rwlock(PFS_rwlock *pfs)
+{
+ m_stat.aggregate(& pfs->m_rwlock_stat.m_wait_stat);
+}
+
+void PFS_instance_wait_visitor::visit_cond(PFS_cond *pfs)
+{
+ m_stat.aggregate(& pfs->m_cond_stat.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()
+{
+ global_table_io_stat.sum(& m_stat);
+ global_table_lock_stat.sum(& m_stat);
+}
+
+void PFS_object_wait_visitor::visit_table_share(PFS_table_share *pfs)
+{
+ uint safe_key_count= sanitize_index_count(pfs->m_key_count);
+ pfs->m_table_stat.sum(& m_stat, safe_key_count);
+}
+
+void PFS_object_wait_visitor::visit_table(PFS_table *pfs)
+{
+ PFS_table_share *table_share= sanitize_table_share(pfs->m_share);
+ if (table_share != NULL)
+ {
+ uint safe_key_count= sanitize_index_count(table_share->m_key_count);
+ pfs->m_table_stat.sum(& m_stat, safe_key_count);
+ }
+}
+
+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()
+{
+ global_table_io_stat.sum(& m_stat);
+}
+
+void PFS_table_io_wait_visitor::visit_table_share(PFS_table_share *pfs)
+{
+ PFS_table_io_stat io_stat;
+ uint safe_key_count= sanitize_index_count(pfs->m_key_count);
+ uint index;
+
+ /* Aggregate index stats */
+ for (index= 0; index < safe_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_INDEXES]);
+
+ 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 safe_key_count= sanitize_index_count(safe_share->m_key_count);
+ uint index;
+
+ /* Aggregate index stats */
+ for (index= 0; index < safe_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_INDEXES]);
+
+ 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 safe_key_count= sanitize_index_count(pfs->m_key_count);
+ uint index;
+
+ /* Aggregate index stats */
+ for (index= 0; index < safe_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_INDEXES]);
+}
+
+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 safe_key_count= sanitize_index_count(safe_share->m_key_count);
+ uint index;
+
+ /* Aggregate index stats */
+ for (index= 0; index < safe_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_INDEXES]);
+ }
+}
+
+/** 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()
+{
+ global_table_lock_stat.sum(& m_stat);
+}
+
+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
new file mode 100644
index 00000000000..ae8988d3a93
--- /dev/null
+++ b/storage/perfschema/table_all_instr.cc
@@ -0,0 +1,175 @@
+/* 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_all_instr.cc
+ Abstract tables for all instruments (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "table_all_instr.h"
+#include "pfs_global.h"
+
+table_all_instr::table_all_instr(const PFS_engine_table_share *share)
+ : PFS_engine_table(share, &m_pos),
+ m_pos(), m_next_pos()
+{}
+
+void table_all_instr::reset_position(void)
+{
+ m_pos.reset();
+ m_next_pos.reset();
+}
+
+int table_all_instr::rnd_next(void)
+{
+ PFS_mutex *mutex;
+ 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();
+ m_pos.next_view())
+ {
+ switch (m_pos.m_index_1) {
+ case pos_all_instr::VIEW_MUTEX:
+ for ( ; m_pos.m_index_2 < mutex_max; m_pos.m_index_2++)
+ {
+ mutex= &mutex_array[m_pos.m_index_2];
+ if (mutex->m_lock.is_populated())
+ {
+ make_mutex_row(mutex);
+ m_next_pos.set_after(&m_pos);
+ return 0;
+ }
+ }
+ break;
+ case pos_all_instr::VIEW_RWLOCK:
+ for ( ; m_pos.m_index_2 < rwlock_max; m_pos.m_index_2++)
+ {
+ rwlock= &rwlock_array[m_pos.m_index_2];
+ if (rwlock->m_lock.is_populated())
+ {
+ make_rwlock_row(rwlock);
+ m_next_pos.set_after(&m_pos);
+ return 0;
+ }
+ }
+ break;
+ case pos_all_instr::VIEW_COND:
+ for ( ; m_pos.m_index_2 < cond_max; m_pos.m_index_2++)
+ {
+ cond= &cond_array[m_pos.m_index_2];
+ if (cond->m_lock.is_populated())
+ {
+ make_cond_row(cond);
+ m_next_pos.set_after(&m_pos);
+ return 0;
+ }
+ }
+ break;
+ case pos_all_instr::VIEW_FILE:
+ for ( ; m_pos.m_index_2 < file_max; m_pos.m_index_2++)
+ {
+ file= &file_array[m_pos.m_index_2];
+ if (file->m_lock.is_populated())
+ {
+ make_file_row(file);
+ m_next_pos.set_after(&m_pos);
+ return 0;
+ }
+ }
+ 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;
+ }
+ }
+
+ return HA_ERR_END_OF_FILE;
+}
+
+int table_all_instr::rnd_pos(const void *pos)
+{
+ PFS_mutex *mutex;
+ PFS_rwlock *rwlock;
+ PFS_cond *cond;
+ PFS_file *file;
+ PFS_socket *socket;
+
+ set_position(pos);
+
+ switch (m_pos.m_index_1) {
+ case pos_all_instr::VIEW_MUTEX:
+ DBUG_ASSERT(m_pos.m_index_2 < mutex_max);
+ mutex= &mutex_array[m_pos.m_index_2];
+ if (mutex->m_lock.is_populated())
+ {
+ make_mutex_row(mutex);
+ return 0;
+ }
+ break;
+ case pos_all_instr::VIEW_RWLOCK:
+ DBUG_ASSERT(m_pos.m_index_2 < rwlock_max);
+ rwlock= &rwlock_array[m_pos.m_index_2];
+ if (rwlock->m_lock.is_populated())
+ {
+ make_rwlock_row(rwlock);
+ return 0;
+ }
+ break;
+ case pos_all_instr::VIEW_COND:
+ DBUG_ASSERT(m_pos.m_index_2 < cond_max);
+ cond= &cond_array[m_pos.m_index_2];
+ if (cond->m_lock.is_populated())
+ {
+ make_cond_row(cond);
+ return 0;
+ }
+ break;
+ case pos_all_instr::VIEW_FILE:
+ DBUG_ASSERT(m_pos.m_index_2 < file_max);
+ file= &file_array[m_pos.m_index_2];
+ if (file->m_lock.is_populated())
+ {
+ make_file_row(file);
+ return 0;
+ }
+ break;
+ 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_socket_row(socket);
+ return 0;
+ }
+ break;
+ }
+
+ return HA_ERR_RECORD_DELETED;
+}
diff --git a/storage/perfschema/table_all_instr.h b/storage/perfschema/table_all_instr.h
new file mode 100644
index 00000000000..f78f8cee3ba
--- /dev/null
+++ b/storage/perfschema/table_all_instr.h
@@ -0,0 +1,115 @@
+/* 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_ALL_INSTR_H
+#define TABLE_ALL_INSTR_H
+
+/**
+ @file storage/perfschema/table_all_instr.h
+ Abstract tables for all instruments (declarations).
+*/
+
+#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. */
+struct pos_all_instr : public PFS_double_index,
+ public PFS_instrument_view_constants
+{
+ pos_all_instr()
+ : 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;
+ }
+};
+
+/**
+ Abstract table, a union of all instrumentations instances.
+ This table is a union of:
+ - 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 socket instances
+*/
+class table_all_instr : 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(const PFS_engine_table_share *share);
+
+public:
+ ~table_all_instr()
+ {}
+
+protected:
+ /**
+ Build a row in the mutex instance view.
+ @param pfs the mutex instance
+ */
+ virtual void make_mutex_row(PFS_mutex *pfs)= 0;
+ /**
+ Build a row in the rwlock instance view.
+ @param pfs the rwlock instance
+ */
+ virtual void make_rwlock_row(PFS_rwlock *pfs)= 0;
+ /**
+ Build a row in the condition instance view.
+ @param pfs the condition instance
+ */
+ virtual void make_cond_row(PFS_cond *pfs)= 0;
+ /**
+ Build a row in the file instance view.
+ @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;
+ /** Next position. */
+ pos_all_instr m_next_pos;
+};
+
+/** @} */
+#endif
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..eeef6c3fbb2
--- /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("bigint(20)") },
+ { 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_ulonglong(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..5295a9eacdf
--- /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. */
+ ulonglong 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..276ac8d7704
--- /dev/null
+++ b/storage/perfschema/table_esgs_global_by_event_name.cc
@@ -0,0 +1,207 @@
+/* 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_by_account();
+ reset_events_stages_by_user();
+ reset_events_stages_by_host();
+ 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..d0250c14e5d
--- /dev/null
+++ b/storage/perfschema/table_esms_by_digest.cc
@@ -0,0 +1,331 @@
+/* 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("SCHEMA_NAME") },
+ { C_STRING_WITH_LEN("varchar(64)") },
+ { 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("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=
+{ 29, 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: /* SCHEMA_NAME */
+ case 1: /* DIGEST */
+ case 2: /* DIGEST_TEXT */
+ m_row.m_digest.set_field(f->field_index, f);
+ break;
+ case 27: /* FIRST_SEEN */
+ set_field_timestamp(f, m_row.m_first_seen);
+ break;
+ case 28: /* LAST_SEEN */
+ set_field_timestamp(f, m_row.m_last_seen);
+ 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_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..fccdf5dea60
--- /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("bigint(20)") },
+ { 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_ulonglong(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..9fb9f7c58dc
--- /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. */
+ ulonglong 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..efcb5b6fa7c
--- /dev/null
+++ b/storage/perfschema/table_esms_global_by_event_name.cc
@@ -0,0 +1,302 @@
+/* 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_by_account();
+ reset_events_statements_by_user();
+ reset_events_statements_by_host();
+ 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..854e1be15cd
--- /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("bigint(20)") },
+ { 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_ulonglong(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..09c555c80fd
--- /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. */
+ ulonglong 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..fb2b4b242d4
--- /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("bigint(20)") },
+ { 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_key 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_ulonglong(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..dcc6611f555
--- /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. */
+ ulonglong 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
new file mode 100644
index 00000000000..82d8ba2a0cc
--- /dev/null
+++ b/storage/perfschema/table_events_waits.cc
@@ -0,0 +1,1035 @@
+/* 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_events_waits.cc
+ Table EVENTS_WAITS_xxx (implementation).
+*/
+
+#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;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+ {
+ { C_STRING_WITH_LEN("THREAD_ID") },
+ { C_STRING_WITH_LEN("bigint(20)") },
+ { 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("SPINS") },
+ { C_STRING_WITH_LEN("int(10)") },
+ { 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(512)") },
+ { 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}
+ },
+ {
+ { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") },
+ { 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}
+ },
+ {
+ { C_STRING_WITH_LEN("OPERATION") },
+ { C_STRING_WITH_LEN("varchar(32)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("NUMBER_OF_BYTES") },
+ { C_STRING_WITH_LEN("bigint(20)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("FLAGS") },
+ { C_STRING_WITH_LEN("int(10)") },
+ { NULL, 0}
+ }
+};
+
+TABLE_FIELD_DEF
+table_events_waits_current::m_field_def=
+{ 19, field_types };
+
+PFS_engine_table_share
+table_events_waits_current::m_share=
+{
+ { C_STRING_WITH_LEN("events_waits_current") },
+ &pfs_truncatable_acl,
+ &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,
+ &m_field_def,
+ false /* checked */
+};
+
+THR_LOCK table_events_waits_history::m_table_lock;
+
+PFS_engine_table_share
+table_events_waits_history::m_share=
+{
+ { C_STRING_WITH_LEN("events_waits_history") },
+ &pfs_truncatable_acl,
+ &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,
+ &table_events_waits_current::m_field_def,
+ false /* checked */
+};
+
+THR_LOCK table_events_waits_history_long::m_table_lock;
+
+PFS_engine_table_share
+table_events_waits_history_long::m_share=
+{
+ { C_STRING_WITH_LEN("events_waits_history_long") },
+ &pfs_truncatable_acl,
+ &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,
+ &table_events_waits_current::m_field_def,
+ false /* checked */
+};
+
+table_events_waits_common::table_events_waits_common
+(const PFS_engine_table_share *share, void *pos)
+ : PFS_engine_table(share, pos),
+ m_row_exists(false)
+{}
+
+void table_events_waits_common::clear_object_columns()
+{
+ m_row.m_object_type= NULL;
+ 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;
+ uint safe_key_count= sanitize_index_count(safe_table_share->m_key_count);
+ if (safe_index < safe_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;
+}
+
+/**
+ Build a row.
+ @param thread_own_wait True if the memory for the wait
+ is owned by pfs_thread
+ @param pfs_thread the thread the cursor is reading
+ @param wait the wait the cursor is reading
+*/
+void table_events_waits_common::make_row(bool thread_own_wait,
+ PFS_thread *pfs_thread,
+ volatile PFS_events_waits *wait)
+{
+ pfs_lock lock;
+ PFS_thread *safe_thread;
+ PFS_instr_class *safe_class;
+ const char *base;
+ const char *safe_source_file;
+
+ m_row_exists= false;
+ safe_thread= sanitize_thread(pfs_thread);
+ if (unlikely(safe_thread == NULL))
+ return;
+
+ /* Protect this reader against a thread termination */
+ if (thread_own_wait)
+ safe_thread->m_lock.begin_optimistic_lock(&lock);
+
+ /*
+ Design choice:
+ We could have used a pfs_lock in PFS_events_waits here,
+ to protect the reader from concurrent event generation,
+ but this leads to too many pfs_lock atomic operations
+ each time an event is recorded:
+ - 1 dirty() + 1 allocated() per event start, for EVENTS_WAITS_CURRENT
+ - 1 dirty() + 1 allocated() per event end, for EVENTS_WAITS_CURRENT
+ - 1 dirty() + 1 allocated() per copy to EVENTS_WAITS_HISTORY
+ - 1 dirty() + 1 allocated() per copy to EVENTS_WAITS_HISTORY_LONG
+ or 8 atomics per recorded event.
+ The problem is that we record a *lot* of events ...
+
+ This code is prepared to accept *dirty* records,
+ and sanitizes all the data before returning a row.
+ */
+
+ /*
+ PFS_events_waits::m_class needs to be sanitized,
+ for race conditions when this code:
+ - reads a new value in m_wait_class,
+ - reads an old value in m_class.
+ */
+ 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);
+ break;
+ case WAIT_CLASS_RWLOCK:
+ clear_object_columns();
+ safe_class= sanitize_rwlock_class((PFS_rwlock_class*) wait->m_class);
+ break;
+ case WAIT_CLASS_COND:
+ clear_object_columns();
+ safe_class= sanitize_cond_class((PFS_cond_class*) wait->m_class);
+ break;
+ case WAIT_CLASS_TABLE:
+ if (make_table_object_columns(wait))
+ return;
+ safe_class= sanitize_table_class(wait->m_class);
+ break;
+ case WAIT_CLASS_FILE:
+ if (make_file_object_columns(wait))
+ return;
+ 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;
+
+ /*
+ We are assuming this pointer is sane,
+ since it comes from __FILE__.
+ */
+ safe_source_file= wait->m_source_file;
+ if (unlikely(safe_source_file == NULL))
+ return;
+
+ base= base_name(wait->m_source_file);
+ m_row.m_source_length= my_snprintf(m_row.m_source, sizeof(m_row.m_source),
+ "%s:%d", base, wait->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.m_operation= wait->m_operation;
+ m_row.m_number_of_bytes= wait->m_number_of_bytes;
+ m_row.m_flags= wait->m_flags;
+
+ if (thread_own_wait)
+ {
+ if (safe_thread->m_lock.end_optimistic_lock(&lock))
+ m_row_exists= true;
+ }
+ else
+ {
+ /*
+ For EVENTS_WAITS_HISTORY_LONG (thread_own_wait is false),
+ the wait record is always valid, because it is not stored
+ in memory owned by pfs_thread.
+ Even when the thread terminated, the record is mostly readable,
+ so this record is displayed.
+ */
+ m_row_exists= true;
+ }
+}
+
+/**
+ Operations names map, as displayed in the 'OPERATION' column.
+ Indexed by enum_operation_type - 1.
+ Note: enum_operation_type contains a more precise definition,
+ since more details are needed internally by the instrumentation.
+ Different similar operations (CLOSE vs STREAMCLOSE) are displayed
+ with the same name 'close'.
+*/
+static const LEX_STRING operation_names_map[]=
+{
+ /* Mutex operations */
+ { C_STRING_WITH_LEN("lock") },
+ { C_STRING_WITH_LEN("try_lock") },
+
+ /* RWLock operations */
+ { C_STRING_WITH_LEN("read_lock") },
+ { C_STRING_WITH_LEN("write_lock") },
+ { C_STRING_WITH_LEN("try_read_lock") },
+ { C_STRING_WITH_LEN("try_write_lock") },
+
+ /* Condition operations */
+ { C_STRING_WITH_LEN("wait") },
+ { C_STRING_WITH_LEN("timed_wait") },
+
+ /* File operations */
+ { C_STRING_WITH_LEN("create") },
+ { C_STRING_WITH_LEN("create") }, /* create tmp */
+ { C_STRING_WITH_LEN("open") },
+ { C_STRING_WITH_LEN("open") }, /* stream open */
+ { C_STRING_WITH_LEN("close") },
+ { C_STRING_WITH_LEN("close") }, /* stream close */
+ { C_STRING_WITH_LEN("read") },
+ { C_STRING_WITH_LEN("write") },
+ { C_STRING_WITH_LEN("seek") },
+ { C_STRING_WITH_LEN("tell") },
+ { C_STRING_WITH_LEN("flush") },
+ { C_STRING_WITH_LEN("stat") },
+ { C_STRING_WITH_LEN("stat") }, /* fstat */
+ { C_STRING_WITH_LEN("chsize") },
+ { C_STRING_WITH_LEN("delete") },
+ { C_STRING_WITH_LEN("rename") },
+ { 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") }
+};
+
+
+int table_events_waits_common::read_row_values(TABLE *table,
+ unsigned char *buf,
+ Field **fields,
+ bool read_all)
+{
+ Field *f;
+ const LEX_STRING *operation;
+
+ compile_time_assert(COUNT_OPERATION_TYPE ==
+ array_elements(operation_names_map));
+
+ if (unlikely(! m_row_exists))
+ return HA_ERR_RECORD_DELETED;
+
+ /* Set the null bits */
+ DBUG_ASSERT(table->s->null_bytes == 2);
+ buf[0]= 0;
+ buf[1]= 0;
+
+ /*
+ Some columns are unreliable, because they are joined with other buffers,
+ which could have changed and been reused for something else.
+ These columns are:
+ - THREAD_ID (m_thread joins with PFS_thread),
+ - SCHEMA_NAME (m_schema_name joins with PFS_table_share)
+ - OBJECT_NAME (m_object_name joins with PFS_table_share)
+ */
+ 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_ulonglong(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: /* SPINS */
+ f->set_null();
+ break;
+ case 9: /* OBJECT_SCHEMA */
+ if (m_row.m_object_schema_length > 0)
+ {
+ set_field_varchar_utf8(f, m_row.m_object_schema,
+ m_row.m_object_schema_length);
+ }
+ else
+ f->set_null();
+ break;
+ case 10: /* OBJECT_NAME */
+ if (m_row.m_object_name_length > 0)
+ {
+ set_field_varchar_utf8(f, m_row.m_object_name,
+ m_row.m_object_name_length);
+ }
+ else
+ f->set_null();
+ break;
+ 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,
+ m_row.m_object_type_length);
+ }
+ else
+ f->set_null();
+ break;
+ case 13: /* OBJECT_INSTANCE */
+ set_field_ulonglong(f, m_row.m_object_instance_addr);
+ break;
+ 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 16: /* OPERATION */
+ operation= &operation_names_map[(int) m_row.m_operation - 1];
+ set_field_varchar_utf8(f, operation->str, operation->length);
+ break;
+ 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_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 18: /* FLAGS */
+ f->set_null();
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+ return 0;
+}
+
+PFS_engine_table* table_events_waits_current::create(void)
+{
+ return new table_events_waits_current();
+}
+
+table_events_waits_current::table_events_waits_current()
+ : table_events_waits_common(&m_share, &m_pos),
+ m_pos(), m_next_pos()
+{}
+
+void table_events_waits_current::reset_position(void)
+{
+ m_pos.reset();
+ m_next_pos.reset();
+}
+
+int table_events_waits_current::rnd_next(void)
+{
+ PFS_thread *pfs_thread;
+ PFS_events_waits *wait;
+
+ 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;
+ }
+
+ /*
+ We do not show nested events for now,
+ this will be revised with TABLE io
+ */
+// #define ONLY_SHOW_ONE_WAIT
+
+#ifdef ONLY_SHOW_ONE_WAIT
+ if (m_pos.m_index_2 >= 1)
+ continue;
+#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];
+
+ 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)
+ {
+ /*
+ This locker does not exist.
+ There can not be more lockers in the stack, skip to the next thread
+ */
+ continue;
+ }
+
+ make_row(true, pfs_thread, wait);
+ /* Next iteration, look for the next locker in this thread */
+ m_next_pos.set_after(&m_pos);
+ return 0;
+ }
+
+ return HA_ERR_END_OF_FILE;
+}
+
+int table_events_waits_current::rnd_pos(const void *pos)
+{
+ PFS_thread *pfs_thread;
+ PFS_events_waits *wait;
+
+ 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;
+
+#ifdef ONLY_SHOW_ONE_WAIT
+ if (m_pos.m_index_2 >= 1)
+ return HA_ERR_RECORD_DELETED;
+#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];
+
+ 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
+
+ DBUG_ASSERT(m_pos.m_index_2 < WAIT_STACK_LOGICAL_SIZE);
+
+ if (wait->m_wait_class == NO_WAIT_CLASS)
+ return HA_ERR_RECORD_DELETED;
+
+ make_row(true, pfs_thread, wait);
+ return 0;
+}
+
+int table_events_waits_current::delete_all_rows(void)
+{
+ reset_events_waits_current();
+ return 0;
+}
+
+PFS_engine_table* table_events_waits_history::create(void)
+{
+ return new table_events_waits_history();
+}
+
+table_events_waits_history::table_events_waits_history()
+ : table_events_waits_common(&m_share, &m_pos),
+ m_pos(), m_next_pos()
+{}
+
+void table_events_waits_history::reset_position(void)
+{
+ m_pos.reset();
+ m_next_pos.reset();
+}
+
+int table_events_waits_history::rnd_next(void)
+{
+ PFS_thread *pfs_thread;
+ PFS_events_waits *wait;
+
+ if (events_waits_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_waits_history_per_thread)
+ {
+ /* This thread does not have more (full) history */
+ continue;
+ }
+
+ if ( ! pfs_thread->m_waits_history_full &&
+ (m_pos.m_index_2 >= pfs_thread->m_waits_history_index))
+ {
+ /* This thread does not have more (not full) history */
+ continue;
+ }
+
+ if (pfs_thread->m_waits_history[m_pos.m_index_2].m_wait_class
+ == NO_WAIT_CLASS)
+ {
+ /*
+ This locker does not exist.
+ There can not be more lockers in the stack, skip to the next thread
+ */
+ continue;
+ }
+
+ wait= &pfs_thread->m_waits_history[m_pos.m_index_2];
+
+ make_row(true, pfs_thread, wait);
+ /* 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_waits_history::rnd_pos(const void *pos)
+{
+ PFS_thread *pfs_thread;
+ PFS_events_waits *wait;
+
+ DBUG_ASSERT(events_waits_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_waits_history_per_thread);
+
+ if ( ! pfs_thread->m_waits_history_full &&
+ (m_pos.m_index_2 >= pfs_thread->m_waits_history_index))
+ 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;
+}
+
+int table_events_waits_history::delete_all_rows(void)
+{
+ reset_events_waits_history();
+ return 0;
+}
+
+PFS_engine_table* table_events_waits_history_long::create(void)
+{
+ return new table_events_waits_history_long();
+}
+
+table_events_waits_history_long::table_events_waits_history_long()
+ : table_events_waits_common(&m_share, &m_pos),
+ m_pos(0), m_next_pos(0)
+{}
+
+void table_events_waits_history_long::reset_position(void)
+{
+ m_pos.m_index= 0;
+ m_next_pos.m_index= 0;
+}
+
+int table_events_waits_history_long::rnd_next(void)
+{
+ PFS_events_waits *wait;
+ uint limit;
+
+ if (events_waits_history_long_size == 0)
+ return HA_ERR_END_OF_FILE;
+
+ if (events_waits_history_long_full)
+ limit= events_waits_history_long_size;
+ else
+ limit= events_waits_history_long_index % events_waits_history_long_size;
+
+ for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next())
+ {
+ wait= &events_waits_history_long_array[m_pos.m_index];
+
+ if (wait->m_wait_class != NO_WAIT_CLASS)
+ {
+ make_row(false, wait->m_thread, wait);
+ /* 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_waits_history_long::rnd_pos(const void *pos)
+{
+ PFS_events_waits *wait;
+ uint limit;
+
+ if (events_waits_history_long_size == 0)
+ return HA_ERR_RECORD_DELETED;
+
+ set_position(pos);
+
+ if (events_waits_history_long_full)
+ limit= events_waits_history_long_size;
+ else
+ limit= events_waits_history_long_index % events_waits_history_long_size;
+
+ if (m_pos.m_index >= limit)
+ return HA_ERR_RECORD_DELETED;
+
+ wait= &events_waits_history_long_array[m_pos.m_index];
+
+ if (wait->m_wait_class == NO_WAIT_CLASS)
+ return HA_ERR_RECORD_DELETED;
+
+ make_row(false, wait->m_thread, wait);
+ return 0;
+}
+
+int table_events_waits_history_long::delete_all_rows(void)
+{
+ reset_events_waits_history_long();
+ return 0;
+}
+
diff --git a/storage/perfschema/table_events_waits.h b/storage/perfschema/table_events_waits.h
new file mode 100644
index 00000000000..065bf95e5a6
--- /dev/null
+++ b/storage/perfschema/table_events_waits.h
@@ -0,0 +1,259 @@
+/* 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_EVENTS_WAITS_H
+#define TABLE_EVENTS_WAITS_H
+
+/**
+ @file storage/perfschema/table_events_waits.h
+ Table EVENTS_WAITS_xxx (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+#include "pfs_events_waits.h"
+
+struct PFS_thread;
+
+/**
+ @addtogroup Performance_schema_tables
+ @{
+*/
+
+/** A row of table_events_waits_common. */
+struct row_events_waits
+{
+ /** Column THREAD_ID. */
+ ulonglong 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 OBJECT_TYPE. */
+ const char *m_object_type;
+ /** Length in bytes of @c m_object_type. */
+ uint m_object_type_length;
+ /** Column OBJECT_SCHEMA. */
+ char m_object_schema[COL_OBJECT_SCHEMA_SIZE];
+ /** Length in bytes of @c m_object_schema. */
+ uint m_object_schema_length;
+ /** Column OBJECT_NAME. */
+ 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. */
+ char m_source[COL_SOURCE_SIZE];
+ /** Length in bytes of @c m_source. */
+ uint m_source_length;
+ /** Column OPERATION. */
+ enum_operation_type m_operation;
+ /** Column NUMBER_OF_BYTES. */
+ ulonglong m_number_of_bytes;
+ /** Column FLAGS. */
+ uint m_flags;
+};
+
+/** Position of a cursor on PERFORMANCE_SCHEMA.EVENTS_WAITS_CURRENT. */
+struct pos_events_waits_current : public PFS_double_index
+{
+ pos_events_waits_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_WAITS_HISTORY. */
+struct pos_events_waits_history : public PFS_double_index
+{
+ pos_events_waits_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_WAITS_CURRENT.
+*/
+class table_events_waits_common : public PFS_engine_table
+{
+protected:
+ virtual int read_row_values(TABLE *table,
+ unsigned char *buf,
+ Field **fields,
+ bool read_all);
+
+ table_events_waits_common(const PFS_engine_table_share *share, void *pos);
+
+ ~table_events_waits_common()
+ {}
+
+ 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 if the current row exists. */
+ bool m_row_exists;
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_CURRENT. */
+class table_events_waits_current : public table_events_waits_common
+{
+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:
+ table_events_waits_current();
+
+public:
+ ~table_events_waits_current()
+ {}
+
+private:
+ friend class table_events_waits_history;
+ friend class table_events_waits_history_long;
+
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+ /**
+ Fields definition.
+ Also used by table_events_waits_history
+ and table_events_waits_history_long.
+ */
+ static TABLE_FIELD_DEF m_field_def;
+
+ /** Current position. */
+ pos_events_waits_current m_pos;
+ /** Next position. */
+ pos_events_waits_current m_next_pos;
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_HISTORY. */
+class table_events_waits_history : public table_events_waits_common
+{
+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:
+ table_events_waits_history();
+
+public:
+ ~table_events_waits_history()
+ {}
+
+private:
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+
+ /** Current position. */
+ pos_events_waits_history m_pos;
+ /** Next position. */
+ pos_events_waits_history m_next_pos;
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_HISTORY_LONG. */
+class table_events_waits_history_long : public table_events_waits_common
+{
+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:
+ table_events_waits_history_long();
+
+public:
+ ~table_events_waits_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_summary.cc b/storage/perfschema/table_events_waits_summary.cc
new file mode 100644
index 00000000000..f437e83f3ff
--- /dev/null
+++ b/storage/perfschema/table_events_waits_summary.cc
@@ -0,0 +1,265 @@
+/* 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_events_waits_summary.cc
+ Table EVENTS_WAITS_SUMMARY_BY_xxx (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_events_waits_summary.h"
+#include "pfs_global.h"
+
+THR_LOCK table_events_waits_summary_by_instance::m_table_lock;
+
+static const TABLE_FIELD_TYPE ews_by_instance_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}
+ }
+};
+
+TABLE_FIELD_DEF
+table_events_waits_summary_by_instance::m_field_def=
+{ 7, ews_by_instance_field_types };
+
+PFS_engine_table_share
+table_events_waits_summary_by_instance::m_share=
+{
+ { C_STRING_WITH_LEN("events_waits_summary_by_instance") },
+ &pfs_truncatable_acl,
+ &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,
+ &m_field_def,
+ false /* checked */
+};
+
+PFS_engine_table* table_events_waits_summary_by_instance::create(void)
+{
+ return new table_events_waits_summary_by_instance();
+}
+
+int table_events_waits_summary_by_instance::delete_all_rows(void)
+{
+ reset_events_waits_by_instance();
+ return 0;
+}
+
+table_events_waits_summary_by_instance
+::table_events_waits_summary_by_instance()
+ : table_all_instr(&m_share), m_row_exists(false)
+{}
+
+void table_events_waits_summary_by_instance
+::make_instr_row(PFS_instr *pfs, PFS_instr_class *klass,
+ const void *object_instance_begin,
+ PFS_single_stat *pfs_stat)
+{
+ pfs_lock lock;
+ m_row_exists= false;
+
+ /*
+ Protect this reader against a mutex/rwlock/cond destroy,
+ file delete, table drop.
+ */
+ pfs->m_lock.begin_optimistic_lock(&lock);
+
+ m_row.m_name= klass->m_name;
+ m_row.m_name_length= klass->m_name_length;
+ m_row.m_object_instance_addr= (intptr) object_instance_begin;
+
+ get_normalizer(klass);
+ m_row.m_stat.set(m_normalizer, pfs_stat);
+
+ if (pfs->m_lock.end_optimistic_lock(&lock))
+ m_row_exists= true;
+}
+
+/**
+ Build a row, for mutex statistics in a thread.
+ @param pfs the mutex this cursor is reading
+*/
+void table_events_waits_summary_by_instance::make_mutex_row(PFS_mutex *pfs)
+{
+ PFS_mutex_class *safe_class;
+ safe_class= sanitize_mutex_class(pfs->m_class);
+ if (unlikely(safe_class == NULL))
+ return;
+
+ make_instr_row(pfs, safe_class, pfs->m_identity, &pfs->m_mutex_stat.m_wait_stat);
+}
+
+/**
+ Build a row, for rwlock statistics in a thread.
+ @param pfs the rwlock this cursor is reading
+*/
+void table_events_waits_summary_by_instance::make_rwlock_row(PFS_rwlock *pfs)
+{
+ PFS_rwlock_class *safe_class;
+ safe_class= sanitize_rwlock_class(pfs->m_class);
+ if (unlikely(safe_class == NULL))
+ return;
+
+ make_instr_row(pfs, safe_class, pfs->m_identity, &pfs->m_rwlock_stat.m_wait_stat);
+}
+
+/**
+ Build a row, for condition statistics in a thread.
+ @param pfs the condition this cursor is reading
+*/
+void table_events_waits_summary_by_instance::make_cond_row(PFS_cond *pfs)
+{
+ PFS_cond_class *safe_class;
+ safe_class= sanitize_cond_class(pfs->m_class);
+ if (unlikely(safe_class == NULL))
+ return;
+
+ make_instr_row(pfs, safe_class, pfs->m_identity, &pfs->m_cond_stat.m_wait_stat);
+}
+
+/**
+ Build a row, for file statistics in a thread.
+ @param pfs the file this cursor is reading
+*/
+void table_events_waits_summary_by_instance::make_file_row(PFS_file *pfs)
+{
+ PFS_file_class *safe_class;
+ safe_class= sanitize_file_class(pfs->m_class);
+ if (unlikely(safe_class == NULL))
+ return;
+
+ PFS_single_stat sum;
+ pfs->m_file_stat.m_io_stat.sum_waits(& sum);
+ /*
+ 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, & sum);
+}
+
+/**
+ 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
+::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 */
+ set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
+ break;
+ case 1: /* OBJECT_INSTANCE */
+ set_field_ulonglong(f, m_row.m_object_instance_addr);
+ break;
+ case 2: /* COUNT */
+ set_field_ulonglong(f, m_row.m_stat.m_count);
+ break;
+ case 3: /* SUM */
+ set_field_ulonglong(f, m_row.m_stat.m_sum);
+ break;
+ case 4: /* MIN */
+ set_field_ulonglong(f, m_row.m_stat.m_min);
+ break;
+ case 5: /* AVG */
+ set_field_ulonglong(f, m_row.m_stat.m_avg);
+ break;
+ case 6: /* MAX */
+ set_field_ulonglong(f, m_row.m_stat.m_max);
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/storage/perfschema/table_events_waits_summary.h b/storage/perfschema/table_events_waits_summary.h
new file mode 100644
index 00000000000..7463ace3eb6
--- /dev/null
+++ b/storage/perfschema/table_events_waits_summary.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_EVENTS_WAITS_SUMMARY_H
+#define TABLE_EVENTS_WAITS_SUMMARY_H
+
+/**
+ @file storage/perfschema/table_events_waits_summary.h
+ Table EVENTS_WAITS_SUMMARY_BY_xxx (declarations).
+*/
+
+#include "pfs_column_types.h"
+#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_BY_INSTANCE. */
+struct row_events_waits_summary_by_instance
+{
+ /** Column EVENT_NAME. */
+ const char *m_name;
+ /** Length in bytes of @c m_name. */
+ uint m_name_length;
+ /** Column OBJECT_INSTANCE_BEGIN. */
+ intptr m_object_instance_addr;
+ /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */
+ PFS_stat_row m_stat;
+};
+
+/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_INSTANCE. */
+class table_events_waits_summary_by_instance : public table_all_instr
+{
+public:
+ /** Table share */
+ static PFS_engine_table_share m_share;
+ static PFS_engine_table* create();
+ static int delete_all_rows();
+
+protected:
+ void make_instr_row(PFS_instr *pfs, PFS_instr_class *klass,
+ 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,
+ Field **fields,
+ bool read_all);
+
+ table_events_waits_summary_by_instance();
+
+public:
+ ~table_events_waits_summary_by_instance()
+ {}
+
+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_instance m_row;
+ /** True if the current row exists. */
+ bool m_row_exists;
+};
+
+/** @} */
+#endif
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..4db97b1c98c
--- /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("bigint(20)") },
+ { 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_ulonglong(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..989356be646
--- /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. */
+ ulonglong 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
new file mode 100644
index 00000000000..1e165c36bc5
--- /dev/null
+++ b/storage/perfschema/table_ews_global_by_event_name.cc
@@ -0,0 +1,417 @@
+/* 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_global_by_event_name.cc
+ Table EVENTS_WAITS_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_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;
+
+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_ews_global_by_event_name::m_field_def=
+{ 6, field_types };
+
+PFS_engine_table_share
+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,
+ NULL, /* write_row */
+ table_ews_global_by_event_name::delete_all_rows,
+ NULL, /* get_row_count */
+ 1000, /* records */
+ 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)
+{
+ return new table_ews_global_by_event_name();
+}
+
+int
+table_ews_global_by_event_name::delete_all_rows(void)
+{
+ reset_events_waits_by_instance();
+ reset_table_waits_by_table_handle();
+ reset_table_waits_by_table();
+ reset_events_waits_by_class();
+ return 0;
+}
+
+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::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;
+
+ 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)
+{
+ 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;
+
+ set_position(pos);
+
+ 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);
+ 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
+::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;
+ 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_ews_global_by_event_name.h b/storage/perfschema/table_ews_global_by_event_name.h
new file mode 100644
index 00000000000..a118e536b6a
--- /dev/null
+++ b/storage/perfschema/table_ews_global_by_event_name.h
@@ -0,0 +1,128 @@
+/* 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_GLOBAL_BY_EVENT_NAME_H
+#define TABLE_EWS_GLOBAL_BY_EVENT_NAME_H
+
+/**
+ @file storage/perfschema/table_ews_global_by_event_name.h
+ Table EVENTS_WAITS_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_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME.
+*/
+struct row_ews_global_by_event_name
+{
+ /** 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_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 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_global_by_event_name();
+
+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;
+ /** Fields definition. */
+ static TABLE_FIELD_DEF m_field_def;
+
+ /** 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;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_file_instances.cc b/storage/perfschema/table_file_instances.cc
new file mode 100644
index 00000000000..a3d2fc454bb
--- /dev/null
+++ b/storage/perfschema/table_file_instances.cc
@@ -0,0 +1,182 @@
+/* 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_file_instances.cc
+ Table FILE_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_file_instances.h"
+#include "pfs_global.h"
+
+THR_LOCK table_file_instances::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("OPEN_COUNT") },
+ { C_STRING_WITH_LEN("int(10)") },
+ { NULL, 0}
+ }
+};
+
+TABLE_FIELD_DEF
+table_file_instances::m_field_def=
+{ 3, field_types };
+
+PFS_engine_table_share
+table_file_instances::m_share=
+{
+ { C_STRING_WITH_LEN("file_instances") },
+ &pfs_readonly_acl,
+ &table_file_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_file_instances::create(void)
+{
+ return new table_file_instances();
+}
+
+table_file_instances::table_file_instances()
+ : PFS_engine_table(&m_share, &m_pos),
+ m_row_exists(false), m_pos(0), m_next_pos(0)
+{}
+
+void table_file_instances::reset_position(void)
+{
+ m_pos.m_index= 0;
+ m_next_pos.m_index= 0;
+}
+
+int table_file_instances::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_instances::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;
+}
+
+void table_file_instances::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= safe_class->m_name;
+ m_row.m_event_name_length= safe_class->m_name_length;
+ m_row.m_open_count= pfs->m_file_stat.m_open_count;
+
+ if (pfs->m_lock.end_optimistic_lock(&lock))
+ m_row_exists= true;
+}
+
+int table_file_instances::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: /* FILENAME */
+ set_field_varchar_utf8(f, m_row.m_filename, m_row.m_filename_length);
+ break;
+ case 1: /* EVENT_NAME */
+ set_field_varchar_utf8(f, m_row.m_event_name,
+ m_row.m_event_name_length);
+ break;
+ case 2: /* OPEN_COUNT */
+ set_field_ulong(f, m_row.m_open_count);
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/storage/perfschema/table_file_instances.h b/storage/perfschema/table_file_instances.h
new file mode 100644
index 00000000000..f7ec16715f3
--- /dev/null
+++ b/storage/perfschema/table_file_instances.h
@@ -0,0 +1,90 @@
+/* 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_FILE_INSTANCES_H
+#define TABLE_FILE_INSTANCES_H
+
+/**
+ @file storage/perfschema/table_file_instances.h
+ Table FILE_INSTANCES (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+
+/**
+ @addtogroup Performance_schema_tables
+ @{
+*/
+
+/** A row of PERFORMANCE_SCHEMA.FILE_INSTANCES. */
+struct row_file_instances
+{
+ /** Column FILE_NAME. */
+ const char *m_filename;
+ /** Length in bytes of @c m_filename. */
+ uint m_filename_length;
+ /** Column EVENT_NAME. */
+ const char *m_event_name;
+ /** Length in bytes of @c m_event_name. */
+ uint m_event_name_length;
+ /** Column OPEN_COUNT. */
+ uint m_open_count;
+};
+
+/** Table PERFORMANCE_SCHEMA.FILE_INSTANCES. */
+class table_file_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_file_instances();
+
+public:
+ ~table_file_instances()
+ {}
+
+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_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_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..9f803434ab6
--- /dev/null
+++ b/storage/perfschema/table_helper.cc
@@ -0,0 +1,351 @@
+/* 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)
+ {
+ m_schema_name_length= pfs->m_digest_key.m_schema_name_length;
+ if (m_schema_name_length > 0)
+ memcpy(m_schema_name, pfs->m_digest_key.m_schema_name, m_schema_name_length);
+ /*
+ Calculate digest from MD5 HASH collected to be shown as
+ DIGEST in this row.
+ */
+ MD5_HASH_TO_STRING(pfs->m_digest_key.m_md5, m_digest);
+ m_digest_length= MD5_HASH_TO_STRING_LENGTH;
+
+ /*
+ Calculate 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_schema_name_length= 0;
+ 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: /* SCHEMA_NAME */
+ if (m_schema_name_length > 0)
+ PFS_engine_table::set_field_varchar_utf8(f, m_schema_name,
+ m_schema_name_length);
+ else
+ f->set_null();
+ break;
+ case 1: /* 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 2: /* 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_INDEXES)
+ {
+ 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..769122570eb
--- /dev/null
+++ b/storage/perfschema/table_helper.h
@@ -0,0 +1,522 @@
+/* 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 SCHEMA_NAME. */
+ char m_schema_name[NAME_LEN];
+ /** Length in bytes of @c m_schema_name. */
+ uint m_schema_name_length;
+ /** 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..02c7f72140a
--- /dev/null
+++ b/storage/perfschema/table_host_cache.cc
@@ -0,0 +1,478 @@
+/* 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"
+
+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();
+ }
+
+ 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;
+}
+
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..70d9d6819ac
--- /dev/null
+++ b/storage/perfschema/table_os_global_by_type.cc
@@ -0,0 +1,275 @@
+/* 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;
+ uint safe_key_count;
+
+ 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;
+
+ /* This is a dirty read, some thread can write data while we are reading it */
+ safe_key_count= sanitize_index_count(share->m_key_count);
+
+ share->m_table_stat.sum(& cumulated_stat, safe_key_count);
+
+ 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, safe_key_count);
+ }
+ }
+ }
+
+ 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
new file mode 100644
index 00000000000..a891d2f04cd
--- /dev/null
+++ b/storage/perfschema/table_performance_timers.cc
@@ -0,0 +1,189 @@
+/* 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_performance_timers.cc
+ Table PERFORMANCE_TIMERS (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "table_performance_timers.h"
+#include "pfs_timer.h"
+#include "pfs_global.h"
+
+THR_LOCK table_performance_timers::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+ {
+ { C_STRING_WITH_LEN("TIMER_NAME") },
+ { C_STRING_WITH_LEN("enum(\'CYCLE\',\'NANOSECOND\',\'MICROSECOND\',"
+ "\'MILLISECOND\',\'TICK\')") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("TIMER_FREQUENCY") },
+ { C_STRING_WITH_LEN("bigint(20)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("TIMER_RESOLUTION") },
+ { C_STRING_WITH_LEN("bigint(20)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("TIMER_OVERHEAD") },
+ { C_STRING_WITH_LEN("bigint(20)") },
+ { NULL, 0}
+ }
+};
+
+TABLE_FIELD_DEF
+table_performance_timers::m_field_def=
+{ 4, field_types };
+
+PFS_engine_table_share
+table_performance_timers::m_share=
+{
+ { C_STRING_WITH_LEN("performance_timers") },
+ &pfs_readonly_acl,
+ &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,
+ &m_field_def,
+ false /* checked */
+};
+
+PFS_engine_table* table_performance_timers::create(void)
+{
+ return new table_performance_timers();
+}
+
+table_performance_timers::table_performance_timers()
+ : PFS_engine_table(&m_share, &m_pos),
+ m_row(NULL), m_pos(0), m_next_pos(0)
+{
+ int index;
+
+ index= (int)TIMER_NAME_CYCLE - FIRST_TIMER_NAME;
+ m_data[index].m_timer_name= TIMER_NAME_CYCLE;
+ m_data[index].m_info= pfs_timer_info.cycles;
+
+ index= (int)TIMER_NAME_NANOSEC - FIRST_TIMER_NAME;
+ m_data[index].m_timer_name= TIMER_NAME_NANOSEC;
+ m_data[index].m_info= pfs_timer_info.nanoseconds;
+
+ index= (int)TIMER_NAME_MICROSEC - FIRST_TIMER_NAME;
+ m_data[index].m_timer_name= TIMER_NAME_MICROSEC;
+ m_data[index].m_info= pfs_timer_info.microseconds;
+
+ index= (int)TIMER_NAME_MILLISEC - FIRST_TIMER_NAME;
+ m_data[index].m_timer_name= TIMER_NAME_MILLISEC;
+ m_data[index].m_info= pfs_timer_info.milliseconds;
+
+ index= (int)TIMER_NAME_TICK - FIRST_TIMER_NAME;
+ m_data[index].m_timer_name= TIMER_NAME_TICK;
+ m_data[index].m_info= pfs_timer_info.ticks;
+}
+
+void table_performance_timers::reset_position(void)
+{
+ m_pos.m_index= 0;
+ m_next_pos.m_index= 0;
+}
+
+int table_performance_timers::rnd_next(void)
+{
+ int result;
+
+ m_pos.set_at(&m_next_pos);
+
+ if (m_pos.m_index < COUNT_TIMER_NAME)
+ {
+ m_row= &m_data[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_performance_timers::rnd_pos(const void *pos)
+{
+ set_position(pos);
+ DBUG_ASSERT(m_pos.m_index < COUNT_TIMER_NAME);
+ m_row= &m_data[m_pos.m_index];
+ return 0;
+}
+
+int table_performance_timers::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: /* TIMER_NAME */
+ set_field_enum(f, m_row->m_timer_name);
+ break;
+ case 1: /* TIMER_FREQUENCY */
+ if (m_row->m_info.routine != 0)
+ set_field_ulonglong(f, m_row->m_info.frequency);
+ else
+ f->set_null();
+ break;
+ case 2: /* TIMER_RESOLUTION */
+ if (m_row->m_info.routine != 0)
+ set_field_ulonglong(f, m_row->m_info.resolution);
+ else
+ f->set_null();
+ break;
+ case 3: /* TIMER_OVERHEAD */
+ if (m_row->m_info.routine != 0)
+ set_field_ulonglong(f, m_row->m_info.overhead);
+ else
+ f->set_null();
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/storage/perfschema/table_performance_timers.h b/storage/perfschema/table_performance_timers.h
new file mode 100644
index 00000000000..dbd47665ff6
--- /dev/null
+++ b/storage/perfschema/table_performance_timers.h
@@ -0,0 +1,86 @@
+/* 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_PERFORMANCE_TIMERS_H
+#define TABLE_PERFORMANCE_TIMERS_H
+
+/**
+ @file storage/perfschema/table_performance_timers.h
+ Table PERFORMANCE_TIMERS (declarations).
+*/
+
+#include <my_rdtsc.h>
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+
+/**
+ @addtogroup Performance_schema_tables
+ @{
+*/
+
+/** A row of PERFORMANCE_SCHEMA.PERFORMANCE_TIMERS. */
+struct row_performance_timers
+{
+ /** Column TIMER_NAME. */
+ enum_timer_name m_timer_name;
+ /**
+ Columns ROUTINE (not displayed), TIMER_OVERHEAD,
+ TIMER_FREQUENCY, TIMER_RESOLUTION.
+ */
+ struct my_timer_unit_info m_info;
+};
+
+/** Table PERFORMANCE_SCHEMA.PERFORMANCE_TIMERS. */
+class table_performance_timers : 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);
+
+protected:
+ virtual int read_row_values(TABLE *table,
+ unsigned char *buf,
+ Field **fields,
+ bool read_all);
+
+protected:
+ table_performance_timers();
+
+public:
+ ~table_performance_timers()
+ {}
+
+private:
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+ /** Fields definition. */
+ static TABLE_FIELD_DEF m_field_def;
+
+ /** Current row. */
+ row_performance_timers *m_row;
+ /** Current position. */
+ PFS_simple_index m_pos;
+ /** Next position. */
+ PFS_simple_index m_next_pos;
+ row_performance_timers m_data[COUNT_TIMER_NAME];
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_session_account_connect_attrs.cc b/storage/perfschema/table_session_account_connect_attrs.cc
new file mode 100644
index 00000000000..4a3fcc22341
--- /dev/null
+++ b/storage/perfschema/table_session_account_connect_attrs.cc
@@ -0,0 +1,70 @@
+/* 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 */
+
+#include "table_session_account_connect_attrs.h"
+
+THR_LOCK table_session_account_connect_attrs::m_table_lock;
+
+PFS_engine_table_share
+table_session_account_connect_attrs::m_share=
+{
+ { C_STRING_WITH_LEN("session_account_connect_attrs") },
+ &pfs_readonly_acl,
+ &table_session_account_connect_attrs::create,
+ NULL, /* write_row */
+ NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
+ 1000, /* records */
+ sizeof(pos_connect_attr_by_thread_by_attr), /* ref length */
+ &m_table_lock,
+ &m_field_def,
+ false /* checked */
+};
+
+PFS_engine_table* table_session_account_connect_attrs::create()
+{
+ return new table_session_account_connect_attrs();
+}
+
+table_session_account_connect_attrs::table_session_account_connect_attrs()
+ : table_session_connect(&m_share)
+{}
+
+bool
+table_session_account_connect_attrs::thread_fits(PFS_thread *thread)
+{
+ PFS_thread *current_thread= PFS_thread::get_current_thread();
+ /* The current thread may not have instrumentation attached. */
+ if (current_thread == NULL)
+ return false;
+
+ /* The thread we compare to, by definition, has some instrumentation. */
+ DBUG_ASSERT(thread != NULL);
+
+ uint username_length= current_thread->m_username_length;
+ uint hostname_length= current_thread->m_hostname_length;
+
+ if ( (thread->m_username_length != username_length)
+ || (thread->m_hostname_length != hostname_length))
+ return false;
+
+ if (memcmp(thread->m_username, current_thread->m_username, username_length) != 0)
+ return false;
+
+ if (memcmp(thread->m_hostname, current_thread->m_hostname, hostname_length) != 0)
+ return false;
+
+ return true;
+}
diff --git a/storage/perfschema/table_session_account_connect_attrs.h b/storage/perfschema/table_session_account_connect_attrs.h
new file mode 100644
index 00000000000..ba8893e7cad
--- /dev/null
+++ b/storage/perfschema/table_session_account_connect_attrs.h
@@ -0,0 +1,50 @@
+/* Copyright (c) 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 TABLE_SESSION_ACCOUNT_CONNECT_ATTRS_H
+#define TABLE_SESSION_ACCOUNT_CONNECT_ATTRS_H
+
+#include "table_session_connect.h"
+/**
+ \addtogroup Performance_schema_tables
+ @{
+*/
+
+/** Table PERFORMANCE_SCHEMA.SESSION_ACCOUNT_CONNECT_ATTRS. */
+class table_session_account_connect_attrs : public table_session_connect
+{
+public:
+ /** Table share */
+ static PFS_engine_table_share m_share;
+ /** Table builder */
+ static PFS_engine_table* create();
+
+protected:
+ table_session_account_connect_attrs();
+
+public:
+ ~table_session_account_connect_attrs()
+ {}
+
+protected:
+ virtual bool thread_fits(PFS_thread *thread);
+
+private:
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_session_connect.cc b/storage/perfschema/table_session_connect.cc
new file mode 100644
index 00000000000..bd905b5756c
--- /dev/null
+++ b/storage/perfschema/table_session_connect.cc
@@ -0,0 +1,268 @@
+/* Copyright (c) 2008, 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 */
+
+#include "table_session_connect.h"
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+ {
+ { C_STRING_WITH_LEN("PROCESSLIST_ID") },
+ { C_STRING_WITH_LEN("int(11)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("ATTR_NAME") },
+ { C_STRING_WITH_LEN("varchar(32)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("ATTR_VALUE") },
+ { C_STRING_WITH_LEN("varchar(1024)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("ORDINAL_POSITION") },
+ { C_STRING_WITH_LEN("int(11)") },
+ { NULL, 0}
+ }
+};
+
+TABLE_FIELD_DEF table_session_connect::m_field_def=
+{ 4, field_types };
+
+table_session_connect::table_session_connect(const PFS_engine_table_share *share) :
+ cursor_by_thread_connect_attr(share)
+{}
+
+/**
+ Take a length encoded string
+
+ @arg ptr inout the input string array
+ @arg dest where to store the result
+ @arg dest_size max size of @c dest
+ @arg copied_len the actual length of the data copied
+ @arg start_ptr pointer to the start of input
+ @arg input_length the length of the incoming data
+ @arg copy_data copy the data or just skip the input
+ @arg from_cs character set in which @c ptr is encoded
+ @arg nchars_max maximum number of characters to read
+ @return status
+ @retval true parsing failed
+ @retval false parsing succeeded
+*/
+bool parse_length_encoded_string(const char **ptr,
+ char *dest, uint dest_size,
+ uint *copied_len,
+ const char *start_ptr, uint input_length,
+ bool copy_data,
+ const CHARSET_INFO *from_cs,
+ uint nchars_max)
+{
+ ulong copy_length, data_length;
+ const char *well_formed_error_pos= NULL, *cannot_convert_error_pos= NULL,
+ *from_end_pos= NULL;
+
+ copy_length= data_length= net_field_length((uchar **) ptr);
+
+ /* we don't tolerate NULL as a length */
+ if (data_length == NULL_LENGTH)
+ return true;
+
+ if (*ptr - start_ptr + data_length > input_length)
+ return true;
+
+ copy_length= well_formed_copy_nchars(&my_charset_utf8_bin, dest, dest_size,
+ from_cs, *ptr, data_length, nchars_max,
+ &well_formed_error_pos,
+ &cannot_convert_error_pos,
+ &from_end_pos);
+ *copied_len= copy_length;
+ (*ptr)+= data_length;
+
+ return false;
+}
+
+/**
+ Take the nth attribute name/value pair
+
+ Parse the attributes blob form the beginning, skipping the attributes
+ whose number is lower than the one we seek.
+ When we reach the attribute at an index we're looking for the values
+ are copied to the output parameters.
+ If parsing fails or no more attributes are found the function stops
+ and returns an error code.
+
+ @arg connect_attrs pointer to the connect attributes blob
+ @arg connect_attrs_length length of @c connect_attrs
+ @arg connect_attrs_cs character set used to encode @c connect_attrs
+ @arg ordinal index of the attribute we need
+ @arg attr_name [out] buffer to receive the attribute name
+ @arg max_attr_name max size of @c attr_name in bytes
+ @arg attr_name_length [out] number of bytes written in @attr_name
+ @arg attr_value [out] buffer to receive the attribute name
+ @arg max_attr_value max size of @c attr_value in bytes
+ @arg attr_value_length [out] number of bytes written in @attr_value
+ @return status
+ @retval true requested attribute pair is found and copied
+ @retval false error. Either because of parsing or too few attributes.
+*/
+bool read_nth_attr(const char *connect_attrs,
+ uint connect_attrs_length,
+ const CHARSET_INFO *connect_attrs_cs,
+ uint ordinal,
+ char *attr_name, uint max_attr_name,
+ uint *attr_name_length,
+ char *attr_value, uint max_attr_value,
+ uint *attr_value_length)
+{
+ uint idx;
+ const char *ptr;
+
+ for (ptr= connect_attrs, idx= 0;
+ (uint)(ptr - connect_attrs) < connect_attrs_length && idx <= ordinal;
+ idx++)
+ {
+ uint copy_length;
+ /* do the copying only if we absolutely have to */
+ bool fill_in_attr_name= idx == ordinal;
+ bool fill_in_attr_value= idx == ordinal;
+
+ /* read the key */
+ if (parse_length_encoded_string(&ptr,
+ attr_name, max_attr_name, &copy_length,
+ connect_attrs,
+ connect_attrs_length,
+ fill_in_attr_name,
+ connect_attrs_cs, 32) ||
+ !copy_length
+ )
+ return false;
+
+ if (idx == ordinal)
+ *attr_name_length= copy_length;
+
+ /* read the value */
+ if (parse_length_encoded_string(&ptr,
+ attr_value, max_attr_value, &copy_length,
+ connect_attrs,
+ connect_attrs_length,
+ fill_in_attr_value,
+ connect_attrs_cs, 1024))
+ return false;
+
+ if (idx == ordinal)
+ *attr_value_length= copy_length;
+
+ if (idx == ordinal)
+ return true;
+ }
+
+ return false;
+}
+
+void table_session_connect::make_row(PFS_thread *pfs, uint ordinal)
+{
+ pfs_lock lock;
+ PFS_thread_class *safe_class;
+
+ m_row_exists= false;
+
+ /* Protect this reader against thread termination */
+ pfs->m_lock.begin_optimistic_lock(&lock);
+ safe_class= sanitize_thread_class(pfs->m_class);
+ if (unlikely(safe_class == NULL))
+ return;
+
+ /* Filtering threads must be done under the protection of the optimistic lock. */
+ if (! thread_fits(pfs))
+ return;
+
+ /* populate the row */
+ if (read_nth_attr(pfs->m_session_connect_attrs,
+ pfs->m_session_connect_attrs_length,
+ pfs->m_session_connect_attrs_cs,
+ ordinal,
+ m_row.m_attr_name, (uint) sizeof(m_row.m_attr_name),
+ &m_row.m_attr_name_length,
+ m_row.m_attr_value, (uint) sizeof(m_row.m_attr_value),
+ &m_row.m_attr_value_length))
+ {
+ /* we don't expect internal threads to have connection attributes */
+ DBUG_ASSERT(pfs->m_processlist_id != 0);
+
+ m_row.m_ordinal_position= ordinal;
+ m_row.m_process_id= pfs->m_processlist_id;
+ }
+ else
+ return;
+
+ if (pfs->m_lock.end_optimistic_lock(& lock))
+ m_row_exists= true;
+}
+
+int table_session_connect::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 FO_PROCESS_ID:
+ if (m_row.m_process_id != 0)
+ set_field_ulong(f, m_row.m_process_id);
+ else
+ f->set_null();
+ break;
+ case FO_ATTR_NAME:
+ set_field_varchar_utf8(f, m_row.m_attr_name,
+ m_row.m_attr_name_length);
+ break;
+ case FO_ATTR_VALUE:
+ if (m_row.m_attr_value_length)
+ set_field_varchar_utf8(f, m_row.m_attr_value,
+ m_row.m_attr_value_length);
+ else
+ f->set_null();
+ break;
+ case FO_ORDINAL_POSITION:
+ set_field_ulong(f, m_row.m_ordinal_position);
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+ return 0;
+}
+
+bool
+table_session_connect::thread_fits(PFS_thread *thread)
+{
+ return true;
+}
+
diff --git a/storage/perfschema/table_session_connect.h b/storage/perfschema/table_session_connect.h
new file mode 100644
index 00000000000..097623d2c80
--- /dev/null
+++ b/storage/perfschema/table_session_connect.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 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 TABLE_SESSION_CONNECT_H
+#define TABLE_SESSION_CONNECT_H
+
+#include "pfs_column_types.h"
+#include "cursor_by_thread_connect_attr.h"
+#include "table_helper.h"
+
+#define MAX_ATTR_NAME_CHARS 32
+#define MAX_ATTR_VALUE_CHARS 1024
+#define MAX_UTF8_BYTES 6
+
+/** symbolic names for field offsets, keep in sync with field_types */
+enum field_offsets {
+ FO_PROCESS_ID,
+ FO_ATTR_NAME,
+ FO_ATTR_VALUE,
+ FO_ORDINAL_POSITION
+};
+
+/**
+ A row of PERFORMANCE_SCHEMA.SESSION_CONNECT_ATTRS and
+ PERFORMANCE_SCHEMA.SESSION_ACCOUNT_CONNECT_ATTRS.
+*/
+struct row_session_connect_attrs
+{
+ /** Column PROCESS_ID. */
+ ulong m_process_id;
+ /** Column ATTR_NAME. In UTF-8 */
+ char m_attr_name[MAX_ATTR_NAME_CHARS * MAX_UTF8_BYTES];
+ /** Length in bytes of @c m_attr_name. */
+ uint m_attr_name_length;
+ /** Column ATTR_VALUE. In UTF-8 */
+ char m_attr_value[MAX_ATTR_VALUE_CHARS * MAX_UTF8_BYTES];
+ /** Length in bytes of @c m_attr_name. */
+ uint m_attr_value_length;
+ /** Column ORDINAL_POSITION. */
+ ulong m_ordinal_position;
+};
+
+class table_session_connect : public cursor_by_thread_connect_attr
+{
+protected:
+ table_session_connect(const PFS_engine_table_share *share);
+
+public:
+ ~table_session_connect()
+ {}
+
+protected:
+ virtual void make_row(PFS_thread *pfs, uint ordinal);
+ virtual bool thread_fits(PFS_thread *thread);
+ virtual int read_row_values(TABLE *table, unsigned char *buf,
+ Field **fields, bool read_all);
+protected:
+ /** Fields definition. */
+ static TABLE_FIELD_DEF m_field_def;
+ /** Current row. */
+ row_session_connect_attrs m_row;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_session_connect_attrs.cc b/storage/perfschema/table_session_connect_attrs.cc
new file mode 100644
index 00000000000..9e1804b7294
--- /dev/null
+++ b/storage/perfschema/table_session_connect_attrs.cc
@@ -0,0 +1,43 @@
+/* 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 */
+
+#include "table_session_connect_attrs.h"
+
+THR_LOCK table_session_connect_attrs::m_table_lock;
+
+PFS_engine_table_share
+table_session_connect_attrs::m_share=
+{
+ { C_STRING_WITH_LEN("session_connect_attrs") },
+ &pfs_readonly_acl,
+ &table_session_connect_attrs::create,
+ NULL, /* write_row */
+ NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
+ 1000, /* records */
+ sizeof(pos_connect_attr_by_thread_by_attr), /* ref length */
+ &m_table_lock,
+ &m_field_def,
+ false /* checked */
+};
+
+PFS_engine_table* table_session_connect_attrs::create()
+{
+ return new table_session_connect_attrs();
+}
+
+table_session_connect_attrs::table_session_connect_attrs()
+ : table_session_connect(&m_share)
+{}
diff --git a/storage/perfschema/table_session_connect_attrs.h b/storage/perfschema/table_session_connect_attrs.h
new file mode 100644
index 00000000000..b10b106ba0d
--- /dev/null
+++ b/storage/perfschema/table_session_connect_attrs.h
@@ -0,0 +1,47 @@
+/* Copyright (c) 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 TABLE_SESSION_CONNECT_ATTRS_H
+#define TABLE_SESSION_CONNECT_ATTRS_H
+
+#include "table_session_connect.h"
+/**
+ \addtogroup Performance_schema_tables
+ @{
+*/
+
+/** Table PERFORMANCE_SCHEMA.SESSION_CONNECT_ATTRS. */
+class table_session_connect_attrs : public table_session_connect
+{
+public:
+ /** Table share */
+ static PFS_engine_table_share m_share;
+ /** Table builder */
+ static PFS_engine_table* create();
+
+protected:
+ table_session_connect_attrs();
+
+public:
+ ~table_session_connect_attrs()
+ {}
+
+private:
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_setup_actors.cc b/storage/perfschema/table_setup_actors.cc
new file mode 100644
index 00000000000..91dbb942ead
--- /dev/null
+++ b/storage/perfschema/table_setup_actors.cc
@@ -0,0 +1,279 @@
+/* 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);
+ }
+ }
+ }
+
+ if (user->length() == 0 || host->length() == 0 || role->length() == 0)
+ return HA_ERR_WRONG_COMMAND;
+
+ 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)
+{
+ DBUG_ASSERT(m_row_exists);
+
+ CHARSET_INFO *cs= &my_charset_utf8_bin;
+ String user(m_row.m_username, m_row.m_username_length, cs);
+ String role(m_row.m_rolename, m_row.m_rolename_length, cs);
+ String host(m_row.m_hostname, m_row.m_hostname_length, cs);
+
+ 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
new file mode 100644
index 00000000000..7b5441b684a
--- /dev/null
+++ b/storage/perfschema/table_setup_consumers.cc
@@ -0,0 +1,244 @@
+/* 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_setup_consumers.cc
+ Table SETUP_CONSUMERS (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "table_setup_consumers.h"
+#include "pfs_instr.h"
+#include "pfs_events_waits.h"
+#include "pfs_digest.h"
+
+#define COUNT_SETUP_CONSUMERS 12
+static row_setup_consumers all_setup_consumers_data[COUNT_SETUP_CONSUMERS]=
+{
+ {
+ { C_STRING_WITH_LEN("events_stages_current") },
+ &flag_events_stages_current,
+ false
+ },
+ {
+ { C_STRING_WITH_LEN("events_stages_history") },
+ &flag_events_stages_history,
+ false
+ },
+ {
+ { 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_statements_history") },
+ &flag_events_statements_history,
+ false
+ },
+ {
+ { C_STRING_WITH_LEN("events_statements_history_long") },
+ &flag_events_statements_history_long,
+ false
+ },
+ {
+ { C_STRING_WITH_LEN("events_waits_current") },
+ &flag_events_waits_current,
+ false
+ },
+ {
+ { C_STRING_WITH_LEN("events_waits_history") },
+ &flag_events_waits_history,
+ false
+ },
+ {
+ { 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
+ }
+};
+
+THR_LOCK table_setup_consumers::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+ {
+ { C_STRING_WITH_LEN("NAME") },
+ { C_STRING_WITH_LEN("varchar(64)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("ENABLED") },
+ { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") },
+ { NULL, 0}
+ }
+};
+
+TABLE_FIELD_DEF
+table_setup_consumers::m_field_def=
+{ 2, field_types };
+
+PFS_engine_table_share
+table_setup_consumers::m_share=
+{
+ { C_STRING_WITH_LEN("setup_consumers") },
+ &pfs_updatable_acl,
+ &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,
+ &m_field_def,
+ false /* checked */
+};
+
+PFS_engine_table* table_setup_consumers::create(void)
+{
+ return new table_setup_consumers();
+}
+
+table_setup_consumers::table_setup_consumers()
+ : PFS_engine_table(&m_share, &m_pos),
+ m_row(NULL), m_pos(0), m_next_pos(0)
+{}
+
+void table_setup_consumers::reset_position(void)
+{
+ m_pos.m_index= 0;
+ m_next_pos.m_index= 0;
+}
+
+int table_setup_consumers::rnd_next(void)
+{
+ int result;
+
+ m_pos.set_at(&m_next_pos);
+
+ if (m_pos.m_index < COUNT_SETUP_CONSUMERS)
+ {
+ m_row= &all_setup_consumers_data[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_setup_consumers::rnd_pos(const void *pos)
+{
+ set_position(pos);
+ DBUG_ASSERT(m_pos.m_index < COUNT_SETUP_CONSUMERS);
+ m_row= &all_setup_consumers_data[m_pos.m_index];
+ return 0;
+}
+
+int table_setup_consumers::read_row_values(TABLE *table,
+ unsigned char *,
+ Field **fields,
+ bool read_all)
+{
+ Field *f;
+
+ DBUG_ASSERT(m_row);
+
+
+ /* 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 */
+ set_field_varchar_utf8(f, m_row->m_name.str, m_row->m_name.length);
+ break;
+ case 1: /* ENABLED */
+ set_field_enum(f, (*m_row->m_enabled_ptr) ? ENUM_YES : ENUM_NO);
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int table_setup_consumers::update_row_values(TABLE *table,
+ const unsigned char *,
+ unsigned char *,
+ Field **fields)
+{
+ Field *f;
+ enum_yes_no value;
+
+ DBUG_ASSERT(m_row);
+
+ for (; (f= *fields) ; fields++)
+ {
+ if (bitmap_is_set(table->write_set, f->field_index))
+ {
+ switch(f->field_index)
+ {
+ case 0: /* NAME */
+ 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;
+ break;
+ }
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+
+ 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
new file mode 100644
index 00000000000..bc7e9d553bb
--- /dev/null
+++ b/storage/perfschema/table_setup_consumers.h
@@ -0,0 +1,87 @@
+/* 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_CONSUMERS_H
+#define TABLE_SETUP_CONSUMERS_H
+
+/**
+ @file storage/perfschema/table_setup_consumers.h
+ Table SETUP_CONSUMERS (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+
+/**
+ @addtogroup Performance_schema_tables
+ @{
+*/
+
+/** A row of PERFORMANCE_SCHEMA.SETUP_CONSUMERS. */
+struct row_setup_consumers
+{
+ /** Column NAME. */
+ LEX_STRING m_name;
+ /** Column ENABLED. */
+ bool *m_enabled_ptr;
+ /** Hidden column, refresh. */
+ bool m_refresh;
+};
+
+/** Table PERFORMANCE_SCHEMA.SETUP_CONSUMERS. */
+class table_setup_consumers : 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);
+
+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);
+
+ table_setup_consumers();
+
+public:
+ ~table_setup_consumers()
+ {}
+
+private:
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+ /** Fields definition. */
+ static TABLE_FIELD_DEF m_field_def;
+
+ /** Current row. */
+ row_setup_consumers *m_row;
+ /** Current position. */
+ PFS_simple_index m_pos;
+ /** Next position. */
+ PFS_simple_index m_next_pos;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_setup_instruments.cc b/storage/perfschema/table_setup_instruments.cc
new file mode 100644
index 00000000000..31e2adb0f62
--- /dev/null
+++ b/storage/perfschema/table_setup_instruments.cc
@@ -0,0 +1,306 @@
+/* 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_setup_instruments.cc
+ Table SETUP_INSTRUMENTS (implementation).
+*/
+
+#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;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+ {
+ { C_STRING_WITH_LEN("NAME") },
+ { C_STRING_WITH_LEN("varchar(128)") },
+ { 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_instruments::m_field_def=
+{ 3, field_types };
+
+PFS_engine_table_share
+table_setup_instruments::m_share=
+{
+ { C_STRING_WITH_LEN("setup_instruments") },
+ &pfs_updatable_acl,
+ &table_setup_instruments::create,
+ NULL, /* write_row */
+ NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
+ 1000, /* records */
+ sizeof(pos_setup_instruments),
+ &m_table_lock,
+ &m_field_def,
+ false /* checked */
+};
+
+PFS_engine_table* table_setup_instruments::create(void)
+{
+ return new table_setup_instruments();
+}
+
+table_setup_instruments::table_setup_instruments()
+ : PFS_engine_table(&m_share, &m_pos),
+ m_pos(), m_next_pos()
+{}
+
+void table_setup_instruments::reset_position(void)
+{
+ m_pos.reset();
+ m_next_pos.reset();
+}
+
+int table_setup_instruments::rnd_next(void)
+{
+ 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)
+ {
+ case pos_setup_instruments::VIEW_MUTEX:
+ instr_class= find_mutex_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_RWLOCK:
+ instr_class= find_rwlock_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_COND:
+ instr_class= find_cond_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_THREAD:
+ /* Not used yet */
+ break;
+ case pos_setup_instruments::VIEW_FILE:
+ 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;
+}
+
+int table_setup_instruments::rnd_pos(const void *pos)
+{
+ 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)
+ {
+ case pos_setup_instruments::VIEW_MUTEX:
+ instr_class= find_mutex_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_RWLOCK:
+ instr_class= find_rwlock_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_COND:
+ instr_class= find_cond_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_THREAD:
+ /* Not used yet */
+ break;
+ case pos_setup_instruments::VIEW_FILE:
+ 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_instr_class= klass;
+}
+
+int table_setup_instruments::read_row_values(TABLE *table,
+ unsigned char *,
+ Field **fields,
+ bool read_all)
+{
+ Field *f;
+
+ 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_instr_class->m_name, m_row.m_instr_class->m_name_length);
+ break;
+ case 1: /* ENABLED */
+ set_field_enum(f, m_row.m_instr_class->m_enabled ? ENUM_YES : ENUM_NO);
+ break;
+ case 2: /* TIMED */
+ set_field_enum(f, m_row.m_instr_class->m_timed ? ENUM_YES : ENUM_NO);
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int table_setup_instruments::update_row_values(TABLE *table,
+ const unsigned char *,
+ unsigned char *,
+ 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: /* NAME */
+ return HA_ERR_WRONG_COMMAND;
+ case 1: /* ENABLED */
+ value= (enum_yes_no) get_field_enum(f);
+ m_row.m_instr_class->m_enabled= (value == ENUM_YES) ? true : false;
+ break;
+ case 2: /* TIMED */
+ 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);
+ }
+ }
+ }
+
+ 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
new file mode 100644
index 00000000000..cb4c6a06de1
--- /dev/null
+++ b/storage/perfschema/table_setup_instruments.h
@@ -0,0 +1,121 @@
+/* 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_SETUP_INSTRUMENTS_H
+#define TABLE_SETUP_INSTRUMENTS_H
+
+/**
+ @file storage/perfschema/table_setup_instruments.h
+ Table SETUP_INSTRUMENTS (declarations).
+*/
+
+#include "pfs_instr_class.h"
+#include "pfs_engine_table.h"
+
+/**
+ @addtogroup Performance_schema_tables
+ @{
+*/
+
+/** A row of PERFORMANCE_SCHEMA.SETUP_INSTRUMENTS. */
+struct row_setup_instruments
+{
+ /** 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;
+ 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(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.SETUP_INSTRUMENTS. */
+class table_setup_instruments : 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);
+
+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);
+
+ table_setup_instruments();
+
+public:
+ ~table_setup_instruments()
+ {}
+
+private:
+ void make_row(PFS_instr_class *klass);
+
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+ /** Fields definition. */
+ static TABLE_FIELD_DEF m_field_def;
+
+ /** Current row. */
+ row_setup_instruments m_row;
+ /** Current position. */
+ pos_setup_instruments m_pos;
+ /** Next position. */
+ pos_setup_instruments m_next_pos;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_setup_objects.cc b/storage/perfschema/table_setup_objects.cc
new file mode 100644
index 00000000000..11fab913ac4
--- /dev/null
+++ b/storage/perfschema/table_setup_objects.cc
@@ -0,0 +1,355 @@
+/* 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)
+{
+ DBUG_ASSERT(m_row_exists);
+
+ CHARSET_INFO *cs= &my_charset_utf8_bin;
+ enum_object_type object_type= OBJECT_TYPE_TABLE;
+ String object_schema(m_row.m_schema_name, m_row.m_schema_name_length, cs);
+ String object_name(m_row.m_object_name, m_row.m_object_name_length, cs);
+
+ int 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
new file mode 100644
index 00000000000..a6a8a52b7e5
--- /dev/null
+++ b/storage/perfschema/table_setup_timers.cc
@@ -0,0 +1,197 @@
+/* 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_setup_timers.cc
+ Table SETUP_TIMERS (implementation).
+*/
+
+#include "my_global.h"
+#include "my_pthread.h"
+#include "table_setup_timers.h"
+#include "pfs_column_values.h"
+#include "pfs_timer.h"
+
+#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
+ }
+};
+
+THR_LOCK table_setup_timers::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+ {
+ { C_STRING_WITH_LEN("NAME") },
+ { C_STRING_WITH_LEN("varchar(64)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("TIMER_NAME") },
+ { C_STRING_WITH_LEN("enum(\'CYCLE\',\'NANOSECOND\',\'MICROSECOND\',"
+ "\'MILLISECOND\',\'TICK\')") },
+ { NULL, 0}
+ }
+};
+
+TABLE_FIELD_DEF
+table_setup_timers::m_field_def=
+{ 2, field_types };
+
+PFS_engine_table_share
+table_setup_timers::m_share=
+{
+ { C_STRING_WITH_LEN("setup_timers") },
+ &pfs_updatable_acl,
+ &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,
+ &m_field_def,
+ false /* checked */
+};
+
+PFS_engine_table* table_setup_timers::create(void)
+{
+ return new table_setup_timers();
+}
+
+table_setup_timers::table_setup_timers()
+ : PFS_engine_table(&m_share, &m_pos),
+ m_row(NULL), m_pos(0), m_next_pos(0)
+{}
+
+void table_setup_timers::reset_position(void)
+{
+ m_pos.m_index= 0;
+ m_next_pos.m_index= 0;
+}
+
+int table_setup_timers::rnd_next(void)
+{
+ int result;
+
+ m_pos.set_at(&m_next_pos);
+
+ if (m_pos.m_index < COUNT_SETUP_TIMERS)
+ {
+ m_row= &all_setup_timers_data[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_setup_timers::rnd_pos(const void *pos)
+{
+ set_position(pos);
+ DBUG_ASSERT(m_pos.m_index < COUNT_SETUP_TIMERS);
+ m_row= &all_setup_timers_data[m_pos.m_index];
+ return 0;
+}
+
+int table_setup_timers::read_row_values(TABLE *table,
+ unsigned char *,
+ Field **fields,
+ bool read_all)
+{
+ Field *f;
+
+ DBUG_ASSERT(m_row);
+
+ /* 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 */
+ set_field_varchar_utf8(f, m_row->m_name.str, m_row->m_name.length);
+ break;
+ case 1: /* TIMER_NAME */
+ set_field_enum(f, *(m_row->m_timer_name_ptr));
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int table_setup_timers::update_row_values(TABLE *table,
+ const unsigned char *,
+ unsigned char *,
+ Field **fields)
+{
+ Field *f;
+ longlong value;
+
+ DBUG_ASSERT(m_row);
+
+ for (; (f= *fields) ; fields++)
+ {
+ if (bitmap_is_set(table->write_set, f->field_index))
+ {
+ switch(f->field_index)
+ {
+ case 0: /* NAME */
+ return HA_ERR_WRONG_COMMAND;
+ case 1: /* TIMER_NAME */
+ value= get_field_enum(f);
+ if ((value >= FIRST_TIMER_NAME) && (value <= LAST_TIMER_NAME))
+ *(m_row->m_timer_name_ptr)= (enum_timer_name) value;
+ else
+ return HA_ERR_WRONG_COMMAND;
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/storage/perfschema/table_setup_timers.h b/storage/perfschema/table_setup_timers.h
new file mode 100644
index 00000000000..a81e6fefaaf
--- /dev/null
+++ b/storage/perfschema/table_setup_timers.h
@@ -0,0 +1,85 @@
+/* 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_TIMERS_H
+#define TABLE_SETUP_TIMERS_H
+
+/**
+ @file storage/perfschema/table_setup_timers.h
+ Table SETUP_TIMERS (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+
+/**
+ @addtogroup Performance_schema_tables
+ @{
+*/
+
+/** A row of table PERFORMANCE_SCHEMA.SETUP_TIMERS. */
+struct row_setup_timers
+{
+ /** Column NAME. */
+ LEX_STRING m_name;
+ /** Column TIMER_NAME. */
+ enum_timer_name *m_timer_name_ptr;
+};
+
+/** Table PERFORMANCE_SCHEMA.SETUP_TIMERS. */
+class table_setup_timers : 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);
+
+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);
+
+ table_setup_timers();
+
+public:
+ ~table_setup_timers()
+ {}
+
+private:
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+ /** Fields definition. */
+ static TABLE_FIELD_DEF m_field_def;
+
+ /** Current row. */
+ row_setup_timers *m_row;
+ /** Current position. */
+ PFS_simple_index m_pos;
+ /** Next position. */
+ PFS_simple_index m_next_pos;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_socket_instances.cc b/storage/perfschema/table_socket_instances.cc
new file mode 100644
index 00000000000..0fa1d2b1a3a
--- /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("bigint(20)") },
+ { 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_ulonglong(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..080f11c1ba8
--- /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 */
+ ulonglong 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
new file mode 100644
index 00000000000..4d7c48efdc1
--- /dev/null
+++ b/storage/perfschema/table_sync_instances.cc
@@ -0,0 +1,511 @@
+/* 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_sync_instances.cc
+ Table MUTEX_INSTANCES, RWLOCK_INSTANCES
+ and COND_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_sync_instances.h"
+#include "pfs_global.h"
+
+THR_LOCK table_mutex_instances::m_table_lock;
+
+static const TABLE_FIELD_TYPE mutex_field_types[]=
+{
+ {
+ { C_STRING_WITH_LEN("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("LOCKED_BY_THREAD_ID") },
+ { C_STRING_WITH_LEN("bigint(20)") },
+ { NULL, 0}
+ }
+};
+
+TABLE_FIELD_DEF
+table_mutex_instances::m_field_def=
+{ 3, mutex_field_types };
+
+PFS_engine_table_share
+table_mutex_instances::m_share=
+{
+ { C_STRING_WITH_LEN("mutex_instances") },
+ &pfs_readonly_acl,
+ &table_mutex_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_mutex_instances::create(void)
+{
+ return new table_mutex_instances();
+}
+
+table_mutex_instances::table_mutex_instances()
+ : PFS_engine_table(&m_share, &m_pos),
+ m_row_exists(false), m_pos(0), m_next_pos(0)
+{}
+
+void table_mutex_instances::reset_position(void)
+{
+ m_pos.m_index= 0;
+ m_next_pos.m_index= 0;
+}
+
+int table_mutex_instances::rnd_next(void)
+{
+ PFS_mutex *pfs;
+
+ for (m_pos.set_at(&m_next_pos); m_pos.m_index < mutex_max; m_pos.next())
+ {
+ pfs= &mutex_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_mutex_instances::rnd_pos(const void *pos)
+{
+ PFS_mutex *pfs;
+
+ set_position(pos);
+ DBUG_ASSERT(m_pos.m_index < mutex_max);
+ pfs= &mutex_array[m_pos.m_index];
+ if (pfs->m_lock.is_populated())
+ {
+ make_row(pfs);
+ return 0;
+ }
+
+ return HA_ERR_RECORD_DELETED;
+}
+
+void table_mutex_instances::make_row(PFS_mutex *pfs)
+{
+ pfs_lock lock;
+ PFS_mutex_class *safe_class;
+
+ m_row_exists= false;
+
+ /* Protect this reader against a mutex destroy */
+ pfs->m_lock.begin_optimistic_lock(&lock);
+
+ safe_class= sanitize_mutex_class(pfs->m_class);
+ if (unlikely(safe_class == NULL))
+ return;
+
+ m_row.m_name= safe_class->m_name;
+ m_row.m_name_length= safe_class->m_name_length;
+ m_row.m_identity= pfs->m_identity;
+
+ /* Protect this reader against a mutex unlock */
+ PFS_thread *safe_owner= sanitize_thread(pfs->m_owner);
+ if (safe_owner)
+ {
+ m_row.m_locked_by_thread_id= safe_owner->m_thread_internal_id;
+ m_row.m_locked= true;
+ }
+ else
+ m_row.m_locked= false;
+
+ if (pfs->m_lock.end_optimistic_lock(&lock))
+ m_row_exists= true;
+}
+
+int table_mutex_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: /* NAME */
+ set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
+ break;
+ case 1: /* OBJECT_INSTANCE */
+ set_field_ulonglong(f, (intptr) m_row.m_identity);
+ break;
+ case 2: /* LOCKED_BY_THREAD_ID */
+ if (m_row.m_locked)
+ set_field_ulonglong(f, m_row.m_locked_by_thread_id);
+ else
+ f->set_null();
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+
+ return 0;
+}
+
+THR_LOCK table_rwlock_instances::m_table_lock;
+
+static const TABLE_FIELD_TYPE rwlock_field_types[]=
+{
+ {
+ { C_STRING_WITH_LEN("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("WRITE_LOCKED_BY_THREAD_ID") },
+ { C_STRING_WITH_LEN("bigint(20)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("READ_LOCKED_BY_COUNT") },
+ { C_STRING_WITH_LEN("int(10)") },
+ { NULL, 0}
+ }
+};
+
+TABLE_FIELD_DEF
+table_rwlock_instances::m_field_def=
+{ 4, rwlock_field_types };
+
+PFS_engine_table_share
+table_rwlock_instances::m_share=
+{
+ { C_STRING_WITH_LEN("rwlock_instances") },
+ &pfs_readonly_acl,
+ &table_rwlock_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_rwlock_instances::create(void)
+{
+ return new table_rwlock_instances();
+}
+
+table_rwlock_instances::table_rwlock_instances()
+ : PFS_engine_table(&m_share, &m_pos),
+ m_row_exists(false), m_pos(0), m_next_pos(0)
+{}
+
+void table_rwlock_instances::reset_position(void)
+{
+ m_pos.m_index= 0;
+ m_next_pos.m_index= 0;
+}
+
+int table_rwlock_instances::rnd_next(void)
+{
+ PFS_rwlock *pfs;
+
+ for (m_pos.set_at(&m_next_pos); m_pos.m_index < rwlock_max; m_pos.next())
+ {
+ pfs= &rwlock_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_rwlock_instances::rnd_pos(const void *pos)
+{
+ PFS_rwlock *pfs;
+
+ set_position(pos);
+ DBUG_ASSERT(m_pos.m_index < rwlock_max);
+ pfs= &rwlock_array[m_pos.m_index];
+ if (pfs->m_lock.is_populated())
+ {
+ make_row(pfs);
+ return 0;
+ }
+
+ return HA_ERR_RECORD_DELETED;
+}
+
+void table_rwlock_instances::make_row(PFS_rwlock *pfs)
+{
+ pfs_lock lock;
+ PFS_rwlock_class *safe_class;
+
+ m_row_exists= false;
+
+ /* Protect this reader against a rwlock destroy */
+ pfs->m_lock.begin_optimistic_lock(&lock);
+
+ safe_class= sanitize_rwlock_class(pfs->m_class);
+ if (unlikely(safe_class == NULL))
+ return;
+
+ m_row.m_name= safe_class->m_name;
+ m_row.m_name_length= safe_class->m_name_length;
+ m_row.m_identity= pfs->m_identity;
+
+ /* Protect this reader against a rwlock unlock in the writer */
+ PFS_thread *safe_writer= sanitize_thread(pfs->m_writer);
+ if (safe_writer)
+ {
+ m_row.m_write_locked_by_thread_id= safe_writer->m_thread_internal_id;
+ m_row.m_readers= 0;
+ m_row.m_write_locked= true;
+ }
+ else
+ {
+ m_row.m_readers= pfs->m_readers;
+ m_row.m_write_locked= false;
+ }
+
+ if (pfs->m_lock.end_optimistic_lock(&lock))
+ m_row_exists= true;
+}
+
+int table_rwlock_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: /* NAME */
+ set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
+ break;
+ case 1: /* OBJECT_INSTANCE */
+ set_field_ulonglong(f, (intptr) m_row.m_identity);
+ break;
+ case 2: /* WRITE_LOCKED_BY_THREAD_ID */
+ if (m_row.m_write_locked)
+ set_field_ulonglong(f, m_row.m_write_locked_by_thread_id);
+ else
+ f->set_null();
+ break;
+ case 3: /* READ_LOCKED_BY_COUNT */
+ set_field_ulong(f, m_row.m_readers);
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+
+ return 0;
+}
+
+THR_LOCK table_cond_instances::m_table_lock;
+
+static const TABLE_FIELD_TYPE cond_field_types[]=
+{
+ {
+ { C_STRING_WITH_LEN("NAME") },
+ { C_STRING_WITH_LEN("varchar(128)") },
+ { NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("OBJECT_INSTANCE_BEGIN") },
+ { C_STRING_WITH_LEN("bigint(20)") },
+ { NULL, 0}
+ }
+};
+
+TABLE_FIELD_DEF
+table_cond_instances::m_field_def=
+{ 2, cond_field_types };
+
+PFS_engine_table_share
+table_cond_instances::m_share=
+{
+ { C_STRING_WITH_LEN("cond_instances") },
+ &pfs_readonly_acl,
+ &table_cond_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_cond_instances::create(void)
+{
+ return new table_cond_instances();
+}
+
+table_cond_instances::table_cond_instances()
+ : PFS_engine_table(&m_share, &m_pos),
+ m_row_exists(false), m_pos(0), m_next_pos(0)
+{}
+
+void table_cond_instances::reset_position(void)
+{
+ m_pos.m_index= 0;
+ m_next_pos.m_index= 0;
+}
+
+int table_cond_instances::rnd_next(void)
+{
+ PFS_cond *pfs;
+
+ for (m_pos.set_at(&m_next_pos); m_pos.m_index < cond_max; m_pos.next())
+ {
+ pfs= &cond_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_cond_instances::rnd_pos(const void *pos)
+{
+ PFS_cond *pfs;
+
+ set_position(pos);
+ DBUG_ASSERT(m_pos.m_index < cond_max);
+ pfs= &cond_array[m_pos.m_index];
+ if (pfs->m_lock.is_populated())
+ {
+ make_row(pfs);
+ return 0;
+ }
+
+ return HA_ERR_RECORD_DELETED;
+}
+
+void table_cond_instances::make_row(PFS_cond *pfs)
+{
+ pfs_lock lock;
+ PFS_cond_class *safe_class;
+
+ m_row_exists= false;
+
+ /* Protect this reader against a cond destroy */
+ pfs->m_lock.begin_optimistic_lock(&lock);
+
+ safe_class= sanitize_cond_class(pfs->m_class);
+ if (unlikely(safe_class == NULL))
+ return;
+
+ m_row.m_name= safe_class->m_name;
+ m_row.m_name_length= safe_class->m_name_length;
+ m_row.m_identity= pfs->m_identity;
+
+ if (pfs->m_lock.end_optimistic_lock(&lock))
+ m_row_exists= true;
+}
+
+int table_cond_instances::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 */
+ set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
+ break;
+ case 1: /* OBJECT_INSTANCE */
+ set_field_ulonglong(f, (intptr) m_row.m_identity);
+ break;
+ default:
+ DBUG_ASSERT(false);
+ }
+ }
+ }
+
+ return 0;
+}
+
diff --git a/storage/perfschema/table_sync_instances.h b/storage/perfschema/table_sync_instances.h
new file mode 100644
index 00000000000..ff7b2765a11
--- /dev/null
+++ b/storage/perfschema/table_sync_instances.h
@@ -0,0 +1,206 @@
+/* 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_SYNC_INSTANCE_H
+#define TABLE_SYNC_INSTANCE_H
+
+/**
+ @file storage/perfschema/table_sync_instances.h
+ Table MUTEX_INSTANCES, RWLOCK_INSTANCES and COND_INSTANCES (declarations).
+*/
+
+#include "pfs_column_types.h"
+#include "pfs_engine_table.h"
+
+struct PFS_mutex;
+struct PFS_rwlock;
+struct PFS_cond;
+
+/**
+ @addtogroup Performance_schema_tables
+ @{
+*/
+
+/** A row of table PERFORMANCE_SCHEMA.MUTEX_INSTANCES. */
+struct row_mutex_instances
+{
+ /** Column NAME. */
+ const char *m_name;
+ /** Length in bytes of @c m_name. */
+ uint m_name_length;
+ /** Column OBJECT_INSTANCE_BEGIN. */
+ const void *m_identity;
+ /** True if column LOCKED_BY_THREAD_ID is not null. */
+ bool m_locked;
+ /** Column LOCKED_BY_THREAD_ID. */
+ ulonglong m_locked_by_thread_id;
+};
+
+/** Table PERFORMANCE_SCHEMA.MUTEX_INSTANCES. */
+class table_mutex_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_mutex_instances();
+
+public:
+ ~table_mutex_instances()
+ {}
+
+private:
+ void make_row(PFS_mutex *pfs);
+
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+ /** Fields definition. */
+ static TABLE_FIELD_DEF m_field_def;
+
+ /** Current row. */
+ row_mutex_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;
+};
+
+/** A row of table PERFORMANCE_SCHEMA.RWLOCK_INSTANCES. */
+struct row_rwlock_instances
+{
+ /** Column NAME. */
+ const char *m_name;
+ /** Length in bytes of @c m_name. */
+ uint m_name_length;
+ /** Column OBJECT_INSTANCE_BEGIN. */
+ const void *m_identity;
+ /** True if column WRITE_LOCKED_BY_THREAD_ID is not null. */
+ bool m_write_locked;
+ /** Column WRITE_LOCKED_BY_THREAD_ID. */
+ ulonglong m_write_locked_by_thread_id;
+ /** Column READ_LOCKED_BY_COUNT. */
+ ulong m_readers;
+};
+
+/** Table PERFORMANCE_SCHEMA.RWLOCK_INSTANCES. */
+class table_rwlock_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_rwlock_instances();
+
+public:
+ ~table_rwlock_instances()
+ {}
+
+private:
+ void make_row(PFS_rwlock *pfs);
+
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+ /** Fields definition. */
+ static TABLE_FIELD_DEF m_field_def;
+
+ /** Current row. */
+ row_rwlock_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;
+};
+
+/** A row of table PERFORMANCE_SCHEMA.COND_INSTANCES. */
+struct row_cond_instances
+{
+ /** Column NAME. */
+ const char *m_name;
+ /** Length in bytes of @c m_name. */
+ uint m_name_length;
+ /** Column OBJECT_INSTANCE_BEGIN. */
+ const void *m_identity;
+};
+
+/** Table PERFORMANCE_SCHEMA.COND_INSTANCES. */
+class table_cond_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_cond_instances();
+
+public:
+ ~table_cond_instances()
+ {}
+
+private:
+ void make_row(PFS_cond *pfs);
+
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+ /** Fields definition. */
+ static TABLE_FIELD_DEF m_field_def;
+
+ /** Current row. */
+ row_cond_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_threads.cc b/storage/perfschema/table_threads.cc
new file mode 100644
index 00000000000..b1ec2ad754e
--- /dev/null
+++ b/storage/perfschema/table_threads.cc
@@ -0,0 +1,350 @@
+/* Copyright (c) 2008, 2013, 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_threads.h"
+#include "sql_parse.h"
+#include "pfs_instr_class.h"
+#include "pfs_instr.h"
+
+THR_LOCK table_threads::m_table_lock;
+
+static const TABLE_FIELD_TYPE field_types[]=
+{
+ {
+ { C_STRING_WITH_LEN("THREAD_ID") },
+ { C_STRING_WITH_LEN("bigint(20)") },
+ { 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("bigint(20)") },
+ { NULL, 0}
+ },
+ {
+ { 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("bigint(20)") },
+ { 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=
+{ 14, field_types };
+
+PFS_engine_table_share
+table_threads::m_share=
+{
+ { C_STRING_WITH_LEN("threads") },
+ &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,
+ &m_field_def,
+ false /* checked */
+};
+
+PFS_engine_table* table_threads::create()
+{
+ return new table_threads();
+}
+
+table_threads::table_threads()
+ : cursor_by_thread(& m_share),
+ m_row_exists(false)
+{}
+
+void table_threads::make_row(PFS_thread *pfs)
+{
+ pfs_lock lock;
+ pfs_lock processlist_lock;
+ PFS_thread_class *safe_class;
+
+ m_row_exists= false;
+
+ /* Protect this reader against thread termination */
+ pfs->m_lock.begin_optimistic_lock(&lock);
+
+ safe_class= sanitize_thread_class(pfs->m_class);
+ if (unlikely(safe_class == NULL))
+ 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_processlist_id= pfs->m_processlist_id;
+ m_row.m_name= safe_class->m_name;
+ m_row.m_name_length= safe_class->m_name_length;
+
+ 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;
+
+ /* Protect this reader against attribute changes. */
+ pfs->m_processlist_lock.begin_optimistic_lock(&processlist_lock);
+
+ /* 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;
+
+ if (! pfs->m_processlist_lock.end_optimistic_lock(& processlist_lock))
+ {
+ /*
+ Columns PROCESSLIST_STATE or PROCESSLIST_INFO are being
+ updated while we read them, and are unsafe to use.
+ Do not discard the entire row.
+ Do not loop waiting for a stable value.
+ Just return NULL values for these columns.
+ */
+ m_row.m_processlist_state_length= 0;
+ m_row.m_processlist_info_length= 0;
+ }
+
+ m_row.m_enabled_ptr= &pfs->m_enabled;
+
+ if (pfs->m_lock.end_optimistic_lock(& lock))
+ m_row_exists= true;
+}
+
+int table_threads::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 == 2);
+ buf[0]= 0;
+ buf[1]= 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_ulonglong(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: /* TYPE */
+ if (m_row.m_processlist_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_processlist_id != 0)
+ set_field_ulonglong(f, m_row.m_processlist_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_processlist_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_ulonglong(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);
+ }
+ }
+ }
+ return 0;
+}
+
diff --git a/storage/perfschema/table_threads.h b/storage/perfschema/table_threads.h
new file mode 100644
index 00000000000..bce45c0cbce
--- /dev/null
+++ b/storage/perfschema/table_threads.h
@@ -0,0 +1,115 @@
+/* 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_THREADS_H
+#define TABLE_THREADS_H
+
+#include "pfs_column_types.h"
+#include "cursor_by_thread.h"
+
+struct PFS_thread;
+
+/**
+ \addtogroup Performance_schema_tables
+ @{
+*/
+
+/**
+ A row of PERFORMANCE_SCHEMA.THREADS.
+*/
+struct row_threads
+{
+ /** Column THREAD_ID. */
+ ulonglong m_thread_internal_id;
+ /** Column PROCESSLIST_ID. */
+ ulonglong m_processlist_id;
+ /** Column 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. */
+ ulonglong m_parent_thread_internal_id;
+};
+
+/** Table PERFORMANCE_SCHEMA.THREADS. */
+class table_threads : public cursor_by_thread
+{
+public:
+ /** Table share */
+ static PFS_engine_table_share m_share;
+ /** Table builder */
+ static PFS_engine_table* create();
+
+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();
+
+public:
+ ~table_threads()
+ {}
+
+private:
+ virtual void make_row(PFS_thread *pfs);
+
+ /** Table share lock. */
+ static THR_LOCK m_table_lock;
+ /** Fields definition. */
+ static TABLE_FIELD_DEF m_field_def;
+
+ /** Current row. */
+ row_threads m_row;
+ /** True if the current row exists. */
+ bool m_row_exists;
+};
+
+/** @} */
+#endif
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..71455793516
--- /dev/null
+++ b/storage/perfschema/table_tiws_by_index_usage.cc
@@ -0,0 +1,499 @@
+/* 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())
+ {
+ uint safe_key_count= sanitize_index_count(table_share->m_key_count);
+ if (m_pos.m_index_2 < safe_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_INDEXES)
+ {
+ m_pos.m_index_2= MAX_INDEXES;
+ 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())
+ {
+ uint safe_key_count= sanitize_index_count(table_share->m_key_count);
+ if (m_pos.m_index_2 < safe_key_count)
+ {
+ make_row(table_share, m_pos.m_index_2);
+ return 0;
+ }
+ if (m_pos.m_index_2 == MAX_INDEXES)
+ {
+ 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
new file mode 100644
index 00000000000..47539ffd211
--- /dev/null
+++ b/storage/perfschema/unittest/CMakeLists.txt
@@ -0,0 +1,70 @@
+# Copyright (c) 2009, 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, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/include/mysql
+ ${CMAKE_SOURCE_DIR}/regex
+ ${CMAKE_SOURCE_DIR}/sql
+ ${SSL_INCLUDE_DIRS}
+ ${CMAKE_SOURCE_DIR}/unittest/mytap
+ ${CMAKE_SOURCE_DIR}/storage/perfschema)
+
+ADD_DEFINITIONS(-DMYSQL_SERVER ${SSL_DEFINES})
+
+MACRO (PFS_ADD_TEST name)
+ ADD_EXECUTABLE(${name}-t ${name}-t.cc)
+ TARGET_LINK_LIBRARIES(${name}-t mytap perfschema mysys)
+ ADD_TEST(${name} ${name}-t)
+ENDMACRO()
+
+SET(tests
+ pfs_instr_class
+ pfs_instr_class-oom
+ pfs_instr
+ pfs_instr-oom
+ pfs_account-oom
+ pfs_host-oom
+ pfs_user-oom
+ pfs
+)
+FOREACH(testname ${tests})
+ PFS_ADD_TEST(${testname})
+ENDFOREACH()
+
+IF(WIN32)
+ SET(MYSQLD_EXTRA_SOURCES ${CMAKE_SOURCE_DIR}/sql/nt_servc.cc)
+ENDIF()
+
+# We need the server libs to test the blob parser.
+# Add sql_builtin.cc here, to force linkage of plugins below.
+# Also add mysys/string.c (see Bug#45488)
+ADD_EXECUTABLE(pfs_connect_attr-t
+ pfs_connect_attr-t.cc
+ ${CMAKE_BINARY_DIR}/sql/sql_builtin.cc
+ ${CMAKE_SOURCE_DIR}/mysys/string.c
+ ${MYSQLD_EXTRA_SOURCES}
+)
+ADD_DEPENDENCIES(pfs_connect_attr-t GenServerSource)
+TARGET_LINK_LIBRARIES(pfs_connect_attr-t mytap perfschema)
+# We need to explicitly link in everything referenced in sql/sql_builtin.cc
+TARGET_LINK_LIBRARIES(pfs_connect_attr-t ${MYSQLD_STATIC_PLUGIN_LIBS})
+TARGET_LINK_LIBRARIES(pfs_connect_attr-t sql binlog rpl master slave sql)
+TARGET_LINK_LIBRARIES(pfs_connect_attr-t mysys mysys_ssl)
+TARGET_LINK_LIBRARIES(pfs_connect_attr-t vio ${SSL_LIBRARIES})
+TARGET_LINK_LIBRARIES(pfs_connect_attr-t strings dbug regex mysys zlib)
+ADD_TEST(pfs_connect_attr pfs_connect_attr-t)
+
+# On windows, pfs_connect_attr-t may depend on openssl dlls.
+COPY_OPENSSL_DLLS(copy_openssl_pfs_unittest)
diff --git a/storage/perfschema/unittest/conf.txt b/storage/perfschema/unittest/conf.txt
new file mode 100644
index 00000000000..8afd0b4dca7
--- /dev/null
+++ b/storage/perfschema/unittest/conf.txt
@@ -0,0 +1,420 @@
+# 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
+# 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
+
+Performance schema test configurations.
+(Used internally for performance testing)
+
+Configuration PERFSCHEMA-COMPILED-OUT
+=====================================
+
+Description
+-----------
+
+Reference for timings, server built without the performance schema.
+
+Compiling options
+-----------------
+
+./configure --without-perfschema
+
+Server start options
+--------------------
+
+N/A
+
+Configuration
+-------------
+
+N/A
+
+Pre-test queries
+----------------
+
+select version();
+
+This is just to make sure the build is not including the performance schema.
+
+Post-test queries
+-----------------
+
+N/A
+
+Configuration PERFSCHEMA-DISABLED
+=================================
+
+Description
+-----------
+
+Server built with the performance schema,
+but the performance schema is disabled at startup.
+
+Compiling options
+-----------------
+
+./configure --with-perfschema
+
+Server start options
+--------------------
+
+./mysqld --disable-performance-schema
+
+Configuration
+-------------
+
+N/A
+
+Pre-test queries
+----------------
+
+select version();
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+select * from performance_schema.PERFORMANCE_TIMERS;
+select * from performance_schema.SETUP_CONSUMERS;
+select * from performance_schema.SETUP_INSTRUMENTS;
+select * from performance_schema.SETUP_TIMERS;
+
+Post-test queries
+-----------------
+
+N/A
+
+Configuration PERFSCHEMA-ENABLED-STANDBY
+========================================
+
+Description
+-----------
+
+Server built with the performance schema.
+The performance schema is enabled at startup,
+but configured to not record anything.
+This is a "stanby" configuration, in the sense that the DBA can add
+dynamically more setup options later to get data.
+
+Compiling options
+-----------------
+
+./configure --with-perfschema
+
+Server start options
+--------------------
+
+./mysqld --enable-performance-schema
+
+Configuration
+-------------
+
+UPDATE performance_schema.SETUP_INSTRUMENTS
+ set enabled='NO', timed='NO';
+
+UPDATE performance_schema.SETUP_CONSUMERS
+ set enabled='NO';
+
+Pre-test queries
+----------------
+
+select version();
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+select * from performance_schema.PERFORMANCE_TIMERS;
+select * from performance_schema.SETUP_CONSUMERS;
+select * from performance_schema.SETUP_INSTRUMENTS;
+select * from performance_schema.SETUP_TIMERS;
+
+Post-test queries
+-----------------
+
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+
+Configuration PERFSCHEMA-ENABLED-CURRENT
+========================================
+
+Description
+-----------
+
+Server built with the performance schema.
+The performance schema is enabled at startup.
+All instruments are enabled but not timed,
+and only one consumer (EVENTS_WAITS_CURRENT) is set.
+
+Compiling options
+-----------------
+
+./configure --with-perfschema
+
+Server start options
+--------------------
+
+./mysqld --enable-performance-schema
+
+Configuration
+-------------
+
+UPDATE performance_schema.SETUP_INSTRUMENTS
+ set enabled='YES', timed='NO';
+
+UPDATE performance_schema.SETUP_CONSUMERS
+ set enabled='NO';
+
+UPDATE performance_schema.SETUP_CONSUMERS
+ set enabled='YES' where name='EVENTS_WAITS_CURRENT';
+
+Pre-test queries
+----------------
+
+select version();
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+select * from performance_schema.PERFORMANCE_TIMERS;
+select * from performance_schema.SETUP_CONSUMERS;
+select * from performance_schema.SETUP_INSTRUMENTS;
+select * from performance_schema.SETUP_TIMERS;
+
+Post-test queries
+-----------------
+
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+
+Configuration PERFSCHEMA-ENABLED-CURRENT-CYCLE
+==============================================
+
+Description
+-----------
+
+Server built with the performance schema.
+The performance schema is enabled at startup.
+All instruments are enabled and timed,
+and only one consumer (EVENTS_WAITS_CURRENT) is set.
+The timer used is CYCLE.
+
+Compiling options
+-----------------
+
+./configure --with-perfschema
+
+Server start options
+--------------------
+
+./mysqld --enable-performance-schema
+
+Configuration
+-------------
+
+UPDATE performance_schema.SETUP_INSTRUMENTS
+ set enabled='YES', timed='YES';
+
+UPDATE performance_schema.SETUP_TIMERS
+ set timer_name='CYCLE';
+
+UPDATE performance_schema.SETUP_CONSUMERS
+ set enabled='NO';
+
+UPDATE performance_schema.SETUP_CONSUMERS
+ set enabled='YES' where name='EVENTS_WAITS_CURRENT';
+
+Pre-test queries
+----------------
+
+select version();
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+select * from performance_schema.PERFORMANCE_TIMERS;
+select * from performance_schema.SETUP_CONSUMERS;
+select * from performance_schema.SETUP_INSTRUMENTS;
+select * from performance_schema.SETUP_TIMERS;
+
+Post-test queries
+-----------------
+
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+
+Configuration PERFSCHEMA-ENABLED-HISTORY-CYCLE
+==============================================
+
+Description
+-----------
+
+Server built with the performance schema.
+The performance schema is enabled at startup.
+All instruments are enabled and timed, in CYCLE.
+Two consumers (EVENTS_WAITS_CURRENT, EVENTS_WAITS_HISTORY) are set.
+
+Compiling options
+-----------------
+
+./configure --with-perfschema
+
+Server start options
+--------------------
+
+./mysqld --enable-performance-schema
+
+Configuration
+-------------
+
+UPDATE performance_schema.SETUP_INSTRUMENTS
+ set enabled='YES', timed='YES';
+
+UPDATE performance_schema.SETUP_TIMERS
+ set timer_name='CYCLE';
+
+UPDATE performance_schema.SETUP_CONSUMERS
+ set enabled='NO';
+
+UPDATE performance_schema.SETUP_CONSUMERS
+ set enabled='YES' where name='EVENTS_WAITS_CURRENT';
+
+UPDATE performance_schema.SETUP_CONSUMERS
+ set enabled='YES' where name='EVENTS_WAITS_HISTORY';
+
+Pre-test queries
+----------------
+
+select version();
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+select * from performance_schema.PERFORMANCE_TIMERS;
+select * from performance_schema.SETUP_CONSUMERS;
+select * from performance_schema.SETUP_INSTRUMENTS;
+select * from performance_schema.SETUP_TIMERS;
+
+Post-test queries
+-----------------
+
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+
+Configuration PERFSCHEMA-ENABLED-HISTORY_LONG-CYCLE
+===================================================
+
+Description
+-----------
+
+Server built with the performance schema.
+The performance schema is enabled at startup.
+All instruments are enabled and timed, in CYCLE.
+Two consumers (EVENTS_WAITS_CURRENT, EVENTS_WAITS_HISTORY_LONG) are set.
+
+Compiling options
+-----------------
+
+./configure --with-perfschema
+
+Server start options
+--------------------
+
+./mysqld --enable-performance-schema
+
+Configuration
+-------------
+
+UPDATE performance_schema.SETUP_INSTRUMENTS
+ set enabled='YES', timed='YES';
+
+UPDATE performance_schema.SETUP_TIMERS
+ set timer_name='CYCLE';
+
+UPDATE performance_schema.SETUP_CONSUMERS
+ set enabled='NO';
+
+UPDATE performance_schema.SETUP_CONSUMERS
+ set enabled='YES' where name='EVENTS_WAITS_CURRENT';
+
+UPDATE performance_schema.SETUP_CONSUMERS
+ set enabled='YES' where name='EVENTS_WAITS_HISTORY_LONG';
+
+Pre-test queries
+----------------
+
+select version();
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+select * from performance_schema.PERFORMANCE_TIMERS;
+select * from performance_schema.SETUP_CONSUMERS;
+select * from performance_schema.SETUP_INSTRUMENTS;
+select * from performance_schema.SETUP_TIMERS;
+
+Post-test queries
+-----------------
+
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+
+Configuration PERFSCHEMA-ENABLED-BIGBANG-CYCLE
+==============================================
+
+Description
+-----------
+
+Server built with the performance schema.
+The performance schema is enabled at startup.
+All instruments are enabled and timed, in CYCLE.
+All possible consumers are enabled.
+
+Compiling options
+-----------------
+
+./configure --with-perfschema
+
+Server start options
+--------------------
+
+./mysqld --enable-performance-schema
+
+Configuration
+-------------
+
+UPDATE performance_schema.SETUP_INSTRUMENTS
+ set enabled='YES', timed='YES';
+
+UPDATE performance_schema.SETUP_TIMERS
+ set timer_name='CYCLE';
+
+UPDATE performance_schema.SETUP_CONSUMERS
+ set enabled='YES';
+
+Pre-test queries
+----------------
+
+select version();
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+select * from performance_schema.PERFORMANCE_TIMERS;
+select * from performance_schema.SETUP_CONSUMERS;
+select * from performance_schema.SETUP_INSTRUMENTS;
+select * from performance_schema.SETUP_TIMERS;
+
+Post-test queries
+-----------------
+
+show engine performance_schema status;
+show variables like "performance%";
+show status like "performance%";
+
diff --git a/storage/perfschema/unittest/pfs-t.cc b/storage/perfschema/unittest/pfs-t.cc
new file mode 100644
index 00000000000..6e63a18f174
--- /dev/null
+++ b/storage/perfschema/unittest/pfs-t.cc
@@ -0,0 +1,1645 @@
+/* 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 */
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include <pfs_server.h>
+#include <pfs_instr_class.h>
+#include <pfs_instr.h>
+#include <pfs_global.h>
+#include <tap.h>
+
+#include <string.h>
+#include <memory.h>
+
+#include "stub_print_error.h"
+#include "stub_pfs_defaults.h"
+#include "stub_server_misc.h"
+
+/* test helpers, to simulate the setup */
+
+void setup_thread(PSI_thread *t, bool enabled)
+{
+ PFS_thread *t2= (PFS_thread*) t;
+ t2->m_enabled= enabled;
+}
+
+/* test helpers, to inspect data */
+
+PFS_file* lookup_file_by_name(const char* name)
+{
+ uint i;
+ PFS_file *pfs;
+ uint len= strlen(name);
+ size_t dirlen;
+ const char *filename;
+ uint filename_length;;
+
+ for (i= 0; i < file_max; i++)
+ {
+ pfs= & file_array[i];
+ if (pfs->m_lock.is_populated())
+ {
+ /*
+ When a file "foo" is instrumented, the name is normalized
+ to "/path/to/current/directory/foo", so we remove the
+ directory name here to find it back.
+ */
+ dirlen= dirname_length(pfs->m_filename);
+ filename= pfs->m_filename + dirlen;
+ filename_length= pfs->m_filename_length - dirlen;
+ if ((len == filename_length) &&
+ (strncmp(name, filename, filename_length) == 0))
+ return pfs;
+ }
+ }
+
+ return NULL;
+}
+
+/* tests */
+
+void test_bootstrap()
+{
+ void *psi;
+ void *psi_2;
+ PSI_bootstrap *boot;
+ PFS_global_param param;
+
+ diag("test_bootstrap");
+
+ 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= 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;
+ 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;
+ 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_session_connect_attrs_sizing= 0;
+
+ boot= initialize_performance_schema(& param);
+ ok(boot != NULL, "boot");
+ ok(boot->get_interface != NULL, "boot->get_interface");
+
+ psi= boot->get_interface(0);
+ ok(psi == NULL, "no version 0");
+
+ psi= boot->get_interface(PSI_VERSION_1);
+ ok(psi != NULL, "version 1");
+
+ psi_2= boot->get_interface(PSI_VERSION_2);
+ ok(psi_2 == NULL, "version 2");
+
+ shutdown_performance_schema();
+}
+
+/*
+ Not a test, helper for testing pfs.cc
+*/
+PSI * load_perfschema()
+{
+ void *psi;
+ 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;
+ param.m_cond_class_sizing= 10;
+ 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;
+ param.m_thread_sizing= 10;
+ 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;
+ param.m_session_connect_attrs_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;
+}
+
+void test_bad_registration()
+{
+ PSI *psi;
+
+ diag("test_bad_registration");
+
+ psi= load_perfschema();
+
+ /*
+ Test that length('wait/synch/mutex/' (17) + category + '/' (1)) < 32
+ --> category can be up to 13 chars for a mutex.
+ */
+
+ PSI_mutex_key dummy_mutex_key= 9999;
+ PSI_mutex_info bad_mutex_1[]=
+ {
+ { & dummy_mutex_key, "X", 0}
+ };
+
+ psi->register_mutex("/", bad_mutex_1, 1);
+ ok(dummy_mutex_key == 0, "zero key");
+ dummy_mutex_key= 9999;
+ psi->register_mutex("a/", bad_mutex_1, 1);
+ ok(dummy_mutex_key == 0, "zero key");
+ dummy_mutex_key= 9999;
+ psi->register_mutex("/b", bad_mutex_1, 1);
+ ok(dummy_mutex_key == 0, "zero key");
+ dummy_mutex_key= 9999;
+ psi->register_mutex("a/b", bad_mutex_1, 1);
+ ok(dummy_mutex_key == 0, "zero key");
+ dummy_mutex_key= 9999;
+ psi->register_mutex("12345678901234", bad_mutex_1, 1);
+ ok(dummy_mutex_key == 0, "zero key");
+ dummy_mutex_key= 9999;
+ psi->register_mutex("1234567890123", bad_mutex_1, 1);
+ ok(dummy_mutex_key == 1, "assigned key");
+
+ /*
+ Test that length('wait/synch/mutex/' (17) + category + '/' (1) + name) <= 128
+ --> category + name can be up to 110 chars for a mutex.
+ */
+
+ dummy_mutex_key= 9999;
+ PSI_mutex_info bad_mutex_2[]=
+ {
+ { & dummy_mutex_key,
+ /* 110 chars name */
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "1234567890",
+ 0}
+ };
+
+ psi->register_mutex("X", bad_mutex_2, 1);
+ ok(dummy_mutex_key == 0, "zero key");
+
+ dummy_mutex_key= 9999;
+ PSI_mutex_info bad_mutex_3[]=
+ {
+ { & dummy_mutex_key,
+ /* 109 chars name */
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "123456789",
+ 0}
+ };
+
+ psi->register_mutex("XX", bad_mutex_3, 1);
+ ok(dummy_mutex_key == 0, "zero key");
+
+ psi->register_mutex("X", bad_mutex_3, 1);
+ ok(dummy_mutex_key == 2, "assigned key");
+
+ /*
+ Test that length('wait/synch/rwlock/' (18) + category + '/' (1)) < 32
+ --> category can be up to 12 chars for a rwlock.
+ */
+
+ PSI_rwlock_key dummy_rwlock_key= 9999;
+ PSI_rwlock_info bad_rwlock_1[]=
+ {
+ { & dummy_rwlock_key, "X", 0}
+ };
+
+ psi->register_rwlock("/", bad_rwlock_1, 1);
+ ok(dummy_rwlock_key == 0, "zero key");
+ dummy_rwlock_key= 9999;
+ psi->register_rwlock("a/", bad_rwlock_1, 1);
+ ok(dummy_rwlock_key == 0, "zero key");
+ dummy_rwlock_key= 9999;
+ psi->register_rwlock("/b", bad_rwlock_1, 1);
+ ok(dummy_rwlock_key == 0, "zero key");
+ dummy_rwlock_key= 9999;
+ psi->register_rwlock("a/b", bad_rwlock_1, 1);
+ ok(dummy_rwlock_key == 0, "zero key");
+ dummy_rwlock_key= 9999;
+ psi->register_rwlock("1234567890123", bad_rwlock_1, 1);
+ ok(dummy_rwlock_key == 0, "zero key");
+ dummy_rwlock_key= 9999;
+ psi->register_rwlock("123456789012", bad_rwlock_1, 1);
+ ok(dummy_rwlock_key == 1, "assigned key");
+
+ /*
+ Test that length('wait/synch/rwlock/' (18) + category + '/' (1) + name) <= 128
+ --> category + name can be up to 109 chars for a rwlock.
+ */
+
+ dummy_rwlock_key= 9999;
+ PSI_rwlock_info bad_rwlock_2[]=
+ {
+ { & dummy_rwlock_key,
+ /* 109 chars name */
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "123456789",
+ 0}
+ };
+
+ psi->register_rwlock("X", bad_rwlock_2, 1);
+ ok(dummy_rwlock_key == 0, "zero key");
+
+ dummy_rwlock_key= 9999;
+ PSI_rwlock_info bad_rwlock_3[]=
+ {
+ { & dummy_rwlock_key,
+ /* 108 chars name */
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678",
+ 0}
+ };
+
+ psi->register_rwlock("XX", bad_rwlock_3, 1);
+ ok(dummy_rwlock_key == 0, "zero key");
+
+ psi->register_rwlock("X", bad_rwlock_3, 1);
+ ok(dummy_rwlock_key == 2, "assigned key");
+
+ /*
+ Test that length('wait/synch/cond/' (16) + category + '/' (1)) < 32
+ --> category can be up to 14 chars for a cond.
+ */
+
+ PSI_cond_key dummy_cond_key= 9999;
+ PSI_cond_info bad_cond_1[]=
+ {
+ { & dummy_cond_key, "X", 0}
+ };
+
+ psi->register_cond("/", bad_cond_1, 1);
+ ok(dummy_cond_key == 0, "zero key");
+ dummy_cond_key= 9999;
+ psi->register_cond("a/", bad_cond_1, 1);
+ ok(dummy_cond_key == 0, "zero key");
+ dummy_cond_key= 9999;
+ psi->register_cond("/b", bad_cond_1, 1);
+ ok(dummy_cond_key == 0, "zero key");
+ dummy_cond_key= 9999;
+ psi->register_cond("a/b", bad_cond_1, 1);
+ ok(dummy_cond_key == 0, "zero key");
+ dummy_cond_key= 9999;
+ psi->register_cond("123456789012345", bad_cond_1, 1);
+ ok(dummy_cond_key == 0, "zero key");
+ dummy_cond_key= 9999;
+ psi->register_cond("12345678901234", bad_cond_1, 1);
+ ok(dummy_cond_key == 1, "assigned key");
+
+ /*
+ Test that length('wait/synch/cond/' (16) + category + '/' (1) + name) <= 128
+ --> category + name can be up to 111 chars for a cond.
+ */
+
+ dummy_cond_key= 9999;
+ PSI_cond_info bad_cond_2[]=
+ {
+ { & dummy_cond_key,
+ /* 111 chars name */
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901",
+ 0}
+ };
+
+ psi->register_cond("X", bad_cond_2, 1);
+ ok(dummy_cond_key == 0, "zero key");
+
+ dummy_cond_key= 9999;
+ PSI_cond_info bad_cond_3[]=
+ {
+ { & dummy_cond_key,
+ /* 110 chars name */
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "1234567890",
+ 0}
+ };
+
+ psi->register_cond("XX", bad_cond_3, 1);
+ ok(dummy_cond_key == 0, "zero key");
+
+ psi->register_cond("X", bad_cond_3, 1);
+ ok(dummy_cond_key == 2, "assigned key");
+
+ /*
+ Test that length('thread/' (7) + category + '/' (1)) < 32
+ --> category can be up to 23 chars for a thread.
+ */
+
+ PSI_thread_key dummy_thread_key= 9999;
+ PSI_thread_info bad_thread_1[]=
+ {
+ { & dummy_thread_key, "X", 0}
+ };
+
+ psi->register_thread("/", bad_thread_1, 1);
+ ok(dummy_thread_key == 0, "zero key");
+ dummy_thread_key= 9999;
+ psi->register_thread("a/", bad_thread_1, 1);
+ ok(dummy_thread_key == 0, "zero key");
+ dummy_thread_key= 9999;
+ psi->register_thread("/b", bad_thread_1, 1);
+ ok(dummy_thread_key == 0, "zero key");
+ dummy_thread_key= 9999;
+ psi->register_thread("a/b", bad_thread_1, 1);
+ ok(dummy_thread_key == 0, "zero key");
+ dummy_thread_key= 9999;
+ psi->register_thread("123456789012345678901234", bad_thread_1, 1);
+ ok(dummy_thread_key == 0, "zero key");
+ dummy_thread_key= 9999;
+ psi->register_thread("12345678901234567890123", bad_thread_1, 1);
+ ok(dummy_thread_key == 1, "assigned key");
+
+ /*
+ Test that length('thread/' (7) + category + '/' (1) + name) <= 128
+ --> category + name can be up to 120 chars for a thread.
+ */
+
+ dummy_thread_key= 9999;
+ PSI_thread_info bad_thread_2[]=
+ {
+ { & dummy_thread_key,
+ /* 120 chars name */
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890",
+ 0}
+ };
+
+ psi->register_thread("X", bad_thread_2, 1);
+ ok(dummy_thread_key == 0, "zero key");
+
+ dummy_thread_key= 9999;
+ PSI_thread_info bad_thread_3[]=
+ {
+ { & dummy_thread_key,
+ /* 119 chars name */
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "1234567890123456789",
+ 0}
+ };
+
+ psi->register_thread("XX", bad_thread_3, 1);
+ ok(dummy_thread_key == 0, "zero key");
+
+ psi->register_thread("X", bad_thread_3, 1);
+ ok(dummy_thread_key == 2, "assigned key");
+
+ /*
+ Test that length('wait/io/file/' (13) + category + '/' (1)) < 32
+ --> category can be up to 17 chars for a file.
+ */
+
+ PSI_file_key dummy_file_key= 9999;
+ PSI_file_info bad_file_1[]=
+ {
+ { & dummy_file_key, "X", 0}
+ };
+
+ psi->register_file("/", bad_file_1, 1);
+ ok(dummy_file_key == 0, "zero key");
+ dummy_file_key= 9999;
+ psi->register_file("a/", bad_file_1, 1);
+ ok(dummy_file_key == 0, "zero key");
+ dummy_file_key= 9999;
+ psi->register_file("/b", bad_file_1, 1);
+ ok(dummy_file_key == 0, "zero key");
+ dummy_file_key= 9999;
+ psi->register_file("a/b", bad_file_1, 1);
+ ok(dummy_file_key == 0, "zero key");
+ dummy_file_key= 9999;
+ psi->register_file("123456789012345678", bad_file_1, 1);
+ ok(dummy_file_key == 0, "zero key");
+ dummy_file_key= 9999;
+ psi->register_file("12345678901234567", bad_file_1, 1);
+ ok(dummy_file_key == 1, "assigned key");
+
+ /*
+ Test that length('wait/io/file/' (13) + category + '/' (1) + name) <= 128
+ --> category + name can be up to 114 chars for a file.
+ */
+
+ dummy_file_key= 9999;
+ PSI_file_info bad_file_2[]=
+ {
+ { & dummy_file_key,
+ /* 114 chars name */
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234",
+ 0}
+ };
+
+ psi->register_file("X", bad_file_2, 1);
+ ok(dummy_file_key == 0, "zero key");
+
+ dummy_file_key= 9999;
+ PSI_file_info bad_file_3[]=
+ {
+ { & dummy_file_key,
+ /* 113 chars name */
+ "12345678901234567890123456789012345678901234567890"
+ "12345678901234567890123456789012345678901234567890"
+ "1234567890123",
+ 0}
+ };
+
+ psi->register_file("XX", bad_file_3, 1);
+ ok(dummy_file_key == 0, "zero key");
+
+ 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();
+}
+
+void test_init_disabled()
+{
+ PSI *psi;
+
+ diag("test_init_disabled");
+
+ psi= load_perfschema();
+
+ PSI_mutex_key mutex_key_A;
+ PSI_mutex_info all_mutex[]=
+ {
+ { & mutex_key_A, "M-A", 0}
+ };
+
+ PSI_rwlock_key rwlock_key_A;
+ PSI_rwlock_info all_rwlock[]=
+ {
+ { & rwlock_key_A, "RW-A", 0}
+ };
+
+ PSI_cond_key cond_key_A;
+ PSI_cond_info all_cond[]=
+ {
+ { & cond_key_A, "C-A", 0}
+ };
+
+ PSI_file_key file_key_A;
+ PSI_file_info all_file[]=
+ {
+ { & 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[]=
+ {
+ { & thread_key_1, "T-1", 0}
+ };
+
+ psi->register_mutex("test", all_mutex, 1);
+ 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 */
+
+ thread_1= psi->new_thread(thread_key_1, NULL, 0);
+ ok(thread_1 != NULL, "T-1");
+ psi->set_thread_id(thread_1, 1);
+
+ mutex_class_A= find_mutex_class(mutex_key_A);
+ ok(mutex_class_A != NULL, "mutex class A");
+
+ rwlock_class_A= find_rwlock_class(rwlock_key_A);
+ ok(rwlock_class_A != NULL, "rwlock class A");
+
+ cond_class_A= find_cond_class(cond_key_A);
+ ok(cond_class_A != NULL, "cond class A");
+
+ file_class_A= find_file_class(file_key_A);
+ ok(file_class_A != NULL, "file class A");
+
+ 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);
+
+ /* disabled M-A + disabled T-1: no instrumentation */
+
+ mutex_class_A->m_enabled= false;
+ mutex_A1= psi->init_mutex(mutex_key_A, NULL);
+ ok(mutex_A1 == NULL, "mutex_A1 not instrumented");
+
+ /* 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, "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, "mutex key 0 not instrumented");
+ mutex_A1= psi->init_mutex(99, NULL);
+ 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, "rwlock_A1 not instrumented");
+
+ /* 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, "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, "rwlock key 0 not instrumented");
+ rwlock_A1= psi->init_rwlock(99, NULL);
+ 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, "cond_A1 not instrumented");
+
+ /* 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, "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, "cond key 0 not instrumented");
+ cond_A1= psi->init_cond(99, NULL);
+ ok(cond_A1 == NULL, "broken cond key not instrumented");
+
+ /* disabled F-A + disabled T-1: no instrumentation */
+
+ file_class_A->m_enabled= false;
+ psi->create_file(file_key_A, "foo", (File) 12);
+ file_A1= lookup_file_by_name("foo");
+ ok(file_A1 == NULL, "not instrumented");
+
+ /* enabled F-A + disabled T-1: no instrumentation */
+
+ file_class_A->m_enabled= true;
+ psi->create_file(file_key_A, "foo", (File) 12);
+ file_A1= lookup_file_by_name("foo");
+ ok(file_A1 == NULL, "not instrumented");
+
+ /* broken key + disabled 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");
+ psi->create_file(99, "foo", (File) 12);
+ 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, NULL, 0);
+ 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, NULL, 0);
+ 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, NULL, 0);
+ ok(socket_A1 == NULL, "socket key 0 not instrumented");
+ socket_A1= psi->init_socket(99, NULL, NULL, 0);
+ ok(socket_A1 == NULL, "broken socket key not instrumented");
+
+ /* Pretend thread T-1 is enabled */
+ /* ----------------------------- */
+
+ setup_thread(thread_1, true);
+
+ /* disabled M-A + enabled T-1: no instrumentation */
+
+ mutex_class_A->m_enabled= false;
+ mutex_A1= psi->init_mutex(mutex_key_A, NULL);
+ ok(mutex_A1 == NULL, "not instrumented");
+
+ /* enabled M-A + enabled T-1: instrumentation */
+
+ mutex_class_A->m_enabled= true;
+ mutex_A1= psi->init_mutex(mutex_key_A, NULL);
+ ok(mutex_A1 != NULL, "instrumented");
+ psi->destroy_mutex(mutex_A1);
+
+ /* broken key + enabled T-1: no instrumentation */
+
+ mutex_class_A->m_enabled= true;
+ mutex_A1= psi->init_mutex(0, NULL);
+ ok(mutex_A1 == NULL, "not instrumented");
+ mutex_A1= psi->init_mutex(99, NULL);
+ ok(mutex_A1 == NULL, "not instrumented");
+
+ /* disabled RW-A + enabled 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");
+
+ /* enabled RW-A + enabled T-1: instrumentation */
+
+ rwlock_class_A->m_enabled= true;
+ rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL);
+ ok(rwlock_A1 != NULL, "instrumented");
+ psi->destroy_rwlock(rwlock_A1);
+
+ /* broken key + enabled T-1: no instrumentation */
+
+ rwlock_class_A->m_enabled= true;
+ rwlock_A1= psi->init_rwlock(0, NULL);
+ ok(rwlock_A1 == NULL, "not instrumented");
+ rwlock_A1= psi->init_rwlock(99, NULL);
+ ok(rwlock_A1 == NULL, "not instrumented");
+
+ /* disabled C-A + enabled 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");
+
+ /* enabled C-A + enabled T-1: instrumentation */
+
+ cond_class_A->m_enabled= true;
+ cond_A1= psi->init_cond(cond_key_A, NULL);
+ ok(cond_A1 != NULL, "instrumented");
+ psi->destroy_cond(cond_A1);
+
+ /* broken key + enabled T-1: no instrumentation */
+
+ cond_class_A->m_enabled= true;
+ cond_A1= psi->init_cond(0, NULL);
+ ok(cond_A1 == NULL, "not instrumented");
+ cond_A1= psi->init_cond(99, NULL);
+ ok(cond_A1 == NULL, "not instrumented");
+
+ /* disabled F-A + enabled T-1: no instrumentation */
+
+ file_class_A->m_enabled= false;
+ psi->create_file(file_key_A, "foo", (File) 12);
+ file_A1= lookup_file_by_name("foo");
+ ok(file_A1 == NULL, "not instrumented");
+
+ /* enabled F-A + open failed + enabled T-1: no instrumentation */
+
+ file_class_A->m_enabled= true;
+ psi->create_file(file_key_A, "foo", (File) -1);
+ file_A1= lookup_file_by_name("foo");
+ ok(file_A1 == NULL, "not instrumented");
+
+ /* enabled F-A + out-of-descriptors + enabled T-1: no instrumentation */
+
+ file_class_A->m_enabled= true;
+ psi->create_file(file_key_A, "foo", (File) 65000);
+ file_A1= lookup_file_by_name("foo");
+ ok(file_A1 == NULL, "not instrumented");
+ ok(file_handle_lost == 1, "lost a file handle");
+ file_handle_lost= 0;
+
+ /* enabled F-A + enabled T-1: instrumentation */
+
+ 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, "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, "file key 0 not instrumented");
+ psi->create_file(99, "foo", (File) 12);
+ file_A1= lookup_file_by_name("foo");
+ 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, NULL, 0);
+ 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, NULL, 0);
+ ok(socket_A1 == NULL, "not instrumented");
+ socket_A1= psi->init_socket(99, NULL, NULL, 0);
+ ok(socket_A1 == NULL, "not instrumented");
+
+ /* Pretend the running thread is not instrumented */
+ /* ---------------------------------------------- */
+
+ psi->delete_current_thread();
+
+ /* disabled M-A + unknown thread: no instrumentation */
+
+ mutex_class_A->m_enabled= false;
+ mutex_A1= psi->init_mutex(mutex_key_A, NULL);
+ ok(mutex_A1 == NULL, "mutex_A1 not instrumented");
+
+ /* 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, "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, "mutex key 0 not instrumented");
+ mutex_A1= psi->init_mutex(99, NULL);
+ 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, "rwlock_A1 not instrumented");
+
+ /* 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, "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, "rwlock key 0 not instrumented");
+ rwlock_A1= psi->init_rwlock(99, NULL);
+ 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, "cond_A1 not instrumented");
+
+ /* 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, "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, "cond key 0 not instrumented");
+ cond_A1= psi->init_cond(99, NULL);
+ ok(cond_A1 == NULL, "broken cond key not instrumented");
+
+ /* disabled F-A + unknown thread: no instrumentation */
+
+ file_class_A->m_enabled= false;
+ psi->create_file(file_key_A, "foo", (File) 12);
+ file_A1= lookup_file_by_name("foo");
+ ok(file_A1 == NULL, "not instrumented");
+
+ /* enabled F-A + unknown thread: no instrumentation */
+
+ file_class_A->m_enabled= true;
+ psi->create_file(file_key_A, "foo", (File) 12);
+ file_A1= lookup_file_by_name("foo");
+ ok(file_A1 == NULL, "not instrumented");
+
+ /* broken key + unknown thread: 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");
+ psi->create_file(99, "foo", (File) 12);
+ 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, NULL, 0);
+ 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, NULL, 0);
+ 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, NULL, 0);
+ ok(socket_A1 == NULL, "socket key 0 not instrumented");
+ socket_A1= psi->init_socket(99, NULL, NULL, 0);
+ ok(socket_A1 == NULL, "broken socket key not instrumented");
+
+ shutdown_performance_schema();
+}
+
+void test_locker_disabled()
+{
+ PSI *psi;
+
+ diag("test_locker_disabled");
+
+ psi= load_perfschema();
+
+ PSI_mutex_key mutex_key_A;
+ PSI_mutex_info all_mutex[]=
+ {
+ { & mutex_key_A, "M-A", 0}
+ };
+
+ PSI_rwlock_key rwlock_key_A;
+ PSI_rwlock_info all_rwlock[]=
+ {
+ { & rwlock_key_A, "RW-A", 0}
+ };
+
+ PSI_cond_key cond_key_A;
+ PSI_cond_info all_cond[]=
+ {
+ { & cond_key_A, "C-A", 0}
+ };
+
+ PSI_file_key file_key_A;
+ PSI_file_info all_file[]=
+ {
+ { & 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[]=
+ {
+ { & thread_key_1, "T-1", 0}
+ };
+
+ psi->register_mutex("test", all_mutex, 1);
+ 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 */
+
+ thread_1= psi->new_thread(thread_key_1, NULL, 0);
+ ok(thread_1 != NULL, "T-1");
+ psi->set_thread_id(thread_1, 1);
+
+ mutex_class_A= find_mutex_class(mutex_key_A);
+ ok(mutex_class_A != NULL, "mutex info A");
+
+ rwlock_class_A= find_rwlock_class(rwlock_key_A);
+ ok(rwlock_class_A != NULL, "rwlock info A");
+
+ cond_class_A= find_cond_class(cond_key_A);
+ ok(cond_class_A != NULL, "cond info A");
+
+ 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 */
+ /* ------------------------------------------ */
+
+ psi->set_thread(thread_1);
+ setup_thread(thread_1, true);
+
+ /* Enable all instruments, instantiate objects */
+
+ mutex_class_A->m_enabled= true;
+ mutex_A1= psi->init_mutex(mutex_key_A, NULL);
+ ok(mutex_A1 != NULL, "instrumented");
+
+ rwlock_class_A->m_enabled= true;
+ rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL);
+ ok(rwlock_A1 != NULL, "instrumented");
+
+ cond_class_A->m_enabled= true;
+ cond_A1= psi->init_cond(cond_key_A, NULL);
+ ok(cond_A1 != NULL, "instrumented");
+
+ file_class_A->m_enabled= true;
+ psi->create_file(file_key_A, "foo", (File) 12);
+ 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, NULL, 0);
+ 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;
+ PSI_rwlock_locker_state rwlock_state;
+ PSI_cond_locker *cond_locker;
+ 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 */
+ /* ------------------------------ */
+
+ setup_thread(thread_1, false);
+ flag_events_waits_current= true;
+ 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;
+
+ 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 (T-1 disabled)");
+ file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ);
+ 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 (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 global consumer is disabled */
+ /* --------------------------------------- */
+
+ setup_thread(thread_1, true);
+ 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)");
+
+ /* 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, "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, "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, "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->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12);
+ ok(mutex_locker == NULL, "no locker");
+ 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->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");
+ file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ);
+ 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 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->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, __FILE__, __LINE__);
+ ok(mutex_locker != NULL, "locker");
+ psi->end_mutex_wait(mutex_locker, 0);
+ rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, __FILE__, __LINE__);
+ ok(rwlock_locker != NULL, "locker");
+ psi->end_rwlock_rdwait(rwlock_locker, 0);
+ cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, __FILE__, __LINE__);
+ ok(cond_locker != NULL, "locker");
+ psi->end_cond_wait(cond_locker, 0);
+ file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_STREAM_OPEN, "xxx", NULL);
+ ok(file_locker != NULL, "locker");
+ psi->start_file_open_wait(file_locker, __FILE__, __LINE__);
+ psi->end_file_open_wait(file_locker, NULL);
+ file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ);
+ ok(file_locker != NULL, "locker");
+ 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, "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, NULL, 0);
+ 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 */
+ /* ---------------------------------------------- */
+
+ psi->delete_current_thread();
+ flag_events_waits_current= true;
+ 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");
+ 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->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");
+ file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ);
+ 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();
+}
+
+void test_file_instrumentation_leak()
+{
+ PSI *psi;
+
+ diag("test_file_instrumentation_leak");
+
+ psi= load_perfschema();
+
+ PSI_file_key file_key_A;
+ PSI_file_key file_key_B;
+ PSI_file_info all_file[]=
+ {
+ { & file_key_A, "F-A", 0},
+ { & file_key_B, "F-B", 0}
+ };
+
+ PSI_thread_key thread_key_1;
+ PSI_thread_info all_thread[]=
+ {
+ { & thread_key_1, "T-1", 0}
+ };
+
+ psi->register_file("test", all_file, 2);
+ psi->register_thread("test", all_thread, 1);
+
+ PFS_file_class *file_class_A;
+ PFS_file_class *file_class_B;
+ PSI_file_locker_state file_state;
+ PSI_thread *thread_1;
+
+ /* Preparation */
+
+ thread_1= psi->new_thread(thread_key_1, NULL, 0);
+ ok(thread_1 != NULL, "T-1");
+ psi->set_thread_id(thread_1, 1);
+
+ file_class_A= find_file_class(file_key_A);
+ ok(file_class_A != NULL, "file info A");
+
+ file_class_B= find_file_class(file_key_B);
+ ok(file_class_B != NULL, "file info B");
+
+ psi->set_thread(thread_1);
+
+ /* Pretend everything is enabled */
+ /* ----------------------------- */
+
+ setup_thread(thread_1, true);
+ flag_events_waits_current= true;
+ file_class_A->m_enabled= true;
+ file_class_B->m_enabled= true;
+
+ PSI_file_locker *file_locker;
+
+ /* Simulate OPEN + READ of 100 bytes + CLOSE on descriptor 12 */
+
+ file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "AAA", NULL);
+ ok(file_locker != NULL, "locker");
+ psi->start_file_open_wait(file_locker, __FILE__, __LINE__);
+ psi->end_file_open_wait_and_bind_to_descriptor(file_locker, 12);
+
+ file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ);
+ ok(file_locker != NULL, "locker");
+ psi->start_file_wait(file_locker, 100, __FILE__, __LINE__);
+ psi->end_file_wait(file_locker, 100);
+
+ file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_CLOSE);
+ ok(file_locker != NULL, "locker");
+ psi->start_file_wait(file_locker, 0, __FILE__, __LINE__);
+ psi->end_file_wait(file_locker, 0);
+
+ /* Simulate uninstrumented-OPEN + WRITE on descriptor 24 */
+
+ file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 24, PSI_FILE_WRITE);
+ ok(file_locker == NULL, "no locker, since the open was not instrumented");
+
+ /*
+ Simulate uninstrumented-OPEN + WRITE on descriptor 12 :
+ the instrumentation should not leak (don't charge the file io on unknown B to "AAA")
+ */
+
+ file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_WRITE);
+ ok(file_locker == NULL, "no locker, no leak");
+
+ shutdown_performance_schema();
+}
+
+void test_enabled()
+{
+#ifdef LATER
+ PSI *psi;
+
+ diag("test_enabled");
+
+ psi= load_perfschema();
+
+ PSI_mutex_key mutex_key_A;
+ PSI_mutex_key mutex_key_B;
+ PSI_mutex_info all_mutex[]=
+ {
+ { & mutex_key_A, "M-A", 0},
+ { & mutex_key_B, "M-B", 0}
+ };
+
+ PSI_rwlock_key rwlock_key_A;
+ PSI_rwlock_key rwlock_key_B;
+ PSI_rwlock_info all_rwlock[]=
+ {
+ { & rwlock_key_A, "RW-A", 0},
+ { & rwlock_key_B, "RW-B", 0}
+ };
+
+ PSI_cond_key cond_key_A;
+ PSI_cond_key cond_key_B;
+ PSI_cond_info all_cond[]=
+ {
+ { & cond_key_A, "C-A", 0},
+ { & cond_key_B, "C-B", 0}
+ };
+
+ shutdown_performance_schema();
+#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;
+
+ /* NOTE: Need to add 3 to each index: table io, table lock, idle */
+
+ /* 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_session_connect_attrs_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 == 3, "index 3");
+ mutex_class= find_mutex_class(dummy_mutex_key_2);
+ ok(mutex_class != NULL, "mutex class 2");
+ ok(mutex_class->m_event_name_index == 4, "index 4");
+
+ 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 == 13, "index 13");
+ rwlock_class= find_rwlock_class(dummy_rwlock_key_2);
+ ok(rwlock_class != NULL, "rwlock class 2");
+ ok(rwlock_class->m_event_name_index == 14, "index 14");
+
+ 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 == 33, "index 33");
+ cond_class= find_cond_class(dummy_cond_key_2);
+ ok(cond_class != NULL, "cond class 2");
+ ok(cond_class->m_event_name_index == 34, "index 34");
+
+ 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 == 73, "index 73");
+ file_class= find_file_class(dummy_file_key_2);
+ ok(file_class != NULL, "file class 2");
+ ok(file_class->m_event_name_index == 74, "index 74");
+
+ 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 == 153, "index 153");
+ socket_class= find_socket_class(dummy_socket_key_2);
+ ok(socket_class != NULL, "socket class 2");
+ ok(socket_class->m_event_name_index == 154, "index 154");
+
+ ok(global_table_io_class.m_event_name_index == 0, "index 0");
+ ok(global_table_lock_class.m_event_name_index == 1, "index 1");
+ ok(wait_class_max= 313, "313 event names"); // 3 global classes
+}
+
+void do_all_tests()
+{
+ /* Using initialize_performance_schema(), no partial init needed. */
+
+ test_bootstrap();
+ test_bad_registration();
+ test_init_disabled();
+ test_locker_disabled();
+ test_file_instrumentation_leak();
+ test_event_name_index();
+}
+
+int main(int, char **)
+{
+ plan(216);
+ MY_INIT("pfs-t");
+ do_all_tests();
+ 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..f877615da0f
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_account-oom-t.cc
@@ -0,0 +1,117 @@
+/* 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;
+ param.m_session_connect_attrs_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_connect_attr-t.cc b/storage/perfschema/unittest/pfs_connect_attr-t.cc
new file mode 100644
index 00000000000..7bee1d063a1
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_connect_attr-t.cc
@@ -0,0 +1,345 @@
+/* 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 */
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include <pfs_server.h>
+#include <pfs_instr_class.h>
+#include <pfs_instr.h>
+#include <pfs_global.h>
+#include <tap.h>
+
+
+#include <string.h>
+#include <memory.h>
+
+/* test helpers, to inspect data */
+bool read_nth_attr(const char *connect_attrs, uint connect_attrs_length,
+ const CHARSET_INFO *connect_attrs_cs,
+ uint ordinal,
+ char *attr_name, uint max_attr_name,
+ uint *attr_name_length,
+ char *attr_value, uint max_attr_value,
+ uint *attr_value_length);
+
+void test_blob_parser()
+{
+ char name[100], value[4096];
+ unsigned char packet[10000], *ptr;
+ uint name_len, value_len, idx, packet_length;
+ bool result;
+ const CHARSET_INFO *cs= &my_charset_utf8_bin;
+
+ diag("test_blob_parser");
+
+ result= read_nth_attr("", 0, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "zero length blob");
+
+
+ result= read_nth_attr("\x1", 1, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "invalid key length");
+
+
+ result= read_nth_attr("\x2k1\x1", 4, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "invalid value length");
+
+
+ result= read_nth_attr("\x2k1\x2v1", 6, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "one pair return");
+ ok(name_len == 2, "one pair attr name length");
+ ok(!strncmp(name, "k1", name_len), "one pair attr name");
+ ok(value_len == 2, "one pair value length");
+ ok(!strncmp(value, "v1", value_len), "one pair value");
+
+ result= read_nth_attr("\x2k1\x2v1", 6, cs, 1,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "no second arg");
+
+ result= read_nth_attr("\x2k1\x2v1\x2k2\x2v2", 12, cs, 1,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "two pairs return");
+ ok(name_len == 2, "two pairs attr name length");
+ ok(!strncmp(name, "k2", name_len), "two pairs attr name");
+ ok(value_len == 2, "two pairs value length");
+ ok(!strncmp(value, "v2", value_len), "two pairs value");
+
+ result= read_nth_attr("\x2k1\xff\x2k2\x2v2", 12, cs, 1,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "two pairs first value bad return");
+
+ result= read_nth_attr("\x2k1\x2v1\x2k2\x2v2", 10, cs, 1,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "two pairs wrong global length");
+
+ result= read_nth_attr("\x21z123456789z123456789z123456789z12\x2v1", 37, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "attr name overflow");
+ ok(name_len == 32, "attr name overflow length");
+ ok(!strncmp(name, "z123456789z123456789z123456789z1", name_len),
+ "attr name overflow name");
+ ok(value_len == 2, "attr name overflow value length");
+ ok(!strncmp(value, "v1", value_len), "attr name overflow value");
+
+ packet[0]= 2;
+ packet[1]= 'k';
+ packet[2]= '1';
+ ptr= net_store_length(packet + 3, 1025);
+ for (idx= 0; idx < 1025; idx++)
+ *ptr++= '0' + (idx % 10);
+ packet_length= (uint) (ptr - packet);
+ result= read_nth_attr((char *) packet, packet_length, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "attr value overflow");
+ ok(name_len == 2, "attr value overflow length");
+ ok(!strncmp(name, "k1", name_len), "attr value overflow name");
+ ok(value_len == 1024, "attr value overflow value length");
+ for (idx= 0; idx < 1024; idx++)
+ {
+ if (value[idx] != (char) ('0' + (idx % 10)))
+ break;
+ }
+ ok (idx == 1024, "attr value overflow value");
+
+ result= read_nth_attr("\x21z123456789z123456789z123456789z12\x2v1\x2k2\x2v2",
+ 43, cs, 1,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "prev attr name overflow");
+ ok(name_len == 2, "prev attr name overflow length");
+ ok(!strncmp(name, "k2", name_len),
+ "prev attr name overflow name");
+ ok(value_len == 2, "prev attr name overflow value length");
+ ok(!strncmp(value, "v2", value_len), "prev attr name overflow value");
+
+
+ packet[1]= 'k';
+ packet[2]= '1';
+ packet[3]= 2;
+ packet[4]= 'v';
+ packet[5]= '1';
+
+ for(idx= 251; idx < 256; idx++)
+ {
+ packet[0]= idx;
+ result= read_nth_attr((char *) packet, 6, cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "invalid string length %d", idx);
+ }
+
+ memset(packet, 0, sizeof(packet));
+ for (idx=0; idx < 1660 /* *6 = 9960 */; idx++)
+ memcpy(packet + idx * 6, "\x2k1\x2v1", 6);
+ result= read_nth_attr((char *) packet, 8192, cs, 1364,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "last valid attribute %d", 1364);
+ result= read_nth_attr((char *) packet, 8192, cs, 1365,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == false, "first attribute that's cut %d", 1365);
+}
+
+void test_multibyte_lengths()
+{
+ char name[100], value[4096];
+ uint name_len, value_len;
+ bool result;
+ const CHARSET_INFO *cs= &my_charset_utf8_bin;
+
+ unsigned char var_len_packet[] = {
+ 252, 2, 0, 'k', '1',
+ 253, 2, 0, 0, 'v', '1',
+ 254, 2, 0, 0, 0, 0, 0, 0, 0, 'k', '2',
+ 254, 2, 0, 0, 0, 0, 0, 0, 0, 'v', '2'
+ };
+
+ result= read_nth_attr((char *) var_len_packet, sizeof(var_len_packet), cs, 0,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "multibyte lengths return");
+ ok(name_len == 2, "multibyte lengths name length");
+ ok(!strncmp(name, "k1", name_len), "multibyte lengths attr name");
+ ok(value_len == 2, "multibyte lengths value length");
+ ok(!strncmp(value, "v1", value_len), "multibyte lengths value");
+
+ result= read_nth_attr((char *) var_len_packet, sizeof(var_len_packet), cs, 1,
+ name, 32, &name_len, value, 1024, &value_len);
+ ok(result == true, "multibyte lengths second attr return");
+ ok(name_len == 2, "multibyte lengths second attr name length");
+ ok(!strncmp(name, "k2", name_len), "multibyte lengths second attr attr name");
+ ok(value_len == 2, "multibyte lengths value length");
+ ok(!strncmp(value, "v2", value_len), "multibyte lengths second attr value");
+}
+
+
+void test_utf8_parser()
+{
+ /* utf8 max byte length per character is 6 */
+ char name[33 * 6], value[1024 * 6], packet[1500 * 6], *ptr;
+ uint name_len, value_len;
+ bool result;
+ const CHARSET_INFO *cs= &my_charset_utf8_bin;
+
+ /* note : this is encoded in utf-8 */
+ const char *attr1= "Георги";
+ const char *val1= "Кодинов";
+ const char *attr2= "Пловдив";
+ const char *val2= "България";
+
+ ptr= packet;
+ *ptr++= strlen(attr1);
+ memcpy(ptr, attr1, strlen(attr1));
+ ptr+= strlen(attr1);
+ *ptr++= strlen(val1);
+ memcpy(ptr, val1, strlen(val1));
+ ptr+= strlen(val1);
+
+ *ptr++= strlen(attr2);
+ memcpy(ptr, attr2, strlen(attr2));
+ ptr+= strlen(attr2);
+ *ptr++= strlen(val2);
+ memcpy(ptr, val2, strlen(val2));
+ ptr+= strlen(val2);
+
+ diag("test_utf8_parser attr pair #1");
+
+ result= read_nth_attr((char *) packet, ptr - packet, cs, 0,
+ name, sizeof(name), &name_len,
+ value, sizeof(value), &value_len);
+ ok(result == true, "return");
+ ok(name_len == strlen(attr1), "name length");
+ ok(!strncmp(name, attr1, name_len), "attr name");
+ ok(value_len == strlen(val1), "value length");
+ ok(!strncmp(value, val1, value_len), "value");
+
+ diag("test_utf8_parser attr pair #2");
+ result= read_nth_attr((char *) packet, ptr - packet, cs, 1,
+ name, sizeof(name), &name_len,
+ value, sizeof(value), &value_len);
+ ok(result == true, "return");
+ ok(name_len == strlen(attr2), "name length");
+ ok(!strncmp(name, attr2, name_len), "attr name");
+ ok(value_len == strlen(val2), "value length");
+ ok(!strncmp(value, val2, value_len), "value");
+}
+
+
+void test_utf8_parser_bad_encoding()
+{
+ /* utf8 max byte length per character is 3*/
+ char name[33 * 3], value[1024 * 3], packet[1500 * 3], *ptr;
+ uint name_len, value_len;
+ bool result;
+ const CHARSET_INFO *cs= &my_charset_utf8_bin;
+
+ /* note : this is encoded in utf-8 */
+ const char *attr= "Георги";
+ const char *val= "Кодинов";
+
+ ptr= packet;
+ *ptr++= strlen(attr);
+ memcpy(ptr, attr, strlen(attr));
+ ptr[0]= 0xFA; // invalid UTF-8 char
+ ptr+= strlen(attr);
+ *ptr++= strlen(val);
+ memcpy(ptr, val, strlen(val));
+ ptr+= strlen(val);
+
+ diag("test_utf8_parser_bad_encoding");
+
+ result= read_nth_attr((char *) packet, ptr - packet, cs, 0,
+ name, sizeof(name), &name_len,
+ value, sizeof(value), &value_len);
+ ok(result == false, "return");
+}
+
+const CHARSET_INFO *cs_cp1251;
+
+void test_cp1251_parser()
+{
+ /* utf8 max byte length per character is 3*/
+ char name[33 * 3], value[1024 * 3], packet[1500 * 3], *ptr;
+ uint name_len, value_len;
+ bool result;
+
+ /* note : this is Георги in windows-1251 */
+ const char *attr1= "\xc3\xe5\xee\xf0\xe3\xe8";
+ /* note : this is Кодинов in windows-1251 */
+ const char *val1= "\xca\xee\xe4\xe8\xed\xee\xe2";
+ /* note : this is Пловдив in windows-1251 */
+ const char *attr2= "\xcf\xeb\xee\xe2\xe4\xe8\xe2";
+ /* note : this is България in windows-1251 */
+ const char *val2= "\xc1\xfa\xeb\xe3\xe0\xf0\xe8\xff";
+
+ ptr= packet;
+ *ptr++= strlen(attr1);
+ memcpy(ptr, attr1, strlen(attr1));
+ ptr+= strlen(attr1);
+ *ptr++= strlen(val1);
+ memcpy(ptr, val1, strlen(val1));
+ ptr+= strlen(val1);
+
+ *ptr++= strlen(attr2);
+ memcpy(ptr, attr2, strlen(attr2));
+ ptr+= strlen(attr2);
+ *ptr++= strlen(val2);
+ memcpy(ptr, val2, strlen(val2));
+ ptr+= strlen(val2);
+
+ diag("test_cp1251_parser attr pair #1");
+
+ result= read_nth_attr((char *) packet, ptr - packet, cs_cp1251, 0,
+ name, sizeof(name), &name_len,
+ value, sizeof(value), &value_len);
+ ok(result == true, "return");
+ /* need to compare to the UTF-8 equivalents */
+ ok(name_len == strlen("Георги"), "name length");
+ ok(!strncmp(name, "Георги", name_len), "attr name");
+ ok(value_len == strlen("Кодинов"), "value length");
+ ok(!strncmp(value, "Кодинов", value_len), "value");
+
+ diag("test_cp1251_parser attr pair #2");
+ result= read_nth_attr((char *) packet, ptr - packet, cs_cp1251, 1,
+ name, sizeof(name), &name_len,
+ value, sizeof(value), &value_len);
+ ok(result == true, "return");
+ /* need to compare to the UTF-8 equivalents */
+ ok(name_len == strlen("Пловдив"), "name length");
+ ok(!strncmp(name, "Пловдив", name_len), "attr name");
+ ok(value_len == strlen("България"), "value length");
+ ok(!strncmp(value, "България", value_len), "value");
+}
+
+
+void do_all_tests()
+{
+ test_blob_parser();
+ test_multibyte_lengths();
+ test_utf8_parser();
+ test_utf8_parser_bad_encoding();
+ test_cp1251_parser();
+}
+
+int main(int, char **)
+{
+ MY_INIT("pfs_connect_attr-t");
+
+ cs_cp1251= get_charset_by_csname("cp1251", MY_CS_PRIMARY, MYF(0));
+ if (!cs_cp1251)
+ diag("skipping the cp1251 tests : missing character set");
+ plan(59 + (cs_cp1251 ? 10 : 0));
+ 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..cdc9764210a
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_host-oom-t.cc
@@ -0,0 +1,117 @@
+/* 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;
+ param.m_session_connect_attrs_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
new file mode 100644
index 00000000000..1ec198511c9
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_instr-oom-t.cc
@@ -0,0 +1,671 @@
+/* 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 */
+
+#include <my_global.h>
+#include <my_pthread.h>
+#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;
+ PFS_global_param param;
+
+ 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;
+ 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= 0;
+ param.m_mutex_sizing= 1000;
+ 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;
+ 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;
+ param.m_session_connect_attrs_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;
+ param.m_rwlock_class_sizing= 10;
+ 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= 0;
+ param.m_mutex_sizing= 0;
+ param.m_rwlock_sizing= 1000;
+ 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;
+ 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;
+ param.m_session_connect_attrs_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;
+ param.m_rwlock_class_sizing= 0;
+ param.m_cond_class_sizing= 10;
+ 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;
+ 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;
+ 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;
+ param.m_session_connect_attrs_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;
+ 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= 10;
+ param.m_socket_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= 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;
+ param.m_session_connect_attrs_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;
+ param.m_session_connect_attrs_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;
+ param.m_rwlock_class_sizing= 0;
+ param.m_cond_class_sizing= 0;
+ 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;
+ param.m_thread_sizing= 0;
+ 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;
+ param.m_session_connect_attrs_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;
+ 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_socket_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_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;
+ param.m_session_connect_attrs_sizing= 0;
+
+ init_event_name_sizing(& param);
+ rc= init_instruments(& param);
+ ok(rc == 1, "oom (thread)");
+ cleanup_instruments();
+
+ stub_alloc_always_fails= false;
+
+ 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_socket_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_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;
+ param.m_session_connect_attrs_sizing= 0;
+
+ stub_alloc_fails_after_count= 2;
+ init_event_name_sizing(& param);
+ rc= init_instruments(& param);
+ ok(rc == 1, "oom (thread waits history sizing)");
+ cleanup_instruments();
+
+ param.m_enabled= true;
+ param.m_mutex_class_sizing= 50;
+ param.m_rwlock_class_sizing= 50;
+ param.m_cond_class_sizing= 50;
+ 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;
+ param.m_thread_sizing= 1000;
+ 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;
+ param.m_session_connect_attrs_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;
+ param.m_session_connect_attrs_sizing= 0;
+
+ stub_alloc_fails_after_count= 1;
+ 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;
+ param.m_session_connect_attrs_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;
+ param.m_session_connect_attrs_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;
+ param.m_session_connect_attrs_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;
+ param.m_session_connect_attrs_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;
+ param.m_session_connect_attrs_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;
+ param.m_session_connect_attrs_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;
+ param.m_session_connect_attrs_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()
+{
+ PFS_atomic::init();
+
+ test_oom();
+
+ PFS_atomic::cleanup();
+}
+
+int main(int, char **)
+{
+ plan(20);
+ MY_INIT("pfs_instr-oom-t");
+ do_all_tests();
+ return 0;
+}
+
diff --git a/storage/perfschema/unittest/pfs_instr-t.cc b/storage/perfschema/unittest/pfs_instr-t.cc
new file mode 100644
index 00000000000..43c143fe30f
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_instr-t.cc
@@ -0,0 +1,421 @@
+/* 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 */
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include <pfs_instr.h>
+#include <pfs_stat.h>
+#include <pfs_global.h>
+#include <pfs_instr_class.h>
+#include <tap.h>
+
+#include <memory.h>
+
+#include "stub_server_misc.h"
+
+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;
+ 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= 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;
+ 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;
+ param.m_digest_sizing= 0;
+ param.m_session_connect_attrs_sizing= 0;
+
+ init_event_name_sizing(& param);
+ rc= init_instruments(& param);
+ ok(rc == 0, "zero init");
+
+ cleanup_instruments();
+}
+
+void test_no_instances()
+{
+ 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_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;
+ param.m_cond_class_sizing= 1;
+ 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;
+ 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;
+ 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;
+ param.m_digest_sizing= 0;
+ param.m_session_connect_attrs_sizing= 0;
+
+ init_event_name_sizing(& param);
+ rc= init_instruments(& param);
+ ok(rc == 0, "no instances init");
+
+ mutex= create_mutex(& dummy_mutex_class, NULL);
+ ok(mutex == NULL, "no mutex");
+ ok(mutex_lost == 1, "lost 1");
+ mutex= create_mutex(& dummy_mutex_class, NULL);
+ ok(mutex == NULL, "no mutex");
+ ok(mutex_lost == 2, "lost 2");
+
+ rwlock= create_rwlock(& dummy_rwlock_class, NULL);
+ ok(rwlock == NULL, "no rwlock");
+ ok(rwlock_lost == 1, "lost 1");
+ rwlock= create_rwlock(& dummy_rwlock_class, NULL);
+ ok(rwlock == NULL, "no rwlock");
+ ok(rwlock_lost == 2, "lost 2");
+
+ cond= create_cond(& dummy_cond_class, NULL);
+ ok(cond == NULL, "no cond");
+ ok(cond_lost == 1, "lost 1");
+ cond= create_cond(& dummy_cond_class, NULL);
+ ok(cond == NULL, "no cond");
+ ok(cond_lost == 2, "lost 2");
+
+ thread= create_thread(& dummy_thread_class, NULL, 0);
+ ok(thread == NULL, "no thread");
+ ok(thread_lost == 1, "lost 1");
+ thread= create_thread(& dummy_thread_class, NULL, 0);
+ ok(thread == NULL, "no thread");
+ ok(thread_lost == 2, "lost 2");
+
+ PFS_thread fake_thread;
+ fake_thread.m_filename_hash_pins= NULL;
+
+ file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true);
+ ok(file == NULL, "no file");
+ ok(file_lost == 1, "lost 1");
+ file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true);
+ ok(file == NULL, "no file");
+ ok(file_lost == 2, "lost 2");
+
+ init_file_hash();
+
+ file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true);
+ ok(file == NULL, "no file");
+ ok(file_lost == 3, "lost 3");
+ file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true);
+ ok(file == NULL, "no file");
+ ok(file_lost == 4, "lost 4");
+
+ char long_file_name[10000];
+ int size= sizeof(long_file_name);
+ memset(long_file_name, 'X', size);
+
+ file= find_or_create_file(& fake_thread, & dummy_file_class, long_file_name, size, true);
+ ok(file == NULL, "no file");
+ ok(file_lost == 5, "lost 5");
+
+ 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, & fake_thread, NULL);
+ ok(table == NULL, "no table");
+ ok(table_lost == 2, "lost 2");
+
+ socket= create_socket(& dummy_socket_class, NULL, NULL, 0);
+ ok(socket == NULL, "no socket");
+ ok(socket_lost == 1, "lost 1");
+ socket= create_socket(& dummy_socket_class, NULL, NULL, 0);
+ 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_events_waits_by_thread();
+
+ cleanup_file_hash();
+ cleanup_instruments();
+}
+
+void test_with_instances()
+{
+ 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_socket_class dummy_socket_class;
+ PFS_table_share dummy_table_share;
+ PFS_mutex *mutex_1;
+ PFS_mutex *mutex_2;
+ PFS_rwlock *rwlock_1;
+ PFS_rwlock *rwlock_2;
+ PFS_cond *cond_1;
+ PFS_cond *cond_2;
+ PFS_thread *thread_1;
+ 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;
+ param.m_cond_class_sizing= 1;
+ 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;
+ param.m_thread_sizing= 2;
+ 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;
+ param.m_digest_sizing= 0;
+ param.m_session_connect_attrs_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");
+ mutex_2= create_mutex(& dummy_mutex_class, NULL);
+ ok(mutex_2 != NULL, "mutex");
+ ok(mutex_lost == 0, "not lost");
+ mutex_2= create_mutex(& dummy_mutex_class, NULL);
+ ok(mutex_2 == NULL, "no mutex");
+ ok(mutex_lost == 1, "lost 1");
+ destroy_mutex(mutex_1);
+ mutex_2= create_mutex(& dummy_mutex_class, NULL);
+ ok(mutex_2 != NULL, "mutex");
+ ok(mutex_lost == 1, "no new loss");
+
+ rwlock_1= create_rwlock(& dummy_rwlock_class, NULL);
+ ok(rwlock_1 != NULL, "rwlock");
+ ok(rwlock_lost == 0, "not lost");
+ rwlock_2= create_rwlock(& dummy_rwlock_class, NULL);
+ ok(rwlock_2 != NULL, "rwlock");
+ ok(rwlock_lost == 0, "not lost");
+ rwlock_2= create_rwlock(& dummy_rwlock_class, NULL);
+ ok(rwlock_2 == NULL, "no rwlock");
+ ok(rwlock_lost == 1, "lost 1");
+ destroy_rwlock(rwlock_1);
+ rwlock_2= create_rwlock(& dummy_rwlock_class, NULL);
+ ok(rwlock_2 != NULL, "rwlock");
+ ok(rwlock_lost == 1, "no new loss");
+
+ cond_1= create_cond(& dummy_cond_class, NULL);
+ ok(cond_1 != NULL, "cond");
+ ok(cond_lost == 0, "not lost");
+ cond_2= create_cond(& dummy_cond_class, NULL);
+ ok(cond_2 != NULL, "cond");
+ ok(cond_lost == 0, "not lost");
+ cond_2= create_cond(& dummy_cond_class, NULL);
+ ok(cond_2 == NULL, "no cond");
+ ok(cond_lost == 1, "lost 1");
+ destroy_cond(cond_1);
+ cond_2= create_cond(& dummy_cond_class, NULL);
+ ok(cond_2 != NULL, "cond");
+ ok(cond_lost == 1, "no new loss");
+
+ thread_1= create_thread(& dummy_thread_class, NULL, 0);
+ ok(thread_1 != NULL, "thread");
+ ok(thread_lost == 0, "not lost");
+ thread_2= create_thread(& dummy_thread_class, NULL, 0);
+ ok(thread_2 != NULL, "thread");
+ ok(thread_lost == 0, "not lost");
+ thread_2= create_thread(& dummy_thread_class, NULL, 0);
+ ok(thread_2 == NULL, "no thread");
+ ok(thread_lost == 1, "lost 1");
+ destroy_thread(thread_1);
+ thread_2= create_thread(& dummy_thread_class, NULL, 0);
+ ok(thread_2 != NULL, "thread");
+ ok(thread_lost == 1, "no new loss");
+
+ PFS_thread fake_thread;
+ fake_thread.m_filename_hash_pins= NULL;
+
+ file_1= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true);
+ ok(file_1 == NULL, "no file");
+ ok(file_lost == 1, "lost 1");
+ file_1= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true);
+ ok(file_1 == NULL, "no file");
+ ok(file_lost == 2, "lost 2");
+
+ init_file_hash();
+ file_lost= 0;
+
+ file_1= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_A", 7, true);
+ ok(file_1 != NULL, "file");
+ ok(file_1->m_file_stat.m_open_count == 1, "open count 1");
+ ok(file_lost == 0, "not lost");
+ file_2= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_A", 7, true);
+ ok(file_1 == file_2, "same file");
+ ok(file_1->m_file_stat.m_open_count == 2, "open count 2");
+ ok(file_lost == 0, "not lost");
+ release_file(file_2);
+ ok(file_1->m_file_stat.m_open_count == 1, "open count 1");
+ file_2= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_B", 7, true);
+ ok(file_2 != NULL, "file");
+ ok(file_lost == 0, "not lost");
+ file_2= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_C", 7, true);
+ ok(file_2 == NULL, "no file");
+ ok(file_lost == 1, "lost");
+ release_file(file_1);
+ /* the file still exists, not destroyed */
+ ok(file_1->m_file_stat.m_open_count == 0, "open count 0");
+ file_2= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_D", 7, true);
+ ok(file_2 == NULL, "no file");
+ ok(file_lost == 2, "lost");
+
+ socket_1= create_socket(& dummy_socket_class, NULL, NULL, 0);
+ ok(socket_1 != NULL, "socket");
+ ok(socket_lost == 0, "not lost");
+ socket_2= create_socket(& dummy_socket_class, NULL, NULL, 0);
+ ok(socket_2 != NULL, "socket");
+ ok(socket_lost == 0, "not lost");
+ socket_2= create_socket(& dummy_socket_class, NULL, NULL, 0);
+ ok(socket_2 == NULL, "no socket");
+ ok(socket_lost == 1, "lost 1");
+ destroy_socket(socket_1);
+ socket_2= create_socket(& dummy_socket_class, NULL, NULL, 0);
+ 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, & fake_thread, NULL);
+ ok(table_2 != NULL, "table");
+ ok(table_lost == 0, "not lost");
+ 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, & 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_events_waits_by_thread();
+
+ cleanup_file_hash();
+ cleanup_instruments();
+}
+
+void do_all_tests()
+{
+ PFS_atomic::init();
+
+ test_no_instruments();
+ test_no_instances();
+ test_with_instances();
+
+ PFS_atomic::cleanup();
+}
+
+int main(int, char **)
+{
+ plan(103);
+ MY_INIT("pfs_instr-t");
+ do_all_tests();
+ return 0;
+}
+
diff --git a/storage/perfschema/unittest/pfs_instr_class-oom-t.cc b/storage/perfschema/unittest/pfs_instr_class-oom-t.cc
new file mode 100644
index 00000000000..f83d017f231
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_instr_class-oom-t.cc
@@ -0,0 +1,73 @@
+/* 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 */
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include <pfs_instr_class.h>
+#include <pfs_global.h>
+#include <tap.h>
+
+#include "stub_pfs_global.h"
+#include "stub_server_misc.h"
+
+void test_oom()
+{
+ int rc;
+
+ rc= init_sync_class(1000, 0, 0);
+ ok(rc == 1, "oom (mutex)");
+ rc= init_sync_class(0, 1000, 0);
+ ok(rc == 1, "oom (rwlock)");
+ rc= init_sync_class(0, 0, 1000);
+ ok(rc == 1, "oom (cond)");
+ rc= init_thread_class(1000);
+ ok(rc == 1, "oom (thread)");
+ rc= init_file_class(1000);
+ 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()
+{
+ PFS_atomic::init();
+
+ test_oom();
+
+ PFS_atomic::cleanup();
+}
+
+int main(int, char **)
+{
+ plan(9);
+ MY_INIT("pfs_instr_info-oom-t");
+ do_all_tests();
+ return 0;
+}
+
diff --git a/storage/perfschema/unittest/pfs_instr_class-t.cc b/storage/perfschema/unittest/pfs_instr_class-t.cc
new file mode 100644
index 00000000000..85dec2dccc4
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_instr_class-t.cc
@@ -0,0 +1,680 @@
+/* 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 */
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include <string.h> // strncpy
+#include <pfs_instr_class.h>
+#include <pfs_instr.h>
+#include <pfs_global.h>
+#include <tap.h>
+
+#include "stub_server_misc.h"
+
+void test_no_registration()
+{
+ int rc;
+ 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_socket_class *socket;
+ /* PFS_table_share *table; */
+
+ rc= init_sync_class(0, 0, 0);
+ ok(rc == 0, "zero init (sync)");
+ rc= init_thread_class(0);
+ 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)");
+
+ key= register_mutex_class("FOO", 3, 0);
+ ok(key == 0, "no mutex registered");
+ key= register_mutex_class("BAR", 3, 0);
+ ok(key == 0, "no mutex registered");
+ key= register_mutex_class("FOO", 3, 0);
+ ok(key == 0, "no mutex registered");
+
+ key= register_rwlock_class("FOO", 3, 0);
+ ok(key == 0, "no rwlock registered");
+ key= register_rwlock_class("BAR", 3, 0);
+ ok(key == 0, "no rwlock registered");
+ key= register_rwlock_class("FOO", 3, 0);
+ ok(key == 0, "no rwlock registered");
+
+ key= register_cond_class("FOO", 3, 0);
+ ok(key == 0, "no cond registered");
+ key= register_cond_class("BAR", 3, 0);
+ ok(key == 0, "no cond registered");
+ key= register_cond_class("FOO", 3, 0);
+ ok(key == 0, "no cond registered");
+
+ thread_key= register_thread_class("FOO", 3, 0);
+ ok(thread_key == 0, "no thread registered");
+ thread_key= register_thread_class("BAR", 3, 0);
+ ok(thread_key == 0, "no thread registered");
+ thread_key= register_thread_class("FOO", 3, 0);
+ ok(thread_key == 0, "no thread registered");
+
+ file_key= register_file_class("FOO", 3, 0);
+ ok(file_key == 0, "no file registered");
+ file_key= register_file_class("BAR", 3, 0);
+ ok(file_key == 0, "no file registered");
+ 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, false, "foo_db", 6, "foo_table", 9);
+ ok(table == NULL, "not created");
+ 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, 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");
+ mutex= find_mutex_class(1);
+ ok(mutex == NULL, "no mutex key 1");
+ mutex= find_mutex_class(9999);
+ ok(mutex == NULL, "no mutex key 9999");
+
+ rwlock= find_rwlock_class(0);
+ ok(rwlock == NULL, "no rwlock key 0");
+ rwlock= find_rwlock_class(1);
+ ok(rwlock == NULL, "no rwlock key 1");
+ rwlock= find_rwlock_class(9999);
+ ok(rwlock == NULL, "no rwlock key 9999");
+
+ cond= find_cond_class(0);
+ ok(cond == NULL, "no cond key 0");
+ cond= find_cond_class(1);
+ ok(cond == NULL, "no cond key 1");
+ cond= find_cond_class(9999);
+ ok(cond == NULL, "no cond key 9999");
+
+ thread= find_thread_class(0);
+ ok(thread == NULL, "no thread key 0");
+ thread= find_thread_class(1);
+ ok(thread == NULL, "no thread key 1");
+ thread= find_thread_class(9999);
+ ok(thread == NULL, "no thread key 9999");
+
+ file= find_file_class(0);
+ ok(file == NULL, "no file key 0");
+ file= find_file_class(1);
+ ok(file == NULL, "no file key 1");
+ 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();
+}
+
+void test_mutex_registration()
+{
+ int rc;
+ PFS_sync_key key;
+ PFS_mutex_class *mutex;
+
+ rc= init_sync_class(5, 0, 0);
+ ok(rc == 0, "room for 5 mutex");
+
+ key= register_mutex_class("FOO", 3, 0);
+ ok(key == 1, "foo registered");
+ key= register_mutex_class("BAR", 3, 0);
+ ok(key == 2, "bar registered");
+ key= register_mutex_class("FOO", 3, 0);
+ ok(key == 1, "foo re registered");
+ key= register_mutex_class("M-3", 3, 0);
+ ok(key == 3, "M-3 registered");
+ key= register_mutex_class("M-4", 3, 0);
+ ok(key == 4, "M-4 registered");
+ key= register_mutex_class("M-5", 3, 0);
+ ok(key == 5, "M-5 registered");
+ ok(mutex_class_lost == 0, "lost nothing");
+ key= register_mutex_class("M-6", 3, 0);
+ ok(key == 0, "M-6 not registered");
+ ok(mutex_class_lost == 1, "lost 1 mutex");
+ key= register_mutex_class("M-7", 3, 0);
+ ok(key == 0, "M-7 not registered");
+ ok(mutex_class_lost == 2, "lost 2 mutex");
+ key= register_mutex_class("M-3", 3, 0);
+ ok(key == 3, "M-3 re registered");
+ ok(mutex_class_lost == 2, "lost 2 mutex");
+ key= register_mutex_class("M-5", 3, 0);
+ ok(key == 5, "M-5 re registered");
+ ok(mutex_class_lost == 2, "lost 2 mutex");
+
+ mutex= find_mutex_class(0);
+ ok(mutex == NULL, "no key 0");
+ mutex= find_mutex_class(3);
+ ok(mutex != NULL, "found key 3");
+ ok(strncmp(mutex->m_name, "M-3", 3) == 0, "key 3 is M-3");
+ ok(mutex->m_name_length == 3, "name length 3");
+ mutex= find_mutex_class(9999);
+ ok(mutex == NULL, "no key 9999");
+
+ cleanup_sync_class();
+}
+
+void test_rwlock_registration()
+{
+ int rc;
+ PFS_sync_key key;
+ PFS_rwlock_class *rwlock;
+
+ rc= init_sync_class(0, 5, 0);
+ ok(rc == 0, "room for 5 rwlock");
+
+ key= register_rwlock_class("FOO", 3, 0);
+ ok(key == 1, "foo registered");
+ key= register_rwlock_class("BAR", 3, 0);
+ ok(key == 2, "bar registered");
+ key= register_rwlock_class("FOO", 3, 0);
+ ok(key == 1, "foo re registered");
+ key= register_rwlock_class("RW-3", 4, 0);
+ ok(key == 3, "RW-3 registered");
+ key= register_rwlock_class("RW-4", 4, 0);
+ ok(key == 4, "RW-4 registered");
+ key= register_rwlock_class("RW-5", 4, 0);
+ ok(key == 5, "RW-5 registered");
+ key= register_rwlock_class("RW-6", 4, 0);
+ ok(key == 0, "RW-6 not registered");
+ key= register_rwlock_class("RW-7", 4, 0);
+ ok(key == 0, "RW-7 not registered");
+ key= register_rwlock_class("RW-3", 4, 0);
+ ok(key == 3, "RW-3 re registered");
+ key= register_rwlock_class("RW-5", 4, 0);
+ ok(key == 5, "RW-5 re registered");
+
+ rwlock= find_rwlock_class(0);
+ ok(rwlock == NULL, "no key 0");
+ rwlock= find_rwlock_class(3);
+ ok(rwlock != NULL, "found key 3");
+ ok(strncmp(rwlock->m_name, "RW-3", 4) == 0, "key 3 is RW-3");
+ ok(rwlock->m_name_length == 4, "name length 4");
+ rwlock= find_rwlock_class(9999);
+ ok(rwlock == NULL, "no key 9999");
+
+ cleanup_sync_class();
+}
+
+void test_cond_registration()
+{
+ int rc;
+ PFS_sync_key key;
+ PFS_cond_class *cond;
+
+ rc= init_sync_class(0, 0, 5);
+ ok(rc == 0, "room for 5 cond");
+
+ key= register_cond_class("FOO", 3, 0);
+ ok(key == 1, "foo registered");
+ key= register_cond_class("BAR", 3, 0);
+ ok(key == 2, "bar registered");
+ key= register_cond_class("FOO", 3, 0);
+ ok(key == 1, "foo re registered");
+ key= register_cond_class("C-3", 3, 0);
+ ok(key == 3, "C-3 registered");
+ key= register_cond_class("C-4", 3, 0);
+ ok(key == 4, "C-4 registered");
+ key= register_cond_class("C-5", 3, 0);
+ ok(key == 5, "C-5 registered");
+ key= register_cond_class("C-6", 3, 0);
+ ok(key == 0, "C-6 not registered");
+ key= register_cond_class("C-7", 3, 0);
+ ok(key == 0, "C-7 not registered");
+ key= register_cond_class("C-3", 3, 0);
+ ok(key == 3, "C-3 re registered");
+ key= register_cond_class("C-5", 3, 0);
+ ok(key == 5, "C-5 re registered");
+
+ cond= find_cond_class(0);
+ ok(cond == NULL, "no key 0");
+ cond= find_cond_class(3);
+ ok(cond != NULL, "found key 3");
+ ok(strncmp(cond->m_name, "C-3", 3) == 0, "key 3 is C-3");
+ ok(cond->m_name_length == 3, "name length 3");
+ cond= find_cond_class(9999);
+ ok(cond == NULL, "no key 9999");
+
+ cleanup_sync_class();
+}
+
+void test_thread_registration()
+{
+ int rc;
+ PFS_thread_key key;
+ PFS_thread_class *thread;
+
+ rc= init_thread_class(5);
+ ok(rc == 0, "room for 5 thread");
+
+ key= register_thread_class("FOO", 3, 0);
+ ok(key == 1, "foo registered");
+ key= register_thread_class("BAR", 3, 0);
+ ok(key == 2, "bar registered");
+ key= register_thread_class("FOO", 3, 0);
+ ok(key == 1, "foo re registered");
+ key= register_thread_class("Thread-3", 8, 0);
+ ok(key == 3, "Thread-3 registered");
+ key= register_thread_class("Thread-4", 8, 0);
+ ok(key == 4, "Thread-4 registered");
+ key= register_thread_class("Thread-5", 8, 0);
+ ok(key == 5, "Thread-5 registered");
+ key= register_thread_class("Thread-6", 8, 0);
+ ok(key == 0, "Thread-6 not registered");
+ key= register_thread_class("Thread-7", 8, 0);
+ ok(key == 0, "Thread-7 not registered");
+ key= register_thread_class("Thread-3", 8, 0);
+ ok(key == 3, "Thread-3 re registered");
+ key= register_thread_class("Thread-5", 8, 0);
+ ok(key == 5, "Thread-5 re registered");
+
+ thread= find_thread_class(0);
+ ok(thread == NULL, "no key 0");
+ thread= find_thread_class(3);
+ ok(thread != NULL, "found key 3");
+ ok(strncmp(thread->m_name, "Thread-3", 8) == 0, "key 3 is Thread-3");
+ ok(thread->m_name_length == 8, "name length 8");
+ thread= find_thread_class(9999);
+ ok(thread == NULL, "no key 9999");
+
+ cleanup_thread_class();
+}
+
+void test_file_registration()
+{
+ int rc;
+ PFS_file_key key;
+ PFS_file_class *file;
+
+ rc= init_file_class(5);
+ ok(rc == 0, "room for 5 file");
+
+ key= register_file_class("FOO", 3, 0);
+ ok(key == 1, "foo registered");
+ key= register_file_class("BAR", 3, 0);
+ ok(key == 2, "bar registered");
+ key= register_file_class("FOO", 3, 0);
+ ok(key == 1, "foo re registered");
+ key= register_file_class("File-3", 6, 0);
+ ok(key == 3, "File-3 registered");
+ key= register_file_class("File-4", 6, 0);
+ ok(key == 4, "File-4 registered");
+ key= register_file_class("File-5", 6, 0);
+ ok(key == 5, "File-5 registered");
+ key= register_file_class("File-6", 6, 0);
+ ok(key == 0, "File-6 not registered");
+ key= register_file_class("File-7", 6, 0);
+ ok(key == 0, "File-7 not registered");
+ key= register_file_class("File-3", 6, 0);
+ ok(key == 3, "File-3 re registered");
+ key= register_file_class("File-5", 6, 0);
+ ok(key == 5, "File-5 re registered");
+
+ file= find_file_class(0);
+ ok(file == NULL, "no key 0");
+ file= find_file_class(3);
+ ok(file != NULL, "found key 3");
+ ok(strncmp(file->m_name, "File-3", 6) == 0, "key 3 is File-3");
+ ok(file->m_name_length == 6, "name length 6");
+ file= find_file_class(9999);
+ ok(file == NULL, "no key 9999");
+
+ 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;
+
+ PFS_thread fake_thread;
+ fake_thread.m_table_share_hash_pins= NULL;
+
+ table_share_lost= 0;
+ 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");
+
+ table_share_lost= 0;
+ init_table_share(5);
+ init_table_share_hash();
+
+ 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, 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, 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, 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, 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, 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, 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, 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");
+ ok(table_share_2->m_schema_name_length == 3, "length 3");
+ ok(strncmp(table_share_2->m_table_name, "t2", 2) == 0 , "table t2");
+ ok(table_share_2->m_table_name_length == 2, "length 2");
+
+ cleanup_table_share_hash();
+ cleanup_table_share();
+#endif
+}
+
+#ifdef LATER
+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_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)
+ return false;
+ if (stat->m_max != 0)
+ return false;
+ if (stat->m_sum != 0)
+ return false;
+ return true;
+}
+#endif
+
+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;
+ PFS_rwlock_class *rwlock_1;
+ PFS_rwlock_class *rwlock_2;
+ PFS_rwlock_class *rwlock_3;
+ PFS_cond_class *cond_1;
+ PFS_cond_class *cond_2;
+ PFS_cond_class *cond_3;
+ 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)");
+ rc= init_thread_class(3);
+ 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");
+ key= register_mutex_class("M-2", 3, 0);
+ ok(key == 2, "mutex registered");
+ key= register_mutex_class("M-3", 3, 0);
+ ok(key == 3, "mutex registered");
+
+ key= register_rwlock_class("RW-1", 4, 0);
+ ok(key == 1, "rwlock registered");
+ key= register_rwlock_class("RW-2", 4, 0);
+ ok(key == 2, "rwlock registered");
+ key= register_rwlock_class("RW-3", 4, 0);
+ ok(key == 3, "rwlock registered");
+
+ key= register_cond_class("C-1", 3, 0);
+ ok(key == 1, "cond registered");
+ key= register_cond_class("C-2", 3, 0);
+ ok(key == 2, "cond registered");
+ key= register_cond_class("C-3", 3, 0);
+ ok(key == 3, "cond registered");
+
+ file_key= register_file_class("F-1", 3, 0);
+ ok(file_key == 1, "file registered");
+ file_key= register_file_class("F-2", 3, 0);
+ ok(file_key == 2, "file registered");
+ 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);
+ ok(mutex_2 != NULL, "mutex key 2");
+ mutex_3= find_mutex_class(3);
+ ok(mutex_3 != NULL, "mutex key 3");
+
+ rwlock_1= find_rwlock_class(1);
+ ok(rwlock_1 != NULL, "rwlock key 1");
+ rwlock_2= find_rwlock_class(2);
+ ok(rwlock_2 != NULL, "rwlock key 2");
+ rwlock_3= find_rwlock_class(3);
+ ok(rwlock_3 != NULL, "rwlock key 3");
+
+ cond_1= find_cond_class(1);
+ ok(cond_1 != NULL, "cond key 1");
+ cond_2= find_cond_class(2);
+ ok(cond_2 != NULL, "cond key 2");
+ cond_3= find_cond_class(3);
+ ok(cond_3 != NULL, "cond key 3");
+
+ file_1= find_file_class(1);
+ ok(file_1 != NULL, "file key 1");
+ file_2= find_file_class(2);
+ ok(file_2 != NULL, "file key 2");
+ file_3= find_file_class(3);
+ ok(file_3 != NULL, "file key 3");
+
+ 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()
+{
+ PFS_atomic::init();
+
+ test_no_registration();
+ test_mutex_registration();
+ test_rwlock_registration();
+ test_cond_registration();
+ test_thread_registration();
+ test_file_registration();
+ test_socket_registration();
+ test_table_registration();
+ test_instruments_reset();
+
+ PFS_atomic::cleanup();
+}
+
+int main(int, char **)
+{
+ plan(181);
+ MY_INIT("pfs_instr_info-t");
+ do_all_tests();
+ return 0;
+}
+
diff --git a/storage/perfschema/unittest/pfs_timer-t.cc b/storage/perfschema/unittest/pfs_timer-t.cc
new file mode 100644
index 00000000000..9c9ae0f75f1
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_timer-t.cc
@@ -0,0 +1,122 @@
+/* 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 */
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include <pfs_timer.h>
+#include "my_sys.h"
+#include <tap.h>
+
+void test_timers()
+{
+ ulonglong t1_a;
+ ulonglong t2_a;
+ ulonglong t3_a;
+ ulonglong t4_a;
+ ulonglong t5_a;
+ ulonglong t1_b;
+ ulonglong t2_b;
+ ulonglong t3_b;
+ ulonglong t4_b;
+ ulonglong t5_b;
+
+ init_timers();
+
+ t1_a= get_timer_pico_value(TIMER_NAME_CYCLE);
+ /* Wait 5 seconds */
+ my_sleep(5000000);
+ t1_b= get_timer_pico_value(TIMER_NAME_CYCLE);
+
+ t2_a= get_timer_pico_value(TIMER_NAME_NANOSEC);
+ my_sleep(5000000);
+ t2_b= get_timer_pico_value(TIMER_NAME_NANOSEC);
+
+ t3_a= get_timer_pico_value(TIMER_NAME_MICROSEC);
+ my_sleep(5000000);
+ t3_b= get_timer_pico_value(TIMER_NAME_MICROSEC);
+
+ t4_a= get_timer_pico_value(TIMER_NAME_MILLISEC);
+ my_sleep(5000000);
+ t4_b= get_timer_pico_value(TIMER_NAME_MILLISEC);
+
+ t5_a= get_timer_pico_value(TIMER_NAME_TICK);
+ my_sleep(5000000);
+ t5_b= get_timer_pico_value(TIMER_NAME_TICK);
+
+ /*
+ Print the timer values, for manual inspection by a human.
+ Tests involving low level timers can not be automated.
+ */
+ diag("cycle a: %13llu", t1_a);
+ diag("nano a: %13llu", t2_a);
+ diag("micro a: %13llu", t3_a);
+ diag("milli a: %13llu", t4_a);
+ diag("tick a: %13llu", t5_a);
+
+ diag("cycle b: %13llu", t1_b);
+ diag("nano b: %13llu", t2_b);
+ diag("micro b: %13llu", t3_b);
+ diag("milli b: %13llu", t4_b);
+ diag("tick b: %13llu", t5_b);
+
+ diag("cycle b-a: %13llu", t1_b-t1_a);
+ diag("nano b-a: %13llu", t2_b-t2_a);
+ diag("micro b-a: %13llu", t3_b-t3_a);
+ diag("milli b-a: %13llu", t4_b-t4_a);
+ diag("tick b-a: %13llu", t5_b-t5_a);
+
+ if ((t1_a == 0) && (t1_b == 0))
+ skip(1, "cycle timer not implemented");
+ else
+ ok(t1_b > t1_a, "cycle timer ascending");
+
+ if ((t2_a == 0) && (t2_b == 0))
+ skip(1, "nano timer not implemented");
+ else
+ ok(t2_b > t2_a, "nano timer ascending");
+
+ if ((t3_a == 0) && (t3_b == 0))
+ skip(1, "micro timer not implemented");
+ else
+ ok(t3_b > t3_a, "micro timer ascending");
+
+ if ((t4_a == 0) && (t4_b == 0))
+ skip(1, "milli timer not implemented");
+ else
+ ok(t4_b > t4_a, "milli timer ascending");
+
+ if ((t5_a == 0) && (t5_b == 0))
+ skip(1, "tick timer not implemented");
+ else
+ ok(t5_b > t5_a, "tick timer ascending");
+}
+
+void do_all_tests()
+{
+ PFS_atomic::init();
+
+ test_timers();
+
+ PFS_atomic::cleanup();
+}
+
+int main(int, char **)
+{
+ plan(5);
+ MY_INIT("pfs_timer-t");
+ do_all_tests();
+ return 0;
+}
+
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
new file mode 100644
index 00000000000..34c52e18b5a
--- /dev/null
+++ b/storage/perfschema/unittest/stub_pfs_global.h
@@ -0,0 +1,49 @@
+/* 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 */
+
+#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 size, myf)
+{
+ if (stub_alloc_always_fails)
+ return NULL;
+
+ if (--stub_alloc_fails_after_count <= 0)
+ return NULL;
+
+ 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_print_error(const char *format, ...)
+{
+}
+
diff --git a/storage/perfschema/unittest/stub_print_error.h b/storage/perfschema/unittest/stub_print_error.h
new file mode 100644
index 00000000000..caad24e5257
--- /dev/null
+++ b/storage/perfschema/unittest/stub_print_error.h
@@ -0,0 +1,40 @@
+/* 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 */
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <pfs_global.h>
+
+bool pfs_initialized= false;
+
+void *pfs_malloc(size_t size, myf flags)
+{
+ void *ptr= malloc(size);
+ if (ptr && (flags & MY_ZEROFILL))
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+void pfs_free(void *ptr)
+{
+ if (ptr != NULL)
+ free(ptr);
+}
+
+void pfs_print_error(const char *format, ...)
+{
+ /* Do not pollute the unit test output with annoying messages. */
+}
+
diff --git a/storage/perfschema/unittest/stub_server_misc.h b/storage/perfschema/unittest/stub_server_misc.h
new file mode 100644
index 00000000000..8b008273bd8
--- /dev/null
+++ b/storage/perfschema/unittest/stub_server_misc.h
@@ -0,0 +1,28 @@
+/* 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 */
+
+/*
+ Minimal code to be able to link a unit test.
+*/
+
+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)
+{
+}
+