summaryrefslogtreecommitdiff
path: root/storage/perfschema
diff options
context:
space:
mode:
Diffstat (limited to 'storage/perfschema')
-rw-r--r--storage/perfschema/CMakeLists.txt223
-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.cc351
-rw-r--r--storage/perfschema/ha_perfschema.cc140
-rw-r--r--storage/perfschema/ha_perfschema.h105
-rw-r--r--storage/perfschema/pfs.cc4514
-rw-r--r--storage/perfschema/pfs.h8
-rw-r--r--storage/perfschema/pfs_account.cc583
-rw-r--r--storage/perfschema/pfs_account.h122
-rw-r--r--storage/perfschema/pfs_atomic.cc83
-rw-r--r--storage/perfschema/pfs_atomic.h122
-rw-r--r--storage/perfschema/pfs_autosize.cc386
-rw-r--r--storage/perfschema/pfs_check.cc62
-rw-r--r--storage/perfschema/pfs_column_types.h110
-rw-r--r--storage/perfschema/pfs_column_values.cc11
-rw-r--r--storage/perfschema/pfs_column_values.h13
-rw-r--r--storage/perfschema/pfs_con_slice.cc119
-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.cc388
-rw-r--r--storage/perfschema/pfs_digest.h86
-rw-r--r--storage/perfschema/pfs_engine_table.cc852
-rw-r--r--storage/perfschema/pfs_engine_table.h213
-rw-r--r--storage/perfschema/pfs_events.h62
-rw-r--r--storage/perfschema/pfs_events_stages.cc252
-rw-r--r--storage/perfschema/pfs_events_stages.h65
-rw-r--r--storage/perfschema/pfs_events_statements.cc290
-rw-r--r--storage/perfschema/pfs_events_statements.h133
-rw-r--r--storage/perfschema/pfs_events_waits.cc178
-rw-r--r--storage/perfschema/pfs_events_waits.h159
-rw-r--r--storage/perfschema/pfs_global.cc174
-rw-r--r--storage/perfschema/pfs_global.h54
-rw-r--r--storage/perfschema/pfs_host.cc389
-rw-r--r--storage/perfschema/pfs_host.h113
-rw-r--r--storage/perfschema/pfs_instr.cc1973
-rw-r--r--storage/perfschema/pfs_instr.h522
-rw-r--r--storage/perfschema/pfs_instr_class.cc1007
-rw-r--r--storage/perfschema/pfs_instr_class.h382
-rw-r--r--storage/perfschema/pfs_lock.h131
-rw-r--r--storage/perfschema/pfs_server.cc179
-rw-r--r--storage/perfschema/pfs_server.h225
-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.h720
-rw-r--r--storage/perfschema/pfs_timer.cc207
-rw-r--r--storage/perfschema/pfs_timer.h113
-rw-r--r--storage/perfschema/pfs_user.cc382
-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.cc123
-rw-r--r--storage/perfschema/table_accounts.h78
-rw-r--r--storage/perfschema/table_all_instr.cc128
-rw-r--r--storage/perfschema/table_all_instr.h75
-rw-r--r--storage/perfschema/table_esgs_by_account_by_event_name.cc192
-rw-r--r--storage/perfschema/table_esgs_by_account_by_event_name.h123
-rw-r--r--storage/perfschema/table_esgs_by_host_by_event_name.cc192
-rw-r--r--storage/perfschema/table_esgs_by_host_by_event_name.h123
-rw-r--r--storage/perfschema/table_esgs_by_thread_by_event_name.cc192
-rw-r--r--storage/perfschema/table_esgs_by_thread_by_event_name.h127
-rw-r--r--storage/perfschema/table_esgs_by_user_by_event_name.cc192
-rw-r--r--storage/perfschema/table_esgs_by_user_by_event_name.h128
-rw-r--r--storage/perfschema/table_esgs_global_by_event_name.cc174
-rw-r--r--storage/perfschema/table_esgs_global_by_event_name.h91
-rw-r--r--storage/perfschema/table_esms_by_account_by_event_name.cc214
-rw-r--r--storage/perfschema/table_esms_by_account_by_event_name.h123
-rw-r--r--storage/perfschema/table_esms_by_digest.cc212
-rw-r--r--storage/perfschema/table_esms_by_digest.h93
-rw-r--r--storage/perfschema/table_esms_by_host_by_event_name.cc214
-rw-r--r--storage/perfschema/table_esms_by_host_by_event_name.h123
-rw-r--r--storage/perfschema/table_esms_by_thread_by_event_name.cc215
-rw-r--r--storage/perfschema/table_esms_by_thread_by_event_name.h127
-rw-r--r--storage/perfschema/table_esms_by_user_by_event_name.cc214
-rw-r--r--storage/perfschema/table_esms_by_user_by_event_name.h123
-rw-r--r--storage/perfschema/table_esms_global_by_event_name.cc198
-rw-r--r--storage/perfschema/table_esms_global_by_event_name.h91
-rw-r--r--storage/perfschema/table_events_stages.cc502
-rw-r--r--storage/perfschema/table_events_stages.h206
-rw-r--r--storage/perfschema/table_events_statements.cc901
-rw-r--r--storage/perfschema/table_events_statements.h290
-rw-r--r--storage/perfschema/table_events_waits.cc560
-rw-r--r--storage/perfschema/table_events_waits.h31
-rw-r--r--storage/perfschema/table_events_waits_summary.cc429
-rw-r--r--storage/perfschema/table_events_waits_summary.h133
-rw-r--r--storage/perfschema/table_ews_by_account_by_event_name.cc247
-rw-r--r--storage/perfschema/table_ews_by_account_by_event_name.h134
-rw-r--r--storage/perfschema/table_ews_by_host_by_event_name.cc248
-rw-r--r--storage/perfschema/table_ews_by_host_by_event_name.h134
-rw-r--r--storage/perfschema/table_ews_by_thread_by_event_name.cc262
-rw-r--r--storage/perfschema/table_ews_by_thread_by_event_name.h133
-rw-r--r--storage/perfschema/table_ews_by_user_by_event_name.cc248
-rw-r--r--storage/perfschema/table_ews_by_user_by_event_name.h134
-rw-r--r--storage/perfschema/table_ews_global_by_event_name.cc390
-rw-r--r--storage/perfschema/table_ews_global_by_event_name.h84
-rw-r--r--storage/perfschema/table_file_instances.cc30
-rw-r--r--storage/perfschema/table_file_instances.h4
-rw-r--r--storage/perfschema/table_file_summary.cc372
-rw-r--r--storage/perfschema/table_file_summary_by_event_name.cc245
-rw-r--r--storage/perfschema/table_file_summary_by_event_name.h (renamed from storage/perfschema/table_file_summary.h)88
-rw-r--r--storage/perfschema/table_file_summary_by_instance.cc266
-rw-r--r--storage/perfschema/table_file_summary_by_instance.h97
-rw-r--r--storage/perfschema/table_helper.cc360
-rw-r--r--storage/perfschema/table_helper.h520
-rw-r--r--storage/perfschema/table_host_cache.cc353
-rw-r--r--storage/perfschema/table_host_cache.h142
-rw-r--r--storage/perfschema/table_hosts.cc126
-rw-r--r--storage/perfschema/table_hosts.h78
-rw-r--r--storage/perfschema/table_os_global_by_type.cc234
-rw-r--r--storage/perfschema/table_os_global_by_type.h128
-rw-r--r--storage/perfschema/table_performance_timers.cc47
-rw-r--r--storage/perfschema/table_performance_timers.h2
-rw-r--r--storage/perfschema/table_session_account_connect_attrs.cc74
-rw-r--r--storage/perfschema/table_session_account_connect_attrs.h50
-rw-r--r--storage/perfschema/table_session_connect.cc286
-rw-r--r--storage/perfschema/table_session_connect.h78
-rw-r--r--storage/perfschema/table_session_connect_attrs.cc47
-rw-r--r--storage/perfschema/table_session_connect_attrs.h47
-rw-r--r--storage/perfschema/table_setup_actors.cc258
-rw-r--r--storage/perfschema/table_setup_actors.h104
-rw-r--r--storage/perfschema/table_setup_consumers.cc88
-rw-r--r--storage/perfschema/table_setup_consumers.h7
-rw-r--r--storage/perfschema/table_setup_instruments.cc221
-rw-r--r--storage/perfschema/table_setup_instruments.h29
-rw-r--r--storage/perfschema/table_setup_objects.cc326
-rw-r--r--storage/perfschema/table_setup_objects.h107
-rw-r--r--storage/perfschema/table_setup_timers.cc38
-rw-r--r--storage/perfschema/table_setup_timers.h5
-rw-r--r--storage/perfschema/table_socket_instances.cc195
-rw-r--r--storage/perfschema/table_socket_instances.h100
-rw-r--r--storage/perfschema/table_socket_summary_by_event_name.cc241
-rw-r--r--storage/perfschema/table_socket_summary_by_event_name.h90
-rw-r--r--storage/perfschema/table_socket_summary_by_instance.cc258
-rw-r--r--storage/perfschema/table_socket_summary_by_instance.h93
-rw-r--r--storage/perfschema/table_sync_instances.cc94
-rw-r--r--storage/perfschema/table_sync_instances.h16
-rw-r--r--storage/perfschema/table_threads.cc324
-rw-r--r--storage/perfschema/table_threads.h72
-rw-r--r--storage/perfschema/table_tiws_by_index_usage.cc334
-rw-r--r--storage/perfschema/table_tiws_by_index_usage.h121
-rw-r--r--storage/perfschema/table_tiws_by_table.cc312
-rw-r--r--storage/perfschema/table_tiws_by_table.h91
-rw-r--r--storage/perfschema/table_tlws_by_table.cc464
-rw-r--r--storage/perfschema/table_tlws_by_table.h91
-rw-r--r--storage/perfschema/table_users.cc126
-rw-r--r--storage/perfschema/table_users.h78
-rw-r--r--storage/perfschema/unittest/CMakeLists.txt18
-rw-r--r--storage/perfschema/unittest/conf.txt3
-rw-r--r--storage/perfschema/unittest/pfs-t.cc616
-rw-r--r--storage/perfschema/unittest/pfs_account-oom-t.cc113
-rw-r--r--storage/perfschema/unittest/pfs_connect_attr-t.cc345
-rw-r--r--storage/perfschema/unittest/pfs_host-oom-t.cc113
-rw-r--r--storage/perfschema/unittest/pfs_instr-oom-t.cc489
-rw-r--r--storage/perfschema/unittest/pfs_instr-t.cc231
-rw-r--r--storage/perfschema/unittest/pfs_instr_class-oom-t.cc21
-rw-r--r--storage/perfschema/unittest/pfs_instr_class-t.cc226
-rw-r--r--storage/perfschema/unittest/pfs_misc-t.cc72
-rw-r--r--storage/perfschema/unittest/pfs_server_stubs.cc47
-rw-r--r--storage/perfschema/unittest/pfs_timer-t.cc32
-rw-r--r--storage/perfschema/unittest/pfs_user-oom-t.cc112
-rw-r--r--storage/perfschema/unittest/stub_pfs_defaults.h (renamed from storage/perfschema/unittest/stub_server_misc.h)12
-rw-r--r--storage/perfschema/unittest/stub_pfs_global.h41
-rw-r--r--storage/perfschema/unittest/stub_print_error.h20
174 files changed, 34807 insertions, 4408 deletions
diff --git a/storage/perfschema/CMakeLists.txt b/storage/perfschema/CMakeLists.txt
index f8ee1ca76f4..7db67700fac 100644
--- a/storage/perfschema/CMakeLists.txt
+++ b/storage/perfschema/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -16,64 +16,175 @@
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/sql
- ${CMAKE_SOURCE_DIR}/regex
- ${CMAKE_SOURCE_DIR}/extra/yassl/include)
+ ${CMAKE_BINARY_DIR}/sql
+ ${PCRE_INCLUDES}
+ ${SSL_INCLUDE_DIRS})
ADD_DEFINITIONS(-DMYSQL_SERVER)
-SET(PERFSCHEMA_SOURCES ha_perfschema.h
- pfs_column_types.h
- pfs_column_values.h
- pfs_events_waits.h
- pfs_global.h
- pfs.h
- pfs_instr.h
- pfs_instr_class.h
- pfs_lock.h
- pfs_atomic.h
- pfs_server.h
- pfs_stat.h
- pfs_engine_table.h
- pfs_timer.h
- table_all_instr.h
- table_events_waits.h
- table_events_waits_summary.h
- table_ews_global_by_event_name.h
- table_file_instances.h
- table_file_summary.h
- table_performance_timers.h
- table_setup_consumers.h
- table_setup_instruments.h
- table_setup_timers.h
- table_sync_instances.h
- table_threads.h
- ha_perfschema.cc
- pfs.cc
- pfs_column_values.cc
- pfs_events_waits.cc
- pfs_global.cc
- pfs_instr.cc
- pfs_instr_class.cc
- pfs_server.cc
- pfs_engine_table.cc
- pfs_timer.cc
- table_all_instr.cc
- table_events_waits.cc
- table_events_waits_summary.cc
- table_ews_global_by_event_name.cc
- table_file_instances.cc
- table_file_summary.cc
- table_performance_timers.cc
- table_setup_consumers.cc
- table_setup_instruments.cc
- table_setup_timers.cc
- table_sync_instances.cc
- table_threads.cc
- pfs_atomic.cc
- pfs_check.cc
+#
+# Maintainer: keep this list sorted, to avoid merge collisions.
+# Tip: ls -1 *.h, ls -1 *.cc
+#
+SET(PERFSCHEMA_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_autosize.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)
- ADD_SUBDIRECTORY(unittest)
-ENDIF()
+IF (TARGET perfschema)
+ ADD_DEPENDENCIES(perfschema GenServerSource)
+ IF(WITH_UNIT_TESTS)
+ ADD_SUBDIRECTORY(unittest)
+ ENDIF(WITH_UNIT_TESTS)
+ENDIF(TARGET perfschema)
diff --git a/storage/perfschema/cursor_by_account.cc b/storage/perfschema/cursor_by_account.cc
new file mode 100644
index 00000000000..2e75b8d51bd
--- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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..150615b9c54
--- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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..d16f8b24b8e
--- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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..db33bbad808
--- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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..2fa9202fcf0
--- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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..5a77edf325f
--- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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..2d5399cdac1
--- /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, Fifth Floor, 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..b5059918f7f
--- /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, Fifth Floor, 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..37ecbf17fee
--- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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..d6e997766b6
--- /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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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..dcf25c79706
--- /dev/null
+++ b/storage/perfschema/gen_pfs_lex_token.cc
@@ -0,0 +1,351 @@
+/*
+ Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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
+/** Generated token. */
+struct gen_lex_token_string
+{
+ const char *m_token_string;
+ int m_token_length;
+ bool m_append_space;
+ bool m_start_expr;
+};
+
+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);
+ compiled_token_array[tok].m_append_space= true;
+ compiled_token_array[tok].m_start_expr= false;
+}
+
+void set_start_expr_token(int tok)
+{
+ compiled_token_array[tok].m_start_expr= true;
+}
+
+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;
+ compiled_token_array[tok].m_append_space= true;
+ compiled_token_array[tok].m_start_expr= false;
+ }
+
+ /*
+ 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;
+ compiled_token_array[tok].m_append_space= true;
+ }
+
+ 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");
+
+ /*
+ Fix whitespace for some special tokens.
+ */
+
+ /*
+ The lexer parses "@@variable" as '@', '@', 'variable',
+ returning a token for '@' alone.
+
+ This is incorrect, '@' is not really a token,
+ because the syntax "@ @ variable" (with spaces) is not accepted:
+ The lexer keeps some internal state after the '@' fake token.
+
+ To work around this, digest text are printed as "@@variable".
+ */
+ compiled_token_array[(int) '@'].m_append_space= false;
+
+ /*
+ Define additional properties for tokens.
+
+ List all the token that are followed by an expression.
+ This is needed to differentiate unary from binary
+ '+' and '-' operators, because we want to:
+ - reduce <unary +> <NUM> to <?>,
+ - preserve <...> <binary +> <NUM> as is.
+ */
+ set_start_expr_token('(');
+ set_start_expr_token(',');
+ set_start_expr_token(EVERY_SYM);
+ set_start_expr_token(AT_SYM);
+ set_start_expr_token(STARTS_SYM);
+ set_start_expr_token(ENDS_SYM);
+ set_start_expr_token(DEFAULT);
+ set_start_expr_token(RETURN_SYM);
+ set_start_expr_token(IF_SYM);
+ set_start_expr_token(ELSEIF_SYM);
+ set_start_expr_token(CASE_SYM);
+ set_start_expr_token(WHEN_SYM);
+ set_start_expr_token(WHILE_SYM);
+ set_start_expr_token(UNTIL_SYM);
+ set_start_expr_token(SELECT_SYM);
+
+ set_start_expr_token(OR_SYM);
+ set_start_expr_token(OR2_SYM);
+ set_start_expr_token(XOR);
+ set_start_expr_token(AND_SYM);
+ set_start_expr_token(AND_AND_SYM);
+ set_start_expr_token(NOT_SYM);
+ set_start_expr_token(BETWEEN_SYM);
+ set_start_expr_token(LIKE);
+ set_start_expr_token(REGEXP);
+
+ set_start_expr_token('|');
+ set_start_expr_token('&');
+ set_start_expr_token(SHIFT_LEFT);
+ set_start_expr_token(SHIFT_RIGHT);
+ set_start_expr_token('+');
+ set_start_expr_token('-');
+ set_start_expr_token(INTERVAL_SYM);
+ set_start_expr_token('*');
+ set_start_expr_token('/');
+ set_start_expr_token('%');
+ set_start_expr_token(DIV_SYM);
+ set_start_expr_token(MOD_SYM);
+ set_start_expr_token('^');
+}
+
+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, %s, %s},\n",
+ tok,
+ tok,
+ compiled_token_array[tok].m_append_space ? "true" : "false",
+ compiled_token_array[tok].m_start_expr ? "true" : "false");
+ }
+
+ printf("/* PART 2: named tokens. */\n");
+
+ for (tok= 256; tok<= max_token_seen; tok++)
+ {
+ printf("/* %03d */ { \"%s\", %d, %s, %s},\n",
+ tok,
+ compiled_token_array[tok].m_token_string,
+ compiled_token_array[tok].m_token_length,
+ compiled_token_array[tok].m_append_space ? "true" : "false",
+ compiled_token_array[tok].m_start_expr ? "true" : "false");
+ }
+
+ printf("/* DUMMY */ { \"\", 0, false, false}\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(" bool m_append_space;\n");
+ printf(" bool m_start_expr;\n");
+ printf("};\n");
+ printf("typedef struct lex_token_string lex_token_string;\n");
+
+ compute_tokens();
+ print_tokens();
+
+ return 0;
+}
+
diff --git a/storage/perfschema/ha_perfschema.cc b/storage/perfschema/ha_perfschema.cc
index 647f7b8a7c2..42b452ca4dd 100644
--- a/storage/perfschema/ha_perfschema.cc
+++ b/storage/perfschema/ha_perfschema.cc
@@ -18,16 +18,18 @@
Performance schema storage engine (implementation).
*/
-#include "my_global.h"
+#include "sql_plugin.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
/*
@@ -69,6 +71,23 @@ find_table_share(const char *db, const char *name)
DBUG_RETURN(result);
}
+static int pfs_discover_table(handlerton *hton, THD *thd, TABLE_SHARE *share)
+{
+ const PFS_engine_table_share *pfs_share;
+
+ if ((pfs_share= find_table_share(share->db.str, share->table_name.str)))
+ return share->init_from_sql_statement_string(thd, false,
+ pfs_share->sql.str,
+ pfs_share->sql.length);
+ return HA_ERR_NO_SUCH_TABLE;
+}
+
+static int pfs_discover_table_existence(handlerton *hton, const char *db,
+ const char *table_name)
+{
+ return MY_TEST(find_table_share(db, table_name));
+}
+
static int pfs_init_func(void *p)
{
DBUG_ENTER("pfs_init_func");
@@ -80,7 +99,8 @@ static int pfs_init_func(void *p)
pfs_hton->show_status= pfs_show_status;
pfs_hton->flags= HTON_ALTER_NOT_SUPPORTED |
HTON_TEMPORARY_NOT_SUPPORTED |
- HTON_NO_PARTITION;
+ HTON_NO_PARTITION |
+ HTON_NO_BINLOG_ROW_OPT;
/*
As long as the server implementation keeps using legacy_db_type,
@@ -96,6 +116,9 @@ static int pfs_init_func(void *p)
the performance schema. See Bug#43039.
*/
pfs_hton->db_type= DB_TYPE_PERFORMANCE_SCHEMA;
+ pfs_hton->discover_table= pfs_discover_table;
+ pfs_hton->discover_table_existence= pfs_discover_table_existence;
+ pfs_hton->discover_table_names= pfs_discover_table_names;
PFS_engine_table_share::init_all_locks();
@@ -125,6 +148,8 @@ static struct st_mysql_show_var pfs_status_vars[]=
(char*) &thread_class_lost, SHOW_LONG_NOFLUSH},
{"Performance_schema_file_classes_lost",
(char*) &file_class_lost, SHOW_LONG_NOFLUSH},
+ {"Performance_schema_socket_classes_lost",
+ (char*) &socket_class_lost, SHOW_LONG_NOFLUSH},
{"Performance_schema_mutex_instances_lost",
(char*) &mutex_lost, SHOW_LONG},
{"Performance_schema_rwlock_instances_lost",
@@ -137,6 +162,8 @@ static struct st_mysql_show_var pfs_status_vars[]=
(char*) &file_lost, SHOW_LONG},
{"Performance_schema_file_handles_lost",
(char*) &file_handle_lost, SHOW_LONG},
+ {"Performance_schema_socket_instances_lost",
+ (char*) &socket_lost, SHOW_LONG},
{"Performance_schema_locker_lost",
(char*) &locker_lost, SHOW_LONG},
/* table shares, can be flushed */
@@ -145,6 +172,20 @@ static struct st_mysql_show_var pfs_status_vars[]=
/* table handles, can be flushed */
{"Performance_schema_table_handles_lost",
(char*) &table_lost, SHOW_LONG},
+ {"Performance_schema_hosts_lost",
+ (char*) &host_lost, SHOW_LONG},
+ {"Performance_schema_users_lost",
+ (char*) &user_lost, SHOW_LONG},
+ {"Performance_schema_accounts_lost",
+ (char*) &account_lost, SHOW_LONG},
+ {"Performance_schema_stage_classes_lost",
+ (char*) &stage_class_lost, SHOW_LONG},
+ {"Performance_schema_statement_classes_lost",
+ (char*) &statement_class_lost, SHOW_LONG},
+ {"Performance_schema_digest_lost",
+ (char*) &digest_lost, SHOW_LONG},
+ {"Performance_schema_session_connect_attrs_lost",
+ (char*) &session_connect_attrs_lost, SHOW_LONG},
{NullS, NullS, SHOW_LONG}
};
@@ -184,8 +225,8 @@ maria_declare_plugin(perfschema)
0x0001,
pfs_status_vars,
NULL,
- "0.1",
- MariaDB_PLUGIN_MATURITY_GAMMA /* because MySQL-5.5 is RC */
+ "5.6.40",
+ MariaDB_PLUGIN_MATURITY_STABLE
}
maria_declare_plugin_end;
@@ -196,15 +237,6 @@ ha_perfschema::ha_perfschema(handlerton *hton, TABLE_SHARE *share)
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");
@@ -217,8 +249,6 @@ int ha_perfschema::open(const char *name, int mode, uint test_if_locked)
thr_lock_data_init(m_table_share->m_thr_lock_ptr, &m_thr_lock, NULL);
ref_length= m_table_share->m_ref_length;
- psi_open();
-
DBUG_RETURN(0);
}
@@ -229,8 +259,6 @@ int ha_perfschema::close(void)
delete m_table;
m_table= NULL;
- psi_close();
-
DBUG_RETURN(0);
}
@@ -239,17 +267,12 @@ int ha_perfschema::write_row(uchar *buf)
int result;
DBUG_ENTER("ha_perfschema::write_row");
+ if (!pfs_initialized)
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
- ha_statistic_increment(&SSV::ha_write_count);
DBUG_ASSERT(m_table_share);
-
- if (m_table_share->m_write_row)
- result= m_table_share->m_write_row(table, buf, table->field);
- else
- {
- result= HA_ERR_WRONG_COMMAND;
- }
-
+ ha_statistic_increment(&SSV::ha_write_count);
+ result= m_table_share->write_row(table, buf, table->field);
DBUG_RETURN(result);
}
@@ -267,12 +290,30 @@ void ha_perfschema::use_hidden_primary_key(void)
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);
+
+ if (is_executed_by_slave())
+ DBUG_RETURN(0);
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;
@@ -287,6 +328,9 @@ int ha_perfschema::rnd_init(bool scan)
else
m_table->reset_position();
+ if (m_table != NULL)
+ m_table->rnd_init(scan);
+
result= m_table ? 0 : HA_ERR_OUT_OF_MEM;
DBUG_RETURN(result);
}
@@ -303,8 +347,15 @@ int ha_perfschema::rnd_end(void)
int ha_perfschema::rnd_next(uchar *buf)
{
DBUG_ENTER("ha_perfschema::rnd_next");
+ if (!pfs_initialized)
+ {
+ table->status= STATUS_NOT_FOUND;
+ 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)
{
@@ -312,6 +363,7 @@ int ha_perfschema::rnd_next(uchar *buf)
if (result == 0)
stats.records++;
}
+ table->status= (result ? STATUS_NOT_FOUND : 0);
DBUG_RETURN(result);
}
@@ -327,11 +379,18 @@ void ha_perfschema::position(const uchar *record)
int ha_perfschema::rnd_pos(uchar *buf, uchar *pos)
{
DBUG_ENTER("ha_perfschema::rnd_pos");
+ if (!pfs_initialized)
+ {
+ table->status= STATUS_NOT_FOUND;
+ 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);
+ table->status= (result ? STATUS_NOT_FOUND : 0);
DBUG_RETURN(result);
}
@@ -340,7 +399,7 @@ int ha_perfschema::info(uint flag)
DBUG_ENTER("ha_perfschema::info");
DBUG_ASSERT(m_table_share);
if (flag & HA_STATUS_VARIABLE)
- stats.records= m_table_share->m_records;
+ stats.records= m_table_share->get_row_count();
if (flag & HA_STATUS_CONST)
ref_length= m_table_share->m_ref_length;
DBUG_RETURN(0);
@@ -351,6 +410,11 @@ int ha_perfschema::delete_all_rows(void)
int result;
DBUG_ENTER("ha_perfschema::delete_all_rows");
+ if (!pfs_initialized)
+ DBUG_RETURN(0);
+
+ if (is_executed_by_slave())
+ DBUG_RETURN(0);
DBUG_ASSERT(m_table_share);
if (m_table_share->m_delete_all_rows)
@@ -362,6 +426,11 @@ int ha_perfschema::delete_all_rows(void)
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)
@@ -389,19 +458,6 @@ 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.
diff --git a/storage/perfschema/ha_perfschema.h b/storage/perfschema/ha_perfschema.h
index 153f3be21ac..9c56fc1928e 100644
--- a/storage/perfschema/ha_perfschema.h
+++ b/storage/perfschema/ha_perfschema.h
@@ -20,10 +20,6 @@
#include "table.h"
#include "sql_class.h"
-#ifdef USE_PRAGMA_INTERFACE
-#pragma interface /* gcc class implementation */
-#endif
-
/**
@file storage/perfschema/ha_perfschema.h
Performance schema storage engine (declarations).
@@ -34,22 +30,24 @@
*/
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
{
@@ -72,13 +70,9 @@ public:
Without HA_FAST_KEY_READ, the optimizer reads all columns and never
calls ::rnd_pos(), so it is guaranteed to return only thread <n>
records.
- We use HA_HAS_OWN_BINLOGGING to stop changes to this table to
- be logged to slaves (as enabled performance tracking on all slaves
- is probably not what anyone wants)
*/
- return (HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_NO_AUTO_INCREMENT |
- HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
- HA_HAS_OWN_BINLOGGING | HA_NO_BLOBS);
+ return HA_NO_TRANSACTIONS | HA_REC_NOT_IN_SEQ | HA_NO_AUTO_INCREMENT |
+ HA_PRIMARY_KEY_REQUIRED_FOR_DELETE;
}
/**
@@ -106,30 +100,80 @@ public:
double scan_time(void)
{ return 1.0; }
+ /**
+ Open a performance schema table.
+ @param name the table to open
+ @param mode unused
+ @param test_if_locked unused
+ @return 0 on success
+ */
int open(const char *name, int mode, uint test_if_locked);
+ /**
+ Close a table handle.
+ @sa open.
+ */
int close(void);
+ /**
+ Write a row.
+ @param buf the row to write
+ @return 0 on success
+ */
int write_row(uchar *buf);
void use_hidden_primary_key();
+ /**
+ Update a row.
+ @param old_data the row old values
+ @param new_data the row new values
+ @return 0 on success
+ */
int update_row(const uchar *old_data, uchar *new_data);
+ /**
+ Delete a row.
+ @param buf the row to delete
+ @return 0 on success
+ */
+ int delete_row(const uchar *buf);
+
int rnd_init(bool scan);
+ /**
+ Scan end.
+ @sa rnd_init.
+ */
int rnd_end(void);
+ /**
+ Iterator, fetch the next row.
+ @param[out] buf the row fetched.
+ @return 0 on success
+ */
int rnd_next(uchar *buf);
+ /**
+ Iterator, fetch the row at a given position.
+ @param[out] buf the row fetched.
+ @param pos the row position
+ @return 0 on success
+ */
int rnd_pos(uchar *buf, uchar *pos);
+ /**
+ Read the row current position.
+ @param record the current row
+ */
void position(const uchar *record);
int info(uint);
int delete_all_rows(void);
+ int truncate();
+
int delete_table(const char *from);
int rename_table(const char * from, const char * to);
@@ -153,6 +197,39 @@ public:
virtual void print_error(int error, myf errflags);
private:
+ /**
+ Check if the caller is a replication thread or the caller is called
+ by a client thread executing base64 encoded BINLOG'... statement.
+
+ In theory, performance schema tables are not supposed to be replicated.
+ This is true and enforced starting with MySQL 5.6.10.
+ In practice, in previous versions such as MySQL 5.5 (GA) or earlier 5.6
+ (non GA) DML on performance schema tables could end up written in the binlog,
+ both in STATEMENT and ROW format.
+ While these records are not supposed to be there, they are found when:
+ - performing replication from a 5.5 master to a 5.6 slave during
+ upgrades
+ - performing replication from 5.5 (performance_schema enabled)
+ to a 5.6 slave
+ - performing point in time recovery in 5.6 with old archived logs.
+
+ This API detects when the code calling the performance schema storage
+ engine is a slave thread or whether the code calling isthe client thread
+ executing a BINLOG'.. statement.
+
+ This API acts as a late filter for the above mentioned cases.
+
+ For ROW format, @see Rows_log_event::do_apply_event()
+
+ */
+ bool is_executed_by_slave() const
+ {
+ DBUG_ASSERT(table != NULL);
+ DBUG_ASSERT(table->in_use != NULL);
+ return table->in_use->slave_thread;
+
+ }
+
/** MySQL lock */
THR_LOCK_DATA m_thr_lock;
/** Performance schema table share for this table handler. */
diff --git a/storage/perfschema/pfs.cc b/storage/perfschema/pfs.cc
index 572f31093ef..e73e65ce059 100644
--- a/storage/perfschema/pfs.cc
+++ b/storage/perfschema/pfs.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,19 +17,31 @@
@file storage/perfschema/pfs.cc
The performance schema implementation of all instruments.
*/
-
#include "my_global.h"
+#include "thr_lock.h"
+#include "mysql/psi/psi.h"
+#include "mysql/psi/mysql_thread.h"
+#include "my_pthread.h"
+#include "sql_const.h"
#include "pfs.h"
#include "pfs_instr_class.h"
#include "pfs_instr.h"
+#include "pfs_host.h"
+#include "pfs_user.h"
+#include "pfs_account.h"
#include "pfs_global.h"
#include "pfs_column_values.h"
#include "pfs_timer.h"
#include "pfs_events_waits.h"
-
-/* Pending WL#4895 PERFORMANCE_SCHEMA Instrumenting Table IO */
-#undef HAVE_TABLE_WAIT
-
+#include "pfs_events_stages.h"
+#include "pfs_events_statements.h"
+#include "pfs_setup_actor.h"
+#include "pfs_setup_object.h"
+#include "sql_error.h"
+#include "sp_head.h"
+#include "pfs_digest.h"
+
+using std::min;
/**
@page PAGE_PERFORMANCE_SCHEMA The Performance Schema main page
MySQL PERFORMANCE_SCHEMA implementation.
@@ -300,8 +312,7 @@
*/
/**
- @page PAGE_INSTRUMENTATION_INTERFACE
- Performance schema: instrumentation interface page.
+ @page PAGE_INSTRUMENTATION_INTERFACE Performance schema: instrumentation interface page.
MySQL performance schema instrumentation interface.
@section INTRO Introduction
@@ -355,26 +366,14 @@
For a given instrumentation point in the API, the basic coding pattern
used is:
- - (a) If the performance schema is not initialized, do nothing
- - (b) If the object acted upon is not instrumented, do nothing
- - (c) otherwise, notify the performance schema of the operation
+ - (a) notify the performance schema of the operation
about to be performed.
+ - (b) execute the instrumented code.
+ - (c) notify the performance schema that the operation
+ is completed.
- The implementation of the instrumentation interface can:
- - decide that it is not interested by the event, and return NULL.
- In this context, 'interested' means whether the instrumentation for
- this object + event is turned on in the performance schema configuration
- (the SETUP_ tables).
- - decide that this event is to be instrumented.
- In this case, the instrumentation returns an opaque pointer,
- that acts as a listener.
-
- If a listener is returned, the instrumentation point then:
- - (d) invokes the "start" event method
- - (e) executes the instrumented code.
- - (f) invokes the "end" event method.
-
- If no listener is returned, only the instrumented code (e) is invoked.
+ An opaque "locker" pointer is returned by (a), that is given to (c).
+ This pointer helps the implementation to keep context, for performances.
The following code fragment is annotated to show how in detail this pattern
in implemented, when the instrumentation is compiled in:
@@ -384,25 +383,18 @@ static inline int mysql_mutex_lock(
mysql_mutex_t *that, myf flags, const char *src_file, uint src_line)
{
int result;
+ struct PSI_mutex_locker_state state;
struct PSI_mutex_locker *locker= NULL;
- ...... (a) .......... (b)
- if (PSI_server && that->m_psi)
+ ............... (a)
+ locker= PSI_server->start_mutex_wait(&state, that->p_psi,
+ PSI_MUTEX_LOCK, locker, src_file, src_line);
- .......................... (c)
- if ((locker= PSI_server->get_thread_mutex_locker(that->m_psi,
- PSI_MUTEX_LOCK)))
-
- ............... (d)
- PSI_server->start_mutex_wait(locker, src_file, src_line);
-
- ........ (e)
+ ............... (b)
result= pthread_mutex_lock(&that->m_mutex);
- if (locker)
-
- ............. (f)
- PSI_server->end_mutex_wait(locker, result);
+ ............... (c)
+ PSI_server->end_mutex_wait(locker, result);
return result;
}
@@ -416,7 +408,7 @@ static inline int mysql_mutex_lock(...)
{
int result;
- ........ (e)
+ ............... (b)
result= pthread_mutex_lock(&that->m_mutex);
return result;
@@ -487,7 +479,7 @@ static inline int mysql_mutex_lock(...)
Applying this function to our point P gives another point P':
F_i (P):
- P(x1, x2, ..., x{i-1}, x_i, x{i+1}, ..., x_N
+ P(x1, x2, ..., x{i-1}, x_i, x{i+1}, ..., x_N)
--> P' (x1, x2, ..., x{i-1}, f_i(x_i), x{i+1}, ..., x_N)
That function defines in fact an aggregate !
@@ -583,27 +575,17 @@ static inline int mysql_mutex_lock(...)
What has all this to do with the code ?
- Function composition such as F_2_to_3 o F_1_to_2 o F1 is implemented
- as PFS_single_stat_chain, where each link in the chain represents
- an individual F_{i}_to_{i+1} aggregation step.
-
- A single call to aggregate_single_stat_chain() updates all the tables
- described in the statistics chain.
-
- @section STAT_CHAIN Statistics chains
+ Functions (or aggregates) such as F_3 are not implemented as is.
+ Instead, they are decomposed into F_2_to_3 o F_1_to_2 o F1,
+ and each intermediate aggregate is stored into an internal buffer.
+ This allows to support every F1, F2, F3 aggregates from shared
+ internal buffers, where computation already performed to compute F2
+ is reused when computing F3.
- Statistics chains are only used for on the fly aggregates,
- and are therefore all based initially on the '_CURRENT' base table that
- contains the data recorded.
- The following table aggregates are implemented with a statistics chain:
+ @section OBJECT_GRAPH Object graph
- EVENTS_WAITS_CURRENT --> EVENTS_WAITS_SUMMARY_BY_INSTANCE
- --> EVENTS_WAITS_SUMMARY_BY_EVENT_NAME
-
- This relationship is between classes.
-
- In terms of object instances, or records, this chain is implemented
- as a flyweight.
+ In terms of object instances, or records, pointers between
+ different buffers define an object instance graph.
For example, assuming the following scenario:
- A mutex class "M" is instrumented, the instrument name
@@ -654,10 +636,466 @@ static inline int mysql_mutex_lock(...)
This is necessary because the data the aggregate is based on is volatile,
and can not be kept indefinitely.
+ With on the fly aggregates:
+ - the writer thread does all the computation
+ - the reader thread accesses the result directly
+
+ This model is to be avoided if possible, due to the overhead
+ caused when instrumenting code.
+
@section HIGHER_LEVEL Higher level aggregates
- Note: no higher level aggregate is implemented yet,
- this section is a place holder.
+ 'Higher level' aggregates are implemented on demand only.
+ The code executing a SELECT from the aggregate table is
+ collecting data from multiple internal buffers to produce the result.
+
+ With higher level aggregates:
+ - the reader thread does all the computation
+ - the writer thread has no overhead.
+
+ @section MIXED Mixed level aggregates
+
+ The 'Mixed' model is a compromise between 'On the fly' and 'Higher level'
+ aggregates, for internal buffers that are not permanent.
+
+ While an object is present in a buffer, the higher level model is used.
+ When an object is about to be destroyed, statistics are saved into
+ a 'parent' buffer with a longer life cycle, to follow the on the fly model.
+
+ With mixed aggregates:
+ - the reader thread does a lot of complex computation,
+ - the writer thread has minimal overhead, on destroy events.
+
+ @section IMPL_WAIT Implementation for waits aggregates
+
+ For waits, the tables that contains aggregated wait data are:
+ - EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME
+ - EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME
+ - EVENTS_WAITS_SUMMARY_BY_INSTANCE
+ - EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
+ - EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME
+ - EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME
+ - FILE_SUMMARY_BY_EVENT_NAME
+ - FILE_SUMMARY_BY_INSTANCE
+ - SOCKET_SUMMARY_BY_INSTANCE
+ - SOCKET_SUMMARY_BY_EVENT_NAME
+ - OBJECTS_SUMMARY_GLOBAL_BY_TYPE
+
+ The instrumented code that generates waits events consist of:
+ - mutexes (mysql_mutex_t)
+ - rwlocks (mysql_rwlock_t)
+ - conditions (mysql_cond_t)
+ - file io (MYSQL_FILE)
+ - socket io (MYSQL_SOCKET)
+ - table io
+ - table lock
+ - 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()
*/
/**
@@ -676,12 +1114,20 @@ static inline int mysql_mutex_lock(...)
pthread_key(PFS_thread*, THR_PFS);
bool THR_PFS_initialized= false;
+/**
+ Conversion map from PSI_mutex_operation to enum_operation_type.
+ Indexed by enum PSI_mutex_operation.
+*/
static enum_operation_type mutex_operation_map[]=
{
OPERATION_TYPE_LOCK,
OPERATION_TYPE_TRYLOCK
};
+/**
+ Conversion map from PSI_rwlock_operation to enum_operation_type.
+ Indexed by enum PSI_rwlock_operation.
+*/
static enum_operation_type rwlock_operation_map[]=
{
OPERATION_TYPE_READLOCK,
@@ -690,6 +1136,10 @@ static enum_operation_type rwlock_operation_map[]=
OPERATION_TYPE_TRYWRITELOCK
};
+/**
+ Conversion map from PSI_cond_operation to enum_operation_type.
+ Indexed by enum PSI_cond_operation.
+*/
static enum_operation_type cond_operation_map[]=
{
OPERATION_TYPE_WAIT,
@@ -722,6 +1172,60 @@ static enum_operation_type file_operation_map[]=
};
/**
+ Conversion map from PSI_table_operation to enum_operation_type.
+ Indexed by enum PSI_table_io_operation.
+*/
+static enum_operation_type table_io_operation_map[]=
+{
+ OPERATION_TYPE_TABLE_FETCH,
+ OPERATION_TYPE_TABLE_WRITE_ROW,
+ OPERATION_TYPE_TABLE_UPDATE_ROW,
+ OPERATION_TYPE_TABLE_DELETE_ROW
+};
+
+/**
+ Conversion map from enum PFS_TL_LOCK_TYPE to enum_operation_type.
+ Indexed by enum PFS_TL_LOCK_TYPE.
+*/
+static enum_operation_type table_lock_operation_map[]=
+{
+ OPERATION_TYPE_TL_READ_NORMAL, /* PFS_TL_READ */
+ OPERATION_TYPE_TL_READ_WITH_SHARED_LOCKS, /* PFS_TL_READ_WITH_SHARED_LOCKS */
+ OPERATION_TYPE_TL_READ_HIGH_PRIORITY, /* PFS_TL_READ_HIGH_PRIORITY */
+ OPERATION_TYPE_TL_READ_NO_INSERTS, /* PFS_TL_READ_NO_INSERT */
+ OPERATION_TYPE_TL_WRITE_ALLOW_WRITE, /* PFS_TL_WRITE_ALLOW_WRITE */
+ OPERATION_TYPE_TL_WRITE_CONCURRENT_INSERT, /* PFS_TL_WRITE_CONCURRENT_INSERT */
+ OPERATION_TYPE_TL_WRITE_DELAYED, /* PFS_TL_WRITE_DELAYED */
+ OPERATION_TYPE_TL_WRITE_LOW_PRIORITY, /* PFS_TL_WRITE_LOW_PRIORITY */
+ OPERATION_TYPE_TL_WRITE_NORMAL, /* PFS_TL_WRITE */
+ OPERATION_TYPE_TL_READ_EXTERNAL, /* PFS_TL_READ_EXTERNAL */
+ OPERATION_TYPE_TL_WRITE_EXTERNAL /* PFS_TL_WRITE_EXTERNAL */
+};
+
+/**
+ Conversion map from PSI_socket_operation to enum_operation_type.
+ Indexed by enum PSI_socket_operation.
+*/
+static enum_operation_type socket_operation_map[]=
+{
+ OPERATION_TYPE_SOCKETCREATE,
+ OPERATION_TYPE_SOCKETCONNECT,
+ OPERATION_TYPE_SOCKETBIND,
+ OPERATION_TYPE_SOCKETCLOSE,
+ OPERATION_TYPE_SOCKETSEND,
+ OPERATION_TYPE_SOCKETRECV,
+ OPERATION_TYPE_SOCKETSENDTO,
+ OPERATION_TYPE_SOCKETRECVFROM,
+ OPERATION_TYPE_SOCKETSENDMSG,
+ OPERATION_TYPE_SOCKETRECVMSG,
+ OPERATION_TYPE_SOCKETSEEK,
+ OPERATION_TYPE_SOCKETOPT,
+ OPERATION_TYPE_SOCKETSTAT,
+ OPERATION_TYPE_SOCKETSHUTDOWN,
+ OPERATION_TYPE_SOCKETSELECT
+};
+
+/**
Build the prefix name of a class of instruments in a category.
For example, this function builds the string 'wait/sync/mutex/sql/' from
a prefix 'wait/sync/mutex' and a category 'sql'.
@@ -810,6 +1314,10 @@ static int build_prefix(const LEX_STRING *prefix, const char *category,
C_MODE_START
+/**
+ Implementation of the mutex instrumentation interface.
+ @sa PSI_v1::register_mutex.
+*/
static void register_mutex_v1(const char *category,
PSI_mutex_info_v1 *info,
int count)
@@ -819,6 +1327,10 @@ static void register_mutex_v1(const char *category,
register_mutex_class)
}
+/**
+ Implementation of the rwlock instrumentation interface.
+ @sa PSI_v1::register_rwlock.
+*/
static void register_rwlock_v1(const char *category,
PSI_rwlock_info_v1 *info,
int count)
@@ -828,6 +1340,10 @@ static void register_rwlock_v1(const char *category,
register_rwlock_class)
}
+/**
+ Implementation of the cond instrumentation interface.
+ @sa PSI_v1::register_cond.
+*/
static void register_cond_v1(const char *category,
PSI_cond_info_v1 *info,
int count)
@@ -837,6 +1353,10 @@ static void register_cond_v1(const char *category,
register_cond_class)
}
+/**
+ Implementation of the thread instrumentation interface.
+ @sa PSI_v1::register_thread.
+*/
static void register_thread_v1(const char *category,
PSI_thread_info_v1 *info,
int count)
@@ -846,6 +1366,10 @@ static void register_thread_v1(const char *category,
register_thread_class)
}
+/**
+ Implementation of the file instrumentation interface.
+ @sa PSI_v1::register_file.
+*/
static void register_file_v1(const char *category,
PSI_file_info_v1 *info,
int count)
@@ -855,14 +1379,102 @@ static void register_file_v1(const char *category,
register_file_class)
}
+static void register_stage_v1(const char *category,
+ PSI_stage_info_v1 **info_array,
+ int count)
+{
+ char formatted_name[PFS_MAX_INFO_NAME_LENGTH];
+ int prefix_length;
+ int len;
+ int full_length;
+ PSI_stage_info_v1 *info;
+
+ DBUG_ASSERT(category != NULL);
+ DBUG_ASSERT(info_array != NULL);
+ if (unlikely(build_prefix(&stage_instrument_prefix, category,
+ formatted_name, &prefix_length)))
+ {
+ for (; count>0; count--, info_array++)
+ (*info_array)->m_key= 0;
+ return ;
+ }
+
+ for (; count>0; count--, info_array++)
+ {
+ info= *info_array;
+ DBUG_ASSERT(info != NULL);
+ DBUG_ASSERT(info->m_name != NULL);
+ len= strlen(info->m_name);
+ full_length= prefix_length + len;
+ if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH))
+ {
+ memcpy(formatted_name + prefix_length, info->m_name, len);
+ info->m_key= register_stage_class(formatted_name,
+ prefix_length,
+ full_length,
+ info->m_flags);
+ }
+ else
+ {
+ pfs_print_error("register_stage_v1: name too long <%s> <%s>\n",
+ category, info->m_name);
+ info->m_key= 0;
+ }
+ }
+ return;
+}
+
+static void register_statement_v1(const char *category,
+ PSI_statement_info_v1 *info,
+ int count)
+{
+ char formatted_name[PFS_MAX_INFO_NAME_LENGTH];
+ int prefix_length;
+ int len;
+ int full_length;
+
+ DBUG_ASSERT(category != NULL);
+ DBUG_ASSERT(info != NULL);
+ if (unlikely(build_prefix(&statement_instrument_prefix,
+ category, formatted_name, &prefix_length)))
+ {
+ for (; count>0; count--, info++)
+ info->m_key= 0;
+ return ;
+ }
+
+ for (; count>0; count--, info++)
+ {
+ DBUG_ASSERT(info->m_name != NULL);
+ len= strlen(info->m_name);
+ full_length= prefix_length + len;
+ if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH))
+ {
+ memcpy(formatted_name + prefix_length, info->m_name, len);
+ info->m_key= register_statement_class(formatted_name, full_length, info->m_flags);
+ }
+ else
+ {
+ pfs_print_error("register_statement_v1: name too long <%s>\n",
+ info->m_name);
+ info->m_key= 0;
+ }
+ }
+ return;
+}
+
+static void register_socket_v1(const char *category,
+ PSI_socket_info_v1 *info,
+ int count)
+{
+ REGISTER_BODY_V1(PSI_socket_key,
+ socket_instrument_prefix,
+ register_socket_class)
+}
+
#define INIT_BODY_V1(T, KEY, ID) \
PFS_##T##_class *klass; \
PFS_##T *pfs; \
- PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); \
- if (unlikely(pfs_thread == NULL)) \
- return NULL; \
- if (! pfs_thread->m_enabled) \
- return NULL; \
klass= find_##T##_class(KEY); \
if (unlikely(klass == NULL)) \
return NULL; \
@@ -871,114 +1483,330 @@ static void register_file_v1(const char *category,
pfs= create_##T(klass, ID); \
return reinterpret_cast<PSI_##T *> (pfs)
+/**
+ Implementation of the mutex instrumentation interface.
+ @sa PSI_v1::init_mutex.
+*/
static PSI_mutex*
init_mutex_v1(PSI_mutex_key key, const void *identity)
{
INIT_BODY_V1(mutex, key, identity);
}
+/**
+ Implementation of the mutex instrumentation interface.
+ @sa PSI_v1::destroy_mutex.
+*/
static void destroy_mutex_v1(PSI_mutex* mutex)
{
PFS_mutex *pfs= reinterpret_cast<PFS_mutex*> (mutex);
+
+ DBUG_ASSERT(pfs != NULL);
+
destroy_mutex(pfs);
}
+/**
+ Implementation of the rwlock instrumentation interface.
+ @sa PSI_v1::init_rwlock.
+*/
static PSI_rwlock*
init_rwlock_v1(PSI_rwlock_key key, const void *identity)
{
INIT_BODY_V1(rwlock, key, identity);
}
+/**
+ Implementation of the rwlock instrumentation interface.
+ @sa PSI_v1::destroy_rwlock.
+*/
static void destroy_rwlock_v1(PSI_rwlock* rwlock)
{
PFS_rwlock *pfs= reinterpret_cast<PFS_rwlock*> (rwlock);
+
+ DBUG_ASSERT(pfs != NULL);
+
destroy_rwlock(pfs);
}
+/**
+ Implementation of the cond instrumentation interface.
+ @sa PSI_v1::init_cond.
+*/
static PSI_cond*
init_cond_v1(PSI_cond_key key, const void *identity)
{
INIT_BODY_V1(cond, key, identity);
}
+/**
+ Implementation of the cond instrumentation interface.
+ @sa PSI_v1::destroy_cond.
+*/
static void destroy_cond_v1(PSI_cond* cond)
{
PFS_cond *pfs= reinterpret_cast<PFS_cond*> (cond);
+
+ DBUG_ASSERT(pfs != NULL);
+
destroy_cond(pfs);
}
+/**
+ Implementation of the table instrumentation interface.
+ @sa PSI_v1::get_table_share.
+*/
static PSI_table_share*
-get_table_share_v1(const char *schema_name, int schema_name_length,
- const char *table_name, int table_name_length,
- const void *identity)
+get_table_share_v1(my_bool temporary, TABLE_SHARE *share)
{
-#ifdef HAVE_TABLE_WAIT
+ /* Ignore temporary tables and views. */
+ if (temporary || share->is_view)
+ return NULL;
+ /* An instrumented thread is required, for LF_PINS. */
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
if (unlikely(pfs_thread == NULL))
return NULL;
- PFS_table_share* share;
- share= find_or_create_table_share(pfs_thread,
- schema_name, schema_name_length,
- table_name, table_name_length);
- return reinterpret_cast<PSI_table_share*> (share);
-#else
- return NULL;
-#endif
+ PFS_table_share* pfs_share;
+ pfs_share= find_or_create_table_share(pfs_thread, temporary, share);
+ return reinterpret_cast<PSI_table_share*> (pfs_share);
}
+/**
+ Implementation of the table instrumentation interface.
+ @sa PSI_v1::release_table_share.
+*/
static void release_table_share_v1(PSI_table_share* share)
{
- /*
- To be implemented by WL#4895 PERFORMANCE_SCHEMA Instrumenting Table IO.
- */
+ PFS_table_share* pfs= reinterpret_cast<PFS_table_share*> (share);
+
+ if (unlikely(pfs == NULL))
+ return;
+
+ release_table_share(pfs);
+}
+
+/**
+ Implementation of the table instrumentation interface.
+ @sa PSI_v1::drop_table_share.
+*/
+static void
+drop_table_share_v1(my_bool temporary,
+ const char *schema_name, int schema_name_length,
+ const char *table_name, int table_name_length)
+{
+ /* Ignore temporary tables. */
+ if (temporary)
+ return;
+ PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ if (unlikely(pfs_thread == NULL))
+ return;
+ /* TODO: temporary tables */
+ drop_table_share(pfs_thread, temporary, schema_name, schema_name_length,
+ table_name, table_name_length);
}
+/**
+ Implementation of the table instrumentation interface.
+ @sa PSI_v1::open_table.
+*/
static PSI_table*
open_table_v1(PSI_table_share *share, const void *identity)
{
- PFS_table_share *pfs_table_share=
- reinterpret_cast<PFS_table_share*> (share);
- PFS_table *pfs_table;
- DBUG_ASSERT(pfs_table_share);
- pfs_table= create_table(pfs_table_share, identity);
+ PFS_table_share *pfs_table_share= reinterpret_cast<PFS_table_share*> (share);
+
+ if (unlikely(pfs_table_share == NULL))
+ return NULL;
+
+ /* This object is not to be instrumented. */
+ if (! pfs_table_share->m_enabled)
+ return NULL;
+
+ /* This object is instrumented, but all table instruments are disabled. */
+ if (! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled)
+ return NULL;
+
+ /*
+ When the performance schema is off, do not instrument anything.
+ Table handles have short life cycle, instrumentation will happen
+ again if needed during the next open().
+ */
+ if (! flag_global_instrumentation)
+ return NULL;
+
+ PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ if (unlikely(thread == NULL))
+ return NULL;
+
+ PFS_table *pfs_table= create_table(pfs_table_share, thread, identity);
return reinterpret_cast<PSI_table *> (pfs_table);
}
+/**
+ Implementation of the table instrumentation interface.
+ @sa PSI_v1::unbind_table.
+*/
+static void unbind_table_v1(PSI_table *table)
+{
+ PFS_table *pfs= reinterpret_cast<PFS_table*> (table);
+ if (likely(pfs != NULL))
+ {
+ pfs->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);
+ if (unlikely(thread == NULL))
+ return NULL;
+
+ PFS_table *pfs_table= create_table(pfs_table_share, thread, identity);
+ return reinterpret_cast<PSI_table *> (pfs_table);
+}
+
+/**
+ Implementation of the table instrumentation interface.
+ @sa PSI_v1::close_table.
+*/
static void close_table_v1(PSI_table *table)
{
PFS_table *pfs= reinterpret_cast<PFS_table*> (table);
- DBUG_ASSERT(pfs);
+ if (unlikely(pfs == NULL))
+ return;
+ pfs->aggregate();
destroy_table(pfs);
}
+static PSI_socket*
+init_socket_v1(PSI_socket_key key, const my_socket *fd,
+ 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_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
- if (unlikely(pfs_thread == NULL))
- return;
- if (! pfs_thread->m_enabled)
- return;
PFS_file_class *klass= find_file_class(key);
if (unlikely(klass == NULL))
return;
if (! klass->m_enabled)
return;
- if (likely(index < file_handle_max))
+
+ /* A thread is needed for LF_PINS */
+ PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ if (unlikely(pfs_thread == NULL))
+ return;
+
+ if (flag_thread_instrumentation && ! pfs_thread->m_enabled)
+ return;
+
+ /*
+ We want this check after pfs_thread->m_enabled,
+ to avoid reporting false loss.
+ */
+ if (unlikely(index >= file_handle_max))
{
- uint len= strlen(name);
- PFS_file *pfs= find_or_create_file(pfs_thread, klass, name, len);
- file_handle_array[index]= pfs;
- }
- else
file_handle_lost++;
+ return;
+ }
+
+ uint len= strlen(name);
+ PFS_file *pfs_file= find_or_create_file(pfs_thread, klass, name, len, 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;
+ ulonglong m_thread_internal_id;
+ char m_username[USERNAME_LENGTH];
+ uint m_username_length;
+ char m_hostname[HOSTNAME_LENGTH];
+ uint m_hostname_length;
+
PSI_thread_key m_child_key;
const void *m_child_identity;
void *(*m_user_start_routine)(void*);
@@ -996,9 +1824,27 @@ void* pfs_spawn_thread(void *arg)
/* First, attach instrumentation to this newly created pthread. */
PFS_thread_class *klass= find_thread_class(typed_arg->m_child_key);
if (likely(klass != NULL))
+ {
pfs= create_thread(klass, typed_arg->m_child_identity, 0);
+ if (likely(pfs != NULL))
+ {
+ clear_thread_account(pfs);
+
+ pfs->m_parent_thread_internal_id= typed_arg->m_thread_internal_id;
+
+ memcpy(pfs->m_username, typed_arg->m_username, sizeof(pfs->m_username));
+ pfs->m_username_length= typed_arg->m_username_length;
+
+ memcpy(pfs->m_hostname, typed_arg->m_hostname, sizeof(pfs->m_hostname));
+ pfs->m_hostname_length= typed_arg->m_hostname_length;
+
+ set_thread_account(pfs);
+ }
+ }
else
+ {
pfs= NULL;
+ }
my_pthread_setspecific_ptr(THR_PFS, pfs);
/*
@@ -1017,11 +1863,16 @@ void* pfs_spawn_thread(void *arg)
return NULL;
}
+/**
+ Implementation of the thread instrumentation interface.
+ @sa PSI_v1::spawn_thread.
+*/
static int spawn_thread_v1(PSI_thread_key key,
pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void*), void *arg)
{
PFS_spawn_thread_arg *psi_arg;
+ PFS_thread *parent;
/* 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),
@@ -1029,39 +1880,74 @@ static int spawn_thread_v1(PSI_thread_key key,
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;
+ parent= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ if (parent != NULL)
+ {
+ /*
+ Make a copy of the parent attributes.
+ This is required, because instrumentation for this thread (the parent)
+ may be destroyed before the child thread instrumentation is created.
+ */
+ psi_arg->m_thread_internal_id= parent->m_thread_internal_id;
+
+ memcpy(psi_arg->m_username, parent->m_username, sizeof(psi_arg->m_username));
+ psi_arg->m_username_length= parent->m_username_length;
+
+ memcpy(psi_arg->m_hostname, parent->m_hostname, sizeof(psi_arg->m_hostname));
+ psi_arg->m_hostname_length= parent->m_hostname_length;
+ }
+ else
+ {
+ psi_arg->m_thread_internal_id= 0;
+ psi_arg->m_username_length= 0;
+ psi_arg->m_hostname_length= 0;
+ }
+
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, ulong thread_id)
+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, thread_id);
+ pfs= create_thread(klass, identity, processlist_id);
else
pfs= NULL;
return reinterpret_cast<PSI_thread*> (pfs);
}
-static void set_thread_id_v1(PSI_thread *thread, unsigned long id)
+/**
+ Implementation of the thread instrumentation interface.
+ @sa PSI_v1::set_thread_id.
+*/
+static void set_thread_id_v1(PSI_thread *thread, ulonglong processlist_id)
{
- DBUG_ASSERT(thread);
PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread);
- pfs->m_thread_id= id;
+ 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)
{
@@ -1069,124 +1955,449 @@ get_thread_v1(void)
return reinterpret_cast<PSI_thread*> (pfs);
}
+/**
+ Implementation of the thread instrumentation interface.
+ @sa PSI_v1::set_thread_user.
+*/
+static void set_thread_user_v1(const char *user, int user_len)
+{
+ PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+
+ DBUG_ASSERT((user != NULL) || (user_len == 0));
+ DBUG_ASSERT(user_len >= 0);
+ DBUG_ASSERT((uint) user_len <= sizeof(pfs->m_username));
+
+ if (unlikely(pfs == NULL))
+ return;
+
+ aggregate_thread(pfs, pfs->m_account, pfs->m_user, pfs->m_host);
+
+ pfs->m_session_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_session_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);
+
+ host_len= min<size_t>(host_len, sizeof(pfs->m_hostname));
+
+ if (unlikely(pfs == NULL))
+ return;
+
+ pfs->m_session_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_session_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_stmt_lock.allocated_to_dirty();
+ if (db_len > 0)
+ memcpy(pfs->m_dbname, db, db_len);
+ pfs->m_dbname_length= db_len;
+ pfs->m_stmt_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_command= command;
+ }
+}
+
+/**
+ 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_start_time= start_time;
+ }
+}
+
+/**
+ Implementation of the thread instrumentation interface.
+ @sa PSI_v1::set_thread_state.
+*/
+static void set_thread_state_v1(const char* state)
+{
+ /* DEPRECATED. */
+}
+
+/**
+ Implementation of the thread instrumentation interface.
+ @sa PSI_v1::set_thread_info.
+*/
+static void set_thread_info_v1(const char* info, uint info_len)
+{
+ PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+
+ DBUG_ASSERT((info != NULL) || (info_len == 0));
+
+ if (likely(pfs != NULL))
+ {
+ if ((info != NULL) && (info_len > 0))
+ {
+ if (info_len > sizeof(pfs->m_processlist_info))
+ info_len= sizeof(pfs->m_processlist_info);
+
+ pfs->m_stmt_lock.allocated_to_dirty();
+ memcpy(pfs->m_processlist_info, info, info_len);
+ pfs->m_processlist_info_length= info_len;
+ pfs->m_stmt_lock.dirty_to_allocated();
+ }
+ else
+ {
+ pfs->m_stmt_lock.allocated_to_dirty();
+ pfs->m_processlist_info_length= 0;
+ pfs->m_stmt_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, thread->m_account, thread->m_user, thread->m_host);
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, pfs->m_account, pfs->m_user, pfs->m_host);
destroy_thread(pfs);
+ }
}
+/**
+ Implementation of the mutex instrumentation interface.
+ @sa PSI_v1::start_mutex_wait.
+*/
static PSI_mutex_locker*
-get_thread_mutex_locker_v1(PSI_mutex_locker_state *state,
- PSI_mutex *mutex, PSI_mutex_operation op)
+start_mutex_wait_v1(PSI_mutex_locker_state *state,
+ PSI_mutex *mutex, PSI_mutex_operation op,
+ const char *src_file, uint src_line)
{
PFS_mutex *pfs_mutex= reinterpret_cast<PFS_mutex*> (mutex);
DBUG_ASSERT((int) op >= 0);
DBUG_ASSERT((uint) op < array_elements(mutex_operation_map));
+ DBUG_ASSERT(state != NULL);
+
DBUG_ASSERT(pfs_mutex != NULL);
DBUG_ASSERT(pfs_mutex->m_class != NULL);
- if (! flag_events_waits_current)
- return NULL;
- if (! pfs_mutex->m_class->m_enabled)
- return NULL;
- PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
- if (unlikely(pfs_thread == NULL))
- return NULL;
- if (! pfs_thread->m_enabled)
- return NULL;
- if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE))
- {
- locker_lost++;
+
+ if (! pfs_mutex->m_enabled)
return NULL;
- }
- PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack
- [pfs_thread->m_wait_locker_count];
- pfs_locker->m_target.m_mutex= pfs_mutex;
- pfs_locker->m_waits_current.m_thread= pfs_thread;
- pfs_locker->m_waits_current.m_class= pfs_mutex->m_class;
- if (pfs_mutex->m_class->m_timed)
+ register uint flags;
+ ulonglong timer_start= 0;
+
+ if (flag_thread_instrumentation)
{
- pfs_locker->m_timer_name= wait_timer;
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING;
+ PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ if (unlikely(pfs_thread == NULL))
+ return NULL;
+ if (! pfs_thread->m_enabled)
+ return NULL;
+ state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
+ flags= STATE_FLAG_THREAD;
+
+ if (pfs_mutex->m_timed)
+ {
+ timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
+ state->m_timer_start= timer_start;
+ flags|= STATE_FLAG_TIMED;
+ }
+
+ if (flag_events_waits_current)
+ {
+ if (unlikely(pfs_thread->m_events_waits_current >=
+ & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
+ {
+ locker_lost++;
+ return NULL;
+ }
+ PFS_events_waits *wait= pfs_thread->m_events_waits_current;
+ state->m_wait= wait;
+ flags|= STATE_FLAG_EVENT;
+
+ PFS_events_waits *parent_event= wait - 1;
+ wait->m_event_type= EVENT_TYPE_WAIT;
+ wait->m_nesting_event_id= parent_event->m_event_id;
+ wait->m_nesting_event_type= parent_event->m_event_type;
+
+ wait->m_thread= pfs_thread;
+ wait->m_class= pfs_mutex->m_class;
+ wait->m_timer_start= timer_start;
+ wait->m_timer_end= 0;
+ wait->m_object_instance_addr= pfs_mutex->m_identity;
+ wait->m_event_id= pfs_thread->m_event_id++;
+ wait->m_end_event_id= 0;
+ wait->m_operation= mutex_operation_map[(int) op];
+ wait->m_source_file= src_file;
+ wait->m_source_line= src_line;
+ wait->m_wait_class= WAIT_CLASS_MUTEX;
+
+ pfs_thread->m_events_waits_current++;
+ }
}
else
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED;
- pfs_locker->m_waits_current.m_object_instance_addr= pfs_mutex->m_identity;
- pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++;
- pfs_locker->m_waits_current.m_operation= mutex_operation_map[(int) op];
- pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_MUTEX;
+ {
+ if (pfs_mutex->m_timed)
+ {
+ timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
+ state->m_timer_start= timer_start;
+ flags= STATE_FLAG_TIMED;
+ state->m_thread= NULL;
+ }
+ else
+ {
+ /*
+ Complete shortcut.
+ */
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
+ pfs_mutex->m_mutex_stat.m_wait_stat.aggregate_counted();
+ return NULL;
+ }
+ }
- pfs_thread->m_wait_locker_count++;
- return reinterpret_cast<PSI_mutex_locker*> (pfs_locker);
+ state->m_flags= flags;
+ state->m_mutex= mutex;
+ return reinterpret_cast<PSI_mutex_locker*> (state);
}
+/**
+ Implementation of the rwlock instrumentation interface.
+ @sa PSI_v1::start_rwlock_rdwait
+ @sa PSI_v1::start_rwlock_wrwait
+*/
static PSI_rwlock_locker*
-get_thread_rwlock_locker_v1(PSI_rwlock_locker_state *state,
- PSI_rwlock *rwlock, PSI_rwlock_operation op)
+start_rwlock_wait_v1(PSI_rwlock_locker_state *state,
+ PSI_rwlock *rwlock,
+ PSI_rwlock_operation op,
+ const char *src_file, uint src_line)
{
PFS_rwlock *pfs_rwlock= reinterpret_cast<PFS_rwlock*> (rwlock);
DBUG_ASSERT(static_cast<int> (op) >= 0);
DBUG_ASSERT(static_cast<uint> (op) < array_elements(rwlock_operation_map));
+ DBUG_ASSERT(state != NULL);
DBUG_ASSERT(pfs_rwlock != NULL);
DBUG_ASSERT(pfs_rwlock->m_class != NULL);
- if (! flag_events_waits_current)
- return NULL;
- if (! pfs_rwlock->m_class->m_enabled)
- return NULL;
- PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
- if (unlikely(pfs_thread == NULL))
- return NULL;
- if (! pfs_thread->m_enabled)
- return NULL;
- if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE))
- {
- locker_lost++;
+
+ if (! pfs_rwlock->m_enabled)
return NULL;
- }
- PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack
- [pfs_thread->m_wait_locker_count];
- pfs_locker->m_target.m_rwlock= pfs_rwlock;
- pfs_locker->m_waits_current.m_thread= pfs_thread;
- pfs_locker->m_waits_current.m_class= pfs_rwlock->m_class;
- if (pfs_rwlock->m_class->m_timed)
+ register uint flags;
+ ulonglong timer_start= 0;
+
+ if (flag_thread_instrumentation)
{
- pfs_locker->m_timer_name= wait_timer;
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING;
+ PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ if (unlikely(pfs_thread == NULL))
+ return NULL;
+ if (! pfs_thread->m_enabled)
+ return NULL;
+ state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
+ flags= STATE_FLAG_THREAD;
+
+ if (pfs_rwlock->m_timed)
+ {
+ timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
+ state->m_timer_start= timer_start;
+ flags|= STATE_FLAG_TIMED;
+ }
+
+ if (flag_events_waits_current)
+ {
+ if (unlikely(pfs_thread->m_events_waits_current >=
+ & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
+ {
+ locker_lost++;
+ return NULL;
+ }
+ PFS_events_waits *wait= pfs_thread->m_events_waits_current;
+ state->m_wait= wait;
+ flags|= STATE_FLAG_EVENT;
+
+ PFS_events_waits *parent_event= wait - 1;
+ wait->m_event_type= EVENT_TYPE_WAIT;
+ wait->m_nesting_event_id= parent_event->m_event_id;
+ wait->m_nesting_event_type= parent_event->m_event_type;
+
+ wait->m_thread= pfs_thread;
+ wait->m_class= pfs_rwlock->m_class;
+ wait->m_timer_start= timer_start;
+ wait->m_timer_end= 0;
+ wait->m_object_instance_addr= pfs_rwlock->m_identity;
+ wait->m_event_id= pfs_thread->m_event_id++;
+ wait->m_end_event_id= 0;
+ wait->m_operation= rwlock_operation_map[static_cast<int> (op)];
+ wait->m_source_file= src_file;
+ wait->m_source_line= src_line;
+ wait->m_wait_class= WAIT_CLASS_RWLOCK;
+
+ pfs_thread->m_events_waits_current++;
+ }
}
else
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED;
- pfs_locker->m_waits_current.m_object_instance_addr= pfs_rwlock->m_identity;
- pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++;
- pfs_locker->m_waits_current.m_operation=
- rwlock_operation_map[static_cast<int> (op)];
- pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_RWLOCK;
+ {
+ if (pfs_rwlock->m_timed)
+ {
+ timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
+ state->m_timer_start= timer_start;
+ flags= STATE_FLAG_TIMED;
+ state->m_thread= NULL;
+ }
+ else
+ {
+ /*
+ Complete shortcut.
+ */
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
+ pfs_rwlock->m_rwlock_stat.m_wait_stat.aggregate_counted();
+ return NULL;
+ }
+ }
- pfs_thread->m_wait_locker_count++;
- return reinterpret_cast<PSI_rwlock_locker*> (pfs_locker);
+ state->m_flags= flags;
+ state->m_rwlock= rwlock;
+ return reinterpret_cast<PSI_rwlock_locker*> (state);
}
+/**
+ Implementation of the cond instrumentation interface.
+ @sa PSI_v1::start_cond_wait.
+*/
static PSI_cond_locker*
-get_thread_cond_locker_v1(PSI_cond_locker_state *state,
- PSI_cond *cond, PSI_mutex * /* unused: mutex */,
- PSI_cond_operation op)
+start_cond_wait_v1(PSI_cond_locker_state *state,
+ PSI_cond *cond, PSI_mutex *mutex,
+ PSI_cond_operation op,
+ const char *src_file, uint src_line)
{
/*
Note about the unused PSI_mutex *mutex parameter:
@@ -1202,87 +2413,365 @@ get_thread_cond_locker_v1(PSI_cond_locker_state *state,
PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond);
DBUG_ASSERT(static_cast<int> (op) >= 0);
DBUG_ASSERT(static_cast<uint> (op) < array_elements(cond_operation_map));
+ DBUG_ASSERT(state != NULL);
DBUG_ASSERT(pfs_cond != NULL);
DBUG_ASSERT(pfs_cond->m_class != NULL);
- if (! flag_events_waits_current)
- return NULL;
- if (! pfs_cond->m_class->m_enabled)
- return NULL;
- PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
- if (unlikely(pfs_thread == NULL))
- return NULL;
- if (! pfs_thread->m_enabled)
+
+ if (! pfs_cond->m_enabled)
return NULL;
- if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE))
+
+ register uint flags;
+ ulonglong timer_start= 0;
+
+ if (flag_thread_instrumentation)
{
- locker_lost++;
- return NULL;
+ PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ if (unlikely(pfs_thread == NULL))
+ return NULL;
+ if (! pfs_thread->m_enabled)
+ return NULL;
+ 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;
+ }
}
- PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack
- [pfs_thread->m_wait_locker_count];
- pfs_locker->m_target.m_cond= pfs_cond;
- pfs_locker->m_waits_current.m_thread= pfs_thread;
- pfs_locker->m_waits_current.m_class= pfs_cond->m_class;
- if (pfs_cond->m_class->m_timed)
+ 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)
{
- pfs_locker->m_timer_name= wait_timer;
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING;
+ 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);
}
- else
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED;
- pfs_locker->m_waits_current.m_object_instance_addr= pfs_cond->m_identity;
- pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++;
- pfs_locker->m_waits_current.m_operation=
- cond_operation_map[static_cast<int> (op)];
- pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_COND;
- pfs_thread->m_wait_locker_count++;
- return reinterpret_cast<PSI_cond_locker*> (pfs_locker);
+ /* 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*
-get_thread_table_locker_v1(PSI_table_locker_state *state,
- PSI_table *table)
+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 (! flag_events_waits_current)
- return NULL;
- if (! pfs_table->m_share->m_enabled)
+
+ if (! pfs_table->m_io_enabled)
return NULL;
+
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
- if (unlikely(pfs_thread == NULL))
- return NULL;
- if (! pfs_thread->m_enabled)
- return NULL;
- if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE))
+
+ 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
{
- locker_lost++;
+ 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= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+
+ 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);
}
- PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack
- [pfs_thread->m_wait_locker_count];
- pfs_locker->m_target.m_table= pfs_table;
- pfs_locker->m_waits_current.m_thread= pfs_thread;
- pfs_locker->m_waits_current.m_class= &global_table_class;
- if (pfs_table->m_share->m_timed)
+ DBUG_ASSERT((uint) lock_type < array_elements(table_lock_operation_map));
+
+ register uint flags;
+ ulonglong timer_start= 0;
+
+ if (flag_thread_instrumentation)
{
- pfs_locker->m_timer_name= wait_timer;
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING;
+ if (pfs_thread == 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
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED;
- pfs_locker->m_waits_current.m_object_instance_addr= pfs_table->m_identity;
- pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++;
- pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_TABLE;
+ {
+ if (pfs_table->m_lock_timed)
+ {
+ timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
+ state->m_timer_start= timer_start;
+ flags= STATE_FLAG_TIMED;
+ }
+ else
+ {
+ /* TODO: consider a shortcut here */
+ flags= 0;
+ }
+ }
- pfs_thread->m_wait_locker_count++;
- return reinterpret_cast<PSI_table_locker*> (pfs_locker);
+ state->m_flags= flags;
+ state->m_table= table;
+ state->m_index= lock_type;
+ return reinterpret_cast<PSI_table_locker*> (state);
}
+/**
+ Implementation of the file instrumentation interface.
+ @sa PSI_v1::get_thread_file_name_locker.
+*/
static PSI_file_locker*
get_thread_file_name_locker_v1(PSI_file_locker_state *state,
PSI_file_key key,
@@ -1291,180 +2780,399 @@ get_thread_file_name_locker_v1(PSI_file_locker_state *state,
{
DBUG_ASSERT(static_cast<int> (op) >= 0);
DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map));
+ DBUG_ASSERT(state != NULL);
- if (! flag_events_waits_current)
+ if (! flag_global_instrumentation)
return NULL;
PFS_file_class *klass= find_file_class(key);
if (unlikely(klass == NULL))
return NULL;
if (! klass->m_enabled)
return NULL;
+
+ /* Needed for the LF_HASH */
PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
if (unlikely(pfs_thread == NULL))
return NULL;
- if (! pfs_thread->m_enabled)
- return NULL;
- if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE))
- {
- locker_lost++;
- return NULL;
- }
- uint len= strlen(name);
- PFS_file *pfs_file= find_or_create_file(pfs_thread, klass, name, len);
- if (unlikely(pfs_file == NULL))
+
+ if (flag_thread_instrumentation && ! pfs_thread->m_enabled)
return NULL;
- PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack
- [pfs_thread->m_wait_locker_count];
+ register uint flags;
- pfs_locker->m_target.m_file= pfs_file;
- pfs_locker->m_waits_current.m_thread= pfs_thread;
- pfs_locker->m_waits_current.m_class= pfs_file->m_class;
- if (pfs_file->m_class->m_timed)
+ 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)
{
- pfs_locker->m_timer_name= wait_timer;
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING;
+ if (unlikely(pfs_thread->m_events_waits_current >=
+ & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
+ {
+ locker_lost++;
+ return NULL;
+ }
+ PFS_events_waits *wait= pfs_thread->m_events_waits_current;
+ state->m_wait= wait;
+ flags|= STATE_FLAG_EVENT;
+
+ PFS_events_waits *parent_event= wait - 1;
+ wait->m_event_type= EVENT_TYPE_WAIT;
+ wait->m_nesting_event_id= parent_event->m_event_id;
+ wait->m_nesting_event_type= parent_event->m_event_type;
+
+ wait->m_thread= pfs_thread;
+ wait->m_class= klass;
+ wait->m_timer_start= 0;
+ wait->m_timer_end= 0;
+ wait->m_object_instance_addr= 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++;
}
- else
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED;
- pfs_locker->m_waits_current.m_object_instance_addr= pfs_file;
- pfs_locker->m_waits_current.m_object_name= pfs_file->m_filename;
- pfs_locker->m_waits_current.m_object_name_length=
- pfs_file->m_filename_length;
- pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++;
- pfs_locker->m_waits_current.m_operation=
- file_operation_map[static_cast<int> (op)];
- pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_FILE;
- pfs_thread->m_wait_locker_count++;
- return reinterpret_cast<PSI_file_locker*> (pfs_locker);
+ state->m_flags= flags;
+ state->m_file= 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(pfs_file != NULL);
- DBUG_ASSERT(pfs_file->m_class != NULL);
+ DBUG_ASSERT(state != NULL);
- if (! flag_events_waits_current)
- return NULL;
- if (! pfs_file->m_class->m_enabled)
- return NULL;
- PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
- if (unlikely(pfs_thread == NULL))
- return NULL;
- if (! pfs_thread->m_enabled)
+ if (unlikely(pfs_file == NULL))
return NULL;
- if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE))
- {
- locker_lost++;
+ DBUG_ASSERT(pfs_file->m_class != NULL);
+ PFS_file_class *klass= pfs_file->m_class;
+
+ if (! pfs_file->m_enabled)
return NULL;
- }
- PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack
- [pfs_thread->m_wait_locker_count];
- pfs_locker->m_target.m_file= pfs_file;
- pfs_locker->m_waits_current.m_thread= pfs_thread;
- pfs_locker->m_waits_current.m_class= pfs_file->m_class;
- if (pfs_file->m_class->m_timed)
+ register uint flags;
+
+ if (flag_thread_instrumentation)
{
- pfs_locker->m_timer_name= wait_timer;
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING;
+ PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ if (unlikely(pfs_thread == NULL))
+ return NULL;
+ if (! pfs_thread->m_enabled)
+ return NULL;
+ state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
+ flags= STATE_FLAG_THREAD;
+
+ if (pfs_file->m_timed)
+ flags|= STATE_FLAG_TIMED;
+
+ if (flag_events_waits_current)
+ {
+ if (unlikely(pfs_thread->m_events_waits_current >=
+ & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
+ {
+ locker_lost++;
+ return NULL;
+ }
+ PFS_events_waits *wait= pfs_thread->m_events_waits_current;
+ state->m_wait= wait;
+ flags|= STATE_FLAG_EVENT;
+
+ PFS_events_waits *parent_event= wait - 1;
+ wait->m_event_type= EVENT_TYPE_WAIT;
+ wait->m_nesting_event_id= parent_event->m_event_id;
+ wait->m_nesting_event_type= parent_event->m_event_type;
+
+ wait->m_thread= pfs_thread;
+ wait->m_class= klass;
+ wait->m_timer_start= 0;
+ wait->m_timer_end= 0;
+ wait->m_object_instance_addr= pfs_file;
+ wait->m_weak_file= pfs_file;
+ wait->m_weak_version= pfs_file->get_version();
+ wait->m_event_id= pfs_thread->m_event_id++;
+ wait->m_end_event_id= 0;
+ wait->m_operation= file_operation_map[static_cast<int> (op)];
+ wait->m_wait_class= WAIT_CLASS_FILE;
+
+ pfs_thread->m_events_waits_current++;
+ }
}
else
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED;
- pfs_locker->m_waits_current.m_object_instance_addr= pfs_file;
- pfs_locker->m_waits_current.m_object_name= pfs_file->m_filename;
- pfs_locker->m_waits_current.m_object_name_length=
- pfs_file->m_filename_length;
- pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++;
- pfs_locker->m_waits_current.m_operation=
- file_operation_map[static_cast<int> (op)];
- pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_FILE;
+ {
+ state->m_thread= NULL;
+ if (pfs_file->m_timed)
+ {
+ flags= STATE_FLAG_TIMED;
+ }
+ else
+ {
+ /* TODO: consider a shortcut. */
+ flags= 0;
+ }
+ }
- pfs_thread->m_wait_locker_count++;
- return reinterpret_cast<PSI_file_locker*> (pfs_locker);
+ state->m_flags= flags;
+ state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
+ state->m_operation= op;
+ 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;
- if (! flag_events_waits_current)
+ /*
+ 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;
- if (likely((index >= 0) && (index < file_handle_max)))
+
+ 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
{
- PFS_file *pfs_file= file_handle_array[index];
- if (likely(pfs_file != NULL))
+ state->m_thread= NULL;
+ if (pfs_file->m_timed)
+ {
+ flags= STATE_FLAG_TIMED;
+ }
+ else
{
- PFS_thread *pfs_thread;
+ /* TODO: consider a shortcut. */
+ flags= 0;
+ }
+ }
- /*
- We are about to close a file by descriptor number,
- and the calling code still holds the descriptor.
- Cleanup the file descriptor <--> file instrument association.
- Remove the instrumentation *before* the close to avoid race
- conditions with another thread opening a file
- (that could be given the same descriptor).
- */
- if (op == PSI_FILE_CLOSE)
- file_handle_array[index]= NULL;
+ state->m_flags= flags;
+ state->m_file= reinterpret_cast<PSI_file*> (pfs_file);
+ state->m_operation= op;
+ state->m_name= NULL;
+ state->m_class= klass;
+ return reinterpret_cast<PSI_file_locker*> (state);
+}
- DBUG_ASSERT(pfs_file->m_class != NULL);
- if (! pfs_file->m_class->m_enabled)
- return NULL;
- pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
- if (unlikely(pfs_thread == NULL))
- return NULL;
- if (! pfs_thread->m_enabled)
- return NULL;
- if (unlikely(pfs_thread->m_wait_locker_count >= LOCKER_STACK_SIZE))
+/** Socket locker */
+
+static PSI_socket_locker*
+start_socket_wait_v1(PSI_socket_locker_state *state,
+ PSI_socket *socket,
+ PSI_socket_operation op,
+ size_t count,
+ const char *src_file, uint src_line)
+{
+ DBUG_ASSERT(static_cast<int> (op) >= 0);
+ DBUG_ASSERT(static_cast<uint> (op) < array_elements(socket_operation_map));
+ DBUG_ASSERT(state != NULL);
+ PFS_socket *pfs_socket= reinterpret_cast<PFS_socket*> (socket);
+
+ DBUG_ASSERT(pfs_socket != NULL);
+ DBUG_ASSERT(pfs_socket->m_class != NULL);
+
+ if (!pfs_socket->m_enabled || pfs_socket->m_idle)
+ return NULL;
+
+ register uint flags= 0;
+ ulonglong timer_start= 0;
+
+ if (flag_thread_instrumentation)
+ {
+ /*
+ Do not use pfs_socket->m_thread_owner here,
+ as different threads may use concurrently the same socket,
+ for example during a KILL.
+ */
+ 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_socket->m_timed)
+ {
+ timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
+ state->m_timer_start= timer_start;
+ flags|= STATE_FLAG_TIMED;
+ }
+
+ if (flag_events_waits_current)
+ {
+ if (unlikely(pfs_thread->m_events_waits_current >=
+ & pfs_thread->m_events_waits_stack[WAIT_STACK_SIZE]))
{
locker_lost++;
return NULL;
}
- PFS_wait_locker *pfs_locker= &pfs_thread->m_wait_locker_stack
- [pfs_thread->m_wait_locker_count];
-
- pfs_locker->m_target.m_file= pfs_file;
- pfs_locker->m_waits_current.m_thread= pfs_thread;
- pfs_locker->m_waits_current.m_class= pfs_file->m_class;
- if (pfs_file->m_class->m_timed)
+ PFS_events_waits *wait= pfs_thread->m_events_waits_current;
+ state->m_wait= wait;
+ flags|= STATE_FLAG_EVENT;
+
+ PFS_events_waits *parent_event= wait - 1;
+ wait->m_event_type= EVENT_TYPE_WAIT;
+ wait->m_nesting_event_id= parent_event->m_event_id;
+ wait->m_nesting_event_type= parent_event->m_event_type;
+ wait->m_thread= pfs_thread;
+ wait->m_class= pfs_socket->m_class;
+ wait->m_timer_start= timer_start;
+ wait->m_timer_end= 0;
+ wait->m_object_instance_addr= pfs_socket->m_identity;
+ wait->m_weak_socket= pfs_socket;
+ wait->m_weak_version= pfs_socket->get_version();
+ wait->m_event_id= pfs_thread->m_event_id++;
+ wait->m_end_event_id= 0;
+ wait->m_operation= socket_operation_map[static_cast<int>(op)];
+ wait->m_source_file= src_file;
+ wait->m_source_line= src_line;
+ wait->m_number_of_bytes= count;
+ wait->m_wait_class= WAIT_CLASS_SOCKET;
+
+ pfs_thread->m_events_waits_current++;
+ }
+ }
+ else
+ {
+ if (pfs_socket->m_timed)
+ {
+ timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
+ state->m_timer_start= timer_start;
+ flags= STATE_FLAG_TIMED;
+ }
+ else
+ {
+ /*
+ Even if timing is disabled, end_socket_wait() still needs a locker to
+ capture the number of bytes sent or received by the socket operation.
+ For operations that do not have a byte count, then just increment the
+ event counter and return a NULL locker.
+ */
+ switch (op)
{
- pfs_locker->m_timer_name= wait_timer;
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_STARTING;
+ case PSI_SOCKET_CONNECT:
+ case PSI_SOCKET_CREATE:
+ case PSI_SOCKET_BIND:
+ case PSI_SOCKET_SEEK:
+ case PSI_SOCKET_OPT:
+ case PSI_SOCKET_STAT:
+ case PSI_SOCKET_SHUTDOWN:
+ case PSI_SOCKET_CLOSE:
+ case PSI_SOCKET_SELECT:
+ pfs_socket->m_socket_stat.m_io_stat.m_misc.aggregate_counted();
+ return NULL;
+ default:
+ break;
}
- else
- pfs_locker->m_waits_current.m_timer_state= TIMER_STATE_UNTIMED;
- pfs_locker->m_waits_current.m_object_instance_addr= pfs_file;
- pfs_locker->m_waits_current.m_object_name= pfs_file->m_filename;
- pfs_locker->m_waits_current.m_object_name_length=
- pfs_file->m_filename_length;
- pfs_locker->m_waits_current.m_event_id= pfs_thread->m_event_id++;
- pfs_locker->m_waits_current.m_operation=
- file_operation_map[static_cast<int> (op)];
- pfs_locker->m_waits_current.m_wait_class= WAIT_CLASS_FILE;
-
- pfs_thread->m_wait_locker_count++;
- return reinterpret_cast<PSI_file_locker*> (pfs_locker);
}
}
- return NULL;
+
+ state->m_flags= flags;
+ state->m_socket= socket;
+ state->m_operation= op;
+ return reinterpret_cast<PSI_socket_locker*> (state);
}
+/**
+ Implementation of the mutex instrumentation interface.
+ @sa PSI_v1::unlock_mutex.
+*/
static void unlock_mutex_v1(PSI_mutex *mutex)
{
PFS_mutex *pfs_mutex= reinterpret_cast<PFS_mutex*> (mutex);
+
DBUG_ASSERT(pfs_mutex != NULL);
/*
@@ -1482,29 +3190,30 @@ static void unlock_mutex_v1(PSI_mutex *mutex)
PFS_mutex::m_lock_stat is not exposed in user visible tables
currently, so there is no point spending time computing it.
*/
- PFS_thread *pfs_thread= reinterpret_cast<PFS_thread*> (thread);
- DBUG_ASSERT(pfs_thread != NULL);
-
- if (unlikely(! flag_events_waits_current))
- return;
- if (! pfs_mutex->m_class->m_enabled)
+ if (! pfs_mutex->m_enabled)
return;
- if (! pfs_thread->m_enabled)
+
+ if (! pfs_mutex->m_timed)
return;
- if (pfs_mutex->m_class->m_timed)
- {
- ulonglong locked_time;
- locked_time= get_timer_value(wait_timer) - pfs_mutex->m_last_locked;
- aggregate_single_stat_chain(&pfs_mutex->m_lock_stat, locked_time);
- }
+ 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;
@@ -1517,7 +3226,7 @@ static void unlock_rwlock_v1(PSI_rwlock *rwlock)
*/
/* Always update the instrumented state */
- if (pfs_rwlock->m_writer)
+ if (pfs_rwlock->m_writer != NULL)
{
/* Nominal case, a writer is unlocking. */
last_writer= true;
@@ -1547,32 +3256,23 @@ static void unlock_rwlock_v1(PSI_rwlock *rwlock)
#ifdef LATER_WL2333
/* See WL#2333: SHOW ENGINE ... LOCK STATUS. */
- PFS_thread *pfs_thread= reinterpret_cast<PFS_thread*> (thread);
- DBUG_ASSERT(pfs_thread != NULL);
- if (unlikely(! flag_events_waits_current))
+ if (! pfs_rwlock->m_enabled)
return;
- if (! pfs_rwlock->m_class->m_enabled)
- return;
- if (! pfs_thread->m_enabled)
+
+ if (! pfs_rwlock->m_timed)
return;
ulonglong locked_time;
if (last_writer)
{
- if (pfs_rwlock->m_class->m_timed)
- {
- locked_time= get_timer_value(wait_timer) - pfs_rwlock->m_last_written;
- aggregate_single_stat_chain(&pfs_rwlock->m_write_lock_stat, locked_time);
- }
+ 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)
{
- if (pfs_rwlock->m_class->m_timed)
- {
- locked_time= get_timer_value(wait_timer) - pfs_rwlock->m_last_read;
- aggregate_single_stat_chain(&pfs_rwlock->m_read_lock_stat, locked_time);
- }
+ 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;
@@ -1580,109 +3280,282 @@ static void unlock_rwlock_v1(PSI_rwlock *rwlock)
#endif
}
+/**
+ Implementation of the cond instrumentation interface.
+ @sa PSI_v1::signal_cond.
+*/
static void signal_cond_v1(PSI_cond* cond)
{
PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond);
+
DBUG_ASSERT(pfs_cond != NULL);
pfs_cond->m_cond_stat.m_signal_count++;
}
+/**
+ Implementation of the cond instrumentation interface.
+ @sa PSI_v1::broadcast_cond.
+*/
static void broadcast_cond_v1(PSI_cond* cond)
{
PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond);
+
DBUG_ASSERT(pfs_cond != NULL);
pfs_cond->m_cond_stat.m_broadcast_count++;
}
-static void start_mutex_wait_v1(PSI_mutex_locker* locker,
- const char *src_file, uint src_line)
+/**
+ Implementation of the idle instrumentation interface.
+ @sa PSI_v1::start_idle_wait.
+*/
+static PSI_idle_locker*
+start_idle_wait_v1(PSI_idle_locker_state* state, const char *src_file, uint src_line)
{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
+ DBUG_ASSERT(state != NULL);
+
+ if (!flag_global_instrumentation)
+ return NULL;
+
+ if (!global_idle_class.m_enabled)
+ return NULL;
+
+ register uint flags= 0;
+ ulonglong timer_start= 0;
+
+ if (flag_thread_instrumentation)
+ {
+ PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ if (unlikely(pfs_thread == NULL))
+ return NULL;
+ if (!pfs_thread->m_enabled)
+ return NULL;
+ state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread);
+ flags= STATE_FLAG_THREAD;
+
+ DBUG_ASSERT(pfs_thread->m_events_statements_count == 0);
+
+ 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;
- PFS_events_waits *wait= &pfs_locker->m_waits_current;
- if (wait->m_timer_state == TIMER_STATE_STARTING)
+ wait->m_event_type= EVENT_TYPE_WAIT;
+ /*
+ IDLE events are waits, but by definition we know that
+ such waits happen outside of any STAGE and STATEMENT,
+ so they have no parents.
+ */
+ wait->m_nesting_event_id= 0;
+ /* no need to set wait->m_nesting_event_type */
+
+ wait->m_thread= pfs_thread;
+ wait->m_class= &global_idle_class;
+ wait->m_timer_start= timer_start;
+ wait->m_timer_end= 0;
+ wait->m_event_id= pfs_thread->m_event_id++;
+ wait->m_end_event_id= 0;
+ wait->m_operation= OPERATION_TYPE_IDLE;
+ wait->m_source_file= src_file;
+ wait->m_source_line= src_line;
+ wait->m_wait_class= WAIT_CLASS_IDLE;
+
+ pfs_thread->m_events_waits_current++;
+ }
+ }
+ else
{
- wait->m_timer_start= get_timer_value(pfs_locker->m_timer_name);
- wait->m_timer_state= TIMER_STATE_STARTED;
+ if (global_idle_class.m_timed)
+ {
+ timer_start= get_timer_raw_value_and_function(idle_timer, &state->m_timer);
+ state->m_timer_start= timer_start;
+ flags= STATE_FLAG_TIMED;
+ }
}
- wait->m_source_file= src_file;
- wait->m_source_line= src_line;
+
+ state->m_flags= flags;
+ return reinterpret_cast<PSI_idle_locker*> (state);
}
-static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc)
+/**
+ Implementation of the mutex instrumentation interface.
+ @sa PSI_v1::end_idle_wait.
+*/
+static void end_idle_wait_v1(PSI_idle_locker* locker)
{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
- PFS_events_waits *wait= &pfs_locker->m_waits_current;
+ PSI_idle_locker_state *state= reinterpret_cast<PSI_idle_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
+ ulonglong timer_end= 0;
+ ulonglong wait_time= 0;
+
+ register uint flags= state->m_flags;
- if (wait->m_timer_state == TIMER_STATE_STARTED)
+ if (flags & STATE_FLAG_TIMED)
{
- wait->m_timer_end= get_timer_value(pfs_locker->m_timer_name);
- wait->m_timer_state= TIMER_STATE_TIMED;
+ timer_end= state->m_timer();
+ wait_time= timer_end - state->m_timer_start;
}
- if (flag_events_waits_history)
- insert_events_waits_history(wait->m_thread, wait);
- if (flag_events_waits_history_long)
- insert_events_waits_history_long(wait);
- if (rc == 0)
+ if (flags & STATE_FLAG_THREAD)
{
- /* Thread safe: we are protected by the instrumented mutex */
- PFS_mutex *mutex= pfs_locker->m_target.m_mutex;
- PFS_single_stat_chain *stat= find_per_thread_mutex_class_wait_stat(wait->m_thread, mutex->m_class);
- mutex->m_owner= wait->m_thread;
- mutex->m_last_locked= wait->m_timer_end;
+ PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
+ PFS_single_stat *event_name_array;
+ event_name_array= thread->m_instr_class_waits_stats;
- /* If timed then aggregate stats, else increment the value counts only */
- if (wait->m_timer_state == TIMER_STATE_TIMED)
+ if (flags & STATE_FLAG_TIMED)
{
- ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
- aggregate_single_stat_chain(&mutex->m_wait_stat, wait_time);
- aggregate_single_stat_chain(stat, wait_time);
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
+ event_name_array[GLOBAL_IDLE_EVENT_INDEX].aggregate_value(wait_time);
}
else
{
- increment_single_stat_chain(&mutex->m_wait_stat);
- increment_single_stat_chain(stat);
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
+ event_name_array[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--;
+
+ DBUG_ASSERT(wait == thread->m_events_waits_current);
}
}
- wait->m_thread->m_wait_locker_count--;
+
+ 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();
+ }
}
-static void start_rwlock_rdwait_v1(PSI_rwlock_locker* locker,
- const char *src_file, uint src_line)
+/**
+ Implementation of the mutex instrumentation interface.
+ @sa PSI_v1::end_mutex_wait.
+*/
+static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc)
{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
+ PSI_mutex_locker_state *state= reinterpret_cast<PSI_mutex_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
+
+ 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);
- PFS_events_waits *wait= &pfs_locker->m_waits_current;
- if (wait->m_timer_state == TIMER_STATE_STARTING)
+ 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)
{
- wait->m_timer_start= get_timer_value(pfs_locker->m_timer_name);
- wait->m_timer_state= TIMER_STATE_STARTED;
+ 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--;
+
+ DBUG_ASSERT(wait == thread->m_events_waits_current);
+ }
}
- wait->m_source_file= src_file;
- wait->m_source_line= src_line;
}
+/**
+ Implementation of the rwlock instrumentation interface.
+ @sa PSI_v1::end_rwlock_rdwait.
+*/
static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc)
{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
- PFS_events_waits *wait= &pfs_locker->m_waits_current;
+ PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
+
+ ulonglong timer_end= 0;
+ ulonglong wait_time= 0;
+
+ PFS_rwlock *rwlock= reinterpret_cast<PFS_rwlock *> (state->m_rwlock);
+ DBUG_ASSERT(rwlock != NULL);
- if (wait->m_timer_state == TIMER_STATE_STARTED)
+ 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
{
- wait->m_timer_end= get_timer_value(pfs_locker->m_timer_name);
- wait->m_timer_state= TIMER_STATE_TIMED;
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
+ rwlock->m_rwlock_stat.m_wait_stat.aggregate_counted();
}
- if (flag_events_waits_history)
- insert_events_waits_history(wait->m_thread, wait);
- if (flag_events_waits_history_long)
- insert_events_waits_history_long(wait);
if (rc == 0)
{
@@ -1693,220 +3566,357 @@ static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc)
The statistics generated are not safe, which is why they are
just statistics, not facts.
*/
- PFS_rwlock *rwlock= pfs_locker->m_target.m_rwlock;
- PFS_single_stat_chain *stat= find_per_thread_rwlock_class_wait_stat(wait->m_thread, rwlock->m_class);
-
if (rwlock->m_readers == 0)
- rwlock->m_last_read= wait->m_timer_end;
+ rwlock->m_last_read= timer_end;
rwlock->m_writer= NULL;
rwlock->m_readers++;
+ }
+
+ if (state->m_flags & STATE_FLAG_THREAD)
+ {
+ PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
+ DBUG_ASSERT(thread != NULL);
- /* If timed then aggregate stats, else increment the value counts only */
- if (wait->m_timer_state == TIMER_STATE_TIMED)
+ PFS_single_stat *event_name_array;
+ event_name_array= thread->m_instr_class_waits_stats;
+ uint index= rwlock->m_class->m_event_name_index;
+
+ if (state->m_flags & STATE_FLAG_TIMED)
{
- ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
- aggregate_single_stat_chain(&rwlock->m_wait_stat, wait_time);
- aggregate_single_stat_chain(stat, wait_time);
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
+ event_name_array[index].aggregate_value(wait_time);
}
else
{
- increment_single_stat_chain(&rwlock->m_wait_stat);
- increment_single_stat_chain(stat);
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
+ event_name_array[index].aggregate_counted();
}
- }
- wait->m_thread->m_wait_locker_count--;
-}
-
-static void start_rwlock_wrwait_v1(PSI_rwlock_locker* locker,
- const char *src_file, uint src_line)
-{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
- PFS_events_waits *wait= &pfs_locker->m_waits_current;
- if (wait->m_timer_state == TIMER_STATE_STARTING)
- {
- wait->m_timer_start= get_timer_value(pfs_locker->m_timer_name);
- wait->m_timer_state= TIMER_STATE_STARTED;
+ if (state->m_flags & STATE_FLAG_EVENT)
+ {
+ PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
+ DBUG_ASSERT(wait != NULL);
+
+ wait->m_timer_end= timer_end;
+ wait->m_end_event_id= thread->m_event_id;
+ if (flag_events_waits_history)
+ insert_events_waits_history(thread, wait);
+ if (flag_events_waits_history_long)
+ insert_events_waits_history_long(wait);
+ thread->m_events_waits_current--;
+
+ DBUG_ASSERT(wait == thread->m_events_waits_current);
+ }
}
- wait->m_source_file= src_file;
- wait->m_source_line= src_line;
}
+/**
+ Implementation of the rwlock instrumentation interface.
+ @sa PSI_v1::end_rwlock_wrwait.
+*/
static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc)
{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
- PFS_events_waits *wait= &pfs_locker->m_waits_current;
+ PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
- if (wait->m_timer_state == TIMER_STATE_STARTED)
+ ulonglong timer_end= 0;
+ ulonglong wait_time= 0;
+
+ PFS_rwlock *rwlock= reinterpret_cast<PFS_rwlock *> (state->m_rwlock);
+ DBUG_ASSERT(rwlock != NULL);
+ PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread);
+
+ if (state->m_flags & STATE_FLAG_TIMED)
+ {
+ timer_end= state->m_timer();
+ wait_time= timer_end - state->m_timer_start;
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
+ rwlock->m_rwlock_stat.m_wait_stat.aggregate_value(wait_time);
+ }
+ else
{
- wait->m_timer_end= get_timer_value(pfs_locker->m_timer_name);
- wait->m_timer_state= TIMER_STATE_TIMED;
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
+ rwlock->m_rwlock_stat.m_wait_stat.aggregate_counted();
}
- if (flag_events_waits_history)
- insert_events_waits_history(wait->m_thread, wait);
- if (flag_events_waits_history_long)
- insert_events_waits_history_long(wait);
- if (rc == 0)
+ if (likely(rc == 0))
{
/* Thread safe : we are protected by the instrumented rwlock */
- PFS_rwlock *rwlock= pfs_locker->m_target.m_rwlock;
- PFS_single_stat_chain *stat= find_per_thread_rwlock_class_wait_stat(wait->m_thread, rwlock->m_class);
- rwlock->m_writer= wait->m_thread;
- rwlock->m_last_written= wait->m_timer_end;
+ rwlock->m_writer= thread;
+ rwlock->m_last_written= timer_end;
/* Reset the readers stats, they could be off */
rwlock->m_readers= 0;
rwlock->m_last_read= 0;
+ }
- /* If timed then aggregate stats, else increment the value counts only */
- if (wait->m_timer_state == TIMER_STATE_TIMED)
+ 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)
{
- ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
- aggregate_single_stat_chain(&rwlock->m_wait_stat, wait_time);
- aggregate_single_stat_chain(stat, wait_time);
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */
+ event_name_array[index].aggregate_value(wait_time);
}
else
{
- increment_single_stat_chain(&rwlock->m_wait_stat);
- increment_single_stat_chain(stat);
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */
+ event_name_array[index].aggregate_counted();
+ }
+
+ 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--;
+
+ DBUG_ASSERT(wait == thread->m_events_waits_current);
}
}
- wait->m_thread->m_wait_locker_count--;
}
-static void start_cond_wait_v1(PSI_cond_locker* locker,
- const char *src_file, uint src_line)
+/**
+ Implementation of the cond instrumentation interface.
+ @sa PSI_v1::end_cond_wait.
+*/
+static void end_cond_wait_v1(PSI_cond_locker* locker, int rc)
{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
+ 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();
+ }
- PFS_events_waits *wait= &pfs_locker->m_waits_current;
- if (wait->m_timer_state == TIMER_STATE_STARTING)
+ if (state->m_flags & STATE_FLAG_THREAD)
{
- wait->m_timer_start= get_timer_value(pfs_locker->m_timer_name);
- wait->m_timer_state= TIMER_STATE_STARTED;
+ 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--;
+
+ DBUG_ASSERT(wait == thread->m_events_waits_current);
+ }
}
- wait->m_source_file= src_file;
- wait->m_source_line= src_line;
}
-static void end_cond_wait_v1(PSI_cond_locker* locker, int rc)
+/**
+ Implementation of the table instrumentation interface.
+ @sa PSI_v1::end_table_io_wait.
+*/
+static void end_table_io_wait_v1(PSI_table_locker* locker)
{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
- PFS_events_waits *wait= &pfs_locker->m_waits_current;
+ 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));
- if (wait->m_timer_state == TIMER_STATE_STARTED)
+ 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)
{
- wait->m_timer_end= get_timer_value(pfs_locker->m_timer_name);
- wait->m_timer_state= TIMER_STATE_TIMED;
+ 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;
}
- if (flag_events_waits_history)
- insert_events_waits_history(wait->m_thread, wait);
- if (flag_events_waits_history_long)
- insert_events_waits_history_long(wait);
- if (rc == 0)
+ 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;
+
/*
- Not thread safe, race conditions will occur.
- A first race condition is:
- - thread 1 waits on cond A
- - thread 2 waits on cond B
- threads 1 and 2 compete when updating the same cond A
- statistics, possibly missing a min / max / sum / count.
- A second race condition is:
- - thread 1 waits on cond A
- - thread 2 destroys cond A
- - thread 2 or 3 creates cond B in the same condition slot
- thread 1 will then aggregate statistics about defunct A
- in condition B.
- This is accepted, the data will be slightly inaccurate.
+ Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME
+ (for wait/io/table/sql/handler)
*/
- PFS_cond *cond= pfs_locker->m_target.m_cond;
- PFS_single_stat_chain *stat= find_per_thread_cond_class_wait_stat(wait->m_thread, cond->m_class);
-
- /* If timed then aggregate stats, else increment the value counts only */
- if (wait->m_timer_state == TIMER_STATE_TIMED)
+ if (flags & STATE_FLAG_TIMED)
{
- ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
- aggregate_single_stat_chain(&cond->m_wait_stat, wait_time);
- aggregate_single_stat_chain(stat, wait_time);
+ event_name_array[GLOBAL_TABLE_IO_EVENT_INDEX].aggregate_value(wait_time);
}
else
{
- increment_single_stat_chain(&cond->m_wait_stat);
- increment_single_stat_chain(stat);
+ 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--;
+
+ DBUG_ASSERT(wait == thread->m_events_waits_current);
}
}
- wait->m_thread->m_wait_locker_count--;
+
+ table->m_has_io_stats= true;
}
-static void start_table_wait_v1(PSI_table_locker* locker,
- const char *src_file, uint src_line)
+/**
+ Implementation of the table instrumentation interface.
+ @sa PSI_v1::end_table_lock_wait.
+*/
+static void end_table_lock_wait_v1(PSI_table_locker* locker)
{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
+ PSI_table_locker_state *state= reinterpret_cast<PSI_table_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
- PFS_events_waits *wait= &pfs_locker->m_waits_current;
- if (wait->m_timer_state == TIMER_STATE_STARTING)
- {
- wait->m_timer_start= get_timer_value(pfs_locker->m_timer_name);
- wait->m_timer_state= TIMER_STATE_STARTED;
- }
- wait->m_source_file= src_file;
- wait->m_source_line= src_line;
- wait->m_operation= OPERATION_TYPE_LOCK;
- PFS_table_share *share= pfs_locker->m_target.m_table->m_share;
- wait->m_schema_name= share->m_schema_name;
- wait->m_schema_name_length= share->m_schema_name_length;
- wait->m_object_name= share->m_table_name;
- wait->m_object_name_length= share->m_table_name_length;
-}
+ ulonglong timer_end= 0;
+ ulonglong wait_time= 0;
-static void end_table_wait_v1(PSI_table_locker* locker)
-{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
- PFS_events_waits *wait= &pfs_locker->m_waits_current;
+ PFS_table *table= reinterpret_cast<PFS_table *> (state->m_table);
+ DBUG_ASSERT(table != NULL);
- if (wait->m_timer_state == TIMER_STATE_STARTED)
- {
- wait->m_timer_end= get_timer_value(pfs_locker->m_timer_name);
- wait->m_timer_state= TIMER_STATE_TIMED;
- }
- if (flag_events_waits_history)
- insert_events_waits_history(wait->m_thread, wait);
- if (flag_events_waits_history_long)
- insert_events_waits_history_long(wait);
+ PFS_single_stat *stat= & table->m_table_stat.m_lock_stat.m_stat[state->m_index];
- PFS_table *table= pfs_locker->m_target.m_table;
+ register uint flags= state->m_flags;
- /* If timed then aggregate stats, else increment the value counts only */
- if (wait->m_timer_state == TIMER_STATE_TIMED)
+ if (flags & STATE_FLAG_TIMED)
{
- ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
- aggregate_single_stat_chain(&table->m_wait_stat, wait_time);
+ timer_end= state->m_timer();
+ wait_time= timer_end - state->m_timer_start;
+ stat->aggregate_value(wait_time);
}
else
{
- increment_single_stat_chain(&table->m_wait_stat);
+ stat->aggregate_counted();
}
- /*
- There is currently no per table and per thread aggregation.
- The number of tables in the application is arbitrary, and may be high.
- The number of slots per thread to hold aggregates is fixed,
- and is constrained by memory.
- Implementing a per thread and per table aggregate has not been
- decided yet.
- If it's implemented, it's likely that the user will have to specify,
- per table name, if the aggregate per thread is to be computed or not.
- This will mean a SETUP_ table.
- */
- wait->m_thread->m_wait_locker_count--;
+ if (flags & STATE_FLAG_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--;
+
+ DBUG_ASSERT(wait == thread->m_events_waits_current);
+ }
+ }
+
+ table->m_has_lock_stats= true;
}
static void start_file_wait_v1(PSI_file_locker *locker,
@@ -1917,131 +3927,1297 @@ static void start_file_wait_v1(PSI_file_locker *locker,
static void end_file_wait_v1(PSI_file_locker *locker,
size_t count);
-static PSI_file* start_file_open_wait_v1(PSI_file_locker *locker,
- const char *src_file,
- uint src_line)
+/**
+ 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)
{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
-
start_file_wait_v1(locker, 0, src_file, src_line);
- PFS_file *pfs_file= pfs_locker->m_target.m_file;
- return reinterpret_cast<PSI_file*> (pfs_file);
+ return;
}
-static void end_file_open_wait_v1(PSI_file_locker *locker)
+/**
+ 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:
+ case PSI_FILE_RENAME:
+ break;
+ case PSI_FILE_STREAM_OPEN:
+ case PSI_FILE_CREATE:
+ case PSI_FILE_OPEN:
+ 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;
+ 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;
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
+ PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
- end_file_wait_v1(locker, 0);
+ 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);
+ }
- PFS_file *pfs_file= pfs_locker->m_target.m_file;
- DBUG_ASSERT(pfs_file != NULL);
+ 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++;
+ }
}
- else
- release_file(pfs_file);
}
+/**
+ Implementation of the file instrumentation interface.
+ @sa PSI_v1::start_file_wait.
+*/
static void start_file_wait_v1(PSI_file_locker *locker,
size_t count,
const char *src_file,
uint src_line)
{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
+ ulonglong timer_start= 0;
+ PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker);
+ DBUG_ASSERT(state != NULL);
- PFS_events_waits *wait= &pfs_locker->m_waits_current;
- if (wait->m_timer_state == TIMER_STATE_STARTING)
+ register uint flags= state->m_flags;
+
+ if (flags & STATE_FLAG_TIMED)
{
- wait->m_timer_start= get_timer_value(pfs_locker->m_timer_name);
- wait->m_timer_state= TIMER_STATE_STARTED;
+ timer_start= get_timer_raw_value_and_function(wait_timer, & state->m_timer);
+ state->m_timer_start= timer_start;
+ }
+
+ if (flags & STATE_FLAG_EVENT)
+ {
+ PFS_events_waits *wait= reinterpret_cast<PFS_events_waits*> (state->m_wait);
+ DBUG_ASSERT(wait != NULL);
+
+ wait->m_timer_start= timer_start;
+ wait->m_source_file= src_file;
+ wait->m_source_line= src_line;
+ wait->m_number_of_bytes= count;
}
- wait->m_source_file= src_file;
- wait->m_source_line= src_line;
- wait->m_number_of_bytes= count;
}
+/**
+ Implementation of the file instrumentation interface.
+ @sa PSI_v1::end_file_wait.
+*/
static void end_file_wait_v1(PSI_file_locker *locker,
- size_t count)
+ size_t byte_count)
{
- PFS_wait_locker *pfs_locker= reinterpret_cast<PFS_wait_locker*> (locker);
- DBUG_ASSERT(pfs_locker != NULL);
- PFS_events_waits *wait= &pfs_locker->m_waits_current;
+ 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);
- wait->m_number_of_bytes= count;
- if (wait->m_timer_state == TIMER_STATE_STARTED)
+ PFS_file_stat *file_stat;
+
+ if (file != NULL)
+ {
+ file_stat= & file->m_file_stat;
+ }
+ else
{
- wait->m_timer_end= get_timer_value(pfs_locker->m_timer_name);
- wait->m_timer_state= TIMER_STATE_TIMED;
+ file_stat= & klass->m_file_stat;
}
- if (flag_events_waits_history)
- insert_events_waits_history(wait->m_thread, wait);
- if (flag_events_waits_history_long)
- insert_events_waits_history_long(wait);
- PFS_file *file= pfs_locker->m_target.m_file;
- PFS_single_stat_chain *stat= find_per_thread_file_class_wait_stat(wait->m_thread, file->m_class);
+ 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;
+ }
- /* If timed then aggregate stats, else increment the value counts only */
- if (wait->m_timer_state == TIMER_STATE_TIMED)
+ /* Aggregation for EVENTS_WAITS_SUMMARY_BY_INSTANCE */
+ if (flags & STATE_FLAG_TIMED)
{
- ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
- aggregate_single_stat_chain(&file->m_wait_stat, wait_time);
- aggregate_single_stat_chain(stat, wait_time);
+ timer_end= state->m_timer();
+ wait_time= timer_end - state->m_timer_start;
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (timed) */
+ byte_stat->aggregate(wait_time, bytes);
}
else
{
- increment_single_stat_chain(&file->m_wait_stat);
- increment_single_stat_chain(stat);
+ /* Aggregate to EVENTS_WAITS_SUMMARY_BY_INSTANCE (counted) */
+ byte_stat->aggregate_counted(bytes);
}
- PFS_file_class *klass= file->m_class;
+ if (flags & STATE_FLAG_THREAD)
+ {
+ DBUG_ASSERT(thread != NULL);
+
+ PFS_single_stat *event_name_array;
+ event_name_array= thread->m_instr_class_waits_stats;
+ uint index= 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();
+ }
- switch(wait->m_operation)
+ 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--;
+
+ DBUG_ASSERT(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 OPERATION_TYPE_FILEREAD:
- file->m_file_stat.m_count_read++;
- file->m_file_stat.m_read_bytes+= count;
- klass->m_file_stat.m_count_read++;
- klass->m_file_stat.m_read_bytes+= count;
+ 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 OPERATION_TYPE_FILEWRITE:
- file->m_file_stat.m_count_write++;
- file->m_file_stat.m_write_bytes+= count;
- klass->m_file_stat.m_count_write++;
- klass->m_file_stat.m_write_bytes+= count;
- break;
- case OPERATION_TYPE_FILECLOSE:
- case OPERATION_TYPE_FILESTREAMCLOSE:
- case OPERATION_TYPE_FILESTAT:
- release_file(pfs_locker->m_target.m_file);
- break;
- case OPERATION_TYPE_FILEDELETE:
- destroy_file(wait->m_thread, pfs_locker->m_target.m_file);
+ case PSI_FILE_STREAM_CLOSE:
+ case PSI_FILE_CLOSE:
break;
default:
+ DBUG_ASSERT(false);
break;
}
- wait->m_thread->m_wait_locker_count--;
+ 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;
+
+ PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ if (unlikely(pfs_thread == NULL))
+ return;
+
+ /* Always update column threads.processlist_state. */
+ pfs_thread->m_stage= key;
+
+ if (! flag_global_instrumentation)
+ 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 (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;
+
+ PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
+ if (unlikely(pfs_thread == NULL))
+ return;
+
+ pfs_thread->m_stage= 0;
+
+ if (! flag_global_instrumentation)
+ 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 (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);
+ DBUG_ASSERT(charset != 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_thread->m_stmt_lock.allocated_to_dirty();
+ 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_sqltext_truncated= false;
+ pfs->m_sqltext_cs_number= system_charset_info->number; /* default */
+
+ 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;
+ pfs->m_digest_storage.reset();
+
+ /* 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++;
+ pfs_thread->m_stmt_lock.dirty_to_allocated();
+ }
+ }
+ else
+ {
+ if (klass->m_timed)
+ flags= STATE_FLAG_TIMED;
+ else
+ flags= 0;
+ }
+
+ if (flag_statements_digest)
+ {
+ flags|= STATE_FLAG_DIGEST;
+ }
+
+ 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_digest= NULL;
+
+ state->m_schema_name_length= 0;
+ state->m_cs_number= ((CHARSET_INFO *)charset)->number;
+
+ 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->is_mutable());
+ klass= find_statement_class(key);
+
+ uint flags= state->m_flags;
+
+ if (unlikely(klass == NULL) || !klass->m_enabled)
+ {
+ /* pop statement stack */
+ if (flags & STATE_FLAG_THREAD)
+ {
+ PFS_thread *pfs_thread= reinterpret_cast<PFS_thread *> (state->m_thread);
+ DBUG_ASSERT(pfs_thread != NULL);
+ if (pfs_thread->m_events_statements_count > 0)
+ pfs_thread->m_events_statements_count--;
+ }
+
+ state->m_discarded= true;
+ return NULL;
+ }
+
+ 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);
+ pfs->m_sqltext_truncated= true;
+ }
+ if (text_len)
+ memcpy(pfs->m_sqltext, text, text_len);
+ pfs->m_sqltext_length= text_len;
+ pfs->m_sqltext_cs_number= state->m_cs_number;
+ }
+
+ 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.
+ */
+ const sql_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;
+
+ if (digest_storage != NULL)
+ {
+ /* 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);
+
+ thread->m_stmt_lock.allocated_to_dirty();
+
+ 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();
+ pfs->m_error_count++;
+ 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 (digest_storage != NULL)
+ {
+ /*
+ The following columns in events_statement_current:
+ - DIGEST,
+ - DIGEST_TEXT
+ are computed from the digest storage.
+ */
+ pfs->m_digest_storage.copy(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--;
+ thread->m_stmt_lock.dirty_to_allocated();
+ }
+ }
+ 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;
+
+ if (digest_storage != NULL)
+ {
+ /* 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--;
+
+ DBUG_ASSERT(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);
+}
+
+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)
+ {
+ return reinterpret_cast<PSI_digest_locker*> (locker);
+ }
+
+ return NULL;
+}
+
+void pfs_digest_end_v1(PSI_digest_locker *locker, const sql_digest_storage *digest)
+{
+ PSI_statement_locker_state *statement_state;
+ statement_state= reinterpret_cast<PSI_statement_locker_state*> (locker);
+ DBUG_ASSERT(statement_state != NULL);
+ DBUG_ASSERT(digest != NULL);
+
+ if (statement_state->m_discarded)
+ return;
+
+ if (statement_state->m_flags & STATE_FLAG_DIGEST)
+ {
+ statement_state->m_digest= digest;
+ }
+}
+
+/**
+ 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)
+ {
+ const CHARSET_INFO *cs = static_cast<const CHARSET_INFO *> (from_cs);
+
+ /* 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_session_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_number= cs->number;
+ thd->m_session_lock.dirty_to_allocated();
+
+ if (copy_size == length)
+ return 0;
+
+ session_connect_attrs_lost++;
+ return 1;
+ }
+ return 0;
+}
+
+
+/**
+ Implementation of the instrumentation interface.
+ @sa PSI_v1.
+*/
PSI_v1 PFS_v1=
{
register_mutex_v1,
@@ -2049,28 +5225,39 @@ PSI_v1 PFS_v1=
register_cond_v1,
register_thread_v1,
register_file_v1,
+ register_stage_v1,
+ register_statement_v1,
+ register_socket_v1,
init_mutex_v1,
destroy_mutex_v1,
init_rwlock_v1,
destroy_rwlock_v1,
init_cond_v1,
destroy_cond_v1,
+ init_socket_v1,
+ destroy_socket_v1,
get_table_share_v1,
release_table_share_v1,
+ drop_table_share_v1,
open_table_v1,
+ unbind_table_v1,
+ rebind_table_v1,
close_table_v1,
create_file_v1,
spawn_thread_v1,
new_thread_v1,
set_thread_id_v1,
get_thread_v1,
+ set_thread_user_v1,
+ set_thread_account_v1,
+ set_thread_db_v1,
+ set_thread_command_v1,
+ set_thread_start_time_v1,
+ set_thread_state_v1,
+ set_thread_info_v1,
set_thread_v1,
delete_current_thread_v1,
delete_thread_v1,
- get_thread_mutex_locker_v1,
- get_thread_rwlock_locker_v1,
- get_thread_cond_locker_v1,
- get_thread_table_locker_v1,
get_thread_file_name_locker_v1,
get_thread_file_stream_locker_v1,
get_thread_file_descriptor_locker_v1,
@@ -2078,21 +5265,58 @@ PSI_v1 PFS_v1=
unlock_rwlock_v1,
signal_cond_v1,
broadcast_cond_v1,
+ start_idle_wait_v1,
+ end_idle_wait_v1,
start_mutex_wait_v1,
end_mutex_wait_v1,
- start_rwlock_rdwait_v1,
+ start_rwlock_wait_v1, /* read */
end_rwlock_rdwait_v1,
- start_rwlock_wrwait_v1,
+ start_rwlock_wait_v1, /* write */
end_rwlock_wrwait_v1,
start_cond_wait_v1,
end_cond_wait_v1,
- start_table_wait_v1,
- end_table_wait_v1,
+ start_table_io_wait_v1,
+ end_table_io_wait_v1,
+ start_table_lock_wait_v1,
+ end_table_lock_wait_v1,
start_file_open_wait_v1,
end_file_open_wait_v1,
end_file_open_wait_and_bind_to_descriptor_v1,
start_file_wait_v1,
- end_file_wait_v1
+ end_file_wait_v1,
+ start_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_end_v1,
+ set_thread_connect_attrs_v1,
};
static void* get_interface(int version)
diff --git a/storage/perfschema/pfs.h b/storage/perfschema/pfs.h
index ee1ec7325f6..da5e11edab7 100644
--- a/storage/perfschema/pfs.h
+++ b/storage/perfschema/pfs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,8 +27,14 @@
#include <my_pthread.h>
#include <mysql/psi/psi.h>
+/**
+ Entry point to the performance schema implementation.
+ This singleton is used to discover the performance schema services.
+*/
extern struct PSI_bootstrap PFS_bootstrap;
+/** Performance schema Thread Local Storage key. */
extern pthread_key(PFS_thread*, THR_PFS);
+/** True when @c THR_PFS is initialized. */
extern bool THR_PFS_initialized;
#endif
diff --git a/storage/perfschema/pfs_account.cc b/storage/perfschema/pfs_account.cc
new file mode 100644
index 00000000000..6f949d44065
--- /dev/null
+++ b/storage/perfschema/pfs_account.cc
@@ -0,0 +1,583 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 Street, Fifth Floor, Boston, MA 02110-1335 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, sizeof(PFS_account), 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;
+ pfs_free(account_instr_class_stages_array);
+ account_instr_class_stages_array= 0;
+ pfs_free(account_instr_class_statements_array);
+ account_instr_class_statements_array=0;
+ 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(PFS_user *safe_user, PFS_host *safe_host)
+{
+ aggregate_waits(safe_user, safe_host);
+ aggregate_stages(safe_user, safe_host);
+ aggregate_statements(safe_user, safe_host);
+ aggregate_stats(safe_user, safe_host);
+}
+
+void PFS_account::aggregate_waits(PFS_user *safe_user, PFS_host *safe_host)
+{
+ if (likely(safe_user != NULL && safe_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,
+ safe_user->m_instr_class_waits_stats,
+ safe_host->m_instr_class_waits_stats);
+ return;
+ }
+
+ if (safe_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,
+ safe_user->m_instr_class_waits_stats);
+ return;
+ }
+
+ if (safe_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,
+ safe_host->m_instr_class_waits_stats);
+ return;
+ }
+
+ /* Orphan account, no parent to aggregate to. */
+ reset_waits_stats();
+ return;
+}
+
+void PFS_account::aggregate_stages(PFS_user *safe_user, PFS_host *safe_host)
+{
+ if (likely(safe_user != NULL && safe_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,
+ safe_user->m_instr_class_stages_stats,
+ safe_host->m_instr_class_stages_stats);
+ return;
+ }
+
+ if (safe_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,
+ safe_user->m_instr_class_stages_stats,
+ global_instr_class_stages_array);
+ return;
+ }
+
+ if (safe_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,
+ safe_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(PFS_user *safe_user, PFS_host *safe_host)
+{
+ if (likely(safe_user != NULL && safe_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,
+ safe_user->m_instr_class_statements_stats,
+ safe_host->m_instr_class_statements_stats);
+ return;
+ }
+
+ if (safe_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,
+ safe_user->m_instr_class_statements_stats,
+ global_instr_class_statements_array);
+ return;
+ }
+
+ if (safe_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,
+ safe_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(PFS_user *safe_user, PFS_host *safe_host)
+{
+ if (likely(safe_user != NULL && safe_host != NULL))
+ {
+ safe_user->m_disconnected_count+= m_disconnected_count;
+ safe_host->m_disconnected_count+= m_disconnected_count;
+ m_disconnected_count= 0;
+ return;
+ }
+
+ if (safe_user != NULL)
+ {
+ safe_user->m_disconnected_count+= m_disconnected_count;
+ m_disconnected_count= 0;
+ return;
+ }
+
+ if (safe_host != NULL)
+ {
+ safe_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,
+ PFS_user *safe_user, PFS_host *safe_host)
+{
+ account->aggregate(safe_user, safe_host);
+
+ LF_PINS *pins= get_account_hash_pins(thread);
+ if (unlikely(pins == NULL))
+ return;
+
+ PFS_account **entry;
+ entry= reinterpret_cast<PFS_account**>
+ (lf_hash_search(&account_hash, pins,
+ account->m_key.m_hash_key,
+ account->m_key.m_key_length));
+ if (entry && (entry != MY_ERRPTR))
+ {
+ DBUG_ASSERT(*entry == account);
+ if (account->get_refcount() == 0)
+ {
+ lf_hash_delete(&account_hash, pins,
+ account->m_key.m_hash_key,
+ account->m_key.m_key_length);
+ if (account->m_user != NULL)
+ {
+ account->m_user->release();
+ account->m_user= NULL;
+ }
+ if (account->m_host != NULL)
+ {
+ account->m_host->release();
+ account->m_host= NULL;
+ }
+ account->m_lock.allocated_to_free();
+ }
+ }
+
+ lf_hash_search_unpin(pins);
+}
+
+/** Purge non connected user@host, reset stats of connected user@host. */
+void purge_all_account(void)
+{
+ PFS_thread *thread= PFS_thread::get_current_thread();
+ if (unlikely(thread == NULL))
+ return;
+
+ PFS_account *pfs= account_array;
+ PFS_account *pfs_last= account_array + account_max;
+ PFS_user *user;
+ PFS_host *host;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ if (pfs->m_lock.is_populated())
+ {
+ user= sanitize_user(pfs->m_user);
+ host= sanitize_host(pfs->m_host);
+ pfs->aggregate_stats(user, host);
+
+ if (pfs->get_refcount() == 0)
+ purge_account(thread, pfs, user, host);
+ }
+ }
+}
+
+/** @} */
diff --git a/storage/perfschema/pfs_account.h b/storage/perfschema/pfs_account.h
new file mode 100644
index 00000000000..544abf913ae
--- /dev/null
+++ b/storage/perfschema/pfs_account.h
@@ -0,0 +1,122 @@
+/* Copyright (c) 2010, 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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(PFS_user *safe_user, PFS_host *safe_host);
+ void aggregate_waits(PFS_user *safe_user, PFS_host *safe_host);
+ void aggregate_stages(PFS_user *safe_user, PFS_host *safe_host);
+ void aggregate_statements(PFS_user *safe_user, PFS_host *safe_host);
+ void aggregate_stats(PFS_user *safe_user, PFS_host *safe_host);
+ 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
deleted file mode 100644
index 6662c29c05d..00000000000
--- a/storage/perfschema/pfs_atomic.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- Copyright (c) 2009, 2010 Sun Microsystems, Inc.
- Use is subject to license terms.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- 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, Fifth Floor, 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];
-static int init_done;
-
-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]);
- init_done= 1;
-}
-
-void PFS_atomic::cleanup(void)
-{
- uint i;
- if (!init_done)
- return;
- 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
index ace541d177c..def9339d06d 100644
--- a/storage/perfschema/pfs_atomic.h
+++ b/storage/perfschema/pfs_atomic.h
@@ -1,6 +1,4 @@
-/*
- Copyright (c) 2009, 2010 Sun Microsystems, Inc.
- Use is subject to license terms.
+/* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -29,120 +27,106 @@
class PFS_atomic
{
public:
- static void init();
- 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;
+ return my_atomic_load32(ptr);
+ }
+
+ /** Atomic load. */
+ static inline int64 load_64(volatile int64 *ptr)
+ {
+ return my_atomic_load64(ptr);
}
/** 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;
+ return (uint32) my_atomic_load32((int32*) ptr);
+ }
+
+ /** Atomic load. */
+ static inline uint64 load_u64(volatile uint64 *ptr)
+ {
+ return (uint64) my_atomic_load64((int64*) ptr);
}
/** 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)
+ {
+ my_atomic_store64(ptr, value);
}
/** Atomic store. */
static inline void store_u32(volatile uint32 *ptr, uint32 value)
{
- wrlock(ptr);
my_atomic_store32((int32*) ptr, (int32) value);
- wrunlock(ptr);
}
- /** Atomic add. */
- static inline int32 add_32(volatile int32 *ptr, int32 value)
+ /** Atomic store. */
+ static inline void store_u64(volatile uint64 *ptr, uint64 value)
{
- int32 result;
- wrlock(ptr);
- result= my_atomic_add32(ptr, value);
- wrunlock(ptr);
- return result;
+ my_atomic_store64((int64*) ptr, (int64) value);
}
/** Atomic add. */
- static inline uint32 add_u32(volatile uint32 *ptr, uint32 value)
+ static inline int32 add_32(volatile int32 *ptr, int32 value)
{
- uint32 result;
- wrlock(ptr);
- result= (uint32) my_atomic_add32((int32*) ptr, (int32) value);
- wrunlock(ptr);
- return result;
+ return my_atomic_add32(ptr, value);
}
- /** Atomic compare and swap. */
- static inline bool cas_32(volatile int32 *ptr, int32 *old_value,
- int32 new_value)
+ /** Atomic add. */
+ static inline int64 add_64(volatile int64 *ptr, int64 value)
{
- bool result;
- wrlock(ptr);
- result= my_atomic_cas32(ptr, old_value, new_value);
- wrunlock(ptr);
- return result;
+ return my_atomic_add64(ptr, value);
}
- /** Atomic compare and swap. */
- static inline bool cas_u32(volatile uint32 *ptr, uint32 *old_value,
- uint32 new_value)
+ /** Atomic add. */
+ static inline uint32 add_u32(volatile uint32 *ptr, uint32 value)
{
- bool result;
- wrlock(ptr);
- result= my_atomic_cas32((int32*) ptr, (int32*) old_value,
- (uint32) new_value);
- wrunlock(ptr);
- return result;
+ return (uint32) my_atomic_add32((int32*) ptr, (int32) value);
}
-private:
- static my_atomic_rwlock_t m_rwlock_array[256];
-
- static inline my_atomic_rwlock_t *get_rwlock(volatile void *ptr)
+ /** Atomic add. */
+ static inline uint64 add_u64(volatile uint64 *ptr, uint64 value)
{
- /*
- 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;
+ return (uint64) my_atomic_add64((int64*) ptr, (int64) value);
}
- static inline void rdlock(volatile void *ptr)
+ /** Atomic compare and swap. */
+ static inline bool cas_32(volatile int32 *ptr, int32 *old_value,
+ int32 new_value)
{
- my_atomic_rwlock_rdlock(get_rwlock(ptr));
+ return my_atomic_cas32(ptr, old_value, new_value);
}
- static inline void wrlock(volatile void *ptr)
+ /** Atomic compare and swap. */
+ static inline bool cas_64(volatile int64 *ptr, int64 *old_value,
+ int64 new_value)
{
- my_atomic_rwlock_wrlock(get_rwlock(ptr));
+ return my_atomic_cas64(ptr, old_value, new_value);
}
- static inline void rdunlock(volatile void *ptr)
+ /** Atomic compare and swap. */
+ static inline bool cas_u32(volatile uint32 *ptr, uint32 *old_value,
+ uint32 new_value)
{
- my_atomic_rwlock_rdunlock(get_rwlock(ptr));
+ return my_atomic_cas32((int32*) ptr, (int32*) old_value,
+ (uint32) new_value);
}
- static inline void wrunlock(volatile void *ptr)
+ /** Atomic compare and swap. */
+ static inline bool cas_u64(volatile uint64 *ptr, uint64 *old_value,
+ uint64 new_value)
{
- my_atomic_rwlock_wrunlock(get_rwlock(ptr));
+ return my_atomic_cas64((int64*) ptr, (int64*) old_value,
+ (uint64) new_value);
}
};
diff --git a/storage/perfschema/pfs_autosize.cc b/storage/perfschema/pfs_autosize.cc
new file mode 100644
index 00000000000..d099a3f1836
--- /dev/null
+++ b/storage/perfschema/pfs_autosize.cc
@@ -0,0 +1,386 @@
+/* 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, Fifth Floor, 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 "set_var.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;
+
+ SYSVAR_AUTOSIZE(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);
+ SYSVAR_AUTOSIZE(p->m_table_share_sizing,
+ apply_load_factor(count, h->m_load_factor_static));
+ }
+
+ if (p->m_account_sizing < 0)
+ {
+ SYSVAR_AUTOSIZE(p->m_account_sizing,
+ h->m_account_sizing);
+ }
+
+ if (p->m_user_sizing < 0)
+ {
+ SYSVAR_AUTOSIZE(p->m_user_sizing,
+ h->m_user_sizing);
+ }
+
+ if (p->m_host_sizing < 0)
+ {
+ SYSVAR_AUTOSIZE(p->m_host_sizing,
+ h->m_host_sizing);
+ }
+
+ if (p->m_events_waits_history_sizing < 0)
+ {
+ SYSVAR_AUTOSIZE(p->m_events_waits_history_sizing,
+ h->m_events_waits_history_sizing);
+ }
+
+ if (p->m_events_waits_history_long_sizing < 0)
+ {
+ SYSVAR_AUTOSIZE(p->m_events_waits_history_long_sizing,
+ h->m_events_waits_history_long_sizing);
+ }
+
+ if (p->m_events_stages_history_sizing < 0)
+ {
+ SYSVAR_AUTOSIZE(p->m_events_stages_history_sizing,
+ h->m_events_stages_history_sizing);
+ }
+
+ if (p->m_events_stages_history_long_sizing < 0)
+ {
+ SYSVAR_AUTOSIZE(p->m_events_stages_history_long_sizing,
+ h->m_events_stages_history_long_sizing);
+ }
+
+ if (p->m_events_statements_history_sizing < 0)
+ {
+ SYSVAR_AUTOSIZE(p->m_events_statements_history_sizing,
+ h->m_events_statements_history_sizing);
+ }
+
+ if (p->m_events_statements_history_long_sizing < 0)
+ {
+ SYSVAR_AUTOSIZE(p->m_events_statements_history_long_sizing,
+ h->m_events_statements_history_long_sizing);
+ }
+
+ if (p->m_digest_sizing < 0)
+ {
+ SYSVAR_AUTOSIZE(p->m_digest_sizing,
+ h->m_digest_sizing);
+ }
+
+ if (p->m_session_connect_attrs_sizing < 0)
+ {
+ SYSVAR_AUTOSIZE(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;
+
+ SYSVAR_AUTOSIZE(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;
+
+ SYSVAR_AUTOSIZE(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;
+
+ SYSVAR_AUTOSIZE(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);
+ SYSVAR_AUTOSIZE(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;
+
+ SYSVAR_AUTOSIZE(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;
+
+ SYSVAR_AUTOSIZE(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
deleted file mode 100644
index 07560313076..00000000000
--- a/storage/perfschema/pfs_check.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright (c) 2009, 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, Fifth Floor, 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);
-
- thd->reset_globals();
- delete thd;
- DBUG_VOID_RETURN;
-}
-
diff --git a/storage/perfschema/pfs_column_types.h b/storage/perfschema/pfs_column_types.h
index b09404e7523..ef657b38707 100644
--- a/storage/perfschema/pfs_column_types.h
+++ b/storage/perfschema/pfs_column_types.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc.
- Use is subject to license terms.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -39,9 +38,27 @@
/** Size of the OBJECT_NAME columns. */
#define COL_OBJECT_NAME_SIZE 64
+/** Size of the INDEX_NAME columns. */
+#define COL_INDEX_NAME_SIZE 64
+
+/**
+ Size of INFO columns.
+ Size in bytes of:
+ - performance_schema.events_statement_current (INFO)
+ - performance_schema.events_statement_history (INFO)
+ - performance_schema.events_statement_history_long (INFO)
+*/
+#define COL_INFO_SIZE 1024
+
/** Size of the SOURCE columns. */
#define COL_SOURCE_SIZE 64
+/** Size of the DIGEST columns. */
+#define COL_DIGEST_SIZE 64
+
+/** Size of the DIGEST_TEXT columns. */
+#define COL_DIGEST_TEXT_SIZE 1024
+
/**
Enum values for the TIMER_NAME columns.
This enum is found in the following tables:
@@ -57,8 +74,11 @@ enum enum_timer_name
TIMER_NAME_TICK= 5
};
+/** Integer, first value of @sa enum_timer_name. */
#define FIRST_TIMER_NAME (static_cast<int> (TIMER_NAME_CYCLE))
+/** Integer, last value of @sa enum_timer_name. */
#define LAST_TIMER_NAME (static_cast<int> (TIMER_NAME_TICK))
+/** Integer, number of values of @sa enum_timer_name. */
#define COUNT_TIMER_NAME (LAST_TIMER_NAME - FIRST_TIMER_NAME + 1)
/**
@@ -83,17 +103,21 @@ enum enum_yes_no
*/
enum enum_operation_type
{
+ /* Mutex operations */
OPERATION_TYPE_LOCK= 1,
OPERATION_TYPE_TRYLOCK= 2,
+ /* Rwlock operations */
OPERATION_TYPE_READLOCK= 3,
OPERATION_TYPE_WRITELOCK= 4,
OPERATION_TYPE_TRYREADLOCK= 5,
OPERATION_TYPE_TRYWRITELOCK= 6,
+ /* Cond operations */
OPERATION_TYPE_WAIT= 7,
OPERATION_TYPE_TIMEDWAIT= 8,
+ /* File operations */
OPERATION_TYPE_FILECREATE= 9,
OPERATION_TYPE_FILECREATETMP= 10,
OPERATION_TYPE_FILEOPEN= 11,
@@ -110,11 +134,89 @@ enum enum_operation_type
OPERATION_TYPE_FILECHSIZE= 22,
OPERATION_TYPE_FILEDELETE= 23,
OPERATION_TYPE_FILERENAME= 24,
- OPERATION_TYPE_FILESYNC= 25
+ OPERATION_TYPE_FILESYNC= 25,
+
+ /* Table io operations */
+ OPERATION_TYPE_TABLE_FETCH= 26,
+ OPERATION_TYPE_TABLE_WRITE_ROW= 27,
+ OPERATION_TYPE_TABLE_UPDATE_ROW= 28,
+ OPERATION_TYPE_TABLE_DELETE_ROW= 29,
+
+ /* Table lock operations */
+ OPERATION_TYPE_TL_READ_NORMAL= 30,
+ OPERATION_TYPE_TL_READ_WITH_SHARED_LOCKS= 31,
+ OPERATION_TYPE_TL_READ_HIGH_PRIORITY= 32,
+ OPERATION_TYPE_TL_READ_NO_INSERTS= 33,
+ OPERATION_TYPE_TL_WRITE_ALLOW_WRITE= 34,
+ OPERATION_TYPE_TL_WRITE_CONCURRENT_INSERT= 35,
+ OPERATION_TYPE_TL_WRITE_DELAYED= 36,
+ OPERATION_TYPE_TL_WRITE_LOW_PRIORITY= 37,
+ OPERATION_TYPE_TL_WRITE_NORMAL= 38,
+ OPERATION_TYPE_TL_READ_EXTERNAL= 39,
+ OPERATION_TYPE_TL_WRITE_EXTERNAL= 40,
+
+ /* Socket operations */
+ OPERATION_TYPE_SOCKETCREATE = 41,
+ OPERATION_TYPE_SOCKETCONNECT = 42,
+ OPERATION_TYPE_SOCKETBIND = 43,
+ OPERATION_TYPE_SOCKETCLOSE = 44,
+ OPERATION_TYPE_SOCKETSEND = 45,
+ OPERATION_TYPE_SOCKETRECV = 46,
+ OPERATION_TYPE_SOCKETSENDTO = 47,
+ OPERATION_TYPE_SOCKETRECVFROM = 48,
+ OPERATION_TYPE_SOCKETSENDMSG = 49,
+ OPERATION_TYPE_SOCKETRECVMSG = 50,
+ OPERATION_TYPE_SOCKETSEEK = 51,
+ OPERATION_TYPE_SOCKETOPT = 52,
+ OPERATION_TYPE_SOCKETSTAT = 53,
+ OPERATION_TYPE_SOCKETSHUTDOWN = 54,
+ OPERATION_TYPE_SOCKETSELECT = 55,
+
+ /* Idle operation */
+ OPERATION_TYPE_IDLE= 56
};
+/** Integer, first value of @sa enum_operation_type. */
#define FIRST_OPERATION_TYPE (static_cast<int> (OPERATION_TYPE_LOCK))
-#define LAST_OPERATION_TYPE (static_cast<int> (OPERATION_TYPE_FILESYNC))
+/** Integer, last value of @sa enum_operation_type. */
+#define LAST_OPERATION_TYPE (static_cast<int> (OPERATION_TYPE_IDLE))
+/** Integer, number of values of @sa enum_operation_type. */
#define COUNT_OPERATION_TYPE (LAST_OPERATION_TYPE - FIRST_OPERATION_TYPE + 1)
+/**
+ Enum values for the various OBJECT_TYPE columns.
+*/
+enum enum_object_type
+{
+ OBJECT_TYPE_TABLE= 1,
+ OBJECT_TYPE_TEMPORARY_TABLE= 2
+};
+/** Integer, first value of @sa enum_object_type. */
+#define FIRST_OBJECT_TYPE (static_cast<int> (OBJECT_TYPE_TABLE))
+/** Integer, last value of @sa enum_object_type. */
+#define LAST_OBJECT_TYPE (static_cast<int> (OBJECT_TYPE_TEMPORARY_TABLE))
+/** Integer, number of values of @sa enum_object_type. */
+#define COUNT_OBJECT_TYPE (LAST_OBJECT_TYPE - FIRST_OBJECT_TYPE + 1)
+
+/**
+ Enum values for the NESTING_EVENT_TYPE columns.
+ This enum is found in the following tables:
+ - performance_schema.events_waits_current (NESTING_EVENT_TYPE)
+ - performance_schema.events_stages_current (NESTING_EVENT_TYPE)
+ - performance_schema.events_statements_current (NESTING_EVENT_TYPE)
+*/
+enum enum_event_type
+{
+ EVENT_TYPE_STATEMENT= 1,
+ EVENT_TYPE_STAGE= 2,
+ EVENT_TYPE_WAIT= 3
+};
+
+/** Integer, first value of @sa enum_event_type. */
+#define FIRST_EVENT_TYPE (static_cast<int> (EVENT_TYPE_STATEMENT))
+/** Integer, last value of @sa enum_event_type. */
+#define LAST_EVENT_TYPE (static_cast<int> (EVENT_TYPE_WAIT))
+/** Integer, number of values of @sa enum_event_type. */
+#define COUNT_EVENT_TYPE (LAST_EVENT_TYPE - FIRST_EVENT_TYPE + 1)
+
#endif
diff --git a/storage/perfschema/pfs_column_values.cc b/storage/perfschema/pfs_column_values.cc
index 91186a804d9..87fa9f0b639 100644
--- a/storage/perfschema/pfs_column_values.cc
+++ b/storage/perfschema/pfs_column_values.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
schema tables (implementation).
*/
+#include "my_global.h"
#include "pfs_column_values.h"
LEX_STRING PERFORMANCE_SCHEMA_str=
@@ -39,3 +40,11 @@ LEX_STRING thread_instrument_prefix=
LEX_STRING file_instrument_prefix=
{ C_STRING_WITH_LEN("wait/io/file/") };
+LEX_STRING stage_instrument_prefix=
+{ C_STRING_WITH_LEN("stage/") };
+
+LEX_STRING statement_instrument_prefix=
+{ C_STRING_WITH_LEN("statement/") };
+
+LEX_STRING socket_instrument_prefix=
+{ C_STRING_WITH_LEN("wait/io/socket/") };
diff --git a/storage/perfschema/pfs_column_values.h b/storage/perfschema/pfs_column_values.h
index c3c49370f74..eb25a5977e3 100644
--- a/storage/perfschema/pfs_column_values.h
+++ b/storage/perfschema/pfs_column_values.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,13 +24,24 @@
performance schema tables (declarations).
*/
+/** String, "PERFORMANCE_SCHEMA". */
extern LEX_STRING PERFORMANCE_SCHEMA_str;
+/** String prefix for all mutex instruments. */
extern LEX_STRING mutex_instrument_prefix;
+/** String prefix for all rwlock instruments. */
extern LEX_STRING rwlock_instrument_prefix;
+/** String prefix for all cond instruments. */
extern LEX_STRING cond_instrument_prefix;
+/** String prefix for all thread instruments. */
extern LEX_STRING thread_instrument_prefix;
+/** String prefix for all file instruments. */
extern LEX_STRING file_instrument_prefix;
+/** String prefix for all stage instruments. */
+extern LEX_STRING stage_instrument_prefix;
+/** String prefix for all statement instruments. */
+extern LEX_STRING statement_instrument_prefix;
+extern LEX_STRING socket_instrument_prefix;
#endif
diff --git a/storage/perfschema/pfs_con_slice.cc b/storage/perfschema/pfs_con_slice.cc
new file mode 100644
index 00000000000..bce4918ae9e
--- /dev/null
+++ b/storage/perfschema/pfs_con_slice.cc
@@ -0,0 +1,119 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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-1335 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, sizeof(PFS_single_stat), 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, sizeof(PFS_stage_stat), 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, sizeof(PFS_statement_stat), 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..f83764339c3
--- /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-1335 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..ec2da41e30b
--- /dev/null
+++ b/storage/perfschema/pfs_defaults.cc
@@ -0,0 +1,63 @@
+/* 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, Fifth Floor, 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..d95c4914e9d
--- /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, Fifth Floor, 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..1362ef2676b
--- /dev/null
+++ b/storage/perfschema/pfs_digest.cc
@@ -0,0 +1,388 @@
+/* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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
+*/
+
+#define MYSQL_LEX 1
+
+#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 "sql_lex.h"
+#include "sql_get_diagnostics.h"
+#include "sql_string.h"
+#include <string.h>
+
+size_t digest_max= 0;
+ulong digest_lost= 0;
+
+/** EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */
+PFS_statements_digest_stat *statements_digest_stat_array= NULL;
+static unsigned char *statements_digest_token_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 PFS_ALIGNED digest_monotonic_index;
+bool digest_full= false;
+
+LF_HASH digest_hash;
+static bool digest_hash_inited= false;
+
+/**
+ Initialize table EVENTS_STATEMENTS_SUMMARY_BY_DIGEST.
+ @param param performance schema sizing
+*/
+int init_digest(const PFS_global_param *param)
+{
+ /*
+ Allocate memory for statements_digest_stat_array based on
+ performance_schema_digests_size values
+ */
+ digest_max= param->m_digest_sizing;
+ digest_lost= 0;
+ PFS_atomic::store_u32(& digest_monotonic_index, 1);
+ digest_full= false;
+
+ if (digest_max == 0)
+ return 0;
+
+ statements_digest_stat_array=
+ PFS_MALLOC_ARRAY(digest_max,
+ sizeof(PFS_statements_digest_stat),
+ PFS_statements_digest_stat,
+ MYF(MY_ZEROFILL));
+
+ if (unlikely(statements_digest_stat_array == NULL))
+ {
+ cleanup_digest();
+ return 1;
+ }
+
+ if (pfs_max_digest_length > 0)
+ {
+ /* Size of each digest array. */
+ size_t digest_memory_size= pfs_max_digest_length * sizeof(unsigned char);
+
+ statements_digest_token_array=
+ PFS_MALLOC_ARRAY(digest_max,
+ digest_memory_size,
+ unsigned char,
+ MYF(MY_ZEROFILL));
+
+ if (unlikely(statements_digest_token_array == NULL))
+ {
+ cleanup_digest();
+ return 1;
+ }
+ }
+
+ for (size_t index= 0; index < digest_max; index++)
+ {
+ statements_digest_stat_array[index].reset_data(statements_digest_token_array
+ + index * pfs_max_digest_length, pfs_max_digest_length);
+ }
+
+ /* Set record[0] as allocated. */
+ statements_digest_stat_array[0].m_lock.set_allocated();
+
+ 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);
+ pfs_free(statements_digest_token_array);
+ statements_digest_stat_array= NULL;
+ statements_digest_token_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,
+ const sql_digest_storage *digest_storage,
+ const char *schema_name,
+ uint schema_name_length)
+{
+ DBUG_ASSERT(digest_storage != NULL);
+
+ 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_digest_md5(digest_storage, hash_key.m_md5);
+ memcpy((void*)& digest_storage->m_md5, &hash_key.m_md5, MD5_HASH_SIZE);
+ /* 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;
+ uint retry_count= 0;
+ const uint retry_max= 3;
+ size_t safe_index;
+ size_t attempts= 0;
+ PFS_statements_digest_stat **entry;
+ PFS_statements_digest_stat *pfs= NULL;
+
+ ulonglong now= my_hrtime().val;
+
+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);
+
+ if (digest_full)
+ {
+ /* digest_stat array is full. Add stat at index 0 and return. */
+ pfs= &statements_digest_stat_array[0];
+ digest_lost++;
+
+ if (pfs->m_first_seen == 0)
+ pfs->m_first_seen= now;
+ pfs->m_last_seen= now;
+ return & pfs->m_stat;
+ }
+
+ while (++attempts <= digest_max)
+ {
+ safe_index= PFS_atomic::add_u32(& digest_monotonic_index, 1) % digest_max;
+ if (safe_index == 0)
+ {
+ /* Record [0] is reserved. */
+ continue;
+ }
+
+ /* Add a new record in digest stat array. */
+ DBUG_ASSERT(safe_index < digest_max);
+ pfs= &statements_digest_stat_array[safe_index];
+
+ if (pfs->m_lock.is_free())
+ {
+ if (pfs->m_lock.free_to_dirty())
+ {
+ /* 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.
+ */
+ pfs->m_digest_storage.copy(digest_storage);
+
+ pfs->m_first_seen= now;
+ pfs->m_last_seen= now;
+
+ res= lf_hash_insert(&digest_hash, pins, &pfs);
+ if (likely(res == 0))
+ {
+ pfs->m_lock.dirty_to_allocated();
+ return & pfs->m_stat;
+ }
+
+ pfs->m_lock.dirty_to_free();
+
+ 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;
+ }
+ }
+ }
+
+ /* The digest array is now full. */
+ digest_full= true;
+ 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;
+}
+
+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(unsigned char *token_array, uint length)
+{
+ m_lock.set_dirty();
+ m_digest_storage.reset(token_array, length);
+ m_stat.reset();
+ m_first_seen= 0;
+ m_last_seen= 0;
+ m_lock.dirty_to_free();
+}
+
+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()
+{
+ 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 (size_t index= 0; index < digest_max; index++)
+ {
+ statements_digest_stat_array[index].reset_index(thread);
+ statements_digest_stat_array[index].reset_data(statements_digest_token_array + index * pfs_max_digest_length, pfs_max_digest_length);
+ }
+
+ /* Mark record[0] as allocated again. */
+ statements_digest_stat_array[0].m_lock.set_allocated();
+
+ /*
+ Reset index which indicates where the next calculated digest information
+ to be inserted in statements_digest_stat_array.
+ */
+ PFS_atomic::store_u32(& digest_monotonic_index, 1);
+ digest_full= false;
+}
+
diff --git a/storage/perfschema/pfs_digest.h b/storage/perfschema/pfs_digest.h
new file mode 100644
index 00000000000..543fa7858a4
--- /dev/null
+++ b/storage/perfschema/pfs_digest.h
@@ -0,0 +1,86 @@
+/* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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"
+#include "sql_digest.h"
+
+extern bool flag_statements_digest;
+extern size_t digest_max;
+extern ulong digest_lost;
+struct PFS_thread;
+
+/**
+ Structure to store a MD5 hash value (digest) for a statement.
+*/
+struct PFS_digest_key
+{
+ unsigned char m_md5[MD5_HASH_SIZE];
+ char m_schema_name[NAME_LEN];
+ uint m_schema_name_length;
+};
+
+/** A statement digest stat record. */
+struct PFS_ALIGNED PFS_statements_digest_stat
+{
+ /** Internal lock. */
+ pfs_lock m_lock;
+
+ /** Digest Schema + MD5 Hash. */
+ PFS_digest_key m_digest_key;
+
+ /** Digest Storage. */
+ sql_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(unsigned char* token_array, uint length);
+ /** 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,
+ const sql_digest_storage *digest_storage,
+ const char *schema_name,
+ uint schema_name_length);
+
+void reset_esms_by_digest();
+
+/* Exposing the data directly, for iterators. */
+extern PFS_statements_digest_stat *statements_digest_stat_array;
+
+extern LF_HASH digest_hash;
+
+#endif
diff --git a/storage/perfschema/pfs_engine_table.cc b/storage/perfschema/pfs_engine_table.cc
index 23a9b59acaf..289eb034e03 100644
--- a/storage/perfschema/pfs_engine_table.cc
+++ b/storage/perfschema/pfs_engine_table.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,24 +18,69 @@
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_threads.h"
#include "table_events_waits_summary.h"
+#include "table_ews_by_thread_by_event_name.h"
#include "table_ews_global_by_event_name.h"
+#include "table_host_cache.h"
+#include "table_os_global_by_type.h"
#include "table_sync_instances.h"
#include "table_file_instances.h"
-#include "table_file_summary.h"
+#include "table_file_summary_by_instance.h"
+#include "table_file_summary_by_event_name.h"
+#include "table_threads.h"
+
+#include "table_ews_by_host_by_event_name.h"
+#include "table_ews_by_user_by_event_name.h"
+#include "table_ews_by_account_by_event_name.h"
+#include "table_tiws_by_index_usage.h"
+#include "table_tiws_by_table.h"
+#include "table_tlws_by_table.h"
+
+#include "table_events_stages.h"
+#include "table_esgs_by_thread_by_event_name.h"
+#include "table_esgs_by_host_by_event_name.h"
+#include "table_esgs_by_user_by_event_name.h"
+#include "table_esgs_by_account_by_event_name.h"
+#include "table_esgs_global_by_event_name.h"
+
+#include "table_events_statements.h"
+#include "table_esms_by_thread_by_event_name.h"
+#include "table_esms_by_host_by_event_name.h"
+#include "table_esms_by_user_by_event_name.h"
+#include "table_esms_by_account_by_event_name.h"
+#include "table_esms_global_by_event_name.h"
+#include "table_esms_by_digest.h"
+
+#include "table_users.h"
+#include "table_accounts.h"
+#include "table_hosts.h"
+
+#include "table_socket_instances.h"
+#include "table_socket_summary_by_instance.h"
+#include "table_socket_summary_by_event_name.h"
+#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
@@ -47,126 +92,108 @@
static PFS_engine_table_share *all_shares[]=
{
+ &table_cond_instances::m_share,
&table_events_waits_current::m_share,
&table_events_waits_history::m_share,
&table_events_waits_history_long::m_share,
- &table_setup_consumers::m_share,
- &table_setup_instruments::m_share,
- &table_setup_timers::m_share,
- &table_performance_timers::m_share,
- &table_threads::m_share,
- &table_events_waits_summary_by_thread_by_event_name::m_share,
+ &table_ews_by_host_by_event_name::m_share,
&table_events_waits_summary_by_instance::m_share,
+ &table_ews_by_thread_by_event_name::m_share,
+ &table_ews_by_user_by_event_name::m_share,
+ &table_ews_by_account_by_event_name::m_share,
&table_ews_global_by_event_name::m_share,
+ &table_file_instances::m_share,
&table_file_summary_by_event_name::m_share,
&table_file_summary_by_instance::m_share,
+ &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_cond_instances::m_share,
- &table_file_instances::m_share,
+ &table_setup_actors::m_share,
+ &table_setup_consumers::m_share,
+ &table_setup_instruments::m_share,
+ &table_setup_objects::m_share,
+ &table_setup_timers::m_share,
+ &table_tiws_by_index_usage::m_share,
+ &table_tiws_by_table::m_share,
+ &table_tlws_by_table::m_share,
+ &table_threads::m_share,
+
+ &table_events_stages_current::m_share,
+ &table_events_stages_history::m_share,
+ &table_events_stages_history_long::m_share,
+ &table_esgs_by_thread_by_event_name::m_share,
+ &table_esgs_by_account_by_event_name::m_share,
+ &table_esgs_by_user_by_event_name::m_share,
+ &table_esgs_by_host_by_event_name::m_share,
+ &table_esgs_global_by_event_name::m_share,
+
+ &table_events_statements_current::m_share,
+ &table_events_statements_history::m_share,
+ &table_events_statements_history_long::m_share,
+ &table_esms_by_thread_by_event_name::m_share,
+ &table_esms_by_account_by_event_name::m_share,
+ &table_esms_by_user_by_event_name::m_share,
+ &table_esms_by_host_by_event_name::m_share,
+ &table_esms_global_by_event_name::m_share,
+ &table_esms_by_digest::m_share,
+
+ &table_users::m_share,
+ &table_accounts::m_share,
+ &table_hosts::m_share,
+
+ &table_socket_instances::m_share,
+ &table_socket_summary_by_instance::m_share,
+ &table_socket_summary_by_event_name::m_share,
+ &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)
+/** Initialize all the table share locks. */
+void PFS_engine_table_share::init_all_locks(void)
{
PFS_engine_table_share **current;
- DBUG_EXECUTE_IF("tampered_perfschema_table1",
- {
- /* Hack SETUP_INSTRUMENT, incompatible change. */
- all_shares[4]->m_field_def->count++;
- });
-
for (current= &all_shares[0]; (*current) != NULL; current++)
- (*current)->check_one_table(thd);
+ thr_lock_init((*current)->m_thr_lock_ptr);
}
-class PFS_check_intact : public Table_check_intact
+/** Delete all the table share locks. */
+void PFS_engine_table_share::delete_all_locks(void)
{
-protected:
- virtual void report_error(uint code, const char *fmt, ...);
-
-public:
- PFS_check_intact()
- {}
+ PFS_engine_table_share **current;
- ~PFS_check_intact()
- {}
-};
+ for (current= &all_shares[0]; (*current) != NULL; current++)
+ thr_lock_delete((*current)->m_thr_lock_ptr);
+}
-void PFS_check_intact::report_error(uint code, const char *fmt, ...)
+ha_rows PFS_engine_table_share::get_row_count(void) const
{
- 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);
+ /* 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;
}
-/**
- 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)
+int PFS_engine_table_share::write_row(TABLE *table, unsigned char *buf,
+ Field **fields) const
{
- 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);
+ my_bitmap_map *org_bitmap;
- if (! open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
+ if (m_write_row == NULL)
{
- PFS_check_intact checker;
-
- if (!checker.check(tables.table, m_field_def))
- m_checked= true;
- close_thread_tables(thd);
+ return HA_ERR_WRONG_COMMAND;
}
- 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;
+ /* 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);
- for (current= &all_shares[0]; (*current) != NULL; current++)
- thr_lock_delete((*current)->m_thr_lock_ptr);
+ return result;
}
static int compare_table_names(const char *name1, const char *name2)
@@ -226,15 +253,6 @@ int PFS_engine_table::read_row(TABLE *table,
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);
@@ -271,15 +289,6 @@ int PFS_engine_table::update_row(TABLE *table,
{
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);
@@ -288,6 +297,27 @@ int PFS_engine_table::update_row(TABLE *table,
return result;
}
+int PFS_engine_table::delete_row(TABLE *table,
+ const unsigned char *buf,
+ Field **fields)
+{
+ my_bitmap_map *org_bitmap;
+
+ /* We internally read from Fields to support the delete interface */
+ org_bitmap= dbug_tmp_use_all_columns(table, table->read_set);
+ int result= delete_row_values(table, buf, fields);
+ dbug_tmp_restore_column_map(table->read_set, org_bitmap);
+
+ return result;
+}
+
+int PFS_engine_table::delete_row_values(TABLE *,
+ const unsigned char *,
+ Field **)
+{
+ return HA_ERR_WRONG_COMMAND;
+}
+
/**
Get the position of the current row.
@param [out] ref position
@@ -306,6 +336,19 @@ void PFS_engine_table::set_position(const void *ref)
memcpy(m_pos_ptr, ref, m_share_ptr->m_ref_length);
}
+/**
+ Get the timer normalizer and class type for the current row.
+ @param [in] instr_class class
+*/
+void PFS_engine_table::get_normalizer(PFS_instr_class *instr_class)
+{
+ if (instr_class->m_type != m_class_type)
+ {
+ m_normalizer= time_normalizer::get(*instr_class->m_timer);
+ m_class_type= instr_class->m_type;
+ }
+}
+
void PFS_engine_table::set_field_ulong(Field *f, ulong value)
{
DBUG_ASSERT(f->real_type() == MYSQL_TYPE_LONG);
@@ -320,6 +363,14 @@ void PFS_engine_table::set_field_ulonglong(Field *f, ulonglong value)
f2->store(value, true);
}
+void PFS_engine_table::set_field_char_utf8(Field *f, const char* str,
+ uint len)
+{
+ DBUG_ASSERT(f->real_type() == MYSQL_TYPE_STRING);
+ Field_string *f2= (Field_string*) f;
+ f2->store(str, len, &my_charset_utf8_bin);
+}
+
void PFS_engine_table::set_field_varchar_utf8(Field *f, const char* str,
uint len)
{
@@ -328,6 +379,14 @@ void PFS_engine_table::set_field_varchar_utf8(Field *f, const char* str,
f2->store(str, len, &my_charset_utf8_bin);
}
+void PFS_engine_table::set_field_longtext_utf8(Field *f, const char* str,
+ uint len)
+{
+ DBUG_ASSERT(f->real_type() == MYSQL_TYPE_BLOB);
+ Field_blob *f2= (Field_blob*) f;
+ f2->store(str, len, &my_charset_utf8_bin);
+}
+
void PFS_engine_table::set_field_enum(Field *f, ulonglong value)
{
DBUG_ASSERT(f->real_type() == MYSQL_TYPE_ENUM);
@@ -335,6 +394,13 @@ void PFS_engine_table::set_field_enum(Field *f, ulonglong value)
f2->store_type(value);
}
+void PFS_engine_table::set_field_timestamp(Field *f, ulonglong value)
+{
+ DBUG_ASSERT(is_timestamp_type(f->real_type()));
+ Field_timestamp *f2= (Field_timestamp*) f;
+ f2->store_TIME((long)(value / 1000000), (value % 1000000));
+}
+
ulonglong PFS_engine_table::get_field_enum(Field *f)
{
DBUG_ASSERT(f->real_type() == MYSQL_TYPE_ENUM);
@@ -342,6 +408,24 @@ ulonglong PFS_engine_table::get_field_enum(Field *f)
return f2->val_int();
}
+String*
+PFS_engine_table::get_field_char_utf8(Field *f, String *val)
+{
+ DBUG_ASSERT(f->real_type() == MYSQL_TYPE_STRING);
+ Field_string *f2= (Field_string*) f;
+ val= f2->val_str(NULL, val);
+ return val;
+}
+
+String*
+PFS_engine_table::get_field_varchar_utf8(Field *f, String *val)
+{
+ DBUG_ASSERT(f->real_type() == MYSQL_TYPE_VARCHAR);
+ Field_varstring *f2= (Field_varstring*) f;
+ val= f2->val_str(NULL, val);
+ return val;
+}
+
int PFS_engine_table::update_row_values(TABLE *,
const unsigned char *,
unsigned char *,
@@ -350,6 +434,7 @@ int PFS_engine_table::update_row_values(TABLE *,
return HA_ERR_WRONG_COMMAND;
}
+/** Implementation of internal ACL checks, for the performance schema. */
class PFS_internal_schema_access : public ACL_internal_schema_access
{
public:
@@ -480,20 +565,22 @@ 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= INSERT_ACL | UPDATE_ACL | DELETE_ACL
- | CREATE_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL
- | CREATE_VIEW_ACL | TRIGGER_ACL | LOCK_TABLES_ACL;
+ 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 hidding (by enforcing ACCESS_DENIED for SELECT_ACL
+ 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;
}
@@ -533,11 +620,11 @@ bool pfs_show_status(handlerton *hton, THD *thd,
switch (i){
case 0:
name= "events_waits_current.row_size";
- size= sizeof(PFS_wait_locker);
+ size= sizeof(PFS_events_waits);
break;
case 1:
name= "events_waits_current.row_count";
- size= LOCKER_STACK_SIZE * thread_max;
+ size= WAIT_STACK_SIZE * thread_max;
break;
case 2:
name= "events_waits_history.row_size";
@@ -711,15 +798,15 @@ bool pfs_show_status(handlerton *hton, THD *thd,
break;
case 41:
name= "events_waits_summary_by_thread_by_event_name.row_size";
- size= sizeof(PFS_single_stat_chain);
+ size= sizeof(PFS_single_stat);
break;
case 42:
name= "events_waits_summary_by_thread_by_event_name.row_count";
- size= thread_max * instr_class_per_thread;
+ size= thread_max * wait_class_max;
break;
case 43:
name= "events_waits_summary_by_thread_by_event_name.memory";
- size= thread_max * instr_class_per_thread * sizeof(PFS_single_stat_chain);
+ size= thread_max * wait_class_max * sizeof(PFS_single_stat);
total_memory+= size;
break;
case 44:
@@ -748,11 +835,520 @@ bool pfs_show_status(handlerton *hton, THD *thd,
size= table_max * sizeof(PFS_table);
total_memory+= size;
break;
+ case 50:
+ name= "setup_actors.row_size";
+ size= sizeof(PFS_setup_actor);
+ break;
+ case 51:
+ name= "setup_actors.row_count";
+ size= setup_actor_max;
+ break;
+ case 52:
+ name= "setup_actors.memory";
+ size= setup_actor_max * sizeof(PFS_setup_actor);
+ total_memory+= size;
+ break;
+ case 53:
+ name= "setup_objects.row_size";
+ size= sizeof(PFS_setup_object);
+ break;
+ case 54:
+ name= "setup_objects.row_count";
+ size= setup_object_max;
+ break;
+ case 55:
+ name= "setup_objects.memory";
+ size= setup_object_max * sizeof(PFS_setup_object);
+ total_memory+= size;
+ break;
+ case 56:
+ name= "(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;
+ case 154:
+ name= "(history_long_statements_digest_token_array).row_count";
+ size= events_statements_history_long_size;
+ break;
+ case 155:
+ name= "(history_long_statements_digest_token_array).row_size";
+ size= pfs_max_digest_length;
+ break;
+ case 156:
+ name= "(history_long_statements_digest_token_array).memory";
+ size= events_statements_history_long_size * pfs_max_digest_length;
+ total_memory+= size;
+ break;
+ case 157:
+ name= "(history_statements_digest_token_array).row_count";
+ size= thread_max * events_statements_history_per_thread;
+ break;
+ case 158:
+ name= "(history_statements_digest_token_array).row_size";
+ size= pfs_max_digest_length;
+ break;
+ case 159:
+ name= "(history_statements_digest_token_array).memory";
+ size= thread_max * events_statements_history_per_thread * pfs_max_digest_length;
+ total_memory+= size;
+ break;
+ case 160:
+ name= "(current_statements_digest_token_array).row_count";
+ size= thread_max * statement_stack_max;
+ break;
+ case 161:
+ name= "(current_statements_digest_token_array).row_size";
+ size= pfs_max_digest_length;
+ break;
+ case 162:
+ name= "(current_statements_digest_token_array).memory";
+ size= thread_max * statement_stack_max * pfs_max_digest_length;
+ total_memory+= size;
+ break;
+ case 163:
+ name= "(statements_digest_token_array).row_count";
+ size= digest_max;
+ break;
+ case 164:
+ name= "(statements_digest_token_array).row_size";
+ size= pfs_max_digest_length;
+ break;
+ case 165:
+ name= "(statements_digest_token_array).memory";
+ size= digest_max * pfs_max_digest_length;
+ total_memory+= size;
+ break;
+
/*
This case must be last,
for aggregation in total_memory.
*/
- case 50:
+ case 166:
name= "performance_schema.memory";
size= total_memory;
/* This will fail if something is not advertised here */
@@ -775,6 +1371,18 @@ end:
DBUG_RETURN(false);
}
-/** @} */
+int pfs_discover_table_names(handlerton *hton __attribute__((unused)),
+ LEX_STRING *db,
+ MY_DIR *dir __attribute__((unused)),
+ handlerton::discovered_list *result)
+{
+ if (compare_table_names(db->str, PERFORMANCE_SCHEMA_str.str))
+ return 0;
+ for (size_t i= 0; i < array_elements(all_shares) - 1; i++)
+ result->add_table(all_shares[i]->m_name.str,
+ all_shares[i]->m_name.length);
+ return 0;
+}
+/** @} */
diff --git a/storage/perfschema/pfs_engine_table.h b/storage/perfschema/pfs_engine_table.h
index 562df5ad476..d3c4a0e43e6 100644
--- a/storage/perfschema/pfs_engine_table.h
+++ b/storage/perfschema/pfs_engine_table.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -22,8 +22,10 @@
Performance schema tables (declarations).
*/
+#include "pfs_instr_class.h"
class Field;
struct PFS_engine_table_share;
+struct time_normalizer;
/**
@addtogroup Performance_schema_engine
@@ -46,6 +48,18 @@ public:
int update_row(TABLE *table, const unsigned char *old_buf,
unsigned char *new_buf, Field **fields);
+ /**
+ Delete a row from this table.
+ @param table Table handle
+ @param buf the row buffer to delete
+ @param fields Table fields
+ @return 0 on success
+ */
+ int delete_row(TABLE *table, const unsigned char *buf, Field **fields);
+
+ /** Initialize table scan. */
+ virtual int rnd_init(bool scan){return 0;};
+
/** Fetch the next row in this cursor. */
virtual int rnd_next(void)= 0;
/**
@@ -56,12 +70,82 @@ public:
void get_position(void *ref);
void set_position(const void *ref);
+ /** Reset the cursor position to the beginning of the table. */
virtual void reset_position(void)= 0;
+ /** Get the normalizer and class type for the current row. */
+ void get_normalizer(PFS_instr_class *instr_class);
+
/** Destructor. */
virtual ~PFS_engine_table()
{}
+ /**
+ Helper, assign a value to a ulong field.
+ @param f the field to set
+ @param value the value to assign
+ */
+ static void set_field_ulong(Field *f, ulong value);
+ /**
+ Helper, assign a value to a ulonglong field.
+ @param f the field to set
+ @param value the value to assign
+ */
+ static void set_field_ulonglong(Field *f, ulonglong value);
+ /**
+ Helper, assign a value to a char utf8 field.
+ @param f the field to set
+ @param str the string to assign
+ @param len the length of the string to assign
+ */
+ static void set_field_char_utf8(Field *f, const char *str, uint len);
+ /**
+ Helper, assign a value to a varchar utf8 field.
+ @param f the field to set
+ @param str the string to assign
+ @param len the length of the string to assign
+ */
+ static void set_field_varchar_utf8(Field *f, const char *str, uint len);
+ /**
+ Helper, assign a value to a longtext utf8 field.
+ @param f the field to set
+ @param str the string to assign
+ @param len the length of the string to assign
+ */
+ static void set_field_longtext_utf8(Field *f, const char *str, uint len);
+ /**
+ Helper, assign a value to an enum field.
+ @param f the field to set
+ @param value the value to assign
+ */
+ static void set_field_enum(Field *f, ulonglong value);
+ /**
+ Helper, assign a value to a timestamp field.
+ @param f the field to set
+ @param value the value to assign
+ */
+ static void set_field_timestamp(Field *f, ulonglong value);
+ /**
+ Helper, read a value from an enum field.
+ @param f the field to read
+ @return the field value
+ */
+ static ulonglong get_field_enum(Field *f);
+ /**
+ Helper, read a value from a char utf8 field.
+ @param f the field to read
+ @param[out] val the field value
+ @return the field value
+ */
+ static String *get_field_char_utf8(Field *f, String *val);
+ /**
+ Helper, read a value from a varchar utf8 field.
+ @param f the field to read
+ @param[out] val the field value
+ @return the field value
+ */
+ static String *get_field_varchar_utf8(Field *f, String *val);
+
protected:
/**
Read the current row values.
@@ -84,25 +168,32 @@ protected:
unsigned char *new_buf, Field **fields);
/**
+ Delete a row.
+ @param table Table handle
+ @param buf Row buffer
+ @param fields Table fields
+ */
+ virtual int delete_row_values(TABLE *table, const unsigned char *buf,
+ Field **fields);
+
+ /**
Constructor.
@param share table share
@param pos address of the m_pos position member
*/
PFS_engine_table(const PFS_engine_table_share *share, void *pos)
- : m_share_ptr(share), m_pos_ptr(pos)
+ : m_share_ptr(share), m_pos_ptr(pos),
+ m_normalizer(NULL), m_class_type(PFS_CLASS_NONE)
{}
- void set_field_ulong(Field *f, ulong value);
- void set_field_ulonglong(Field *f, ulonglong value);
- void set_field_varchar_utf8(Field *f, const char* str, uint len);
- void set_field_enum(Field *f, ulonglong value);
-
- ulonglong get_field_enum(Field *f);
-
/** Table share. */
const PFS_engine_table_share *m_share_ptr;
/** Opaque pointer to the m_pos position of this cursor. */
void *m_pos_ptr;
+ /** Current normalizer */
+ time_normalizer *m_normalizer;
+ /** Current class type */
+ enum PFS_class_type m_class_type;
};
/** Callback to open a table. */
@@ -112,6 +203,8 @@ typedef int (*pfs_write_row_t)(TABLE *table,
unsigned char *buf, Field **fields);
/** Callback to delete all rows. */
typedef int (*pfs_delete_all_rows_t)(void);
+/** Callback to get a row count. */
+typedef ha_rows (*pfs_get_row_count_t)(void);
/**
A PERFORMANCE_SCHEMA table share.
@@ -119,10 +212,12 @@ typedef int (*pfs_delete_all_rows_t)(void);
*/
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;
@@ -134,6 +229,8 @@ struct PFS_engine_table_share
pfs_write_row_t m_write_row;
/** Delete all rows function. */
pfs_delete_all_rows_t m_delete_all_rows;
+ /** Get rows count function. */
+ pfs_get_row_count_t m_get_row_count;
/**
Number or records.
This number does not need to be precise,
@@ -145,12 +242,14 @@ struct PFS_engine_table_share
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;
+ /** Table definition. */
+ LEX_STRING sql;
};
+/**
+ Privileges for read only tables.
+ The only operation allowed is SELECT.
+*/
class PFS_readonly_acl : public ACL_internal_table_access
{
public:
@@ -160,11 +259,16 @@ public:
~PFS_readonly_acl()
{}
- ACL_internal_access_result check(ulong want_access, ulong *save_priv) const;
+ 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:
@@ -177,8 +281,13 @@ public:
ACL_internal_access_result check(ulong want_access, ulong *save_priv) const;
};
+/** Singleton instance of PFS_truncatable_acl. */
extern PFS_truncatable_acl pfs_truncatable_acl;
+/**
+ Privileges for updatable tables.
+ Operations allowed are SELECT and UPDATE.
+*/
class PFS_updatable_acl : public ACL_internal_table_access
{
public:
@@ -191,8 +300,13 @@ public:
ACL_internal_access_result check(ulong want_access, ulong *save_priv) const;
};
+/** Singleton instance of PFS_updatable_acl. */
extern PFS_updatable_acl pfs_updatable_acl;
+/**
+ Privileges for editable tables.
+ Operations allowed are SELECT, INSERT, UPDATE, DELETE and TRUNCATE.
+*/
class PFS_editable_acl : public ACL_internal_table_access
{
public:
@@ -205,8 +319,12 @@ public:
ACL_internal_access_result check(ulong want_access, ulong *save_priv) const;
};
+/** Singleton instance of PFS_editable_acl. */
extern PFS_editable_acl pfs_editable_acl;
+/**
+ Privileges for unknown tables.
+*/
class PFS_unknown_acl : public ACL_internal_table_access
{
public:
@@ -219,6 +337,7 @@ public:
ACL_internal_access_result check(ulong want_access, ulong *save_priv) const;
};
+/** Singleton instance of PFS_unknown_acl. */
extern PFS_unknown_acl pfs_unknown_acl;
/** Position of a cursor, for simple iterations. */
@@ -227,20 +346,34 @@ struct PFS_simple_index
/** Current row index. */
uint m_index;
+ /**
+ Constructor.
+ @param index the index initial value.
+ */
PFS_simple_index(uint index)
: m_index(index)
{}
+ /**
+ Set this index at a given position.
+ @param other a position
+ */
void set_at(const struct PFS_simple_index *other)
{ m_index= other->m_index; }
+ /**
+ Set this index after a given position.
+ @param other a position
+ */
void set_after(const struct PFS_simple_index *other)
{ m_index= other->m_index + 1; }
+ /** Set this index to the next record. */
void next(void)
{ m_index++; }
};
+/** Position of a double cursor, for iterations using 2 nested loops. */
struct PFS_double_index
{
/** Outer index. */
@@ -248,16 +381,29 @@ struct PFS_double_index
/** Current index within index_1. */
uint m_index_2;
+ /**
+ Constructor.
+ @param index_1 the first index initial value.
+ @param index_2 the second index initial value.
+ */
PFS_double_index(uint index_1, uint index_2)
: m_index_1(index_1), m_index_2(index_2)
{}
+ /**
+ Set this index at a given position.
+ @param other a position
+ */
void set_at(const struct PFS_double_index *other)
{
m_index_1= other->m_index_1;
m_index_2= other->m_index_2;
}
+ /**
+ Set this index after a given position.
+ @param other a position
+ */
void set_after(const struct PFS_double_index *other)
{
m_index_1= other->m_index_1;
@@ -265,6 +411,7 @@ struct PFS_double_index
}
};
+/** Position of a triple cursor, for iterations using 3 nested loops. */
struct PFS_triple_index
{
/** Outer index. */
@@ -274,10 +421,20 @@ struct PFS_triple_index
/** Current index within index_2. */
uint m_index_3;
+ /**
+ Constructor.
+ @param index_1 the first index initial value.
+ @param index_2 the second index initial value.
+ @param index_3 the third index initial value.
+ */
PFS_triple_index(uint index_1, uint index_2, uint index_3)
: m_index_1(index_1), m_index_2(index_2), m_index_3(index_3)
{}
+ /**
+ Set this index at a given position.
+ @param other a position
+ */
void set_at(const struct PFS_triple_index *other)
{
m_index_1= other->m_index_1;
@@ -285,6 +442,10 @@ struct PFS_triple_index
m_index_3= other->m_index_3;
}
+ /**
+ Set this index after a given position.
+ @param other a position
+ */
void set_after(const struct PFS_triple_index *other)
{
m_index_1= other->m_index_1;
@@ -293,24 +454,12 @@ struct PFS_triple_index
}
};
-struct PFS_instrument_view_constants
-{
- static const uint VIEW_MUTEX= 1;
- static const uint VIEW_RWLOCK= 2;
- static const uint VIEW_COND= 3;
- static const uint VIEW_FILE= 4;
-};
-
-struct PFS_object_view_constants
-{
- static const uint VIEW_TABLE= 1;
- static const uint VIEW_EVENT= 2;
- static const uint VIEW_PROCEDURE= 3;
- static const uint VIEW_FUNCTION= 4;
-};
-
bool pfs_show_status(handlerton *hton, THD *thd,
stat_print_fn *print, enum ha_stat_type stat);
+int pfs_discover_table_names(handlerton *hton, LEX_STRING *db,
+ MY_DIR *dir,
+ handlerton::discovered_list *result);
+
/** @} */
#endif
diff --git a/storage/perfschema/pfs_events.h b/storage/perfschema/pfs_events.h
new file mode 100644
index 00000000000..09c3935816f
--- /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-1335 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;
+ /** NESTING_EVENT_ID. */
+ ulonglong m_nesting_event_id;
+ /**
+ 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;
+ /** Instrument metadata. */
+ PFS_instr_class *m_class;
+ /** Location of the instrumentation in the source code (file name). */
+ const char *m_source_file;
+ /** (EVENT_TYPE) */
+ enum_event_type m_event_type;
+ /** NESTING_EVENT_TYPE */
+ enum_event_type m_nesting_event_type;
+ /** 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..673d2cb95f5
--- /dev/null
+++ b/storage/perfschema/pfs_events_stages.cc
@@ -0,0 +1,252 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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, sizeof(PFS_events_stages),
+ 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;
+ PFS_account *account;
+ PFS_user *user;
+ PFS_host *host;
+
+ for ( ; thread < thread_last; thread++)
+ {
+ if (thread->m_lock.is_populated())
+ {
+ account= sanitize_account(thread->m_account);
+ user= sanitize_user(thread->m_user);
+ host= sanitize_host(thread->m_host);
+ aggregate_thread_stages(thread, account, user, host);
+ }
+ }
+}
+
+/** 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;
+ PFS_user *user;
+ PFS_host *host;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ if (pfs->m_lock.is_populated())
+ {
+ user= sanitize_user(pfs->m_user);
+ host= sanitize_host(pfs->m_host);
+ pfs->aggregate_stages(user, host);
+ }
+ }
+}
+
+/** 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..ea879bcd211
--- /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-1335 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..66a98e3f7d8
--- /dev/null
+++ b/storage/perfschema/pfs_events_statements.cc
@@ -0,0 +1,290 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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"
+
+size_t 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;
+static unsigned char *h_long_stmts_digest_token_array= NULL;
+
+/**
+ Initialize table EVENTS_STATEMENTS_HISTORY_LONG.
+ @param events_statements_history_long_sizing table sizing
+*/
+int init_events_statements_history_long(size_t 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, sizeof(PFS_events_statements),
+ PFS_events_statements, MYF(MY_ZEROFILL));
+
+ if (events_statements_history_long_array == NULL)
+ {
+ cleanup_events_statements_history_long();
+ return 1;
+ }
+
+ if (pfs_max_digest_length > 0)
+ {
+ /* Size of each digest token array. */
+ size_t digest_text_size= pfs_max_digest_length * sizeof(unsigned char);
+
+ h_long_stmts_digest_token_array=
+ PFS_MALLOC_ARRAY(events_statements_history_long_size, digest_text_size,
+ unsigned char, MYF(MY_ZEROFILL));
+ if (h_long_stmts_digest_token_array == NULL)
+ {
+ cleanup_events_statements_history_long();
+ return 1;
+ }
+ }
+
+ for (size_t index= 0; index < events_statements_history_long_size; index++)
+ {
+ events_statements_history_long_array[index].m_digest_storage.reset(h_long_stmts_digest_token_array
+ + index * pfs_max_digest_length, pfs_max_digest_length);
+ }
+
+ return 0;
+}
+
+/** Cleanup table EVENTS_STATEMENTS_HISTORY_LONG. */
+void cleanup_events_statements_history_long(void)
+{
+ pfs_free(events_statements_history_long_array);
+ pfs_free(h_long_stmts_digest_token_array);
+ events_statements_history_long_array= NULL;
+ h_long_stmts_digest_token_array= NULL;
+}
+
+static inline void copy_events_statements(PFS_events_statements *dest,
+ const PFS_events_statements *source)
+{
+ /* Copy all attributes except DIGEST */
+ memcpy(dest, source, my_offsetof(PFS_events_statements, m_digest_storage));
+
+ /* Copy DIGEST */
+ dest->m_digest_storage.copy(& source->m_digest_storage);
+}
+
+/**
+ 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;
+ PFS_account *account;
+ PFS_user *user;
+ PFS_host *host;
+
+ for ( ; thread < thread_last; thread++)
+ {
+ if (thread->m_lock.is_populated())
+ {
+ account= sanitize_account(thread->m_account);
+ user= sanitize_user(thread->m_user);
+ host= sanitize_host(thread->m_host);
+ aggregate_thread_statements(thread, account, user, host);
+ }
+ }
+}
+
+/** 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;
+ PFS_user *user;
+ PFS_host *host;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ if (pfs->m_lock.is_populated())
+ {
+ user= sanitize_user(pfs->m_user);
+ host= sanitize_host(pfs->m_host);
+ pfs->aggregate_statements(user, host);
+ }
+ }
+}
+
+/** 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..a56423d3863
--- /dev/null
+++ b/storage/perfschema/pfs_events_statements.h
@@ -0,0 +1,133 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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-1335 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;
+
+ /** True if sqltext was truncated. */
+ bool m_sqltext_truncated;
+ /** Statement character set number. */
+ uint m_sqltext_cs_number;
+
+ /**
+ Statement digest.
+ This underlying token array storage pointer is immutable,
+ and always point to pre allocated memory.
+ */
+ sql_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 size_t events_statements_history_long_size;
+
+int init_events_statements_history_long(size_t events_statements_history_long_sizing);
+void cleanup_events_statements_history_long();
+
+void reset_events_statements_current();
+void reset_events_statements_history();
+void reset_events_statements_history_long();
+void reset_events_statements_by_thread();
+void reset_events_statements_by_account();
+void reset_events_statements_by_user();
+void reset_events_statements_by_host();
+void reset_events_statements_global();
+void aggregate_account_statements(PFS_account *account);
+void aggregate_user_statements(PFS_user *user);
+void aggregate_host_statements(PFS_host *host);
+
+#endif
+
diff --git a/storage/perfschema/pfs_events_waits.cc b/storage/perfschema/pfs_events_waits.cc
index 8623aeaae6b..f99a1f31bd9 100644
--- a/storage/perfschema/pfs_events_waits.cc
+++ b/storage/perfschema/pfs_events_waits.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,30 +21,26 @@
#include "my_global.h"
#include "my_sys.h"
#include "pfs_global.h"
+#include "pfs_instr_class.h"
#include "pfs_instr.h"
+#include "pfs_user.h"
+#include "pfs_host.h"
+#include "pfs_account.h"
#include "pfs_events_waits.h"
#include "pfs_atomic.h"
#include "m_string.h"
ulong events_waits_history_long_size= 0;
/** Consumer flag for table EVENTS_WAITS_CURRENT. */
-bool flag_events_waits_current= true;
+bool flag_events_waits_current= false;
/** Consumer flag for table EVENTS_WAITS_HISTORY. */
-bool flag_events_waits_history= true;
+bool flag_events_waits_history= false;
/** Consumer flag for table EVENTS_WAITS_HISTORY_LONG. */
-bool flag_events_waits_history_long= true;
-/** Consumer flag for table EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME. */
-bool flag_events_waits_summary_by_thread_by_event_name= true;
-/** Consumer flag for table EVENTS_WAITS_SUMMARY_BY_EVENT_NAME. */
-bool flag_events_waits_summary_by_event_name= true;
-/** Consumer flag for table EVENTS_WAITS_SUMMARY_BY_INSTANCE. */
-bool flag_events_waits_summary_by_instance= true;
-bool flag_events_locks_summary_by_event_name= true;
-bool flag_events_locks_summary_by_instance= true;
-/** Consumer flag for table FILE_SUMMARY_BY_EVENT_NAME. */
-bool flag_file_summary_by_event_name= true;
-/** Consumer flag for table FILE_SUMMARY_BY_INSTANCE. */
-bool flag_file_summary_by_instance= true;
+bool flag_events_waits_history_long= false;
+/** Consumer flag for the global instrumentation. */
+bool flag_global_instrumentation= false;
+/** Consumer flag for the per thread instrumentation. */
+bool flag_thread_instrumentation= false;
/** True if EVENTS_WAITS_HISTORY_LONG circular buffer is full. */
bool events_waits_history_long_full= false;
@@ -67,8 +63,8 @@ int init_events_waits_history_long(uint events_waits_history_long_sizing)
return 0;
events_waits_history_long_array=
- PFS_MALLOC_ARRAY(events_waits_history_long_size, PFS_events_waits,
- MYF(MY_ZEROFILL));
+ PFS_MALLOC_ARRAY(events_waits_history_long_size, sizeof(PFS_events_waits),
+ PFS_events_waits, MYF(MY_ZEROFILL));
return (events_waits_history_long_array ? 0 : 1);
}
@@ -144,11 +140,11 @@ void reset_events_waits_current(void)
for ( ; pfs_thread < pfs_thread_last; pfs_thread++)
{
- PFS_wait_locker *locker= pfs_thread->m_wait_locker_stack;
- PFS_wait_locker *locker_last= locker + LOCKER_STACK_SIZE;
+ PFS_events_waits *pfs_wait= pfs_thread->m_events_waits_stack;
+ PFS_events_waits *pfs_wait_last= pfs_wait + WAIT_STACK_SIZE;
- for ( ; locker < locker_last; locker++)
- locker->m_waits_current.m_wait_class= NO_WAIT_CLASS;
+ for ( ; pfs_wait < pfs_wait_last; pfs_wait++)
+ pfs_wait->m_wait_class= NO_WAIT_CLASS;
}
}
@@ -182,3 +178,141 @@ void reset_events_waits_history_long(void)
wait->m_wait_class= NO_WAIT_CLASS;
}
+/** Reset table EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */
+void reset_events_waits_by_thread()
+{
+ PFS_thread *thread= thread_array;
+ PFS_thread *thread_last= thread_array + thread_max;
+ PFS_account *account;
+ PFS_user *user;
+ PFS_host *host;
+
+ for ( ; thread < thread_last; thread++)
+ {
+ if (thread->m_lock.is_populated())
+ {
+ account= sanitize_account(thread->m_account);
+ user= sanitize_user(thread->m_user);
+ host= sanitize_host(thread->m_host);
+ aggregate_thread_waits(thread, account, user, host);
+ }
+ }
+}
+
+/** 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;
+ PFS_user *user;
+ PFS_host *host;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ if (pfs->m_lock.is_populated())
+ {
+ user= sanitize_user(pfs->m_user);
+ host= sanitize_host(pfs->m_host);
+ pfs->aggregate_waits(user, host);
+ }
+ }
+}
+
+/** 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
index d26de7caafb..79bd3383241 100644
--- a/storage/perfschema/pfs_events_waits.h
+++ b/storage/perfschema/pfs_events_waits.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#include "pfs_column_types.h"
#include "pfs_lock.h"
+#include "pfs_events.h"
struct PFS_mutex;
struct PFS_rwlock;
@@ -30,7 +31,12 @@ struct PFS_cond;
struct PFS_table;
struct PFS_file;
struct PFS_thread;
+struct PFS_socket;
struct PFS_instr_class;
+struct PFS_table_share;
+struct PFS_account;
+struct PFS_user;
+struct PFS_host;
/** Class of a wait event. */
enum events_waits_class
@@ -40,52 +46,31 @@ enum events_waits_class
WAIT_CLASS_RWLOCK,
WAIT_CLASS_COND,
WAIT_CLASS_TABLE,
- WAIT_CLASS_FILE
+ WAIT_CLASS_FILE,
+ WAIT_CLASS_SOCKET,
+ WAIT_CLASS_IDLE
};
-/** State of a timer. */
-enum timer_state
+/** A wait event record. */
+struct PFS_events_waits : public PFS_events
{
+ /** Executing thread. */
+ PFS_thread *m_thread;
+ /** Table share, for table operations only. */
+ PFS_table_share *m_weak_table_share;
+ /** File, for file operations only. */
+ PFS_file *m_weak_file;
+ /** Address in memory of the object instance waited on. */
+ const void *m_object_instance_addr;
+ /** Socket, for socket operations only. */
+ PFS_socket *m_weak_socket;
/**
- Not timed.
- In this state, TIMER_START, TIMER_END and TIMER_WAIT are NULL.
- */
- TIMER_STATE_UNTIMED,
- /**
- About to start.
- In this state, TIMER_START, TIMER_END and TIMER_WAIT are NULL.
- */
- TIMER_STATE_STARTING,
- /**
- Started, but not yet ended.
- In this state, TIMER_START has a value, TIMER_END and TIMER_WAIT are NULL.
- */
- TIMER_STATE_STARTED,
- /**
- Ended.
- In this state, TIMER_START, TIMER_END and TIMER_WAIT have a value.
+ Number of bytes read/written.
+ This member is populated for file READ/WRITE operations only.
*/
- TIMER_STATE_TIMED
-};
-
-/** Target object a wait event is waiting on. */
-union events_waits_target
-{
- /** Mutex waited on. */
- PFS_mutex *m_mutex;
- /** RWLock waited on. */
- PFS_rwlock *m_rwlock;
- /** Condition waited on. */
- PFS_cond *m_cond;
- /** Table waited on. */
- PFS_table *m_table;
- /** File waited on. */
- PFS_file *m_file;
-};
-
-/** A wait event record. */
-struct PFS_events_waits
-{
+ size_t m_number_of_bytes;
+ /** Flags */
+ ulong m_flags;
/**
The type of wait.
Readers:
@@ -98,61 +83,27 @@ struct PFS_events_waits
- TRUNCATE EVENTS_WAITS_HISTORY_LONG
*/
events_waits_class m_wait_class;
- /** Executing thread. */
- PFS_thread *m_thread;
- /** Instrument metadata. */
- PFS_instr_class *m_class;
- /** Timer state. */
- enum timer_state m_timer_state;
- /** Event id. */
- ulonglong m_event_id;
- /**
- Timer start.
- This member is populated only if m_timed is true.
- */
- ulonglong m_timer_start;
- /**
- Timer end.
- This member is populated only if m_timed is true.
- */
- ulonglong m_timer_end;
- /** Schema name. */
- const char *m_schema_name;
- /** Length in bytes of @c m_schema_name. */
- uint m_schema_name_length;
- /** Object name. */
- const char *m_object_name;
- /** Length in bytes of @c m_object_name. */
- uint m_object_name_length;
- /** Address in memory of the object instance waited on. */
- const void *m_object_instance_addr;
- /** Location of the instrumentation in the source code (file name). */
- const char *m_source_file;
- /** Location of the instrumentation in the source code (line number). */
- uint m_source_line;
+ /** Object type */
+ enum_object_type m_object_type;
+ /** For weak pointers, target object version. */
+ uint32 m_weak_version;
/** Operation performed. */
enum_operation_type m_operation;
/**
- Number of bytes read/written.
- This member is populated for file READ/WRITE operations only.
+ Index used.
+ This member is populated for TABLE IO operations only.
*/
- size_t m_number_of_bytes;
+ uint m_index;
};
-/**
- A wait locker.
- A locker is a transient helper structure used by the instrumentation
- during the recording of a wait.
-*/
-struct PFS_wait_locker
-{
- /** The timer used to measure the wait. */
- enum_timer_name m_timer_name;
- /** The object waited on. */
- events_waits_target m_target;
- /** The wait data recorded. */
- PFS_events_waits m_waits_current;
-};
+/** TIMED bit in the state flags bitfield. */
+#define STATE_FLAG_TIMED (1<<0)
+/** THREAD bit in the state flags bitfield. */
+#define STATE_FLAG_THREAD (1<<1)
+/** EVENT bit in the state flags bitfield. */
+#define STATE_FLAG_EVENT (1<<2)
+/** DIGEST bit in the state flags bitfield. */
+#define STATE_FLAG_DIGEST (1<<3)
void insert_events_waits_history(PFS_thread *thread, PFS_events_waits *wait);
@@ -161,14 +112,9 @@ void insert_events_waits_history_long(PFS_events_waits *wait);
extern bool flag_events_waits_current;
extern bool flag_events_waits_history;
extern bool flag_events_waits_history_long;
-extern bool flag_events_waits_summary_by_thread_by_event_name;
-extern bool flag_events_waits_summary_by_event_name;
-extern bool flag_events_waits_summary_by_instance;
-extern bool flag_events_locks_summary_by_thread_by_name;
-extern bool flag_events_locks_summary_by_event_name;
-extern bool flag_events_locks_summary_by_instance;
-extern bool flag_file_summary_by_event_name;
-extern bool flag_file_summary_by_instance;
+extern bool flag_global_instrumentation;
+extern bool flag_thread_instrumentation;
+
extern bool events_waits_history_long_full;
extern volatile uint32 events_waits_history_long_index;
extern PFS_events_waits *events_waits_history_long_array;
@@ -180,6 +126,21 @@ void cleanup_events_waits_history_long();
void reset_events_waits_current();
void reset_events_waits_history();
void reset_events_waits_history_long();
+void reset_events_waits_by_thread();
+void reset_events_waits_by_account();
+void reset_events_waits_by_user();
+void reset_events_waits_by_host();
+void reset_events_waits_global();
+void aggregate_account_waits(PFS_account *account);
+void aggregate_user_waits(PFS_user *user);
+void aggregate_host_waits(PFS_host *host);
+
+void reset_table_waits_by_table();
+void reset_table_io_waits_by_table();
+void reset_table_lock_waits_by_table();
+void reset_table_waits_by_table_handle();
+void reset_table_io_waits_by_table_handle();
+void reset_table_lock_waits_by_table_handle();
#endif
diff --git a/storage/perfschema/pfs_global.cc b/storage/perfschema/pfs_global.cc
index 7fd0ab4f291..25dd817b149 100644
--- a/storage/perfschema/pfs_global.cc
+++ b/storage/perfschema/pfs_global.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,12 +18,26 @@
Miscellaneous global dependencies (implementation).
*/
-#include "my_global.h"
-#include "my_sys.h"
#include "pfs_global.h"
+#include <my_sys.h>
+#include <my_net.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h> /* memalign() may be here */
+#endif
-#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_STRING_H
#include <string.h>
+#endif
+
+#ifdef __WIN__
+ #include <winsock2.h>
+#else
+ #include <arpa/inet.h>
+#endif
bool pfs_initialized= false;
size_t pfs_allocated_memory= 0;
@@ -38,18 +52,65 @@ void *pfs_malloc(size_t size, myf flags)
DBUG_ASSERT(! pfs_initialized);
DBUG_ASSERT(size > 0);
- void *ptr= malloc(size);
- if (likely(ptr != NULL))
- pfs_allocated_memory+= size;
- if (likely((ptr != NULL) && (flags & MY_ZEROFILL)))
+ void *ptr= NULL;
+
+#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)
- free(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, ...)
@@ -67,3 +128,96 @@ void pfs_print_error(const char *format, ...)
fflush(stderr);
}
+/**
+ Array allocation for the performance schema.
+ Checks for overflow of n * size before allocating.
+ @param n number of array elements
+ @param size element size
+ @param flags malloc flags
+ @return pointer to memory on success, else NULL
+*/
+void *pfs_malloc_array(size_t n, size_t size, myf flags)
+{
+ DBUG_ASSERT(n > 0);
+ DBUG_ASSERT(size > 0);
+ size_t array_size= n * size;
+ /* Check for overflow before allocating. */
+ if (is_overflow(array_size, n, size))
+ return NULL;
+ return pfs_malloc(array_size, flags);
+}
+
+/**
+ Detect multiplication overflow.
+ @param product multiplication product
+ @param n1 operand
+ @param n2 operand
+ @return true if multiplication caused an overflow.
+*/
+bool is_overflow(size_t product, size_t n1, size_t n2)
+{
+ if (n1 != 0 && (product / n1 != n2))
+ return true;
+ else
+ return false;
+}
+
+/** Convert raw ip address into readable format. Do not do a reverse DNS lookup. */
+
+uint pfs_get_socket_address(char *host,
+ uint host_len,
+ uint *port,
+ const struct sockaddr_storage *src_addr,
+ socklen_t src_len)
+{
+ DBUG_ASSERT(host);
+ DBUG_ASSERT(src_addr);
+ DBUG_ASSERT(port);
+
+ memset(host, 0, host_len);
+ *port= 0;
+
+ switch (src_addr->ss_family)
+ {
+ case AF_INET:
+ {
+ if (host_len < INET_ADDRSTRLEN+1)
+ return 0;
+ struct sockaddr_in *sa4= (struct sockaddr_in *)(src_addr);
+ #ifdef __WIN__
+ /* Older versions of Windows do not support inet_ntop() */
+ getnameinfo((struct sockaddr *)sa4, sizeof(struct sockaddr_in),
+ host, host_len, NULL, 0, NI_NUMERICHOST);
+ #else
+ inet_ntop(AF_INET, &(sa4->sin_addr), host, INET_ADDRSTRLEN);
+ #endif
+ *port= ntohs(sa4->sin_port);
+ }
+ break;
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ {
+ if (host_len < INET6_ADDRSTRLEN+1)
+ return 0;
+ struct sockaddr_in6 *sa6= (struct sockaddr_in6 *)(src_addr);
+ #ifdef __WIN__
+ /* Older versions of Windows do not support inet_ntop() */
+ getnameinfo((struct sockaddr *)sa6, sizeof(struct sockaddr_in6),
+ host, host_len, NULL, 0, NI_NUMERICHOST);
+ #else
+ inet_ntop(AF_INET6, &(sa6->sin6_addr), host, INET6_ADDRSTRLEN);
+ #endif
+ *port= ntohs(sa6->sin6_port);
+ }
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ /* Return actual IP address string length */
+ return (strlen((const char*)host));
+}
+
diff --git a/storage/perfschema/pfs_global.h b/storage/perfschema/pfs_global.h
index 7791dfa31ba..009c6a0e603 100644
--- a/storage/perfschema/pfs_global.h
+++ b/storage/perfschema/pfs_global.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,19 +16,65 @@
#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 size_t 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);
-#define PFS_MALLOC_ARRAY(n, T, f) \
- reinterpret_cast<T*> (pfs_malloc((n) * sizeof(T), (f)))
+
+/** Allocate an array of structures with overflow check. */
+void *pfs_malloc_array(size_t n, size_t size, myf flags);
+
+/**
+ Helper, to allocate an array of structures.
+ @param n number of elements in the array
+ @param s size of array element
+ @param T type of an element
+ @param f flags to use when allocating memory
+*/
+#define PFS_MALLOC_ARRAY(n, s, T, f) \
+ reinterpret_cast<T*>(pfs_malloc_array((n), (s), (f)))
+
+/** Free memory allocated with @sa pfs_malloc. */
void pfs_free(void *ptr);
+/** Detect multiplication overflow. */
+bool is_overflow(size_t product, size_t n1, size_t n2);
+
+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;
@@ -67,7 +113,7 @@ inline uint randomized_index(const void *ptr, uint max_size)
value= (reinterpret_cast<intptr> (ptr)) >> 3;
value*= 1789;
value+= seed2 + seed1 + 1;
-
+
result= (static_cast<uint> (value)) % max_size;
seed2= seed1*seed1;
diff --git a/storage/perfschema/pfs_host.cc b/storage/perfschema/pfs_host.cc
new file mode 100644
index 00000000000..8ac2b2fd5d9
--- /dev/null
+++ b/storage/perfschema/pfs_host.cc
@@ -0,0 +1,389 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 Street, Fifth Floor, Boston, MA 02110-1335 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, sizeof(PFS_host), 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();
+}
+
+PFS_host *sanitize_host(PFS_host *unsafe)
+{
+ if ((&host_array[0] <= unsafe) &&
+ (unsafe < &host_array[host_max]))
+ return unsafe;
+ return NULL;
+}
+
+void purge_host(PFS_thread *thread, PFS_host *host)
+{
+ LF_PINS *pins= get_host_hash_pins(thread);
+ if (unlikely(pins == NULL))
+ return;
+
+ PFS_host **entry;
+ entry= reinterpret_cast<PFS_host**>
+ (lf_hash_search(&host_hash, pins,
+ host->m_key.m_hash_key, host->m_key.m_key_length));
+ if (entry && (entry != MY_ERRPTR))
+ {
+ DBUG_ASSERT(*entry == host);
+ if (host->get_refcount() == 0)
+ {
+ lf_hash_delete(&host_hash, pins,
+ host->m_key.m_hash_key, host->m_key.m_key_length);
+ host->m_lock.allocated_to_free();
+ }
+ }
+
+ lf_hash_search_unpin(pins);
+}
+
+/** Purge non connected hosts, reset stats of connected hosts. */
+void purge_all_host(void)
+{
+ PFS_thread *thread= PFS_thread::get_current_thread();
+ if (unlikely(thread == NULL))
+ return;
+
+ PFS_host *pfs= host_array;
+ PFS_host *pfs_last= host_array + host_max;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ if (pfs->m_lock.is_populated())
+ {
+ pfs->aggregate();
+ if (pfs->get_refcount() == 0)
+ purge_host(thread, pfs);
+ }
+ }
+}
+
+/** @} */
diff --git a/storage/perfschema/pfs_host.h b/storage/perfschema/pfs_host.h
new file mode 100644
index 00000000000..4e6b24bf6c6
--- /dev/null
+++ b/storage/perfschema/pfs_host.h
@@ -0,0 +1,113 @@
+/* Copyright (c) 2010, 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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);
+
+PFS_host *sanitize_host(PFS_host *unsafe);
+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
index 2f768bb220a..44b170469bf 100644
--- a/storage/perfschema/pfs_instr.cc
+++ b/storage/perfschema/pfs_instr.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,7 +25,11 @@
#include "pfs.h"
#include "pfs_stat.h"
#include "pfs_instr.h"
+#include "pfs_host.h"
+#include "pfs_user.h"
+#include "pfs_account.h"
#include "pfs_global.h"
+#include "pfs_instr_class.h"
/**
@addtogroup Performance_schema_buffers
@@ -34,22 +38,32 @@
/** Size of the mutex instances array. @sa mutex_array */
ulong mutex_max;
+/** True when @c mutex_array is full. */
+bool mutex_full;
/** Number of mutexes instance lost. @sa mutex_array */
ulong mutex_lost;
/** Size of the rwlock instances array. @sa rwlock_array */
ulong rwlock_max;
+/** True when @c rwlock_array is full. */
+bool rwlock_full;
/** Number or rwlock instances lost. @sa rwlock_array */
ulong rwlock_lost;
/** Size of the conditions instances array. @sa cond_array */
ulong cond_max;
+/** True when @c cond_array is full. */
+bool cond_full;
/** Number of conditions instances lost. @sa cond_array */
ulong cond_lost;
/** Size of the thread instances array. @sa thread_array */
ulong thread_max;
+/** True when @c thread_array is full. */
+bool thread_full;
/** Number or thread instances lost. @sa thread_array */
ulong thread_lost;
/** Size of the file instances array. @sa file_array */
ulong file_max;
+/** True when @c file_array is full. */
+bool file_full;
/** Number of file instances lost. @sa file_array */
ulong file_lost;
/**
@@ -57,18 +71,38 @@ ulong file_lost;
Signed value, for easier comparisons with a file descriptor number.
*/
long file_handle_max;
+/** True when @c file_handle_array is full. */
+bool file_handle_full;
/** 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;
+/** True when @c table_array is full. */
+bool table_full;
/** Number of table instances lost. @sa table_array */
ulong table_lost;
+/** Size of the socket instances array. @sa socket_array */
+ulong socket_max;
+/** True when @c socket_array is full. */
+bool socket_full;
+/** Number of socket instances lost. @sa socket_array */
+ulong socket_lost;
/** Number of EVENTS_WAITS_HISTORY records per thread. */
ulong events_waits_history_per_thread;
-/** Number of instruments class per thread. */
-ulong instr_class_per_thread;
+/** Number of EVENTS_STAGES_HISTORY records per thread. */
+ulong events_stages_history_per_thread;
+/** Number of EVENTS_STATEMENTS_HISTORY records per thread. */
+ulong events_statements_history_per_thread;
+uint statement_stack_max;
+size_t pfs_max_digest_length= 0;
/** 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.
@@ -120,24 +154,37 @@ PFS_file **file_handle_array= NULL;
*/
PFS_table *table_array= NULL;
-static volatile uint32 thread_internal_id_counter= 0;
+/**
+ Socket instrumentation instances array.
+ @sa socket_max
+ @sa socket_lost
+*/
+PFS_socket *socket_array= NULL;
-static uint per_thread_rwlock_class_start;
-static uint per_thread_cond_class_start;
-static uint per_thread_file_class_start;
-static uint thread_instr_class_waits_sizing;
-static PFS_single_stat_chain *thread_instr_class_waits_array= NULL;
+PFS_stage_stat *global_instr_class_stages_array= NULL;
+PFS_statement_stat *global_instr_class_statements_array= NULL;
-static PFS_events_waits *thread_history_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 unsigned char *current_stmts_digest_token_array= NULL;
+static unsigned char *history_stmts_digest_token_array= NULL;
+static char *thread_session_connect_attrs_array= NULL;
/** Hash table for instrumented files. */
-static LF_HASH filename_hash;
+LF_HASH filename_hash;
/** True if filename_hash is initialized. */
static bool filename_hash_inited= false;
-C_MODE_START
-/** Get hash table key for instrumented files. */
-static uchar *filename_hash_get_key(const uchar *, size_t *, my_bool);
-C_MODE_END
/**
Initialize all the instruments instance buffers.
@@ -146,39 +193,78 @@ C_MODE_END
*/
int init_instruments(const PFS_global_param *param)
{
- uint thread_history_sizing;
+ PFS_events_statements *pfs_stmt;
+ unsigned char *pfs_tokens;
+
+ 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;
- DBUG_ENTER("init_instruments");
+
+ /* Make sure init_event_name_sizing is called */
+ DBUG_ASSERT(wait_class_max != 0);
mutex_max= param->m_mutex_sizing;
+ mutex_full= false;
mutex_lost= 0;
rwlock_max= param->m_rwlock_sizing;
+ rwlock_full= false;
rwlock_lost= 0;
cond_max= param->m_cond_sizing;
+ cond_full= false;
cond_lost= 0;
file_max= param->m_file_sizing;
+ file_full= false;
file_lost= 0;
file_handle_max= param->m_file_handle_sizing;
+ file_handle_full= false;
file_handle_lost= 0;
+
+ pfs_max_digest_length= param->m_max_digest_length;
+
table_max= param->m_table_sizing;
+ table_full= false;
table_lost= 0;
thread_max= param->m_thread_sizing;
+ thread_full= false;
thread_lost= 0;
+ socket_max= param->m_socket_sizing;
+ socket_full= false;
+ socket_lost= 0;
events_waits_history_per_thread= param->m_events_waits_history_sizing;
- thread_history_sizing= param->m_thread_sizing
+ thread_waits_history_sizing= param->m_thread_sizing
* events_waits_history_per_thread;
- per_thread_rwlock_class_start= param->m_mutex_class_sizing;
- per_thread_cond_class_start= per_thread_rwlock_class_start
- + param->m_rwlock_class_sizing;
- per_thread_file_class_start= per_thread_cond_class_start
- + param->m_cond_class_sizing;
- instr_class_per_thread= per_thread_file_class_start
- + param->m_file_class_sizing;
-
thread_instr_class_waits_sizing= param->m_thread_sizing
- * instr_class_per_thread;
+ * wait_class_max;
+
+ events_stages_history_per_thread= param->m_events_stages_history_sizing;
+ thread_stages_history_sizing= param->m_thread_sizing
+ * events_stages_history_per_thread;
+
+ events_statements_history_per_thread= param->m_events_statements_history_sizing;
+ thread_statements_history_sizing= param->m_thread_sizing
+ * events_statements_history_per_thread;
+
+ statement_stack_max= 1;
+ thread_statements_stack_sizing= param->m_thread_sizing * statement_stack_max;
+
+ thread_instr_class_stages_sizing= param->m_thread_sizing
+ * param->m_stage_class_sizing;
+
+ thread_instr_class_statements_sizing= param->m_thread_sizing
+ * param->m_statement_class_sizing;
+
+ 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;
+
+ size_t current_digest_tokens_sizing= param->m_thread_sizing * pfs_max_digest_length * statement_stack_max;
+ size_t history_digest_tokens_sizing= param->m_thread_sizing * pfs_max_digest_length * events_statements_history_per_thread;
mutex_array= NULL;
rwlock_array= NULL;
@@ -186,213 +272,237 @@ int init_instruments(const PFS_global_param *param)
file_array= NULL;
file_handle_array= NULL;
table_array= NULL;
+ socket_array= NULL;
thread_array= NULL;
- thread_history_array= NULL;
+ thread_waits_history_array= NULL;
+ thread_stages_history_array= NULL;
+ thread_statements_history_array= NULL;
+ thread_statements_stack_array= NULL;
+ current_stmts_digest_token_array= NULL;
+ history_stmts_digest_token_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));
+ mutex_array= PFS_MALLOC_ARRAY(mutex_max, sizeof(PFS_mutex), PFS_mutex, MYF(MY_ZEROFILL));
if (unlikely(mutex_array == NULL))
- DBUG_RETURN(1);
+ return 1;
}
if (rwlock_max > 0)
{
- rwlock_array= PFS_MALLOC_ARRAY(rwlock_max, PFS_rwlock, MYF(MY_ZEROFILL));
+ rwlock_array= PFS_MALLOC_ARRAY(rwlock_max, sizeof(PFS_rwlock), PFS_rwlock, MYF(MY_ZEROFILL));
if (unlikely(rwlock_array == NULL))
- DBUG_RETURN(1);
+ return 1;
}
if (cond_max > 0)
{
- cond_array= PFS_MALLOC_ARRAY(cond_max, PFS_cond, MYF(MY_ZEROFILL));
+ cond_array= PFS_MALLOC_ARRAY(cond_max, sizeof(PFS_cond), PFS_cond, MYF(MY_ZEROFILL));
if (unlikely(cond_array == NULL))
- DBUG_RETURN(1);
+ return 1;
}
if (file_max > 0)
{
- file_array= PFS_MALLOC_ARRAY(file_max, PFS_file, MYF(MY_ZEROFILL));
+ file_array= PFS_MALLOC_ARRAY(file_max, sizeof(PFS_file), PFS_file, MYF(MY_ZEROFILL));
if (unlikely(file_array == NULL))
- DBUG_RETURN(1);
+ return 1;
}
if (file_handle_max > 0)
{
- file_handle_array= PFS_MALLOC_ARRAY(file_handle_max, PFS_file*, MYF(MY_ZEROFILL));
+ file_handle_array= PFS_MALLOC_ARRAY(file_handle_max, sizeof(PFS_file*), PFS_file*, MYF(MY_ZEROFILL));
if (unlikely(file_handle_array == NULL))
- DBUG_RETURN(1);
+ return 1;
}
if (table_max > 0)
{
- table_array= PFS_MALLOC_ARRAY(table_max, PFS_table, MYF(MY_ZEROFILL));
+ table_array= PFS_MALLOC_ARRAY(table_max, sizeof(PFS_table), PFS_table, MYF(MY_ZEROFILL));
if (unlikely(table_array == NULL))
- DBUG_RETURN(1);
+ return 1;
+ }
+
+ if (socket_max > 0)
+ {
+ socket_array= PFS_MALLOC_ARRAY(socket_max, sizeof(PFS_socket), 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));
+ thread_array= PFS_MALLOC_ARRAY(thread_max, sizeof(PFS_thread), PFS_thread, MYF(MY_ZEROFILL));
if (unlikely(thread_array == NULL))
- DBUG_RETURN(1);
+ return 1;
}
- if (thread_history_sizing > 0)
+ if (thread_waits_history_sizing > 0)
{
- thread_history_array=
- PFS_MALLOC_ARRAY(thread_history_sizing, PFS_events_waits,
+ thread_waits_history_array=
+ PFS_MALLOC_ARRAY(thread_waits_history_sizing, sizeof(PFS_events_waits), PFS_events_waits,
MYF(MY_ZEROFILL));
- if (unlikely(thread_history_array == NULL))
- DBUG_RETURN(1);
+ 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_chain, MYF(MY_ZEROFILL));
+ sizeof(PFS_single_stat), PFS_single_stat, MYF(MY_ZEROFILL));
if (unlikely(thread_instr_class_waits_array == NULL))
- DBUG_RETURN(1);
+ return 1;
+
+ for (index= 0; index < thread_instr_class_waits_sizing; index++)
+ thread_instr_class_waits_array[index].reset();
}
- for (index= 0; index < thread_instr_class_waits_sizing; index++)
+ if (thread_stages_history_sizing > 0)
{
- /*
- Currently, this chain is of length 1,
- but it's still implemented as a stat chain,
- since more aggregations are planned to be implemented in m_parent.
- */
- thread_instr_class_waits_array[index].m_control_flag=
- &flag_events_waits_summary_by_thread_by_event_name;
- thread_instr_class_waits_array[index].m_parent= NULL;
+ thread_stages_history_array=
+ PFS_MALLOC_ARRAY(thread_stages_history_sizing, sizeof(PFS_events_stages), PFS_events_stages,
+ MYF(MY_ZEROFILL));
+ if (unlikely(thread_stages_history_array == NULL))
+ return 1;
}
- for (index= 0; index < thread_max; index++)
+ if (thread_instr_class_stages_sizing > 0)
{
- thread_array[index].m_waits_history=
- &thread_history_array[index * events_waits_history_per_thread];
- thread_array[index].m_instr_class_wait_stats=
- &thread_instr_class_waits_array[index * instr_class_per_thread];
+ thread_instr_class_stages_array=
+ PFS_MALLOC_ARRAY(thread_instr_class_stages_sizing,
+ sizeof(PFS_stage_stat), 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();
}
- DBUG_RETURN(0);
-}
-
-/**
- Find the per-thread wait statistics for a mutex class.
- @param thread input thread
- @param klass mutex class
- @return the per thread per mutex class wait stat
-*/
-PFS_single_stat_chain *
-find_per_thread_mutex_class_wait_stat(PFS_thread *thread,
- PFS_mutex_class *klass)
-{
- PFS_single_stat_chain *stat;
- uint index;
- DBUG_ENTER("find_per_thread_mutex_class_wait_stat");
+ if (thread_statements_history_sizing > 0)
+ {
+ thread_statements_history_array=
+ PFS_MALLOC_ARRAY(thread_statements_history_sizing, sizeof(PFS_events_statements),
+ PFS_events_statements, MYF(MY_ZEROFILL));
+ if (unlikely(thread_statements_history_array == NULL))
+ return 1;
+ }
- DBUG_ASSERT(thread != NULL);
- DBUG_ASSERT(klass != NULL);
- index= klass->m_index;
- DBUG_ASSERT(index < mutex_class_max);
+ if (thread_statements_stack_sizing > 0)
+ {
+ thread_statements_stack_array=
+ PFS_MALLOC_ARRAY(thread_statements_stack_sizing, sizeof(PFS_events_statements),
+ PFS_events_statements, MYF(MY_ZEROFILL));
+ if (unlikely(thread_statements_stack_array == NULL))
+ return 1;
+ }
- stat= &(thread->m_instr_class_wait_stats[index]);
- DBUG_RETURN(stat);
-}
+ if (thread_instr_class_statements_sizing > 0)
+ {
+ thread_instr_class_statements_array=
+ PFS_MALLOC_ARRAY(thread_instr_class_statements_sizing,
+ sizeof(PFS_statement_stat), 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();
+ }
-/**
- Find the per-thread wait statistics for a rwlock class.
- @param thread input thread
- @param klass rwlock class
- @return the per thread per rwlock class wait stat
-*/
-PFS_single_stat_chain *
-find_per_thread_rwlock_class_wait_stat(PFS_thread *thread,
- PFS_rwlock_class *klass)
-{
- PFS_single_stat_chain *stat;
- uint index;
- DBUG_ENTER("find_per_thread_rwlock_class_wait_stat");
+ if (thread_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;
+ }
- DBUG_ASSERT(thread != NULL);
- DBUG_ASSERT(klass != NULL);
- index= klass->m_index;
- DBUG_ASSERT(index < rwlock_class_max);
+ if (current_digest_tokens_sizing > 0)
+ {
+ current_stmts_digest_token_array=
+ (unsigned char *)pfs_malloc(current_digest_tokens_sizing, MYF(MY_ZEROFILL));
+ if (unlikely(current_stmts_digest_token_array == NULL))
+ return 1;
+ }
- stat= &(thread->m_instr_class_wait_stats
- [per_thread_rwlock_class_start + index]);
- DBUG_RETURN(stat);
-}
+ if (history_digest_tokens_sizing > 0)
+ {
+ history_stmts_digest_token_array=
+ (unsigned char *)pfs_malloc(history_digest_tokens_sizing, MYF(MY_ZEROFILL));
+ if (unlikely(history_stmts_digest_token_array == NULL))
+ return 1;
+ }
-/**
- Find the per-thread wait statistics for a condition class.
- @param thread input thread
- @param klass condition class
- @return the per thread per condition class wait stat
-*/
-PFS_single_stat_chain *
-find_per_thread_cond_class_wait_stat(PFS_thread *thread,
- PFS_cond_class *klass)
-{
- PFS_single_stat_chain *stat;
- uint index;
- DBUG_ENTER("find_per_thread_cond_class_wait_stat");
+ for (index= 0; index < thread_max; index++)
+ {
+ thread_array[index].m_waits_history=
+ &thread_waits_history_array[index * events_waits_history_per_thread];
+ thread_array[index].m_instr_class_waits_stats=
+ &thread_instr_class_waits_array[index * wait_class_max];
+ thread_array[index].m_stages_history=
+ &thread_stages_history_array[index * events_stages_history_per_thread];
+ thread_array[index].m_instr_class_stages_stats=
+ &thread_instr_class_stages_array[index * stage_class_max];
+ thread_array[index].m_statements_history=
+ &thread_statements_history_array[index * events_statements_history_per_thread];
+ thread_array[index].m_statement_stack=
+ &thread_statements_stack_array[index * statement_stack_max];
+ thread_array[index].m_instr_class_statements_stats=
+ &thread_instr_class_statements_array[index * statement_class_max];
+ thread_array[index].m_session_connect_attrs=
+ &thread_session_connect_attrs_array[index * session_connect_attrs_size_per_thread];
+ }
- DBUG_ASSERT(thread != NULL);
- DBUG_ASSERT(klass != NULL);
- index= klass->m_index;
- DBUG_ASSERT(index < cond_class_max);
+ for (index= 0; index < thread_statements_stack_sizing; index++)
+ {
+ pfs_stmt= & thread_statements_stack_array[index];
- stat= &(thread->m_instr_class_wait_stats
- [per_thread_cond_class_start + index]);
- DBUG_RETURN(stat);
-}
+ pfs_tokens= & current_stmts_digest_token_array[index * pfs_max_digest_length];
+ pfs_stmt->m_digest_storage.reset(pfs_tokens, pfs_max_digest_length);
+ }
-/**
- Find the per-thread wait statistics for a file class.
- @param thread input thread
- @param klass file class
- @return the per thread per file class wait stat
-*/
-PFS_single_stat_chain *
-find_per_thread_file_class_wait_stat(PFS_thread *thread,
- PFS_file_class *klass)
-{
- PFS_single_stat_chain *stat;
- uint index;
- DBUG_ENTER("find_per_thread_file_class_wait_stat");
+ for (index= 0; index < thread_statements_history_sizing; index++)
+ {
+ pfs_stmt= & thread_statements_history_array[index];
- DBUG_ASSERT(thread != NULL);
- DBUG_ASSERT(klass != NULL);
- index= klass->m_index;
- DBUG_ASSERT(index < file_class_max);
+ pfs_tokens= & history_stmts_digest_token_array[index * pfs_max_digest_length];
+ pfs_stmt->m_digest_storage.reset(pfs_tokens, pfs_max_digest_length);
+ }
- stat= &(thread->m_instr_class_wait_stats
- [per_thread_file_class_start + index]);
- DBUG_RETURN(stat);
-}
+ if (stage_class_max > 0)
+ {
+ global_instr_class_stages_array=
+ PFS_MALLOC_ARRAY(stage_class_max,
+ sizeof(PFS_stage_stat), 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();
+ }
-/** Reset the wait statistics per thread. */
-void reset_per_thread_wait_stat(void)
-{
- PFS_single_stat_chain *stat= thread_instr_class_waits_array;
- PFS_single_stat_chain *stat_last= stat + thread_instr_class_waits_sizing;
- DBUG_ENTER("reset_per_thread_wait_stat");
+ if (statement_class_max > 0)
+ {
+ global_instr_class_statements_array=
+ PFS_MALLOC_ARRAY(statement_class_max,
+ sizeof(PFS_statement_stat), 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();
+ }
- for ( ; stat < stat_last; stat++)
- reset_single_stat_link(stat);
- DBUG_VOID_RETURN;
+ return 0;
}
/** Cleanup all the instruments buffers. */
void cleanup_instruments(void)
{
- DBUG_ENTER("cleanup_instruments");
-
pfs_free(mutex_array);
mutex_array= NULL;
mutex_max= 0;
@@ -411,35 +521,55 @@ void cleanup_instruments(void)
pfs_free(table_array);
table_array= NULL;
table_max= 0;
+ pfs_free(socket_array);
+ socket_array= NULL;
+ socket_max= 0;
pfs_free(thread_array);
thread_array= NULL;
thread_max= 0;
- pfs_free(thread_history_array);
- thread_history_array= NULL;
+ pfs_free(thread_waits_history_array);
+ thread_waits_history_array= NULL;
+ pfs_free(thread_stages_history_array);
+ thread_stages_history_array= NULL;
+ pfs_free(thread_statements_history_array);
+ thread_statements_history_array= NULL;
+ pfs_free(thread_statements_stack_array);
+ thread_statements_stack_array= NULL;
pfs_free(thread_instr_class_waits_array);
thread_instr_class_waits_array= NULL;
- DBUG_VOID_RETURN;
+ 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_instr_class_statements_array);
+ thread_instr_class_statements_array= NULL;
+ pfs_free(thread_instr_class_stages_array);
+ thread_instr_class_stages_array= NULL;
+ pfs_free(thread_session_connect_attrs_array);
+ thread_session_connect_attrs_array=NULL;
+ pfs_free(current_stmts_digest_token_array);
+ current_stmts_digest_token_array= NULL;
+ pfs_free(history_stmts_digest_token_array);
+ history_stmts_digest_token_array= NULL;
}
-extern "C"
-{
+C_MODE_START
+/** Get hash table key for instrumented files. */
static uchar *filename_hash_get_key(const uchar *entry, size_t *length,
my_bool)
{
const PFS_file * const *typed_entry;
const PFS_file *file;
const void *result;
- DBUG_ENTER("filename_hash_get_key");
-
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;
- DBUG_RETURN(const_cast<uchar*> (reinterpret_cast<const uchar*> (result)));
-}
+ return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
}
+C_MODE_END
/**
Initialize the file name hash.
@@ -447,41 +577,35 @@ static uchar *filename_hash_get_key(const uchar *entry, size_t *length,
*/
int init_file_hash(void)
{
- DBUG_ENTER("init_file_hash");
-
- if (! filename_hash_inited)
+ 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;
}
- DBUG_RETURN(0);
+ return 0;
}
/** Cleanup the file name hash. */
void cleanup_file_hash(void)
{
- DBUG_ENTER("cleanup_file_hash");
-
if (filename_hash_inited)
{
lf_hash_destroy(&filename_hash);
filename_hash_inited= false;
}
- DBUG_VOID_RETURN;
}
void PFS_scan::init(uint random, uint max_size)
{
- DBUG_ENTER("PFS_scan::init");
-
m_pass= 0;
if (max_size == 0)
{
/* Degenerated case, no buffer */
m_pass_max= 0;
- DBUG_VOID_RETURN;
+ return;
}
DBUG_ASSERT(random < max_size);
@@ -540,7 +664,6 @@ void PFS_scan::init(uint random, uint 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);
- DBUG_VOID_RETURN;
}
/**
@@ -551,43 +674,76 @@ void PFS_scan::init(uint random, uint max_size)
*/
PFS_mutex* create_mutex(PFS_mutex_class *klass, const void *identity)
{
- PFS_scan scan;
- uint random= randomized_index(identity, mutex_max);
- DBUG_ENTER("create_mutex");
+ static uint PFS_ALIGNED mutex_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_mutex *pfs;
+
+ if (mutex_full)
+ {
+ /*
+ This is a safety plug.
+ When mutex_array is severely undersized,
+ do not spin to death for each call.
+ */
+ mutex_lost++;
+ return NULL;
+ }
- for (scan.init(random, mutex_max);
- scan.has_pass();
- scan.next_pass())
+ while (++attempts <= mutex_max)
{
- PFS_mutex *pfs= mutex_array + scan.first();
- PFS_mutex *pfs_last= mutex_array + scan.last();
- for ( ; pfs < pfs_last; pfs++)
+ /*
+ Problem:
+ Multiple threads running concurrently may need to create a new
+ instrumented mutex, and find an empty slot in mutex_array[].
+ With N1 threads running on a N2 core hardware:
+ - up to N2 hardware threads can run concurrently,
+ causing contention if looking at the same array[i] slot.
+ - up to N1 threads can run almost concurrently (with thread scheduling),
+ scanning maybe overlapping regions in the [0-mutex_max] array.
+
+ Solution:
+ Instead of letting different threads compete on the same array[i] entry,
+ this code forces all threads to cooperate with the monotonic_index.
+ Only one thread will be allowed to test a given array[i] slot.
+ All threads do scan from the same region, starting at monotonic_index.
+ Serializing on monotonic_index ensures that when a slot is found occupied
+ in a given loop by a given thread, other threads will not attempt this
+ slot.
+ */
+ index= PFS_atomic::add_u32(& mutex_monotonic_index, 1) % mutex_max;
+ pfs= mutex_array + index;
+
+ if (pfs->m_lock.is_free())
{
- if (pfs->m_lock.is_free())
+ if (pfs->m_lock.free_to_dirty())
{
- if (pfs->m_lock.free_to_dirty())
- {
- pfs->m_identity= identity;
- pfs->m_class= klass;
- pfs->m_wait_stat.m_control_flag=
- &flag_events_waits_summary_by_instance;
- pfs->m_wait_stat.m_parent= &klass->m_wait_stat;
- reset_single_stat_link(&pfs->m_wait_stat);
- pfs->m_lock_stat.m_control_flag=
- &flag_events_locks_summary_by_instance;
- pfs->m_lock_stat.m_parent= &klass->m_lock_stat;
- reset_single_stat_link(&pfs->m_lock_stat);
- pfs->m_owner= NULL;
- pfs->m_last_locked= 0;
- pfs->m_lock.dirty_to_allocated();
- DBUG_RETURN(pfs);
- }
+ pfs->m_identity= identity;
+ pfs->m_class= klass;
+ pfs->m_enabled= klass->m_enabled && flag_global_instrumentation;
+ pfs->m_timed= klass->m_timed;
+ pfs->m_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++;
- DBUG_RETURN(NULL);
+ /*
+ Race condition.
+ The mutex_array might not be full if a concurrent thread
+ called destroy_mutex() during the scan, leaving one
+ empty slot we did not find.
+ However, 99.999 percent full tables or 100 percent full tables
+ are treated the same here, we declare the array overloaded.
+ */
+ mutex_full= true;
+ return NULL;
}
/**
@@ -596,11 +752,15 @@ PFS_mutex* create_mutex(PFS_mutex_class *klass, const void *identity)
*/
void destroy_mutex(PFS_mutex *pfs)
{
- DBUG_ENTER("destroy_mutex");
-
DBUG_ASSERT(pfs != NULL);
+ PFS_mutex_class *klass= pfs->m_class;
+ /* Aggregate to EVENTS_WAITS_SUMMARY_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();
- DBUG_VOID_RETURN;
+ mutex_full= false;
}
/**
@@ -611,49 +771,47 @@ void destroy_mutex(PFS_mutex *pfs)
*/
PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity)
{
- PFS_scan scan;
- uint random= randomized_index(identity, rwlock_max);
- DBUG_ENTER("create_rwlock");
+ static uint PFS_ALIGNED rwlock_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_rwlock *pfs;
- for (scan.init(random, rwlock_max);
- scan.has_pass();
- scan.next_pass())
+ if (rwlock_full)
{
- PFS_rwlock *pfs= rwlock_array + scan.first();
- PFS_rwlock *pfs_last= rwlock_array + scan.last();
- for ( ; pfs < pfs_last; pfs++)
+ rwlock_lost++;
+ return NULL;
+ }
+
+ 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.is_free())
+ if (pfs->m_lock.free_to_dirty())
{
- if (pfs->m_lock.free_to_dirty())
- {
- pfs->m_identity= identity;
- pfs->m_class= klass;
- pfs->m_wait_stat.m_control_flag=
- &flag_events_waits_summary_by_instance;
- pfs->m_wait_stat.m_parent= &klass->m_wait_stat;
- reset_single_stat_link(&pfs->m_wait_stat);
- pfs->m_lock.dirty_to_allocated();
- pfs->m_read_lock_stat.m_control_flag=
- &flag_events_locks_summary_by_instance;
- pfs->m_read_lock_stat.m_parent= &klass->m_read_lock_stat;
- reset_single_stat_link(&pfs->m_read_lock_stat);
- pfs->m_write_lock_stat.m_control_flag=
- &flag_events_locks_summary_by_instance;
- pfs->m_write_lock_stat.m_parent= &klass->m_write_lock_stat;
- reset_single_stat_link(&pfs->m_write_lock_stat);
- pfs->m_writer= NULL;
- pfs->m_readers= 0;
- pfs->m_last_written= 0;
- pfs->m_last_read= 0;
- DBUG_RETURN(pfs);
- }
+ pfs->m_identity= identity;
+ pfs->m_class= klass;
+ pfs->m_enabled= klass->m_enabled && flag_global_instrumentation;
+ pfs->m_timed= klass->m_timed;
+ pfs->m_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++;
- DBUG_RETURN(NULL);
+ rwlock_full= true;
+ return NULL;
}
/**
@@ -662,11 +820,15 @@ PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity)
*/
void destroy_rwlock(PFS_rwlock *pfs)
{
- DBUG_ENTER("destroy_rwlock");
-
DBUG_ASSERT(pfs != NULL);
+ PFS_rwlock_class *klass= pfs->m_class;
+ /* Aggregate to EVENTS_WAITS_SUMMARY_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();
- DBUG_VOID_RETURN;
+ rwlock_full= false;
}
/**
@@ -677,39 +839,45 @@ void destroy_rwlock(PFS_rwlock *pfs)
*/
PFS_cond* create_cond(PFS_cond_class *klass, const void *identity)
{
- PFS_scan scan;
- uint random= randomized_index(identity, cond_max);
- DBUG_ENTER("create_cond");
+ static uint PFS_ALIGNED cond_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_cond *pfs;
+
+ if (cond_full)
+ {
+ cond_lost++;
+ return NULL;
+ }
- for (scan.init(random, cond_max);
- scan.has_pass();
- scan.next_pass())
+ while (++attempts <= cond_max)
{
- PFS_cond *pfs= cond_array + scan.first();
- PFS_cond *pfs_last= cond_array + scan.last();
- for ( ; pfs < pfs_last; pfs++)
+ /* See create_mutex() */
+ index= PFS_atomic::add_u32(& cond_monotonic_index, 1) % cond_max;
+ pfs= cond_array + index;
+
+ if (pfs->m_lock.is_free())
{
- if (pfs->m_lock.is_free())
+ if (pfs->m_lock.free_to_dirty())
{
- if (pfs->m_lock.free_to_dirty())
- {
- pfs->m_identity= identity;
- pfs->m_class= klass;
- pfs->m_cond_stat.m_signal_count= 0;
- pfs->m_cond_stat.m_broadcast_count= 0;
- pfs->m_wait_stat.m_control_flag=
- &flag_events_waits_summary_by_instance;
- pfs->m_wait_stat.m_parent= &klass->m_wait_stat;
- reset_single_stat_link(&pfs->m_wait_stat);
- pfs->m_lock.dirty_to_allocated();
- DBUG_RETURN(pfs);
- }
+ pfs->m_identity= identity;
+ pfs->m_class= klass;
+ pfs->m_enabled= klass->m_enabled && flag_global_instrumentation;
+ pfs->m_timed= klass->m_timed;
+ pfs->m_cond_stat.m_signal_count= 0;
+ pfs->m_cond_stat.m_broadcast_count= 0;
+ pfs->m_wait_stat.reset();
+ pfs->m_lock.dirty_to_allocated();
+ if (klass->is_singleton())
+ klass->m_singleton= pfs;
+ return pfs;
}
}
}
cond_lost++;
- DBUG_RETURN(NULL);
+ cond_full= true;
+ return NULL;
}
/**
@@ -718,11 +886,34 @@ PFS_cond* create_cond(PFS_cond_class *klass, const void *identity)
*/
void destroy_cond(PFS_cond *pfs)
{
- DBUG_ENTER("destroy_cond");
-
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();
- DBUG_VOID_RETURN;
+ cond_full= false;
+}
+
+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_number= 0;
+
+ 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);
+ }
}
/**
@@ -730,54 +921,165 @@ void destroy_cond(PFS_cond *pfs)
@param klass the thread class
@param identity the thread address,
or a value characteristic of this thread
- @param thread_id the PROCESSLIST thread id,
+ @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,
- ulong thread_id)
+ ulonglong processlist_id)
{
- PFS_scan scan;
- uint random= randomized_index(identity, thread_max);
- DBUG_ENTER("create_thread");
+ static uint PFS_ALIGNED thread_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_thread *pfs;
+
+ if (thread_full)
+ {
+ thread_lost++;
+ return NULL;
+ }
- for (scan.init(random, thread_max);
- scan.has_pass();
- scan.next_pass())
+ while (++attempts <= thread_max)
{
- PFS_thread *pfs= thread_array + scan.first();
- PFS_thread *pfs_last= thread_array + scan.last();
- for ( ; pfs < pfs_last; pfs++)
+ /* See create_mutex() */
+ index= PFS_atomic::add_u32(& thread_monotonic_index, 1) % thread_max;
+ pfs= thread_array + index;
+
+ if (pfs->m_lock.is_free())
{
- if (pfs->m_lock.is_free())
+ if (pfs->m_lock.free_to_dirty())
{
- if (pfs->m_lock.free_to_dirty())
+ pfs->m_thread_internal_id=
+ PFS_atomic::add_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_stmt_lock.set_allocated();
+ pfs->m_session_lock.set_allocated();
+ 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_stage= 0;
+ pfs->m_processlist_info[0]= '\0';
+ pfs->m_processlist_info_length= 0;
+
+ pfs->m_host= NULL;
+ pfs->m_user= NULL;
+ pfs->m_account= NULL;
+ set_thread_account(pfs);
+
+ PFS_events_waits *child_wait;
+ for (index= 0; index < WAIT_STACK_SIZE; index++)
{
- pfs->m_thread_internal_id=
- PFS_atomic::add_u32(&thread_internal_id_counter, 1);
- pfs->m_thread_id= thread_id;
- pfs->m_event_id= 1;
- pfs->m_enabled= true;
- pfs->m_class= klass;
- pfs->m_wait_locker_count= 0;
- pfs->m_waits_history_full= false;
- pfs->m_waits_history_index= 0;
-
- PFS_single_stat_chain *stat= pfs->m_instr_class_wait_stats;
- PFS_single_stat_chain *stat_last= stat + instr_class_per_thread;
- for ( ; stat < stat_last; stat++)
- reset_single_stat_link(stat);
- pfs->m_filename_hash_pins= NULL;
- pfs->m_table_share_hash_pins= NULL;
- pfs->m_lock.dirty_to_allocated();
- DBUG_RETURN(pfs);
+ child_wait= & pfs->m_events_waits_stack[index];
+ child_wait->m_thread_internal_id= pfs->m_thread_internal_id;
+ child_wait->m_event_id= 0;
+ child_wait->m_end_event_id= 0;
+ child_wait->m_event_type= EVENT_TYPE_STATEMENT;
+ child_wait->m_wait_class= NO_WAIT_CLASS;
}
+
+ PFS_events_stages *child_stage= & pfs->m_stage_current;
+ child_stage->m_thread_internal_id= pfs->m_thread_internal_id;
+ child_stage->m_event_id= 0;
+ child_stage->m_end_event_id= 0;
+ child_stage->m_event_type= EVENT_TYPE_STATEMENT;
+ child_stage->m_class= NULL;
+ child_stage->m_timer_start= 0;
+ child_stage->m_timer_end= 0;
+ child_stage->m_source_file= NULL;
+ child_stage->m_source_line= 0;
+
+ PFS_events_statements *child_statement;
+ for (index= 0; index < statement_stack_max; index++)
+ {
+ child_statement= & pfs->m_statement_stack[index];
+ child_statement->m_thread_internal_id= pfs->m_thread_internal_id;
+ child_statement->m_event_id= 0;
+ child_statement->m_end_event_id= 0;
+ child_statement->m_event_type= EVENT_TYPE_STATEMENT;
+ child_statement->m_class= NULL;
+ child_statement->m_timer_start= 0;
+ child_statement->m_timer_end= 0;
+ child_statement->m_lock_time= 0;
+ child_statement->m_source_file= NULL;
+ child_statement->m_source_line= 0;
+ child_statement->m_current_schema_name_length= 0;
+ child_statement->m_sqltext_length= 0;
+
+ child_statement->m_message_text[0]= '\0';
+ child_statement->m_sql_errno= 0;
+ child_statement->m_sqlstate[0]= '\0';
+ child_statement->m_error_count= 0;
+ child_statement->m_warning_count= 0;
+ child_statement->m_rows_affected= 0;
+
+ child_statement->m_rows_sent= 0;
+ child_statement->m_rows_examined= 0;
+ child_statement->m_created_tmp_disk_tables= 0;
+ child_statement->m_created_tmp_tables= 0;
+ child_statement->m_select_full_join= 0;
+ child_statement->m_select_full_range_join= 0;
+ child_statement->m_select_range= 0;
+ child_statement->m_select_range_check= 0;
+ child_statement->m_select_scan= 0;
+ child_statement->m_sort_merge_passes= 0;
+ child_statement->m_sort_range= 0;
+ child_statement->m_sort_rows= 0;
+ child_statement->m_sort_scan= 0;
+ child_statement->m_no_index_used= 0;
+ child_statement->m_no_good_index_used= 0;
+ }
+ pfs->m_events_statements_count= 0;
+
+ pfs->m_lock.dirty_to_allocated();
+ return pfs;
}
}
}
thread_lost++;
- DBUG_RETURN(NULL);
+ thread_full= true;
+ 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);
}
/**
@@ -794,25 +1096,14 @@ PFS_thread *sanitize_thread(PFS_thread *unsafe)
SANITIZE_ARRAY_BODY(PFS_thread, thread_array, thread_max, unsafe);
}
-const char *sanitize_file_name(const char *unsafe)
+PFS_file *sanitize_file(PFS_file *unsafe)
{
- intptr ptr= (intptr) unsafe;
- intptr first= (intptr) &file_array[0];
- intptr last= (intptr) &file_array[file_max];
- DBUG_ENTER("sanitize_file_name");
+ SANITIZE_ARRAY_BODY(PFS_file, file_array, file_max, unsafe);
+}
- /* Check if unsafe points inside file_array[] */
- if (likely((first <= ptr) && (ptr < last)))
- {
- /* Check if unsafe points to PFS_file::m_filename */
- intptr offset= (ptr - first) % sizeof(PFS_file);
- intptr valid_offset= my_offsetof(PFS_file, m_filename[0]);
- if (likely(offset == valid_offset))
- {
- DBUG_RETURN(unsafe);
- }
- }
- DBUG_RETURN(NULL);
+PFS_socket *sanitize_socket(PFS_socket *unsafe)
+{
+ SANITIZE_ARRAY_BODY(PFS_socket, socket_array, socket_max, unsafe);
}
/**
@@ -821,9 +1112,28 @@ const char *sanitize_file_name(const char *unsafe)
*/
void destroy_thread(PFS_thread *pfs)
{
- DBUG_ENTER("destroy_thread");
-
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);
@@ -834,8 +1144,38 @@ void destroy_thread(PFS_thread *pfs)
lf_hash_put_pins(pfs->m_table_share_hash_pins);
pfs->m_table_share_hash_pins= NULL;
}
+ if (pfs->m_setup_actor_hash_pins)
+ {
+ lf_hash_put_pins(pfs->m_setup_actor_hash_pins);
+ pfs->m_setup_actor_hash_pins= NULL;
+ }
+ if (pfs->m_setup_object_hash_pins)
+ {
+ lf_hash_put_pins(pfs->m_setup_object_hash_pins);
+ pfs->m_setup_object_hash_pins= NULL;
+ }
+ if (pfs->m_user_hash_pins)
+ {
+ lf_hash_put_pins(pfs->m_user_hash_pins);
+ pfs->m_user_hash_pins= NULL;
+ }
+ if (pfs->m_account_hash_pins)
+ {
+ lf_hash_put_pins(pfs->m_account_hash_pins);
+ pfs->m_account_hash_pins= NULL;
+ }
+ if (pfs->m_host_hash_pins)
+ {
+ lf_hash_put_pins(pfs->m_host_hash_pins);
+ pfs->m_host_hash_pins= NULL;
+ }
+ if (pfs->m_digest_hash_pins)
+ {
+ lf_hash_put_pins(pfs->m_digest_hash_pins);
+ pfs->m_digest_hash_pins= NULL;
+ }
pfs->m_lock.allocated_to_free();
- DBUG_VOID_RETURN;
+ thread_full= false;
}
/**
@@ -860,21 +1200,22 @@ LF_PINS* get_filename_hash_pins(PFS_thread *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)
+ const char *filename, uint len, bool create)
{
PFS_file *pfs;
- PFS_scan scan;
- DBUG_ENTER("find_or_create_file");
+
+ DBUG_ASSERT(klass != NULL || ! create);
LF_PINS *pins= get_filename_hash_pins(thread);
if (unlikely(pins == NULL))
{
file_lost++;
- DBUG_RETURN(NULL);
+ return NULL;
}
char safe_buffer[FN_REFLEN];
@@ -942,7 +1283,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
if (my_realpath(buffer, dirbuffer, MYF(0)) != 0)
{
file_lost++;
- DBUG_RETURN(NULL);
+ return NULL;
}
/* Append the unresolved file name to the resolved path */
@@ -960,7 +1301,12 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
PFS_file **entry;
uint retry_count= 0;
const uint retry_max= 3;
+ static uint 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));
@@ -969,69 +1315,78 @@ search:
pfs= *entry;
pfs->m_file_stat.m_open_count++;
lf_hash_search_unpin(pins);
- DBUG_RETURN(pfs);
+ return pfs;
}
lf_hash_search_unpin(pins);
- /* filename is not constant, just using it for noise on create */
- uint random= randomized_index(filename, file_max);
+ if (! create)
+ {
+ /* No lost counter, just looking for the file existence. */
+ return NULL;
+ }
- for (scan.init(random, file_max);
- scan.has_pass();
- scan.next_pass())
+ if (file_full)
{
- pfs= file_array + scan.first();
- PFS_file *pfs_last= file_array + scan.last();
- for ( ; pfs < pfs_last; pfs++)
+ file_lost++;
+ 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.is_free())
+ if (pfs->m_lock.free_to_dirty())
{
- if (pfs->m_lock.free_to_dirty())
+ pfs->m_class= klass;
+ pfs->m_enabled= klass->m_enabled && flag_global_instrumentation;
+ pfs->m_timed= klass->m_timed;
+ strncpy(pfs->m_filename, normalized_filename, normalized_length);
+ pfs->m_filename[normalized_length]= '\0';
+ pfs->m_filename_length= normalized_length;
+ pfs->m_file_stat.m_open_count= 1;
+ pfs->m_file_stat.m_io_stat.reset();
+ pfs->m_identity= (const void *)pfs;
+
+ int res;
+ res= lf_hash_insert(&filename_hash, thread->m_filename_hash_pins,
+ &pfs);
+ if (likely(res == 0))
{
- pfs->m_class= klass;
- strncpy(pfs->m_filename, normalized_filename, normalized_length);
- pfs->m_filename[normalized_length]= '\0';
- pfs->m_filename_length= normalized_length;
- pfs->m_file_stat.m_open_count= 1;
- pfs->m_wait_stat.m_control_flag=
- &flag_events_waits_summary_by_instance;
- pfs->m_wait_stat.m_parent= &klass->m_wait_stat;
- reset_single_stat_link(&pfs->m_wait_stat);
-
- int res;
- res= lf_hash_insert(&filename_hash, pins,
- &pfs);
- if (likely(res == 0))
- {
- pfs->m_lock.dirty_to_allocated();
- DBUG_RETURN(pfs);
- }
+ pfs->m_lock.dirty_to_allocated();
+ if (klass->is_singleton())
+ klass->m_singleton= pfs;
+ return pfs;
+ }
- pfs->m_lock.dirty_to_free();
+ pfs->m_lock.dirty_to_free();
- if (res > 0)
+ if (res > 0)
+ {
+ /* Duplicate insert by another thread */
+ if (++retry_count > retry_max)
{
- /* Duplicate insert by another thread */
- if (++retry_count > retry_max)
- {
- /* Avoid infinite loops */
- file_lost++;
- DBUG_RETURN(NULL);
- }
- goto search;
+ /* Avoid infinite loops */
+ file_lost++;
+ return NULL;
}
-
- /* OOM in lf_hash_insert */
- file_lost++;
- DBUG_RETURN(NULL);
+ goto search;
}
+
+ /* OOM in lf_hash_insert */
+ file_lost++;
+ return NULL;
}
}
}
file_lost++;
- DBUG_RETURN(NULL);
+ file_full= true;
+ return NULL;
}
/**
@@ -1040,11 +1395,8 @@ search:
*/
void release_file(PFS_file *pfs)
{
- DBUG_ENTER("release_file");
-
DBUG_ASSERT(pfs != NULL);
pfs->m_file_stat.m_open_count--;
- DBUG_VOID_RETURN;
}
/**
@@ -1054,59 +1406,166 @@ void release_file(PFS_file *pfs)
*/
void destroy_file(PFS_thread *thread, PFS_file *pfs)
{
- DBUG_ENTER("destroy_file");
-
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();
- DBUG_VOID_RETURN;
+ file_full= false;
}
/**
Create instrumentation for a table instance.
@param share the table share
+ @param opening_thread the opening thread
@param identity the table address
@return a table instance, or NULL
*/
-PFS_table* create_table(PFS_table_share *share, const void *identity)
+PFS_table* create_table(PFS_table_share *share, PFS_thread *opening_thread,
+ const void *identity)
{
- PFS_scan scan;
- uint random= randomized_index(identity, table_max);
- DBUG_ENTER("create_table");
+ static uint PFS_ALIGNED table_monotonic_index= 0;
+ uint index;
+ uint attempts= 0;
+ PFS_table *pfs;
- for (scan.init(random, table_max);
- scan.has_pass();
- scan.next_pass())
+ if (table_full)
{
- PFS_table *pfs= table_array + scan.first();
- PFS_table *pfs_last= table_array + scan.last();
- for ( ; pfs < pfs_last; pfs++)
+ table_lost++;
+ return NULL;
+ }
+
+ 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.is_free())
+ if (pfs->m_lock.free_to_dirty())
{
- if (pfs->m_lock.free_to_dirty())
- {
- pfs->m_identity= identity;
- pfs->m_share= share;
- pfs->m_wait_stat.m_control_flag=
- &flag_events_waits_summary_by_instance;
- pfs->m_wait_stat.m_parent= &share->m_wait_stat;
- reset_single_stat_link(&pfs->m_wait_stat);
- pfs->m_lock.dirty_to_allocated();
- DBUG_RETURN(pfs);
- }
+ 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++;
- DBUG_RETURN(NULL);
+ table_full= true;
+ 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();
}
/**
@@ -1115,67 +1574,175 @@ PFS_table* create_table(PFS_table_share *share, const void *identity)
*/
void destroy_table(PFS_table *pfs)
{
- DBUG_ENTER("destroy_table");
+ DBUG_ASSERT(pfs != NULL);
+ pfs->m_share->dec_refcount();
+ pfs->m_lock.allocated_to_free();
+ table_full= false;
+}
+
+/**
+ 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;
+
+ if (socket_full)
+ {
+ socket_lost++;
+ return NULL;
+ }
+
+ 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++;
+ socket_full= true;
+ 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();
- DBUG_VOID_RETURN;
+ socket_full= false;
}
static void reset_mutex_waits_by_instance(void)
{
PFS_mutex *pfs= mutex_array;
PFS_mutex *pfs_last= mutex_array + mutex_max;
- DBUG_ENTER("reset_mutex_waits_by_instance");
for ( ; pfs < pfs_last; pfs++)
- reset_single_stat_link(&pfs->m_wait_stat);
- DBUG_VOID_RETURN;
+ 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;
- DBUG_ENTER("reset_rwlock_waits_by_instance");
for ( ; pfs < pfs_last; pfs++)
- reset_single_stat_link(&pfs->m_wait_stat);
- DBUG_VOID_RETURN;
+ 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;
- DBUG_ENTER("reset_cond_waits_by_instance");
for ( ; pfs < pfs_last; pfs++)
- reset_single_stat_link(&pfs->m_wait_stat);
- DBUG_VOID_RETURN;
+ 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;
- DBUG_ENTER("reset_file_waits_by_instance");
for ( ; pfs < pfs_last; pfs++)
- reset_single_stat_link(&pfs->m_wait_stat);
- DBUG_VOID_RETURN;
+ 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)
{
- DBUG_ENTER("reset_events_waits_by_instance");
-
reset_mutex_waits_by_instance();
reset_rwlock_waits_by_instance();
reset_cond_waits_by_instance();
reset_file_waits_by_instance();
- DBUG_VOID_RETURN;
+ reset_socket_waits_by_instance();
}
/** Reset the io statistics per file instance. */
@@ -1183,11 +1750,567 @@ void reset_file_instance_io(void)
{
PFS_file *pfs= file_array;
PFS_file *pfs_last= file_array + file_max;
- DBUG_ENTER("reset_file_instance_io");
for ( ; pfs < pfs_last; pfs++)
- reset_file_stat(&pfs->m_file_stat);
- DBUG_VOID_RETURN;
+ 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,
+ PFS_account *safe_account,
+ PFS_user *safe_user,
+ PFS_host *safe_host)
+{
+ if (likely(safe_account != NULL))
+ {
+ safe_account->m_disconnected_count++;
+ return;
+ }
+
+ if (safe_user != NULL)
+ safe_user->m_disconnected_count++;
+
+ if (safe_host != NULL)
+ safe_host->m_disconnected_count++;
+
+ /* There is no global table for connections statistics. */
+ return;
+}
+
+void aggregate_thread(PFS_thread *thread,
+ PFS_account *safe_account,
+ PFS_user *safe_user,
+ PFS_host *safe_host)
+{
+ aggregate_thread_waits(thread, safe_account, safe_user, safe_host);
+ aggregate_thread_stages(thread, safe_account, safe_user, safe_host);
+ aggregate_thread_statements(thread, safe_account, safe_user, safe_host);
+ aggregate_thread_stats(thread, safe_account, safe_user, safe_host);
+}
+
+void aggregate_thread_waits(PFS_thread *thread,
+ PFS_account *safe_account,
+ PFS_user *safe_user,
+ PFS_host *safe_host)
+{
+ if (likely(safe_account != NULL))
+ {
+ /*
+ 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,
+ safe_account->m_instr_class_waits_stats);
+
+ return;
+ }
+
+ if ((safe_user != NULL) && (safe_host != NULL))
+ {
+ /*
+ 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,
+ safe_user->m_instr_class_waits_stats,
+ safe_host->m_instr_class_waits_stats);
+ return;
+ }
+
+ if (safe_user != NULL)
+ {
+ /*
+ 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,
+ safe_user->m_instr_class_waits_stats);
+ return;
+ }
+
+ if (safe_host != NULL)
+ {
+ /*
+ 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,
+ safe_host->m_instr_class_waits_stats);
+ return;
+ }
+
+ /* Orphan thread, clean the waits stats. */
+ thread->reset_waits_stats();
+}
+
+void aggregate_thread_stages(PFS_thread *thread,
+ PFS_account *safe_account,
+ PFS_user *safe_user,
+ PFS_host *safe_host)
+{
+ if (likely(safe_account != NULL))
+ {
+ /*
+ 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,
+ safe_account->m_instr_class_stages_stats);
+
+ return;
+ }
+
+ if ((safe_user != NULL) && (safe_host != NULL))
+ {
+ /*
+ 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,
+ safe_user->m_instr_class_stages_stats,
+ safe_host->m_instr_class_stages_stats);
+ return;
+ }
+
+ if (safe_user != NULL)
+ {
+ /*
+ 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,
+ safe_user->m_instr_class_stages_stats,
+ global_instr_class_stages_array);
+ return;
+ }
+
+ if (safe_host != NULL)
+ {
+ /*
+ 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,
+ safe_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,
+ PFS_account *safe_account,
+ PFS_user *safe_user,
+ PFS_host *safe_host)
+{
+ if (likely(safe_account != NULL))
+ {
+ /*
+ 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,
+ safe_account->m_instr_class_statements_stats);
+
+ return;
+ }
+
+ if ((safe_user != NULL) && (safe_host != NULL))
+ {
+ /*
+ 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,
+ safe_user->m_instr_class_statements_stats,
+ safe_host->m_instr_class_statements_stats);
+ return;
+ }
+
+ if (safe_user != NULL)
+ {
+ /*
+ 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,
+ safe_user->m_instr_class_statements_stats,
+ global_instr_class_statements_array);
+ return;
+ }
+
+ if (safe_host != NULL)
+ {
+ /*
+ 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,
+ safe_host->m_instr_class_statements_stats);
+ return;
+ }
+
+ /*
+ Aggregate EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME
+ to EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME.
+ */
+ aggregate_all_statements(thread->m_instr_class_statements_stats,
+ global_instr_class_statements_array);
+}
+
+void clear_thread_account(PFS_thread *thread)
+{
+ if (thread->m_account != NULL)
+ {
+ thread->m_account->release();
+ thread->m_account= NULL;
+ }
+
+ if (thread->m_user != NULL)
+ {
+ thread->m_user->release();
+ thread->m_user= NULL;
+ }
+
+ if (thread->m_host != NULL)
+ {
+ thread->m_host->release();
+ thread->m_host= NULL;
+ }
+}
+
+void set_thread_account(PFS_thread *thread)
+{
+ DBUG_ASSERT(thread->m_account == NULL);
+ DBUG_ASSERT(thread->m_user == NULL);
+ DBUG_ASSERT(thread->m_host == NULL);
+
+ thread->m_account= find_or_create_account(thread,
+ thread->m_username,
+ thread->m_username_length,
+ thread->m_hostname,
+ thread->m_hostname_length);
+
+ if ((thread->m_account == NULL) && (thread->m_username_length > 0))
+ thread->m_user= find_or_create_user(thread,
+ thread->m_username,
+ thread->m_username_length);
+
+ if ((thread->m_account == NULL) && (thread->m_hostname_length > 0))
+ thread->m_host= find_or_create_host(thread,
+ thread->m_hostname,
+ thread->m_hostname_length);
+}
+
+void update_mutex_derived_flags()
+{
+ PFS_mutex *pfs= mutex_array;
+ PFS_mutex *pfs_last= mutex_array + mutex_max;
+ PFS_mutex_class *klass;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ klass= sanitize_mutex_class(pfs->m_class);
+ if (likely(klass != NULL))
+ {
+ pfs->m_enabled= klass->m_enabled && flag_global_instrumentation;
+ pfs->m_timed= klass->m_timed;
+ }
+ else
+ {
+ pfs->m_enabled= false;
+ pfs->m_timed= false;
+ }
+ }
+}
+
+void update_rwlock_derived_flags()
+{
+ PFS_rwlock *pfs= rwlock_array;
+ PFS_rwlock *pfs_last= rwlock_array + rwlock_max;
+ PFS_rwlock_class *klass;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ klass= sanitize_rwlock_class(pfs->m_class);
+ if (likely(klass != NULL))
+ {
+ pfs->m_enabled= klass->m_enabled && flag_global_instrumentation;
+ pfs->m_timed= klass->m_timed;
+ }
+ else
+ {
+ pfs->m_enabled= false;
+ pfs->m_timed= false;
+ }
+ }
+}
+
+void update_cond_derived_flags()
+{
+ PFS_cond *pfs= cond_array;
+ PFS_cond *pfs_last= cond_array + cond_max;
+ PFS_cond_class *klass;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ klass= sanitize_cond_class(pfs->m_class);
+ if (likely(klass != NULL))
+ {
+ pfs->m_enabled= klass->m_enabled && flag_global_instrumentation;
+ pfs->m_timed= klass->m_timed;
+ }
+ else
+ {
+ pfs->m_enabled= false;
+ pfs->m_timed= false;
+ }
+ }
+}
+
+void update_file_derived_flags()
+{
+ PFS_file *pfs= file_array;
+ PFS_file *pfs_last= file_array + file_max;
+ PFS_file_class *klass;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ klass= sanitize_file_class(pfs->m_class);
+ if (likely(klass != NULL))
+ {
+ pfs->m_enabled= klass->m_enabled && flag_global_instrumentation;
+ pfs->m_timed= klass->m_timed;
+ }
+ else
+ {
+ pfs->m_enabled= false;
+ pfs->m_timed= false;
+ }
+ }
+}
+
+void update_table_derived_flags()
+{
+ PFS_table *pfs= table_array;
+ PFS_table *pfs_last= table_array + table_max;
+ PFS_table_share *share;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ share= sanitize_table_share(pfs->m_share);
+ if (likely(share != NULL))
+ {
+ pfs->m_io_enabled= share->m_enabled &&
+ flag_global_instrumentation && global_table_io_class.m_enabled;
+ pfs->m_io_timed= share->m_timed && global_table_io_class.m_timed;
+ pfs->m_lock_enabled= share->m_enabled &&
+ flag_global_instrumentation && global_table_lock_class.m_enabled;
+ pfs->m_lock_timed= share->m_timed && global_table_lock_class.m_timed;
+ }
+ else
+ {
+ pfs->m_io_enabled= false;
+ pfs->m_io_timed= false;
+ pfs->m_lock_enabled= false;
+ pfs->m_lock_timed= false;
+ }
+ }
+}
+
+void update_socket_derived_flags()
+{
+ PFS_socket *pfs= socket_array;
+ PFS_socket *pfs_last= socket_array + socket_max;
+ PFS_socket_class *klass;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ klass= sanitize_socket_class(pfs->m_class);
+ if (likely(klass != NULL))
+ {
+ pfs->m_enabled= klass->m_enabled && flag_global_instrumentation;
+ pfs->m_timed= klass->m_timed;
+ }
+ else
+ {
+ pfs->m_enabled= false;
+ pfs->m_timed= false;
+ }
+ }
+}
+
+void update_instruments_derived_flags()
+{
+ update_mutex_derived_flags();
+ update_rwlock_derived_flags();
+ update_cond_derived_flags();
+ update_file_derived_flags();
+ update_table_derived_flags();
+ update_socket_derived_flags();
+ /* nothing for stages and statements (no instances) */
}
/** @} */
diff --git a/storage/perfschema/pfs_instr.h b/storage/perfschema/pfs_instr.h
index f34cc94f7d2..76eeabb99da 100644
--- a/storage/perfschema/pfs_instr.h
+++ b/storage/perfschema/pfs_instr.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,11 +21,30 @@
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
@@ -33,27 +52,30 @@
*/
struct PFS_thread;
+struct PFS_host;
+struct PFS_user;
+struct PFS_account;
+/** Base structure for wait instruments. */
struct PFS_instr
{
/** Internal lock. */
pfs_lock m_lock;
- /** Instrument wait statistics chain. */
- PFS_single_stat_chain m_wait_stat;
+ /** Enabled flag. */
+ bool m_enabled;
+ /** Timed flag. */
+ bool m_timed;
};
/** Instrumented mutex implementation. @see PSI_mutex. */
-struct PFS_mutex : public PFS_instr
+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;
- /**
- Mutex lock usage statistics chain.
- This statistic is not exposed in user visible tables yet.
- */
- PFS_single_stat_chain m_lock_stat;
+ /** Instrument statistics. */
+ PFS_mutex_stat m_mutex_stat;
/** Current owner. */
PFS_thread *m_owner;
/**
@@ -64,22 +86,14 @@ struct PFS_mutex : public PFS_instr
};
/** Instrumented rwlock implementation. @see PSI_rwlock. */
-struct PFS_rwlock : public PFS_instr
+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;
- /**
- RWLock read lock usage statistics chain.
- This statistic is not exposed in user visible tables yet.
- */
- PFS_single_stat_chain m_read_lock_stat;
- /**
- RWLock write lock usage statistics chain.
- This statistic is not exposed in user visible tables yet.
- */
- PFS_single_stat_chain m_write_lock_stat;
+ /** Instrument statistics. */
+ PFS_rwlock_stat m_rwlock_stat;
/** Current writer thread. */
PFS_thread *m_writer;
/** Current count of readers. */
@@ -97,19 +111,26 @@ struct PFS_rwlock : public PFS_instr
};
/** Instrumented cond implementation. @see PSI_cond. */
-struct PFS_cond : public PFS_instr
+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_file : public PFS_instr
+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. */
@@ -121,19 +142,164 @@ struct PFS_file : public PFS_instr
};
/** Instrumented table implementation. @see PSI_table. */
-struct PFS_table : public PFS_instr
+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 LOCKER_STACK_SIZE
+ @def WAIT_STACK_LOGICAL_SIZE
Maximum number of nested waits.
+ Some waits, such as:
+ - "wait/io/table/sql/handler"
+ - "wait/lock/table/sql/handler"
+ are implemented by calling code in a storage engine,
+ that can cause nested waits (file io, mutex, ...)
+ Because of partitioned tables, a table io event (on the whole table)
+ can contain a nested table io event (on a partition).
+ Because of additional debug instrumentation,
+ waiting on what looks like a "mutex" (safe_mutex, innodb sync0sync, ...)
+ can cause nested waits to be recorded.
+ For example, a wait on innodb mutexes can lead to:
+ - wait/sync/mutex/innobase/some_mutex
+ - wait/sync/mutex/innobase/sync0sync
+ - wait/sync/mutex/innobase/os0sync
+ The max depth of the event stack must be sufficient
+ for these low level details to be visible.
*/
-#define LOCKER_STACK_SIZE 3
+#define WAIT_STACK_LOGICAL_SIZE 5
+/**
+ @def WAIT_STACK_BOTTOM
+ Maximum number dummy waits records.
+ One dummy record is reserved for the parent stage / statement,
+ at the bottom of the wait stack.
+*/
+#define WAIT_STACK_BOTTOM 1
+/**
+ @def WAIT_STACK_SIZE
+ Physical size of the waits stack
+*/
+#define WAIT_STACK_SIZE (WAIT_STACK_BOTTOM + WAIT_STACK_LOGICAL_SIZE)
+
+/** Max size of the statements stack. */
+extern uint statement_stack_max;
+/** Max size of the digests token array. */
+extern size_t pfs_max_digest_length;
/**
@def PFS_MAX_ALLOC_RETRY
@@ -142,6 +308,7 @@ struct PFS_table : public PFS_instr
*/
#define PFS_MAX_ALLOC_RETRY 1000
+/** The maximun number of passes in @sa PFS_scan. */
#define PFS_MAX_SCAN_PASS 2
/**
@@ -155,59 +322,119 @@ struct PFS_table : public PFS_instr
struct PFS_scan
{
public:
+ /**
+ Initialize a new scan.
+ @param random a random index to start from
+ @param max_size the max size of the interval to scan
+ */
void init(uint random, uint max_size);
+ /**
+ Predicate, has a next pass.
+ @return true if there is a next pass to perform.
+ */
bool has_pass() const
{ return (m_pass < m_pass_max); }
+ /**
+ Iterator, proceed to the next pass.
+ */
void next_pass()
{ m_pass++; }
+ /** First index for this pass. */
uint first() const
{ return m_first[m_pass]; }
+ /** Last index for this pass. */
uint last() const
{ return m_last[m_pass]; }
private:
+ /** Current pass. */
uint m_pass;
+ /** Maximum number of passes. */
uint m_pass_max;
+ /** First element for each pass. */
uint m_first[PFS_MAX_SCAN_PASS];
+ /** Last element for each pass. */
uint m_last[PFS_MAX_SCAN_PASS];
};
/** Instrumented thread implementation. @see PSI_thread. */
-struct PFS_thread
+struct PFS_ALIGNED PFS_thread : PFS_connection_slice
{
- /** Internal lock. */
+ 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.
+ This lock is exclusively used to protect against races
+ when creating and destroying PFS_thread.
+ Do not use this lock to protect thread attributes,
+ use one of @c m_stmt_lock or @c m_session_lock instead.
+ */
pfs_lock m_lock;
/** Pins for filename_hash. */
LF_PINS *m_filename_hash_pins;
/** Pins for table_share_hash. */
LF_PINS *m_table_share_hash_pins;
- /** Event ID counter */
- ulonglong m_event_id;
- /** Thread instrumentation flag. */
- bool m_enabled;
+ /** Pins for setup_actor_hash. */
+ LF_PINS *m_setup_actor_hash_pins;
+ /** Pins for setup_object_hash. */
+ LF_PINS *m_setup_object_hash_pins;
+ /** Pins for host_hash. */
+ LF_PINS *m_host_hash_pins;
+ /** Pins for user_hash. */
+ LF_PINS *m_user_hash_pins;
+ /** Pins for account_hash. */
+ LF_PINS *m_account_hash_pins;
+ /** Pins for digest_hash. */
+ LF_PINS *m_digest_hash_pins;
/** Internal thread identifier, unique. */
- ulong m_thread_internal_id;
+ ulonglong m_thread_internal_id;
+ /** Parent internal thread identifier. */
+ ulonglong m_parent_thread_internal_id;
/** External (SHOW PROCESSLIST) thread identifier, not unique. */
- ulong m_thread_id;
+ ulong m_processlist_id;
/** Thread class. */
PFS_thread_class *m_class;
- /** Size of @c m_wait_locker_stack. */
- uint m_wait_locker_count;
/**
- Stack of wait lockers.
- This member holds the data for the table
- PERFORMANCE_SCHEMA.EVENTS_WAITS_CURRENT.
- For most locks, only 1 wait locker is used at a given time.
- For composite locks, several records are needed:
- - 1 for a 'logical' wait (for example on the GLOBAL READ LOCK state)
- - 1 for a 'physical' wait (for example on COND_refresh)
+ Stack of events waits.
+ This member holds the data for the table PERFORMANCE_SCHEMA.EVENTS_WAITS_CURRENT.
+ Note that stack[0] is a dummy record that represents the parent stage/statement.
+ For example, assuming the following tree:
+ - STAGE ID 100
+ - WAIT ID 101, parent STAGE 100
+ - WAIT ID 102, parent wait 101
+ the data in the stack will be:
+ stack[0].m_event_id= 100, set by the stage instrumentation
+ stack[0].m_event_type= STAGE, set by the stage instrumentation
+ stack[0].m_nesting_event_id= unused
+ stack[0].m_nesting_event_type= unused
+ stack[1].m_event_id= 101
+ stack[1].m_event_type= WAIT
+ stack[1].m_nesting_event_id= stack[0].m_event_id= 100
+ stack[1].m_nesting_event_type= stack[0].m_event_type= STAGE
+ stack[2].m_event_id= 102
+ stack[2].m_event_type= WAIT
+ stack[2].m_nesting_event_id= stack[1].m_event_id= 101
+ stack[2].m_nesting_event_type= stack[1].m_event_type= WAIT
+
+ The whole point of the stack[0] record is to allow this optimization
+ in the code, in the instrumentation for wait events:
+ wait->m_nesting_event_id= (wait-1)->m_event_id;
+ wait->m_nesting_event_type= (wait-1)->m_event_type;
+ This code works for both the top level wait, and nested waits,
+ and works without if conditions, which helps performances.
*/
- PFS_wait_locker m_wait_locker_stack[LOCKER_STACK_SIZE];
+ PFS_events_waits m_events_waits_stack[WAIT_STACK_SIZE];
/** True if the circular buffer @c m_waits_history is full. */
bool m_waits_history_full;
/** Current index in the circular buffer @c m_waits_history. */
@@ -218,32 +445,127 @@ struct PFS_thread
PERFORMANCE_SCHEMA.EVENTS_WAITS_HISTORY.
*/
PFS_events_waits *m_waits_history;
+
+ /** True if the circular buffer @c m_stages_history is full. */
+ bool m_stages_history_full;
+ /** Current index in the circular buffer @c m_stages_history. */
+ uint m_stages_history_index;
/**
- Per thread waits aggregated statistics.
+ Stages history circular buffer.
This member holds the data for the table
- PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME.
+ PERFORMANCE_SCHEMA.EVENTS_STAGES_HISTORY.
*/
- PFS_single_stat_chain *m_instr_class_wait_stats;
-};
+ PFS_events_stages *m_stages_history;
-PFS_thread *sanitize_thread(PFS_thread *unsafe);
-const char *sanitize_file_name(const char *unsafe);
+ /** 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;
+
+ /**
+ Internal lock, for session attributes.
+ Statement attributes are expected to be updated in frequently,
+ typically per session execution.
+ */
+ pfs_lock m_session_lock;
+ /**
+ User name.
+ Protected by @c m_session_lock.
+ */
+ char m_username[USERNAME_LENGTH];
+ /**
+ Length of @c m_username.
+ Protected by @c m_session_lock.
+ */
+ uint m_username_length;
+ /**
+ Host name.
+ Protected by @c m_session_lock.
+ */
+ char m_hostname[HOSTNAME_LENGTH];
+ /**
+ Length of @c m_hostname.
+ Protected by @c m_session_lock.
+ */
+ uint m_hostname_length;
+ /**
+ Database name.
+ Protected by @c m_stmt_lock.
+ */
+ char m_dbname[NAME_LEN];
+ /**
+ Length of @c m_dbname.
+ Protected by @c m_stmt_lock.
+ */
+ uint m_dbname_length;
+ /** Current command. */
+ int m_command;
+ /** Start time. */
+ time_t m_start_time;
+ /**
+ Internal lock, for statement attributes.
+ Statement attributes are expected to be updated frequently,
+ typically per statement execution.
+ */
+ pfs_lock m_stmt_lock;
+ /** Processlist state (derived from stage). */
+ PFS_stage_key m_stage;
+ /**
+ Processlist info.
+ Protected by @c m_stmt_lock.
+ */
+ char m_processlist_info[COL_INFO_SIZE];
+ /**
+ Length of @c m_processlist_info_length.
+ Protected by @c m_stmt_lock.
+ */
+ uint m_processlist_info_length;
-PFS_single_stat_chain*
-find_per_thread_mutex_class_wait_stat(PFS_thread *thread,
- PFS_mutex_class *klass);
+ PFS_events_stages m_stage_current;
-PFS_single_stat_chain*
-find_per_thread_rwlock_class_wait_stat(PFS_thread *thread,
- PFS_rwlock_class *klass);
+ /** Size of @c m_events_statements_stack. */
+ uint m_events_statements_count;
+ PFS_events_statements *m_statement_stack;
-PFS_single_stat_chain*
-find_per_thread_cond_class_wait_stat(PFS_thread *thread,
- PFS_cond_class *klass);
+ PFS_host *m_host;
+ PFS_user *m_user;
+ PFS_account *m_account;
-PFS_single_stat_chain*
-find_per_thread_file_class_wait_stat(PFS_thread *thread,
- PFS_file_class *klass);
+ /** Reset session connect attributes */
+ void reset_session_connect_attrs();
+
+ /**
+ Buffer for the connection attributes.
+ Protected by @c m_session_lock.
+ */
+ char *m_session_connect_attrs;
+ /**
+ Length used by @c m_connect_attrs.
+ Protected by @c m_session_lock.
+ */
+ uint m_session_connect_attrs_length;
+ /**
+ Character set in which @c m_connect_attrs are encoded.
+ Protected by @c m_session_lock.
+ */
+ uint m_session_connect_attrs_cs_number;
+};
+
+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();
@@ -257,18 +579,25 @@ 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,
- ulong thread_id);
+ 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);
+ 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, const void *identity);
+PFS_table* create_table(PFS_table_share *share, PFS_thread *opening_thread,
+ const void *identity);
void destroy_table(PFS_table *pfs);
+PFS_socket* create_socket(PFS_socket_class *socket_class,
+ const 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;
@@ -285,9 +614,15 @@ extern long file_handle_max;
extern ulong file_handle_lost;
extern ulong table_max;
extern ulong table_lost;
+extern ulong socket_max;
+extern ulong socket_lost;
extern ulong events_waits_history_per_thread;
-extern ulong instr_class_per_thread;
+extern ulong events_stages_history_per_thread;
+extern ulong events_statements_history_per_thread;
extern ulong locker_lost;
+extern ulong statement_lost;
+extern ulong session_connect_attrs_lost;
+extern ulong session_connect_attrs_size_per_thread;
/* Exposing the data directly, for iterators. */
@@ -298,10 +633,65 @@ extern PFS_thread *thread_array;
extern PFS_file *file_array;
extern PFS_file **file_handle_array;
extern PFS_table *table_array;
+extern PFS_socket *socket_array;
void reset_events_waits_by_instance();
-void reset_per_thread_wait_stat();
void reset_file_instance_io();
+void reset_socket_instance_io();
+
+void aggregate_all_event_names(PFS_single_stat *from_array,
+ PFS_single_stat *to_array);
+void aggregate_all_event_names(PFS_single_stat *from_array,
+ PFS_single_stat *to_array_1,
+ PFS_single_stat *to_array_2);
+
+void aggregate_all_stages(PFS_stage_stat *from_array,
+ PFS_stage_stat *to_array);
+void aggregate_all_stages(PFS_stage_stat *from_array,
+ PFS_stage_stat *to_array_1,
+ PFS_stage_stat *to_array_2);
+
+void aggregate_all_statements(PFS_statement_stat *from_array,
+ PFS_statement_stat *to_array);
+void aggregate_all_statements(PFS_statement_stat *from_array,
+ PFS_statement_stat *to_array_1,
+ PFS_statement_stat *to_array_2);
+
+void aggregate_thread(PFS_thread *thread,
+ PFS_account *safe_account,
+ PFS_user *safe_user,
+ PFS_host *safe_host);
+void aggregate_thread_waits(PFS_thread *thread,
+ PFS_account *safe_account,
+ PFS_user *safe_user,
+ PFS_host *safe_host);
+void aggregate_thread_stages(PFS_thread *thread,
+ PFS_account *safe_account,
+ PFS_user *safe_user,
+ PFS_host *safe_host);
+void aggregate_thread_statements(PFS_thread *thread,
+ PFS_account *safe_account,
+ PFS_user *safe_user,
+ PFS_host *safe_host);
+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
index 67220675a4d..0d06ac025f2 100644
--- a/storage/perfschema/pfs_instr_class.cc
+++ b/storage/perfschema/pfs_instr_class.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,10 +20,14 @@
#include "my_global.h"
#include "my_sys.h"
+#include "structs.h"
+#include "table.h"
#include "pfs_instr_class.h"
#include "pfs_instr.h"
#include "pfs_global.h"
+#include "pfs_timer.h"
#include "pfs_events_waits.h"
+#include "pfs_setup_object.h"
#include "pfs_atomic.h"
#include "mysql/psi/mysql_thread.h"
#include "lf.h"
@@ -44,6 +48,21 @@
my_bool pfs_enabled= TRUE;
/**
+ PFS_INSTRUMENT option settings array and associated state variable to
+ serialize access during shutdown.
+ */
+DYNAMIC_ARRAY pfs_instr_config_array;
+int pfs_instr_config_state= PFS_INSTR_CONFIG_NOT_INITIALIZED;
+
+static void configure_instr_class(PFS_instr_class *entry);
+
+static void init_instr_class(PFS_instr_class *klass,
+ const char *name,
+ uint name_length,
+ int flags,
+ PFS_class_type class_type);
+
+/**
Current number of elements in mutex_class_array.
This global variable is written to during:
- the performance schema initialization
@@ -76,14 +95,26 @@ ulong thread_class_lost= 0;
ulong file_class_max= 0;
/** Number of file class lost. @sa file_class_array */
ulong file_class_lost= 0;
+/** Size of the stage class array. @sa stage_class_array */
+ulong stage_class_max= 0;
+/** Number of stage class lost. @sa stage_class_array */
+ulong stage_class_lost= 0;
+/** Size of the statement class array. @sa statement_class_array */
+ulong statement_class_max= 0;
+/** Number of statement class lost. @sa statement_class_array */
+ulong statement_class_lost= 0;
/** Size of the table share array. @sa table_share_array */
ulong table_share_max= 0;
/** Number of table share lost. @sa table_share_array */
ulong table_share_lost= 0;
+/** Size of the socket class array. @sa socket_class_array */
+ulong socket_class_max= 0;
+/** Number of socket class lost. @sa socket_class_array */
+ulong socket_class_lost= 0;
-static PFS_mutex_class *mutex_class_array= NULL;
-static PFS_rwlock_class *rwlock_class_array= NULL;
-static PFS_cond_class *cond_class_array= NULL;
+PFS_mutex_class *mutex_class_array= NULL;
+PFS_rwlock_class *rwlock_class_array= NULL;
+PFS_cond_class *cond_class_array= NULL;
/**
Current number or elements in thread_class_array.
@@ -104,29 +135,100 @@ static PFS_thread_class *thread_class_array= NULL;
*/
PFS_table_share *table_share_array= NULL;
-PFS_instr_class global_table_class=
-{
- "wait/table", /* name */
- 10, /* name length */
- 0, /* flags */
- true, /* enabled */
- true, /* timed */
- { &flag_events_waits_current, NULL, 0, 0, 0, 0} /* wait stat chain */
+PFS_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 table for instrumented tables. */
-static LF_HASH table_share_hash;
+/**
+ 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;
-C_MODE_START
-/** Get hash table key for instrumented tables. */
-static uchar *table_share_hash_get_key(const uchar *, size_t *, my_bool);
-C_MODE_END
static volatile uint32 file_class_dirty_count= 0;
static volatile uint32 file_class_allocated_count= 0;
-static PFS_file_class *file_class_array= NULL;
+PFS_file_class *file_class_array= NULL;
+
+static volatile uint32 stage_class_dirty_count= 0;
+static volatile uint32 stage_class_allocated_count= 0;
+
+static PFS_stage_class *stage_class_array= NULL;
+
+static volatile uint32 statement_class_dirty_count= 0;
+static volatile uint32 statement_class_allocated_count= 0;
+
+static PFS_statement_class *statement_class_array= NULL;
+
+static volatile uint32 socket_class_dirty_count= 0;
+static volatile uint32 socket_class_allocated_count= 0;
+
+static PFS_socket_class *socket_class_array= NULL;
+
+uint mutex_class_start= 0;
+uint rwlock_class_start= 0;
+uint cond_class_start= 0;
+uint file_class_start= 0;
+uint 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.
@@ -153,24 +255,24 @@ int init_sync_class(uint mutex_class_sizing,
if (mutex_class_max > 0)
{
- mutex_class_array= PFS_MALLOC_ARRAY(mutex_class_max, PFS_mutex_class,
- MYF(MY_ZEROFILL));
+ mutex_class_array= PFS_MALLOC_ARRAY(mutex_class_max, sizeof(PFS_mutex_class),
+ 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));
+ rwlock_class_array= PFS_MALLOC_ARRAY(rwlock_class_max, sizeof(PFS_rwlock_class),
+ 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));
+ cond_class_array= PFS_MALLOC_ARRAY(cond_class_max, sizeof(PFS_cond_class),
+ PFS_cond_class, MYF(MY_ZEROFILL));
if (unlikely(cond_class_array == NULL))
return 1;
}
@@ -206,8 +308,8 @@ int init_thread_class(uint thread_class_sizing)
if (thread_class_max > 0)
{
- thread_class_array= PFS_MALLOC_ARRAY(thread_class_max, PFS_thread_class,
- MYF(MY_ZEROFILL));
+ thread_class_array= PFS_MALLOC_ARRAY(thread_class_max, sizeof(PFS_thread_class),
+ PFS_thread_class, MYF(MY_ZEROFILL));
if (unlikely(thread_class_array == NULL))
result= 1;
}
@@ -239,8 +341,8 @@ int init_table_share(uint table_share_sizing)
if (table_share_max > 0)
{
- table_share_array= PFS_MALLOC_ARRAY(table_share_max, PFS_table_share,
- MYF(MY_ZEROFILL));
+ table_share_array= PFS_MALLOC_ARRAY(table_share_max, sizeof(PFS_table_share),
+ PFS_table_share, MYF(MY_ZEROFILL));
if (unlikely(table_share_array == NULL))
result= 1;
}
@@ -258,6 +360,8 @@ void cleanup_table_share(void)
table_share_max= 0;
}
+C_MODE_START
+/** get_key function for @c table_share_hash. */
static uchar *table_share_hash_get_key(const uchar *entry, size_t *length,
my_bool)
{
@@ -272,6 +376,7 @@ static uchar *table_share_hash_get_key(const uchar *entry, size_t *length,
result= &share->m_key.m_hash_key[0];
return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
}
+C_MODE_END
/** Initialize the table share hash table. */
int init_table_share_hash(void)
@@ -280,6 +385,7 @@ int init_table_share_hash(void)
{
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;
@@ -296,6 +402,72 @@ void cleanup_table_share_hash(void)
}
/**
+ Get the hash pins for @sa table_share_hash.
+ @param thread The running thread.
+ @returns The LF_HASH pins for the thread.
+*/
+LF_PINS* get_table_share_hash_pins(PFS_thread *thread)
+{
+ if (unlikely(thread->m_table_share_hash_pins == NULL))
+ {
+ if (! table_share_hash_inited)
+ return NULL;
+ thread->m_table_share_hash_pins= lf_hash_get_pins(&table_share_hash);
+ }
+ return thread->m_table_share_hash_pins;
+}
+
+/**
+ Set a table share hash key.
+ @param [out] key The key to populate.
+ @param temporary True for TEMPORARY TABLE.
+ @param schema_name The table schema name.
+ @param schema_name_length The table schema name length.
+ @param table_name The table name.
+ @param table_name_length The table name length.
+*/
+static void set_table_share_key(PFS_table_share_key *key,
+ bool temporary,
+ const char *schema_name, uint schema_name_length,
+ const char *table_name, uint table_name_length)
+{
+ DBUG_ASSERT(schema_name_length <= NAME_LEN);
+ DBUG_ASSERT(table_name_length <= NAME_LEN);
+ char *saved_schema_name;
+ char *saved_table_name;
+
+ char *ptr= &key->m_hash_key[0];
+ ptr[0]= (temporary ? OBJECT_TYPE_TEMPORARY_TABLE : OBJECT_TYPE_TABLE);
+ ptr++;
+ saved_schema_name= ptr;
+ memcpy(ptr, schema_name, schema_name_length);
+ ptr+= schema_name_length;
+ ptr[0]= 0;
+ ptr++;
+ saved_table_name= ptr;
+ memcpy(ptr, table_name, table_name_length);
+ ptr+= table_name_length;
+ ptr[0]= 0;
+ ptr++;
+ key->m_key_length= ptr - &key->m_hash_key[0];
+
+ if (lower_case_table_names)
+ {
+ my_casedn_str(files_charset_info, saved_schema_name);
+ my_casedn_str(files_charset_info, saved_table_name);
+ }
+}
+
+void PFS_table_share::refresh_setup_object_flags(PFS_thread *thread)
+{
+ lookup_setup_object(thread,
+ OBJECT_TYPE_TABLE,
+ m_schema_name, m_schema_name_length,
+ m_table_name, m_table_name_length,
+ &m_enabled, &m_timed);
+}
+
+/**
Initialize the file class buffer.
@param file_class_sizing max number of file class
@return 0 on success
@@ -309,8 +481,8 @@ int init_file_class(uint file_class_sizing)
if (file_class_max > 0)
{
- file_class_array= PFS_MALLOC_ARRAY(file_class_max, PFS_file_class,
- MYF(MY_ZEROFILL));
+ file_class_array= PFS_MALLOC_ARRAY(file_class_max, sizeof(PFS_file_class),
+ PFS_file_class, MYF(MY_ZEROFILL));
if (unlikely(file_class_array == NULL))
return 1;
}
@@ -329,10 +501,113 @@ void cleanup_file_class(void)
file_class_max= 0;
}
+/**
+ Initialize the stage class buffer.
+ @param stage_class_sizing max number of stage class
+ @return 0 on success
+*/
+int init_stage_class(uint stage_class_sizing)
+{
+ int result= 0;
+ stage_class_dirty_count= stage_class_allocated_count= 0;
+ stage_class_max= stage_class_sizing;
+ stage_class_lost= 0;
+
+ if (stage_class_max > 0)
+ {
+ stage_class_array= PFS_MALLOC_ARRAY(stage_class_max, sizeof(PFS_stage_class),
+ 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, sizeof(PFS_statement_class),
+ 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, sizeof(PFS_socket_class),
+ PFS_socket_class, MYF(MY_ZEROFILL));
+ if (unlikely(socket_class_array == NULL))
+ return 1;
+ }
+ else
+ socket_class_array= NULL;
+
+ return result;
+}
+
+/** Cleanup the socket class buffers. */
+void cleanup_socket_class(void)
+{
+ pfs_free(socket_class_array);
+ socket_class_array= NULL;
+ socket_class_dirty_count= socket_class_allocated_count= 0;
+ socket_class_max= 0;
+}
+
static void init_instr_class(PFS_instr_class *klass,
const char *name,
uint name_length,
- int flags)
+ int flags,
+ PFS_class_type class_type)
{
DBUG_ASSERT(name_length <= PFS_MAX_INFO_NAME_LENGTH);
memset(klass, 0, sizeof(PFS_instr_class));
@@ -341,6 +616,43 @@ static void init_instr_class(PFS_instr_class *klass,
klass->m_flags= flags;
klass->m_enabled= true;
klass->m_timed= true;
+ klass->m_type= class_type;
+ klass->m_timer= class_timers[class_type];
+}
+
+/**
+ Set user-defined configuration values for an instrument.
+*/
+static void configure_instr_class(PFS_instr_class *entry)
+{
+ uint match_length= 0; /* length of matching pattern */
+
+ for (uint i= 0; i < pfs_instr_config_array.elements; i++)
+ {
+ PFS_instr_config* e;
+ get_dynamic(&pfs_instr_config_array, (uchar*)&e, i);
+
+ /**
+ Compare class name to all configuration entries. In case of multiple
+ matches, the longer specification wins. For example, the pattern
+ 'ABC/DEF/GHI=ON' has precedence over 'ABC/DEF/%=OFF' regardless of
+ position within the configuration file or command line.
+
+ Consecutive wildcards affect the count.
+ */
+ if (!my_wildcmp(&my_charset_latin1,
+ entry->m_name, entry->m_name+entry->m_name_length,
+ e->m_name, e->m_name+e->m_name_length,
+ '\\', '?','%'))
+ {
+ if (e->m_name_length >= match_length)
+ {
+ entry->m_enabled= e->m_enabled;
+ entry->m_timed= e->m_timed;
+ match_length= MY_MAX(e->m_name_length, match_length);
+ }
+ }
+ }
}
#define REGISTER_CLASS_BODY_PART(INDEX, ARRAY, MAX, NAME, NAME_LENGTH) \
@@ -404,16 +716,16 @@ PFS_sync_key register_mutex_class(const char *name, uint name_length,
in INSTALL PLUGIN.
*/
entry= &mutex_class_array[index];
- init_instr_class(entry, name, name_length, flags);
- entry->m_wait_stat.m_control_flag=
- &flag_events_waits_summary_by_event_name;
- entry->m_wait_stat.m_parent= NULL;
- reset_single_stat_link(&entry->m_wait_stat);
- entry->m_lock_stat.m_control_flag=
- &flag_events_locks_summary_by_event_name;
- entry->m_lock_stat.m_parent= NULL;
- reset_single_stat_link(&entry->m_lock_stat);
- entry->m_index= index;
+ init_instr_class(entry, name, name_length, flags, PFS_CLASS_MUTEX);
+ entry->m_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
@@ -470,20 +782,14 @@ PFS_sync_key register_rwlock_class(const char *name, uint name_length,
if (index < rwlock_class_max)
{
entry= &rwlock_class_array[index];
- init_instr_class(entry, name, name_length, flags);
- entry->m_wait_stat.m_control_flag=
- &flag_events_waits_summary_by_event_name;
- entry->m_wait_stat.m_parent= NULL;
- reset_single_stat_link(&entry->m_wait_stat);
- entry->m_read_lock_stat.m_control_flag=
- &flag_events_locks_summary_by_event_name;
- entry->m_read_lock_stat.m_parent= NULL;
- reset_single_stat_link(&entry->m_read_lock_stat);
- entry->m_write_lock_stat.m_control_flag=
- &flag_events_locks_summary_by_event_name;
- entry->m_write_lock_stat.m_parent= NULL;
- reset_single_stat_link(&entry->m_write_lock_stat);
- entry->m_index= index;
+ init_instr_class(entry, name, name_length, flags, PFS_CLASS_RWLOCK);
+ entry->m_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);
}
@@ -514,12 +820,13 @@ PFS_sync_key register_cond_class(const char *name, uint name_length,
if (index < cond_class_max)
{
entry= &cond_class_array[index];
- init_instr_class(entry, name, name_length, flags);
- entry->m_wait_stat.m_control_flag=
- &flag_events_waits_summary_by_event_name;
- entry->m_wait_stat.m_parent= NULL;
- reset_single_stat_link(&entry->m_wait_stat);
- entry->m_index= index;
+ init_instr_class(entry, name, name_length, flags, PFS_CLASS_COND);
+ entry->m_event_name_index= cond_class_start + index;
+ entry->m_singleton= NULL;
+ entry->m_enabled= false; /* disabled by default */
+ entry->m_timed= false;
+ /* Set user-defined configuration options for this instrument */
+ configure_instr_class(entry);
PFS_atomic::add_u32(&cond_class_allocated_count, 1);
return (index + 1);
}
@@ -655,12 +962,13 @@ PFS_file_key register_file_class(const char *name, uint name_length,
if (index < file_class_max)
{
entry= &file_class_array[index];
- init_instr_class(entry, name, name_length, flags);
- entry->m_wait_stat.m_control_flag=
- &flag_events_waits_summary_by_event_name;
- entry->m_wait_stat.m_parent= NULL;
- reset_single_stat_link(&entry->m_wait_stat);
- entry->m_index= index;
+ init_instr_class(entry, name, name_length, flags, PFS_CLASS_FILE);
+ entry->m_event_name_index= file_class_start + index;
+ entry->m_singleton= NULL;
+ entry->m_enabled= true; /* enabled by default */
+ entry->m_timed= true;
+ /* Set user-defined configuration options for this instrument */
+ configure_instr_class(entry);
PFS_atomic::add_u32(&file_class_allocated_count, 1);
return (index + 1);
}
@@ -670,6 +978,84 @@ PFS_file_key register_file_class(const char *name, uint name_length,
}
/**
+ Register a stage instrumentation metadata.
+ @param name the instrumented name
+ @param prefix_length length in bytes of the name prefix
+ @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 prefix_length,
+ 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_prefix_length= prefix_length;
+ entry->m_event_name_index= index;
+ entry->m_enabled= false; /* disabled by default */
+ entry->m_timed= false;
+ /* Set user-defined configuration options for this instrument */
+ configure_instr_class(entry);
+ PFS_atomic::add_u32(&stage_class_allocated_count, 1);
+
+ return (index + 1);
+ }
+
+ stage_class_lost++;
+ return 0;
+}
+
+/**
+ Register a statement instrumentation metadata.
+ @param name the instrumented name
+ @param name_length length in bytes of name
+ @param flags the instrumentation flags
+ @return a statement instrumentation key
+*/
+PFS_statement_key register_statement_class(const char *name, uint name_length,
+ int flags)
+{
+ /* See comments in register_mutex_class */
+ uint32 index;
+ PFS_statement_class *entry;
+
+ REGISTER_CLASS_BODY_PART(index, statement_class_array, statement_class_max,
+ name, name_length)
+
+ index= PFS_atomic::add_u32(&statement_class_dirty_count, 1);
+
+ if (index < statement_class_max)
+ {
+ entry= &statement_class_array[index];
+ init_instr_class(entry, name, name_length, flags, PFS_CLASS_STATEMENT);
+ entry->m_event_name_index= index;
+ entry->m_enabled= true; /* enabled by default */
+ entry->m_timed= true;
+ /* Set user-defined configuration options for this instrument */
+ configure_instr_class(entry);
+ PFS_atomic::add_u32(&statement_class_allocated_count, 1);
+
+ return (index + 1);
+ }
+
+ statement_class_lost++;
+ return 0;
+}
+
+/**
Find a file instrumentation class by key.
@param key the instrument key
@return the instrument class, or NULL
@@ -685,125 +1071,282 @@ PFS_file_class *sanitize_file_class(PFS_file_class *unsafe)
}
/**
- Find or create a table instance by name.
+ Find a stage instrumentation class by key.
+ @param key the instrument key
+ @return the instrument class, or NULL
+*/
+PFS_stage_class *find_stage_class(PFS_stage_key key)
+{
+ FIND_CLASS_BODY(key, stage_class_allocated_count, stage_class_array);
+}
+
+PFS_stage_class *sanitize_stage_class(PFS_stage_class *unsafe)
+{
+ SANITIZE_ARRAY_BODY(PFS_stage_class, stage_class_array, stage_class_max, unsafe);
+}
+
+/**
+ Find a statement instrumentation class by key.
+ @param key the instrument key
+ @return the instrument class, or NULL
+*/
+PFS_statement_class *find_statement_class(PFS_stage_key key)
+{
+ FIND_CLASS_BODY(key, statement_class_allocated_count, statement_class_array);
+}
+
+PFS_statement_class *sanitize_statement_class(PFS_statement_class *unsafe)
+{
+ SANITIZE_ARRAY_BODY(PFS_statement_class, statement_class_array, statement_class_max, unsafe);
+}
+
+/**
+ Register a socket instrumentation metadata.
+ @param name the instrumented name
+ @param name_length length in bytes of name
+ @param flags the instrumentation flags
+ @return a socket instrumentation key
+*/
+PFS_socket_key register_socket_class(const char *name, uint name_length,
+ int flags)
+{
+ /* See comments in register_mutex_class */
+ uint32 index;
+ PFS_socket_class *entry;
+
+ REGISTER_CLASS_BODY_PART(index, socket_class_array, socket_class_max,
+ name, name_length)
+
+ index= PFS_atomic::add_u32(&socket_class_dirty_count, 1);
+
+ if (index < socket_class_max)
+ {
+ entry= &socket_class_array[index];
+ init_instr_class(entry, name, name_length, flags, PFS_CLASS_SOCKET);
+ entry->m_event_name_index= socket_class_start + index;
+ entry->m_singleton= NULL;
+ entry->m_enabled= false; /* disabled by default */
+ entry->m_timed= false;
+ /* Set user-defined configuration options for this instrument */
+ configure_instr_class(entry);
+ PFS_atomic::add_u32(&socket_class_allocated_count, 1);
+ return (index + 1);
+ }
+
+ socket_class_lost++;
+ return 0;
+}
+
+/**
+ Find a socket instrumentation class by key.
+ @param key the instrument key
+ @return the instrument class, or NULL
+*/
+PFS_socket_class *find_socket_class(PFS_socket_key key)
+{
+ FIND_CLASS_BODY(key, socket_class_allocated_count, socket_class_array);
+}
+
+PFS_socket_class *sanitize_socket_class(PFS_socket_class *unsafe)
+{
+ SANITIZE_ARRAY_BODY(PFS_socket_class, socket_class_array, socket_class_max, unsafe);
+}
+
+PFS_instr_class *find_table_class(uint index)
+{
+ if (index == 1)
+ return & global_table_io_class;
+ if (index == 2)
+ return & global_table_lock_class;
+ return NULL;
+}
+
+PFS_instr_class *sanitize_table_class(PFS_instr_class *unsafe)
+{
+ if (likely((& global_table_io_class == unsafe) ||
+ (& global_table_lock_class == unsafe)))
+ return unsafe;
+ return NULL;
+}
+
+PFS_instr_class *find_idle_class(uint index)
+{
+ if (index == 1)
+ return & global_idle_class;
+ return NULL;
+}
+
+PFS_instr_class *sanitize_idle_class(PFS_instr_class *unsafe)
+{
+ if (likely(& global_idle_class == unsafe))
+ return unsafe;
+ return NULL;
+}
+
+static void set_keys(PFS_table_share *pfs, const TABLE_SHARE *share)
+{
+ int len;
+ KEY *key_info= share->key_info;
+ PFS_table_key *pfs_key= pfs->m_keys;
+ PFS_table_key *pfs_key_last= pfs->m_keys + share->keys;
+ pfs->m_key_count= share->keys;
+
+ for ( ; pfs_key < pfs_key_last; pfs_key++, key_info++)
+ {
+ len= strlen(key_info->name);
+ memcpy(pfs_key->m_name, key_info->name, len);
+ pfs_key->m_name_length= len;
+ }
+
+ pfs_key_last= pfs->m_keys + MAX_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 schema_name the table schema name
- @param schema_name_length the table schema name length
- @param table_name the table name
- @param table_name_length the table name length
- @return a table instance, or NULL
+ @param temporary true for TEMPORARY TABLE
+ @param share table share
+ @return a table share, or NULL
*/
PFS_table_share* find_or_create_table_share(PFS_thread *thread,
- const char *schema_name,
- uint schema_name_length,
- const char *table_name,
- uint table_name_length)
+ bool temporary,
+ const TABLE_SHARE *share)
{
/* See comments in register_mutex_class */
- int pass;
PFS_table_share_key key;
- if (! table_share_hash_inited)
+ LF_PINS *pins= get_table_share_hash_pins(thread);
+ if (unlikely(pins == NULL))
{
- /* Table instrumentation can be turned off. */
table_share_lost++;
return NULL;
}
- if (unlikely(thread->m_table_share_hash_pins == NULL))
- {
- thread->m_table_share_hash_pins= lf_hash_get_pins(&table_share_hash);
- if (unlikely(thread->m_table_share_hash_pins == NULL))
- {
- table_share_lost++;
- return NULL;
- }
- }
-
- DBUG_ASSERT(schema_name_length <= NAME_LEN);
- DBUG_ASSERT(table_name_length <= NAME_LEN);
+ 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;
- char *ptr= &key.m_hash_key[0];
- memcpy(ptr, schema_name, schema_name_length);
- ptr+= schema_name_length;
- ptr[0]= 0; ptr++;
- memcpy(ptr, table_name, table_name_length);
- ptr+= table_name_length;
- ptr[0]= 0; ptr++;
- key.m_key_length= ptr - &key.m_hash_key[0];
+ set_table_share_key(&key, temporary,
+ schema_name, schema_name_length,
+ table_name, table_name_length);
PFS_table_share **entry;
uint retry_count= 0;
const uint retry_max= 3;
+ bool enabled= true;
+ bool timed= true;
+ static uint 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, thread->m_table_share_hash_pins,
- &key.m_hash_key[0], key.m_key_length));
+ (lf_hash_search(&table_share_hash, pins,
+ key.m_hash_key, key.m_key_length));
if (entry && (entry != MY_ERRPTR))
{
- PFS_table_share *pfs;
pfs= *entry;
- lf_hash_search_unpin(thread->m_table_share_hash_pins);
+ pfs->inc_refcount() ;
+ if (compare_keys(pfs, share) != 0)
+ {
+ set_keys(pfs, share);
+ /* FIXME: aggregate to table_share sink ? */
+ pfs->m_table_stat.fast_reset();
+ }
+ lf_hash_search_unpin(pins);
return pfs;
}
- /* table_name is not constant, just using it for noise on create */
- uint i= randomized_index(table_name, table_share_max);
+ lf_hash_search_unpin(pins);
- /*
- Pass 1: [random, table_share_max - 1]
- Pass 2: [0, table_share_max - 1]
- */
- for (pass= 1; pass <= 2; i=0, pass++)
+ if (retry_count == 0)
+ {
+ lookup_setup_object(thread,
+ OBJECT_TYPE_TABLE,
+ schema_name, schema_name_length,
+ table_name, table_name_length,
+ &enabled, &timed);
+ /*
+ Even when enabled is false, a record is added in the dictionary:
+ - It makes enabling a table already in the table cache possible,
+ - It improves performances for the next time a TABLE_SHARE is reloaded
+ in the table cache.
+ */
+ }
+
+ while (++attempts <= table_share_max)
{
- PFS_table_share *pfs= table_share_array + i;
- PFS_table_share *pfs_last= table_share_array + table_share_max;
- for ( ; pfs < pfs_last; pfs++)
+ /* See create_mutex() */
+ 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.is_free())
+ if (pfs->m_lock.free_to_dirty())
{
- if (pfs->m_lock.free_to_dirty())
+ pfs->m_key= key;
+ pfs->m_schema_name= &pfs->m_key.m_hash_key[1];
+ pfs->m_schema_name_length= schema_name_length;
+ pfs->m_table_name= &pfs->m_key.m_hash_key[schema_name_length + 2];
+ pfs->m_table_name_length= table_name_length;
+ pfs->m_enabled= enabled;
+ pfs->m_timed= timed;
+ pfs->init_refcount();
+ pfs->m_table_stat.fast_reset();
+ set_keys(pfs, share);
+
+ int res;
+ res= lf_hash_insert(&table_share_hash, pins, &pfs);
+ if (likely(res == 0))
{
- pfs->m_key= key;
- pfs->m_schema_name= &pfs->m_key.m_hash_key[0];
- pfs->m_schema_name_length= schema_name_length;
- pfs->m_table_name= &pfs->m_key.m_hash_key[schema_name_length + 1];
- pfs->m_table_name_length= table_name_length;
- pfs->m_wait_stat.m_control_flag=
- &flag_events_waits_summary_by_instance;
- pfs->m_wait_stat.m_parent= NULL;
- reset_single_stat_link(&pfs->m_wait_stat);
- pfs->m_enabled= true;
- pfs->m_timed= true;
- pfs->m_aggregated= false;
-
- int res;
- res= lf_hash_insert(&table_share_hash,
- thread->m_table_share_hash_pins, &pfs);
- if (likely(res == 0))
- {
- pfs->m_lock.dirty_to_allocated();
- return pfs;
- }
+ pfs->m_lock.dirty_to_allocated();
+ return pfs;
+ }
- pfs->m_lock.dirty_to_free();
+ pfs->m_lock.dirty_to_free();
- if (res > 0)
+ if (res > 0)
+ {
+ /* Duplicate insert by another thread */
+ if (++retry_count > retry_max)
{
- /* Duplicate insert by another thread */
- if (++retry_count > retry_max)
- {
- /* Avoid infinite loops */
- table_share_lost++;
- return NULL;
- }
- goto search;
+ /* Avoid infinite loops */
+ table_share_lost++;
+ return NULL;
}
-
- /* OOM in lf_hash_insert */
- table_share_lost++;
- return NULL;
+ goto search;
}
+
+ /* OOM in lf_hash_insert */
+ table_share_lost++;
+ return NULL;
}
}
}
@@ -812,112 +1355,124 @@ search:
return NULL;
}
-PFS_table_share *sanitize_table_share(PFS_table_share *unsafe)
+void PFS_table_share::aggregate_io(void)
{
- SANITIZE_ARRAY_BODY(PFS_table_share, table_share_array, table_share_max, unsafe);
+ 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();
}
-const char *sanitize_table_schema_name(const char *unsafe)
+void PFS_table_share::aggregate_lock(void)
{
- intptr ptr= (intptr) unsafe;
- intptr first= (intptr) &table_share_array[0];
- intptr last= (intptr) &table_share_array[table_share_max];
-
-
- /* Check if unsafe points inside table_share_array[] */
- if (likely((first <= ptr) && (ptr < last)))
- {
- intptr offset= (ptr - first) % sizeof(PFS_table_share);
- intptr from= my_offsetof(PFS_table_share, m_key.m_hash_key);
- /* Check if unsafe points inside PFS_table_share::m_key::m_hash_key */
- if (likely((from <= offset) && (offset < from + PFS_TABLESHARE_HASHKEY_SIZE)))
- {
- PFS_table_share *base= (PFS_table_share*) (ptr - offset);
- /* Check if unsafe really is the schema name */
- if (likely(base->m_schema_name == unsafe))
- return unsafe;
- }
- }
- return NULL;
+ global_table_lock_stat.aggregate(& m_table_stat.m_lock_stat);
+ m_table_stat.fast_reset_lock();
}
-const char *sanitize_table_object_name(const char *unsafe)
+void release_table_share(PFS_table_share *pfs)
{
- intptr ptr= (intptr) unsafe;
- intptr first= (intptr) &table_share_array[0];
- intptr last= (intptr) &table_share_array[table_share_max];
-
-
- /* Check if unsafe points inside table_share_array[] */
- if (likely((first <= ptr) && (ptr < last)))
- {
- intptr offset= (ptr - first) % sizeof(PFS_table_share);
- intptr from= my_offsetof(PFS_table_share, m_key.m_hash_key);
- /* Check if unsafe points inside PFS_table_share::m_key::m_hash_key */
- if (likely((from <= offset) && (offset < from + PFS_TABLESHARE_HASHKEY_SIZE)))
- {
- PFS_table_share *base= (PFS_table_share*) (ptr - offset);
- /* Check if unsafe really is the table name */
- if (likely(base->m_table_name == unsafe))
- return unsafe;
- }
- }
- return NULL;
+ DBUG_ASSERT(pfs->get_refcount() > 0);
+ pfs->dec_refcount();
}
-static void reset_mutex_class_waits(void)
+/**
+ Drop the instrumented table share associated with a table.
+ @param thread The running thread
+ @param temporary True for TEMPORARY TABLE
+ @param schema_name The table schema name
+ @param schema_name_length The table schema name length
+ @param table_name The table name
+ @param table_name_length The table name length
+*/
+void drop_table_share(PFS_thread *thread,
+ bool temporary,
+ const char *schema_name, uint schema_name_length,
+ const char *table_name, uint table_name_length)
{
- PFS_mutex_class *pfs= mutex_class_array;
- PFS_mutex_class *pfs_last= mutex_class_array + mutex_class_max;
+ PFS_table_share_key key;
+ LF_PINS* pins= get_table_share_hash_pins(thread);
+ if (unlikely(pins == NULL))
+ return;
+ set_table_share_key(&key, temporary, schema_name, schema_name_length,
+ table_name, table_name_length);
+ PFS_table_share **entry;
+ entry= reinterpret_cast<PFS_table_share**>
+ (lf_hash_search(&table_share_hash, pins,
+ key.m_hash_key, key.m_key_length));
+ if (entry && (entry != MY_ERRPTR))
+ {
+ PFS_table_share *pfs= *entry;
+ lf_hash_delete(&table_share_hash, pins,
+ pfs->m_key.m_hash_key, pfs->m_key.m_key_length);
+ pfs->m_lock.allocated_to_free();
+ }
- for ( ; pfs < pfs_last; pfs++)
- reset_single_stat_link(&pfs->m_wait_stat);
+ lf_hash_search_unpin(pins);
}
-static void reset_rwlock_class_waits(void)
+/**
+ Sanitize an unsafe table_share pointer.
+ @param unsafe The possibly corrupt pointer.
+ @return A valid table_safe_pointer, or NULL.
+*/
+PFS_table_share *sanitize_table_share(PFS_table_share *unsafe)
{
- PFS_rwlock_class *pfs= rwlock_class_array;
- PFS_rwlock_class *pfs_last= rwlock_class_array + rwlock_class_max;
-
- for ( ; pfs < pfs_last; pfs++)
- reset_single_stat_link(&pfs->m_wait_stat);
+ SANITIZE_ARRAY_BODY(PFS_table_share, table_share_array, table_share_max, unsafe);
}
-static void reset_cond_class_waits(void)
+/** Reset the wait statistics per instrument class. */
+void reset_events_waits_by_class()
{
- PFS_cond_class *pfs= cond_class_array;
- PFS_cond_class *pfs_last= cond_class_array + cond_class_max;
-
- for ( ; pfs < pfs_last; pfs++)
- reset_single_stat_link(&pfs->m_wait_stat);
+ reset_file_class_io();
+ reset_socket_class_io();
+ global_idle_stat.reset();
+ global_table_io_stat.reset();
+ global_table_lock_stat.reset();
}
-static void reset_file_class_waits(void)
+/** Reset the io statistics per file class. */
+void reset_file_class_io(void)
{
PFS_file_class *pfs= file_class_array;
PFS_file_class *pfs_last= file_class_array + file_class_max;
for ( ; pfs < pfs_last; pfs++)
- reset_single_stat_link(&pfs->m_wait_stat);
+ pfs->m_file_stat.m_io_stat.reset();
}
-/** Reset the wait statistics for every instrument class. */
-void reset_instrument_class_waits(void)
+/** Reset the io statistics per socket class. */
+void reset_socket_class_io(void)
{
- reset_mutex_class_waits();
- reset_rwlock_class_waits();
- reset_cond_class_waits();
- reset_file_class_waits();
+ PFS_socket_class *pfs= socket_class_array;
+ PFS_socket_class *pfs_last= socket_class_array + socket_class_max;
+
+ for ( ; pfs < pfs_last; pfs++)
+ pfs->m_socket_stat.m_io_stat.reset();
}
-/** Reset the io statistics per file class. */
-void reset_file_class_io(void)
+void update_table_share_derived_flags(PFS_thread *thread)
{
- PFS_file_class *pfs= file_class_array;
- PFS_file_class *pfs_last= file_class_array + file_class_max;
+ PFS_table_share *pfs= table_share_array;
+ PFS_table_share *pfs_last= table_share_array + table_share_max;
for ( ; pfs < pfs_last; pfs++)
- reset_file_stat(&pfs->m_file_stat);
+ {
+ if (pfs->m_lock.is_populated())
+ pfs->refresh_setup_object_flags(thread);
+ }
}
/** @} */
diff --git a/storage/perfschema/pfs_instr_class.h b/storage/perfschema/pfs_instr_class.h
index 4e2f6d0d2a5..038814b07e2 100644
--- a/storage/perfschema/pfs_instr_class.h
+++ b/storage/perfschema/pfs_instr_class.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 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
@@ -16,7 +16,10 @@
#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
@@ -39,9 +42,13 @@
#define PFS_MAX_FULL_PREFIX_NAME_LENGTH 32
#include <my_global.h>
+#include <my_sys.h>
#include <mysql/psi/psi.h>
#include "pfs_lock.h"
#include "pfs_stat.h"
+#include "pfs_column_types.h"
+
+struct PFS_global_param;
/**
@addtogroup Performance_schema_buffers
@@ -49,6 +56,7 @@
*/
extern my_bool pfs_enabled;
+extern enum_timer_name *class_timers[];
/** Key, naming a synch instrument (mutex, rwlock, cond). */
typedef unsigned int PFS_sync_key;
@@ -56,76 +64,160 @@ typedef unsigned int PFS_sync_key;
typedef unsigned int PFS_thread_key;
/** Key, naming a file instrument. */
typedef unsigned int PFS_file_key;
+/** Key, naming a stage instrument. */
+typedef unsigned int PFS_stage_key;
+/** Key, naming a statement instrument. */
+typedef unsigned int PFS_statement_key;
+/** Key, naming a socket instrument. */
+typedef unsigned int PFS_socket_key;
+
+enum PFS_class_type
+{
+ PFS_CLASS_NONE= 0,
+ PFS_CLASS_MUTEX= 1,
+ PFS_CLASS_RWLOCK= 2,
+ PFS_CLASS_COND= 3,
+ PFS_CLASS_FILE= 4,
+ PFS_CLASS_TABLE= 5,
+ PFS_CLASS_STAGE= 6,
+ PFS_CLASS_STATEMENT= 7,
+ PFS_CLASS_SOCKET= 8,
+ PFS_CLASS_TABLE_IO= 9,
+ PFS_CLASS_TABLE_LOCK= 10,
+ PFS_CLASS_IDLE= 11,
+ PFS_CLASS_LAST= PFS_CLASS_IDLE,
+ PFS_CLASS_MAX= PFS_CLASS_LAST + 1
+};
+
+/** User-defined instrument configuration. */
+struct PFS_instr_config
+{
+ /* Instrument name. */
+ char *m_name;
+ /* Name length. */
+ uint m_name_length;
+ /** Enabled flag. */
+ bool m_enabled;
+ /** Timed flag. */
+ bool m_timed;
+};
+
+extern DYNAMIC_ARRAY pfs_instr_config_array;
+extern int pfs_instr_config_state;
+
+static const int PFS_INSTR_CONFIG_NOT_INITIALIZED= 0;
+static const int PFS_INSTR_CONFIG_ALLOCATED= 1;
+static const int PFS_INSTR_CONFIG_DEALLOCATED= 2;
struct PFS_thread;
+extern uint mutex_class_start;
+extern uint rwlock_class_start;
+extern uint cond_class_start;
+extern uint file_class_start;
+extern uint socket_class_start;
+extern uint wait_class_max;
+
/** Information for all instrumentation. */
struct PFS_instr_class
{
- /** Instrument name. */
- char m_name[PFS_MAX_INFO_NAME_LENGTH];
- /** Length in bytes of @c m_name. */
- uint m_name_length;
- /** Instrument flags. */
- int m_flags;
+ /** Class type */
+ PFS_class_type m_type;
/** True if this instrument is enabled. */
bool m_enabled;
/** True if this instrument is timed. */
bool m_timed;
- /** Wait statistics chain. */
- PFS_single_stat_chain m_wait_stat;
+ /** Instrument flags. */
+ int m_flags;
+ /**
+ Instrument name index.
+ Self index in:
+ - EVENTS_WAITS_SUMMARY_*_BY_EVENT_NAME for waits
+ - EVENTS_STAGES_SUMMARY_*_BY_EVENT_NAME for stages
+ - EVENTS_STATEMENTS_SUMMARY_*_BY_EVENT_NAME for statements
+ */
+ uint m_event_name_index;
+ /** Instrument name. */
+ char m_name[PFS_MAX_INFO_NAME_LENGTH];
+ /** Length in bytes of @c m_name. */
+ uint m_name_length;
+ /** Timer associated with this class. */
+ enum_timer_name *m_timer;
+
+ bool is_singleton() const
+ {
+ return m_flags & PSI_FLAG_GLOBAL;
+ }
+
+ bool is_mutable() const
+ {
+ return m_flags & PSI_FLAG_MUTABLE;
+ }
+
+ static void set_enabled(PFS_instr_class *pfs, bool enabled);
+ static void set_timed(PFS_instr_class *pfs, bool timed);
+
+ bool is_deferred() const
+ {
+ switch(m_type)
+ {
+ case PFS_CLASS_SOCKET:
+ return true;
+ break;
+ default:
+ return false;
+ break;
+ };
+ }
};
+struct PFS_mutex;
+
/** Instrumentation metadata for a MUTEX. */
-struct PFS_mutex_class : public PFS_instr_class
+struct PFS_ALIGNED PFS_mutex_class : public PFS_instr_class
{
- /**
- Lock statistics chain.
- This statistic is not exposed in user visible tables yet.
- */
- PFS_single_stat_chain m_lock_stat;
- /** Self index in @c mutex_class_array. */
- uint m_index;
+ /** 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_rwlock_class : public PFS_instr_class
+struct PFS_ALIGNED PFS_rwlock_class : public PFS_instr_class
{
- /**
- Read lock statistics chain.
- This statistic is not exposed in user visible tables yet.
- */
- PFS_single_stat_chain m_read_lock_stat;
- /**
- Write lock statistics chain.
- This statistic is not exposed in user visible tables yet.
- */
- PFS_single_stat_chain m_write_lock_stat;
- /** Self index in @c rwlock_class_array. */
- uint m_index;
+ /** 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_cond_class : public PFS_instr_class
+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;
- /** Self index in @c cond_class_array. */
- uint m_index;
+ /** Singleton instance. */
+ PFS_cond *m_singleton;
};
/** Instrumentation metadata of a thread. */
-struct PFS_thread_class
+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;
- /** True if this thread instrument is enabled. */
- bool m_enabled;
};
#define PFS_TABLESHARE_HASHKEY_SIZE (NAME_LEN + 1 + NAME_LEN + 1)
@@ -136,7 +228,7 @@ struct PFS_table_share_key
/**
Hash search key.
This has to be a string for LF_HASH,
- the format is "<schema_name><0x00><object_name><0x00>"
+ the format is "<enum_object_type><schema_name><0x00><object_name><0x00>"
@see create_table_def_key
*/
char m_hash_key[PFS_TABLESHARE_HASHKEY_SIZE];
@@ -144,11 +236,70 @@ struct PFS_table_share_key
uint m_key_length;
};
+/** Table index or 'key' */
+struct PFS_table_key
+{
+ /** Index name */
+ char m_name[NAME_LEN];
+ /** Length in bytes of @c m_name. */
+ uint m_name_length;
+};
+
/** Instrumentation metadata for a table share. */
-struct PFS_table_share
+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. */
@@ -159,32 +310,96 @@ struct PFS_table_share
const char *m_table_name;
/** Length in bytes of @c m_table_name. */
uint m_table_name_length;
- /** Wait statistics chain. */
- PFS_single_stat_chain m_wait_stat;
- /** True if this table instrument is enabled. */
- bool m_enabled;
- /** True if this table instrument is timed. */
- bool m_timed;
- /** True if this table instrument is aggregated. */
- bool m_aggregated;
+ /** Number of indexes. */
+ uint m_key_count;
+ /** Table statistics. */
+ PFS_table_stat m_table_stat;
+ /** Index names. */
+ PFS_table_key m_keys[MAX_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 tables.
- This instrument is used as a default when there is no
- entry present in SETUP_OBJECTS.
+ Instrument controlling all table lock.
+ This instrument is used with table SETUP_OBJECTS.
*/
-extern PFS_instr_class global_table_class;
+extern PFS_instr_class global_table_lock_class;
+
+/**
+ Instrument controlling all idle waits.
+*/
+extern PFS_instr_class global_idle_class;
+
+struct PFS_file;
/** Instrumentation metadata for a file. */
-struct PFS_file_class : public PFS_instr_class
+struct PFS_ALIGNED PFS_file_class : public PFS_instr_class
{
/** File usage statistics. */
PFS_file_stat m_file_stat;
- /** Self index in @c file_class_array. */
- uint m_index;
+ /** Singleton instance. */
+ PFS_file *m_singleton;
};
+/** Instrumentation metadata for a stage. */
+struct PFS_ALIGNED PFS_stage_class : public PFS_instr_class
+{
+ /**
+ Length of the 'stage/<component>/' prefix.
+ This is to extract 'foo' from 'stage/sql/foo'.
+ */
+ uint m_prefix_length;
+ /** 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);
@@ -198,6 +413,12 @@ int init_table_share_hash();
void cleanup_table_share_hash();
int init_file_class(uint file_class_sizing);
void cleanup_file_class();
+int init_stage_class(uint stage_class_sizing);
+void cleanup_stage_class();
+int init_statement_class(uint statement_class_sizing);
+void cleanup_statement_class();
+int init_socket_class(uint socket_class_sizing);
+void cleanup_socket_class();
PFS_sync_key register_mutex_class(const char *name, uint name_length,
int flags);
@@ -214,6 +435,17 @@ PFS_thread_key register_thread_class(const char *name, uint name_length,
PFS_file_key register_file_class(const char *name, uint name_length,
int flags);
+PFS_stage_key register_stage_class(const char *name,
+ uint prefix_length,
+ uint name_length,
+ int flags);
+
+PFS_statement_key register_statement_class(const char *name, uint name_length,
+ int flags);
+
+PFS_socket_key register_socket_class(const char *name, uint name_length,
+ int flags);
+
PFS_mutex_class *find_mutex_class(PSI_mutex_key key);
PFS_mutex_class *sanitize_mutex_class(PFS_mutex_class *unsafe);
PFS_rwlock_class *find_rwlock_class(PSI_rwlock_key key);
@@ -224,14 +456,25 @@ PFS_thread_class *find_thread_class(PSI_thread_key key);
PFS_thread_class *sanitize_thread_class(PFS_thread_class *unsafe);
PFS_file_class *find_file_class(PSI_file_key key);
PFS_file_class *sanitize_file_class(PFS_file_class *unsafe);
-const char *sanitize_table_schema_name(const char *unsafe);
-const char *sanitize_table_object_name(const char *unsafe);
+PFS_stage_class *find_stage_class(PSI_stage_key key);
+PFS_stage_class *sanitize_stage_class(PFS_stage_class *unsafe);
+PFS_statement_class *find_statement_class(PSI_statement_key key);
+PFS_statement_class *sanitize_statement_class(PFS_statement_class *unsafe);
+PFS_instr_class *find_table_class(uint index);
+PFS_instr_class *sanitize_table_class(PFS_instr_class *unsafe);
+PFS_socket_class *find_socket_class(PSI_socket_key key);
+PFS_socket_class *sanitize_socket_class(PFS_socket_class *unsafe);
+PFS_instr_class *find_idle_class(uint index);
+PFS_instr_class *sanitize_idle_class(PFS_instr_class *unsafe);
PFS_table_share *find_or_create_table_share(PFS_thread *thread,
- const char *schema_name,
- uint schema_name_length,
- const char *table_name,
- uint table_name_length);
+ bool temporary,
+ const TABLE_SHARE *share);
+void release_table_share(PFS_table_share *pfs);
+void drop_table_share(PFS_thread *thread,
+ bool temporary,
+ const char *schema_name, uint schema_name_length,
+ const char *table_name, uint table_name_length);
PFS_table_share *sanitize_table_share(PFS_table_share *unsafe);
@@ -245,12 +488,31 @@ extern ulong thread_class_max;
extern ulong thread_class_lost;
extern ulong file_class_max;
extern ulong file_class_lost;
+extern ulong stage_class_max;
+extern ulong stage_class_lost;
+extern ulong statement_class_max;
+extern ulong statement_class_lost;
+extern ulong socket_class_max;
+extern ulong socket_class_lost;
extern ulong table_share_max;
extern ulong table_share_lost;
+
+/* Exposing the data directly, for iterators. */
+
+extern PFS_mutex_class *mutex_class_array;
+extern PFS_rwlock_class *rwlock_class_array;
+extern PFS_cond_class *cond_class_array;
+extern PFS_file_class *file_class_array;
extern PFS_table_share *table_share_array;
-void reset_instrument_class_waits();
+void reset_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
index 8032a18a28f..4011cba2070 100644
--- a/storage/perfschema/pfs_lock.h
+++ b/storage/perfschema/pfs_lock.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@
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 0
+#define PFS_LOCK_FREE 0x00
/**
State of a dirty record.
Values of a dirty record should not be read by a reader,
@@ -41,14 +41,18 @@
Only one writer, the writer which owns the record, should
modify the record content.
*/
-#define PFS_LOCK_DIRTY 1
+#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 2
+#define PFS_LOCK_ALLOCATED 0x02
+
+#define VERSION_MASK 0xFFFFFFFC
+#define STATE_MASK 0x00000003
+#define VERSION_INC 4
/**
A 'lock' protecting performance schema internal buffers.
@@ -60,15 +64,11 @@
struct pfs_lock
{
/**
- The record internal state.
+ The record internal version and state
@sa PFS_LOCK_FREE
@sa PFS_LOCK_DIRTY
@sa PFS_LOCK_ALLOCATED
- */
- volatile int32 m_state;
- /**
- The record internal version number.
- This version number is to transform the 'ABA' problem
+ 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,
@@ -76,21 +76,23 @@ struct pfs_lock
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;
+ volatile uint32 m_version_state;
/** Returns true if the record is free. */
bool is_free(void)
{
- /* This is a dirty read */
- return (m_state == PFS_LOCK_FREE);
+ 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)
{
- int32 copy= m_state; /* non volatile copy, and dirty read */
- return (copy == PFS_LOCK_ALLOCATED);
+ uint32 copy= m_version_state; /* non volatile copy, and dirty read */
+ return ((copy & STATE_MASK) == PFS_LOCK_ALLOCATED);
}
/**
@@ -101,10 +103,27 @@ struct pfs_lock
*/
bool free_to_dirty(void)
{
- int32 old_state= PFS_LOCK_FREE;
- int32 new_state= PFS_LOCK_DIRTY;
+ 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_32(&m_state, &old_state, new_state));
+ 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);
}
/**
@@ -114,9 +133,38 @@ struct pfs_lock
*/
void dirty_to_allocated(void)
{
- DBUG_ASSERT(m_state == PFS_LOCK_DIRTY);
- PFS_atomic::add_u32(&m_version, 1);
- PFS_atomic::store_32(&m_state, PFS_LOCK_ALLOCATED);
+ 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);
+ }
+
+ /**
+ Initialize a lock to dirty.
+ */
+ void set_dirty(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 DIRTY state */
+ uint32 new_val= (copy & VERSION_MASK) + VERSION_INC + PFS_LOCK_DIRTY;
+ PFS_atomic::store_u32(&m_version_state, new_val);
}
/**
@@ -125,8 +173,12 @@ struct pfs_lock
*/
void dirty_to_free(void)
{
- DBUG_ASSERT(m_state == PFS_LOCK_DIRTY);
- PFS_atomic::store_32(&m_state, PFS_LOCK_FREE);
+ 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);
}
/**
@@ -142,8 +194,12 @@ struct pfs_lock
The correct assert to use here to guarantee data integrity is simply:
DBUG_ASSERT(m_state == PFS_LOCK_ALLOCATED);
*/
- DBUG_ASSERT(m_state == PFS_LOCK_ALLOCATED);
- PFS_atomic::store_32(&m_state, PFS_LOCK_FREE);
+ 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 FREE state */
+ uint32 new_val= (copy & VERSION_MASK) + PFS_LOCK_FREE;
+ PFS_atomic::store_u32(&m_version_state, new_val);
}
/**
@@ -152,8 +208,7 @@ struct pfs_lock
*/
void begin_optimistic_lock(struct pfs_lock *copy)
{
- copy->m_version= PFS_atomic::load_u32(&m_version);
- copy->m_state= PFS_atomic::load_32(&m_state);
+ copy->m_version_state= PFS_atomic::load_u32(&m_version_state);
}
/**
@@ -163,14 +218,20 @@ struct pfs_lock
*/
bool end_optimistic_lock(struct pfs_lock *copy)
{
- /*
- return true if:
- - the version + state has not changed
- - and there was valid data to look at
- */
- return ((copy->m_version == PFS_atomic::load_u32(&m_version)) &&
- (copy->m_state == PFS_atomic::load_32(&m_state)) &&
- (copy->m_state == PFS_LOCK_ALLOCATED));
+ /* 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);
}
};
diff --git a/storage/perfschema/pfs_server.cc b/storage/perfschema/pfs_server.cc
index 9372cf2a1b5..9dd6fbf4762 100644
--- a/storage/perfschema/pfs_server.cc
+++ b/storage/perfschema/pfs_server.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -27,21 +27,40 @@
#include "pfs_instr_class.h"
#include "pfs_instr.h"
#include "pfs_events_waits.h"
+#include "pfs_events_stages.h"
+#include "pfs_events_statements.h"
#include "pfs_timer.h"
+#include "pfs_setup_actor.h"
+#include "pfs_setup_object.h"
+#include "pfs_host.h"
+#include "pfs_user.h"
+#include "pfs_account.h"
+#include "pfs_defaults.h"
+#include "pfs_digest.h"
PFS_global_param pfs_param;
+PFS_table_stat PFS_table_stat::g_reset_template;
+
C_MODE_START
static void destroy_pfs_thread(void *key);
C_MODE_END
static void cleanup_performance_schema(void);
+void cleanup_instrument_config(void);
struct PSI_bootstrap*
-initialize_performance_schema(const PFS_global_param *param)
+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)
{
/*
@@ -52,7 +71,9 @@ initialize_performance_schema(const PFS_global_param *param)
}
init_timers();
- PFS_atomic::init();
+
+ init_event_name_sizing(param);
+ register_global_classes();
if (pthread_key_create(&THR_PFS, destroy_pfs_thread))
return NULL;
@@ -65,11 +86,30 @@ initialize_performance_schema(const PFS_global_param *param)
init_thread_class(param->m_thread_class_sizing) ||
init_table_share(param->m_table_share_sizing) ||
init_file_class(param->m_file_class_sizing) ||
+ init_stage_class(param->m_stage_class_sizing) ||
+ init_statement_class(param->m_statement_class_sizing) ||
+ init_socket_class(param->m_socket_class_sizing) ||
init_instruments(param) ||
init_events_waits_history_long(
param->m_events_waits_history_long_sizing) ||
+ init_events_stages_history_long(
+ param->m_events_stages_history_long_sizing) ||
+ init_events_statements_history_long(
+ param->m_events_statements_history_long_sizing) ||
init_file_hash() ||
- init_table_share_hash())
+ init_table_share_hash() ||
+ init_setup_actor(param) ||
+ init_setup_actor_hash() ||
+ init_setup_object(param) ||
+ init_setup_object_hash() ||
+ init_host(param) ||
+ init_host_hash() ||
+ init_user(param) ||
+ init_user_hash() ||
+ init_account(param) ||
+ init_account_hash() ||
+ init_digest(param) ||
+ init_digest_hash())
{
/*
The performance schema initialization failed.
@@ -80,6 +120,22 @@ initialize_performance_schema(const PFS_global_param *param)
}
pfs_initialized= true;
+
+ /** Default values for SETUP_CONSUMERS */
+ flag_events_stages_current= param->m_consumer_events_stages_current_enabled;
+ flag_events_stages_history= param->m_consumer_events_stages_history_enabled;
+ flag_events_stages_history_long= param->m_consumer_events_stages_history_long_enabled;
+ flag_events_statements_current= param->m_consumer_events_statements_current_enabled;
+ flag_events_statements_history= param->m_consumer_events_statements_history_enabled;
+ flag_events_statements_history_long= param->m_consumer_events_statements_history_long_enabled;
+ flag_events_waits_current= param->m_consumer_events_waits_current_enabled;
+ flag_events_waits_history= param->m_consumer_events_waits_history_enabled;
+ flag_events_waits_history_long= param->m_consumer_events_waits_history_long_enabled;
+ flag_global_instrumentation= param->m_consumer_global_instrumentation_enabled;
+ flag_thread_instrumentation= param->m_consumer_thread_instrumentation_enabled;
+ flag_statements_digest= param->m_consumer_statement_digest_enabled;
+
+ install_default_setup(&PFS_bootstrap);
return &PFS_bootstrap;
}
@@ -104,21 +160,39 @@ static void destroy_pfs_thread(void *key)
static void cleanup_performance_schema(void)
{
+ cleanup_instrument_config();
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();
- PFS_atomic::cleanup();
+ 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();
+ cleanup_digest_hash();
}
void shutdown_performance_schema(void)
{
pfs_initialized= false;
cleanup_performance_schema();
+#if 0
/*
Be careful to not delete un-initialized keys,
this would affect key 0, which is THR_KEY_mysys,
@@ -129,5 +203,100 @@ void shutdown_performance_schema(void)
pthread_key_delete(THR_PFS);
THR_PFS_initialized= false;
}
+#endif
}
+/**
+ Initialize the dynamic array used to hold PFS_INSTRUMENT configuration
+ options.
+*/
+void init_pfs_instrument_array()
+{
+ my_init_dynamic_array(&pfs_instr_config_array, sizeof(PFS_instr_config*),
+ 10, 10, MYF(0));
+ 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))
+ {
+ PFS_instr_config **array=dynamic_element(&pfs_instr_config_array, 0, PFS_instr_config**);
+ for (uint i=0; i < pfs_instr_config_array.elements; i++)
+ my_free(array[i]);
+ delete_dynamic(&pfs_instr_config_array);
+ }
+}
+
+/**
+ Process one performance_schema_instrument configuration string. Isolate the
+ instrument name, evaluate the option value, and store them in a dynamic array.
+ Return 'false' for success, 'true' for error.
+
+ @param name Instrument name
+ @param value Configuration option: 'on', 'off', etc.
+ @return 0 for success, non zero for errors
+*/
+
+int add_pfs_instr_to_array(const char* name, const char* value)
+{
+ int name_length= strlen(name);
+ int value_length= strlen(value);
+
+ /* Allocate structure plus string buffers plus null terminators */
+ PFS_instr_config* e = (PFS_instr_config*)my_malloc(sizeof(PFS_instr_config)
+ + name_length + 1 + value_length + 1, MYF(MY_WME));
+ if (!e) return 1;
+
+ /* Copy the instrument name */
+ e->m_name= (char*)e + sizeof(PFS_instr_config);
+ memcpy(e->m_name, name, name_length);
+ e->m_name_length= name_length;
+ e->m_name[name_length]= '\0';
+
+ /* Set flags accordingly */
+ if (!my_strcasecmp(&my_charset_latin1, value, "counted"))
+ {
+ e->m_enabled= true;
+ e->m_timed= false;
+ }
+ else
+ if (!my_strcasecmp(&my_charset_latin1, value, "true") ||
+ !my_strcasecmp(&my_charset_latin1, value, "on") ||
+ !my_strcasecmp(&my_charset_latin1, value, "1") ||
+ !my_strcasecmp(&my_charset_latin1, value, "yes"))
+ {
+ e->m_enabled= true;
+ e->m_timed= true;
+ }
+ else
+ if (!my_strcasecmp(&my_charset_latin1, value, "false") ||
+ !my_strcasecmp(&my_charset_latin1, value, "off") ||
+ !my_strcasecmp(&my_charset_latin1, value, "0") ||
+ !my_strcasecmp(&my_charset_latin1, value, "no"))
+ {
+ e->m_enabled= false;
+ e->m_timed= false;
+ }
+ else
+ {
+ my_free(e);
+ return 1;
+ }
+
+ /* Add to the array of default startup options */
+ if (insert_dynamic(&pfs_instr_config_array, &e))
+ {
+ my_free(e);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/storage/perfschema/pfs_server.h b/storage/perfschema/pfs_server.h
index fca0ad8b58e..aea86a576cc 100644
--- a/storage/perfschema/pfs_server.h
+++ b/storage/perfschema/pfs_server.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,78 +24,229 @@
#ifndef PFS_MAX_MUTEX_CLASS
#define PFS_MAX_MUTEX_CLASS 200
#endif
-#ifndef PFS_MAX_MUTEX
- #define PFS_MAX_MUTEX 1000000
-#endif
#ifndef PFS_MAX_RWLOCK_CLASS
- #define PFS_MAX_RWLOCK_CLASS 30
-#endif
-#ifndef PFS_MAX_RWLOCK
- #define PFS_MAX_RWLOCK 1000000
+ #define PFS_MAX_RWLOCK_CLASS 40
#endif
#ifndef PFS_MAX_COND_CLASS
#define PFS_MAX_COND_CLASS 80
#endif
-#ifndef PFS_MAX_COND
- #define PFS_MAX_COND 1000
-#endif
#ifndef PFS_MAX_THREAD_CLASS
#define PFS_MAX_THREAD_CLASS 50
#endif
-#ifndef PFS_MAX_THREAD
- #define PFS_MAX_THREAD 1000
-#endif
#ifndef PFS_MAX_FILE_CLASS
#define PFS_MAX_FILE_CLASS 50
#endif
-#ifndef PFS_MAX_FILE
- #define PFS_MAX_FILE 10000
-#endif
#ifndef PFS_MAX_FILE_HANDLE
#define PFS_MAX_FILE_HANDLE 32768
#endif
-#ifndef PFS_MAX_TABLE_SHARE
- #define PFS_MAX_TABLE_SHARE 50000
+#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_TABLE
- #define PFS_MAX_TABLE 100000
+#ifndef PFS_MAX_STAGE_CLASS
+ #define PFS_MAX_STAGE_CLASS 150
#endif
-#ifndef PFS_WAITS_HISTORY_SIZE
- #define PFS_WAITS_HISTORY_SIZE 10
+#ifndef PFS_STATEMENTS_STACK_SIZE
+ #define PFS_STATEMENTS_STACK_SIZE 10
#endif
-#ifndef PFS_WAITS_HISTORY_LONG_SIZE
- #define PFS_WAITS_HISTORY_LONG_SIZE 10000
+#ifndef PFS_CONNECT_ATTRS_SIZE
+ #define PFS_SESSION_CONNECT_ATTRS_SIZE 2048
#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;
- ulong m_table_share_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;
- ulong m_mutex_sizing;
- ulong m_rwlock_sizing;
- ulong m_cond_sizing;
- ulong m_thread_sizing;
- ulong m_table_sizing;
- ulong m_file_sizing;
- ulong m_file_handle_sizing;
- ulong m_events_waits_history_sizing;
- ulong m_events_waits_history_long_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;
+
+ long m_max_digest_length;
+
+ /** 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(const PFS_global_param *param);
+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..f3b6bc1791f
--- /dev/null
+++ b/storage/perfschema/pfs_setup_actor.cc
@@ -0,0 +1,337 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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, sizeof(PFS_setup_actor),
+ 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..92a1617c304
--- /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, Fifth Floor, 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..3cc14d9a14e
--- /dev/null
+++ b/storage/perfschema/pfs_setup_object.cc
@@ -0,0 +1,345 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 Street, Fifth Floor, Boston, MA 02110-1335 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, sizeof(PFS_setup_object),
+ 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)
+ {
+ setup_object_hash_inited= false;
+ lf_hash_destroy(&setup_object_hash);
+ }
+}
+
+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..0d343f552b2
--- /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-1335 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
index f29285e84d9..9e4da7957f6 100644
--- a/storage/perfschema/pfs_stat.h
+++ b/storage/perfschema/pfs_stat.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 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
@@ -16,6 +16,10 @@
#ifndef PFS_STAT_H
#define PFS_STAT_H
+#include "sql_const.h"
+/* memcpy */
+#include "string.h"
+
/**
@file storage/perfschema/pfs_stat.h
Statistics (declarations).
@@ -26,16 +30,9 @@
@{
*/
-/** Usage statistics chain, for a single value and its aggregates. */
-struct PFS_single_stat_chain
+/** Single statistic. */
+struct PFS_single_stat
{
- /**
- Control flag.
- Statistics are aggregated only if the control flag is true.
- */
- bool *m_control_flag;
- /** Next link in the statistics chain. */
- struct PFS_single_stat_chain *m_parent;
/** Count of values. */
ulonglong m_count;
/** Sum of values. */
@@ -44,68 +41,235 @@ struct PFS_single_stat_chain
ulonglong m_min;
/** Maximum value. */
ulonglong m_max;
+
+ PFS_single_stat()
+ {
+ m_count= 0;
+ m_sum= 0;
+ m_min= ULONGLONG_MAX;
+ m_max= 0;
+ }
+
+ inline void reset(void)
+ {
+ m_count= 0;
+ m_sum= 0;
+ m_min= ULONGLONG_MAX;
+ m_max= 0;
+ }
+
+ inline bool has_timed_stats() const
+ {
+ return (m_min <= m_max);
+ }
+
+ inline void aggregate(const PFS_single_stat *stat)
+ {
+ m_count+= stat->m_count;
+ m_sum+= stat->m_sum;
+ if (unlikely(m_min > stat->m_min))
+ m_min= stat->m_min;
+ if (unlikely(m_max < stat->m_max))
+ m_max= stat->m_max;
+ }
+
+ inline void aggregate_counted()
+ {
+ m_count++;
+ }
+
+ inline void aggregate_counted(ulonglong count)
+ {
+ m_count+= count;
+ }
+
+ inline void aggregate_value(ulonglong value)
+ {
+ m_count++;
+ m_sum+= value;
+ if (unlikely(m_min > value))
+ m_min= value;
+ if (unlikely(m_max < value))
+ m_max= value;
+ }
};
-/**
- Reset a single statistic link.
- Only the current link is reset, parents are not affected.
- @param stat the statistics link to reset
-*/
-inline void reset_single_stat_link(PFS_single_stat_chain *stat)
+/** Combined statistic. */
+struct PFS_byte_stat : public PFS_single_stat
{
- stat->m_count= 0;
- stat->m_sum= 0;
- stat->m_min= ULONGLONG_MAX;
- stat->m_max= 0;
-}
+ /** Byte count statistics */
+ ulonglong m_bytes;
-/**
- Aggregate a value to a statistic chain.
- @param stat the aggregated statistic chain
- @param value the value to aggregate
-*/
-inline void aggregate_single_stat_chain(PFS_single_stat_chain *stat,
- ulonglong value)
+ /* 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
{
- do
+ /** 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)
{
- if (*stat->m_control_flag)
- {
- stat->m_count++;
- stat->m_sum+= value;
- if (stat->m_min > value)
- stat->m_min= value;
- if (stat->m_max < value)
- stat->m_max= value;
- }
- stat= stat->m_parent;
+ m_wait_stat.aggregate(&stat->m_wait_stat);
+ m_lock_stat.aggregate(&stat->m_lock_stat);
}
- while (stat);
-}
-/**
- Increment the value counts in a statistic chain.
- Used for instruments that are 'ENABLED' but not 'TIMED'.
- @param stat the aggregated statistic chain
-*/
-inline void increment_single_stat_chain(PFS_single_stat_chain *stat)
+ inline void reset(void)
+ {
+ m_wait_stat.reset();
+ m_lock_stat.reset();
+ }
+};
+
+/** Statistics for rwlock usage. */
+struct PFS_rwlock_stat
{
- do
+ /** 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)
{
- if (*stat->m_control_flag)
- stat->m_count++;
- stat= stat->m_parent;
+ 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);
}
- while (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
{
- /** Number of times a condition was signalled. */
+ /** 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 broadcasted. */
+ /**
+ 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. */
@@ -113,28 +277,434 @@ struct PFS_file_stat
{
/** Number of current open handles. */
ulong m_open_count;
- /** Count of READ operations. */
- ulonglong m_count_read;
- /** Count of WRITE operations. */
- ulonglong m_count_write;
- /** Number of bytes read. */
- ulonglong m_read_bytes;
- /** Number of bytes written. */
- ulonglong m_write_bytes;
+ /** File IO statistics. */
+ PFS_file_io_stat m_io_stat;
+
+ 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();
+ }
};
-/**
- Reset file statistic.
- @param stat the statistics to reset
-*/
-inline void reset_file_stat(PFS_file_stat *stat)
-{
- stat->m_open_count= 0;
- stat->m_count_read= 0;
- stat->m_count_write= 0;
- stat->m_read_bytes= 0;
- stat->m_write_bytes= 0;
-}
+/** 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
index 82ef84939fe..5e2c27c217b 100644
--- a/storage/perfschema/pfs_timer.cc
+++ b/storage/perfschema/pfs_timer.cc
@@ -22,8 +22,10 @@
#include "pfs_timer.h"
#include "my_rdtsc.h"
+enum_timer_name idle_timer= TIMER_NAME_MICROSEC;
enum_timer_name wait_timer= TIMER_NAME_CYCLE;
-MY_TIMER_INFO pfs_timer_info;
+enum_timer_name stage_timer= TIMER_NAME_NANOSEC;
+enum_timer_name statement_timer= TIMER_NAME_NANOSEC;
static ulonglong cycle_v0;
static ulonglong nanosec_v0;
@@ -37,6 +39,17 @@ static ulong microsec_to_pico; /* In theory, 1 000 000 */
static ulong millisec_to_pico; /* In theory, 1 000 000 000, fits in uint32 */
static ulonglong tick_to_pico; /* 1e10 at 100 Hz, 1.666e10 at 60 Hz */
+/* Indexed by enum enum_timer_name */
+static struct time_normalizer to_pico_data[FIRST_TIMER_NAME + COUNT_TIMER_NAME]=
+{
+ { 0, 0}, /* unused */
+ { 0, 0}, /* cycle */
+ { 0, 0}, /* nanosec */
+ { 0, 0}, /* microsec */
+ { 0, 0}, /* millisec */
+ { 0, 0} /* tick */
+};
+
static inline ulong round_to_ulong(double value)
{
return (ulong) (value + 0.5);
@@ -51,47 +64,61 @@ 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)
+ if (sys_timer_info.cycles.frequency > 0)
cycle_to_pico= round_to_ulong(pico_frequency/
- (double)pfs_timer_info.cycles.frequency);
+ (double)sys_timer_info.cycles.frequency);
else
cycle_to_pico= 0;
- if (pfs_timer_info.nanoseconds.frequency > 0)
+ if (sys_timer_info.nanoseconds.frequency > 0)
nanosec_to_pico= round_to_ulong(pico_frequency/
- (double)pfs_timer_info.nanoseconds.frequency);
+ (double)sys_timer_info.nanoseconds.frequency);
else
nanosec_to_pico= 0;
- if (pfs_timer_info.microseconds.frequency > 0)
+ if (sys_timer_info.microseconds.frequency > 0)
microsec_to_pico= round_to_ulong(pico_frequency/
- (double)pfs_timer_info.microseconds.frequency);
+ (double)sys_timer_info.microseconds.frequency);
else
microsec_to_pico= 0;
- if (pfs_timer_info.milliseconds.frequency > 0)
+ if (sys_timer_info.milliseconds.frequency > 0)
millisec_to_pico= round_to_ulong(pico_frequency/
- (double)pfs_timer_info.milliseconds.frequency);
+ (double)sys_timer_info.milliseconds.frequency);
else
millisec_to_pico= 0;
- if (pfs_timer_info.ticks.frequency > 0)
+ if (sys_timer_info.ticks.frequency > 0)
tick_to_pico= round_to_ulonglong(pico_frequency/
- (double)pfs_timer_info.ticks.frequency);
+ (double)sys_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.
+ Depending on the platform and build options,
+ some timers may not be available.
+ Pick best replacements.
*/
/*
@@ -100,6 +127,7 @@ void init_timers(void)
unlikely that neither cycle nor nanosecond are available, but we continue
probing less resolution timers anyway for consistency with other events.
*/
+
if (cycle_to_pico != 0)
{
/* Normal case. */
@@ -128,13 +156,123 @@ void init_timers(void)
*/
wait_timer= TIMER_NAME_TICK;
}
+
+ /*
+ 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. */
+ wait_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_value(enum_timer_name timer_name)
+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) {
+ switch (timer_name)
+ {
case TIMER_NAME_CYCLE:
result= (my_timer_cycles() - cycle_v0) * cycle_to_pico;
break;
@@ -157,3 +295,38 @@ ulonglong get_timer_value(enum_timer_name timer_name)
return result;
}
+time_normalizer* time_normalizer::get(enum_timer_name timer_name)
+{
+ uint index= static_cast<uint> (timer_name);
+
+ DBUG_ASSERT(index >= FIRST_TIMER_NAME);
+ DBUG_ASSERT(index <= LAST_TIMER_NAME);
+
+ return & to_pico_data[index];
+}
+
+void time_normalizer::to_pico(ulonglong start, ulonglong end,
+ ulonglong *pico_start, ulonglong *pico_end, ulonglong *pico_wait)
+{
+ if (start == 0)
+ {
+ *pico_start= 0;
+ *pico_end= 0;
+ *pico_wait= 0;
+ }
+ else
+ {
+ *pico_start= (start - m_v0) * m_factor;
+ if (end == 0)
+ {
+ *pico_end= 0;
+ *pico_wait= 0;
+ }
+ else
+ {
+ *pico_end= (end - m_v0) * m_factor;
+ *pico_wait= (end - start) * m_factor;
+ }
+ }
+}
+
diff --git a/storage/perfschema/pfs_timer.h b/storage/perfschema/pfs_timer.h
index d24b3b26e25..a4f55c20994 100644
--- a/storage/perfschema/pfs_timer.h
+++ b/storage/perfschema/pfs_timer.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc.
- Use is subject to license terms.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,12 +23,118 @@
#include <my_rdtsc.h>
#include "pfs_column_types.h"
+/** Conversion factor, from micro seconds to pico seconds. */
+#define MICROSEC_TO_PICOSEC 1000000
+
+/**
+ A time normalizer.
+ A time normalizer consist of a transformation that
+ converts raw timer values (expressed in the timer unit)
+ to normalized values, expressed in picoseconds.
+*/
+struct time_normalizer
+{
+ /**
+ Get a time normalizer for a given timer.
+ @param timer_name the timer name
+ @return the normalizer for the timer
+ */
+ static time_normalizer* get(enum_timer_name timer_name);
+
+ /** Timer value at server statup. */
+ ulonglong m_v0;
+ /** Conversion factor from timer values to pico seconds. */
+ ulonglong m_factor;
+
+ /**
+ Convert a wait from timer units to pico seconds.
+ @param wait a wait, expressed in timer units
+ @return the wait, expressed in pico seconds
+ */
+ inline ulonglong wait_to_pico(ulonglong wait)
+ {
+ return wait * m_factor;
+ }
+
+ /**
+ Convert a time from timer units to pico seconds.
+ @param t a time, expressed in timer units
+ @return the time, expressed in pico seconds
+ */
+ inline ulonglong time_to_pico(ulonglong t)
+ {
+ return (t == 0 ? 0 : (t - m_v0) * m_factor);
+ }
+
+ /**
+ Convert start / end times from timer units to pico seconds.
+ @param start start time, expressed in timer units
+ @param end end time, expressed in timer units
+ @param[out] pico_start start time, expressed in pico seconds
+ @param[out] pico_end end time, expressed in pico seconds
+ @param[out] pico_wait wait time, expressed in pico seconds
+ */
+ void to_pico(ulonglong start, ulonglong end,
+ ulonglong *pico_start, ulonglong *pico_end, ulonglong *pico_wait);
+};
+
+/**
+ Idle timer.
+ The timer used to measure all idle events.
+*/
+extern enum_timer_name idle_timer;
+/**
+ Wait timer.
+ The timer used to measure all wait events.
+*/
extern enum_timer_name wait_timer;
-extern MY_TIMER_INFO pfs_timer_info;
+/**
+ 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 MYSQL_PLUGIN_IMPORT MY_TIMER_INFO sys_timer_info;
+/** Initialize the timer component. */
void init_timers();
-ulonglong get_timer_value(enum_timer_name timer_name);
+extern "C"
+{
+ /** A timer function. */
+ typedef ulonglong (*timer_fct_t)(void);
+}
+
+/**
+ Get a timer value, in pico seconds.
+ @param timer_name the timer to use
+ @return timer value, in pico seconds
+*/
+ulonglong get_timer_pico_value(enum_timer_name timer_name);
+/**
+ Get a timer value, in timer units.
+ @param timer_name the timer to use
+ @return timer value, in timer units
+*/
+ulonglong get_timer_raw_value(enum_timer_name timer_name);
+/**
+ Get a timer value and function, in timer units.
+ This function is useful when code needs to call the same timer several times.
+ The returned timer function can be invoked directly, which avoids having to
+ resolve the timer by name for each call.
+ @param timer_name the timer to use
+ @param[out] fct the timer function
+ @return timer value, in timer units
+*/
+ulonglong get_timer_raw_value_and_function(enum_timer_name timer_name, timer_fct_t *fct);
#endif
diff --git a/storage/perfschema/pfs_user.cc b/storage/perfschema/pfs_user.cc
new file mode 100644
index 00000000000..f9f6782cd75
--- /dev/null
+++ b/storage/perfschema/pfs_user.cc
@@ -0,0 +1,382 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 Street, Fifth Floor, Boston, MA 02110-1335 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, sizeof(PFS_user), 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))
+ {
+ DBUG_ASSERT(*entry == user);
+ if (user->get_refcount() == 0)
+ {
+ lf_hash_delete(&user_hash, pins,
+ user->m_key.m_hash_key, user->m_key.m_key_length);
+ user->m_lock.allocated_to_free();
+ }
+ }
+
+ lf_hash_search_unpin(pins);
+}
+
+/** Purge non connected users, reset stats of connected users. */
+void purge_all_user(void)
+{
+ PFS_thread *thread= PFS_thread::get_current_thread();
+ if (unlikely(thread == NULL))
+ return;
+
+ PFS_user *pfs= user_array;
+ PFS_user *pfs_last= user_array + user_max;
+
+ for ( ; pfs < pfs_last; pfs++)
+ {
+ if (pfs->m_lock.is_populated())
+ {
+ pfs->aggregate();
+ if (pfs->get_refcount() == 0)
+ purge_user(thread, pfs);
+ }
+ }
+}
+
+/** @} */
diff --git a/storage/perfschema/pfs_user.h b/storage/perfschema/pfs_user.h
new file mode 100644
index 00000000000..f2b1c4409c7
--- /dev/null
+++ b/storage/perfschema/pfs_user.h
@@ -0,0 +1,115 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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..3df7ef91bb3
--- /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, Fifth Floor, 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..c3ada2f4e0b
--- /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, Fifth Floor, 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..007fcb25550
--- /dev/null
+++ b/storage/perfschema/table_accounts.cc
@@ -0,0 +1,123 @@
+/* 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, Fifth Floor, 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE accounts("
+ "USER CHAR(16) collate utf8_bin default null,"
+ "HOST CHAR(60) collate utf8_bin default null,"
+ "CURRENT_CONNECTIONS bigint not null,"
+ "TOTAL_CONNECTIONS bigint not null)") }
+};
+
+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..f72eb39ed39
--- /dev/null
+++ b/storage/perfschema/table_accounts.h
@@ -0,0 +1,78 @@
+/* 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, Fifth Floor, 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;
+
+ /** Current row. */
+ row_accounts m_row;
+ /** True if the current row exists. */
+ bool m_row_exists;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_all_instr.cc b/storage/perfschema/table_all_instr.cc
index 4b26bd54523..05ec9f09c11 100644
--- a/storage/perfschema/table_all_instr.cc
+++ b/storage/perfschema/table_all_instr.cc
@@ -40,6 +40,7 @@ int table_all_instr::rnd_next(void)
PFS_rwlock *rwlock;
PFS_cond *cond;
PFS_file *file;
+ PFS_socket *socket;
for (m_pos.set_at(&m_next_pos);
m_pos.has_more_view();
@@ -94,6 +95,18 @@ int table_all_instr::rnd_next(void)
}
}
break;
+ case pos_all_instr::VIEW_SOCKET:
+ for ( ; m_pos.m_index_2 < socket_max; m_pos.m_index_2++)
+ {
+ socket= &socket_array[m_pos.m_index_2];
+ if (socket->m_lock.is_populated())
+ {
+ make_socket_row(socket);
+ m_next_pos.set_after(&m_pos);
+ return 0;
+ }
+ }
+ break;
}
}
@@ -106,6 +119,7 @@ int table_all_instr::rnd_pos(const void *pos)
PFS_rwlock *rwlock;
PFS_cond *cond;
PFS_file *file;
+ PFS_socket *socket;
set_position(pos);
@@ -146,115 +160,12 @@ int table_all_instr::rnd_pos(const void *pos)
return 0;
}
break;
- }
-
- return HA_ERR_RECORD_DELETED;
-}
-
-table_all_instr_class::table_all_instr_class
-(const PFS_engine_table_share *share)
- : PFS_engine_table(share, &m_pos),
- m_pos(), m_next_pos()
-{}
-
-void table_all_instr_class::reset_position(void)
-{
- m_pos.reset();
- m_next_pos.reset();
-}
-
-int table_all_instr_class::rnd_next(void)
-{
- PFS_mutex_class *mutex_class;
- PFS_rwlock_class *rwlock_class;
- PFS_cond_class *cond_class;
- PFS_file_class *file_class;
-
- for (m_pos.set_at(&m_next_pos);
- m_pos.has_more_view();
- m_pos.next_view())
- {
- switch (m_pos.m_index_1) {
- case pos_all_instr_class::VIEW_MUTEX:
- mutex_class= find_mutex_class(m_pos.m_index_2);
- if (mutex_class)
- {
- make_instr_row(mutex_class);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
- break;
- case pos_all_instr_class::VIEW_RWLOCK:
- rwlock_class= find_rwlock_class(m_pos.m_index_2);
- if (rwlock_class)
- {
- make_instr_row(rwlock_class);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
- break;
- case pos_all_instr_class::VIEW_COND:
- cond_class= find_cond_class(m_pos.m_index_2);
- if (cond_class)
- {
- make_instr_row(cond_class);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
- break;
- case pos_all_instr_class::VIEW_FILE:
- file_class= find_file_class(m_pos.m_index_2);
- if (file_class)
- {
- make_instr_row(file_class);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
- break;
- }
- }
-
- return HA_ERR_END_OF_FILE;
-}
-
-int table_all_instr_class::rnd_pos(const void *pos)
-{
- PFS_mutex_class *mutex_class;
- PFS_rwlock_class *rwlock_class;
- PFS_cond_class *cond_class;
- PFS_file_class *file_class;
-
- set_position(pos);
- switch (m_pos.m_index_1) {
- case pos_all_instr_class::VIEW_MUTEX:
- mutex_class= find_mutex_class(m_pos.m_index_2);
- if (mutex_class)
- {
- make_instr_row(mutex_class);
- return 0;
- }
- break;
- case pos_all_instr_class::VIEW_RWLOCK:
- rwlock_class= find_rwlock_class(m_pos.m_index_2);
- if (rwlock_class)
+ case pos_all_instr::VIEW_SOCKET:
+ DBUG_ASSERT(m_pos.m_index_2 < socket_max);
+ socket= &socket_array[m_pos.m_index_2];
+ if (socket->m_lock.is_populated())
{
- make_instr_row(rwlock_class);
- return 0;
- }
- break;
- case pos_all_instr_class::VIEW_COND:
- cond_class= find_cond_class(m_pos.m_index_2);
- if (cond_class)
- {
- make_instr_row(cond_class);
- return 0;
- }
- break;
- case pos_all_instr_class::VIEW_FILE:
- file_class= find_file_class(m_pos.m_index_2);
- if (file_class)
- {
- make_instr_row(file_class);
+ make_socket_row(socket);
return 0;
}
break;
@@ -262,4 +173,3 @@ int table_all_instr_class::rnd_pos(const void *pos)
return HA_ERR_RECORD_DELETED;
}
-
diff --git a/storage/perfschema/table_all_instr.h b/storage/perfschema/table_all_instr.h
index 9aa7b02d860..7c9d5d9b0d6 100644
--- a/storage/perfschema/table_all_instr.h
+++ b/storage/perfschema/table_all_instr.h
@@ -24,88 +24,29 @@
#include "pfs_instr_class.h"
#include "pfs_instr.h"
#include "pfs_engine_table.h"
+#include "table_helper.h"
/**
@addtogroup Performance_schema_tables
@{
*/
-/** Position of a cursor on table_all_instr_class. */
-struct pos_all_instr_class : public PFS_double_index,
- public PFS_instrument_view_constants
-{
- pos_all_instr_class()
- : PFS_double_index(VIEW_MUTEX, 1)
- {}
-
- inline void reset(void)
- {
- m_index_1= VIEW_MUTEX;
- m_index_2= 1;
- }
-
- inline bool has_more_view(void)
- { return (m_index_1 <= VIEW_FILE); }
-
- inline void next_view(void)
- {
- m_index_1++;
- /* Instrument keys start at 1, not 0. */
- m_index_2= 1;
- }
-};
-
-/**
- Abstract table, a union of all instrumentations class metadata.
- This table is a union of:
- - a view on all mutex classes,
- - a view on all rwlock classes,
- - a view on all cond classes,
- - a view on all file classes
-*/
-class table_all_instr_class : public PFS_engine_table
-{
-public:
- virtual int rnd_next();
- virtual int rnd_pos(const void *pos);
- virtual void reset_position(void);
-
-protected:
- table_all_instr_class(const PFS_engine_table_share *share);
-
-public:
- ~table_all_instr_class()
- {}
-
-protected:
- /**
- Build a row.
- @param klass the instrument class
- */
- virtual void make_instr_row(PFS_instr_class *klass)= 0;
-
- /** Current position. */
- pos_all_instr_class m_pos;
- /** Next position. */
- pos_all_instr_class m_next_pos;
-};
-
/** Position of a cursor on table_all_instr. */
struct pos_all_instr : public PFS_double_index,
public PFS_instrument_view_constants
{
pos_all_instr()
- : PFS_double_index(VIEW_MUTEX, 0)
+ : PFS_double_index(FIRST_VIEW, 0)
{}
inline void reset(void)
{
- m_index_1= VIEW_MUTEX;
+ m_index_1= FIRST_VIEW;
m_index_2= 0;
}
inline bool has_more_view(void)
- { return (m_index_1 <= VIEW_FILE); }
+ { return (m_index_1 <= LAST_VIEW); }
inline void next_view(void)
{
@@ -120,7 +61,8 @@ struct pos_all_instr : public PFS_double_index,
- a view on all mutex instances,
- a view on all rwlock instances,
- a view on all cond instances,
- - a view on all file instances
+ - a view on all file instances,
+ - a view on all socket instances
*/
class table_all_instr : public PFS_engine_table
{
@@ -157,6 +99,11 @@ protected:
@param pfs the file instance
*/
virtual void make_file_row(PFS_file *pfs)= 0;
+ /**
+ Build a row in the socket instance view.
+ @param pfs the socket instance
+ */
+ virtual void make_socket_row(PFS_socket *pfs)= 0;
/** Current position. */
pos_all_instr m_pos;
diff --git a/storage/perfschema/table_esgs_by_account_by_event_name.cc b/storage/perfschema/table_esgs_by_account_by_event_name.cc
new file mode 100644
index 00000000000..3bc76f899ad
--- /dev/null
+++ b/storage/perfschema/table_esgs_by_account_by_event_name.cc
@@ -0,0 +1,192 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_stages_summary_by_account_by_event_name("
+ "USER CHAR(16) collate utf8_bin default null,"
+ "HOST CHAR(60) collate utf8_bin default null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null)") }
+};
+
+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..5afd68cd7d9
--- /dev/null
+++ b/storage/perfschema/table_esgs_by_account_by_event_name.h
@@ -0,0 +1,123 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** 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..bbef6a8d16d
--- /dev/null
+++ b/storage/perfschema/table_esgs_by_host_by_event_name.cc
@@ -0,0 +1,192 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_stages_summary_by_host_by_event_name("
+ "HOST CHAR(60) collate utf8_bin default null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null)") }
+};
+
+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..afc6d529428
--- /dev/null
+++ b/storage/perfschema/table_esgs_by_host_by_event_name.h
@@ -0,0 +1,123 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** 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..57ef634acad
--- /dev/null
+++ b/storage/perfschema/table_esgs_by_thread_by_event_name.cc
@@ -0,0 +1,192 @@
+/* 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-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_stages_summary_by_thread_by_event_name("
+ "THREAD_ID BIGINT unsigned not null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null)") }
+};
+
+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..7db8d1be408
--- /dev/null
+++ b/storage/perfschema/table_esgs_by_thread_by_event_name.h
@@ -0,0 +1,127 @@
+/* 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-1335 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;
+
+ /** 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..f8e8518bde3
--- /dev/null
+++ b/storage/perfschema/table_esgs_by_user_by_event_name.cc
@@ -0,0 +1,192 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_stages_summary_by_user_by_event_name("
+ "USER CHAR(16) collate utf8_bin default null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null)") }
+};
+
+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..8f48747c8c8
--- /dev/null
+++ b/storage/perfschema/table_esgs_by_user_by_event_name.h
@@ -0,0 +1,128 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** 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..83a4dbf43fd
--- /dev/null
+++ b/storage/perfschema/table_esgs_global_by_event_name.cc
@@ -0,0 +1,174 @@
+/* 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-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_stages_summary_global_by_event_name("
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null)") }
+};
+
+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..2b0ac8b6218
--- /dev/null
+++ b/storage/perfschema/table_esgs_global_by_event_name.h
@@ -0,0 +1,91 @@
+/* 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-1335 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;
+
+ /** 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..d8f04d7af23
--- /dev/null
+++ b/storage/perfschema/table_esms_by_account_by_event_name.cc
@@ -0,0 +1,214 @@
+/* Copyright (c) 2010, 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_by_account_by_event_name("
+ "USER CHAR(16) collate utf8_bin default null,"
+ "HOST CHAR(60) collate utf8_bin default null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "SUM_LOCK_TIME BIGINT unsigned not null,"
+ "SUM_ERRORS BIGINT unsigned not null,"
+ "SUM_WARNINGS BIGINT unsigned not null,"
+ "SUM_ROWS_AFFECTED BIGINT unsigned not null,"
+ "SUM_ROWS_SENT BIGINT unsigned not null,"
+ "SUM_ROWS_EXAMINED BIGINT unsigned not null,"
+ "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null,"
+ "SUM_CREATED_TMP_TABLES BIGINT unsigned not null,"
+ "SUM_SELECT_FULL_JOIN BIGINT unsigned not null,"
+ "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null,"
+ "SUM_SELECT_RANGE BIGINT unsigned not null,"
+ "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null,"
+ "SUM_SELECT_SCAN BIGINT unsigned not null,"
+ "SUM_SORT_MERGE_PASSES BIGINT unsigned not null,"
+ "SUM_SORT_RANGE BIGINT unsigned not null,"
+ "SUM_SORT_ROWS BIGINT unsigned not null,"
+ "SUM_SORT_SCAN BIGINT unsigned not null,"
+ "SUM_NO_INDEX_USED BIGINT unsigned not null,"
+ "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") }
+};
+
+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;
+
+ if (klass->is_mutable())
+ return;
+
+ 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..ff212291760
--- /dev/null
+++ b/storage/perfschema/table_esms_by_account_by_event_name.h
@@ -0,0 +1,123 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** 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..ae648378b2a
--- /dev/null
+++ b/storage/perfschema/table_esms_by_digest.cc
@@ -0,0 +1,212 @@
+/* Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_by_digest("
+ "SCHEMA_NAME VARCHAR(64),"
+ "DIGEST VARCHAR(32),"
+ "DIGEST_TEXT LONGTEXT,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "SUM_LOCK_TIME BIGINT unsigned not null,"
+ "SUM_ERRORS BIGINT unsigned not null,"
+ "SUM_WARNINGS BIGINT unsigned not null,"
+ "SUM_ROWS_AFFECTED BIGINT unsigned not null,"
+ "SUM_ROWS_SENT BIGINT unsigned not null,"
+ "SUM_ROWS_EXAMINED BIGINT unsigned not null,"
+ "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null,"
+ "SUM_CREATED_TMP_TABLES BIGINT unsigned not null,"
+ "SUM_SELECT_FULL_JOIN BIGINT unsigned not null,"
+ "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null,"
+ "SUM_SELECT_RANGE BIGINT unsigned not null,"
+ "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null,"
+ "SUM_SELECT_SCAN BIGINT unsigned not null,"
+ "SUM_SORT_MERGE_PASSES BIGINT unsigned not null,"
+ "SUM_SORT_RANGE BIGINT unsigned not null,"
+ "SUM_SORT_ROWS BIGINT unsigned not null,"
+ "SUM_SORT_SCAN BIGINT unsigned not null,"
+ "SUM_NO_INDEX_USED BIGINT unsigned not null,"
+ "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null,"
+ "FIRST_SEEN TIMESTAMP(0) NOT NULL default 0,"
+ "LAST_SEEN TIMESTAMP(0) NOT NULL default 0)") }
+};
+
+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_lock.is_populated())
+ {
+ 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_lock.is_populated())
+ {
+ 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..682dc70ab10
--- /dev/null
+++ b/storage/perfschema/table_esms_by_digest.h
@@ -0,0 +1,93 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** 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..7233b340bd2
--- /dev/null
+++ b/storage/perfschema/table_esms_by_host_by_event_name.cc
@@ -0,0 +1,214 @@
+/* Copyright (c) 2010, 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_by_host_by_event_name("
+ "HOST CHAR(60) collate utf8_bin default null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "SUM_LOCK_TIME BIGINT unsigned not null,"
+ "SUM_ERRORS BIGINT unsigned not null,"
+ "SUM_WARNINGS BIGINT unsigned not null,"
+ "SUM_ROWS_AFFECTED BIGINT unsigned not null,"
+ "SUM_ROWS_SENT BIGINT unsigned not null,"
+ "SUM_ROWS_EXAMINED BIGINT unsigned not null,"
+ "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null,"
+ "SUM_CREATED_TMP_TABLES BIGINT unsigned not null,"
+ "SUM_SELECT_FULL_JOIN BIGINT unsigned not null,"
+ "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null,"
+ "SUM_SELECT_RANGE BIGINT unsigned not null,"
+ "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null,"
+ "SUM_SELECT_SCAN BIGINT unsigned not null,"
+ "SUM_SORT_MERGE_PASSES BIGINT unsigned not null,"
+ "SUM_SORT_RANGE BIGINT unsigned not null,"
+ "SUM_SORT_ROWS BIGINT unsigned not null,"
+ "SUM_SORT_SCAN BIGINT unsigned not null,"
+ "SUM_NO_INDEX_USED BIGINT unsigned not null,"
+ "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") }
+};
+
+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;
+
+ if (klass->is_mutable())
+ return;
+
+ 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..def5e19ecdc
--- /dev/null
+++ b/storage/perfschema/table_esms_by_host_by_event_name.h
@@ -0,0 +1,123 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** 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..f62d974aa76
--- /dev/null
+++ b/storage/perfschema/table_esms_by_thread_by_event_name.cc
@@ -0,0 +1,215 @@
+/* Copyright (c) 2010, 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, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_by_thread_by_event_name("
+ "THREAD_ID BIGINT unsigned not null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "SUM_LOCK_TIME BIGINT unsigned not null,"
+ "SUM_ERRORS BIGINT unsigned not null,"
+ "SUM_WARNINGS BIGINT unsigned not null,"
+ "SUM_ROWS_AFFECTED BIGINT unsigned not null,"
+ "SUM_ROWS_SENT BIGINT unsigned not null,"
+ "SUM_ROWS_EXAMINED BIGINT unsigned not null,"
+ "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null,"
+ "SUM_CREATED_TMP_TABLES BIGINT unsigned not null,"
+ "SUM_SELECT_FULL_JOIN BIGINT unsigned not null,"
+ "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null,"
+ "SUM_SELECT_RANGE BIGINT unsigned not null,"
+ "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null,"
+ "SUM_SELECT_SCAN BIGINT unsigned not null,"
+ "SUM_SORT_MERGE_PASSES BIGINT unsigned not null,"
+ "SUM_SORT_RANGE BIGINT unsigned not null,"
+ "SUM_SORT_ROWS BIGINT unsigned not null,"
+ "SUM_SORT_SCAN BIGINT unsigned not null,"
+ "SUM_NO_INDEX_USED BIGINT unsigned not null,"
+ "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") }
+};
+
+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;
+
+ if (klass->is_mutable())
+ return;
+
+ /* 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..7c50307c483
--- /dev/null
+++ b/storage/perfschema/table_esms_by_thread_by_event_name.h
@@ -0,0 +1,127 @@
+/* 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-1335 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;
+
+ /** 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..66afe288f12
--- /dev/null
+++ b/storage/perfschema/table_esms_by_user_by_event_name.cc
@@ -0,0 +1,214 @@
+/* Copyright (c) 2010, 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_by_user_by_event_name("
+ "USER CHAR(16) collate utf8_bin default null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "SUM_LOCK_TIME BIGINT unsigned not null,"
+ "SUM_ERRORS BIGINT unsigned not null,"
+ "SUM_WARNINGS BIGINT unsigned not null,"
+ "SUM_ROWS_AFFECTED BIGINT unsigned not null,"
+ "SUM_ROWS_SENT BIGINT unsigned not null,"
+ "SUM_ROWS_EXAMINED BIGINT unsigned not null,"
+ "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null,"
+ "SUM_CREATED_TMP_TABLES BIGINT unsigned not null,"
+ "SUM_SELECT_FULL_JOIN BIGINT unsigned not null,"
+ "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null,"
+ "SUM_SELECT_RANGE BIGINT unsigned not null,"
+ "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null,"
+ "SUM_SELECT_SCAN BIGINT unsigned not null,"
+ "SUM_SORT_MERGE_PASSES BIGINT unsigned not null,"
+ "SUM_SORT_RANGE BIGINT unsigned not null,"
+ "SUM_SORT_ROWS BIGINT unsigned not null,"
+ "SUM_SORT_SCAN BIGINT unsigned not null,"
+ "SUM_NO_INDEX_USED BIGINT unsigned not null,"
+ "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") }
+};
+
+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;
+
+ if (klass->is_mutable())
+ return;
+
+ 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..65284122043
--- /dev/null
+++ b/storage/perfschema/table_esms_by_user_by_event_name.h
@@ -0,0 +1,123 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** 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..96957bf028e
--- /dev/null
+++ b/storage/perfschema/table_esms_global_by_event_name.cc
@@ -0,0 +1,198 @@
+/* Copyright (c) 2010, 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, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_global_by_event_name("
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "SUM_LOCK_TIME BIGINT unsigned not null,"
+ "SUM_ERRORS BIGINT unsigned not null,"
+ "SUM_WARNINGS BIGINT unsigned not null,"
+ "SUM_ROWS_AFFECTED BIGINT unsigned not null,"
+ "SUM_ROWS_SENT BIGINT unsigned not null,"
+ "SUM_ROWS_EXAMINED BIGINT unsigned not null,"
+ "SUM_CREATED_TMP_DISK_TABLES BIGINT unsigned not null,"
+ "SUM_CREATED_TMP_TABLES BIGINT unsigned not null,"
+ "SUM_SELECT_FULL_JOIN BIGINT unsigned not null,"
+ "SUM_SELECT_FULL_RANGE_JOIN BIGINT unsigned not null,"
+ "SUM_SELECT_RANGE BIGINT unsigned not null,"
+ "SUM_SELECT_RANGE_CHECK BIGINT unsigned not null,"
+ "SUM_SELECT_SCAN BIGINT unsigned not null,"
+ "SUM_SORT_MERGE_PASSES BIGINT unsigned not null,"
+ "SUM_SORT_RANGE BIGINT unsigned not null,"
+ "SUM_SORT_ROWS BIGINT unsigned not null,"
+ "SUM_SORT_SCAN BIGINT unsigned not null,"
+ "SUM_NO_INDEX_USED BIGINT unsigned not null,"
+ "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") }
+};
+
+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_exists= false;
+
+ if (klass->is_mutable())
+ return;
+
+ 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..7453d635848
--- /dev/null
+++ b/storage/perfschema/table_esms_global_by_event_name.h
@@ -0,0 +1,91 @@
+/* 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-1335 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;
+
+ /** 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..757c42b59c4
--- /dev/null
+++ b/storage/perfschema/table_events_stages.cc
@@ -0,0 +1,502 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_stages_current("
+ "THREAD_ID BIGINT unsigned not null,"
+ "EVENT_ID BIGINT unsigned not null,"
+ "END_EVENT_ID BIGINT unsigned,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "SOURCE VARCHAR(64),"
+ "TIMER_START BIGINT unsigned,"
+ "TIMER_END BIGINT unsigned,"
+ "TIMER_WAIT BIGINT unsigned,"
+ "NESTING_EVENT_ID BIGINT unsigned,"
+ "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") }
+};
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_stages_history("
+ "THREAD_ID BIGINT unsigned not null,"
+ "EVENT_ID BIGINT unsigned not null,"
+ "END_EVENT_ID BIGINT unsigned,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "SOURCE VARCHAR(64),"
+ "TIMER_START BIGINT unsigned,"
+ "TIMER_END BIGINT unsigned,"
+ "TIMER_WAIT BIGINT unsigned,"
+ "NESTING_EVENT_ID BIGINT unsigned,"
+ "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") }
+};
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_stages_history_long("
+ "THREAD_ID BIGINT unsigned not null,"
+ "EVENT_ID BIGINT unsigned not null,"
+ "END_EVENT_ID BIGINT unsigned,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "SOURCE VARCHAR(64),"
+ "TIMER_START BIGINT unsigned,"
+ "TIMER_END BIGINT unsigned,"
+ "TIMER_WAIT BIGINT unsigned,"
+ "NESTING_EVENT_ID BIGINT unsigned,"
+ "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") }
+};
+
+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;
+ ulonglong timer_end;
+
+ 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;
+
+ if (m_row.m_end_event_id == 0)
+ {
+ timer_end= get_timer_raw_value(stage_timer);
+ }
+ else
+ {
+ timer_end= stage->m_timer_end;
+ }
+
+ m_normalizer->to_pico(stage->m_timer_start, 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..cbc0f9a42bb
--- /dev/null
+++ b/storage/perfschema/table_events_stages.h
@@ -0,0 +1,206 @@
+/* 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, Fifth Floor, 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;
+
+ /** 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..9dc8c329b96
--- /dev/null
+++ b/storage/perfschema/table_events_statements.cc
@@ -0,0 +1,901 @@
+/* Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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;
+
+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(pos_events_statements_current), /* ref length */
+ &m_table_lock,
+ { C_STRING_WITH_LEN("CREATE TABLE events_statements_current("
+ "THREAD_ID BIGINT unsigned not null,"
+ "EVENT_ID BIGINT unsigned not null,"
+ "END_EVENT_ID BIGINT unsigned,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "SOURCE VARCHAR(64),"
+ "TIMER_START BIGINT unsigned,"
+ "TIMER_END BIGINT unsigned,"
+ "TIMER_WAIT BIGINT unsigned,"
+ "LOCK_TIME bigint unsigned not null,"
+ "SQL_TEXT LONGTEXT,"
+ "DIGEST VARCHAR(32),"
+ "DIGEST_TEXT LONGTEXT,"
+ "CURRENT_SCHEMA VARCHAR(64),"
+ "OBJECT_TYPE VARCHAR(64),"
+ "OBJECT_SCHEMA VARCHAR(64),"
+ "OBJECT_NAME VARCHAR(64),"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned,"
+ "MYSQL_ERRNO INTEGER,"
+ "RETURNED_SQLSTATE VARCHAR(5),"
+ "MESSAGE_TEXT VARCHAR(128),"
+ "ERRORS BIGINT unsigned not null,"
+ "WARNINGS BIGINT unsigned not null,"
+ "ROWS_AFFECTED BIGINT unsigned not null,"
+ "ROWS_SENT BIGINT unsigned not null,"
+ "ROWS_EXAMINED BIGINT unsigned not null,"
+ "CREATED_TMP_DISK_TABLES BIGINT unsigned not null,"
+ "CREATED_TMP_TABLES BIGINT unsigned not null,"
+ "SELECT_FULL_JOIN BIGINT unsigned not null,"
+ "SELECT_FULL_RANGE_JOIN BIGINT unsigned not null,"
+ "SELECT_RANGE BIGINT unsigned not null,"
+ "SELECT_RANGE_CHECK BIGINT unsigned not null,"
+ "SELECT_SCAN BIGINT unsigned not null,"
+ "SORT_MERGE_PASSES BIGINT unsigned not null,"
+ "SORT_RANGE BIGINT unsigned not null,"
+ "SORT_ROWS BIGINT unsigned not null,"
+ "SORT_SCAN BIGINT unsigned not null,"
+ "NO_INDEX_USED BIGINT unsigned not null,"
+ "NO_GOOD_INDEX_USED BIGINT unsigned not null,"
+ "NESTING_EVENT_ID BIGINT unsigned,"
+ "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") }
+};
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_statements_history("
+ "THREAD_ID BIGINT unsigned not null,"
+ "EVENT_ID BIGINT unsigned not null,"
+ "END_EVENT_ID BIGINT unsigned,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "SOURCE VARCHAR(64),"
+ "TIMER_START BIGINT unsigned,"
+ "TIMER_END BIGINT unsigned,"
+ "TIMER_WAIT BIGINT unsigned,"
+ "LOCK_TIME bigint unsigned not null,"
+ "SQL_TEXT LONGTEXT,"
+ "DIGEST VARCHAR(32),"
+ "DIGEST_TEXT LONGTEXT,"
+ "CURRENT_SCHEMA VARCHAR(64),"
+ "OBJECT_TYPE VARCHAR(64),"
+ "OBJECT_SCHEMA VARCHAR(64),"
+ "OBJECT_NAME VARCHAR(64),"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned,"
+ "MYSQL_ERRNO INTEGER,"
+ "RETURNED_SQLSTATE VARCHAR(5),"
+ "MESSAGE_TEXT VARCHAR(128),"
+ "ERRORS BIGINT unsigned not null,"
+ "WARNINGS BIGINT unsigned not null,"
+ "ROWS_AFFECTED BIGINT unsigned not null,"
+ "ROWS_SENT BIGINT unsigned not null,"
+ "ROWS_EXAMINED BIGINT unsigned not null,"
+ "CREATED_TMP_DISK_TABLES BIGINT unsigned not null,"
+ "CREATED_TMP_TABLES BIGINT unsigned not null,"
+ "SELECT_FULL_JOIN BIGINT unsigned not null,"
+ "SELECT_FULL_RANGE_JOIN BIGINT unsigned not null,"
+ "SELECT_RANGE BIGINT unsigned not null,"
+ "SELECT_RANGE_CHECK BIGINT unsigned not null,"
+ "SELECT_SCAN BIGINT unsigned not null,"
+ "SORT_MERGE_PASSES BIGINT unsigned not null,"
+ "SORT_RANGE BIGINT unsigned not null,"
+ "SORT_ROWS BIGINT unsigned not null,"
+ "SORT_SCAN BIGINT unsigned not null,"
+ "NO_INDEX_USED BIGINT unsigned not null,"
+ "NO_GOOD_INDEX_USED BIGINT unsigned not null,"
+ "NESTING_EVENT_ID BIGINT unsigned,"
+ "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") }
+};
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_statements_history_long("
+ "THREAD_ID BIGINT unsigned not null,"
+ "EVENT_ID BIGINT unsigned not null,"
+ "END_EVENT_ID BIGINT unsigned,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "SOURCE VARCHAR(64),"
+ "TIMER_START BIGINT unsigned,"
+ "TIMER_END BIGINT unsigned,"
+ "TIMER_WAIT BIGINT unsigned,"
+ "LOCK_TIME bigint unsigned not null,"
+ "SQL_TEXT LONGTEXT,"
+ "DIGEST VARCHAR(32),"
+ "DIGEST_TEXT LONGTEXT,"
+ "CURRENT_SCHEMA VARCHAR(64),"
+ "OBJECT_TYPE VARCHAR(64),"
+ "OBJECT_SCHEMA VARCHAR(64),"
+ "OBJECT_NAME VARCHAR(64),"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned,"
+ "MYSQL_ERRNO INTEGER,"
+ "RETURNED_SQLSTATE VARCHAR(5),"
+ "MESSAGE_TEXT VARCHAR(128),"
+ "ERRORS BIGINT unsigned not null,"
+ "WARNINGS BIGINT unsigned not null,"
+ "ROWS_AFFECTED BIGINT unsigned not null,"
+ "ROWS_SENT BIGINT unsigned not null,"
+ "ROWS_EXAMINED BIGINT unsigned not null,"
+ "CREATED_TMP_DISK_TABLES BIGINT unsigned not null,"
+ "CREATED_TMP_TABLES BIGINT unsigned not null,"
+ "SELECT_FULL_JOIN BIGINT unsigned not null,"
+ "SELECT_FULL_RANGE_JOIN BIGINT unsigned not null,"
+ "SELECT_RANGE BIGINT unsigned not null,"
+ "SELECT_RANGE_CHECK BIGINT unsigned not null,"
+ "SELECT_SCAN BIGINT unsigned not null,"
+ "SORT_MERGE_PASSES BIGINT unsigned not null,"
+ "SORT_RANGE BIGINT unsigned not null,"
+ "SORT_ROWS BIGINT unsigned not null,"
+ "SORT_SCAN BIGINT unsigned not null,"
+ "NO_INDEX_USED BIGINT unsigned not null,"
+ "NO_GOOD_INDEX_USED BIGINT unsigned not null,"
+ "NESTING_EVENT_ID BIGINT unsigned,"
+ "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") }
+};
+
+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_part_1(PFS_events_statements *statement,
+ sql_digest_storage *digest)
+{
+ const char *base;
+ const char *safe_source_file;
+ ulonglong timer_end;
+
+ 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;
+
+ if (m_row.m_end_event_id == 0)
+ {
+ timer_end= get_timer_raw_value(statement_timer);
+ }
+ else
+ {
+ timer_end= statement->m_timer_end;
+ }
+
+ m_normalizer->to_pico(statement->m_timer_start, 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;
+
+ CHARSET_INFO *cs= get_charset(statement->m_sqltext_cs_number, MYF(0));
+ size_t valid_length= statement->m_sqltext_length;
+
+ if (cs != NULL)
+ {
+ if (cs->mbmaxlen > 1)
+ {
+ int well_formed_error;
+ valid_length= cs->cset->well_formed_len(cs,
+ statement->m_sqltext,
+ statement->m_sqltext + valid_length,
+ valid_length,
+ &well_formed_error);
+ }
+ }
+
+ m_row.m_sqltext.set_charset(cs);
+ m_row.m_sqltext.length(0);
+ m_row.m_sqltext.append(statement->m_sqltext, (uint32)valid_length, cs);
+
+ /* Indicate that sqltext is truncated or not well-formed. */
+ if (statement->m_sqltext_truncated || valid_length < statement->m_sqltext_length)
+ {
+ size_t chars= m_row.m_sqltext.numchars();
+ if (chars > 3)
+ {
+ chars-= 3;
+ size_t bytes_offset= m_row.m_sqltext.charpos(chars, 0);
+ m_row.m_sqltext.length(bytes_offset);
+ m_row.m_sqltext.append("...", 3);
+ }
+ }
+
+ 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= (uint)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;
+ /*
+ Making a copy of digest storage.
+ */
+ digest->copy(& statement->m_digest_storage);
+
+ m_row_exists= true;
+ return;
+}
+
+
+void table_events_statements_common::make_row_part_2(const sql_digest_storage *digest)
+{
+ /*
+ Filling up statement digest information.
+ */
+ size_t safe_byte_count= digest->m_byte_count;
+ if (safe_byte_count > 0 &&
+ safe_byte_count <= pfs_max_digest_length)
+ {
+ /* Generate the DIGEST string from the MD5 digest */
+ MD5_HASH_TO_STRING(digest->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 */
+ compute_digest_text(digest, &m_row.m_digest.m_digest_text);
+
+ if (m_row.m_digest.m_digest_text.length() == 0)
+ m_row.m_digest.m_digest_length= 0;
+ }
+ else
+ {
+ m_row.m_digest.m_digest_length= 0;
+ m_row.m_digest.m_digest_text.length(0);
+ }
+
+ 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.ptr(), 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.ptr(),
+ 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= (uint)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(pfs_thread, 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(pfs_thread, statement);
+ return 0;
+}
+
+void table_events_statements_current::make_row(PFS_thread *pfs_thread,
+ PFS_events_statements *statement)
+{
+ sql_digest_storage digest;
+ pfs_lock lock;
+ pfs_lock stmt_lock;
+
+ digest.reset(m_token_array, MAX_DIGEST_STORAGE_SIZE);
+ /* Protect this reader against thread termination. */
+ pfs_thread->m_lock.begin_optimistic_lock(&lock);
+ /* Protect this reader against writing on statement information. */
+ pfs_thread->m_stmt_lock.begin_optimistic_lock(&stmt_lock);
+
+ table_events_statements_common::make_row_part_1(statement, &digest);
+
+ if (!pfs_thread->m_stmt_lock.end_optimistic_lock(&stmt_lock) ||
+ !pfs_thread->m_lock.end_optimistic_lock(&lock))
+ {
+ m_row_exists= false;
+ return;
+ }
+ table_events_statements_common::make_row_part_2(&digest);
+ return;
+}
+
+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(pfs_thread, 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(pfs_thread, statement);
+ return 0;
+}
+
+void table_events_statements_history::make_row(PFS_thread *pfs_thread,
+ PFS_events_statements *statement)
+{
+ sql_digest_storage digest;
+ pfs_lock lock;
+
+ digest.reset(m_token_array, MAX_DIGEST_STORAGE_SIZE);
+ /* Protect this reader against thread termination. */
+ pfs_thread->m_lock.begin_optimistic_lock(&lock);
+
+ table_events_statements_common::make_row_part_1(statement, &digest);
+
+ if (!pfs_thread->m_lock.end_optimistic_lock(&lock))
+ {
+ m_row_exists= false;
+ return;
+ }
+ table_events_statements_common::make_row_part_2(&digest);
+ return;
+}
+
+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;
+ size_t 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;
+ size_t 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;
+}
+
+void table_events_statements_history_long::make_row(PFS_events_statements *statement)
+{
+ sql_digest_storage digest;
+
+ digest.reset(m_token_array, MAX_DIGEST_STORAGE_SIZE);
+ table_events_statements_common::make_row_part_1(statement, &digest);
+
+ table_events_statements_common::make_row_part_2(&digest);
+ return;
+}
+
+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..6f8bc1621d0
--- /dev/null
+++ b/storage/perfschema/table_events_statements.h
@@ -0,0 +1,290 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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. */
+ String m_sqltext;
+ /** Column DIGEST and DIGEST_TEXT. */
+ PFS_digest_row m_digest;
+ /** 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_part_1(PFS_events_statements *statement,
+ sql_digest_storage *digest);
+
+ void make_row_part_2(const sql_digest_storage *digest);
+
+ /** Current row. */
+ row_events_statements m_row;
+ /** True if the current row exists. */
+ bool m_row_exists;
+ unsigned char m_token_array[MAX_DIGEST_STORAGE_SIZE];
+};
+
+/** 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;
+
+ void make_row(PFS_thread* pfs_thread, PFS_events_statements *statement);
+
+ /** 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;
+
+ void make_row(PFS_thread* pfs_thread, PFS_events_statements *statement);
+
+ /** 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;
+
+ void make_row(PFS_events_statements *statement);
+
+ /** Current position. */
+ PFS_simple_index m_pos;
+ /** Next position. */
+ PFS_simple_index m_next_pos;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_events_waits.cc b/storage/perfschema/table_events_waits.cc
index 0efb5857b4c..c77d35811c8 100644
--- a/storage/perfschema/table_events_waits.cc
+++ b/storage/perfschema/table_events_waits.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,100 +21,15 @@
#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("int(11)") },
- { NULL, 0}
- },
- {
- { C_STRING_WITH_LEN("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("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("OPERATION") },
- { C_STRING_WITH_LEN("varchar(16)") },
- { 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=
-{ 16, field_types };
-
PFS_engine_table_share
table_events_waits_current::m_share=
{
@@ -123,11 +38,30 @@ table_events_waits_current::m_share=
&table_events_waits_current::create,
NULL, /* write_row */
&table_events_waits_current::delete_all_rows,
+ NULL, /* get_row_count */
1000, /* records */
sizeof(pos_events_waits_current), /* ref length */
&m_table_lock,
- &m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE events_waits_current("
+ "THREAD_ID BIGINT unsigned not null,"
+ "EVENT_ID BIGINT unsigned not null,"
+ "END_EVENT_ID BIGINT unsigned,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "SOURCE VARCHAR(64),"
+ "TIMER_START BIGINT unsigned,"
+ "TIMER_END BIGINT unsigned,"
+ "TIMER_WAIT BIGINT unsigned,"
+ "SPINS INTEGER unsigned,"
+ "OBJECT_SCHEMA VARCHAR(64),"
+ "OBJECT_NAME VARCHAR(512),"
+ "INDEX_NAME VARCHAR(64),"
+ "OBJECT_TYPE VARCHAR(64),"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null,"
+ "NESTING_EVENT_ID BIGINT unsigned,"
+ "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'),"
+ "OPERATION VARCHAR(32) not null,"
+ "NUMBER_OF_BYTES BIGINT,"
+ "FLAGS INTEGER unsigned)") }
};
THR_LOCK table_events_waits_history::m_table_lock;
@@ -140,11 +74,30 @@ table_events_waits_history::m_share=
&table_events_waits_history::create,
NULL, /* write_row */
&table_events_waits_history::delete_all_rows,
+ NULL, /* get_row_count */
1000, /* records */
sizeof(pos_events_waits_history), /* ref length */
&m_table_lock,
- &table_events_waits_current::m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE events_waits_history("
+ "THREAD_ID BIGINT unsigned not null,"
+ "EVENT_ID BIGINT unsigned not null,"
+ "END_EVENT_ID BIGINT unsigned,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "SOURCE VARCHAR(64),"
+ "TIMER_START BIGINT unsigned,"
+ "TIMER_END BIGINT unsigned,"
+ "TIMER_WAIT BIGINT unsigned,"
+ "SPINS INTEGER unsigned,"
+ "OBJECT_SCHEMA VARCHAR(64),"
+ "OBJECT_NAME VARCHAR(512),"
+ "INDEX_NAME VARCHAR(64),"
+ "OBJECT_TYPE VARCHAR(64),"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null,"
+ "NESTING_EVENT_ID BIGINT unsigned,"
+ "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'),"
+ "OPERATION VARCHAR(32) not null,"
+ "NUMBER_OF_BYTES BIGINT,"
+ "FLAGS INTEGER unsigned)") }
};
THR_LOCK table_events_waits_history_long::m_table_lock;
@@ -157,11 +110,30 @@ table_events_waits_history_long::m_share=
&table_events_waits_history_long::create,
NULL, /* write_row */
&table_events_waits_history_long::delete_all_rows,
+ NULL, /* get_row_count */
10000, /* records */
sizeof(PFS_simple_index), /* ref length */
&m_table_lock,
- &table_events_waits_current::m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE events_waits_history_long("
+ "THREAD_ID BIGINT unsigned not null,"
+ "EVENT_ID BIGINT unsigned not null,"
+ "END_EVENT_ID BIGINT unsigned,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "SOURCE VARCHAR(64),"
+ "TIMER_START BIGINT unsigned,"
+ "TIMER_END BIGINT unsigned,"
+ "TIMER_WAIT BIGINT unsigned,"
+ "SPINS INTEGER unsigned,"
+ "OBJECT_SCHEMA VARCHAR(64),"
+ "OBJECT_NAME VARCHAR(512),"
+ "INDEX_NAME VARCHAR(64),"
+ "OBJECT_TYPE VARCHAR(64),"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null,"
+ "NESTING_EVENT_ID BIGINT unsigned,"
+ "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'),"
+ "OPERATION VARCHAR(32) not null,"
+ "NUMBER_OF_BYTES BIGINT,"
+ "FLAGS INTEGER unsigned)") }
};
table_events_waits_common::table_events_waits_common
@@ -176,6 +148,158 @@ void table_events_waits_common::clear_object_columns()
m_row.m_object_type_length= 0;
m_row.m_object_schema_length= 0;
m_row.m_object_name_length= 0;
+ m_row.m_index_name_length= 0;
+ m_row.m_object_instance_addr= 0;
+}
+
+int table_events_waits_common::make_table_object_columns(volatile PFS_events_waits *wait)
+{
+ uint safe_index;
+ PFS_table_share *safe_table_share;
+
+ safe_table_share= sanitize_table_share(wait->m_weak_table_share);
+ if (unlikely(safe_table_share == NULL))
+ return 1;
+
+ if (wait->m_object_type == OBJECT_TYPE_TABLE)
+ {
+ m_row.m_object_type= "TABLE";
+ m_row.m_object_type_length= 5;
+ }
+ else
+ {
+ m_row.m_object_type= "TEMPORARY TABLE";
+ m_row.m_object_type_length= 15;
+ }
+
+ if (safe_table_share->get_version() == wait->m_weak_version)
+ {
+ /* OBJECT SCHEMA */
+ m_row.m_object_schema_length= safe_table_share->m_schema_name_length;
+ if (unlikely((m_row.m_object_schema_length == 0) ||
+ (m_row.m_object_schema_length > sizeof(m_row.m_object_schema))))
+ return 1;
+ memcpy(m_row.m_object_schema, safe_table_share->m_schema_name, m_row.m_object_schema_length);
+
+ /* OBJECT NAME */
+ m_row.m_object_name_length= safe_table_share->m_table_name_length;
+ if (unlikely((m_row.m_object_name_length == 0) ||
+ (m_row.m_object_name_length > sizeof(m_row.m_object_name))))
+ return 1;
+ memcpy(m_row.m_object_name, safe_table_share->m_table_name, m_row.m_object_name_length);
+
+ /* INDEX NAME */
+ safe_index= wait->m_index;
+ 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];
+ /*
+ "ip_length" was "ip_len" originally.
+ but it conflicted with some macro on AIX. Renamed.
+ */
+ uint ip_length= 0;
+ port_str[0]= ':';
+
+ /* Get the IP address and port number */
+ ip_length= 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_length + 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_length);
+ memcpy(name + ip_length, port_str, port_len);
+ }
+ else
+ {
+ m_row.m_object_name_length= 0;
+ }
+
+ m_row.m_index_name_length= 0;
+
+ return 0;
}
/**
@@ -194,9 +318,8 @@ void table_events_waits_common::make_row(bool thread_own_wait,
PFS_instr_class *safe_class;
const char *base;
const char *safe_source_file;
- const char *safe_table_schema_name;
- const char *safe_table_object_name;
- const char *safe_file_name;
+ enum_timer_name timer_name= wait_timer;
+ ulonglong timer_end;
m_row_exists= false;
safe_thread= sanitize_thread(pfs_thread);
@@ -224,13 +347,6 @@ void table_events_waits_common::make_row(bool thread_own_wait,
and sanitizes all the data before returning a row.
*/
- m_row.m_thread_internal_id= safe_thread->m_thread_internal_id;
- m_row.m_event_id= wait->m_event_id;
- m_row.m_timer_state= wait->m_timer_state;
- m_row.m_timer_start= wait->m_timer_start;
- m_row.m_timer_end= wait->m_timer_end;
- m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr;
-
/*
PFS_events_waits::m_class needs to be sanitized,
for race conditions when this code:
@@ -239,6 +355,11 @@ void table_events_waits_common::make_row(bool thread_own_wait,
*/
switch (wait->m_wait_class)
{
+ case WAIT_CLASS_IDLE:
+ clear_object_columns();
+ safe_class= sanitize_idle_class(wait->m_class);
+ timer_name= idle_timer;
+ break;
case WAIT_CLASS_MUTEX:
clear_object_columns();
safe_class= sanitize_mutex_class((PFS_mutex_class*) wait->m_class);
@@ -252,43 +373,48 @@ void table_events_waits_common::make_row(bool thread_own_wait,
safe_class= sanitize_cond_class((PFS_cond_class*) wait->m_class);
break;
case WAIT_CLASS_TABLE:
- m_row.m_object_type= "TABLE";
- m_row.m_object_type_length= 5;
- m_row.m_object_schema_length= wait->m_schema_name_length;
- safe_table_schema_name= sanitize_table_schema_name(wait->m_schema_name);
- if (unlikely((m_row.m_object_schema_length == 0) ||
- (m_row.m_object_schema_length > sizeof(m_row.m_object_schema)) ||
- (safe_table_schema_name == NULL)))
+ if (make_table_object_columns(wait))
return;
- memcpy(m_row.m_object_schema, safe_table_schema_name, m_row.m_object_schema_length);
- m_row.m_object_name_length= wait->m_object_name_length;
- safe_table_object_name= sanitize_table_object_name(wait->m_object_name);
- if (unlikely((m_row.m_object_name_length == 0) ||
- (m_row.m_object_name_length > sizeof(m_row.m_object_name)) ||
- (safe_table_object_name == NULL)))
- return;
- memcpy(m_row.m_object_name, safe_table_object_name, m_row.m_object_name_length);
- safe_class= &global_table_class;
+ safe_class= sanitize_table_class(wait->m_class);
break;
case WAIT_CLASS_FILE:
- m_row.m_object_type= "FILE";
- m_row.m_object_type_length= 4;
- m_row.m_object_schema_length= 0;
- m_row.m_object_name_length= wait->m_object_name_length;
- safe_file_name= sanitize_file_name(wait->m_object_name);
- if (unlikely((m_row.m_object_name_length == 0) ||
- (m_row.m_object_name_length > sizeof(m_row.m_object_name)) ||
- (safe_file_name == NULL)))
+ if (make_file_object_columns(wait))
return;
- memcpy(m_row.m_object_name, safe_file_name, m_row.m_object_name_length);
safe_class= sanitize_file_class((PFS_file_class*) wait->m_class);
break;
+ case WAIT_CLASS_SOCKET:
+ if (make_socket_object_columns(wait))
+ return;
+ safe_class= sanitize_socket_class((PFS_socket_class*) wait->m_class);
+ break;
case NO_WAIT_CLASS:
default:
return;
}
+
if (unlikely(safe_class == NULL))
return;
+
+ m_row.m_thread_internal_id= safe_thread->m_thread_internal_id;
+ m_row.m_event_id= wait->m_event_id;
+ m_row.m_end_event_id= wait->m_end_event_id;
+ m_row.m_nesting_event_id= wait->m_nesting_event_id;
+ m_row.m_nesting_event_type= wait->m_nesting_event_type;
+
+ get_normalizer(safe_class);
+
+ if (m_row.m_end_event_id == 0)
+ {
+ timer_end= get_timer_raw_value(timer_name);
+ }
+ else
+ {
+ timer_end= wait->m_timer_end;
+ }
+
+ m_normalizer->to_pico(wait->m_timer_start, timer_end,
+ & m_row.m_timer_start, & m_row.m_timer_end, & m_row.m_timer_wait);
+
m_row.m_name= safe_class->m_name;
m_row.m_name_length= safe_class->m_name_length;
@@ -307,7 +433,7 @@ void table_events_waits_common::make_row(bool thread_own_wait,
m_row.m_source_length= sizeof(m_row.m_source);
m_row.m_operation= wait->m_operation;
m_row.m_number_of_bytes= wait->m_number_of_bytes;
- m_row.m_flags= 0;
+ m_row.m_flags= wait->m_flags;
if (thread_own_wait)
{
@@ -368,7 +494,46 @@ static const LEX_STRING operation_names_map[]=
{ C_STRING_WITH_LEN("chsize") },
{ C_STRING_WITH_LEN("delete") },
{ C_STRING_WITH_LEN("rename") },
- { C_STRING_WITH_LEN("sync") }
+ { C_STRING_WITH_LEN("sync") },
+
+ /* Table io operations */
+ { C_STRING_WITH_LEN("fetch") },
+ { C_STRING_WITH_LEN("insert") }, /* write row */
+ { C_STRING_WITH_LEN("update") }, /* update row */
+ { C_STRING_WITH_LEN("delete") }, /* delete row */
+
+ /* Table lock operations */
+ { C_STRING_WITH_LEN("read normal") },
+ { C_STRING_WITH_LEN("read with shared locks") },
+ { C_STRING_WITH_LEN("read high priority") },
+ { C_STRING_WITH_LEN("read no inserts") },
+ { C_STRING_WITH_LEN("write allow write") },
+ { C_STRING_WITH_LEN("write concurrent insert") },
+ { C_STRING_WITH_LEN("write delayed") },
+ { C_STRING_WITH_LEN("write low priority") },
+ { C_STRING_WITH_LEN("write normal") },
+ { C_STRING_WITH_LEN("read external") },
+ { C_STRING_WITH_LEN("write external") },
+
+ /* Socket operations */
+ { C_STRING_WITH_LEN("create") },
+ { C_STRING_WITH_LEN("connect") },
+ { C_STRING_WITH_LEN("bind") },
+ { C_STRING_WITH_LEN("close") },
+ { C_STRING_WITH_LEN("send") },
+ { C_STRING_WITH_LEN("recv") },
+ { C_STRING_WITH_LEN("sendto") },
+ { C_STRING_WITH_LEN("recvfrom") },
+ { C_STRING_WITH_LEN("sendmsg") },
+ { C_STRING_WITH_LEN("recvmsg") },
+ { C_STRING_WITH_LEN("seek") },
+ { C_STRING_WITH_LEN("opt") },
+ { C_STRING_WITH_LEN("stat") },
+ { C_STRING_WITH_LEN("shutdown") },
+ { C_STRING_WITH_LEN("select") },
+
+ /* Idle operations */
+ { C_STRING_WITH_LEN("idle") }
};
@@ -406,40 +571,45 @@ int table_events_waits_common::read_row_values(TABLE *table,
switch(f->field_index)
{
case 0: /* THREAD_ID */
- set_field_ulong(f, m_row.m_thread_internal_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: /* EVENT_NAME */
+ case 2: /* END_EVENT_ID */
+ if (m_row.m_end_event_id > 0)
+ set_field_ulonglong(f, m_row.m_end_event_id - 1);
+ else
+ f->set_null();
+ break;
+ case 3: /* EVENT_NAME */
set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
break;
- case 3: /* SOURCE */
+ case 4: /* SOURCE */
set_field_varchar_utf8(f, m_row.m_source, m_row.m_source_length);
break;
- case 4: /* TIMER_START */
- if ((m_row.m_timer_state == TIMER_STATE_STARTED) ||
- (m_row.m_timer_state == TIMER_STATE_TIMED))
+ case 5: /* TIMER_START */
+ if (m_row.m_timer_start != 0)
set_field_ulonglong(f, m_row.m_timer_start);
else
f->set_null();
break;
- case 5: /* TIMER_END */
- if (m_row.m_timer_state == TIMER_STATE_TIMED)
+ case 6: /* TIMER_END */
+ if (m_row.m_timer_end != 0)
set_field_ulonglong(f, m_row.m_timer_end);
else
f->set_null();
break;
- case 6: /* TIMER_WAIT */
- if (m_row.m_timer_state == TIMER_STATE_TIMED)
- set_field_ulonglong(f, m_row.m_timer_end - m_row.m_timer_start);
+ case 7: /* TIMER_WAIT */
+ if (m_row.m_timer_wait != 0)
+ set_field_ulonglong(f, m_row.m_timer_wait);
else
f->set_null();
break;
- case 7: /* SPINS */
+ case 8: /* SPINS */
f->set_null();
break;
- case 8: /* OBJECT_SCHEMA */
+ case 9: /* OBJECT_SCHEMA */
if (m_row.m_object_schema_length > 0)
{
set_field_varchar_utf8(f, m_row.m_object_schema,
@@ -448,7 +618,7 @@ int table_events_waits_common::read_row_values(TABLE *table,
else
f->set_null();
break;
- case 9: /* OBJECT_NAME */
+ case 10: /* OBJECT_NAME */
if (m_row.m_object_name_length > 0)
{
set_field_varchar_utf8(f, m_row.m_object_name,
@@ -457,7 +627,16 @@ int table_events_waits_common::read_row_values(TABLE *table,
else
f->set_null();
break;
- case 10: /* OBJECT_TYPE */
+ case 11: /* INDEX_NAME */
+ if (m_row.m_index_name_length > 0)
+ {
+ set_field_varchar_utf8(f, m_row.m_index_name,
+ m_row.m_index_name_length);
+ }
+ else
+ f->set_null();
+ break;
+ case 12: /* OBJECT_TYPE */
if (m_row.m_object_type)
{
set_field_varchar_utf8(f, m_row.m_object_type,
@@ -466,26 +645,39 @@ int table_events_waits_common::read_row_values(TABLE *table,
else
f->set_null();
break;
- case 11: /* OBJECT_INSTANCE */
+ case 13: /* OBJECT_INSTANCE */
set_field_ulonglong(f, m_row.m_object_instance_addr);
break;
- case 12: /* NESTING_EVENT_ID */
- f->set_null();
+ case 14: /* NESTING_EVENT_ID */
+ if (m_row.m_nesting_event_id != 0)
+ set_field_ulonglong(f, m_row.m_nesting_event_id);
+ else
+ f->set_null();
+ break;
+ case 15: /* NESTING_EVENT_TYPE */
+ if (m_row.m_nesting_event_id != 0)
+ set_field_enum(f, m_row.m_nesting_event_type);
+ else
+ f->set_null();
break;
- case 13: /* OPERATION */
+ case 16: /* OPERATION */
operation= &operation_names_map[(int) m_row.m_operation - 1];
set_field_varchar_utf8(f, operation->str, operation->length);
break;
- case 14: /* NUMBER_OF_BYTES */
+ case 17: /* NUMBER_OF_BYTES */
if ((m_row.m_operation == OPERATION_TYPE_FILEREAD) ||
(m_row.m_operation == OPERATION_TYPE_FILEWRITE) ||
- (m_row.m_operation == OPERATION_TYPE_FILECHSIZE))
+ (m_row.m_operation == OPERATION_TYPE_FILECHSIZE) ||
+ (m_row.m_operation == OPERATION_TYPE_SOCKETSEND) ||
+ (m_row.m_operation == OPERATION_TYPE_SOCKETRECV) ||
+ (m_row.m_operation == OPERATION_TYPE_SOCKETSENDTO) ||
+ (m_row.m_operation == OPERATION_TYPE_SOCKETRECVFROM))
set_field_ulonglong(f, m_row.m_number_of_bytes);
else
f->set_null();
break;
- case 15: /* FLAGS */
- set_field_ulong(f, m_row.m_flags);
+ case 18: /* FLAGS */
+ f->set_null();
break;
default:
DBUG_ASSERT(false);
@@ -532,17 +724,31 @@ int table_events_waits_current::rnd_next(void)
We do not show nested events for now,
this will be revised with TABLE io
*/
-#define ONLY_SHOW_ONE_WAIT
+// #define ONLY_SHOW_ONE_WAIT
#ifdef ONLY_SHOW_ONE_WAIT
if (m_pos.m_index_2 >= 1)
continue;
#else
- if (m_pos.m_index_2 >= pfs_thread->m_wait_locker_count)
- continue;
-#endif
+ /* m_events_waits_stack[0] is a dummy record */
+ PFS_events_waits *top_wait = &pfs_thread->m_events_waits_stack[WAIT_STACK_BOTTOM];
+ wait= &pfs_thread->m_events_waits_stack[m_pos.m_index_2 + WAIT_STACK_BOTTOM];
- wait= &pfs_thread->m_wait_locker_stack[m_pos.m_index_2].m_waits_current;
+ PFS_events_waits *safe_current = pfs_thread->m_events_waits_current;
+
+ if (safe_current == top_wait)
+ {
+ /* Display the last top level wait, when completed */
+ if (m_pos.m_index_2 >= 1)
+ continue;
+ }
+ else
+ {
+ /* Display all pending waits, when in progress */
+ if (wait >= safe_current)
+ continue;
+ }
+#endif
if (wait->m_wait_class == NO_WAIT_CLASS)
{
@@ -574,14 +780,31 @@ int table_events_waits_current::rnd_pos(const void *pos)
if (! pfs_thread->m_lock.is_populated())
return HA_ERR_RECORD_DELETED;
-#ifdef ONLY_SHOW_CURRENT_WAITS
- if (m_pos.m_index_2 >= pfs_thread->m_wait_locker_count)
+#ifdef ONLY_SHOW_ONE_WAIT
+ if (m_pos.m_index_2 >= 1)
return HA_ERR_RECORD_DELETED;
-#endif
+#else
+ /* m_events_waits_stack[0] is a dummy record */
+ PFS_events_waits *top_wait = &pfs_thread->m_events_waits_stack[WAIT_STACK_BOTTOM];
+ wait= &pfs_thread->m_events_waits_stack[m_pos.m_index_2 + WAIT_STACK_BOTTOM];
+
+ PFS_events_waits *safe_current = pfs_thread->m_events_waits_current;
- DBUG_ASSERT(m_pos.m_index_2 < LOCKER_STACK_SIZE);
+ if (safe_current == top_wait)
+ {
+ /* Display the last top level wait, when completed */
+ if (m_pos.m_index_2 >= 1)
+ return HA_ERR_RECORD_DELETED;
+ }
+ else
+ {
+ /* Display all pending waits, when in progress */
+ if (wait >= safe_current)
+ return HA_ERR_RECORD_DELETED;
+ }
+#endif
- wait= &pfs_thread->m_wait_locker_stack[m_pos.m_index_2].m_waits_current;
+ DBUG_ASSERT(m_pos.m_index_2 < WAIT_STACK_LOGICAL_SIZE);
if (wait->m_wait_class == NO_WAIT_CLASS)
return HA_ERR_RECORD_DELETED;
@@ -685,12 +908,11 @@ int table_events_waits_history::rnd_pos(const void *pos)
(m_pos.m_index_2 >= pfs_thread->m_waits_history_index))
return HA_ERR_RECORD_DELETED;
- if (pfs_thread->m_waits_history[m_pos.m_index_2].m_wait_class
- == NO_WAIT_CLASS)
- return HA_ERR_RECORD_DELETED;
-
wait= &pfs_thread->m_waits_history[m_pos.m_index_2];
+ if (wait->m_wait_class == NO_WAIT_CLASS)
+ return HA_ERR_RECORD_DELETED;
+
make_row(true, pfs_thread, wait);
return 0;
}
diff --git a/storage/perfschema/table_events_waits.h b/storage/perfschema/table_events_waits.h
index 28948c4bd12..3e09fa487ad 100644
--- a/storage/perfschema/table_events_waits.h
+++ b/storage/perfschema/table_events_waits.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -36,21 +36,25 @@ struct PFS_thread;
struct row_events_waits
{
/** Column THREAD_ID. */
- ulong m_thread_internal_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;
- /** Timer state. */
- enum timer_state m_timer_state;
/** Column TIMER_START. */
ulonglong m_timer_start;
- /** True if TIMER_END is null. */
- bool m_timer_end_null;
/** Column TIMER_END. */
ulonglong m_timer_end;
+ /** Column TIMER_WAIT. */
+ ulonglong m_timer_wait;
/** Column OBJECT_TYPE. */
const char *m_object_type;
/** Length in bytes of @c m_object_type. */
@@ -63,6 +67,10 @@ struct row_events_waits
char m_object_name[COL_OBJECT_NAME_EXTENDED_SIZE];
/** Length in bytes of @c m_object_name. */
uint m_object_name_length;
+ /** Column INDEX_NAME. */
+ char m_index_name[COL_INDEX_NAME_SIZE];
+ /** Length in bytes of @c m_index_name. */
+ uint m_index_name_length;
/** Column OBJECT_INSTANCE_BEGIN. */
intptr m_object_instance_addr;
/** Column SOURCE. */
@@ -135,13 +143,16 @@ protected:
{}
void clear_object_columns();
+ int make_table_object_columns(volatile PFS_events_waits *wait);
+ int make_file_object_columns(volatile PFS_events_waits *wait);
+ int make_socket_object_columns(volatile PFS_events_waits *wait);
void make_row(bool thread_own_wait, PFS_thread *pfs_thread,
volatile PFS_events_waits *wait);
/** Current row. */
row_events_waits m_row;
- /** True is the current row exists. */
+ /** True if the current row exists. */
bool m_row_exists;
};
@@ -171,12 +182,6 @@ private:
/** 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;
diff --git a/storage/perfschema/table_events_waits_summary.cc b/storage/perfschema/table_events_waits_summary.cc
index 11d2807fcd1..2f5c83d57d3 100644
--- a/storage/perfschema/table_events_waits_summary.cc
+++ b/storage/perfschema/table_events_waits_summary.cc
@@ -26,363 +26,8 @@
#include "table_events_waits_summary.h"
#include "pfs_global.h"
-THR_LOCK table_events_waits_summary_by_thread_by_event_name::m_table_lock;
-
-static const TABLE_FIELD_TYPE ews_by_thread_by_event_name_field_types[]=
-{
- {
- { C_STRING_WITH_LEN("THREAD_ID") },
- { C_STRING_WITH_LEN("int(11)") },
- { NULL, 0}
- },
- {
- { C_STRING_WITH_LEN("EVENT_NAME") },
- { C_STRING_WITH_LEN("varchar(128)") },
- { NULL, 0}
- },
- {
- { C_STRING_WITH_LEN("COUNT_STAR") },
- { C_STRING_WITH_LEN("bigint(20)") },
- { NULL, 0}
- },
- {
- { C_STRING_WITH_LEN("SUM_TIMER_WAIT") },
- { C_STRING_WITH_LEN("bigint(20)") },
- { NULL, 0}
- },
- {
- { C_STRING_WITH_LEN("MIN_TIMER_WAIT") },
- { C_STRING_WITH_LEN("bigint(20)") },
- { NULL, 0}
- },
- {
- { C_STRING_WITH_LEN("AVG_TIMER_WAIT") },
- { C_STRING_WITH_LEN("bigint(20)") },
- { NULL, 0}
- },
- {
- { C_STRING_WITH_LEN("MAX_TIMER_WAIT") },
- { C_STRING_WITH_LEN("bigint(20)") },
- { NULL, 0}
- }
-};
-
-TABLE_FIELD_DEF
-table_events_waits_summary_by_thread_by_event_name::m_field_def=
-{ 7, ews_by_thread_by_event_name_field_types };
-
-PFS_engine_table_share
-table_events_waits_summary_by_thread_by_event_name::m_share=
-{
- { C_STRING_WITH_LEN("events_waits_summary_by_thread_by_event_name") },
- &pfs_truncatable_acl,
- &table_events_waits_summary_by_thread_by_event_name::create,
- NULL, /* write_row */
- &table_events_waits_summary_by_thread_by_event_name::delete_all_rows,
- 1000, /* records */
- sizeof(pos_events_waits_summary_by_thread_by_event_name),
- &m_table_lock,
- &m_field_def,
- false /* checked */
-};
-
-PFS_engine_table*
-table_events_waits_summary_by_thread_by_event_name::create(void)
-{
- return new table_events_waits_summary_by_thread_by_event_name();
-}
-
-int
-table_events_waits_summary_by_thread_by_event_name::delete_all_rows(void)
-{
- reset_per_thread_wait_stat();
- return 0;
-}
-
-table_events_waits_summary_by_thread_by_event_name
-::table_events_waits_summary_by_thread_by_event_name()
- : PFS_engine_table(&m_share, &m_pos),
- m_row_exists(false), m_pos(), m_next_pos()
-{}
-
-void table_events_waits_summary_by_thread_by_event_name::reset_position(void)
-{
- m_pos.reset();
- m_next_pos.reset();
-}
-
-int table_events_waits_summary_by_thread_by_event_name::rnd_next(void)
-{
- PFS_thread *thread;
- PFS_mutex_class *mutex_class;
- PFS_rwlock_class *rwlock_class;
- PFS_cond_class *cond_class;
- PFS_file_class *file_class;
-
- for (m_pos.set_at(&m_next_pos);
- m_pos.has_more_thread();
- m_pos.next_thread())
- {
- thread= &thread_array[m_pos.m_index_1];
- if (thread->m_lock.is_populated())
- {
- for ( ; m_pos.has_more_view(); m_pos.next_view())
- {
- switch (m_pos.m_index_2) {
- case pos_events_waits_summary_by_thread_by_event_name::VIEW_MUTEX:
- mutex_class= find_mutex_class(m_pos.m_index_3);
- if (mutex_class)
- {
- make_mutex_row(thread, mutex_class);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
- break;
- case pos_events_waits_summary_by_thread_by_event_name::VIEW_RWLOCK:
- rwlock_class= find_rwlock_class(m_pos.m_index_3);
- if (rwlock_class)
- {
- make_rwlock_row(thread, rwlock_class);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
- break;
- case pos_events_waits_summary_by_thread_by_event_name::VIEW_COND:
- cond_class= find_cond_class(m_pos.m_index_3);
- if (cond_class)
- {
- make_cond_row(thread, cond_class);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
- break;
- case pos_events_waits_summary_by_thread_by_event_name::VIEW_FILE:
- file_class= find_file_class(m_pos.m_index_3);
- if (file_class)
- {
- make_file_row(thread, file_class);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
- break;
- }
- }
- }
- }
-
- return HA_ERR_END_OF_FILE;
-}
-
-int
-table_events_waits_summary_by_thread_by_event_name::rnd_pos(const void *pos)
-{
- PFS_thread *thread;
- PFS_mutex_class *mutex_class;
- PFS_rwlock_class *rwlock_class;
- PFS_cond_class *cond_class;
- PFS_file_class *file_class;
-
- set_position(pos);
- DBUG_ASSERT(m_pos.m_index_1 < thread_max);
-
- thread= &thread_array[m_pos.m_index_1];
- if (! thread->m_lock.is_populated())
- return HA_ERR_RECORD_DELETED;
-
- switch (m_pos.m_index_2) {
- case pos_events_waits_summary_by_thread_by_event_name::VIEW_MUTEX:
- mutex_class= find_mutex_class(m_pos.m_index_3);
- if (mutex_class)
- {
- make_mutex_row(thread, mutex_class);
- return 0;
- }
- break;
- case pos_events_waits_summary_by_thread_by_event_name::VIEW_RWLOCK:
- rwlock_class= find_rwlock_class(m_pos.m_index_3);
- if (rwlock_class)
- {
- make_rwlock_row(thread, rwlock_class);
- return 0;
- }
- break;
- case pos_events_waits_summary_by_thread_by_event_name::VIEW_COND:
- cond_class= find_cond_class(m_pos.m_index_3);
- if (cond_class)
- {
- make_cond_row(thread, cond_class);
- return 0;
- }
- break;
- case pos_events_waits_summary_by_thread_by_event_name::VIEW_FILE:
- file_class= find_file_class(m_pos.m_index_3);
- if (file_class)
- {
- make_file_row(thread, file_class);
- return 0;
- }
- break;
- }
- return HA_ERR_RECORD_DELETED;
-}
-
-void table_events_waits_summary_by_thread_by_event_name
-::make_instr_row(PFS_thread *thread, PFS_instr_class *klass,
- PFS_single_stat_chain *stat)
-{
- pfs_lock lock;
-
- m_row_exists= false;
-
- /* Protect this reader against a thread termination */
- thread->m_lock.begin_optimistic_lock(&lock);
-
- m_row.m_thread_internal_id= thread->m_thread_internal_id;
- m_row.m_name= klass->m_name;
- m_row.m_name_length= klass->m_name_length;
-
- m_row.m_count= stat->m_count;
- m_row.m_sum= stat->m_sum;
- m_row.m_min= stat->m_min;
- m_row.m_max= stat->m_max;
-
- if (m_row.m_count)
- m_row.m_avg= m_row.m_sum / m_row.m_count;
- else
- {
- m_row.m_min= 0;
- m_row.m_avg= 0;
- }
-
- if (thread->m_lock.end_optimistic_lock(&lock))
- m_row_exists= true;
-}
-
-void table_events_waits_summary_by_thread_by_event_name
-::make_mutex_row(PFS_thread *thread, PFS_mutex_class *klass)
-{
- PFS_single_stat_chain *stat;
- stat= find_per_thread_mutex_class_wait_stat(thread, klass);
- make_instr_row(thread, klass, stat);
-}
-
-void table_events_waits_summary_by_thread_by_event_name
-::make_rwlock_row(PFS_thread *thread, PFS_rwlock_class *klass)
-{
- PFS_single_stat_chain *stat;
- stat= find_per_thread_rwlock_class_wait_stat(thread, klass);
- make_instr_row(thread, klass, stat);
-}
-
-void table_events_waits_summary_by_thread_by_event_name
-::make_cond_row(PFS_thread *thread, PFS_cond_class *klass)
-{
- PFS_single_stat_chain *stat;
- stat= find_per_thread_cond_class_wait_stat(thread, klass);
- make_instr_row(thread, klass, stat);
-}
-
-void table_events_waits_summary_by_thread_by_event_name
-::make_file_row(PFS_thread *thread, PFS_file_class *klass)
-{
- PFS_single_stat_chain *stat;
- stat= find_per_thread_file_class_wait_stat(thread, klass);
- make_instr_row(thread, klass, stat);
-}
-
-int table_events_waits_summary_by_thread_by_event_name
-::read_row_values(TABLE *table, unsigned char *, Field **fields,
- bool read_all)
-{
- Field *f;
-
- if (unlikely(! m_row_exists))
- return HA_ERR_RECORD_DELETED;
-
- /* Set the null bits */
- DBUG_ASSERT(table->s->null_bytes == 0);
-
- for (; (f= *fields) ; fields++)
- {
- if (read_all || bitmap_is_set(table->read_set, f->field_index))
- {
- switch(f->field_index)
- {
- case 0: /* THREAD_ID */
- set_field_ulong(f, m_row.m_thread_internal_id);
- break;
- case 1: /* NAME */
- set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
- break;
- case 2: /* COUNT */
- set_field_ulonglong(f, m_row.m_count);
- break;
- case 3: /* SUM */
- set_field_ulonglong(f, m_row.m_sum);
- break;
- case 4: /* MIN */
- set_field_ulonglong(f, m_row.m_min);
- break;
- case 5: /* AVG */
- set_field_ulonglong(f, m_row.m_avg);
- break;
- case 6: /* MAX */
- set_field_ulonglong(f, m_row.m_max);
- break;
- default:
- DBUG_ASSERT(false);
- }
- }
- }
-
- return 0;
-}
-
THR_LOCK table_events_waits_summary_by_instance::m_table_lock;
-static const TABLE_FIELD_TYPE ews_by_instance_field_types[]=
-{
- {
- { 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=
{
@@ -391,11 +36,18 @@ table_events_waits_summary_by_instance::m_share=
&table_events_waits_summary_by_instance::create,
NULL, /* write_row */
&table_events_waits_summary_by_instance::delete_all_rows,
+ NULL, /* get_row_count */
1000, /* records */
sizeof(pos_all_instr),
&m_table_lock,
- &m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_by_instance("
+ "EVENT_NAME VARCHAR(128) not null,"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null)") }
};
PFS_engine_table* table_events_waits_summary_by_instance::create(void)
@@ -416,10 +68,10 @@ table_events_waits_summary_by_instance
void table_events_waits_summary_by_instance
::make_instr_row(PFS_instr *pfs, PFS_instr_class *klass,
- const void *object_instance_begin)
+ const void *object_instance_begin,
+ PFS_single_stat *pfs_stat)
{
pfs_lock lock;
-
m_row_exists= false;
/*
@@ -432,18 +84,8 @@ void table_events_waits_summary_by_instance
m_row.m_name_length= klass->m_name_length;
m_row.m_object_instance_addr= (intptr) object_instance_begin;
- m_row.m_count= pfs->m_wait_stat.m_count;
- m_row.m_sum= pfs->m_wait_stat.m_sum;
- m_row.m_min= pfs->m_wait_stat.m_min;
- m_row.m_max= pfs->m_wait_stat.m_max;
-
- if (m_row.m_count)
- m_row.m_avg= m_row.m_sum / m_row.m_count;
- else
- {
- m_row.m_min= 0;
- m_row.m_avg= 0;
- }
+ get_normalizer(klass);
+ m_row.m_stat.set(m_normalizer, pfs_stat);
if (pfs->m_lock.end_optimistic_lock(&lock))
m_row_exists= true;
@@ -460,7 +102,7 @@ void table_events_waits_summary_by_instance::make_mutex_row(PFS_mutex *pfs)
if (unlikely(safe_class == NULL))
return;
- make_instr_row(pfs, safe_class, pfs->m_identity);
+ make_instr_row(pfs, safe_class, pfs->m_identity, &pfs->m_mutex_stat.m_wait_stat);
}
/**
@@ -474,7 +116,7 @@ void table_events_waits_summary_by_instance::make_rwlock_row(PFS_rwlock *pfs)
if (unlikely(safe_class == NULL))
return;
- make_instr_row(pfs, safe_class, pfs->m_identity);
+ make_instr_row(pfs, safe_class, pfs->m_identity, &pfs->m_rwlock_stat.m_wait_stat);
}
/**
@@ -488,7 +130,7 @@ void table_events_waits_summary_by_instance::make_cond_row(PFS_cond *pfs)
if (unlikely(safe_class == NULL))
return;
- make_instr_row(pfs, safe_class, pfs->m_identity);
+ make_instr_row(pfs, safe_class, pfs->m_identity, &pfs->m_cond_stat.m_wait_stat);
}
/**
@@ -502,11 +144,38 @@ void table_events_waits_summary_by_instance::make_file_row(PFS_file *pfs)
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);
+ 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
@@ -534,19 +203,19 @@ int table_events_waits_summary_by_instance
set_field_ulonglong(f, m_row.m_object_instance_addr);
break;
case 2: /* COUNT */
- set_field_ulonglong(f, m_row.m_count);
+ set_field_ulonglong(f, m_row.m_stat.m_count);
break;
case 3: /* SUM */
- set_field_ulonglong(f, m_row.m_sum);
+ set_field_ulonglong(f, m_row.m_stat.m_sum);
break;
case 4: /* MIN */
- set_field_ulonglong(f, m_row.m_min);
+ set_field_ulonglong(f, m_row.m_stat.m_min);
break;
case 5: /* AVG */
- set_field_ulonglong(f, m_row.m_avg);
+ set_field_ulonglong(f, m_row.m_stat.m_avg);
break;
case 6: /* MAX */
- set_field_ulonglong(f, m_row.m_max);
+ set_field_ulonglong(f, m_row.m_stat.m_max);
break;
default:
DBUG_ASSERT(false);
diff --git a/storage/perfschema/table_events_waits_summary.h b/storage/perfschema/table_events_waits_summary.h
index a32a198cddf..a4f063bb66a 100644
--- a/storage/perfschema/table_events_waits_summary.h
+++ b/storage/perfschema/table_events_waits_summary.h
@@ -26,124 +26,13 @@
#include "pfs_instr_class.h"
#include "pfs_instr.h"
#include "table_all_instr.h"
+#include "table_helper.h"
/**
@addtogroup Performance_schema_tables
@{
*/
-/**
- A row of table
- PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME.
-*/
-struct row_events_waits_summary_by_thread_by_event_name
-{
- /** Column THREAD_ID. */
- ulong m_thread_internal_id;
- /** Column EVENT_NAME. */
- const char *m_name;
- /** Length in bytes of @c m_name. */
- uint m_name_length;
- /** Column COUNT_STAR. */
- ulonglong m_count;
- /** Column SUM_TIMER_WAIT. */
- ulonglong m_sum;
- /** Column MIN_TIMER_WAIT. */
- ulonglong m_min;
- /** Column AVG_TIMER_WAIT. */
- ulonglong m_avg;
- /** Column MAX_TIMER_WAIT. */
- ulonglong m_max;
-};
-
-/**
- Position of a cursor on
- PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME.
-*/
-struct pos_events_waits_summary_by_thread_by_event_name
-: public PFS_triple_index, public PFS_instrument_view_constants
-{
- pos_events_waits_summary_by_thread_by_event_name()
- : PFS_triple_index(0, VIEW_MUTEX, 1)
- {}
-
- inline void reset(void)
- {
- m_index_1= 0;
- m_index_2= VIEW_MUTEX;
- m_index_3= 1;
- }
-
- inline bool has_more_thread(void)
- { return (m_index_1 < thread_max); }
-
- inline bool has_more_view(void)
- { return (m_index_2 <= VIEW_FILE); }
-
- inline void next_thread(void)
- {
- m_index_1++;
- m_index_2= VIEW_MUTEX;
- m_index_3= 1;
- }
-
- inline void next_view(void)
- {
- m_index_2++;
- m_index_3= 1;
- }
-};
-
-/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME. */
-class table_events_waits_summary_by_thread_by_event_name
- : public PFS_engine_table
-{
-public:
- /** Table share */
- static PFS_engine_table_share m_share;
- static PFS_engine_table* create();
- static int delete_all_rows();
-
- virtual int rnd_next();
- virtual int rnd_pos(const void *pos);
- virtual void reset_position(void);
-
-protected:
- virtual int read_row_values(TABLE *table,
- unsigned char *buf,
- Field **fields,
- bool read_all);
-
- table_events_waits_summary_by_thread_by_event_name();
-
-public:
- ~table_events_waits_summary_by_thread_by_event_name()
- {}
-
-protected:
- void make_instr_row(PFS_thread *thread, PFS_instr_class *klass,
- PFS_single_stat_chain *stat);
- void make_mutex_row(PFS_thread *thread, PFS_mutex_class *klass);
- void make_rwlock_row(PFS_thread *thread, PFS_rwlock_class *klass);
- void make_cond_row(PFS_thread *thread, PFS_cond_class *klass);
- void make_file_row(PFS_thread *thread, PFS_file_class *klass);
-
-private:
- /** Table share lock. */
- static THR_LOCK m_table_lock;
- /** Fields definition. */
- static TABLE_FIELD_DEF m_field_def;
-
- /** Current row. */
- row_events_waits_summary_by_thread_by_event_name m_row;
- /** True is the current row exists. */
- bool m_row_exists;
- /** Current position. */
- pos_events_waits_summary_by_thread_by_event_name m_pos;
- /** Next position. */
- pos_events_waits_summary_by_thread_by_event_name m_next_pos;
-};
-
/** A row of PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_INSTANCE. */
struct row_events_waits_summary_by_instance
{
@@ -153,16 +42,8 @@ struct row_events_waits_summary_by_instance
uint m_name_length;
/** Column OBJECT_INSTANCE_BEGIN. */
intptr m_object_instance_addr;
- /** Column COUNT_STAR. */
- ulonglong m_count;
- /** Column SUM_TIMER_WAIT. */
- ulonglong m_sum;
- /** Column MIN_TIMER_WAIT. */
- ulonglong m_min;
- /** Column AVG_TIMER_WAIT. */
- ulonglong m_avg;
- /** Column MAX_TIMER_WAIT. */
- ulonglong m_max;
+ /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */
+ PFS_stat_row m_stat;
};
/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_INSTANCE. */
@@ -176,11 +57,13 @@ public:
protected:
void make_instr_row(PFS_instr *pfs, PFS_instr_class *klass,
- const void *object_instance_begin);
+ const void *object_instance_begin,
+ PFS_single_stat *pfs_stat);
virtual void make_mutex_row(PFS_mutex *pfs);
virtual void make_rwlock_row(PFS_rwlock *pfs);
virtual void make_cond_row(PFS_cond *pfs);
virtual void make_file_row(PFS_file *pfs);
+ virtual void make_socket_row(PFS_socket *pfs);
virtual int read_row_values(TABLE *table,
unsigned char *buf,
@@ -196,12 +79,10 @@ public:
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 is the current row exists. */
+ /** True if the current row exists. */
bool m_row_exists;
};
diff --git a/storage/perfschema/table_ews_by_account_by_event_name.cc b/storage/perfschema/table_ews_by_account_by_event_name.cc
new file mode 100644
index 00000000000..0b86a4ac1dc
--- /dev/null
+++ b/storage/perfschema/table_ews_by_account_by_event_name.cc
@@ -0,0 +1,247 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_by_account_by_event_name("
+ "USER CHAR(16) collate utf8_bin default null,"
+ "HOST CHAR(60) collate utf8_bin default null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null)") }
+};
+
+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..b46008e2675
--- /dev/null
+++ b/storage/perfschema/table_ews_by_account_by_event_name.h
@@ -0,0 +1,134 @@
+/* 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** 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..e82c734431c
--- /dev/null
+++ b/storage/perfschema/table_ews_by_host_by_event_name.cc
@@ -0,0 +1,248 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_by_host_by_event_name("
+ "HOST CHAR(60) collate utf8_bin default null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null)") }
+};
+
+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..c631da36ec5
--- /dev/null
+++ b/storage/perfschema/table_ews_by_host_by_event_name.h
@@ -0,0 +1,134 @@
+/* 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** 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..7b3e220e973
--- /dev/null
+++ b/storage/perfschema/table_ews_by_thread_by_event_name.cc
@@ -0,0 +1,262 @@
+/* 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-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_by_thread_by_event_name("
+ "THREAD_ID BIGINT unsigned not null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null)") }
+};
+
+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..cf94e7a81a2
--- /dev/null
+++ b/storage/perfschema/table_ews_by_thread_by_event_name.h
@@ -0,0 +1,133 @@
+/* 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-1335 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;
+
+ /** 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..577a9ef6676
--- /dev/null
+++ b/storage/perfschema/table_ews_by_user_by_event_name.cc
@@ -0,0 +1,248 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_by_user_by_event_name("
+ "USER CHAR(16) collate utf8_bin default null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null)") }
+};
+
+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..e987cf1bcec
--- /dev/null
+++ b/storage/perfschema/table_ews_by_user_by_event_name.h
@@ -0,0 +1,134 @@
+/* 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** Current row. */
+ row_ews_by_user_by_event_name m_row;
+ /** True is the current row exists. */
+ bool m_row_exists;
+ /** Current position. */
+ pos_ews_by_user_by_event_name m_pos;
+ /** Next position. */
+ pos_ews_by_user_by_event_name m_next_pos;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_ews_global_by_event_name.cc b/storage/perfschema/table_ews_global_by_event_name.cc
index cf33c4484e1..9a5ba4f2375 100644
--- a/storage/perfschema/table_ews_global_by_event_name.cc
+++ b/storage/perfschema/table_ews_global_by_event_name.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,96 +25,330 @@
#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,
+ table_ews_global_by_event_name::create,
NULL, /* write_row */
- &table_ews_global_by_event_name::delete_all_rows,
+ table_ews_global_by_event_name::delete_all_rows,
+ NULL, /* get_row_count */
1000, /* records */
- sizeof(pos_all_instr_class),
+ sizeof(pos_ews_global_by_event_name),
&m_table_lock,
- &m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_global_by_event_name("
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null)") }
};
-PFS_engine_table* table_ews_global_by_event_name::create(void)
+PFS_engine_table*
+table_ews_global_by_event_name::create(void)
{
return new table_ews_global_by_event_name();
}
-int table_ews_global_by_event_name::delete_all_rows(void)
+int
+table_ews_global_by_event_name::delete_all_rows(void)
{
- reset_instrument_class_waits();
+ reset_events_waits_by_instance();
+ reset_table_waits_by_table_handle();
+ reset_table_waits_by_table();
+ reset_events_waits_by_class();
return 0;
}
-table_ews_global_by_event_name
-::table_ews_global_by_event_name()
- : table_all_instr_class(&m_share)
+table_ews_global_by_event_name::table_ews_global_by_event_name()
+ : PFS_engine_table(&m_share, &m_pos),
+ m_row_exists(false), m_pos(), m_next_pos()
{}
-void table_ews_global_by_event_name
-::make_instr_row(PFS_instr_class *klass)
+void table_ews_global_by_event_name::reset_position(void)
{
- m_row.m_name= klass->m_name;
- m_row.m_name_length= klass->m_name_length;
+ m_pos.reset();
+ m_next_pos.reset();
+}
- m_row.m_count= klass->m_wait_stat.m_count;
- m_row.m_sum= klass->m_wait_stat.m_sum;
- m_row.m_min= klass->m_wait_stat.m_min;
- m_row.m_max= klass->m_wait_stat.m_max;
+int table_ews_global_by_event_name::rnd_next(void)
+{
+ PFS_mutex_class *mutex_class;
+ PFS_rwlock_class *rwlock_class;
+ PFS_cond_class *cond_class;
+ PFS_file_class *file_class;
+ PFS_socket_class *socket_class;
+ PFS_instr_class *instr_class;
- if (m_row.m_count)
- m_row.m_avg= m_row.m_sum / m_row.m_count;
- else
+ for (m_pos.set_at(&m_next_pos);
+ m_pos.has_more_view();
+ m_pos.next_view())
{
- m_row.m_min= 0;
- m_row.m_avg= 0;
+ 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
@@ -123,40 +357,24 @@ int table_ews_global_by_event_name
{
Field *f;
+ if (unlikely(! m_row_exists))
+ return HA_ERR_RECORD_DELETED;
+
/* Set the null bits */
DBUG_ASSERT(table->s->null_bytes == 0);
- /*
- The row always exist,
- the instrument classes are static and never disappear.
- */
-
for (; (f= *fields) ; fields++)
{
if (read_all || bitmap_is_set(table->read_set, f->field_index))
{
switch(f->field_index)
{
- case 0: /* NAME */
- set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
- break;
- case 1: /* COUNT */
- set_field_ulonglong(f, m_row.m_count);
- break;
- case 2: /* SUM */
- set_field_ulonglong(f, m_row.m_sum);
- break;
- case 3: /* MIN */
- set_field_ulonglong(f, m_row.m_min);
- break;
- case 4: /* AVG */
- set_field_ulonglong(f, m_row.m_avg);
+ case 0: /* EVENT_NAME */
+ m_row.m_event_name.set_field(f);
break;
- case 5: /* MAX */
- set_field_ulonglong(f, m_row.m_max);
+ default: /* 1, ... COUNT/SUM/MIN/AVG/MAX */
+ m_row.m_stat.set_field(f->field_index - 1, f);
break;
- default:
- DBUG_ASSERT(false);
}
}
}
diff --git a/storage/perfschema/table_ews_global_by_event_name.h b/storage/perfschema/table_ews_global_by_event_name.h
index ae4876b8874..57e3459e373 100644
--- a/storage/perfschema/table_ews_global_by_event_name.h
+++ b/storage/perfschema/table_ews_global_by_event_name.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -13,8 +13,8 @@
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
-#ifndef TABLE_EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME_H
-#define TABLE_EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME_H
+#ifndef TABLE_EWS_GLOBAL_BY_EVENT_NAME_H
+#define TABLE_EWS_GLOBAL_BY_EVENT_NAME_H
/**
@file storage/perfschema/table_ews_global_by_event_name.h
@@ -25,34 +25,56 @@
#include "pfs_engine_table.h"
#include "pfs_instr_class.h"
#include "pfs_instr.h"
-#include "table_all_instr.h"
+#include "table_helper.h"
/**
@addtogroup Performance_schema_tables
@{
*/
-/** A row of PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME. */
+/**
+ A row of table
+ PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME.
+*/
struct row_ews_global_by_event_name
{
/** Column EVENT_NAME. */
- const char *m_name;
- /** Length in bytes of @c m_name. */
- uint m_name_length;
- /** Column COUNT_STAR. */
- ulonglong m_count;
- /** Column SUM_TIMER_WAIT. */
- ulonglong m_sum;
- /** Column MIN_TIMER_WAIT. */
- ulonglong m_min;
- /** Column AVG_TIMER_WAIT. */
- ulonglong m_avg;
- /** Column MAX_TIMER_WAIT. */
- ulonglong m_max;
+ PFS_event_name_row m_event_name;
+ /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */
+ PFS_stat_row m_stat;
+};
+
+/**
+ Position of a cursor on
+ PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME.
+ Index 1 on instrument view
+ Index 2 on instrument class (1 based)
+*/
+struct pos_ews_global_by_event_name
+: public PFS_double_index, public PFS_instrument_view_constants
+{
+ pos_ews_global_by_event_name()
+ : PFS_double_index(FIRST_VIEW, 1)
+ {}
+
+ inline void reset(void)
+ {
+ m_index_1= FIRST_VIEW;
+ m_index_2= 1;
+ }
+
+ inline bool has_more_view(void)
+ { return (m_index_1 <= LAST_VIEW); }
+
+ inline void next_view(void)
+ {
+ m_index_1++;
+ m_index_2= 1;
+ }
};
/** Table PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME. */
-class table_ews_global_by_event_name : public table_all_instr_class
+class table_ews_global_by_event_name : public PFS_engine_table
{
public:
/** Table share */
@@ -60,9 +82,11 @@ public:
static PFS_engine_table* create();
static int delete_all_rows();
-protected:
- virtual void make_instr_row(PFS_instr_class *klass);
+ virtual int rnd_next();
+ virtual int rnd_pos(const void *pos);
+ virtual void reset_position(void);
+protected:
virtual int read_row_values(TABLE *table,
unsigned char *buf,
Field **fields,
@@ -74,14 +98,28 @@ 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;
};
/** @} */
diff --git a/storage/perfschema/table_file_instances.cc b/storage/perfschema/table_file_instances.cc
index 023f65ad7b7..7914664e2e0 100644
--- a/storage/perfschema/table_file_instances.cc
+++ b/storage/perfschema/table_file_instances.cc
@@ -28,29 +28,6 @@
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=
{
@@ -59,11 +36,14 @@ table_file_instances::m_share=
&table_file_instances::create,
NULL, /* write_row */
NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
1000, /* records */
sizeof(PFS_simple_index),
&m_table_lock,
- &m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE file_instances("
+ "FILE_NAME VARCHAR(512) not null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "OPEN_COUNT INTEGER unsigned not null)") }
};
PFS_engine_table* table_file_instances::create(void)
diff --git a/storage/perfschema/table_file_instances.h b/storage/perfschema/table_file_instances.h
index 63f2a3cdcc0..e07017911de 100644
--- a/storage/perfschema/table_file_instances.h
+++ b/storage/perfschema/table_file_instances.h
@@ -73,12 +73,10 @@ private:
/** 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 is the current row exists. */
+ /** True if the current row exists. */
bool m_row_exists;
/** Current position. */
PFS_simple_index m_pos;
diff --git a/storage/perfschema/table_file_summary.cc b/storage/perfschema/table_file_summary.cc
deleted file mode 100644
index 0afd8071e19..00000000000
--- a/storage/perfschema/table_file_summary.cc
+++ /dev/null
@@ -1,372 +0,0 @@
-/* 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, Fifth Floor, Boston, MA 02110-1335 USA */
-
-/**
- @file storage/perfschema/table_file_summary.cc
- Table FILE_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_file_summary.h"
-#include "pfs_global.h"
-
-THR_LOCK table_file_summary_by_event_name::m_table_lock;
-
-static const TABLE_FIELD_TYPE fs_by_event_name_field_types[]=
-{
- {
- { C_STRING_WITH_LEN("EVENT_NAME") },
- { C_STRING_WITH_LEN("varchar(128)") },
- { NULL, 0}
- },
- {
- { C_STRING_WITH_LEN("COUNT_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_NUMBER_OF_BYTES_READ") },
- { 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}
- }
-};
-
-TABLE_FIELD_DEF
-table_file_summary_by_event_name::m_field_def=
-{ 5, fs_by_event_name_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,
- 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_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 *klass)
-{
- m_row.m_name= &klass->m_name[0];
- m_row.m_name_length= klass->m_name_length;
- m_row.m_file_stat= klass->m_file_stat;
-}
-
-int table_file_summary_by_event_name::read_row_values(TABLE *table,
- unsigned char *,
- Field **fields,
- bool read_all)
-{
- Field *f;
-
- /* Set the null bits */
- DBUG_ASSERT(table->s->null_bytes == 0);
-
- /* The row always exists for classes */
-
- for (; (f= *fields) ; fields++)
- {
- if (read_all || bitmap_is_set(table->read_set, f->field_index))
- {
- switch(f->field_index)
- {
- case 0: /* NAME */
- set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
- break;
- case 1: /* COUNT_READ */
- set_field_ulonglong(f, m_row.m_file_stat.m_count_read);
- break;
- case 2: /* COUNT_WRITE */
- set_field_ulonglong(f, m_row.m_file_stat.m_count_write);
- break;
- case 3: /* READ_BYTES */
- set_field_ulonglong(f, m_row.m_file_stat.m_read_bytes);
- break;
- case 4: /* WRITE_BYTES */
- set_field_ulonglong(f, m_row.m_file_stat.m_write_bytes);
- break;
- default:
- DBUG_ASSERT(false);
- }
- }
- }
-
- return 0;
-}
-
-THR_LOCK table_file_summary_by_instance::m_table_lock;
-
-static const TABLE_FIELD_TYPE fs_by_instance_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("COUNT_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_NUMBER_OF_BYTES_READ") },
- { 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}
- }
-};
-
-TABLE_FIELD_DEF
-table_file_summary_by_instance::m_field_def=
-{ 6, fs_by_instance_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,
- 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_name= safe_class->m_name;
- m_row.m_name_length= safe_class->m_name_length;
- m_row.m_file_stat= pfs->m_file_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: /* FILENAME */
- set_field_varchar_utf8(f, m_row.m_filename, m_row.m_filename_length);
- break;
- case 1: /* NAME */
- set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
- break;
- case 2: /* COUNT_READ */
- set_field_ulonglong(f, m_row.m_file_stat.m_count_read);
- break;
- case 3: /* COUNT_WRITE */
- set_field_ulonglong(f, m_row.m_file_stat.m_count_write);
- break;
- case 4: /* READ_BYTES */
- set_field_ulonglong(f, m_row.m_file_stat.m_read_bytes);
- break;
- case 5: /* WRITE_BYTES */
- set_field_ulonglong(f, m_row.m_file_stat.m_write_bytes);
- break;
- default:
- DBUG_ASSERT(false);
- }
- }
- }
-
- return 0;
-}
-
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..e98bc528995
--- /dev/null
+++ b/storage/perfschema/table_file_summary_by_event_name.cc
@@ -0,0 +1,245 @@
+/* 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, Fifth Floor, 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE file_summary_by_event_name("
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "COUNT_READ BIGINT unsigned not null,"
+ "SUM_TIMER_READ BIGINT unsigned not null,"
+ "MIN_TIMER_READ BIGINT unsigned not null,"
+ "AVG_TIMER_READ BIGINT unsigned not null,"
+ "MAX_TIMER_READ BIGINT unsigned not null,"
+ "SUM_NUMBER_OF_BYTES_READ BIGINT not null,"
+ "COUNT_WRITE BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE BIGINT unsigned not null,"
+ "SUM_NUMBER_OF_BYTES_WRITE BIGINT not null,"
+ "COUNT_MISC BIGINT unsigned not null,"
+ "SUM_TIMER_MISC BIGINT unsigned not null,"
+ "MIN_TIMER_MISC BIGINT unsigned not null,"
+ "AVG_TIMER_MISC BIGINT unsigned not null,"
+ "MAX_TIMER_MISC BIGINT unsigned not null)") }
+};
+
+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.h b/storage/perfschema/table_file_summary_by_event_name.h
index 733e654cb2c..7a13fcdc4d9 100644
--- a/storage/perfschema/table_file_summary.h
+++ b/storage/perfschema/table_file_summary_by_event_name.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,14 +17,15 @@
#define TABLE_FILE_SUMMARY_H
/**
- @file storage/perfschema/table_file_summary.h
- Table FILE_SUMMARY_BY_xxx (declarations).
+ @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
@@ -35,14 +36,12 @@
struct row_file_summary_by_event_name
{
/** Column EVENT_NAME. */
- const char *m_name;
- /** Length in bytes of @c m_name. */
- uint m_name_length;
- /**
- Columns COUNT_READ, COUNT_WRITE,
- SUM_NUMBER_OF_BYTES_READ, SUM_NUMBER_OF_BYTES_WRITE.
+ 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_stat m_file_stat;
+ PFS_file_io_stat_row m_io_stat;
};
/** Table PERFORMANCE_SCHEMA.FILE_SUMMARY_BY_EVENT_NAME. */
@@ -58,9 +57,7 @@ public:
virtual int rnd_pos(const void *pos);
virtual void reset_position(void);
-protected:
- void make_row(PFS_file_class *klass);
-
+private:
virtual int read_row_values(TABLE *table,
unsigned char *buf,
Field **fields,
@@ -73,73 +70,14 @@ public:
{}
private:
- /** 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;
- /** Current position. */
- PFS_simple_index m_pos;
- /** Next position. */
- PFS_simple_index m_next_pos;
-};
-
-/** 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. */
- const char *m_name;
- /** Length in bytes of @c m_name. */
- uint m_name_length;
- /**
- Columns COUNT_READ, COUNT_WRITE,
- SUM_NUMBER_OF_BYTES_READ, SUM_NUMBER_OF_BYTES_WRITE.
- */
- PFS_file_stat m_file_stat;
-};
-
-/** Table PERFORMANCE_SCHEMA.FILE_UMMARY_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);
-
-protected:
- void make_row(PFS_file *pfs);
-
- 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()
- {}
+ void make_row(PFS_file_class *klass);
-private:
/** Table share lock. */
static THR_LOCK m_table_lock;
- /** Fields definition. */
- static TABLE_FIELD_DEF m_field_def;
/** Current row. */
- row_file_summary_by_instance m_row;
- /** True is the current row exists. */
+ 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;
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..b80811d0a5b
--- /dev/null
+++ b/storage/perfschema/table_file_summary_by_instance.cc
@@ -0,0 +1,266 @@
+/* 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, Fifth Floor, 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE file_summary_by_instance("
+ "FILE_NAME VARCHAR(512) not null,"
+ "EVENT_NAME VARCHAR(128) not null,"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "COUNT_READ BIGINT unsigned not null,"
+ "SUM_TIMER_READ BIGINT unsigned not null,"
+ "MIN_TIMER_READ BIGINT unsigned not null,"
+ "AVG_TIMER_READ BIGINT unsigned not null,"
+ "MAX_TIMER_READ BIGINT unsigned not null,"
+ "SUM_NUMBER_OF_BYTES_READ BIGINT not null,"
+ "COUNT_WRITE BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE BIGINT unsigned not null,"
+ "SUM_NUMBER_OF_BYTES_WRITE BIGINT not null,"
+ "COUNT_MISC BIGINT unsigned not null,"
+ "SUM_TIMER_MISC BIGINT unsigned not null,"
+ "MIN_TIMER_MISC BIGINT unsigned not null,"
+ "AVG_TIMER_MISC BIGINT unsigned not null,"
+ "MAX_TIMER_MISC BIGINT unsigned not null)") }
+};
+
+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..872698f8e58
--- /dev/null
+++ b/storage/perfschema/table_file_summary_by_instance.h
@@ -0,0 +1,97 @@
+/* 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, Fifth Floor, 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;
+
+ /** 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..0dbeeb259c1
--- /dev/null
+++ b/storage/perfschema/table_helper.cc
@@ -0,0 +1,360 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 Street, Fifth Floor, Boston, MA 02110-1335 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"
+#include "pfs_instr.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)
+{
+ m_schema_name_length= pfs->m_digest_key.m_schema_name_length;
+ if (m_schema_name_length > sizeof(m_schema_name))
+ m_schema_name_length= 0;
+ if (m_schema_name_length > 0)
+ memcpy(m_schema_name, pfs->m_digest_key.m_schema_name, m_schema_name_length);
+
+ size_t safe_byte_count= pfs->m_digest_storage.m_byte_count;
+ if (safe_byte_count > pfs_max_digest_length)
+ safe_byte_count= 0;
+
+ /*
+ "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 (safe_byte_count > 0)
+ {
+ /*
+ Calculate digest from MD5 HASH collected to be shown as
+ DIGEST in this row.
+ */
+ MD5_HASH_TO_STRING(pfs->m_digest_storage.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.
+ */
+ compute_digest_text(&pfs->m_digest_storage, &m_digest_text);
+
+ if (m_digest_text.length() == 0)
+ m_digest_length= 0;
+ }
+ else
+ {
+ m_digest_length= 0;
+ m_digest_text.length(0);
+ }
+
+ return 0;
+}
+
+void PFS_digest_row::set_field(uint index, Field *f)
+{
+ switch (index)
+ {
+ case 0: /* 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.ptr(),
+ 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..b57abe9c4e6
--- /dev/null
+++ b/storage/perfschema/table_helper.h
@@ -0,0 +1,520 @@
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 Street, Fifth Floor, Boston, MA 02110-1335 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. */
+ String m_digest_text;
+
+ /** 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 != 0) && stat->has_timed_stats())
+ {
+ 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_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;
+ }
+
+ /** 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..758a2c6dea6
--- /dev/null
+++ b/storage/perfschema/table_host_cache.cc
@@ -0,0 +1,353 @@
+/* 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, Fifth Floor, 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE host_cache("
+ "IP VARCHAR(64) not null,"
+ "HOST VARCHAR(255) collate utf8_bin,"
+ "HOST_VALIDATED ENUM ('YES', 'NO') not null,"
+ "SUM_CONNECT_ERRORS BIGINT not null,"
+ "COUNT_HOST_BLOCKED_ERRORS BIGINT not null,"
+ "COUNT_NAMEINFO_TRANSIENT_ERRORS BIGINT not null,"
+ "COUNT_NAMEINFO_PERMANENT_ERRORS BIGINT not null,"
+ "COUNT_FORMAT_ERRORS BIGINT not null,"
+ "COUNT_ADDRINFO_TRANSIENT_ERRORS BIGINT not null,"
+ "COUNT_ADDRINFO_PERMANENT_ERRORS BIGINT not null,"
+ "COUNT_FCRDNS_ERRORS BIGINT not null,"
+ "COUNT_HOST_ACL_ERRORS BIGINT not null,"
+ "COUNT_NO_AUTH_PLUGIN_ERRORS BIGINT not null,"
+ "COUNT_AUTH_PLUGIN_ERRORS BIGINT not null,"
+ "COUNT_HANDSHAKE_ERRORS BIGINT not null,"
+ "COUNT_PROXY_USER_ERRORS BIGINT not null,"
+ "COUNT_PROXY_USER_ACL_ERRORS BIGINT not null,"
+ "COUNT_AUTHENTICATION_ERRORS BIGINT not null,"
+ "COUNT_SSL_ERRORS BIGINT not null,"
+ "COUNT_MAX_USER_CONNECTIONS_ERRORS BIGINT not null,"
+ "COUNT_MAX_USER_CONNECTIONS_PER_HOUR_ERRORS BIGINT not null,"
+ "COUNT_DEFAULT_DATABASE_ERRORS BIGINT not null,"
+ "COUNT_INIT_CONNECT_ERRORS BIGINT not null,"
+ "COUNT_LOCAL_ERRORS BIGINT not null,"
+ "COUNT_UNKNOWN_ERRORS BIGINT not null,"
+ "FIRST_SEEN TIMESTAMP(0) NOT NULL default 0,"
+ "LAST_SEEN TIMESTAMP(0) NOT NULL default 0,"
+ "FIRST_ERROR_SEEN TIMESTAMP(0) null default 0,"
+ "LAST_ERROR_SEEN TIMESTAMP(0) null default 0)") }
+};
+
+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..47abb42444e
--- /dev/null
+++ b/storage/perfschema/table_host_cache.h
@@ -0,0 +1,142 @@
+/* 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, Fifth Floor, 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;
+
+ 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..2c5377db4ac
--- /dev/null
+++ b/storage/perfschema/table_hosts.cc
@@ -0,0 +1,126 @@
+/* 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, Fifth Floor, 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE hosts("
+ "HOST CHAR(60) collate utf8_bin default null,"
+ "CURRENT_CONNECTIONS bigint not null,"
+ "TOTAL_CONNECTIONS bigint not null)") }
+};
+
+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..60b70ae803e
--- /dev/null
+++ b/storage/perfschema/table_hosts.h
@@ -0,0 +1,78 @@
+/* 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, Fifth Floor, 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;
+
+ /** 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..cd2ace50c85
--- /dev/null
+++ b/storage/perfschema/table_os_global_by_type.cc
@@ -0,0 +1,234 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE objects_summary_global_by_type("
+ "OBJECT_TYPE VARCHAR(64),"
+ "OBJECT_SCHEMA VARCHAR(64),"
+ "OBJECT_NAME VARCHAR(64),"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null)") }
+};
+
+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..a434961b65b
--- /dev/null
+++ b/storage/perfschema/table_os_global_by_type.h
@@ -0,0 +1,128 @@
+/* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** Current row. */
+ row_os_global_by_type m_row;
+ /** True is the current row exists. */
+ bool m_row_exists;
+ /** Current position. */
+ pos_os_global_by_type m_pos;
+ /** Next position. */
+ pos_os_global_by_type m_next_pos;
+};
+
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_performance_timers.cc b/storage/perfschema/table_performance_timers.cc
index 59096267286..8d31c017832 100644
--- a/storage/perfschema/table_performance_timers.cc
+++ b/storage/perfschema/table_performance_timers.cc
@@ -26,35 +26,6 @@
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=
{
@@ -63,11 +34,15 @@ table_performance_timers::m_share=
&table_performance_timers::create,
NULL, /* write_row */
NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
COUNT_TIMER_NAME, /* records */
sizeof(PFS_simple_index), /* ref length */
&m_table_lock,
- &m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE performance_timers("
+ "TIMER_NAME ENUM ('CYCLE', 'NANOSECOND', 'MICROSECOND', 'MILLISECOND', 'TICK') not null,"
+ "TIMER_FREQUENCY BIGINT,"
+ "TIMER_RESOLUTION BIGINT,"
+ "TIMER_OVERHEAD BIGINT)") }
};
PFS_engine_table* table_performance_timers::create(void)
@@ -83,23 +58,23 @@ table_performance_timers::table_performance_timers()
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;
+ m_data[index].m_info= sys_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;
+ m_data[index].m_info= sys_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;
+ m_data[index].m_info= sys_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;
+ m_data[index].m_info= sys_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;
+ m_data[index].m_info= sys_timer_info.ticks;
}
void table_performance_timers::reset_position(void)
diff --git a/storage/perfschema/table_performance_timers.h b/storage/perfschema/table_performance_timers.h
index 475fa762071..e1dc93fcbe4 100644
--- a/storage/perfschema/table_performance_timers.h
+++ b/storage/perfschema/table_performance_timers.h
@@ -70,8 +70,6 @@ public:
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;
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..c00f72e36b4
--- /dev/null
+++ b/storage/perfschema/table_session_account_connect_attrs.cc
@@ -0,0 +1,74 @@
+/* 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, Fifth Floor, 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,
+ { C_STRING_WITH_LEN("CREATE TABLE session_account_connect_attrs("
+ "PROCESSLIST_ID INT NOT NULL,"
+ "ATTR_NAME VARCHAR(32) NOT NULL,"
+ "ATTR_VALUE VARCHAR(1024),"
+ "ORDINAL_POSITION INT"
+ ") CHARACTER SET utf8 COLLATE utf8_bin") }
+};
+
+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..d56d571fb79
--- /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, Fifth Floor, 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..737ff514555
--- /dev/null
+++ b/storage/perfschema/table_session_connect.cc
@@ -0,0 +1,286 @@
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "table_session_connect.h"
+
+table_session_connect::table_session_connect(const PFS_engine_table_share *share)
+ : cursor_by_thread_connect_attr(share)
+{
+ if (session_connect_attrs_size_per_thread > 0)
+ {
+ m_copy_session_connect_attrs= (char *) my_malloc(/* 5.7: PSI_INSTRUMENT_ME, */
+ session_connect_attrs_size_per_thread,
+ MYF(0));
+ }
+ else
+ {
+ m_copy_session_connect_attrs= NULL;
+ }
+ m_copy_session_connect_attrs_length= 0;
+}
+
+table_session_connect::~table_session_connect()
+{
+ my_free(m_copy_session_connect_attrs);
+}
+
+/**
+ 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;
+ String_copier copier;
+
+ 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= copier.well_formed_copy(&my_charset_utf8_bin, dest, dest_size,
+ from_cs, *ptr, data_length, nchars_max);
+ *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_lock session_lock;
+ PFS_thread_class *safe_class;
+ const CHARSET_INFO *cs;
+
+ m_row_exists= false;
+
+ /* Protect this reader against thread termination */
+ pfs->m_lock.begin_optimistic_lock(&lock);
+ /* Protect this reader against writing on session attributes */
+ pfs->m_session_lock.begin_optimistic_lock(&session_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;
+
+ /* Make a safe copy of the session attributes */
+
+ if (m_copy_session_connect_attrs == NULL)
+ return;
+
+ m_copy_session_connect_attrs_length= pfs->m_session_connect_attrs_length;
+
+ if (m_copy_session_connect_attrs_length > session_connect_attrs_size_per_thread)
+ return;
+
+ memcpy(m_copy_session_connect_attrs,
+ pfs->m_session_connect_attrs,
+ m_copy_session_connect_attrs_length);
+
+ cs= get_charset(pfs->m_session_connect_attrs_cs_number, MYF(0));
+ if (cs == NULL)
+ return;
+
+ if (! pfs->m_session_lock.end_optimistic_lock(& session_lock))
+ return;
+
+ if (! pfs->m_lock.end_optimistic_lock(& lock))
+ return;
+
+ /*
+ Now we have a safe copy of the data,
+ that will not change while parsing it
+ */
+
+ /* populate the row */
+ if (read_nth_attr(m_copy_session_connect_attrs,
+ m_copy_session_connect_attrs_length,
+ 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 */
+ if (pfs->m_processlist_id == 0)
+ return;
+
+ m_row.m_ordinal_position= ordinal;
+ m_row.m_process_id= pfs->m_processlist_id;
+
+ 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..91d24ab7075
--- /dev/null
+++ b/storage/perfschema/table_session_connect.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2012, 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, Fifth Floor, 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:
+ /** Current row. */
+ row_session_connect_attrs m_row;
+ /** Safe copy of @c PFS_thread::m_session_connect_attrs. */
+ char *m_copy_session_connect_attrs;
+ /** Safe copy of @c PFS_thread::m_session_connect_attrs_length. */
+ uint m_copy_session_connect_attrs_length;
+};
+
+/** @} */
+#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..859c6f2f8b8
--- /dev/null
+++ b/storage/perfschema/table_session_connect_attrs.cc
@@ -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, Fifth Floor, 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,
+ { C_STRING_WITH_LEN("CREATE TABLE session_connect_attrs("
+ "PROCESSLIST_ID INT NOT NULL,"
+ "ATTR_NAME VARCHAR(32) NOT NULL,"
+ "ATTR_VALUE VARCHAR(1024),"
+ "ORDINAL_POSITION INT"
+ ") CHARACTER SET utf8 COLLATE utf8_bin") }
+};
+
+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..de18085d8ac
--- /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, Fifth Floor, 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..fcb32b9cb35
--- /dev/null
+++ b/storage/perfschema/table_setup_actors.cc
@@ -0,0 +1,258 @@
+/* Copyright (c) 2010, 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, Fifth Floor, 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE setup_actors("
+ "HOST CHAR(60) collate utf8_bin default '%' not null,"
+ "USER CHAR(16) collate utf8_bin default '%' not null,"
+ "ROLE CHAR(16) collate utf8_bin default '%' not null)") }
+};
+
+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..550e196c8d1
--- /dev/null
+++ b/storage/perfschema/table_setup_actors.h
@@ -0,0 +1,104 @@
+/* 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, Fifth Floor, 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;
+
+ /** Current row. */
+ row_setup_actors m_row;
+ /** True if the current row exists. */
+ bool m_row_exists;
+ /** Current position. */
+ PFS_simple_index m_pos;
+ /** Next position. */
+ PFS_simple_index m_next_pos;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_setup_consumers.cc b/storage/perfschema/table_setup_consumers.cc
index 0288e827b5e..f00e1fff48d 100644
--- a/storage/perfschema/table_setup_consumers.cc
+++ b/storage/perfschema/table_setup_consumers.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,63 +23,74 @@
#include "table_setup_consumers.h"
#include "pfs_instr.h"
#include "pfs_events_waits.h"
+#include "pfs_digest.h"
-#define COUNT_SETUP_CONSUMERS 8
+#define COUNT_SETUP_CONSUMERS 12
static row_setup_consumers all_setup_consumers_data[COUNT_SETUP_CONSUMERS]=
{
{
- { C_STRING_WITH_LEN("events_waits_current") },
- &flag_events_waits_current
+ { C_STRING_WITH_LEN("events_stages_current") },
+ &flag_events_stages_current,
+ false
},
{
- { C_STRING_WITH_LEN("events_waits_history") },
- &flag_events_waits_history
+ { C_STRING_WITH_LEN("events_stages_history") },
+ &flag_events_stages_history,
+ false
},
{
- { C_STRING_WITH_LEN("events_waits_history_long") },
- &flag_events_waits_history_long
+ { C_STRING_WITH_LEN("events_stages_history_long") },
+ &flag_events_stages_history_long,
+ false
},
{
- { C_STRING_WITH_LEN("events_waits_summary_by_thread_by_event_name") },
- &flag_events_waits_summary_by_thread_by_event_name
+ { C_STRING_WITH_LEN("events_statements_current") },
+ &flag_events_statements_current,
+ false
},
{
- { C_STRING_WITH_LEN("events_waits_summary_by_event_name") },
- &flag_events_waits_summary_by_event_name
+ { C_STRING_WITH_LEN("events_statements_history") },
+ &flag_events_statements_history,
+ false
},
{
- { C_STRING_WITH_LEN("events_waits_summary_by_instance") },
- &flag_events_waits_summary_by_instance
+ { C_STRING_WITH_LEN("events_statements_history_long") },
+ &flag_events_statements_history_long,
+ false
},
{
- { C_STRING_WITH_LEN("file_summary_by_event_name") },
- &flag_file_summary_by_event_name
+ { C_STRING_WITH_LEN("events_waits_current") },
+ &flag_events_waits_current,
+ false
},
{
- { C_STRING_WITH_LEN("file_summary_by_instance") },
- &flag_file_summary_by_instance
- }
-};
-
-THR_LOCK table_setup_consumers::m_table_lock;
-
-static const TABLE_FIELD_TYPE field_types[]=
-{
+ { 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("NAME") },
- { C_STRING_WITH_LEN("varchar(64)") },
- { NULL, 0}
+ { C_STRING_WITH_LEN("global_instrumentation") },
+ &flag_global_instrumentation,
+ true
},
{
- { C_STRING_WITH_LEN("ENABLED") },
- { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") },
- { NULL, 0}
+ { C_STRING_WITH_LEN("thread_instrumentation") },
+ &flag_thread_instrumentation,
+ false
+ },
+ {
+ { C_STRING_WITH_LEN("statements_digest") },
+ &flag_statements_digest,
+ false
}
};
-TABLE_FIELD_DEF
-table_setup_consumers::m_field_def=
-{ 2, field_types };
+THR_LOCK table_setup_consumers::m_table_lock;
PFS_engine_table_share
table_setup_consumers::m_share=
@@ -89,11 +100,13 @@ table_setup_consumers::m_share=
&table_setup_consumers::create,
NULL, /* write_row */
NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
COUNT_SETUP_CONSUMERS, /* records */
sizeof(PFS_simple_index), /* ref length */
&m_table_lock,
- &m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE setup_consumers("
+ "NAME VARCHAR(64) not null,"
+ "ENABLED ENUM ('YES', 'NO') not null)") }
};
PFS_engine_table* table_setup_consumers::create(void)
@@ -205,6 +218,9 @@ int table_setup_consumers::update_row_values(TABLE *table,
}
}
+ if (m_row->m_refresh)
+ update_instruments_derived_flags();
+
return 0;
}
diff --git a/storage/perfschema/table_setup_consumers.h b/storage/perfschema/table_setup_consumers.h
index 33e4cc20f2a..b27c8873550 100644
--- a/storage/perfschema/table_setup_consumers.h
+++ b/storage/perfschema/table_setup_consumers.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc.
- Use is subject to license terms.
+/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -37,6 +36,8 @@ struct row_setup_consumers
LEX_STRING m_name;
/** Column ENABLED. */
bool *m_enabled_ptr;
+ /** Hidden column, refresh. */
+ bool m_refresh;
};
/** Table PERFORMANCE_SCHEMA.SETUP_CONSUMERS. */
@@ -71,8 +72,6 @@ public:
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;
diff --git a/storage/perfschema/table_setup_instruments.cc b/storage/perfschema/table_setup_instruments.cc
index 59e25c72eb1..8adea1d3604 100644
--- a/storage/perfschema/table_setup_instruments.cc
+++ b/storage/perfschema/table_setup_instruments.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,36 +21,15 @@
#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=
{
@@ -59,11 +38,14 @@ table_setup_instruments::m_share=
&table_setup_instruments::create,
NULL, /* write_row */
NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
1000, /* records */
sizeof(pos_setup_instruments),
&m_table_lock,
- &m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE setup_instruments("
+ "NAME VARCHAR(128) not null,"
+ "ENABLED ENUM ('YES', 'NO') not null,"
+ "TIMED ENUM ('YES', 'NO') not null)") }
};
PFS_engine_table* table_setup_instruments::create(void)
@@ -84,55 +66,54 @@ void table_setup_instruments::reset_position(void)
int table_setup_instruments::rnd_next(void)
{
- PFS_mutex_class *mutex_class;
- PFS_rwlock_class *rwlock_class;
- PFS_cond_class *cond_class;
- PFS_file_class *file_class;
+ PFS_instr_class *instr_class= NULL;
+
+ /* Do not advertise hard coded instruments when disabled. */
+ if (! pfs_initialized)
+ return HA_ERR_END_OF_FILE;
for (m_pos.set_at(&m_next_pos);
m_pos.has_more_view();
m_pos.next_view())
{
- switch (m_pos.m_index_1) {
+ switch (m_pos.m_index_1)
+ {
case pos_setup_instruments::VIEW_MUTEX:
- mutex_class= find_mutex_class(m_pos.m_index_2);
- if (mutex_class)
- {
- make_row(mutex_class);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
+ instr_class= find_mutex_class(m_pos.m_index_2);
break;
case pos_setup_instruments::VIEW_RWLOCK:
- rwlock_class= find_rwlock_class(m_pos.m_index_2);
- if (rwlock_class)
- {
- make_row(rwlock_class);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
+ instr_class= find_rwlock_class(m_pos.m_index_2);
break;
case pos_setup_instruments::VIEW_COND:
- cond_class= find_cond_class(m_pos.m_index_2);
- if (cond_class)
- {
- make_row(cond_class);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
+ instr_class= find_cond_class(m_pos.m_index_2);
break;
case pos_setup_instruments::VIEW_THREAD:
- /* Reserved for WL#4674, PERFORMANCE_SCHEMA Setup For Actors. */
+ /* Not used yet */
break;
case pos_setup_instruments::VIEW_FILE:
- file_class= find_file_class(m_pos.m_index_2);
- if (file_class)
- {
- make_row(file_class);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
+ instr_class= find_file_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_TABLE:
+ instr_class= find_table_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_STAGE:
+ instr_class= find_stage_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_STATEMENT:
+ instr_class= find_statement_class(m_pos.m_index_2);
break;
+ case pos_setup_instruments::VIEW_SOCKET:
+ instr_class= find_socket_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_IDLE:
+ instr_class= find_idle_class(m_pos.m_index_2);
+ break;
+ }
+ if (instr_class)
+ {
+ make_row(instr_class);
+ m_next_pos.set_after(&m_pos);
+ return 0;
}
}
@@ -141,49 +122,51 @@ int table_setup_instruments::rnd_next(void)
int table_setup_instruments::rnd_pos(const void *pos)
{
- PFS_mutex_class *mutex_class;
- PFS_rwlock_class *rwlock_class;
- PFS_cond_class *cond_class;
- PFS_file_class *file_class;
+ PFS_instr_class *instr_class= NULL;
+
+ /* Do not advertise hard coded instruments when disabled. */
+ if (! pfs_initialized)
+ return HA_ERR_END_OF_FILE;
set_position(pos);
- switch (m_pos.m_index_1) {
+ switch (m_pos.m_index_1)
+ {
case pos_setup_instruments::VIEW_MUTEX:
- mutex_class= find_mutex_class(m_pos.m_index_2);
- if (mutex_class)
- {
- make_row(mutex_class);
- return 0;
- }
+ instr_class= find_mutex_class(m_pos.m_index_2);
break;
case pos_setup_instruments::VIEW_RWLOCK:
- rwlock_class= find_rwlock_class(m_pos.m_index_2);
- if (rwlock_class)
- {
- make_row(rwlock_class);
- return 0;
- }
+ instr_class= find_rwlock_class(m_pos.m_index_2);
break;
case pos_setup_instruments::VIEW_COND:
- cond_class= find_cond_class(m_pos.m_index_2);
- if (cond_class)
- {
- make_row(cond_class);
- return 0;
- }
+ instr_class= find_cond_class(m_pos.m_index_2);
break;
case pos_setup_instruments::VIEW_THREAD:
- /* Reserved for WL#4674, PERFORMANCE_SCHEMA Setup For Actors. */
+ /* Not used yet */
break;
case pos_setup_instruments::VIEW_FILE:
- file_class= find_file_class(m_pos.m_index_2);
- if (file_class)
- {
- make_row(file_class);
- return 0;
- }
+ instr_class= find_file_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_TABLE:
+ instr_class= find_table_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_STAGE:
+ instr_class= find_stage_class(m_pos.m_index_2);
break;
+ case pos_setup_instruments::VIEW_STATEMENT:
+ instr_class= find_statement_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_SOCKET:
+ instr_class= find_socket_class(m_pos.m_index_2);
+ break;
+ case pos_setup_instruments::VIEW_IDLE:
+ instr_class= find_idle_class(m_pos.m_index_2);
+ break;
+ }
+ if (instr_class)
+ {
+ make_row(instr_class);
+ return 0;
}
return HA_ERR_RECORD_DELETED;
@@ -191,10 +174,7 @@ int table_setup_instruments::rnd_pos(const void *pos)
void table_setup_instruments::make_row(PFS_instr_class *klass)
{
- m_row.m_name= &klass->m_name[0];
- m_row.m_name_length= klass->m_name_length;
- m_row.m_enabled_ptr= &klass->m_enabled;
- m_row.m_timed_ptr= &klass->m_timed;
+ m_row.m_instr_class= klass;
}
int table_setup_instruments::read_row_values(TABLE *table,
@@ -218,16 +198,13 @@ int table_setup_instruments::read_row_values(TABLE *table,
switch(f->field_index)
{
case 0: /* NAME */
- set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
+ set_field_varchar_utf8(f, m_row.m_instr_class->m_name, m_row.m_instr_class->m_name_length);
break;
case 1: /* ENABLED */
- set_field_enum(f, (*m_row.m_enabled_ptr) ? ENUM_YES : ENUM_NO);
+ set_field_enum(f, m_row.m_instr_class->m_enabled ? ENUM_YES : ENUM_NO);
break;
case 2: /* TIMED */
- if (m_row.m_timed_ptr)
- set_field_enum(f, (*m_row.m_timed_ptr) ? ENUM_YES : ENUM_NO);
- else
- set_field_enum(f, ENUM_NO);
+ set_field_enum(f, m_row.m_instr_class->m_timed ? ENUM_YES : ENUM_NO);
break;
default:
DBUG_ASSERT(false);
@@ -256,14 +233,11 @@ int table_setup_instruments::update_row_values(TABLE *table,
return HA_ERR_WRONG_COMMAND;
case 1: /* ENABLED */
value= (enum_yes_no) get_field_enum(f);
- *m_row.m_enabled_ptr= (value == ENUM_YES) ? true : false;
+ m_row.m_instr_class->m_enabled= (value == ENUM_YES) ? true : false;
break;
case 2: /* TIMED */
- if (m_row.m_timed_ptr)
- {
- value= (enum_yes_no) get_field_enum(f);
- *m_row.m_timed_ptr= (value == ENUM_YES) ? true : false;
- }
+ value= (enum_yes_no) get_field_enum(f);
+ m_row.m_instr_class->m_timed= (value == ENUM_YES) ? true : false;
break;
default:
DBUG_ASSERT(false);
@@ -271,6 +245,41 @@ int table_setup_instruments::update_row_values(TABLE *table,
}
}
+ switch (m_pos.m_index_1)
+ {
+ case pos_setup_instruments::VIEW_MUTEX:
+ update_mutex_derived_flags();
+ break;
+ case pos_setup_instruments::VIEW_RWLOCK:
+ update_rwlock_derived_flags();
+ break;
+ case pos_setup_instruments::VIEW_COND:
+ update_cond_derived_flags();
+ break;
+ case pos_setup_instruments::VIEW_THREAD:
+ /* Not used yet */
+ break;
+ case pos_setup_instruments::VIEW_FILE:
+ update_file_derived_flags();
+ break;
+ case pos_setup_instruments::VIEW_TABLE:
+ update_table_derived_flags();
+ break;
+ case pos_setup_instruments::VIEW_STAGE:
+ case pos_setup_instruments::VIEW_STATEMENT:
+ /* No flag to update. */
+ break;
+ case pos_setup_instruments::VIEW_SOCKET:
+ update_socket_derived_flags();
+ break;
+ case pos_setup_instruments::VIEW_IDLE:
+ /* No flag to update. */
+ break;
+ default:
+ DBUG_ASSERT(false);
+ break;
+ }
+
return 0;
}
diff --git a/storage/perfschema/table_setup_instruments.h b/storage/perfschema/table_setup_instruments.h
index ed8dac4527d..b2711578d7f 100644
--- a/storage/perfschema/table_setup_instruments.h
+++ b/storage/perfschema/table_setup_instruments.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc.
- Use is subject to license terms.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,38 +32,38 @@
/** A row of PERFORMANCE_SCHEMA.SETUP_INSTRUMENTS. */
struct row_setup_instruments
{
- /** Column NAME. */
- const char *m_name;
- /** Length in bytes of @c m_name. */
- uint m_name_length;
- /** Column ENABLED. */
- bool *m_enabled_ptr;
- /** Column TIMED. */
- bool *m_timed_ptr;
+ /** Columns NAME, ENABLED, TIMED. */
+ PFS_instr_class *m_instr_class;
};
/** Position of a cursor on PERFORMANCE_SCHEMA.SETUP_INSTRUMENTS. */
struct pos_setup_instruments : public PFS_double_index
{
+ static const uint FIRST_VIEW= 1;
static const uint VIEW_MUTEX= 1;
static const uint VIEW_RWLOCK= 2;
static const uint VIEW_COND= 3;
- /** Reverved for WL#4674, PERFORMANCE_SCHEMA Setup For Actors. */
static const uint VIEW_THREAD= 4;
static const uint VIEW_FILE= 5;
+ static const uint VIEW_TABLE= 6;
+ static const uint VIEW_STAGE= 7;
+ static const uint VIEW_STATEMENT= 8;
+ static const uint VIEW_SOCKET= 9;
+ static const uint VIEW_IDLE= 10;
+ static const uint LAST_VIEW= 10;
pos_setup_instruments()
- : PFS_double_index(VIEW_MUTEX, 1)
+ : PFS_double_index(FIRST_VIEW, 1)
{}
inline void reset(void)
{
- m_index_1= VIEW_MUTEX;
+ m_index_1= FIRST_VIEW;
m_index_2= 1;
}
inline bool has_more_view(void)
- { return (m_index_1 <= VIEW_FILE); }
+ { return (m_index_1 <= LAST_VIEW); }
inline void next_view(void)
{
@@ -107,8 +106,6 @@ private:
/** 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;
diff --git a/storage/perfschema/table_setup_objects.cc b/storage/perfschema/table_setup_objects.cc
new file mode 100644
index 00000000000..8049fcdf48c
--- /dev/null
+++ b/storage/perfschema/table_setup_objects.cc
@@ -0,0 +1,326 @@
+/* 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, Fifth Floor, 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE setup_objects("
+ "OBJECT_TYPE ENUM ('TABLE') not null default 'TABLE',"
+ "OBJECT_SCHEMA VARCHAR(64) default '%',"
+ "OBJECT_NAME VARCHAR(64) not null default '%',"
+ "ENABLED ENUM ('YES', 'NO') not null default 'YES',"
+ "TIMED ENUM ('YES', 'NO') not null default 'YES')") }
+};
+
+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..943cc4a1ad5
--- /dev/null
+++ b/storage/perfschema/table_setup_objects.h
@@ -0,0 +1,107 @@
+/* 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, Fifth Floor, 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;
+
+ /** Current row. */
+ row_setup_objects m_row;
+ /** True is the current row exists. */
+ bool m_row_exists;
+ /** Current position. */
+ PFS_simple_index m_pos;
+ /** Next position. */
+ PFS_simple_index m_next_pos;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_setup_timers.cc b/storage/perfschema/table_setup_timers.cc
index e516f87c3fa..26539da2e27 100644
--- a/storage/perfschema/table_setup_timers.cc
+++ b/storage/perfschema/table_setup_timers.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,35 +24,29 @@
#include "pfs_column_values.h"
#include "pfs_timer.h"
-#define COUNT_SETUP_TIMERS 1
+#define COUNT_SETUP_TIMERS 4
+
static row_setup_timers all_setup_timers_data[COUNT_SETUP_TIMERS]=
{
{
+ { C_STRING_WITH_LEN("idle") },
+ &idle_timer
+ },
+ {
{ C_STRING_WITH_LEN("wait") },
&wait_timer
- }
-};
-
-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("stage") },
+ &stage_timer
},
{
- { C_STRING_WITH_LEN("TIMER_NAME") },
- { C_STRING_WITH_LEN("enum(\'CYCLE\',\'NANOSECOND\',\'MICROSECOND\',"
- "\'MILLISECOND\',\'TICK\')") },
- { NULL, 0}
+ { C_STRING_WITH_LEN("statement") },
+ &statement_timer
}
};
-TABLE_FIELD_DEF
-table_setup_timers::m_field_def=
-{ 2, field_types };
+THR_LOCK table_setup_timers::m_table_lock;
PFS_engine_table_share
table_setup_timers::m_share=
@@ -62,11 +56,13 @@ table_setup_timers::m_share=
&table_setup_timers::create,
NULL, /* write_row */
NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
COUNT_SETUP_TIMERS,
sizeof(PFS_simple_index),
&m_table_lock,
- &m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE setup_timers("
+ "NAME VARCHAR(64) not null,"
+ "TIMER_NAME ENUM ('CYCLE', 'NANOSECOND', 'MICROSECOND', 'MILLISECOND', 'TICK') not null)") }
};
PFS_engine_table* table_setup_timers::create(void)
diff --git a/storage/perfschema/table_setup_timers.h b/storage/perfschema/table_setup_timers.h
index dcc53172418..9eb2f95836c 100644
--- a/storage/perfschema/table_setup_timers.h
+++ b/storage/perfschema/table_setup_timers.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc.
- Use is subject to license terms.
+/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -71,8 +70,6 @@ public:
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;
diff --git a/storage/perfschema/table_socket_instances.cc b/storage/perfschema/table_socket_instances.cc
new file mode 100644
index 00000000000..419e19349f4
--- /dev/null
+++ b/storage/perfschema/table_socket_instances.cc
@@ -0,0 +1,195 @@
+/* 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, Fifth Floor, 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE socket_instances("
+ "EVENT_NAME VARCHAR(128) not null,"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null,"
+ "THREAD_ID BIGINT unsigned,"
+ "SOCKET_ID INTEGER not null,"
+ "IP VARCHAR(64) not null,"
+ "PORT INTEGER not null,"
+ "STATE ENUM('IDLE','ACTIVE') not null)") }
+};
+
+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..b5e5edb36ed
--- /dev/null
+++ b/storage/perfschema/table_socket_instances.h
@@ -0,0 +1,100 @@
+/* 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, Fifth Floor, 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;
+
+ /** 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..2da45c0d2cd
--- /dev/null
+++ b/storage/perfschema/table_socket_summary_by_event_name.cc
@@ -0,0 +1,241 @@
+/* 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, Fifth Floor, 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE socket_summary_by_event_name("
+ "EVENT_NAME VARCHAR(128) not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "COUNT_READ BIGINT unsigned not null,"
+ "SUM_TIMER_READ BIGINT unsigned not null,"
+ "MIN_TIMER_READ BIGINT unsigned not null,"
+ "AVG_TIMER_READ BIGINT unsigned not null,"
+ "MAX_TIMER_READ BIGINT unsigned not null,"
+ "SUM_NUMBER_OF_BYTES_READ BIGINT unsigned not null,"
+ "COUNT_WRITE BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE BIGINT unsigned not null,"
+ "SUM_NUMBER_OF_BYTES_WRITE BIGINT unsigned not null,"
+ "COUNT_MISC BIGINT unsigned not null,"
+ "SUM_TIMER_MISC BIGINT unsigned not null,"
+ "MIN_TIMER_MISC BIGINT unsigned not null,"
+ "AVG_TIMER_MISC BIGINT unsigned not null,"
+ "MAX_TIMER_MISC BIGINT unsigned not null)") }
+};
+
+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..9bdeb3104b4
--- /dev/null
+++ b/storage/perfschema/table_socket_summary_by_event_name.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, Fifth Floor, 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;
+
+ /** 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..693f65e4843
--- /dev/null
+++ b/storage/perfschema/table_socket_summary_by_instance.cc
@@ -0,0 +1,258 @@
+/* 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, Fifth Floor, 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE socket_summary_by_instance("
+ "EVENT_NAME VARCHAR(128) not null,"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null,"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "COUNT_READ BIGINT unsigned not null,"
+ "SUM_TIMER_READ BIGINT unsigned not null,"
+ "MIN_TIMER_READ BIGINT unsigned not null,"
+ "AVG_TIMER_READ BIGINT unsigned not null,"
+ "MAX_TIMER_READ BIGINT unsigned not null,"
+ "SUM_NUMBER_OF_BYTES_READ BIGINT unsigned not null,"
+ "COUNT_WRITE BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE BIGINT unsigned not null,"
+ "SUM_NUMBER_OF_BYTES_WRITE BIGINT unsigned not null,"
+ "COUNT_MISC BIGINT unsigned not null,"
+ "SUM_TIMER_MISC BIGINT unsigned not null,"
+ "MIN_TIMER_MISC BIGINT unsigned not null,"
+ "AVG_TIMER_MISC BIGINT unsigned not null,"
+ "MAX_TIMER_MISC BIGINT unsigned not null)") }
+};
+
+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, (intptr)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..deb8ffab554
--- /dev/null
+++ b/storage/perfschema/table_socket_summary_by_instance.h
@@ -0,0 +1,93 @@
+/* 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, Fifth Floor, 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;
+
+ /** Current row. */
+ row_socket_summary_by_instance m_row;
+ /** True if the current row exists. */
+ bool m_row_exists;
+ /** Current position. */
+ PFS_simple_index m_pos;
+ /** Next position. */
+ PFS_simple_index m_next_pos;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/table_sync_instances.cc b/storage/perfschema/table_sync_instances.cc
index 59e8c184966..6e48468e6c3 100644
--- a/storage/perfschema/table_sync_instances.cc
+++ b/storage/perfschema/table_sync_instances.cc
@@ -29,29 +29,6 @@
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("int(11)") },
- { NULL, 0}
- }
-};
-
-TABLE_FIELD_DEF
-table_mutex_instances::m_field_def=
-{ 3, mutex_field_types };
-
PFS_engine_table_share
table_mutex_instances::m_share=
{
@@ -60,11 +37,14 @@ table_mutex_instances::m_share=
&table_mutex_instances::create,
NULL, /* write_row */
NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
1000, /* records */
sizeof(PFS_simple_index),
&m_table_lock,
- &m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE mutex_instances("
+ "NAME VARCHAR(128) not null,"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null,"
+ "LOCKED_BY_THREAD_ID BIGINT unsigned)") }
};
PFS_engine_table* table_mutex_instances::create(void)
@@ -177,7 +157,7 @@ int table_mutex_instances::read_row_values(TABLE *table,
break;
case 2: /* LOCKED_BY_THREAD_ID */
if (m_row.m_locked)
- set_field_ulong(f, m_row.m_locked_by_thread_id);
+ set_field_ulonglong(f, m_row.m_locked_by_thread_id);
else
f->set_null();
break;
@@ -192,34 +172,6 @@ int table_mutex_instances::read_row_values(TABLE *table,
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("int(11)") },
- { 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=
{
@@ -228,11 +180,15 @@ table_rwlock_instances::m_share=
&table_rwlock_instances::create,
NULL, /* write_row */
NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
1000, /* records */
sizeof(PFS_simple_index),
&m_table_lock,
- &m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE rwlock_instances("
+ "NAME VARCHAR(128) not null,"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null,"
+ "WRITE_LOCKED_BY_THREAD_ID BIGINT unsigned,"
+ "READ_LOCKED_BY_COUNT INTEGER unsigned not null)") }
};
PFS_engine_table* table_rwlock_instances::create(void)
@@ -349,7 +305,7 @@ int table_rwlock_instances::read_row_values(TABLE *table,
break;
case 2: /* WRITE_LOCKED_BY_THREAD_ID */
if (m_row.m_write_locked)
- set_field_ulong(f, m_row.m_write_locked_by_thread_id);
+ set_field_ulonglong(f, m_row.m_write_locked_by_thread_id);
else
f->set_null();
break;
@@ -367,24 +323,6 @@ int table_rwlock_instances::read_row_values(TABLE *table,
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=
{
@@ -393,11 +331,13 @@ table_cond_instances::m_share=
&table_cond_instances::create,
NULL, /* write_row */
NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
1000, /* records */
sizeof(PFS_simple_index),
&m_table_lock,
- &m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE cond_instances("
+ "NAME VARCHAR(128) not null,"
+ "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null)") }
};
PFS_engine_table* table_cond_instances::create(void)
diff --git a/storage/perfschema/table_sync_instances.h b/storage/perfschema/table_sync_instances.h
index afee858e712..c6a2ed8adaa 100644
--- a/storage/perfschema/table_sync_instances.h
+++ b/storage/perfschema/table_sync_instances.h
@@ -45,7 +45,7 @@ struct row_mutex_instances
/** True if column LOCKED_BY_THREAD_ID is not null. */
bool m_locked;
/** Column LOCKED_BY_THREAD_ID. */
- ulong m_locked_by_thread_id;
+ ulonglong m_locked_by_thread_id;
};
/** Table PERFORMANCE_SCHEMA.MUTEX_INSTANCES. */
@@ -77,12 +77,10 @@ private:
/** 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 is the current row exists. */
+ /** True if the current row exists. */
bool m_row_exists;
/** Current position. */
PFS_simple_index m_pos;
@@ -102,7 +100,7 @@ struct row_rwlock_instances
/** True if column WRITE_LOCKED_BY_THREAD_ID is not null. */
bool m_write_locked;
/** Column WRITE_LOCKED_BY_THREAD_ID. */
- ulong m_write_locked_by_thread_id;
+ ulonglong m_write_locked_by_thread_id;
/** Column READ_LOCKED_BY_COUNT. */
ulong m_readers;
};
@@ -136,12 +134,10 @@ private:
/** 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 is the current row exists. */
+ /** True if the current row exists. */
bool m_row_exists;
/** Current position. */
PFS_simple_index m_pos;
@@ -189,12 +185,10 @@ private:
/** 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 is the current row exists. */
+ /** True if the current row exists. */
bool m_row_exists;
/** Current position. */
PFS_simple_index m_pos;
diff --git a/storage/perfschema/table_threads.cc b/storage/perfschema/table_threads.cc
index 283e058e3eb..1f198ba1378 100644
--- a/storage/perfschema/table_threads.cc
+++ b/storage/perfschema/table_threads.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -13,112 +13,60 @@
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
-/**
- @file storage/perfschema/table_threads.cc
- Table THREADS (implementation).
-*/
-
#include "my_global.h"
#include "my_pthread.h"
#include "table_threads.h"
+#include "sql_parse.h"
#include "pfs_instr_class.h"
#include "pfs_instr.h"
THR_LOCK table_threads::m_table_lock;
-static const TABLE_FIELD_TYPE field_types[]=
-{
- {
- { C_STRING_WITH_LEN("THREAD_ID") },
- { C_STRING_WITH_LEN("int(11)") },
- { NULL, 0}
- },
- {
- { C_STRING_WITH_LEN("PROCESSLIST_ID") },
- { C_STRING_WITH_LEN("int(11)") },
- { NULL, 0}
- },
- {
- { C_STRING_WITH_LEN("NAME") },
- { C_STRING_WITH_LEN("varchar(128)") },
- { NULL, 0}
- }
-};
-
-TABLE_FIELD_DEF
-table_threads::m_field_def=
-{ 3, field_types };
-
PFS_engine_table_share
table_threads::m_share=
{
{ C_STRING_WITH_LEN("threads") },
- &pfs_readonly_acl,
+ &pfs_updatable_acl,
&table_threads::create,
NULL, /* write_row */
NULL, /* delete_all_rows */
+ NULL, /* get_row_count */
1000, /* records */
sizeof(PFS_simple_index), /* ref length */
&m_table_lock,
- &m_field_def,
- false /* checked */
+ { C_STRING_WITH_LEN("CREATE TABLE threads("
+ "THREAD_ID BIGINT unsigned not null,"
+ "NAME VARCHAR(128) not null,"
+ "TYPE VARCHAR(10) not null,"
+ "PROCESSLIST_ID BIGINT unsigned,"
+ "PROCESSLIST_USER VARCHAR(16),"
+ "PROCESSLIST_HOST VARCHAR(60),"
+ "PROCESSLIST_DB VARCHAR(64),"
+ "PROCESSLIST_COMMAND VARCHAR(16),"
+ "PROCESSLIST_TIME BIGINT,"
+ "PROCESSLIST_STATE VARCHAR(64),"
+ "PROCESSLIST_INFO LONGTEXT,"
+ "PARENT_THREAD_ID BIGINT unsigned,"
+ "ROLE VARCHAR(64),"
+ "INSTRUMENTED ENUM ('YES', 'NO') not null)") }
};
-PFS_engine_table* table_threads::create(void)
+PFS_engine_table* table_threads::create()
{
return new table_threads();
}
table_threads::table_threads()
- : PFS_engine_table(&m_share, &m_pos),
- m_row_exists(false), m_pos(0), m_next_pos(0)
+ : cursor_by_thread(& m_share),
+ m_row_exists(false)
{}
-void table_threads::reset_position(void)
-{
- m_pos.m_index= 0;
- m_next_pos.m_index= 0;
-}
-
-int table_threads::rnd_next(void)
-{
- PFS_thread *pfs;
-
- for (m_pos.set_at(&m_next_pos);
- m_pos.m_index < thread_max;
- m_pos.next())
- {
- pfs= &thread_array[m_pos.m_index];
- if (pfs->m_lock.is_populated())
- {
- make_row(pfs);
- m_next_pos.set_after(&m_pos);
- return 0;
- }
- }
-
- return HA_ERR_END_OF_FILE;
-}
-
-int table_threads::rnd_pos(const void *pos)
-{
- PFS_thread *pfs;
-
- set_position(pos);
- DBUG_ASSERT(m_pos.m_index < thread_max);
- pfs= &thread_array[m_pos.m_index];
- if (pfs->m_lock.is_populated())
- {
- make_row(pfs);
- return 0;
- }
-
- return HA_ERR_RECORD_DELETED;
-}
-
void table_threads::make_row(PFS_thread *pfs)
{
pfs_lock lock;
+ pfs_lock session_lock;
+ pfs_lock stmt_lock;
+ PFS_stage_class *stage_class;
PFS_thread_class *safe_class;
m_row_exists= false;
@@ -131,11 +79,89 @@ void table_threads::make_row(PFS_thread *pfs)
return;
m_row.m_thread_internal_id= pfs->m_thread_internal_id;
- m_row.m_thread_id= pfs->m_thread_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;
- if (pfs->m_lock.end_optimistic_lock(&lock))
+ /* Protect this reader against session attribute changes */
+ pfs->m_session_lock.begin_optimistic_lock(&session_lock);
+
+ m_row.m_username_length= pfs->m_username_length;
+ if (unlikely(m_row.m_username_length > sizeof(m_row.m_username)))
+ return;
+ if (m_row.m_username_length != 0)
+ memcpy(m_row.m_username, pfs->m_username, m_row.m_username_length);
+
+ m_row.m_hostname_length= pfs->m_hostname_length;
+ if (unlikely(m_row.m_hostname_length > sizeof(m_row.m_hostname)))
+ return;
+ if (m_row.m_hostname_length != 0)
+ memcpy(m_row.m_hostname, pfs->m_hostname, m_row.m_hostname_length);
+
+ if (! pfs->m_session_lock.end_optimistic_lock(& session_lock))
+ {
+ /*
+ One of the columns:
+ - PROCESSLIST_USER
+ - PROCESSLIST_HOST
+ is being updated.
+ Do not discard the entire row.
+ Do not loop waiting for a stable value.
+ Just return NULL values.
+ */
+ m_row.m_username_length= 0;
+ m_row.m_hostname_length= 0;
+ }
+
+ /* Protect this reader against statement attributes changes */
+ pfs->m_stmt_lock.begin_optimistic_lock(&stmt_lock);
+
+ 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_processlist_info_ptr= & pfs->m_processlist_info[0];
+ m_row.m_processlist_info_length= pfs->m_processlist_info_length;
+
+ if (! pfs->m_stmt_lock.end_optimistic_lock(& stmt_lock))
+ {
+ /*
+ One of the columns:
+ - PROCESSLIST_DB
+ - PROCESSLIST_INFO
+ is being updated.
+ Do not discard the entire row.
+ Do not loop waiting for a stable value.
+ Just return NULL values.
+ */
+ m_row.m_dbname_length= 0;
+ m_row.m_processlist_info_length= 0;
+ }
+
+ /* Dirty read, sanitize the command. */
+ m_row.m_command= pfs->m_command;
+ if ((m_row.m_command < 0) || (m_row.m_command > COM_END))
+ m_row.m_command= COM_END;
+
+ m_row.m_start_time= pfs->m_start_time;
+
+ stage_class= find_stage_class(pfs->m_stage);
+ if (stage_class != NULL)
+ {
+ m_row.m_processlist_state_ptr= stage_class->m_name + stage_class->m_prefix_length;
+ m_row.m_processlist_state_length= stage_class->m_name_length - stage_class->m_prefix_length;
+ }
+ else
+ {
+ m_row.m_processlist_state_length= 0;
+ }
+
+ m_row.m_enabled_ptr= &pfs->m_enabled;
+
+ if (pfs->m_lock.end_optimistic_lock(& lock))
m_row_exists= true;
}
@@ -150,8 +176,9 @@ int table_threads::read_row_values(TABLE *table,
return HA_ERR_RECORD_DELETED;
/* Set the null bits */
- DBUG_ASSERT(table->s->null_bytes == 1);
+ DBUG_ASSERT(table->s->null_bytes == 2);
buf[0]= 0;
+ buf[1]= 0;
for (; (f= *fields) ; fields++)
{
@@ -160,14 +187,141 @@ int table_threads::read_row_values(TABLE *table,
switch(f->field_index)
{
case 0: /* THREAD_ID */
- set_field_ulong(f, m_row.m_thread_internal_id);
- break;
- case 1: /* PROCESSLIST_ID */
- set_field_ulong(f, m_row.m_thread_id);
+ set_field_ulonglong(f, m_row.m_thread_internal_id);
break;
- case 2: /* NAME */
+ case 1: /* NAME */
set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
break;
+ case 2: /* TYPE */
+ if (m_row.m_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)
+ {
+ /* This column's datatype is declared as varchar(64). But in current
+ code, there are few process state messages which are greater than
+ 64 characters(Eg:stage_slave_has_read_all_relay_log).
+ In those cases, we will end up in 'data truncated'
+ warning/error (depends sql_mode setting) when server is updating
+ this column for those threads. Since 5.6 is GAed, neither the
+ metadata of this column can be changed, nor those state messages.
+ So server will silently truncate the state message to 64 characters
+ if it is longer. In Upper versions(5.7+), these state messages are
+ changed to less than or equal to 64 characters.
+ */
+ set_field_varchar_utf8(f, m_row.m_processlist_state_ptr,
+ std::min<uint>(m_row.m_processlist_state_length,
+ f->char_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);
}
diff --git a/storage/perfschema/table_threads.h b/storage/perfschema/table_threads.h
index 5d6daf08ddc..823f66bf713 100644
--- a/storage/perfschema/table_threads.h
+++ b/storage/perfschema/table_threads.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,52 +16,80 @@
#ifndef TABLE_THREADS_H
#define TABLE_THREADS_H
-/**
- @file storage/perfschema/table_threads.h
- Table THREADS (declarations).
-*/
-
#include "pfs_column_types.h"
-#include "pfs_engine_table.h"
+#include "cursor_by_thread.h"
struct PFS_thread;
/**
- @addtogroup Performance_schema_tables
+ \addtogroup Performance_schema_tables
@{
*/
-/** A row of PERFORMANCE_SCHEMA.THREADS. */
+/**
+ A row of PERFORMANCE_SCHEMA.THREADS.
+*/
struct row_threads
{
/** Column THREAD_ID. */
- ulong m_thread_internal_id;
+ ulonglong m_thread_internal_id;
/** Column PROCESSLIST_ID. */
- ulong m_thread_id;
+ ulonglong m_processlist_id;
/** Column NAME. */
- const char *m_name;
+ const char* m_name;
/** Length in bytes of @c m_name. */
uint m_name_length;
+ /** Column PROCESSLIST_USER. */
+ char m_username[USERNAME_LENGTH];
+ /** Length in bytes of @c m_username. */
+ uint m_username_length;
+ /** Column PROCESSLIST_HOST. */
+ char m_hostname[HOSTNAME_LENGTH];
+ /** Length in bytes of @c m_hostname. */
+ uint m_hostname_length;
+ /** Column PROCESSLIST_DB. */
+ char m_dbname[NAME_LEN];
+ /** Length in bytes of @c m_dbname. */
+ uint m_dbname_length;
+ /** Column PROCESSLIST_COMMAND. */
+ int m_command;
+ /** Column PROCESSLIST_TIME. */
+ time_t m_start_time;
+ /** Column PROCESSLIST_STATE. */
+ const char* m_processlist_state_ptr;
+ /** Length in bytes of @c m_processlist_state_ptr. */
+ uint m_processlist_state_length;
+ /** Column PROCESSLIST_INFO. */
+ const char* m_processlist_info_ptr;
+ /** Length in bytes of @c m_processlist_info_ptr. */
+ uint m_processlist_info_length;
+ /** Column INSTRUMENTED. */
+ bool *m_enabled_ptr;
+ /** Column PARENT_THREAD_ID. */
+ ulonglong m_parent_thread_internal_id;
};
/** Table PERFORMANCE_SCHEMA.THREADS. */
-class table_threads : public PFS_engine_table
+class table_threads : public cursor_by_thread
{
public:
- /** Table share. */
+ /** Table share */
static PFS_engine_table_share m_share;
+ /** Table builder */
static PFS_engine_table* create();
- virtual int rnd_next();
- virtual int rnd_pos(const void *pos);
- virtual void reset_position(void);
-
protected:
virtual int read_row_values(TABLE *table,
unsigned char *buf,
Field **fields,
bool read_all);
+
+ virtual int update_row_values(TABLE *table,
+ const unsigned char *old_buf,
+ unsigned char *new_buf,
+ Field **fields);
+
protected:
table_threads();
@@ -70,21 +98,15 @@ public:
{}
private:
- void make_row(PFS_thread *pfs);
+ 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;
- /** Current position. */
- PFS_simple_index m_pos;
- /** Next position. */
- PFS_simple_index m_next_pos;
};
/** @} */
diff --git a/storage/perfschema/table_tiws_by_index_usage.cc b/storage/perfschema/table_tiws_by_index_usage.cc
new file mode 100644
index 00000000000..5d24fcc689b
--- /dev/null
+++ b/storage/perfschema/table_tiws_by_index_usage.cc
@@ -0,0 +1,334 @@
+/* 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-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE table_io_waits_summary_by_index_usage("
+ "OBJECT_TYPE VARCHAR(64),"
+ "OBJECT_SCHEMA VARCHAR(64),"
+ "OBJECT_NAME VARCHAR(64),"
+ "INDEX_NAME VARCHAR(64),"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "COUNT_READ BIGINT unsigned not null,"
+ "SUM_TIMER_READ BIGINT unsigned not null,"
+ "MIN_TIMER_READ BIGINT unsigned not null,"
+ "AVG_TIMER_READ BIGINT unsigned not null,"
+ "MAX_TIMER_READ BIGINT unsigned not null,"
+ "COUNT_WRITE BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE BIGINT unsigned not null,"
+ "COUNT_FETCH BIGINT unsigned not null,"
+ "SUM_TIMER_FETCH BIGINT unsigned not null,"
+ "MIN_TIMER_FETCH BIGINT unsigned not null,"
+ "AVG_TIMER_FETCH BIGINT unsigned not null,"
+ "MAX_TIMER_FETCH BIGINT unsigned not null,"
+ "COUNT_INSERT BIGINT unsigned not null,"
+ "SUM_TIMER_INSERT BIGINT unsigned not null,"
+ "MIN_TIMER_INSERT BIGINT unsigned not null,"
+ "AVG_TIMER_INSERT BIGINT unsigned not null,"
+ "MAX_TIMER_INSERT BIGINT unsigned not null,"
+ "COUNT_UPDATE BIGINT unsigned not null,"
+ "SUM_TIMER_UPDATE BIGINT unsigned not null,"
+ "MIN_TIMER_UPDATE BIGINT unsigned not null,"
+ "AVG_TIMER_UPDATE BIGINT unsigned not null,"
+ "MAX_TIMER_UPDATE BIGINT unsigned not null,"
+ "COUNT_DELETE BIGINT unsigned not null,"
+ "SUM_TIMER_DELETE BIGINT unsigned not null,"
+ "MIN_TIMER_DELETE BIGINT unsigned not null,"
+ "AVG_TIMER_DELETE BIGINT unsigned not null,"
+ "MAX_TIMER_DELETE BIGINT unsigned not null)") }
+};
+
+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..f6d935365b2
--- /dev/null
+++ b/storage/perfschema/table_tiws_by_index_usage.h
@@ -0,0 +1,121 @@
+/* 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-1335 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;
+
+ /** 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..78535fd6512
--- /dev/null
+++ b/storage/perfschema/table_tiws_by_table.cc
@@ -0,0 +1,312 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE table_io_waits_summary_by_table("
+ "OBJECT_TYPE VARCHAR(64),"
+ "OBJECT_SCHEMA VARCHAR(64),"
+ "OBJECT_NAME VARCHAR(64),"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "COUNT_READ BIGINT unsigned not null,"
+ "SUM_TIMER_READ BIGINT unsigned not null,"
+ "MIN_TIMER_READ BIGINT unsigned not null,"
+ "AVG_TIMER_READ BIGINT unsigned not null,"
+ "MAX_TIMER_READ BIGINT unsigned not null,"
+ "COUNT_WRITE BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE BIGINT unsigned not null,"
+ "COUNT_FETCH BIGINT unsigned not null,"
+ "SUM_TIMER_FETCH BIGINT unsigned not null,"
+ "MIN_TIMER_FETCH BIGINT unsigned not null,"
+ "AVG_TIMER_FETCH BIGINT unsigned not null,"
+ "MAX_TIMER_FETCH BIGINT unsigned not null,"
+ "COUNT_INSERT BIGINT unsigned not null,"
+ "SUM_TIMER_INSERT BIGINT unsigned not null,"
+ "MIN_TIMER_INSERT BIGINT unsigned not null,"
+ "AVG_TIMER_INSERT BIGINT unsigned not null,"
+ "MAX_TIMER_INSERT BIGINT unsigned not null,"
+ "COUNT_UPDATE BIGINT unsigned not null,"
+ "SUM_TIMER_UPDATE BIGINT unsigned not null,"
+ "MIN_TIMER_UPDATE BIGINT unsigned not null,"
+ "AVG_TIMER_UPDATE BIGINT unsigned not null,"
+ "MAX_TIMER_UPDATE BIGINT unsigned not null,"
+ "COUNT_DELETE BIGINT unsigned not null,"
+ "SUM_TIMER_DELETE BIGINT unsigned not null,"
+ "MIN_TIMER_DELETE BIGINT unsigned not null,"
+ "AVG_TIMER_DELETE BIGINT unsigned not null,"
+ "MAX_TIMER_DELETE BIGINT unsigned not null)") }
+};
+
+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..9a86d39196c
--- /dev/null
+++ b/storage/perfschema/table_tiws_by_table.h
@@ -0,0 +1,91 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** 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..5299e7f6a56
--- /dev/null
+++ b/storage/perfschema/table_tlws_by_table.cc
@@ -0,0 +1,464 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE table_lock_waits_summary_by_table("
+ "OBJECT_TYPE VARCHAR(64),"
+ "OBJECT_SCHEMA VARCHAR(64),"
+ "OBJECT_NAME VARCHAR(64),"
+ "COUNT_STAR BIGINT unsigned not null,"
+ "SUM_TIMER_WAIT BIGINT unsigned not null,"
+ "MIN_TIMER_WAIT BIGINT unsigned not null,"
+ "AVG_TIMER_WAIT BIGINT unsigned not null,"
+ "MAX_TIMER_WAIT BIGINT unsigned not null,"
+ "COUNT_READ BIGINT unsigned not null,"
+ "SUM_TIMER_READ BIGINT unsigned not null,"
+ "MIN_TIMER_READ BIGINT unsigned not null,"
+ "AVG_TIMER_READ BIGINT unsigned not null,"
+ "MAX_TIMER_READ BIGINT unsigned not null,"
+ "COUNT_WRITE BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE BIGINT unsigned not null,"
+ "COUNT_READ_NORMAL BIGINT unsigned not null,"
+ "SUM_TIMER_READ_NORMAL BIGINT unsigned not null,"
+ "MIN_TIMER_READ_NORMAL BIGINT unsigned not null,"
+ "AVG_TIMER_READ_NORMAL BIGINT unsigned not null,"
+ "MAX_TIMER_READ_NORMAL BIGINT unsigned not null,"
+ "COUNT_READ_WITH_SHARED_LOCKS BIGINT unsigned not null,"
+ "SUM_TIMER_READ_WITH_SHARED_LOCKS BIGINT unsigned not null,"
+ "MIN_TIMER_READ_WITH_SHARED_LOCKS BIGINT unsigned not null,"
+ "AVG_TIMER_READ_WITH_SHARED_LOCKS BIGINT unsigned not null,"
+ "MAX_TIMER_READ_WITH_SHARED_LOCKS BIGINT unsigned not null,"
+ "COUNT_READ_HIGH_PRIORITY BIGINT unsigned not null,"
+ "SUM_TIMER_READ_HIGH_PRIORITY BIGINT unsigned not null,"
+ "MIN_TIMER_READ_HIGH_PRIORITY BIGINT unsigned not null,"
+ "AVG_TIMER_READ_HIGH_PRIORITY BIGINT unsigned not null,"
+ "MAX_TIMER_READ_HIGH_PRIORITY BIGINT unsigned not null,"
+ "COUNT_READ_NO_INSERT BIGINT unsigned not null,"
+ "SUM_TIMER_READ_NO_INSERT BIGINT unsigned not null,"
+ "MIN_TIMER_READ_NO_INSERT BIGINT unsigned not null,"
+ "AVG_TIMER_READ_NO_INSERT BIGINT unsigned not null,"
+ "MAX_TIMER_READ_NO_INSERT BIGINT unsigned not null,"
+ "COUNT_READ_EXTERNAL BIGINT unsigned not null,"
+ "SUM_TIMER_READ_EXTERNAL BIGINT unsigned not null,"
+ "MIN_TIMER_READ_EXTERNAL BIGINT unsigned not null,"
+ "AVG_TIMER_READ_EXTERNAL BIGINT unsigned not null,"
+ "MAX_TIMER_READ_EXTERNAL BIGINT unsigned not null,"
+ "COUNT_WRITE_ALLOW_WRITE BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE_ALLOW_WRITE BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE_ALLOW_WRITE BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE_ALLOW_WRITE BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE_ALLOW_WRITE BIGINT unsigned not null,"
+ "COUNT_WRITE_CONCURRENT_INSERT BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE_CONCURRENT_INSERT BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE_CONCURRENT_INSERT BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE_CONCURRENT_INSERT BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE_CONCURRENT_INSERT BIGINT unsigned not null,"
+ "COUNT_WRITE_DELAYED BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE_DELAYED BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE_DELAYED BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE_DELAYED BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE_DELAYED BIGINT unsigned not null,"
+ "COUNT_WRITE_LOW_PRIORITY BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE_LOW_PRIORITY BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE_LOW_PRIORITY BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE_LOW_PRIORITY BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE_LOW_PRIORITY BIGINT unsigned not null,"
+ "COUNT_WRITE_NORMAL BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE_NORMAL BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE_NORMAL BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE_NORMAL BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE_NORMAL BIGINT unsigned not null,"
+ "COUNT_WRITE_EXTERNAL BIGINT unsigned not null,"
+ "SUM_TIMER_WRITE_EXTERNAL BIGINT unsigned not null,"
+ "MIN_TIMER_WRITE_EXTERNAL BIGINT unsigned not null,"
+ "AVG_TIMER_WRITE_EXTERNAL BIGINT unsigned not null,"
+ "MAX_TIMER_WRITE_EXTERNAL BIGINT unsigned not null)") }
+};
+
+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..757adc3f5f5
--- /dev/null
+++ b/storage/perfschema/table_tlws_by_table.h
@@ -0,0 +1,91 @@
+/* Copyright (c) 2010, 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 Street, Fifth Floor, Boston, MA 02110-1335 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;
+
+ /** 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..6d6bfc5bfaf
--- /dev/null
+++ b/storage/perfschema/table_users.cc
@@ -0,0 +1,126 @@
+/* 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, Fifth Floor, 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;
+
+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,
+ { C_STRING_WITH_LEN("CREATE TABLE users("
+ "USER CHAR(16) collate utf8_bin default null,"
+ "CURRENT_CONNECTIONS bigint not null,"
+ "TOTAL_CONNECTIONS bigint not null)") }
+};
+
+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..1b24dfb9039
--- /dev/null
+++ b/storage/perfschema/table_users.h
@@ -0,0 +1,78 @@
+/* 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, Fifth Floor, 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;
+
+ /** Current row. */
+ row_users m_row;
+ /** True if the current row exists. */
+ bool m_row_exists;
+};
+
+/** @} */
+#endif
diff --git a/storage/perfschema/unittest/CMakeLists.txt b/storage/perfschema/unittest/CMakeLists.txt
index f2d67ce2882..b449640b374 100644
--- a/storage/perfschema/unittest/CMakeLists.txt
+++ b/storage/perfschema/unittest/CMakeLists.txt
@@ -1,5 +1,4 @@
-# Copyright (c) 2009, 2010 Sun Microsystems, Inc.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -16,13 +15,18 @@
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/include/mysql
- ${CMAKE_SOURCE_DIR}/regex
+ ${PCRE_INCLUDES}
${CMAKE_SOURCE_DIR}/sql
- ${CMAKE_SOURCE_DIR}/extra/yassl/include
+ ${SSL_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/unittest/mytap
${CMAKE_SOURCE_DIR}/storage/perfschema)
-ADD_DEFINITIONS(-DMYSQL_SERVER)
+ADD_DEFINITIONS(-DMYSQL_SERVER ${SSL_DEFINES})
-MY_ADD_TESTS(pfs_instr_class pfs_instr_class-oom pfs_instr pfs_instr-oom pfs
- EXT "cc" LINK_LIBRARIES perfschema mysys)
+ADD_CONVENIENCE_LIBRARY(pfs_server_stubs pfs_server_stubs.cc)
+
+ADD_DEPENDENCIES(pfs_server_stubs GenError)
+
+MY_ADD_TESTS(pfs_instr_class pfs_instr_class-oom pfs_instr pfs_instr-oom
+ pfs_account-oom pfs_host-oom pfs_timer pfs_user-oom pfs pfs_misc
+ EXT "cc" LINK_LIBRARIES perfschema mysys pfs_server_stubs)
diff --git a/storage/perfschema/unittest/conf.txt b/storage/perfschema/unittest/conf.txt
index e6cf7962ccc..8a14b9ed14b 100644
--- a/storage/perfschema/unittest/conf.txt
+++ b/storage/perfschema/unittest/conf.txt
@@ -1,5 +1,4 @@
-# Copyright (c) 2009, 2010 Sun Microsystems, Inc.
-# Use is subject to license terms
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/storage/perfschema/unittest/pfs-t.cc b/storage/perfschema/unittest/pfs-t.cc
index a360fb68fe6..e2ff73699ec 100644
--- a/storage/perfschema/unittest/pfs-t.cc
+++ b/storage/perfschema/unittest/pfs-t.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,7 +25,9 @@
#include <memory.h>
#include "stub_print_error.h"
-#include "stub_server_misc.h"
+#include "stub_pfs_defaults.h"
+
+void unload_performance_schema();
/* test helpers, to simulate the setup */
@@ -79,6 +81,7 @@ void test_bootstrap()
diag("test_bootstrap");
+ memset(& param, 0xFF, sizeof(param));
param.m_enabled= true;
param.m_mutex_class_sizing= 0;
param.m_rwlock_class_sizing= 0;
@@ -86,6 +89,7 @@ void test_bootstrap()
param.m_thread_class_sizing= 0;
param.m_table_share_sizing= 0;
param.m_file_class_sizing= 0;
+ param.m_socket_class_sizing= 0;
param.m_mutex_sizing= 0;
param.m_rwlock_sizing= 0;
param.m_cond_sizing= 0;
@@ -93,8 +97,23 @@ void test_bootstrap()
param.m_table_sizing= 0;
param.m_file_sizing= 0;
param.m_file_handle_sizing= 0;
+ param.m_socket_sizing= 0;
param.m_events_waits_history_sizing= 0;
param.m_events_waits_history_long_sizing= 0;
+ param.m_setup_actor_sizing= 0;
+ param.m_setup_object_sizing= 0;
+ param.m_user_sizing= 0;
+ param.m_account_sizing= 0;
+ param.m_host_sizing= 0;
+ param.m_stage_class_sizing= 0;
+ param.m_events_stages_history_sizing= 0;
+ param.m_events_stages_history_long_sizing= 0;
+ param.m_statement_class_sizing= 0;
+ param.m_events_statements_history_sizing= 0;
+ param.m_events_statements_history_long_sizing= 0;
+ param.m_digest_sizing= 0;
+ param.m_session_connect_attrs_sizing= 0;
+ param.m_max_digest_length= 0;
boot= initialize_performance_schema(& param);
ok(boot != NULL, "boot");
@@ -109,7 +128,7 @@ void test_bootstrap()
psi_2= boot->get_interface(PSI_VERSION_2);
ok(psi_2 == NULL, "version 2");
- shutdown_performance_schema();
+ unload_performance_schema();
}
/*
@@ -121,6 +140,7 @@ PSI * load_perfschema()
PSI_bootstrap *boot;
PFS_global_param param;
+ memset(& param, 0xFF, sizeof(param));
param.m_enabled= true;
param.m_mutex_class_sizing= 10;
param.m_rwlock_class_sizing= 10;
@@ -128,6 +148,7 @@ PSI * load_perfschema()
param.m_thread_class_sizing= 10;
param.m_table_share_sizing= 10;
param.m_file_class_sizing= 10;
+ param.m_socket_class_sizing= 10;
param.m_mutex_sizing= 10;
param.m_rwlock_sizing= 10;
param.m_cond_sizing= 10;
@@ -135,16 +156,56 @@ PSI * load_perfschema()
param.m_table_sizing= 10;
param.m_file_sizing= 10;
param.m_file_handle_sizing= 50;
+ param.m_socket_sizing= 10;
param.m_events_waits_history_sizing= 10;
param.m_events_waits_history_long_sizing= 10;
+ param.m_setup_actor_sizing= 0;
+ param.m_setup_object_sizing= 0;
+ param.m_user_sizing= 0;
+ param.m_account_sizing= 0;
+ param.m_host_sizing= 0;
+ param.m_stage_class_sizing= 0;
+ param.m_events_stages_history_sizing= 0;
+ param.m_events_stages_history_long_sizing= 0;
+ param.m_statement_class_sizing= 0;
+ param.m_events_statements_history_sizing= 0;
+ param.m_events_statements_history_long_sizing= 0;
+ param.m_digest_sizing= 0;
+ param.m_session_connect_attrs_sizing= 0;
+ param.m_max_digest_length= 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 unload_performance_schema()
+{
+ cleanup_table_share();
+ 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_digest();
+
+ shutdown_performance_schema();
+}
+
void test_bad_registration()
{
PSI *psi;
@@ -478,7 +539,72 @@ void test_bad_registration()
psi->register_file("X", bad_file_3, 1);
ok(dummy_file_key == 2, "assigned key");
- shutdown_performance_schema();
+ /*
+ 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");
+
+ unload_performance_schema();
}
void test_init_disabled()
@@ -513,6 +639,12 @@ void test_init_disabled()
{ & file_key_A, "F-A", 0}
};
+ PSI_socket_key socket_key_A;
+ PSI_socket_info all_socket[]=
+ {
+ { & socket_key_A, "S-A", 0}
+ };
+
PSI_thread_key thread_key_1;
PSI_thread_info all_thread[]=
{
@@ -523,16 +655,19 @@ void test_init_disabled()
psi->register_rwlock("test", all_rwlock, 1);
psi->register_cond("test", all_cond, 1);
psi->register_file("test", all_file, 1);
+ psi->register_socket("test", all_socket, 1);
psi->register_thread("test", all_thread, 1);
PFS_mutex_class *mutex_class_A;
PFS_rwlock_class *rwlock_class_A;
PFS_cond_class *cond_class_A;
PFS_file_class *file_class_A;
+ PFS_socket_class *socket_class_A;
PSI_mutex *mutex_A1;
PSI_rwlock *rwlock_A1;
PSI_cond *cond_A1;
PFS_file *file_A1;
+ PSI_socket *socket_A1;
PSI_thread *thread_1;
/* Preparation */
@@ -553,8 +688,11 @@ void test_init_disabled()
file_class_A= find_file_class(file_key_A);
ok(file_class_A != NULL, "file class A");
- /* Pretend thread T-1 is running, and disabled */
- /* ------------------------------------------- */
+ socket_class_A= find_socket_class(socket_key_A);
+ ok(socket_class_A != NULL, "socket class A");
+
+ /* Pretend thread T-1 is running, and disabled, with thread_instrumentation */
+ /* ------------------------------------------------------------------------ */
psi->set_thread(thread_1);
setup_thread(thread_1, false);
@@ -563,61 +701,61 @@ void test_init_disabled()
mutex_class_A->m_enabled= false;
mutex_A1= psi->init_mutex(mutex_key_A, NULL);
- ok(mutex_A1 == NULL, "not instrumented");
+ ok(mutex_A1 == NULL, "mutex_A1 not instrumented");
- /* enabled M-A + disabled T-1: no instrumentation */
+ /* enabled M-A + disabled T-1: instrumentation (for later) */
mutex_class_A->m_enabled= true;
mutex_A1= psi->init_mutex(mutex_key_A, NULL);
- ok(mutex_A1 == NULL, "not instrumented");
+ ok(mutex_A1 != NULL, "mutex_A1 instrumented");
/* broken key + disabled T-1: no instrumentation */
mutex_class_A->m_enabled= true;
mutex_A1= psi->init_mutex(0, NULL);
- ok(mutex_A1 == NULL, "not instrumented");
+ ok(mutex_A1 == NULL, "mutex key 0 not instrumented");
mutex_A1= psi->init_mutex(99, NULL);
- ok(mutex_A1 == NULL, "not instrumented");
+ ok(mutex_A1 == NULL, "broken mutex key not instrumented");
/* disabled RW-A + disabled T-1: no instrumentation */
rwlock_class_A->m_enabled= false;
rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL);
- ok(rwlock_A1 == NULL, "not instrumented");
+ ok(rwlock_A1 == NULL, "rwlock_A1 not instrumented");
- /* enabled RW-A + disabled T-1: no instrumentation */
+ /* enabled RW-A + disabled T-1: instrumentation (for later) */
rwlock_class_A->m_enabled= true;
rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL);
- ok(rwlock_A1 == NULL, "not instrumented");
+ ok(rwlock_A1 != NULL, "rwlock_A1 instrumented");
/* broken key + disabled T-1: no instrumentation */
rwlock_class_A->m_enabled= true;
rwlock_A1= psi->init_rwlock(0, NULL);
- ok(rwlock_A1 == NULL, "not instrumented");
+ ok(rwlock_A1 == NULL, "rwlock key 0 not instrumented");
rwlock_A1= psi->init_rwlock(99, NULL);
- ok(rwlock_A1 == NULL, "not instrumented");
+ ok(rwlock_A1 == NULL, "broken rwlock key not instrumented");
/* disabled C-A + disabled T-1: no instrumentation */
cond_class_A->m_enabled= false;
cond_A1= psi->init_cond(cond_key_A, NULL);
- ok(cond_A1 == NULL, "not instrumented");
+ ok(cond_A1 == NULL, "cond_A1 not instrumented");
- /* enabled C-A + disabled T-1: no instrumentation */
+ /* enabled C-A + disabled T-1: instrumentation (for later) */
cond_class_A->m_enabled= true;
cond_A1= psi->init_cond(cond_key_A, NULL);
- ok(cond_A1 == NULL, "not instrumented");
+ ok(cond_A1 != NULL, "cond_A1 instrumented");
/* broken key + disabled T-1: no instrumentation */
cond_class_A->m_enabled= true;
cond_A1= psi->init_cond(0, NULL);
- ok(cond_A1 == NULL, "not instrumented");
+ ok(cond_A1 == NULL, "cond key 0 not instrumented");
cond_A1= psi->init_cond(99, NULL);
- ok(cond_A1 == NULL, "not instrumented");
+ ok(cond_A1 == NULL, "broken cond key not instrumented");
/* disabled F-A + disabled T-1: no instrumentation */
@@ -643,6 +781,26 @@ void test_init_disabled()
file_A1= lookup_file_by_name("foo");
ok(file_A1 == NULL, "not instrumented");
+ /* disabled S-A + disabled T-1: no instrumentation */
+
+ socket_class_A->m_enabled= false;
+ socket_A1= psi->init_socket(socket_key_A, NULL, 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 */
/* ----------------------------- */
@@ -739,17 +897,38 @@ void test_init_disabled()
file_class_A->m_enabled= true;
psi->create_file(file_key_A, "foo-instrumented", (File) 12);
file_A1= lookup_file_by_name("foo-instrumented");
- ok(file_A1 != NULL, "instrumented");
+ ok(file_A1 != NULL, "file_A1 instrumented");
+ destroy_file(reinterpret_cast<PFS_thread*>(psi->get_thread()), file_A1);
/* broken key + enabled T-1: no instrumentation */
file_class_A->m_enabled= true;
psi->create_file(0, "foo", (File) 12);
file_A1= lookup_file_by_name("foo");
- ok(file_A1 == NULL, "not instrumented");
+ ok(file_A1 == NULL, "file key 0 not instrumented");
psi->create_file(99, "foo", (File) 12);
file_A1= lookup_file_by_name("foo");
- ok(file_A1 == NULL, "not instrumented");
+ ok(file_A1 == NULL, "broken file key not instrumented");
+
+ /* disabled S-A + enabled T-1: no instrumentation */
+
+ socket_class_A->m_enabled= false;
+ ok(socket_A1 == NULL, "not instrumented");
+
+ /* enabled S-A + enabled T-1: instrumentation */
+
+ socket_class_A->m_enabled= true;
+ socket_A1= psi->init_socket(socket_key_A, NULL, 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 */
/* ---------------------------------------------- */
@@ -760,61 +939,61 @@ void test_init_disabled()
mutex_class_A->m_enabled= false;
mutex_A1= psi->init_mutex(mutex_key_A, NULL);
- ok(mutex_A1 == NULL, "not instrumented");
+ ok(mutex_A1 == NULL, "mutex_A1 not instrumented");
- /* enabled M-A + unknown thread: no instrumentation */
+ /* enabled M-A + unknown thread: instrumentation (for later) */
mutex_class_A->m_enabled= true;
mutex_A1= psi->init_mutex(mutex_key_A, NULL);
- ok(mutex_A1 == NULL, "not instrumented");
+ ok(mutex_A1 != NULL, "mutex_A1 instrumented");
/* broken key + unknown thread: no instrumentation */
mutex_class_A->m_enabled= true;
mutex_A1= psi->init_mutex(0, NULL);
- ok(mutex_A1 == NULL, "not instrumented");
+ ok(mutex_A1 == NULL, "mutex key 0 not instrumented");
mutex_A1= psi->init_mutex(99, NULL);
- ok(mutex_A1 == NULL, "not instrumented");
+ ok(mutex_A1 == NULL, "broken mutex key not instrumented");
/* disabled RW-A + unknown thread: no instrumentation */
rwlock_class_A->m_enabled= false;
rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL);
- ok(rwlock_A1 == NULL, "not instrumented");
+ ok(rwlock_A1 == NULL, "rwlock_A1 not instrumented");
- /* enabled RW-A + unknown thread: no instrumentation */
+ /* enabled RW-A + unknown thread: instrumentation (for later) */
rwlock_class_A->m_enabled= true;
rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL);
- ok(rwlock_A1 == NULL, "not instrumented");
+ ok(rwlock_A1 != NULL, "rwlock_A1 instrumented");
/* broken key + unknown thread: no instrumentation */
rwlock_class_A->m_enabled= true;
rwlock_A1= psi->init_rwlock(0, NULL);
- ok(rwlock_A1 == NULL, "not instrumented");
+ ok(rwlock_A1 == NULL, "rwlock key 0 not instrumented");
rwlock_A1= psi->init_rwlock(99, NULL);
- ok(rwlock_A1 == NULL, "not instrumented");
+ ok(rwlock_A1 == NULL, "broken rwlock key not instrumented");
/* disabled C-A + unknown thread: no instrumentation */
cond_class_A->m_enabled= false;
cond_A1= psi->init_cond(cond_key_A, NULL);
- ok(cond_A1 == NULL, "not instrumented");
+ ok(cond_A1 == NULL, "cond_A1 not instrumented");
- /* enabled C-A + unknown thread: no instrumentation */
+ /* enabled C-A + unknown thread: instrumentation (for later) */
cond_class_A->m_enabled= true;
cond_A1= psi->init_cond(cond_key_A, NULL);
- ok(cond_A1 == NULL, "not instrumented");
+ ok(cond_A1 != NULL, "cond_A1 instrumented");
/* broken key + unknown thread: no instrumentation */
cond_class_A->m_enabled= true;
cond_A1= psi->init_cond(0, NULL);
- ok(cond_A1 == NULL, "not instrumented");
+ ok(cond_A1 == NULL, "cond key 0 not instrumented");
cond_A1= psi->init_cond(99, NULL);
- ok(cond_A1 == NULL, "not instrumented");
+ ok(cond_A1 == NULL, "broken cond key not instrumented");
/* disabled F-A + unknown thread: no instrumentation */
@@ -840,7 +1019,27 @@ void test_init_disabled()
file_A1= lookup_file_by_name("foo");
ok(file_A1 == NULL, "not instrumented");
- shutdown_performance_schema();
+ /* 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");
+
+ unload_performance_schema();
}
void test_locker_disabled()
@@ -875,6 +1074,12 @@ void test_locker_disabled()
{ & file_key_A, "F-A", 0}
};
+ PSI_socket_key socket_key_A;
+ PSI_socket_info all_socket[]=
+ {
+ { & socket_key_A, "S-A", 0}
+ };
+
PSI_thread_key thread_key_1;
PSI_thread_info all_thread[]=
{
@@ -885,16 +1090,19 @@ void test_locker_disabled()
psi->register_rwlock("test", all_rwlock, 1);
psi->register_cond("test", all_cond, 1);
psi->register_file("test", all_file, 1);
+ psi->register_socket("test", all_socket, 1);
psi->register_thread("test", all_thread, 1);
PFS_mutex_class *mutex_class_A;
PFS_rwlock_class *rwlock_class_A;
PFS_cond_class *cond_class_A;
PFS_file_class *file_class_A;
+ PFS_socket_class *socket_class_A;
PSI_mutex *mutex_A1;
PSI_rwlock *rwlock_A1;
PSI_cond *cond_A1;
PSI_file *file_A1;
+ PSI_socket *socket_A1;
PSI_thread *thread_1;
/* Preparation */
@@ -915,6 +1123,9 @@ void test_locker_disabled()
file_class_A= find_file_class(file_key_A);
ok(file_class_A != NULL, "file info A");
+ socket_class_A= find_socket_class(socket_key_A);
+ ok(socket_class_A != NULL, "socket info A");
+
/* Pretend thread T-1 is running, and enabled */
/* ------------------------------------------ */
@@ -939,6 +1150,15 @@ void test_locker_disabled()
psi->create_file(file_key_A, "foo", (File) 12);
file_A1= (PSI_file*) lookup_file_by_name("foo");
ok(file_A1 != NULL, "instrumented");
+ destroy_file(reinterpret_cast<PFS_thread*>(psi->get_thread()),
+ reinterpret_cast<PFS_file*>(file_A1));
+
+ 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;
@@ -948,6 +1168,8 @@ void test_locker_disabled()
PSI_cond_locker_state cond_state;
PSI_file_locker *file_locker;
PSI_file_locker_state file_state;
+ PSI_socket_locker *socket_locker;
+ PSI_socket_locker_state socket_state;
/* Pretend thread T-1 is disabled */
/* ------------------------------ */
@@ -958,58 +1180,110 @@ void test_locker_disabled()
rwlock_class_A->m_enabled= true;
cond_class_A->m_enabled= true;
file_class_A->m_enabled= true;
-
- mutex_locker= psi->get_thread_mutex_locker(&mutex_state, mutex_A1, PSI_MUTEX_LOCK);
- ok(mutex_locker == NULL, "no locker");
- rwlock_locker= psi->get_thread_rwlock_locker(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK);
- ok(rwlock_locker == NULL, "no locker");
- cond_locker= psi->get_thread_cond_locker(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT);
- ok(cond_locker == NULL, "no locker");
+ socket_class_A->m_enabled= true;
+
+ mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12);
+ ok(mutex_locker == NULL, "no locker (T-1 disabled)");
+ rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12);
+ ok(rwlock_locker == NULL, "no locker (T-1 disabled)");
+ cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12);
+ ok(cond_locker == NULL, "no locker (T-1 disabled)");
file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL);
- ok(file_locker == NULL, "no locker");
+ ok(file_locker == NULL, "no locker (T-1 disabled)");
file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ);
- ok(file_locker == NULL, "no locker");
+ ok(file_locker == NULL, "no locker (T-1 disabled)");
file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ);
- ok(file_locker == NULL, "no locker");
+ ok(file_locker == NULL, "no locker (T-1 disabled)");
+ socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12);
+ ok(socket_locker == NULL, "no locker (T-1 disabled)");
- /* Pretend the consumer is disabled */
- /* -------------------------------- */
+ /* Pretend the global consumer is disabled */
+ /* --------------------------------------- */
setup_thread(thread_1, true);
- flag_events_waits_current= false;
+ flag_global_instrumentation= false;
mutex_class_A->m_enabled= true;
rwlock_class_A->m_enabled= true;
cond_class_A->m_enabled= true;
file_class_A->m_enabled= true;
+ socket_class_A->m_enabled= true;
+ update_instruments_derived_flags();
+
+ mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12);
+ ok(mutex_locker == NULL, "no locker (global disabled)");
+ rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12);
+ ok(rwlock_locker == NULL, "no locker (global disabled)");
+ cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12);
+ ok(cond_locker == NULL, "no locker (global disabled)");
+ file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL);
+ ok(file_locker == NULL, "no locker (global disabled)");
+ file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ);
+ ok(file_locker == NULL, "no locker (global disabled)");
+ file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ);
+ ok(file_locker == NULL, "no locker (global disabled)");
+ socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12);
+ ok(socket_locker == NULL, "no locker (global disabled)");
- mutex_locker= psi->get_thread_mutex_locker(&mutex_state, mutex_A1, PSI_MUTEX_LOCK);
- ok(mutex_locker == NULL, "no locker");
- rwlock_locker= psi->get_thread_rwlock_locker(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK);
- ok(rwlock_locker == NULL, "no locker");
- cond_locker= psi->get_thread_cond_locker(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT);
- ok(cond_locker == NULL, "no locker");
+ /* Pretend the mode is global, counted only */
+ /* ---------------------------------------- */
+
+ setup_thread(thread_1, true);
+ flag_global_instrumentation= true;
+ flag_thread_instrumentation= false;
+ mutex_class_A->m_enabled= true;
+ mutex_class_A->m_timed= false;
+ rwlock_class_A->m_enabled= true;
+ rwlock_class_A->m_timed= false;
+ cond_class_A->m_enabled= true;
+ cond_class_A->m_timed= false;
+ file_class_A->m_enabled= true;
+ file_class_A->m_timed= false;
+ socket_class_A->m_enabled= true;
+ socket_class_A->m_timed= false;
+ update_instruments_derived_flags();
+
+ mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12);
+ ok(mutex_locker == NULL, "no locker (global counted)");
+ rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12);
+ ok(rwlock_locker == NULL, "no locker (global counted)");
+ cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12);
+ ok(cond_locker == NULL, "no locker (global counted)");
file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL);
- ok(file_locker == NULL, "no locker");
+ ok(file_locker != NULL, "locker (global counted)");
+ psi->start_file_wait(file_locker, 10, __FILE__, __LINE__);
+ psi->end_file_wait(file_locker, 10);
file_locker= psi->get_thread_file_stream_locker(&file_state, file_A1, PSI_FILE_READ);
- ok(file_locker == NULL, "no locker");
+ ok(file_locker != NULL, "locker (global counted)");
+ psi->start_file_wait(file_locker, 10, __FILE__, __LINE__);
+ psi->end_file_wait(file_locker, 10);
file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ);
- ok(file_locker == NULL, "no locker");
+ ok(file_locker != NULL, "locker (global counted)");
+ psi->start_file_wait(file_locker, 10, __FILE__, __LINE__);
+ psi->end_file_wait(file_locker, 10);
+ /* The null locker shortcut applies only to socket ops with no byte count */
+ socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_BIND, 0, "foo.cc", 12);
+ ok(socket_locker == NULL, "no locker (global counted)");
+
+ /* TODO */
/* Pretend the instrument is disabled */
/* ---------------------------------- */
setup_thread(thread_1, true);
+ flag_global_instrumentation= true;
flag_events_waits_current= true;
mutex_class_A->m_enabled= false;
rwlock_class_A->m_enabled= false;
cond_class_A->m_enabled= false;
file_class_A->m_enabled= false;
+ socket_class_A->m_enabled= false;
+ update_instruments_derived_flags();
- mutex_locker= psi->get_thread_mutex_locker(&mutex_state, mutex_A1, PSI_MUTEX_LOCK);
+ mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12);
ok(mutex_locker == NULL, "no locker");
- rwlock_locker= psi->get_thread_rwlock_locker(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK);
+ rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12);
ok(rwlock_locker == NULL, "no locker");
- cond_locker= psi->get_thread_cond_locker(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT);
+ cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12);
ok(cond_locker == NULL, "no locker");
file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL);
ok(file_locker == NULL, "no locker");
@@ -1017,33 +1291,41 @@ void test_locker_disabled()
ok(file_locker == NULL, "no locker");
file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ);
ok(file_locker == NULL, "no locker");
+ socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12);
+ ok(socket_locker == NULL, "no locker");
- /* Pretend everything is enabled */
- /* ----------------------------- */
+ /* Pretend everything is enabled and timed */
+ /* --------------------------------------- */
setup_thread(thread_1, true);
+ flag_global_instrumentation= true;
+ flag_thread_instrumentation= true;
flag_events_waits_current= true;
mutex_class_A->m_enabled= true;
+ mutex_class_A->m_timed= true;
rwlock_class_A->m_enabled= true;
+ rwlock_class_A->m_timed= true;
cond_class_A->m_enabled= true;
+ cond_class_A->m_timed= true;
file_class_A->m_enabled= true;
+ file_class_A->m_timed= true;
+ socket_class_A->m_enabled= true;
+ socket_class_A->m_timed= true;
+ update_instruments_derived_flags();
- mutex_locker= psi->get_thread_mutex_locker(&mutex_state, mutex_A1, PSI_MUTEX_LOCK);
+ mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, __FILE__, __LINE__);
ok(mutex_locker != NULL, "locker");
- psi->start_mutex_wait(mutex_locker, __FILE__, __LINE__);
psi->end_mutex_wait(mutex_locker, 0);
- rwlock_locker= psi->get_thread_rwlock_locker(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK);
+ rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, __FILE__, __LINE__);
ok(rwlock_locker != NULL, "locker");
- psi->start_rwlock_rdwait(rwlock_locker, __FILE__, __LINE__);
psi->end_rwlock_rdwait(rwlock_locker, 0);
- cond_locker= psi->get_thread_cond_locker(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT);
+ cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, __FILE__, __LINE__);
ok(cond_locker != NULL, "locker");
- psi->start_cond_wait(cond_locker, __FILE__, __LINE__);
psi->end_cond_wait(cond_locker, 0);
- file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL);
+ 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);
+ 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__);
@@ -1052,6 +1334,20 @@ void test_locker_disabled()
ok(file_locker != NULL, "locker");
psi->start_file_wait(file_locker, 10, __FILE__, __LINE__);
psi->end_file_wait(file_locker, 10);
+ socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12);
+ ok(socket_locker != NULL, "locker");
+ psi->end_socket_wait(socket_locker, 10);
+
+ /* Pretend the socket does not have a thread owner */
+ /* ---------------------------------------------- */
+
+ socket_class_A->m_enabled= true;
+ socket_A1= psi->init_socket(socket_key_A, NULL, 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, "locker (owner not used)");
+ psi->end_socket_wait(socket_locker, 10);
/* Pretend the running thread is not instrumented */
/* ---------------------------------------------- */
@@ -1062,12 +1358,14 @@ void test_locker_disabled()
rwlock_class_A->m_enabled= true;
cond_class_A->m_enabled= true;
file_class_A->m_enabled= true;
+ socket_class_A->m_enabled= true;
+ update_instruments_derived_flags();
- mutex_locker= psi->get_thread_mutex_locker(&mutex_state, mutex_A1, PSI_MUTEX_LOCK);
+ mutex_locker= psi->start_mutex_wait(&mutex_state, mutex_A1, PSI_MUTEX_LOCK, "foo.cc", 12);
ok(mutex_locker == NULL, "no locker");
- rwlock_locker= psi->get_thread_rwlock_locker(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK);
+ rwlock_locker= psi->start_rwlock_rdwait(&rwlock_state, rwlock_A1, PSI_RWLOCK_READLOCK, "foo.cc", 12);
ok(rwlock_locker == NULL, "no locker");
- cond_locker= psi->get_thread_cond_locker(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT);
+ cond_locker= psi->start_cond_wait(&cond_state, cond_A1, mutex_A1, PSI_COND_WAIT, "foo.cc", 12);
ok(cond_locker == NULL, "no locker");
file_locker= psi->get_thread_file_name_locker(&file_state, file_key_A, PSI_FILE_OPEN, "xxx", NULL);
ok(file_locker == NULL, "no locker");
@@ -1075,8 +1373,10 @@ void test_locker_disabled()
ok(file_locker == NULL, "no locker");
file_locker= psi->get_thread_file_descriptor_locker(&file_state, (File) 12, PSI_FILE_READ);
ok(file_locker == NULL, "no locker");
+ socket_locker= psi->start_socket_wait(&socket_state, socket_A1, PSI_SOCKET_SEND, 12, "foo.cc", 12);
+ ok(socket_locker == NULL, "no locker");
- shutdown_performance_schema();
+ unload_performance_schema();
}
void test_file_instrumentation_leak()
@@ -1163,7 +1463,7 @@ void test_file_instrumentation_leak()
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();
+ unload_performance_schema();
}
void test_enabled()
@@ -1199,10 +1499,158 @@ void test_enabled()
{ & cond_key_B, "C-B", 0}
};
- shutdown_performance_schema();
+ unload_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_max_digest_length= 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. */
@@ -1212,14 +1660,14 @@ void do_all_tests()
test_init_disabled();
test_locker_disabled();
test_file_instrumentation_leak();
+ test_event_name_index();
}
int main(int argc, char **argv)
{
- plan(153);
+ plan(216);
MY_INIT(argv[0]);
do_all_tests();
my_end(0);
- return 0;
+ return (exit_status());
}
-
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..71c089ab0f5
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_account-oom-t.cc
@@ -0,0 +1,113 @@
+/* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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 <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()
+{
+ test_oom();
+}
+
+int main(int, char **)
+{
+ plan(6);
+ MY_INIT("pfs_account-oom-t");
+ do_all_tests();
+ my_end(0);
+ return (exit_status());
+}
+
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..3dd62ca5662
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_connect_attr-t.cc
@@ -0,0 +1,345 @@
+/* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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 (exit_status());
+}
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..e2eba7e6aff
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_host-oom-t.cc
@@ -0,0 +1,113 @@
+/* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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 <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()
+{
+ test_oom();
+}
+
+int main(int, char **)
+{
+ plan(6);
+ MY_INIT("pfs_host-oom-t");
+ do_all_tests();
+ my_end(0);
+ return (exit_status());
+}
+
diff --git a/storage/perfschema/unittest/pfs_instr-oom-t.cc b/storage/perfschema/unittest/pfs_instr-oom-t.cc
index 25fdb4512bc..a18902dc3db 100644
--- a/storage/perfschema/unittest/pfs_instr-oom-t.cc
+++ b/storage/perfschema/unittest/pfs_instr-oom-t.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,10 +18,12 @@
#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()
{
@@ -30,6 +32,7 @@ void test_oom()
stub_alloc_always_fails= true;
+ memset(& param, 0xFF, sizeof(param));
param.m_enabled= true;
param.m_mutex_class_sizing= 10;
param.m_rwlock_class_sizing= 0;
@@ -37,6 +40,7 @@ void test_oom()
param.m_thread_class_sizing= 0;
param.m_table_share_sizing= 0;
param.m_file_class_sizing= 0;
+ param.m_socket_class_sizing= 0;
param.m_mutex_sizing= 1000;
param.m_rwlock_sizing= 0;
param.m_cond_sizing= 0;
@@ -44,11 +48,26 @@ void test_oom()
param.m_table_sizing= 0;
param.m_file_sizing= 0;
param.m_file_handle_sizing= 0;
+ param.m_socket_sizing= 0;
param.m_events_waits_history_sizing= 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;
@@ -57,6 +76,7 @@ void test_oom()
param.m_thread_class_sizing= 0;
param.m_table_share_sizing= 0;
param.m_file_class_sizing= 0;
+ param.m_socket_class_sizing= 0;
param.m_mutex_sizing= 0;
param.m_rwlock_sizing= 1000;
param.m_cond_sizing= 0;
@@ -64,11 +84,26 @@ void test_oom()
param.m_table_sizing= 0;
param.m_file_sizing= 0;
param.m_file_handle_sizing= 0;
+ param.m_socket_sizing= 0;
param.m_events_waits_history_sizing= 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;
@@ -77,6 +112,7 @@ void test_oom()
param.m_thread_class_sizing= 0;
param.m_table_share_sizing= 0;
param.m_file_class_sizing= 0;
+ param.m_socket_class_sizing= 0;
param.m_mutex_sizing= 0;
param.m_rwlock_sizing= 0;
param.m_cond_sizing= 1000;
@@ -84,11 +120,26 @@ void test_oom()
param.m_table_sizing= 0;
param.m_file_sizing= 0;
param.m_file_handle_sizing= 0;
+ param.m_socket_sizing= 0;
param.m_events_waits_history_sizing= 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;
@@ -97,6 +148,7 @@ void test_oom()
param.m_thread_class_sizing= 0;
param.m_table_share_sizing= 0;
param.m_file_class_sizing= 10;
+ param.m_socket_class_sizing= 0;
param.m_mutex_sizing= 0;
param.m_rwlock_sizing= 0;
param.m_cond_sizing= 0;
@@ -104,11 +156,60 @@ void test_oom()
param.m_table_sizing= 0;
param.m_file_sizing= 1000;
param.m_file_handle_sizing= 1000;
+ param.m_socket_sizing= 0;
param.m_events_waits_history_sizing= 0;
param.m_events_waits_history_long_sizing= 0;
+ param.m_setup_actor_sizing= 0;
+ param.m_setup_object_sizing= 0;
+ param.m_host_sizing= 0;
+ param.m_user_sizing= 0;
+ param.m_account_sizing= 0;
+ param.m_stage_class_sizing= 0;
+ param.m_events_stages_history_sizing= 0;
+ param.m_events_stages_history_long_sizing= 0;
+ param.m_statement_class_sizing= 0;
+ param.m_events_statements_history_sizing= 0;
+ param.m_events_statements_history_long_sizing= 0;
+ 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;
@@ -117,6 +218,7 @@ void test_oom()
param.m_thread_class_sizing= 0;
param.m_table_share_sizing= 10;
param.m_file_class_sizing= 0;
+ param.m_socket_class_sizing= 0;
param.m_mutex_sizing= 0;
param.m_rwlock_sizing= 0;
param.m_cond_sizing= 0;
@@ -124,11 +226,26 @@ void test_oom()
param.m_table_sizing= 1000;
param.m_file_sizing= 0;
param.m_file_handle_sizing= 0;
+ param.m_socket_sizing= 0;
param.m_events_waits_history_sizing= 0;
param.m_events_waits_history_long_sizing= 0;
+ param.m_setup_actor_sizing= 0;
+ param.m_setup_object_sizing= 0;
+ param.m_host_sizing= 0;
+ param.m_user_sizing= 0;
+ param.m_account_sizing= 0;
+ param.m_stage_class_sizing= 0;
+ param.m_events_stages_history_sizing= 0;
+ param.m_events_stages_history_long_sizing= 0;
+ param.m_statement_class_sizing= 0;
+ param.m_events_statements_history_sizing= 0;
+ param.m_events_statements_history_long_sizing= 0;
+ 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;
@@ -137,6 +254,7 @@ void test_oom()
param.m_thread_class_sizing= 10;
param.m_table_share_sizing= 0;
param.m_file_class_sizing= 0;
+ param.m_socket_class_sizing= 0;
param.m_mutex_sizing= 0;
param.m_rwlock_sizing= 0;
param.m_cond_sizing= 0;
@@ -144,11 +262,26 @@ void test_oom()
param.m_table_sizing= 0;
param.m_file_sizing= 0;
param.m_file_handle_sizing= 0;
+ param.m_socket_sizing= 0;
param.m_events_waits_history_sizing= 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;
@@ -159,6 +292,7 @@ void test_oom()
param.m_thread_class_sizing= 10;
param.m_table_share_sizing= 0;
param.m_file_class_sizing= 0;
+ param.m_socket_class_sizing= 0;
param.m_mutex_sizing= 0;
param.m_rwlock_sizing= 0;
param.m_cond_sizing= 0;
@@ -166,12 +300,27 @@ void test_oom()
param.m_table_sizing= 0;
param.m_file_sizing= 0;
param.m_file_handle_sizing= 0;
+ param.m_socket_sizing= 0;
param.m_events_waits_history_sizing= 10;
param.m_events_waits_history_long_sizing= 0;
+ param.m_setup_actor_sizing= 0;
+ param.m_setup_object_sizing= 0;
+ param.m_host_sizing= 0;
+ param.m_user_sizing= 0;
+ param.m_account_sizing= 0;
+ param.m_stage_class_sizing= 0;
+ param.m_events_stages_history_sizing= 0;
+ param.m_events_stages_history_long_sizing= 0;
+ param.m_statement_class_sizing= 0;
+ param.m_events_statements_history_sizing= 0;
+ param.m_events_statements_history_long_sizing= 0;
+ 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 history sizing)");
+ ok(rc == 1, "oom (thread waits history sizing)");
+ cleanup_instruments();
param.m_enabled= true;
param.m_mutex_class_sizing= 50;
@@ -180,6 +329,7 @@ void test_oom()
param.m_thread_class_sizing= 10;
param.m_table_share_sizing= 0;
param.m_file_class_sizing= 50;
+ param.m_socket_class_sizing= 0;
param.m_mutex_sizing= 0;
param.m_rwlock_sizing= 0;
param.m_cond_sizing= 0;
@@ -187,31 +337,352 @@ void test_oom()
param.m_table_sizing= 0;
param.m_file_sizing= 0;
param.m_file_handle_sizing= 0;
+ param.m_socket_sizing= 0;
param.m_events_waits_history_sizing= 0;
param.m_events_waits_history_long_sizing= 0;
+ param.m_setup_actor_sizing= 0;
+ param.m_setup_object_sizing= 0;
+ param.m_stage_class_sizing= 0;
+ param.m_events_stages_history_sizing= 0;
+ param.m_events_stages_history_long_sizing= 0;
+ param.m_statement_class_sizing= 0;
+ param.m_events_statements_history_sizing= 0;
+ param.m_events_statements_history_long_sizing= 0;
+ 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)");
+ cleanup_sync_class();
+ cleanup_thread_class();
+ cleanup_file_class();
+ 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_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_thread_class();
+ 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_stage_class();
+ cleanup_thread_class();
+ 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_thread_class();
+ 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_statement_class();
+ cleanup_thread_class();
+ 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_sync_class();
+ 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_sync_class();
+ cleanup_stage_class();
+ 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= 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_sync_class();
+ cleanup_statement_class();
cleanup_instruments();
}
void do_all_tests()
{
- PFS_atomic::init();
-
test_oom();
-
- PFS_atomic::cleanup();
}
int main(int argc, char **argv)
{
- plan(8);
+ plan(20);
MY_INIT(argv[0]);
do_all_tests();
my_end(0);
- return 0;
+ return (exit_status());
}
diff --git a/storage/perfschema/unittest/pfs_instr-t.cc b/storage/perfschema/unittest/pfs_instr-t.cc
index 9ec1dcbb8ba..47a91d9bb9a 100644
--- a/storage/perfschema/unittest/pfs_instr-t.cc
+++ b/storage/perfschema/unittest/pfs_instr-t.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,17 +18,18 @@
#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"
+PFS_global_param param;
void test_no_instruments()
{
int rc;
- PFS_global_param param;
+ memset(& param, 0xFF, sizeof(param));
param.m_enabled= true;
param.m_mutex_class_sizing= 0;
param.m_rwlock_class_sizing= 0;
@@ -36,6 +37,7 @@ void test_no_instruments()
param.m_thread_class_sizing= 0;
param.m_table_share_sizing= 0;
param.m_file_class_sizing= 0;
+ param.m_socket_class_sizing= 0;
param.m_mutex_sizing= 0;
param.m_rwlock_sizing= 0;
param.m_cond_sizing= 0;
@@ -43,9 +45,25 @@ void test_no_instruments()
param.m_table_sizing= 0;
param.m_file_sizing= 0;
param.m_file_handle_sizing= 0;
+ param.m_socket_sizing= 0;
param.m_events_waits_history_sizing= 0;
param.m_events_waits_history_long_sizing= 0;
-
+ param.m_setup_actor_sizing= 0;
+ param.m_setup_object_sizing= 0;
+ param.m_host_sizing= 0;
+ param.m_user_sizing= 0;
+ param.m_account_sizing= 0;
+ param.m_stage_class_sizing= 0;
+ param.m_events_stages_history_sizing= 0;
+ param.m_events_stages_history_long_sizing= 0;
+ param.m_statement_class_sizing= 0;
+ param.m_events_statements_history_sizing= 0;
+ param.m_events_statements_history_long_sizing= 0;
+ param.m_digest_sizing= 0;
+ param.m_session_connect_attrs_sizing= 0;
+ param.m_max_digest_length= 0;
+
+ init_event_name_sizing(& param);
rc= init_instruments(& param);
ok(rc == 0, "zero init");
@@ -61,14 +79,16 @@ void test_no_instances()
PFS_thread_class dummy_thread_class;
PFS_file_class dummy_file_class;
PFS_table_share dummy_table_share;
+ PFS_socket_class dummy_socket_class;
PFS_mutex *mutex;
PFS_rwlock *rwlock;
PFS_cond *cond;
PFS_thread *thread;
PFS_file *file;
+ PFS_socket *socket;
PFS_table *table;
- PFS_global_param param;
+ memset(& param, 0xFF, sizeof(param));
param.m_enabled= true;
param.m_mutex_class_sizing= 1;
param.m_rwlock_class_sizing= 1;
@@ -76,6 +96,7 @@ void test_no_instances()
param.m_thread_class_sizing= 1;
param.m_table_share_sizing= 1;
param.m_file_class_sizing= 1;
+ param.m_socket_class_sizing= 0;
param.m_mutex_sizing= 0;
param.m_rwlock_sizing= 0;
param.m_cond_sizing= 0;
@@ -83,9 +104,25 @@ void test_no_instances()
param.m_table_sizing= 0;
param.m_file_sizing= 0;
param.m_file_handle_sizing= 0;
+ param.m_socket_sizing= 0;
param.m_events_waits_history_sizing= 0;
param.m_events_waits_history_long_sizing= 0;
-
+ param.m_setup_actor_sizing= 0;
+ param.m_setup_object_sizing= 0;
+ param.m_host_sizing= 0;
+ param.m_user_sizing= 0;
+ param.m_account_sizing= 0;
+ param.m_stage_class_sizing= 0;
+ param.m_events_stages_history_sizing= 0;
+ param.m_events_stages_history_long_sizing= 0;
+ param.m_statement_class_sizing= 0;
+ param.m_events_statements_history_sizing= 0;
+ param.m_events_statements_history_long_sizing= 0;
+ param.m_digest_sizing= 0;
+ param.m_session_connect_attrs_sizing= 0;
+ param.m_max_digest_length= 0;
+
+ init_event_name_sizing(& param);
rc= init_instruments(& param);
ok(rc == 0, "no instances init");
@@ -120,19 +157,19 @@ void test_no_instances()
PFS_thread fake_thread;
fake_thread.m_filename_hash_pins= NULL;
- file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5);
+ 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);
+ 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);
+ 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);
+ file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true);
ok(file == NULL, "no file");
ok(file_lost == 4, "lost 4");
@@ -140,20 +177,27 @@ void test_no_instances()
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);
+ 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, NULL);
+ table= create_table(& dummy_table_share, & fake_thread, NULL);
ok(table == NULL, "no table");
ok(table_lost == 1, "lost 1");
- table= create_table(& dummy_table_share, NULL);
+ table= create_table(& dummy_table_share, & fake_thread, NULL);
ok(table == NULL, "no table");
ok(table_lost == 2, "lost 2");
+ socket= create_socket(& dummy_socket_class, NULL, 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_per_thread_wait_stat();
+ reset_events_waits_by_thread();
cleanup_file_hash();
cleanup_instruments();
@@ -167,6 +211,7 @@ void test_with_instances()
PFS_cond_class dummy_cond_class;
PFS_thread_class dummy_thread_class;
PFS_file_class dummy_file_class;
+ PFS_socket_class dummy_socket_class;
PFS_table_share dummy_table_share;
PFS_mutex *mutex_1;
PFS_mutex *mutex_2;
@@ -178,10 +223,12 @@ void test_with_instances()
PFS_thread *thread_2;
PFS_file *file_1;
PFS_file *file_2;
+ PFS_socket *socket_1;
+ PFS_socket *socket_2;
PFS_table *table_1;
PFS_table *table_2;
- PFS_global_param param;
+ memset(& param, 0xFF, sizeof(param));
param.m_enabled= true;
param.m_mutex_class_sizing= 1;
param.m_rwlock_class_sizing= 1;
@@ -189,6 +236,7 @@ void test_with_instances()
param.m_thread_class_sizing= 1;
param.m_table_share_sizing= 1;
param.m_file_class_sizing= 1;
+ param.m_socket_class_sizing= 1;
param.m_mutex_sizing= 2;
param.m_rwlock_sizing= 2;
param.m_cond_sizing= 2;
@@ -196,12 +244,34 @@ void test_with_instances()
param.m_table_sizing= 2;
param.m_file_sizing= 2;
param.m_file_handle_sizing= 100;
+ param.m_socket_sizing= 2;
param.m_events_waits_history_sizing= 10;
param.m_events_waits_history_long_sizing= 10000;
-
+ param.m_setup_actor_sizing= 0;
+ param.m_setup_object_sizing= 0;
+ param.m_host_sizing= 0;
+ param.m_user_sizing= 0;
+ param.m_account_sizing= 0;
+ param.m_stage_class_sizing= 0;
+ param.m_events_stages_history_sizing= 0;
+ param.m_events_stages_history_long_sizing= 0;
+ param.m_statement_class_sizing= 0;
+ param.m_events_statements_history_sizing= 0;
+ param.m_events_statements_history_long_sizing= 0;
+ param.m_digest_sizing= 0;
+ param.m_session_connect_attrs_sizing= 0;
+ param.m_max_digest_length= 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");
@@ -261,161 +331,88 @@ void test_with_instances()
PFS_thread fake_thread;
fake_thread.m_filename_hash_pins= NULL;
- file_1= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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");
- table_1= create_table(& dummy_table_share, NULL);
+ 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, NULL);
+ table_2= create_table(& dummy_table_share, & fake_thread, NULL);
ok(table_2 != NULL, "table");
ok(table_lost == 0, "not lost");
- table_2= create_table(& dummy_table_share, NULL);
+ table_2= create_table(& dummy_table_share, & fake_thread, NULL);
ok(table_2 == NULL, "no table");
ok(table_lost == 1, "lost 1");
destroy_table(table_1);
- table_2= create_table(& dummy_table_share, NULL);
+ table_2= create_table(& dummy_table_share, & fake_thread, NULL);
ok(table_2 != NULL, "table");
ok(table_lost == 1, "no new loss");
//TODO: test that cleanup works
reset_events_waits_by_instance();
- reset_per_thread_wait_stat();
+ reset_events_waits_by_thread();
cleanup_file_hash();
cleanup_instruments();
}
-void test_per_thread_wait()
-{
- int rc;
- PFS_mutex_class dummy_mutex_class;
- PFS_rwlock_class dummy_rwlock_class;
- PFS_cond_class dummy_cond_class;
- PFS_thread_class dummy_thread_class;
- PFS_file_class dummy_file_class;
- PFS_thread *thread;
- PFS_single_stat_chain *base;
- PFS_single_stat_chain *stat;
- PFS_global_param param;
-
-
- /* Per mutex info waits should be at [0..9] */
- mutex_class_max= 10;
- /* Per rwlock info waits should be at [10..29] */
- rwlock_class_max= 20;
- /* Per cond info waits should be at [30..69] */
- cond_class_max= 40;
- /* Per file info waits should be at [70..149] */
- file_class_max= 80;
- /* Per table info waits should be at [150..309] */
- table_share_max= 160;
-
- param.m_enabled= true;
- param.m_mutex_class_sizing= mutex_class_max;
- param.m_rwlock_class_sizing= rwlock_class_max;
- param.m_cond_class_sizing= cond_class_max;
- param.m_thread_class_sizing= 2;
- param.m_table_share_sizing= table_share_max;
- param.m_file_class_sizing= file_class_max;
- param.m_mutex_sizing= 0;
- param.m_rwlock_sizing= 0;
- param.m_cond_sizing= 0;
- param.m_thread_sizing= 2;
- param.m_table_sizing= 0;
- param.m_file_sizing= 0;
- param.m_file_handle_sizing= 0;
- param.m_events_waits_history_sizing= 10;
- param.m_events_waits_history_long_sizing= 10000;
-
- rc= init_instruments(& param);
- ok(rc == 0, "instances init");
-
- thread= create_thread(& dummy_thread_class, NULL, 0);
- ok(thread != NULL, "thread");
- ok(thread_lost == 0, "not lost");
-
- base= & thread->m_instr_class_wait_stats[0];
-
- dummy_mutex_class.m_index= 0;
- stat= find_per_thread_mutex_class_wait_stat(thread, & dummy_mutex_class);
- ok(base + 0 == stat, "fist mutex info slot at 0");
- dummy_mutex_class.m_index= mutex_class_max - 1;
- stat= find_per_thread_mutex_class_wait_stat(thread, & dummy_mutex_class);
- ok(base + 9 == stat, "last mutex info slot at 9");
-
- dummy_rwlock_class.m_index= 0;
- stat= find_per_thread_rwlock_class_wait_stat(thread, & dummy_rwlock_class);
- ok(base + 10 == stat, "fist rwlock info slot at 10");
- dummy_rwlock_class.m_index= rwlock_class_max - 1;
- stat= find_per_thread_rwlock_class_wait_stat(thread, & dummy_rwlock_class);
- ok(base + 29 == stat, "last rwlock info slot at 29");
-
- dummy_cond_class.m_index= 0;
- stat= find_per_thread_cond_class_wait_stat(thread, & dummy_cond_class);
- ok(base + 30 == stat, "fist cond info slot at 30");
- dummy_cond_class.m_index= cond_class_max - 1;
- stat= find_per_thread_cond_class_wait_stat(thread, & dummy_cond_class);
- ok(base + 69 == stat, "last cond info slot at 69");
-
- dummy_file_class.m_index= 0;
- stat= find_per_thread_file_class_wait_stat(thread, & dummy_file_class);
- ok(base + 70 == stat, "fist file info slot at 70");
- dummy_file_class.m_index= file_class_max - 1;
- stat= find_per_thread_file_class_wait_stat(thread, & dummy_file_class);
- ok(base + 149 == stat, "last file info slot at 149");
-
- cleanup_instruments();
-}
-
void do_all_tests()
{
- PFS_atomic::init();
-
test_no_instruments();
test_no_instances();
test_with_instances();
- test_per_thread_wait();
-
- PFS_atomic::cleanup();
}
int main(int argc, char **argv)
{
- plan(102);
+ plan(103);
MY_INIT(argv[0]);
do_all_tests();
my_end(0);
- return 0;
+ return (exit_status());
}
diff --git a/storage/perfschema/unittest/pfs_instr_class-oom-t.cc b/storage/perfschema/unittest/pfs_instr_class-oom-t.cc
index 500978f218c..bdb2648c2f3 100644
--- a/storage/perfschema/unittest/pfs_instr_class-oom-t.cc
+++ b/storage/perfschema/unittest/pfs_instr_class-oom-t.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,6 @@
#include <tap.h>
#include "stub_pfs_global.h"
-#include "stub_server_misc.h"
void test_oom()
{
@@ -38,29 +37,33 @@ void test_oom()
ok(rc == 1, "oom (file)");
rc= init_table_share(1000);
ok(rc == 1, "oom (cond)");
+ rc= init_socket_class(1000);
+ ok(rc == 1, "oom (socket)");
+ rc= init_stage_class(1000);
+ ok(rc == 1, "oom (stage)");
+ rc= init_statement_class(1000);
+ ok(rc == 1, "oom (statement)");
cleanup_sync_class();
cleanup_thread_class();
cleanup_file_class();
cleanup_table_share();
+ cleanup_socket_class();
+ cleanup_stage_class();
+ cleanup_statement_class();
}
void do_all_tests()
{
- PFS_atomic::init();
-
test_oom();
-
- PFS_atomic::cleanup();
}
int main(int argc, char **argv)
{
- plan(6);
+ plan(9);
MY_INIT(argv[0]);
do_all_tests();
my_end(0);
- return 0;
+ return (exit_status());
}
-
diff --git a/storage/perfschema/unittest/pfs_instr_class-t.cc b/storage/perfschema/unittest/pfs_instr_class-t.cc
index c6c797f560e..0d8ec38525d 100644
--- a/storage/perfschema/unittest/pfs_instr_class-t.cc
+++ b/storage/perfschema/unittest/pfs_instr_class-t.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,20 +21,20 @@
#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_table_share *table;
+ PFS_socket_class *socket;
+ /* PFS_table_share *table; */
rc= init_sync_class(0, 0, 0);
ok(rc == 0, "zero init (sync)");
@@ -42,6 +42,8 @@ void test_no_registration()
ok(rc == 0, "zero init (thread)");
rc= init_file_class(0);
ok(rc == 0, "zero init (file)");
+ rc= init_socket_class(0);
+ ok(rc == 0, "zero init (socket)");
rc= init_table_share(0);
ok(rc == 0, "zero init (table)");
@@ -80,15 +82,24 @@ void test_no_registration()
file_key= register_file_class("FOO", 3, 0);
ok(file_key == 0, "no file registered");
+ socket_key= register_socket_class("FOO", 3, 0);
+ ok(socket_key == 0, "no socket registered");
+ socket_key= register_socket_class("BAR", 3, 0);
+ ok(socket_key == 0, "no socket registered");
+ socket_key= register_socket_class("FOO", 3, 0);
+ ok(socket_key == 0, "no socket registered");
+
+#ifdef LATER
PFS_thread fake_thread;
fake_thread.m_table_share_hash_pins= NULL;
- table= find_or_create_table_share(& fake_thread, "foo_db", 6, "foo_table", 9);
+ table= find_or_create_table_share(& fake_thread, false, "foo_db", 6, "foo_table", 9);
ok(table == NULL, "not created");
- table= find_or_create_table_share(& fake_thread, "bar_db", 6, "bar_table", 9);
+ table= find_or_create_table_share(& fake_thread, false, "bar_db", 6, "bar_table", 9);
ok(table == NULL, "not created");
- table= find_or_create_table_share(& fake_thread, "foo_db", 6, "foo_table", 9);
+ table= find_or_create_table_share(& fake_thread, false, "foo_db", 6, "foo_table", 9);
ok(table == NULL, "not created");
+#endif
mutex= find_mutex_class(0);
ok(mutex == NULL, "no mutex key 0");
@@ -125,9 +136,17 @@ void test_no_registration()
file= find_file_class(9999);
ok(file == NULL, "no file key 9999");
+ socket= find_socket_class(0);
+ ok(socket == NULL, "no socket key 0");
+ socket= find_socket_class(1);
+ ok(socket == NULL, "no socket key 1");
+ socket= find_socket_class(9999);
+ ok(socket == NULL, "no socket key 9999");
+
cleanup_sync_class();
cleanup_thread_class();
cleanup_file_class();
+ cleanup_socket_class();
cleanup_table_share();
}
@@ -346,8 +365,56 @@ void test_file_registration()
cleanup_file_class();
}
+void test_socket_registration()
+{
+ int rc;
+ PFS_socket_key key;
+ PFS_socket_class *socket;
+
+ rc= init_socket_class(5);
+ ok(rc == 0, "room for 5 socket");
+
+ key= register_socket_class("FOO", 3, 0);
+ ok(key == 1, "foo registered");
+ key= register_socket_class("BAR", 3, 0);
+ ok(key == 2, "bar registered");
+ key= register_socket_class("FOO", 3, 0);
+ ok(key == 1, "foo re registered");
+ key= register_socket_class("Socket-3", 8, 0);
+ ok(key == 3, "Socket-3 registered");
+ key= register_socket_class("Socket-4", 8, 0);
+ ok(key == 4, "Socket-4 registered");
+ key= register_socket_class("Socket-5", 8, 0);
+ ok(key == 5, "Socket-5 registered");
+ ok(socket_class_lost == 0, "lost nothing");
+ key= register_socket_class("Socket-6", 8, 0);
+ ok(key == 0, "Socket-6 not registered");
+ ok(socket_class_lost == 1, "lost 1 socket");
+ key= register_socket_class("Socket-7", 8, 0);
+ ok(key == 0, "Socket-7 not registered");
+ ok(socket_class_lost == 2, "lost 2 socket");
+ key= register_socket_class("Socket-3", 8, 0);
+ ok(key == 3, "Socket-3 re registered");
+ ok(socket_class_lost == 2, "lost 2 socket");
+ key= register_socket_class("Socket-5", 8, 0);
+ ok(key == 5, "Socket-5 re registered");
+ ok(socket_class_lost == 2, "lost 2 socket");
+
+ socket= find_socket_class(0);
+ ok(socket == NULL, "no key 0");
+ socket= find_socket_class(3);
+ ok(socket != NULL, "found key 3");
+ ok(strncmp(socket->m_name, "Socket-3", 8) == 0, "key 3 is Socket-3");
+ ok(socket->m_name_length == 8, "name length 3");
+ socket= find_socket_class(9999);
+ ok(socket == NULL, "no key 9999");
+
+ cleanup_socket_class();
+}
+
void test_table_registration()
{
+#ifdef LATER
PFS_table_share *table_share;
PFS_table_share *table_share_2;
@@ -355,7 +422,7 @@ void test_table_registration()
fake_thread.m_table_share_hash_pins= NULL;
table_share_lost= 0;
- table_share= find_or_create_table_share(& fake_thread, "db1", 3, "t1", 2);
+ table_share= find_or_create_table_share(& fake_thread, false, "db1", 3, "t1", 2);
ok(table_share == NULL, "not created");
ok(table_share_lost == 1, "lost the table");
@@ -363,37 +430,37 @@ void test_table_registration()
init_table_share(5);
init_table_share_hash();
- table_share= find_or_create_table_share(& fake_thread, "db1", 3, "t1", 2);
+ table_share= find_or_create_table_share(& fake_thread, false, "db1", 3, "t1", 2);
ok(table_share != NULL, "created db1.t1");
ok(table_share_lost == 0, "not lost");
- table_share_2= find_or_create_table_share(& fake_thread, "db1", 3, "t1", 2);
+ table_share_2= find_or_create_table_share(& fake_thread, false, "db1", 3, "t1", 2);
ok(table_share_2 != NULL, "found db1.t1");
ok(table_share_lost == 0, "not lost");
ok(table_share == table_share_2, "same table");
- table_share_2= find_or_create_table_share(& fake_thread, "db1", 3, "t2", 2);
+ table_share_2= find_or_create_table_share(& fake_thread, false, "db1", 3, "t2", 2);
ok(table_share_2 != NULL, "created db1.t2");
ok(table_share_lost == 0, "not lost");
- table_share_2= find_or_create_table_share(& fake_thread, "db2", 3, "t1", 2);
+ table_share_2= find_or_create_table_share(& fake_thread, false, "db2", 3, "t1", 2);
ok(table_share_2 != NULL, "created db2.t1");
ok(table_share_lost == 0, "not lost");
- table_share_2= find_or_create_table_share(& fake_thread, "db2", 3, "t2", 2);
+ table_share_2= find_or_create_table_share(& fake_thread, false, "db2", 3, "t2", 2);
ok(table_share_2 != NULL, "created db2.t2");
ok(table_share_lost == 0, "not lost");
- table_share_2= find_or_create_table_share(& fake_thread, "db3", 3, "t3", 2);
+ table_share_2= find_or_create_table_share(& fake_thread, false, "db3", 3, "t3", 2);
ok(table_share_2 != NULL, "created db3.t3");
ok(table_share_lost == 0, "not lost");
- table_share_2= find_or_create_table_share(& fake_thread, "db4", 3, "t4", 2);
+ table_share_2= find_or_create_table_share(& fake_thread, false, "db4", 3, "t4", 2);
ok(table_share_2 == NULL, "lost db4.t4");
ok(table_share_lost == 1, "lost");
table_share_lost= 0;
- table_share_2= find_or_create_table_share(& fake_thread, "db1", 3, "t2", 2);
+ table_share_2= find_or_create_table_share(& fake_thread, false, "db1", 3, "t2", 2);
ok(table_share_2 != NULL, "found db1.t2");
ok(table_share_lost == 0, "not lost");
ok(strncmp(table_share_2->m_schema_name, "db1", 3) == 0 , "schema db1");
@@ -403,18 +470,26 @@ void test_table_registration()
cleanup_table_share_hash();
cleanup_table_share();
+#endif
}
-void set_wait_stat(PFS_single_stat_chain *stat)
+#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_single_stat_chain *stat)
+bool is_empty_stat(PFS_instr_class *klass)
{
+ PFS_single_stat *stat;
+ stat= & global_instr_class_waits_array[klass->m_event_name_index];
+
if (stat->m_count != 0)
return false;
if (stat->m_min != (ulonglong) -1)
@@ -425,12 +500,14 @@ bool is_empty_stat(PFS_single_stat_chain *stat)
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;
@@ -443,6 +520,9 @@ void test_instruments_reset()
PFS_file_class *file_1;
PFS_file_class *file_2;
PFS_file_class *file_3;
+ PFS_socket_class *socket_1;
+ PFS_socket_class *socket_2;
+ PFS_socket_class *socket_3;
rc= init_sync_class(3, 3, 3);
ok(rc == 0, "init (sync)");
@@ -450,6 +530,8 @@ void test_instruments_reset()
ok(rc == 0, "init (thread)");
rc= init_file_class(3);
ok(rc == 0, "init (file)");
+ rc= init_socket_class(3);
+ ok(rc == 0, "init (socket)");
key= register_mutex_class("M-1", 3, 0);
ok(key == 1, "mutex registered");
@@ -479,6 +561,13 @@ void test_instruments_reset()
file_key= register_file_class("F-3", 3, 0);
ok(file_key == 3, "file registered");
+ socket_key= register_socket_class("S-1", 3, 0);
+ ok(socket_key == 1, "socket registered");
+ socket_key= register_socket_class("S-2", 3, 0);
+ ok(socket_key == 2, "socket registered");
+ socket_key= register_socket_class("S-3", 3, 0);
+ ok(socket_key == 3, "socket registered");
+
mutex_1= find_mutex_class(1);
ok(mutex_1 != NULL, "mutex key 1");
mutex_2= find_mutex_class(2);
@@ -507,74 +596,79 @@ void test_instruments_reset()
file_3= find_file_class(3);
ok(file_3 != NULL, "file key 3");
- set_wait_stat(& mutex_1->m_wait_stat);
- set_wait_stat(& mutex_2->m_wait_stat);
- set_wait_stat(& mutex_3->m_wait_stat);
- set_wait_stat(& rwlock_1->m_wait_stat);
- set_wait_stat(& rwlock_2->m_wait_stat);
- set_wait_stat(& rwlock_3->m_wait_stat);
- set_wait_stat(& cond_1->m_wait_stat);
- set_wait_stat(& cond_2->m_wait_stat);
- set_wait_stat(& cond_3->m_wait_stat);
- set_wait_stat(& file_1->m_wait_stat);
- set_wait_stat(& file_2->m_wait_stat);
- set_wait_stat(& file_3->m_wait_stat);
-
- ok(! is_empty_stat(& mutex_1->m_wait_stat), "mutex_1 stat is populated");
- ok(! is_empty_stat(& mutex_2->m_wait_stat), "mutex_2 stat is populated");
- ok(! is_empty_stat(& mutex_3->m_wait_stat), "mutex_3 stat is populated");
- ok(! is_empty_stat(& rwlock_1->m_wait_stat), "rwlock_1 stat is populated");
- ok(! is_empty_stat(& rwlock_2->m_wait_stat), "rwlock_2 stat is populated");
- ok(! is_empty_stat(& rwlock_3->m_wait_stat), "rwlock_3 stat is populated");
- ok(! is_empty_stat(& cond_1->m_wait_stat), "cond_1 stat is populated");
- ok(! is_empty_stat(& cond_2->m_wait_stat), "cond_2 stat is populated");
- ok(! is_empty_stat(& cond_3->m_wait_stat), "cond_3 stat is populated");
- ok(! is_empty_stat(& file_1->m_wait_stat), "file_1 stat is populated");
- ok(! is_empty_stat(& file_2->m_wait_stat), "file_2 stat is populated");
- ok(! is_empty_stat(& file_3->m_wait_stat), "file_3 stat is populated");
-
- reset_instrument_class_waits();
-
- ok(is_empty_stat(& mutex_1->m_wait_stat), "mutex_1 stat is cleared");
- ok(is_empty_stat(& mutex_2->m_wait_stat), "mutex_2 stat is cleared");
- ok(is_empty_stat(& mutex_3->m_wait_stat), "mutex_3 stat is cleared");
- ok(is_empty_stat(& rwlock_1->m_wait_stat), "rwlock_1 stat is cleared");
- ok(is_empty_stat(& rwlock_2->m_wait_stat), "rwlock_2 stat is cleared");
- ok(is_empty_stat(& rwlock_3->m_wait_stat), "rwlock_3 stat is cleared");
- ok(is_empty_stat(& cond_1->m_wait_stat), "cond_1 stat is cleared");
- ok(is_empty_stat(& cond_2->m_wait_stat), "cond_2 stat is cleared");
- ok(is_empty_stat(& cond_3->m_wait_stat), "cond_3 stat is cleared");
- ok(is_empty_stat(& file_1->m_wait_stat), "file_1 stat is cleared");
- ok(is_empty_stat(& file_2->m_wait_stat), "file_2 stat is cleared");
- ok(is_empty_stat(& file_3->m_wait_stat), "file_3 stat is cleared");
+ socket_1= find_socket_class(1);
+ ok(socket_1 != NULL, "socket key 1");
+ socket_2= find_socket_class(2);
+ ok(socket_2 != NULL, "socket key 2");
+ socket_3= find_socket_class(3);
+ ok(socket_3 != NULL, "socket key 3");
+
+#ifdef LATER
+ set_wait_stat(mutex_1);
+ set_wait_stat(mutex_2);
+ set_wait_stat(mutex_3);
+ set_wait_stat(rwlock_1);
+ set_wait_stat(rwlock_2);
+ set_wait_stat(rwlock_3);
+ set_wait_stat(cond_1);
+ set_wait_stat(cond_2);
+ set_wait_stat(cond_3);
+ set_wait_stat(file_1);
+ set_wait_stat(file_2);
+ set_wait_stat(file_3);
+
+ ok(! is_empty_stat(mutex_1), "mutex_1 stat is populated");
+ ok(! is_empty_stat(mutex_2), "mutex_2 stat is populated");
+ ok(! is_empty_stat(mutex_3), "mutex_3 stat is populated");
+ ok(! is_empty_stat(rwlock_1), "rwlock_1 stat is populated");
+ ok(! is_empty_stat(rwlock_2), "rwlock_2 stat is populated");
+ ok(! is_empty_stat(rwlock_3), "rwlock_3 stat is populated");
+ ok(! is_empty_stat(cond_1), "cond_1 stat is populated");
+ ok(! is_empty_stat(cond_2), "cond_2 stat is populated");
+ ok(! is_empty_stat(cond_3), "cond_3 stat is populated");
+ ok(! is_empty_stat(file_1), "file_1 stat is populated");
+ ok(! is_empty_stat(file_2), "file_2 stat is populated");
+ ok(! is_empty_stat(file_3), "file_3 stat is populated");
+
+ reset_global_wait_stat();
+
+ ok(is_empty_stat(mutex_1), "mutex_1 stat is cleared");
+ ok(is_empty_stat(mutex_2), "mutex_2 stat is cleared");
+ ok(is_empty_stat(mutex_3), "mutex_3 stat is cleared");
+ ok(is_empty_stat(rwlock_1), "rwlock_1 stat is cleared");
+ ok(is_empty_stat(rwlock_2), "rwlock_2 stat is cleared");
+ ok(is_empty_stat(rwlock_3), "rwlock_3 stat is cleared");
+ ok(is_empty_stat(cond_1), "cond_1 stat is cleared");
+ ok(is_empty_stat(cond_2), "cond_2 stat is cleared");
+ ok(is_empty_stat(cond_3), "cond_3 stat is cleared");
+ ok(is_empty_stat(file_1), "file_1 stat is cleared");
+ ok(is_empty_stat(file_2), "file_2 stat is cleared");
+ ok(is_empty_stat(file_3), "file_3 stat is cleared");
+#endif
cleanup_sync_class();
cleanup_file_class();
+ cleanup_socket_class();
}
void do_all_tests()
{
- 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 argc, char **argv)
{
- plan(196);
+ plan(181);
MY_INIT(argv[0]);
do_all_tests();
my_end(0);
- return 0;
+ return (exit_status());
}
-
-
diff --git a/storage/perfschema/unittest/pfs_misc-t.cc b/storage/perfschema/unittest/pfs_misc-t.cc
new file mode 100644
index 00000000000..c308cf4b82d
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_misc-t.cc
@@ -0,0 +1,72 @@
+/* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <pfs_instr.h>
+#include <pfs_stat.h>
+#include <pfs_global.h>
+#include <pfs_instr_class.h>
+#include <tap.h>
+
+#include <memory.h>
+
+void test_digest_length_overflow()
+{
+ if (sizeof(size_t) != 4)
+ {
+ skip(2, "digest length overflow requires a 32-bit environment");
+ return;
+ }
+
+ PFS_global_param param;
+ memset(&param, 0, sizeof(param));
+ param.m_enabled= true;
+ /*
+ Force 32-bit arithmetic overflow using the digest memory allocation
+ parameters. The Performance Schema should detect the overflow, free
+ allocated memory and abort initialization with a warning.
+ */
+
+ /* Max digest length, events_statements_history_long. */
+ param.m_events_statements_history_long_sizing= 10000;
+ param.m_digest_sizing= 1000;
+ param.m_max_digest_length= (1024 * 1024);
+ pfs_max_digest_length= param.m_max_digest_length;
+
+ int rc = init_events_statements_history_long(param.m_events_statements_history_long_sizing);
+ ok(rc == 1, "digest length overflow (init_events_statements_history_long");
+
+ /* Max digest length, events_statements_summary_by_digest. */
+ param.m_max_digest_length= (1024 * 1024);
+ param.m_digest_sizing= 10000;
+
+ rc = init_digest(&param);
+ ok(rc == 1, "digest length overflow (init_digest)");
+}
+
+void do_all_tests()
+{
+ test_digest_length_overflow();
+}
+
+int main(int, char **)
+{
+ plan(2);
+ MY_INIT("pfs_misc-t");
+ do_all_tests();
+ my_end(0);
+ return (exit_status());
+}
+
diff --git a/storage/perfschema/unittest/pfs_server_stubs.cc b/storage/perfschema/unittest/pfs_server_stubs.cc
new file mode 100644
index 00000000000..3c4b864d742
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_server_stubs.cc
@@ -0,0 +1,47 @@
+/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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 Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/*
+ Minimal code to be able to link a unit test.
+*/
+
+#include "my_global.h"
+#include "m_ctype.h"
+#include "sql_class.h"
+#include "sql_show.h"
+
+struct sql_digest_storage;
+
+volatile bool ready_to_exit= false;
+
+uint lower_case_table_names= 0;
+CHARSET_INFO *files_charset_info= NULL;
+CHARSET_INFO *system_charset_info= NULL;
+
+void compute_digest_md5(const sql_digest_storage *, unsigned char *)
+{
+}
+
+class sys_var { public: enum where { AUTO }; };
+void set_sys_var_value_origin(void *ptr, enum sys_var::where here)
+{
+}
+
+enum sys_var::where get_sys_var_value_origin(void *ptr)
+{
+ return sys_var::AUTO;
+}
+
+MY_TIMER_INFO sys_timer_info;
diff --git a/storage/perfschema/unittest/pfs_timer-t.cc b/storage/perfschema/unittest/pfs_timer-t.cc
index d14416673da..9ef111f531c 100644
--- a/storage/perfschema/unittest/pfs_timer-t.cc
+++ b/storage/perfschema/unittest/pfs_timer-t.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -15,6 +15,7 @@
#include <my_global.h>
#include <my_pthread.h>
+#include <pfs_atomic.h>
#include <pfs_timer.h>
#include "my_sys.h"
#include <tap.h>
@@ -32,28 +33,30 @@ void test_timers()
ulonglong t4_b;
ulonglong t5_b;
+ my_timer_init(&sys_timer_info);
+
init_timers();
- t1_a= get_timer_value(TIMER_NAME_CYCLE);
+ t1_a= get_timer_pico_value(TIMER_NAME_CYCLE);
/* Wait 5 seconds */
my_sleep(5000000);
- t1_b= get_timer_value(TIMER_NAME_CYCLE);
+ t1_b= get_timer_pico_value(TIMER_NAME_CYCLE);
- t2_a= get_timer_value(TIMER_NAME_NANOSEC);
+ t2_a= get_timer_pico_value(TIMER_NAME_NANOSEC);
my_sleep(5000000);
- t2_b= get_timer_value(TIMER_NAME_NANOSEC);
+ t2_b= get_timer_pico_value(TIMER_NAME_NANOSEC);
- t3_a= get_timer_value(TIMER_NAME_MICROSEC);
+ t3_a= get_timer_pico_value(TIMER_NAME_MICROSEC);
my_sleep(5000000);
- t3_b= get_timer_value(TIMER_NAME_MICROSEC);
+ t3_b= get_timer_pico_value(TIMER_NAME_MICROSEC);
- t4_a= get_timer_value(TIMER_NAME_MILLISEC);
+ t4_a= get_timer_pico_value(TIMER_NAME_MILLISEC);
my_sleep(5000000);
- t4_b= get_timer_value(TIMER_NAME_MILLISEC);
+ t4_b= get_timer_pico_value(TIMER_NAME_MILLISEC);
- t5_a= get_timer_value(TIMER_NAME_TICK);
+ t5_a= get_timer_pico_value(TIMER_NAME_TICK);
my_sleep(5000000);
- t5_b= get_timer_value(TIMER_NAME_TICK);
+ t5_b= get_timer_pico_value(TIMER_NAME_TICK);
/*
Print the timer values, for manual inspection by a human.
@@ -105,11 +108,7 @@ void test_timers()
void do_all_tests()
{
- PFS_atomic::init();
-
test_timers();
-
- PFS_atomic::cleanup();
}
int main(int, char **)
@@ -117,6 +116,7 @@ int main(int, char **)
plan(5);
MY_INIT("pfs_timer-t");
do_all_tests();
- return 0;
+ my_end(0);
+ return (exit_status());
}
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..6e81df8d5e2
--- /dev/null
+++ b/storage/perfschema/unittest/pfs_user-oom-t.cc
@@ -0,0 +1,112 @@
+/* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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, Fifth Floor, 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 <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()
+{
+ test_oom();
+}
+
+int main(int, char **)
+{
+ plan(6);
+ MY_INIT("pfs_user-oom-t");
+ do_all_tests();
+ my_end(0);
+ return (exit_status());
+}
+
diff --git a/storage/perfschema/unittest/stub_server_misc.h b/storage/perfschema/unittest/stub_pfs_defaults.h
index 86c5c21b967..6b4ee3f0e15 100644
--- a/storage/perfschema/unittest/stub_server_misc.h
+++ b/storage/perfschema/unittest/stub_pfs_defaults.h
@@ -11,11 +11,13 @@
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 Street, Fifth Floor, Boston, MA 02110-1335 USA */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
-/*
- Minimal code to be able to link a unit test.
-*/
+#include <my_global.h>
+#include <pfs.h>
+#include <pfs_defaults.h>
-volatile bool ready_to_exit= false;
+void install_default_setup(PSI_bootstrap *)
+{
+}
diff --git a/storage/perfschema/unittest/stub_pfs_global.h b/storage/perfschema/unittest/stub_pfs_global.h
index 2180783f12f..a665ed39704 100644
--- a/storage/perfschema/unittest/stub_pfs_global.h
+++ b/storage/perfschema/unittest/stub_pfs_global.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc.
- Use is subject to license terms.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,15 +16,19 @@
#include <my_global.h>
#include <my_sys.h>
#include <pfs_global.h>
+#include <string.h>
bool pfs_initialized= false;
bool stub_alloc_always_fails= true;
int stub_alloc_fails_after_count= 0;
-void *pfs_malloc(size_t, myf)
+void *pfs_malloc(size_t size, myf)
{
- static char garbage[100];
+ /*
+ Catch non initialized sizing parameter in the unit tests.
+ */
+ DBUG_ASSERT(size <= 100*1024*1024);
if (stub_alloc_always_fails)
return NULL;
@@ -33,10 +36,36 @@ void *pfs_malloc(size_t, myf)
if (--stub_alloc_fails_after_count <= 0)
return NULL;
- return garbage;
+ void *ptr= malloc(size);
+ if (ptr != NULL)
+ memset(ptr, 0, size);
+ return ptr;
}
-void pfs_free(void *)
+void pfs_free(void *ptr)
+{
+ if (ptr != NULL)
+ free(ptr);
+}
+
+void *pfs_malloc_array(size_t n, size_t size, myf flags)
+{
+ size_t array_size= n * size;
+ /* Check for overflow before allocating. */
+ if (is_overflow(array_size, n, size))
+ return NULL;
+ return pfs_malloc(array_size, flags);
+}
+
+bool is_overflow(size_t product, size_t n1, size_t n2)
+{
+ if (n1 != 0 && (product / n1 != n2))
+ return true;
+ else
+ return false;
+}
+
+void pfs_print_error(const char *format, ...)
{
}
diff --git a/storage/perfschema/unittest/stub_print_error.h b/storage/perfschema/unittest/stub_print_error.h
index 89c3ead4406..476a6c0e901 100644
--- a/storage/perfschema/unittest/stub_print_error.h
+++ b/storage/perfschema/unittest/stub_print_error.h
@@ -1,5 +1,4 @@
-/* Copyright (c) 2008 MySQL AB, 2010 Sun Microsystems, Inc.
- Use is subject to license terms.
+/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -34,6 +33,23 @@ void pfs_free(void *ptr)
free(ptr);
}
+void *pfs_malloc_array(size_t n, size_t size, myf flags)
+{
+ size_t array_size= n * size;
+ /* Check for overflow before allocating. */
+ if (is_overflow(array_size, n, size))
+ return NULL;
+ return pfs_malloc(array_size, flags);
+}
+
+bool is_overflow(size_t product, size_t n1, size_t n2)
+{
+ if (n1 != 0 && (product / n1 != n2))
+ return true;
+ else
+ return false;
+}
+
void pfs_print_error(const char *format, ...)
{
/* Do not pollute the unit test output with annoying messages. */