diff options
author | Sergei Golubchik <serg@mariadb.org> | 2019-12-10 15:35:00 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2020-03-10 19:24:22 +0100 |
commit | 0ea717f51a152afdb3791195c4a25ee0baa2faac (patch) | |
tree | 0eb10fc1413d1583ffdec2c18a66491d7befeec2 /storage/perfschema | |
parent | dfe6e914e58472159f34a8a4c9288ff61eac479f (diff) | |
download | mariadb-git-0ea717f51a152afdb3791195c4a25ee0baa2faac.tar.gz |
P_S 5.7.28
Diffstat (limited to 'storage/perfschema')
253 files changed, 33775 insertions, 6780 deletions
diff --git a/storage/perfschema/CMakeLists.txt b/storage/perfschema/CMakeLists.txt index e1839bc5b00..667d2d99b5d 100644 --- a/storage/perfschema/CMakeLists.txt +++ b/storage/perfschema/CMakeLists.txt @@ -28,6 +28,9 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${SSL_INCLUDE_DIRS}) ADD_DEFINITIONS(-DMYSQL_SERVER) +IF (SSL_DEFINES) + ADD_DEFINITIONS(${SSL_DEFINES}) +ENDIF() # # Maintainer: keep this list sorted, to avoid merge collisions. @@ -42,27 +45,35 @@ cursor_by_user.h pfs.h pfs_account.h pfs_atomic.h +pfs_buffer_container.h +pfs_builtin_memory.h pfs_column_types.h pfs_column_values.h pfs_con_slice.h pfs_defaults.h pfs_digest.h +pfs_program.h +pfs_prepared_stmt.h pfs_engine_table.h pfs_events.h pfs_events_stages.h pfs_events_statements.h +pfs_events_transactions.h pfs_events_waits.h pfs_global.h pfs_host.h pfs_instr.h pfs_instr_class.h pfs_lock.h +pfs_memory.h pfs_server.h pfs_setup_actor.h pfs_setup_object.h pfs_stat.h +pfs_status.h pfs_timer.h pfs_user.h +pfs_variable.h pfs_visitor.h table_accounts.h table_all_instr.h @@ -74,11 +85,19 @@ 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_program.h +table_prepared_stmt_instances.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_ets_by_account_by_event_name.h +table_ets_by_host_by_event_name.h +table_ets_by_thread_by_event_name.h +table_ets_by_user_by_event_name.h +table_ets_global_by_event_name.h table_events_stages.h table_events_statements.h +table_events_transactions.h table_events_waits.h table_events_waits_summary.h table_ews_by_account_by_event_name.h @@ -87,6 +106,12 @@ 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_md_locks.h +table_mems_global_by_event_name.h +table_mems_by_account_by_event_name.h +table_mems_by_host_by_event_name.h +table_mems_by_thread_by_event_name.h +table_mems_by_user_by_event_name.h table_file_summary_by_instance.h table_file_summary_by_event_name.h table_socket_instances.h @@ -103,15 +128,34 @@ table_setup_instruments.h table_setup_objects.h table_setup_timers.h table_sync_instances.h +table_status_by_account.h +table_status_by_host.h +table_status_by_thread.h +table_status_by_user.h +table_global_status.h +table_session_status.h +table_variables_by_thread.h +table_global_variables.h +table_session_variables.h +table_table_handles.h table_threads.h table_tiws_by_index_usage.h table_tiws_by_table.h table_tlws_by_table.h table_users.h +table_uvar_by_thread.h cursor_by_thread_connect_attr.h table_session_connect.h table_session_connect_attrs.h table_session_account_connect_attrs.h +table_replication_connection_configuration.h +table_replication_group_members.h +table_replication_connection_status.h +table_replication_applier_configuration.h +table_replication_applier_status.h +table_replication_applier_status_by_coordinator.h +table_replication_applier_status_by_worker.h +table_replication_group_member_stats.h cursor_by_account.cc cursor_by_host.cc cursor_by_thread.cc @@ -120,23 +164,31 @@ ha_perfschema.cc pfs.cc pfs_account.cc pfs_autosize.cc +pfs_buffer_container.cc +pfs_builtin_memory.cc pfs_column_values.cc pfs_con_slice.cc pfs_defaults.cc pfs_digest.cc +pfs_program.cc +pfs_prepared_stmt.cc pfs_engine_table.cc pfs_events_stages.cc pfs_events_statements.cc +pfs_events_transactions.cc pfs_events_waits.cc pfs_global.cc pfs_host.cc pfs_instr.cc pfs_instr_class.cc +pfs_memory.cc pfs_server.cc pfs_setup_actor.cc pfs_setup_object.cc +pfs_status.cc pfs_timer.cc pfs_user.cc +pfs_variable.cc pfs_visitor.cc table_accounts.cc table_all_instr.cc @@ -148,11 +200,19 @@ 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_program.cc +table_prepared_stmt_instances.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_ets_by_account_by_event_name.cc +table_ets_by_host_by_event_name.cc +table_ets_by_thread_by_event_name.cc +table_ets_by_user_by_event_name.cc +table_ets_global_by_event_name.cc table_events_stages.cc table_events_statements.cc +table_events_transactions.cc table_events_waits.cc table_events_waits_summary.cc table_ews_by_account_by_event_name.cc @@ -161,6 +221,12 @@ 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_md_locks.cc +table_mems_global_by_event_name.cc +table_mems_by_account_by_event_name.cc +table_mems_by_host_by_event_name.cc +table_mems_by_thread_by_event_name.cc +table_mems_by_user_by_event_name.cc table_file_summary_by_instance.cc table_file_summary_by_event_name.cc table_socket_instances.cc @@ -177,15 +243,34 @@ table_setup_instruments.cc table_setup_objects.cc table_setup_timers.cc table_sync_instances.cc +table_status_by_account.cc +table_status_by_host.cc +table_status_by_thread.cc +table_status_by_user.cc +table_global_status.cc +table_session_status.cc +table_variables_by_thread.cc +table_global_variables.cc +table_session_variables.cc +table_table_handles.cc table_threads.cc table_tiws_by_index_usage.cc table_tiws_by_table.cc table_tlws_by_table.cc table_users.cc +table_uvar_by_thread.cc cursor_by_thread_connect_attr.cc table_session_connect.cc table_session_connect_attrs.cc table_session_account_connect_attrs.cc +table_replication_connection_configuration.cc +#table_replication_group_members.cc +#table_replication_connection_status.cc +table_replication_applier_configuration.cc +table_replication_applier_status.cc +table_replication_applier_status_by_coordinator.cc +#table_replication_applier_status_by_worker.cc +#table_replication_group_member_stats.cc ) MYSQL_ADD_PLUGIN(perfschema ${PERFSCHEMA_SOURCES} STORAGE_ENGINE DEFAULT STATIC_ONLY) @@ -195,3 +280,41 @@ IF (TARGET perfschema) ADD_SUBDIRECTORY(unittest) ENDIF(WITH_UNIT_TESTS) ENDIF(TARGET perfschema) + +# Only disable threads when building without *any* instrumentation, +# as other instrumentations have a dependency on threads. +OPTION(DISABLE_PSI_THREAD "Exclude the performance schema thread instrumentation" OFF) + +OPTION(DISABLE_PSI_MUTEX "Exclude the performance schema mutex instrumentation" OFF) +OPTION(DISABLE_PSI_RWLOCK "Exclude the performance schema rwlock instrumentation" OFF) +OPTION(DISABLE_PSI_COND "Exclude the performance schema condition instrumentation" OFF) +OPTION(DISABLE_PSI_FILE "Exclude the performance schema file instrumentation" OFF) +OPTION(DISABLE_PSI_TABLE "Exclude the performance schema table instrumentation" OFF) +OPTION(DISABLE_PSI_SOCKET "Exclude the performance schema socket instrumentation" OFF) +OPTION(DISABLE_PSI_STAGE "Exclude the performance schema stage instrumentation" OFF) +OPTION(DISABLE_PSI_STATEMENT "Exclude the performance schema statement instrumentation" OFF) +OPTION(DISABLE_PSI_SP "Exclude the performance schema stored procedure instrumentation" OFF) +OPTION(DISABLE_PSI_PS "Exclude the performance schema prepared statements instances instrumentation" OFF) +OPTION(DISABLE_PSI_IDLE "Exclude the performance schema idle instrumentation" OFF) +OPTION(DISABLE_PSI_STATEMENT_DIGEST "Exclude the performance schema statement digest instrumentation" OFF) +OPTION(DISABLE_PSI_METADATA "Exclude the performance schema metadata instrumentation" OFF) +OPTION(DISABLE_PSI_MEMORY "Exclude the performance schema memory instrumentation" OFF) +OPTION(DISABLE_PSI_TRANSACTION "Exclude the performance schema transaction instrumentation" OFF) + +MARK_AS_ADVANCED(DISABLE_PSI_THREAD) + +MARK_AS_ADVANCED(DISABLE_PSI_MUTEX) +MARK_AS_ADVANCED(DISABLE_PSI_RWLOCK) +MARK_AS_ADVANCED(DISABLE_PSI_COND) +MARK_AS_ADVANCED(DISABLE_PSI_FILE) +MARK_AS_ADVANCED(DISABLE_PSI_TABLE) +MARK_AS_ADVANCED(DISABLE_PSI_SOCKET) +MARK_AS_ADVANCED(DISABLE_PSI_STAGE) +MARK_AS_ADVANCED(DISABLE_PSI_STATEMENT) +MARK_AS_ADVANCED(DISABLE_PSI_SP) +MARK_AS_ADVANCED(DISABLE_PSI_PS) +MARK_AS_ADVANCED(DISABLE_PSI_IDLE) +MARK_AS_ADVANCED(DISABLE_PSI_STATEMENT_DIGEST) +MARK_AS_ADVANCED(DISABLE_PSI_METADATA) +MARK_AS_ADVANCED(DISABLE_PSI_MEMORY) +MARK_AS_ADVANCED(DISABLE_PSI_TRANSACTION) diff --git a/storage/perfschema/cursor_by_account.cc b/storage/perfschema/cursor_by_account.cc index f26318c42fc..1b208e00d65 100644 --- a/storage/perfschema/cursor_by_account.cc +++ b/storage/perfschema/cursor_by_account.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -27,7 +27,13 @@ #include "my_global.h" #include "cursor_by_account.h" -#include "pfs_user.h" +#include "pfs_buffer_container.h" + +ha_rows +cursor_by_account::get_row_count(void) +{ + return global_account_container.get_row_count(); +} cursor_by_account::cursor_by_account(const PFS_engine_table_share *share) : PFS_engine_table(share, &m_pos), @@ -44,17 +50,14 @@ 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()) + m_pos.set_at(&m_next_pos); + PFS_account_iterator it= global_account_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - 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; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -66,9 +69,9 @@ 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()) + + pfs= global_account_container.get(m_pos.m_index); + if (pfs != NULL) { make_row(pfs); return 0; diff --git a/storage/perfschema/cursor_by_account.h b/storage/perfschema/cursor_by_account.h index c14a563b712..d689cf6c524 100644 --- a/storage/perfschema/cursor_by_account.h +++ b/storage/perfschema/cursor_by_account.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -41,6 +41,8 @@ class cursor_by_account : public PFS_engine_table { public: + static ha_rows get_row_count(); + virtual int rnd_next(); virtual int rnd_pos(const void *pos); virtual void reset_position(void); diff --git a/storage/perfschema/cursor_by_host.cc b/storage/perfschema/cursor_by_host.cc index c3397234e2e..6aa3423c0d1 100644 --- a/storage/perfschema/cursor_by_host.cc +++ b/storage/perfschema/cursor_by_host.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -27,7 +27,13 @@ #include "my_global.h" #include "cursor_by_host.h" -#include "pfs_host.h" +#include "pfs_buffer_container.h" + +ha_rows +cursor_by_host::get_row_count(void) +{ + return global_host_container.get_row_count(); +} cursor_by_host::cursor_by_host(const PFS_engine_table_share *share) : PFS_engine_table(share, &m_pos), @@ -42,19 +48,16 @@ void cursor_by_host::reset_position(void) int cursor_by_host::rnd_next(void) { - PFS_host *host; + PFS_host *pfs; - for (m_pos.set_at(&m_next_pos); - m_pos.m_index < host_max; - m_pos.next()) + m_pos.set_at(&m_next_pos); + PFS_host_iterator it= global_host_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - 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; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -66,9 +69,9 @@ 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()) + + pfs= global_host_container.get(m_pos.m_index); + if (pfs != NULL) { make_row(pfs); return 0; diff --git a/storage/perfschema/cursor_by_host.h b/storage/perfschema/cursor_by_host.h index ac68acf3945..8f256156b1f 100644 --- a/storage/perfschema/cursor_by_host.h +++ b/storage/perfschema/cursor_by_host.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -41,6 +41,8 @@ class cursor_by_host : public PFS_engine_table { public: + static ha_rows get_row_count(); + virtual int rnd_next(); virtual int rnd_pos(const void *pos); virtual void reset_position(void); diff --git a/storage/perfschema/cursor_by_thread.cc b/storage/perfschema/cursor_by_thread.cc index afdc9010b1f..5d56794bf94 100644 --- a/storage/perfschema/cursor_by_thread.cc +++ b/storage/perfschema/cursor_by_thread.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -28,6 +28,13 @@ #include "my_global.h" #include "cursor_by_thread.h" #include "pfs_instr.h" +#include "pfs_buffer_container.h" + +ha_rows +cursor_by_thread::get_row_count(void) +{ + return global_thread_container.get_row_count(); +} cursor_by_thread::cursor_by_thread(const PFS_engine_table_share *share) : PFS_engine_table(share, &m_pos), @@ -44,17 +51,14 @@ 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()) + m_pos.set_at(&m_next_pos); + PFS_thread_iterator it= global_thread_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - 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; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -66,9 +70,9 @@ 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()) + + pfs= global_thread_container.get(m_pos.m_index); + if (pfs != NULL) { make_row(pfs); return 0; diff --git a/storage/perfschema/cursor_by_thread.h b/storage/perfschema/cursor_by_thread.h index db130088920..1fd803d906c 100644 --- a/storage/perfschema/cursor_by_thread.h +++ b/storage/perfschema/cursor_by_thread.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -41,6 +41,8 @@ class cursor_by_thread : public PFS_engine_table { public: + static ha_rows get_row_count(); + virtual int rnd_next(); virtual int rnd_pos(const void *pos); virtual void reset_position(void); diff --git a/storage/perfschema/cursor_by_thread_connect_attr.cc b/storage/perfschema/cursor_by_thread_connect_attr.cc index 90a200b809a..b4462a8d748 100644 --- a/storage/perfschema/cursor_by_thread_connect_attr.cc +++ b/storage/perfschema/cursor_by_thread_connect_attr.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -22,6 +22,20 @@ #include "my_global.h" #include "cursor_by_thread_connect_attr.h" +#include "pfs_buffer_container.h" + +ha_rows +cursor_by_thread_connect_attr::get_row_count(void) +{ + /* + The real number of attributes per thread does not matter, + we only need to hint the optimizer there are many per thread, + so abusing session_connect_attrs_size_per_thread + (which is a number of bytes, not attributes) + */ + return global_thread_container.get_row_count() * + session_connect_attrs_size_per_thread; +} cursor_by_thread_connect_attr::cursor_by_thread_connect_attr( const PFS_engine_table_share *share) : @@ -31,14 +45,14 @@ cursor_by_thread_connect_attr::cursor_by_thread_connect_attr( int cursor_by_thread_connect_attr::rnd_next(void) { PFS_thread *thread; + bool has_more_thread= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_thread(); + has_more_thread; m_pos.next_thread()) { - thread= &thread_array[m_pos.m_index_1]; - - if (thread->m_lock.is_populated()) + thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (thread != NULL) { make_row(thread, m_pos.m_index_2); if (m_row_exists) @@ -48,6 +62,7 @@ int cursor_by_thread_connect_attr::rnd_next(void) } } } + return HA_ERR_END_OF_FILE; } @@ -57,15 +72,14 @@ 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; + thread= global_thread_container.get(m_pos.m_index_1); + if (thread != NULL) + { + make_row(thread, m_pos.m_index_2); + if (m_row_exists) + return 0; + } return HA_ERR_RECORD_DELETED; } diff --git a/storage/perfschema/cursor_by_thread_connect_attr.h b/storage/perfschema/cursor_by_thread_connect_attr.h index 69d1b5ec0c0..7aa31115b30 100644 --- a/storage/perfschema/cursor_by_thread_connect_attr.h +++ b/storage/perfschema/cursor_by_thread_connect_attr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2012, 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, version 2.0, @@ -32,6 +32,10 @@ @{ */ +/** + Position of a cursor on abstract table + PERFORMANCE_SCHEMA.SESSION_CONNECT_ATTRS. +*/ struct pos_connect_attr_by_thread_by_attr : public PFS_double_index { @@ -39,11 +43,6 @@ struct 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++; @@ -61,6 +60,8 @@ struct pos_connect_attr_by_thread_by_attr class cursor_by_thread_connect_attr : public PFS_engine_table { public: + static ha_rows get_row_count(); + virtual int rnd_next(); virtual int rnd_pos(const void *pos); virtual void reset_position(void); diff --git a/storage/perfschema/cursor_by_user.cc b/storage/perfschema/cursor_by_user.cc index 273d186b01c..7699bcf1fc8 100644 --- a/storage/perfschema/cursor_by_user.cc +++ b/storage/perfschema/cursor_by_user.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -27,7 +27,13 @@ #include "my_global.h" #include "cursor_by_user.h" -#include "pfs_user.h" +#include "pfs_buffer_container.h" + +ha_rows +cursor_by_user::get_row_count(void) +{ + return global_user_container.get_row_count(); +} cursor_by_user::cursor_by_user(const PFS_engine_table_share *share) : PFS_engine_table(share, &m_pos), @@ -44,17 +50,14 @@ 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()) + m_pos.set_at(&m_next_pos); + PFS_user_iterator it= global_user_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - 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; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -66,9 +69,9 @@ 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()) + + pfs= global_user_container.get(m_pos.m_index); + if (pfs != NULL) { make_row(pfs); return 0; diff --git a/storage/perfschema/cursor_by_user.h b/storage/perfschema/cursor_by_user.h index 06554ebb228..d31f886170c 100644 --- a/storage/perfschema/cursor_by_user.h +++ b/storage/perfschema/cursor_by_user.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -41,6 +41,8 @@ class cursor_by_user : public PFS_engine_table { public: + static ha_rows get_row_count(); + virtual int rnd_next(); virtual int rnd_pos(const void *pos); virtual void reset_position(void); diff --git a/storage/perfschema/gen_pfs_lex_token.cc b/storage/perfschema/gen_pfs_lex_token.cc deleted file mode 100644 index 5a51a8aeb2f..00000000000 --- a/storage/perfschema/gen_pfs_lex_token.cc +++ /dev/null @@ -1,358 +0,0 @@ -/* - 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, version 2.0, - as published by the Free Software Foundation. - - This program is also distributed with certain software (including - but not limited to OpenSSL) that is licensed under separate terms, - as designated in a particular file or component or in included license - documentation. The authors of MySQL hereby grant you an additional - permission to link the program and your derivative works with the - separately licensed software that they have included with MySQL. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License, version 2.0, for more details. - - 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 0972d0dae21..2261b4feff1 100644 --- a/storage/perfschema/ha_perfschema.cc +++ b/storage/perfschema/ha_perfschema.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2008, 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, version 2.0, @@ -36,10 +36,14 @@ #include "pfs_account.h" #include "pfs_host.h" #include "pfs_user.h" -#include "pfs_account.h" +#include "pfs_program.h" +#include "pfs_prepared_stmt.h" +#include "pfs_buffer_container.h" handlerton *pfs_hton= NULL; +#define PFS_ENABLED() (pfs_initialized && (pfs_enabled || m_table_share->m_perpetual)) + static handler* pfs_create_handler(handlerton *hton, TABLE_SHARE *table, MEM_ROOT *mem_root) @@ -131,6 +135,15 @@ static int pfs_done_func(void *p) DBUG_RETURN(0); } +static int show_func_mutex_instances_lost(THD *thd, SHOW_VAR *var, char *buff) +{ + var->type= SHOW_LONG; + var->value= buff; + long *value= reinterpret_cast<long*>(buff); + *value= global_mutex_container.get_lost_counter(); + return 0; +} + static struct st_mysql_show_var pfs_status_vars[]= { {"Performance_schema_mutex_classes_lost", @@ -145,34 +158,42 @@ static struct st_mysql_show_var pfs_status_vars[]= (char*) &file_class_lost, SHOW_LONG_NOFLUSH}, {"Performance_schema_socket_classes_lost", (char*) &socket_class_lost, SHOW_LONG_NOFLUSH}, + {"Performance_schema_memory_classes_lost", + (char*) &memory_class_lost, SHOW_LONG_NOFLUSH}, {"Performance_schema_mutex_instances_lost", - (char*) &mutex_lost, SHOW_LONG}, + (char*) &show_func_mutex_instances_lost, SHOW_FUNC}, {"Performance_schema_rwlock_instances_lost", - (char*) &rwlock_lost, SHOW_LONG}, + (char*) &global_rwlock_container.m_lost, SHOW_LONG}, {"Performance_schema_cond_instances_lost", - (char*) &cond_lost, SHOW_LONG}, + (char*) &global_cond_container.m_lost, SHOW_LONG}, {"Performance_schema_thread_instances_lost", - (char*) &thread_lost, SHOW_LONG}, + (char*) &global_thread_container.m_lost, SHOW_LONG}, {"Performance_schema_file_instances_lost", - (char*) &file_lost, SHOW_LONG}, + (char*) &global_file_container.m_lost, SHOW_LONG}, {"Performance_schema_file_handles_lost", (char*) &file_handle_lost, SHOW_LONG}, {"Performance_schema_socket_instances_lost", - (char*) &socket_lost, SHOW_LONG}, + (char*) &global_socket_container.m_lost, SHOW_LONG}, {"Performance_schema_locker_lost", (char*) &locker_lost, SHOW_LONG}, /* table shares, can be flushed */ {"Performance_schema_table_instances_lost", - (char*) &table_share_lost, SHOW_LONG}, + (char*) &global_table_share_container.m_lost, SHOW_LONG}, /* table handles, can be flushed */ {"Performance_schema_table_handles_lost", - (char*) &table_lost, SHOW_LONG}, + (char*) &global_table_container.m_lost, SHOW_LONG}, + /* table lock stats, can be flushed */ + {"Performance_schema_table_lock_stat_lost", + (char*) &global_table_share_lock_container.m_lost, SHOW_LONG}, + /* table index stats, can be flushed */ + {"Performance_schema_index_stat_lost", + (char*) &global_table_share_index_container.m_lost, SHOW_LONG}, {"Performance_schema_hosts_lost", - (char*) &host_lost, SHOW_LONG}, + (char*) &global_host_container.m_lost, SHOW_LONG}, {"Performance_schema_users_lost", - (char*) &user_lost, SHOW_LONG}, + (char*) &global_user_container.m_lost, SHOW_LONG}, {"Performance_schema_accounts_lost", - (char*) &account_lost, SHOW_LONG}, + (char*) &global_account_container.m_lost, SHOW_LONG}, {"Performance_schema_stage_classes_lost", (char*) &stage_class_lost, SHOW_LONG}, {"Performance_schema_statement_classes_lost", @@ -181,6 +202,14 @@ static struct st_mysql_show_var pfs_status_vars[]= (char*) &digest_lost, SHOW_LONG}, {"Performance_schema_session_connect_attrs_lost", (char*) &session_connect_attrs_lost, SHOW_LONG}, + {"Performance_schema_program_lost", + (char*) &global_program_container.m_lost, SHOW_LONG}, + {"Performance_schema_nested_statement_lost", + (char*) &nested_statement_lost, SHOW_LONG}, + {"Performance_schema_prepared_statements_lost", + (char*) &global_prepared_stmt_container.m_lost, SHOW_LONG}, + {"Performance_schema_metadata_lock_lost", + (char*) &global_mdl_container.m_lost, SHOW_LONG}, {NullS, NullS, SHOW_LONG} }; @@ -262,7 +291,7 @@ int ha_perfschema::write_row(const uchar *buf) int result; DBUG_ENTER("ha_perfschema::write_row"); - if (!pfs_initialized) + if (!PFS_ENABLED()) DBUG_RETURN(HA_ERR_WRONG_COMMAND); DBUG_ASSERT(m_table_share); @@ -284,7 +313,7 @@ void ha_perfschema::use_hidden_primary_key(void) int ha_perfschema::update_row(const uchar *old_data, const uchar *new_data) { DBUG_ENTER("ha_perfschema::update_row"); - if (!pfs_initialized) + if (!PFS_ENABLED()) DBUG_RETURN(HA_ERR_WRONG_COMMAND); if (is_executed_by_slave()) @@ -298,7 +327,7 @@ int ha_perfschema::update_row(const uchar *old_data, const uchar *new_data) int ha_perfschema::delete_row(const uchar *buf) { DBUG_ENTER("ha_perfschema::delete_row"); - if (!pfs_initialized) + if (!PFS_ENABLED()) DBUG_RETURN(HA_ERR_WRONG_COMMAND); DBUG_ASSERT(m_table); @@ -339,7 +368,7 @@ int ha_perfschema::rnd_end(void) int ha_perfschema::rnd_next(uchar *buf) { DBUG_ENTER("ha_perfschema::rnd_next"); - if (!pfs_initialized) + if (!PFS_ENABLED()) { table->status= STATUS_NOT_FOUND; DBUG_RETURN(HA_ERR_END_OF_FILE); @@ -370,7 +399,7 @@ 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) + if (!PFS_ENABLED()) { table->status= STATUS_NOT_FOUND; DBUG_RETURN(HA_ERR_END_OF_FILE); @@ -400,7 +429,7 @@ int ha_perfschema::delete_all_rows(void) int result; DBUG_ENTER("ha_perfschema::delete_all_rows"); - if (!pfs_initialized) + if (!PFS_ENABLED()) DBUG_RETURN(0); if (is_executed_by_slave()) diff --git a/storage/perfschema/ha_perfschema.h b/storage/perfschema/ha_perfschema.h index 18ac035831d..36ea124056d 100644 --- a/storage/perfschema/ha_perfschema.h +++ b/storage/perfschema/ha_perfschema.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2014, 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, version 2.0, diff --git a/storage/perfschema/my_thread.h b/storage/perfschema/my_thread.h new file mode 100644 index 00000000000..28f8ae07ab8 --- /dev/null +++ b/storage/perfschema/my_thread.h @@ -0,0 +1,90 @@ +#ifndef STORAGE_PERFSCHEMA_MY_THREAD_INCLUDED +#define STORAGE_PERFSCHEMA_MY_THREAD_INCLUDED + +#include <my_pthread.h> +#include <m_string.h> +#include "rpl_gtid.h" + +typedef pthread_key_t thread_local_key_t; +typedef pthread_t my_thread_handle; +typedef pthread_attr_t my_thread_attr_t; +typedef uint32 my_thread_os_id_t; + +static inline int my_create_thread_local_key(thread_local_key_t *key, void (*destructor)(void*)) +{ return pthread_key_create(key, destructor); } + +static inline int my_delete_thread_local_key(thread_local_key_t key) +{ return pthread_key_delete(key); } + +static inline void *my_get_thread_local(thread_local_key_t key) +{ return pthread_getspecific(key); } + +static inline int my_set_thread_local(thread_local_key_t key, const void *ptr) +{ return pthread_setspecific(key, ptr); } + +static inline int my_thread_create(my_thread_handle *thread, + const my_thread_attr_t *attr, void *(*start_routine)(void *), void *arg) +{ return pthread_create(thread, attr, start_routine, arg); } + +static inline my_thread_os_id_t my_thread_os_id() +{ +#ifdef __NR_gettid + return (uint32)syscall(__NR_gettid); +#else + return 0; +#endif +} + +enum enum_sp_type +{ + SP_TYPE_FUNCTION= 1, + SP_TYPE_PROCEDURE, + SP_TYPE_TRIGGER, + SP_TYPE_EVENT +}; + +#define CHANNEL_NAME_LENGTH MAX_CONNECTION_NAME + +enum enum_mysql_show_scope +{ + SHOW_SCOPE_UNDEF, + SHOW_SCOPE_GLOBAL, + SHOW_SCOPE_SESSION, + SHOW_SCOPE_ALL +}; +typedef enum enum_mysql_show_scope SHOW_SCOPE; + +#define SHOW_VAR_MAX_NAME_LEN NAME_LEN + +static inline char *my_stpnmov(char *dst, const char *src, size_t n) +{ return strnmov(dst, src, n); } + +class Gtid_specification: public rpl_gtid +{ +public: + size_t to_string(char *buf) + { + return my_snprintf(buf, GTID_MAX_STR_LENGTH, "%u-%u-%llu", + domain_id, server_id, seq_no); + } +}; + +static inline size_t bin_to_hex_str(char *to, size_t to_len, + const char *from, size_t from_len) +{ + if (to_len < from_len * 2 + 1) + return 0 ; + for (size_t i=0; i < from_len; i++, from++) + { + *to++=_dig_vec_upper[((unsigned char) *from) >> 4]; + *to++=_dig_vec_upper[((unsigned char) *from) & 0xF]; + } + *to= '\0'; + return from_len * 2 + 1; +} + +enum enum_psi_status { PENDING = 0, GRANTED, + PRE_ACQUIRE_NOTIFY, POST_RELEASE_NOTIFY }; + +PSI_thread* thd_get_psi(THD *thd); +#endif diff --git a/storage/perfschema/pfs.cc b/storage/perfschema/pfs.cc index 2f1081b3836..23b9feab6ed 100644 --- a/storage/perfschema/pfs.cc +++ b/storage/perfschema/pfs.cc @@ -26,6 +26,19 @@ */ #include "my_global.h" #include "thr_lock.h" + +/* Make sure exported prototypes match the implementation. */ +#include "pfs_file_provider.h" +#include "pfs_idle_provider.h" +#include "pfs_memory_provider.h" +#include "pfs_metadata_provider.h" +#include "pfs_socket_provider.h" +#include "pfs_stage_provider.h" +#include "pfs_statement_provider.h" +#include "pfs_table_provider.h" +#include "pfs_thread_provider.h" +#include "pfs_transaction_provider.h" + #include "mysql/psi/psi.h" #include "mysql/psi/mysql_thread.h" #include "my_pthread.h" @@ -42,11 +55,48 @@ #include "pfs_events_waits.h" #include "pfs_events_stages.h" #include "pfs_events_statements.h" +#include "pfs_events_transactions.h" #include "pfs_setup_actor.h" #include "pfs_setup_object.h" #include "sql_error.h" #include "sp_head.h" +#include "mdl.h" /* mdl_key_init */ #include "pfs_digest.h" +#include "pfs_program.h" +#include "pfs_prepared_stmt.h" + +using std::min; + +/* + This is a development tool to investigate memory statistics, + do not use in production. +*/ +#undef PFS_PARANOID + +#ifdef PFS_PARANOID +static void report_memory_accounting_error( + const char *api_name, + PFS_thread *new_thread, + size_t size, + PFS_memory_class *klass, + PFS_thread *old_thread) +{ + pfs_print_error("%s " + "thread <%d> of class <%s> " + "not owner of <%d> bytes in class <%s> " + "allocated by thread <%d> of class <%s>\n", + api_name, + new_thread->m_thread_internal_id, + new_thread->m_class->m_name, + size, klass->m_name, + old_thread->m_thread_internal_id, + old_thread->m_class->m_name); + + DBUG_ASSERT(strcmp(new_thread->m_class->m_name, "thread/sql/event_worker") != 0); + DBUG_ASSERT(strcmp(new_thread->m_class->m_name, "thread/sql/event_scheduler") != 0); + DBUG_ASSERT(strcmp(new_thread->m_class->m_name, "thread/sql/one_connection") != 0); +} +#endif /* PFS_PARANOID */ /** @page PAGE_PERFORMANCE_SCHEMA The Performance Schema main page @@ -393,14 +443,14 @@ static inline int mysql_mutex_lock( struct PSI_mutex_locker *locker= NULL; ............... (a) - locker= PSI_server->start_mutex_wait(&state, that->p_psi, - PSI_MUTEX_LOCK, locker, src_file, src_line); + locker= PSI_MUTEX_CALL(start_mutex_wait)(&state, that->p_psi, PSI_MUTEX_LOCK, + locker, src_file, src_line); ............... (b) result= pthread_mutex_lock(&that->m_mutex); ............... (c) - PSI_server->end_mutex_wait(locker, result); + PSI_MUTEX_CALL(end_mutex_wait)(locker, result); return result; } @@ -420,6 +470,62 @@ static inline int mysql_mutex_lock(...) return result; } @endverbatim + + When the performance schema instrumentation is compiled in, + and when the code compiled is internal to the server implementation, + PSI_MUTEX_CALL expands directly to functions calls in the performance schema, + to make (a) and (c) calls as efficient as possible. + +@verbatim +static inline int mysql_mutex_lock(...) +{ + int result; + struct PSI_mutex_locker_state state; + struct PSI_mutex_locker *locker= NULL; + + ............... (a) + locker= pfs_start_mutex_wait_v1(&state, that->p_psi, PSI_MUTEX_LOCK, + locker, src_file, src_line); + + ............... (b) + result= pthread_mutex_lock(&that->m_mutex); + + ............... (c) + pfs_end_mutex_wait_v1(locker, result); + + return result; +} +@endverbatim + + When the performance schema instrumentation is compiled in, + and when the code compiled is external to the server implementation + (typically, a dynamic plugin), + PSI_MUTEX_CALL expands to dynamic calls to the underlying implementation, + using the PSI_server entry point. + This makes (a) and (c) slower, as a function pointer is used instead of a static call, + but also independent of the implementation, for binary compatibility. + +@verbatim +static inline int mysql_mutex_lock(...) +{ + int result; + struct PSI_mutex_locker_state state; + struct PSI_mutex_locker *locker= NULL; + + ............... (a) + locker= PSI_server->start_mutex_wait(&state, that->p_psi, PSI_MUTEX_LOCK, + locker, src_file, src_line); + + ............... (b) + result= pthread_mutex_lock(&that->m_mutex); + + ............... (c) + PSI_server->end_mutex_wait(locker, result); + + return result; +} +@endverbatim + */ /** @@ -1102,6 +1208,134 @@ static inline int mysql_mutex_lock(...) @c table_events_statements_common::make_row() - [I] EVENTS_STATEMENTS_SUMMARY_BY_DIGEST @c table_esms_by_digest::make_row() + +@section IMPL_TRANSACTION Implementation for transactions consumers + + For transactions, the tables that contains individual event data are: + - EVENTS_TRANSACTIONS_CURRENT + - EVENTS_TRANSACTIONS_HISTORY + - EVENTS_TRANSACTIONS_HISTORY_LONG + + For transactions, the tables that contains aggregated data are: + - EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME + - EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME + - EVENTS_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME + - EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME + +@verbatim + transaction_locker(T, TX) + | + | [1] + | +1a |-> pfs_thread(T).event_name(TX) =====>> [A], [B], [C], [D], [E] + | | + | | [2] + | | + | 2a |-> pfs_account(U, H).event_name(TX) =====>> [B], [C], [D], [E] + | . | + | . | [3-RESET] + | . | + | 2b .....+-> pfs_user(U).event_name(TX) =====>> [C] + | . | + | 2c .....+-> pfs_host(H).event_name(TX) =====>> [D], [E] + | . . | + | . . | [4-RESET] + | 2d . . | +1b |----+----+----+-> pfs_transaction_class(TX) =====>> [E] + | +1c |-> pfs_thread(T).transaction_current(TX) =====>> [F] + | +1d |-> pfs_thread(T).transaction_history(TX) =====>> [G] + | +1e |-> transaction_history_long(TX) =====>> [H] + +@endverbatim + + Implemented as: + - [1] @c start_transaction_v1(), end_transaction_v1() + (1a, 1b) is an aggregation by EVENT_NAME, + (1c, 1d, 1e) is an aggregation by TIME, + all of these are orthogonal, + and implemented in end_transaction_v1(). + - [2] @c delete_thread_v1(), @c aggregate_thread_transactions() + - [3] @c PFS_account::aggregate_transactions() + - [4] @c PFS_host::aggregate_transactions() + + - [A] EVENTS_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME, + @c table_ets_by_thread_by_event_name::make_row() + - [B] EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME, + @c table_ets_by_account_by_event_name::make_row() + - [C] EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME, + @c table_ets_by_user_by_event_name::make_row() + - [D] EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME, + @c table_ets_by_host_by_event_name::make_row() + - [E] EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME, + @c table_ets_global_by_event_name::make_row() + - [F] EVENTS_TRANSACTIONS_CURRENT, + @c table_events_transactions_current::rnd_next(), + @c table_events_transactions_common::make_row() + - [G] EVENTS_TRANSACTIONS_HISTORY, + @c table_events_transactions_history::rnd_next(), + @c table_events_transactions_common::make_row() + - [H] EVENTS_TRANSACTIONS_HISTORY_LONG, + @c table_events_transactions_history_long::rnd_next(), + @c table_events_transactions_common::make_row() + +@section IMPL_MEMORY Implementation for memory instruments + + For memory, there are no tables that contains individual event data. + + For memory, the tables that contains aggregated data are: + - MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME + - MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME + - MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME + - MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME + - MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME + +@verbatim + memory_event(T, S) + | + | [1] + | +1a |-> pfs_thread(T).event_name(S) =====>> [A], [B], [C], [D], [E] + | | + | | [2] + | | +1+ | 2a |-> pfs_account(U, H).event_name(S) =====>> [B], [C], [D], [E] + | . | + | . | [3-RESET] + | . | +1+ | 2b .....+-> pfs_user(U).event_name(S) =====>> [C] + | . | +1+ | 2c .....+-> pfs_host(H).event_name(S) =====>> [D], [E] + | . . | + | . . | [4-RESET] + | 2d . . | +1b |----+----+----+-> global.event_name(S) =====>> [E] + +@endverbatim + + Implemented as: + - [1] @c pfs_memory_alloc_v1(), + @c pfs_memory_realloc_v1(), + @c pfs_memory_free_v1(). + - [1+] are overflows that can happen during [1a], + implemented with @c carry_memory_stat_delta() + - [2] @c delete_thread_v1(), @c aggregate_thread_memory() + - [3] @c PFS_account::aggregate_memory() + - [4] @c PFS_host::aggregate_memory() + - [A] EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME, + @c table_mems_by_thread_by_event_name::make_row() + - [B] EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME, + @c table_mems_by_account_by_event_name::make_row() + - [C] EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME, + @c table_mems_by_user_by_event_name::make_row() + - [D] EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME, + @c table_mems_by_host_by_event_name::make_row() + - [E] EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME, + @c table_mems_global_by_event_name::make_row() + */ /** @@ -1117,9 +1351,35 @@ static inline int mysql_mutex_lock(...) @ingroup Performance_schema_implementation */ -pthread_key(PFS_thread*, THR_PFS); +thread_local_key_t THR_PFS; +thread_local_key_t THR_PFS_VG; // global_variables +thread_local_key_t THR_PFS_SV; // session_variables +thread_local_key_t THR_PFS_VBT; // variables_by_thread +thread_local_key_t THR_PFS_SG; // global_status +thread_local_key_t THR_PFS_SS; // session_status +thread_local_key_t THR_PFS_SBT; // status_by_thread +thread_local_key_t THR_PFS_SBU; // status_by_user +thread_local_key_t THR_PFS_SBH; // status_by_host +thread_local_key_t THR_PFS_SBA; // status_by_account + bool THR_PFS_initialized= false; +static inline PFS_thread* +my_thread_get_THR_PFS() +{ + DBUG_ASSERT(THR_PFS_initialized); + PFS_thread *thread= static_cast<PFS_thread*>(my_get_thread_local(THR_PFS)); + DBUG_ASSERT(thread == NULL || sanitize_thread(thread) != NULL); + return thread; +} + +static inline void +my_thread_set_THR_PFS(PFS_thread *pfs) +{ + DBUG_ASSERT(THR_PFS_initialized); + my_set_thread_local(THR_PFS, pfs); +} + /** Conversion map from PSI_mutex_operation to enum_operation_type. Indexed by enum PSI_mutex_operation. @@ -1139,7 +1399,14 @@ static enum_operation_type rwlock_operation_map[]= OPERATION_TYPE_READLOCK, OPERATION_TYPE_WRITELOCK, OPERATION_TYPE_TRYREADLOCK, - OPERATION_TYPE_TRYWRITELOCK + OPERATION_TYPE_TRYWRITELOCK, + + OPERATION_TYPE_SHAREDLOCK, + OPERATION_TYPE_SHAREDEXCLUSIVELOCK, + OPERATION_TYPE_EXCLUSIVELOCK, + OPERATION_TYPE_TRYSHAREDLOCK, + OPERATION_TYPE_TRYSHAREDEXCLUSIVELOCK, + OPERATION_TYPE_TRYEXCLUSIVELOCK, }; /** @@ -1201,7 +1468,6 @@ static enum_operation_type table_lock_operation_map[]= 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 */ @@ -1244,7 +1510,7 @@ static enum_operation_type socket_operation_map[]= @return 0 for success, non zero for errors */ static int build_prefix(const LEX_CSTRING *prefix, const char *category, - char *output, int *output_length) + char *output, size_t *output_length) { size_t len= strlen(category); char *out_ptr= output; @@ -1268,52 +1534,56 @@ static int build_prefix(const LEX_CSTRING *prefix, const char *category, /* output = prefix + category + '/' */ memcpy(out_ptr, prefix->str, prefix_length); out_ptr+= prefix_length; - memcpy(out_ptr, category, len); - out_ptr+= len; - *out_ptr= '/'; - out_ptr++; - *output_length= (int)(out_ptr - output); + if (len > 0) + { + memcpy(out_ptr, category, len); + out_ptr+= len; + *out_ptr= '/'; + out_ptr++; + } + *output_length= int(out_ptr - output); return 0; } -#define REGISTER_BODY_V1(KEY_T, PREFIX, REGISTER_FUNC) \ - KEY_T key; \ - char formatted_name[PFS_MAX_INFO_NAME_LENGTH]; \ - int prefix_length; \ - int len; \ - int full_length; \ - \ - DBUG_ASSERT(category != NULL); \ - DBUG_ASSERT(info != NULL); \ - if (unlikely(build_prefix(&PREFIX, category, \ - formatted_name, &prefix_length))) \ - { \ - for (; count>0; count--, info++) \ - *(info->m_key)= 0; \ - return ; \ - } \ - \ - for (; count>0; count--, info++) \ - { \ - DBUG_ASSERT(info->m_key != NULL); \ - DBUG_ASSERT(info->m_name != NULL); \ - len= (int)strlen(info->m_name); \ - full_length= prefix_length + len; \ - if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH)) \ - { \ - memcpy(formatted_name + prefix_length, info->m_name, len); \ - key= REGISTER_FUNC(formatted_name, full_length, info->m_flags); \ - } \ - else \ - { \ - pfs_print_error("REGISTER_BODY_V1: name too long <%s> <%s>\n", \ - category, info->m_name); \ - key= 0; \ - } \ - \ - *(info->m_key)= key; \ - } \ +#define REGISTER_BODY_V1(KEY_T, PREFIX, REGISTER_FUNC) \ + KEY_T key; \ + char formatted_name[PFS_MAX_INFO_NAME_LENGTH]; \ + size_t prefix_length; \ + size_t len; \ + size_t full_length; \ + \ + DBUG_ASSERT(category != NULL); \ + DBUG_ASSERT(info != NULL); \ + if (unlikely(build_prefix(&PREFIX, category, \ + formatted_name, &prefix_length)) || \ + ! pfs_initialized) \ + { \ + for (; count>0; count--, info++) \ + *(info->m_key)= 0; \ + return ; \ + } \ + \ + for (; count>0; count--, info++) \ + { \ + DBUG_ASSERT(info->m_key != NULL); \ + DBUG_ASSERT(info->m_name != NULL); \ + len= strlen(info->m_name); \ + full_length= prefix_length + len; \ + if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH)) \ + { \ + memcpy(formatted_name + prefix_length, info->m_name, len); \ + key= REGISTER_FUNC(formatted_name, (uint)full_length, info->m_flags); \ + } \ + else \ + { \ + pfs_print_error("REGISTER_BODY_V1: name too long <%s> <%s>\n", \ + category, info->m_name); \ + key= 0; \ + } \ + \ + *(info->m_key)= key; \ + } \ return; /* Use C linkage for the interface functions. */ @@ -1324,9 +1594,9 @@ 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) +void pfs_register_mutex_v1(const char *category, + PSI_mutex_info_v1 *info, + int count) { REGISTER_BODY_V1(PSI_mutex_key, mutex_instrument_prefix, @@ -1337,22 +1607,80 @@ static void register_mutex_v1(const char *category, 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) +void pfs_register_rwlock_v1(const char *category, + PSI_rwlock_info_v1 *info, + int count) { - REGISTER_BODY_V1(PSI_rwlock_key, - rwlock_instrument_prefix, - register_rwlock_class) + PSI_rwlock_key key; + char rw_formatted_name[PFS_MAX_INFO_NAME_LENGTH]; + char sx_formatted_name[PFS_MAX_INFO_NAME_LENGTH]; + size_t rw_prefix_length; + size_t sx_prefix_length; + size_t len; + size_t full_length; + + DBUG_ASSERT(category != NULL); + DBUG_ASSERT(info != NULL); + if (build_prefix(&rwlock_instrument_prefix, category, + rw_formatted_name, &rw_prefix_length) || + build_prefix(&sxlock_instrument_prefix, category, + sx_formatted_name, &sx_prefix_length) || + ! pfs_initialized) + { + for (; count>0; count--, info++) + *(info->m_key)= 0; + return ; + } + + for (; count>0; count--, info++) + { + DBUG_ASSERT(info->m_key != NULL); + DBUG_ASSERT(info->m_name != NULL); + len= strlen(info->m_name); + + if (info->m_flags & PSI_RWLOCK_FLAG_SX) + { + full_length= sx_prefix_length + len; + if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH)) + { + memcpy(sx_formatted_name + sx_prefix_length, info->m_name, len); + key= register_rwlock_class(sx_formatted_name, (uint)full_length, info->m_flags); + } + else + { + pfs_print_error("REGISTER_BODY_V1: (sx) name too long <%s> <%s>\n", + category, info->m_name); + key= 0; + } + } + else + { + full_length= rw_prefix_length + len; + if (likely(full_length <= PFS_MAX_INFO_NAME_LENGTH)) + { + memcpy(rw_formatted_name + rw_prefix_length, info->m_name, len); + key= register_rwlock_class(rw_formatted_name, (uint)full_length, info->m_flags); + } + else + { + pfs_print_error("REGISTER_BODY_V1: (rw) name too long <%s> <%s>\n", + category, info->m_name); + key= 0; + } + } + + *(info->m_key)= key; + } + return; } /** 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) +void pfs_register_cond_v1(const char *category, + PSI_cond_info_v1 *info, + int count) { REGISTER_BODY_V1(PSI_cond_key, cond_instrument_prefix, @@ -1363,9 +1691,9 @@ static void register_cond_v1(const char *category, 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) +void pfs_register_thread_v1(const char *category, + PSI_thread_info_v1 *info, + int count) { REGISTER_BODY_V1(PSI_thread_key, thread_instrument_prefix, @@ -1376,29 +1704,30 @@ static void register_thread_v1(const char *category, 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) +void pfs_register_file_v1(const char *category, + PSI_file_info_v1 *info, + int count) { REGISTER_BODY_V1(PSI_file_key, file_instrument_prefix, register_file_class) } -static void register_stage_v1(const char *category, - PSI_stage_info_v1 **info_array, - int count) +void pfs_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; + size_t prefix_length; + size_t len; + size_t 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))) + formatted_name, &prefix_length)) || + ! pfs_initialized) { for (; count>0; count--, info_array++) (*info_array)->m_key= 0; @@ -1416,8 +1745,8 @@ static void register_stage_v1(const char *category, { memcpy(formatted_name + prefix_length, info->m_name, len); info->m_key= register_stage_class(formatted_name, - prefix_length, - full_length, + (uint)prefix_length, + (uint)full_length, info->m_flags); } else @@ -1430,19 +1759,20 @@ static void register_stage_v1(const char *category, return; } -static void register_statement_v1(const char *category, - PSI_statement_info_v1 *info, - int count) +void pfs_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; + size_t prefix_length; + size_t len; + size_t full_length; DBUG_ASSERT(category != NULL); DBUG_ASSERT(info != NULL); if (unlikely(build_prefix(&statement_instrument_prefix, - category, formatted_name, &prefix_length))) + category, formatted_name, &prefix_length)) || + ! pfs_initialized) { for (; count>0; count--, info++) info->m_key= 0; @@ -1459,7 +1789,7 @@ static void register_statement_v1(const char *category, 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); + info->m_key= register_statement_class(formatted_name, (uint)full_length, info->m_flags); } else { @@ -1471,9 +1801,9 @@ static void register_statement_v1(const char *category, return; } -static void register_socket_v1(const char *category, - PSI_socket_info_v1 *info, - int count) +void pfs_register_socket_v1(const char *category, + PSI_socket_info_v1 *info, + int count) { REGISTER_BODY_V1(PSI_socket_key, socket_instrument_prefix, @@ -1486,8 +1816,6 @@ static void register_socket_v1(const char *category, klass= find_##T##_class(KEY); \ if (unlikely(klass == NULL)) \ return NULL; \ - if (! klass->m_enabled) \ - return NULL; \ pfs= create_##T(klass, ID); \ return reinterpret_cast<PSI_##T *> (pfs) @@ -1495,8 +1823,8 @@ static void register_socket_v1(const char *category, Implementation of the mutex instrumentation interface. @sa PSI_v1::init_mutex. */ -static PSI_mutex* -init_mutex_v1(PSI_mutex_key key, const void *identity) +PSI_mutex* +pfs_init_mutex_v1(PSI_mutex_key key, const void *identity) { INIT_BODY_V1(mutex, key, identity); } @@ -1505,7 +1833,7 @@ init_mutex_v1(PSI_mutex_key key, const void *identity) Implementation of the mutex instrumentation interface. @sa PSI_v1::destroy_mutex. */ -static void destroy_mutex_v1(PSI_mutex* mutex) +void pfs_destroy_mutex_v1(PSI_mutex* mutex) { PFS_mutex *pfs= reinterpret_cast<PFS_mutex*> (mutex); @@ -1518,8 +1846,8 @@ static void destroy_mutex_v1(PSI_mutex* mutex) Implementation of the rwlock instrumentation interface. @sa PSI_v1::init_rwlock. */ -static PSI_rwlock* -init_rwlock_v1(PSI_rwlock_key key, const void *identity) +PSI_rwlock* +pfs_init_rwlock_v1(PSI_rwlock_key key, const void *identity) { INIT_BODY_V1(rwlock, key, identity); } @@ -1528,7 +1856,7 @@ init_rwlock_v1(PSI_rwlock_key key, const void *identity) Implementation of the rwlock instrumentation interface. @sa PSI_v1::destroy_rwlock. */ -static void destroy_rwlock_v1(PSI_rwlock* rwlock) +void pfs_destroy_rwlock_v1(PSI_rwlock* rwlock) { PFS_rwlock *pfs= reinterpret_cast<PFS_rwlock*> (rwlock); @@ -1541,8 +1869,8 @@ static void destroy_rwlock_v1(PSI_rwlock* rwlock) Implementation of the cond instrumentation interface. @sa PSI_v1::init_cond. */ -static PSI_cond* -init_cond_v1(PSI_cond_key key, const void *identity) +PSI_cond* +pfs_init_cond_v1(PSI_cond_key key, const void *identity) { INIT_BODY_V1(cond, key, identity); } @@ -1551,7 +1879,7 @@ init_cond_v1(PSI_cond_key key, const void *identity) Implementation of the cond instrumentation interface. @sa PSI_v1::destroy_cond. */ -static void destroy_cond_v1(PSI_cond* cond) +void pfs_destroy_cond_v1(PSI_cond* cond) { PFS_cond *pfs= reinterpret_cast<PFS_cond*> (cond); @@ -1564,14 +1892,14 @@ static void destroy_cond_v1(PSI_cond* cond) Implementation of the table instrumentation interface. @sa PSI_v1::get_table_share. */ -static PSI_table_share* -get_table_share_v1(my_bool temporary, TABLE_SHARE *share) +PSI_table_share* +pfs_get_table_share_v1(my_bool temporary, TABLE_SHARE *share) { /* Ignore temporary tables and views. */ if (temporary || share->is_view) return NULL; /* An instrumented thread is required, for LF_PINS. */ - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); if (unlikely(pfs_thread == NULL)) return NULL; PFS_table_share* pfs_share; @@ -1583,7 +1911,7 @@ get_table_share_v1(my_bool temporary, TABLE_SHARE *share) Implementation of the table instrumentation interface. @sa PSI_v1::release_table_share. */ -static void release_table_share_v1(PSI_table_share* share) +void pfs_release_table_share_v1(PSI_table_share* share) { PFS_table_share* pfs= reinterpret_cast<PFS_table_share*> (share); @@ -1597,15 +1925,15 @@ static void release_table_share_v1(PSI_table_share* share) 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) +void +pfs_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); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); if (unlikely(pfs_thread == NULL)) return; /* TODO: temporary tables */ @@ -1617,8 +1945,8 @@ drop_table_share_v1(my_bool temporary, Implementation of the table instrumentation interface. @sa PSI_v1::open_table. */ -static PSI_table* -open_table_v1(PSI_table_share *share, const void *identity) +PSI_table* +pfs_open_table_v1(PSI_table_share *share, const void *identity) { PFS_table_share *pfs_table_share= reinterpret_cast<PFS_table_share*> (share); @@ -1641,7 +1969,8 @@ open_table_v1(PSI_table_share *share, const void *identity) if (! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled) return NULL; - PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *thread= my_thread_get_THR_PFS(); + if (unlikely(thread == NULL)) return NULL; @@ -1653,12 +1982,13 @@ open_table_v1(PSI_table_share *share, const void *identity) Implementation of the table instrumentation interface. @sa PSI_v1::unbind_table. */ -static void unbind_table_v1(PSI_table *table) +void pfs_unbind_table_v1(PSI_table *table) { PFS_table *pfs= reinterpret_cast<PFS_table*> (table); if (likely(pfs != NULL)) { pfs->m_thread_owner= NULL; + pfs->m_owner_event_id= 0; } } @@ -1666,43 +1996,42 @@ static void unbind_table_v1(PSI_table *table) 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) +PSI_table * +pfs_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); - if (psi_unlikely(! flag_global_instrumentation)) + if (unlikely(! pfs->m_share->m_enabled)) { destroy_table(pfs); return 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)) + if (unlikely(! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled)) { destroy_table(pfs); return NULL; } - if (unlikely(! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled)) + if (psi_unlikely(! flag_global_instrumentation)) { destroy_table(pfs); return NULL; } + /* The table handle was already instrumented, reuse it for this thread. */ + PFS_thread *thread= my_thread_get_THR_PFS(); pfs->m_thread_owner= thread; + if (thread != NULL) + pfs->m_owner_event_id= thread->m_event_id; + else + pfs->m_owner_event_id= 0; return table; } - if (psi_unlikely(! flag_global_instrumentation)) - return NULL; - /* See open_table_v1() */ PFS_table_share *pfs_table_share= reinterpret_cast<PFS_table_share*> (share); @@ -1716,7 +2045,10 @@ rebind_table_v1(PSI_table_share *share, const void *identity, PSI_table *table) if (! global_table_io_class.m_enabled && ! global_table_lock_class.m_enabled) return NULL; - PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + if (! flag_global_instrumentation) + return NULL; + + PFS_thread *thread= my_thread_get_THR_PFS(); if (unlikely(thread == NULL)) return NULL; @@ -1728,31 +2060,29 @@ rebind_table_v1(PSI_table_share *share, const void *identity, PSI_table *table) Implementation of the table instrumentation interface. @sa PSI_v1::close_table. */ -static void close_table_v1(PSI_table *table) +void pfs_close_table_v1(TABLE_SHARE *server_share, PSI_table *table) { PFS_table *pfs= reinterpret_cast<PFS_table*> (table); if (unlikely(pfs == NULL)) return; - pfs->aggregate(); + pfs->aggregate(server_share); 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) +PSI_socket* +pfs_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) +void pfs_destroy_socket_v1(PSI_socket *socket) { PFS_socket *pfs= reinterpret_cast<PFS_socket*> (socket); @@ -1765,7 +2095,7 @@ static void destroy_socket_v1(PSI_socket *socket) 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) +void pfs_create_file_v1(PSI_file_key key, const char *name, File file) { if (psi_unlikely(! flag_global_instrumentation)) return; @@ -1779,7 +2109,7 @@ static void create_file_v1(PSI_file_key key, const char *name, File file) return; /* A thread is needed for LF_PINS */ - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); if (unlikely(pfs_thread == NULL)) return; @@ -1821,7 +2151,7 @@ struct PFS_spawn_thread_arg void *m_user_arg; }; -void* pfs_spawn_thread(void *arg) +extern "C" void* pfs_spawn_thread(void *arg) { PFS_spawn_thread_arg *typed_arg= (PFS_spawn_thread_arg*) arg; void *user_arg; @@ -1836,6 +2166,7 @@ void* pfs_spawn_thread(void *arg) pfs= create_thread(klass, typed_arg->m_child_identity, 0); if (likely(pfs != NULL)) { + pfs->m_thread_os_id= my_thread_os_id(); clear_thread_account(pfs); pfs->m_parent_thread_internal_id= typed_arg->m_thread_internal_id; @@ -1853,7 +2184,7 @@ void* pfs_spawn_thread(void *arg) { pfs= NULL; } - my_pthread_setspecific_ptr(THR_PFS, pfs); + my_thread_set_THR_PFS(pfs); /* Secondly, free the memory allocated in spawn_thread_v1(). @@ -1875,15 +2206,16 @@ void* pfs_spawn_thread(void *arg) 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) +int pfs_spawn_thread_v1(PSI_thread_key key, + my_thread_handle *thread, const my_thread_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), + psi_arg= (PFS_spawn_thread_arg*) my_malloc(PSI_NOT_INSTRUMENTED, + sizeof(PFS_spawn_thread_arg), MYF(MY_WME)); if (unlikely(psi_arg == NULL)) return EAGAIN; @@ -1893,7 +2225,7 @@ static int spawn_thread_v1(PSI_thread_key key, psi_arg->m_user_start_routine= start_routine; psi_arg->m_user_arg= arg; - parent= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + parent= my_thread_get_THR_PFS(); if (parent != NULL) { /* @@ -1916,7 +2248,7 @@ static int spawn_thread_v1(PSI_thread_key key, psi_arg->m_hostname_length= 0; } - int result= pthread_create(thread, attr, pfs_spawn_thread, psi_arg); + int result= my_thread_create(thread, attr, pfs_spawn_thread, psi_arg); if (unlikely(result != 0)) my_free(psi_arg); return result; @@ -1926,8 +2258,8 @@ static int spawn_thread_v1(PSI_thread_key key, Implementation of the thread instrumentation interface. @sa PSI_v1::new_thread. */ -static PSI_thread* -new_thread_v1(PSI_thread_key key, const void *identity, ulonglong processlist_id) +PSI_thread* +pfs_new_thread_v1(PSI_thread_key key, const void *identity, ulonglong processlist_id) { PFS_thread *pfs; @@ -1944,7 +2276,7 @@ new_thread_v1(PSI_thread_key key, const void *identity, ulonglong processlist_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) +void pfs_set_thread_id_v1(PSI_thread *thread, ulonglong processlist_id) { PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread); if (unlikely(pfs == NULL)) @@ -1954,12 +2286,36 @@ static void set_thread_id_v1(PSI_thread *thread, ulonglong processlist_id) /** Implementation of the thread instrumentation interface. + @sa PSI_v1::set_thread_THD. +*/ +void pfs_set_thread_THD_v1(PSI_thread *thread, THD *thd) +{ + PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread); + if (unlikely(pfs == NULL)) + return; + pfs->m_thd= thd; +} + +/** + Implementation of the thread instrumentation interface. + @sa PSI_v1::set_thread_os_thread_id. +*/ +void pfs_set_thread_os_id_v1(PSI_thread *thread) +{ + PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread); + if (unlikely(pfs == NULL)) + return; + pfs->m_thread_os_id= my_thread_os_id(); +} + +/** + Implementation of the thread instrumentation interface. @sa PSI_v1::get_thread_id. */ -static PSI_thread* -get_thread_v1(void) +PSI_thread* +pfs_get_thread_v1(void) { - PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs= my_thread_get_THR_PFS(); return reinterpret_cast<PSI_thread*> (pfs); } @@ -1967,9 +2323,10 @@ get_thread_v1(void) Implementation of the thread instrumentation interface. @sa PSI_v1::set_thread_user. */ -static void set_thread_user_v1(const char *user, int user_len) +void pfs_set_thread_user_v1(const char *user, int user_len) { - PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + pfs_dirty_state dirty_state; + PFS_thread *pfs= my_thread_get_THR_PFS(); DBUG_ASSERT((user != NULL) || (user_len == 0)); DBUG_ASSERT(user_len >= 0); @@ -1980,7 +2337,7 @@ static void set_thread_user_v1(const char *user, int user_len) aggregate_thread(pfs, pfs->m_account, pfs->m_user, pfs->m_host); - pfs->m_session_lock.allocated_to_dirty(); + pfs->m_session_lock.allocated_to_dirty(& dirty_state); clear_thread_account(pfs); @@ -1990,37 +2347,44 @@ static void set_thread_user_v1(const char *user, int user_len) set_thread_account(pfs); - bool enabled= true; - if (flag_thread_instrumentation) + bool enabled; + bool history; + if (pfs->m_account != NULL) + { + enabled= pfs->m_account->m_enabled; + history= pfs->m_account->m_history; + } + else { 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); + &enabled, &history); + } + else + { + /* There is no setting for background threads */ + enabled= true; + history= true; } } + pfs->set_enabled(enabled); + pfs->set_history(history); - pfs->m_enabled= enabled; - - pfs->m_session_lock.dirty_to_allocated(); + pfs->m_session_lock.dirty_to_allocated(& dirty_state); } /** 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) +void pfs_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); + pfs_dirty_state dirty_state; + PFS_thread *pfs= my_thread_get_THR_PFS(); DBUG_ASSERT((user != NULL) || (user_len == 0)); DBUG_ASSERT(user_len >= 0); @@ -2033,7 +2397,7 @@ static void set_thread_account_v1(const char *user, int user_len, if (unlikely(pfs == NULL)) return; - pfs->m_session_lock.allocated_to_dirty(); + pfs->m_session_lock.allocated_to_dirty(& dirty_state); clear_thread_account(pfs); @@ -2047,35 +2411,42 @@ static void set_thread_account_v1(const char *user, int user_len, set_thread_account(pfs); - bool enabled= true; - if (flag_thread_instrumentation) + bool enabled; + bool history; + if (pfs->m_account != NULL) + { + enabled= pfs->m_account->m_enabled; + history= pfs->m_account->m_history; + } + else { 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); + &enabled, &history); + } + else + { + /* There is no setting for background threads */ + enabled= true; + history= true; } } - pfs->m_enabled= enabled; + pfs->set_enabled(enabled); + pfs->set_history(history); - pfs->m_session_lock.dirty_to_allocated(); + pfs->m_session_lock.dirty_to_allocated(& dirty_state); } /** Implementation of the thread instrumentation interface. @sa PSI_v1::set_thread_db. */ -static void set_thread_db_v1(const char* db, int db_len) +void pfs_set_thread_db_v1(const char* db, int db_len) { - PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs= my_thread_get_THR_PFS(); DBUG_ASSERT((db != NULL) || (db_len == 0)); DBUG_ASSERT(db_len >= 0); @@ -2083,11 +2454,12 @@ static void set_thread_db_v1(const char* db, int db_len) if (likely(pfs != NULL)) { - pfs->m_stmt_lock.allocated_to_dirty(); + pfs_dirty_state dirty_state; + pfs->m_stmt_lock.allocated_to_dirty(& dirty_state); if (db_len > 0) memcpy(pfs->m_dbname, db, db_len); pfs->m_dbname_length= db_len; - pfs->m_stmt_lock.dirty_to_allocated(); + pfs->m_stmt_lock.dirty_to_allocated(& dirty_state); } } @@ -2095,9 +2467,9 @@ static void set_thread_db_v1(const char* db, int db_len) Implementation of the thread instrumentation interface. @sa PSI_v1::set_thread_command. */ -static void set_thread_command_v1(int command) +void pfs_set_thread_command_v1(int command) { - PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs= my_thread_get_THR_PFS(); DBUG_ASSERT(command >= 0); DBUG_ASSERT(command <= (int) COM_END); @@ -2109,12 +2481,27 @@ static void set_thread_command_v1(int command) } /** +Implementation of the thread instrumentation interface. +@sa PSI_v1::set_thread_connection_type. +*/ +void pfs_set_connection_type_v1(opaque_vio_type conn_type) +{ + PFS_thread *pfs= my_thread_get_THR_PFS(); + + if (likely(pfs != NULL)) + { + pfs->m_connection_type= static_cast<enum_vio_type> (conn_type); + } +} + + +/** Implementation of the thread instrumentation interface. @sa PSI_v1::set_thread_start_time. */ -static void set_thread_start_time_v1(time_t start_time) +void pfs_set_thread_start_time_v1(time_t start_time) { - PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs= my_thread_get_THR_PFS(); if (likely(pfs != NULL)) { @@ -2126,7 +2513,7 @@ static void set_thread_start_time_v1(time_t start_time) Implementation of the thread instrumentation interface. @sa PSI_v1::set_thread_state. */ -static void set_thread_state_v1(const char* state) +void pfs_set_thread_state_v1(const char* state) { /* DEPRECATED. */ } @@ -2135,9 +2522,10 @@ static void set_thread_state_v1(const char* state) Implementation of the thread instrumentation interface. @sa PSI_v1::set_thread_info. */ -static void set_thread_info_v1(const char* info, uint info_len) +void pfs_set_thread_info_v1(const char* info, uint info_len) { - PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + pfs_dirty_state dirty_state; + PFS_thread *pfs= my_thread_get_THR_PFS(); DBUG_ASSERT((info != NULL) || (info_len == 0)); @@ -2148,16 +2536,16 @@ static void set_thread_info_v1(const char* info, uint info_len) if (info_len > sizeof(pfs->m_processlist_info)) info_len= sizeof(pfs->m_processlist_info); - pfs->m_stmt_lock.allocated_to_dirty(); + pfs->m_stmt_lock.allocated_to_dirty(& dirty_state); memcpy(pfs->m_processlist_info, info, info_len); pfs->m_processlist_info_length= info_len; - pfs->m_stmt_lock.dirty_to_allocated(); + pfs->m_stmt_lock.dirty_to_allocated(& dirty_state); } else { - pfs->m_stmt_lock.allocated_to_dirty(); + pfs->m_stmt_lock.allocated_to_dirty(& dirty_state); pfs->m_processlist_info_length= 0; - pfs->m_stmt_lock.dirty_to_allocated(); + pfs->m_stmt_lock.dirty_to_allocated(& dirty_state); } } } @@ -2166,23 +2554,23 @@ static void set_thread_info_v1(const char* info, uint info_len) Implementation of the thread instrumentation interface. @sa PSI_v1::set_thread. */ -static void set_thread_v1(PSI_thread* thread) +void pfs_set_thread_v1(PSI_thread* thread) { PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread); - my_pthread_setspecific_ptr(THR_PFS, pfs); + my_thread_set_THR_PFS(pfs); } /** Implementation of the thread instrumentation interface. @sa PSI_v1::delete_current_thread. */ -static void delete_current_thread_v1(void) +void pfs_delete_current_thread_v1(void) { - PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *thread= my_thread_get_THR_PFS(); if (thread != NULL) { aggregate_thread(thread, thread->m_account, thread->m_user, thread->m_host); - my_pthread_setspecific_ptr(THR_PFS, NULL); + my_thread_set_THR_PFS(NULL); destroy_thread(thread); } } @@ -2191,7 +2579,7 @@ static void delete_current_thread_v1(void) Implementation of the thread instrumentation interface. @sa PSI_v1::delete_thread. */ -static void delete_thread_v1(PSI_thread *thread) +void pfs_delete_thread_v1(PSI_thread *thread) { PFS_thread *pfs= reinterpret_cast<PFS_thread*> (thread); @@ -2206,10 +2594,10 @@ static void delete_thread_v1(PSI_thread *thread) Implementation of the mutex instrumentation interface. @sa PSI_v1::start_mutex_wait. */ -static PSI_mutex_locker* -start_mutex_wait_v1(PSI_mutex_locker_state *state, - PSI_mutex *mutex, PSI_mutex_operation op, - const char *src_file, uint src_line) +PSI_mutex_locker* +pfs_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); @@ -2227,7 +2615,7 @@ start_mutex_wait_v1(PSI_mutex_locker_state *state, if (flag_thread_instrumentation) { - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); if (unlikely(pfs_thread == NULL)) return NULL; if (! pfs_thread->m_enabled) @@ -2259,7 +2647,7 @@ start_mutex_wait_v1(PSI_mutex_locker_state *state, 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_thread_internal_id= pfs_thread->m_thread_internal_id; wait->m_class= pfs_mutex->m_class; wait->m_timer_start= timer_start; wait->m_timer_end= 0; @@ -2304,11 +2692,11 @@ start_mutex_wait_v1(PSI_mutex_locker_state *state, @sa PSI_v1::start_rwlock_rdwait @sa PSI_v1::start_rwlock_wrwait */ -static PSI_rwlock_locker* -start_rwlock_wait_v1(PSI_rwlock_locker_state *state, - PSI_rwlock *rwlock, - PSI_rwlock_operation op, - const char *src_file, uint src_line) +PSI_rwlock_locker* +pfs_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); @@ -2317,6 +2705,26 @@ start_rwlock_wait_v1(PSI_rwlock_locker_state *state, DBUG_ASSERT(pfs_rwlock != NULL); DBUG_ASSERT(pfs_rwlock->m_class != NULL); + /* Operations supported for READ WRITE LOCK */ + + DBUG_ASSERT( pfs_rwlock->m_class->is_shared_exclusive() + || (op == PSI_RWLOCK_READLOCK) + || (op == PSI_RWLOCK_WRITELOCK) + || (op == PSI_RWLOCK_TRYREADLOCK) + || (op == PSI_RWLOCK_TRYWRITELOCK) + ); + + /* Operations supported for SHARED EXCLUSIVE LOCK */ + + DBUG_ASSERT( ! pfs_rwlock->m_class->is_shared_exclusive() + || (op == PSI_RWLOCK_SHAREDLOCK) + || (op == PSI_RWLOCK_SHAREDEXCLUSIVELOCK) + || (op == PSI_RWLOCK_EXCLUSIVELOCK) + || (op == PSI_RWLOCK_TRYSHAREDLOCK) + || (op == PSI_RWLOCK_TRYSHAREDEXCLUSIVELOCK) + || (op == PSI_RWLOCK_TRYEXCLUSIVELOCK) + ); + if (! pfs_rwlock->m_enabled) return NULL; @@ -2325,7 +2733,7 @@ start_rwlock_wait_v1(PSI_rwlock_locker_state *state, if (flag_thread_instrumentation) { - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); if (unlikely(pfs_thread == NULL)) return NULL; if (! pfs_thread->m_enabled) @@ -2357,7 +2765,7 @@ start_rwlock_wait_v1(PSI_rwlock_locker_state *state, 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_thread_internal_id= pfs_thread->m_thread_internal_id; wait->m_class= pfs_rwlock->m_class; wait->m_timer_start= timer_start; wait->m_timer_end= 0; @@ -2394,18 +2802,49 @@ start_rwlock_wait_v1(PSI_rwlock_locker_state *state, state->m_flags= flags; state->m_rwlock= rwlock; + state->m_operation= op; return reinterpret_cast<PSI_rwlock_locker*> (state); } +PSI_rwlock_locker* +pfs_start_rwlock_rdwait_v1(PSI_rwlock_locker_state *state, + PSI_rwlock *rwlock, + PSI_rwlock_operation op, + const char *src_file, uint src_line) +{ + DBUG_ASSERT((op == PSI_RWLOCK_READLOCK) || + (op == PSI_RWLOCK_TRYREADLOCK) || + (op == PSI_RWLOCK_SHAREDLOCK) || + (op == PSI_RWLOCK_TRYSHAREDLOCK)); + + return pfs_start_rwlock_wait_v1(state, rwlock, op, src_file, src_line); +} + +PSI_rwlock_locker* +pfs_start_rwlock_wrwait_v1(PSI_rwlock_locker_state *state, + PSI_rwlock *rwlock, + PSI_rwlock_operation op, + const char *src_file, uint src_line) +{ + DBUG_ASSERT((op == PSI_RWLOCK_WRITELOCK) || + (op == PSI_RWLOCK_TRYWRITELOCK) || + (op == PSI_RWLOCK_SHAREDEXCLUSIVELOCK) || + (op == PSI_RWLOCK_TRYSHAREDEXCLUSIVELOCK) || + (op == PSI_RWLOCK_EXCLUSIVELOCK) || + (op == PSI_RWLOCK_TRYEXCLUSIVELOCK)); + + return pfs_start_rwlock_wait_v1(state, rwlock, op, src_file, src_line); +} + /** Implementation of the cond instrumentation interface. @sa PSI_v1::start_cond_wait. */ -static PSI_cond_locker* -start_cond_wait_v1(PSI_cond_locker_state *state, - PSI_cond *cond, PSI_mutex *mutex, - PSI_cond_operation op, - const char *src_file, uint src_line) +PSI_cond_locker* +pfs_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: @@ -2433,7 +2872,7 @@ start_cond_wait_v1(PSI_cond_locker_state *state, if (flag_thread_instrumentation) { - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); if (unlikely(pfs_thread == NULL)) return NULL; if (! pfs_thread->m_enabled) @@ -2465,7 +2904,7 @@ start_cond_wait_v1(PSI_cond_locker_state *state, 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_thread_internal_id= pfs_thread->m_thread_internal_id; wait->m_class= pfs_cond->m_class; wait->m_timer_start= timer_start; wait->m_timer_end= 0; @@ -2523,8 +2962,6 @@ static inline PFS_TL_LOCK_TYPE lock_flags_to_lock_type(uint flags) 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: @@ -2553,12 +2990,12 @@ static inline PFS_TL_LOCK_TYPE external_lock_flags_to_lock_type(uint flags) Implementation of the table instrumentation interface. @sa PSI_v1::start_table_io_wait_v1 */ -static PSI_table_locker* -start_table_io_wait_v1(PSI_table_locker_state *state, - PSI_table *table, - PSI_table_io_operation op, - uint index, - const char *src_file, uint src_line) +PSI_table_locker* +pfs_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)); @@ -2570,7 +3007,7 @@ start_table_io_wait_v1(PSI_table_locker_state *state, if (! pfs_table->m_io_enabled) return NULL; - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); uint flags; ulonglong timer_start= 0; @@ -2609,7 +3046,7 @@ start_table_io_wait_v1(PSI_table_locker_state *state, 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_thread_internal_id= pfs_thread->m_thread_internal_id; wait->m_class= &global_table_io_class; wait->m_timer_start= timer_start; wait->m_timer_end= 0; @@ -2655,12 +3092,12 @@ start_table_io_wait_v1(PSI_table_locker_state *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) +PSI_table_locker* +pfs_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)); @@ -2673,7 +3110,7 @@ start_table_lock_wait_v1(PSI_table_locker_state *state, if (! pfs_table->m_lock_enabled) return NULL; - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); PFS_TL_LOCK_TYPE lock_type; @@ -2681,6 +3118,7 @@ start_table_lock_wait_v1(PSI_table_locker_state *state, { case PSI_TABLE_LOCK: lock_type= lock_flags_to_lock_type(op_flags); + pfs_table->m_internal_lock= lock_type; break; case PSI_TABLE_EXTERNAL_LOCK: /* @@ -2688,8 +3126,12 @@ start_table_lock_wait_v1(PSI_table_locker_state *state, there is no handler::external_unlock(). */ if (op_flags == F_UNLCK) + { + pfs_table->m_external_lock= PFS_TL_NONE; return NULL; + } lock_type= external_lock_flags_to_lock_type(op_flags); + pfs_table->m_external_lock= lock_type; break; default: lock_type= PFS_TL_READ; @@ -2735,7 +3177,7 @@ start_table_lock_wait_v1(PSI_table_locker_state *state, 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_thread_internal_id= pfs_thread->m_thread_internal_id; wait->m_class= &global_table_lock_class; wait->m_timer_start= timer_start; wait->m_timer_end= 0; @@ -2780,11 +3222,11 @@ start_table_lock_wait_v1(PSI_table_locker_state *state, Implementation of the file instrumentation interface. @sa PSI_v1::get_thread_file_name_locker. */ -static PSI_file_locker* -get_thread_file_name_locker_v1(PSI_file_locker_state *state, - PSI_file_key key, - PSI_file_operation op, - const char *name, const void *identity) +PSI_file_locker* +pfs_get_thread_file_name_locker_v1(PSI_file_locker_state *state, + PSI_file_key key, + PSI_file_operation op, + const char *name, const void *identity) { DBUG_ASSERT(static_cast<int> (op) >= 0); DBUG_ASSERT(static_cast<uint> (op) < array_elements(file_operation_map)); @@ -2799,7 +3241,7 @@ get_thread_file_name_locker_v1(PSI_file_locker_state *state, return NULL; /* Needed for the LF_HASH */ - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); if (unlikely(pfs_thread == NULL)) return NULL; @@ -2831,7 +3273,7 @@ get_thread_file_name_locker_v1(PSI_file_locker_state *state, 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_thread_internal_id= pfs_thread->m_thread_internal_id; wait->m_class= klass; wait->m_timer_start= 0; wait->m_timer_end= 0; @@ -2858,9 +3300,9 @@ get_thread_file_name_locker_v1(PSI_file_locker_state *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) +PSI_file_locker* +pfs_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); @@ -2875,16 +3317,20 @@ get_thread_file_stream_locker_v1(PSI_file_locker_state *state, if (! pfs_file->m_enabled) return NULL; + /* Needed for the LF_HASH */ + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); + if (unlikely(pfs_thread == NULL)) + return NULL; + uint flags; + /* Always populated */ + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + 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) @@ -2907,7 +3353,7 @@ get_thread_file_stream_locker_v1(PSI_file_locker_state *state, 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_thread_internal_id= pfs_thread->m_thread_internal_id; wait->m_class= klass; wait->m_timer_start= 0; wait->m_timer_end= 0; @@ -2924,7 +3370,6 @@ get_thread_file_stream_locker_v1(PSI_file_locker_state *state, } else { - state->m_thread= NULL; if (pfs_file->m_timed) { flags= STATE_FLAG_TIMED; @@ -2948,9 +3393,9 @@ get_thread_file_stream_locker_v1(PSI_file_locker_state *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) +PSI_file_locker* +pfs_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); @@ -2981,16 +3426,20 @@ get_thread_file_descriptor_locker_v1(PSI_file_locker_state *state, DBUG_ASSERT(pfs_file->m_class != NULL); PFS_file_class *klass= pfs_file->m_class; + /* Needed for the LF_HASH */ + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); + if (unlikely(pfs_thread == NULL)) + return NULL; + uint flags; + /* Always populated */ + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + 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) @@ -3013,7 +3462,7 @@ get_thread_file_descriptor_locker_v1(PSI_file_locker_state *state, 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_thread_internal_id= pfs_thread->m_thread_internal_id; wait->m_class= klass; wait->m_timer_start= 0; wait->m_timer_end= 0; @@ -3030,7 +3479,6 @@ get_thread_file_descriptor_locker_v1(PSI_file_locker_state *state, } else { - state->m_thread= NULL; if (pfs_file->m_timed) { flags= STATE_FLAG_TIMED; @@ -3052,12 +3500,12 @@ get_thread_file_descriptor_locker_v1(PSI_file_locker_state *state, /** Socket locker */ -static PSI_socket_locker* -start_socket_wait_v1(PSI_socket_locker_state *state, - PSI_socket *socket, - PSI_socket_operation op, - size_t count, - const char *src_file, uint src_line) +PSI_socket_locker* +pfs_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)); @@ -3080,7 +3528,7 @@ start_socket_wait_v1(PSI_socket_locker_state *state, 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); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); if (unlikely(pfs_thread == NULL)) return NULL; @@ -3114,7 +3562,7 @@ start_socket_wait_v1(PSI_socket_locker_state *state, 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_thread_internal_id= pfs_thread->m_thread_internal_id; wait->m_class= pfs_socket->m_class; wait->m_timer_start= timer_start; wait->m_timer_end= 0; @@ -3177,7 +3625,7 @@ start_socket_wait_v1(PSI_socket_locker_state *state, Implementation of the mutex instrumentation interface. @sa PSI_v1::unlock_mutex. */ -static void unlock_mutex_v1(PSI_mutex *mutex) +void pfs_unlock_mutex_v1(PSI_mutex *mutex) { PFS_mutex *pfs_mutex= reinterpret_cast<PFS_mutex*> (mutex); @@ -3214,7 +3662,7 @@ static void unlock_mutex_v1(PSI_mutex *mutex) Implementation of the rwlock instrumentation interface. @sa PSI_v1::unlock_rwlock. */ -static void unlock_rwlock_v1(PSI_rwlock *rwlock) +void pfs_unlock_rwlock_v1(PSI_rwlock *rwlock) { PFS_rwlock *pfs_rwlock= reinterpret_cast<PFS_rwlock*> (rwlock); DBUG_ASSERT(pfs_rwlock != NULL); @@ -3292,34 +3740,38 @@ static void unlock_rwlock_v1(PSI_rwlock *rwlock) Implementation of the cond instrumentation interface. @sa PSI_v1::signal_cond. */ -static void signal_cond_v1(PSI_cond* cond) +void pfs_signal_cond_v1(PSI_cond* cond) { +#ifdef PFS_LATER PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond); DBUG_ASSERT(pfs_cond != NULL); pfs_cond->m_cond_stat.m_signal_count++; +#endif } /** Implementation of the cond instrumentation interface. @sa PSI_v1::broadcast_cond. */ -static void broadcast_cond_v1(PSI_cond* cond) +void pfs_broadcast_cond_v1(PSI_cond* cond) { +#ifdef PFS_LATER PFS_cond *pfs_cond= reinterpret_cast<PFS_cond*> (cond); DBUG_ASSERT(pfs_cond != NULL); pfs_cond->m_cond_stat.m_broadcast_count++; +#endif } /** 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) +PSI_idle_locker* +pfs_start_idle_wait_v1(PSI_idle_locker_state* state, const char *src_file, uint src_line) { DBUG_ASSERT(state != NULL); @@ -3334,7 +3786,7 @@ start_idle_wait_v1(PSI_idle_locker_state* state, const char *src_file, uint src_ if (flag_thread_instrumentation) { - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); if (unlikely(pfs_thread == NULL)) return NULL; if (!pfs_thread->m_enabled) @@ -3372,7 +3824,7 @@ start_idle_wait_v1(PSI_idle_locker_state* state, const char *src_file, uint src_ wait->m_nesting_event_id= 0; /* no need to set wait->m_nesting_event_type */ - wait->m_thread= pfs_thread; + wait->m_thread_internal_id= pfs_thread->m_thread_internal_id; wait->m_class= &global_idle_class; wait->m_timer_start= timer_start; wait->m_timer_end= 0; @@ -3404,7 +3856,7 @@ start_idle_wait_v1(PSI_idle_locker_state* state, const char *src_file, uint src_ Implementation of the mutex instrumentation interface. @sa PSI_v1::end_idle_wait. */ -static void end_idle_wait_v1(PSI_idle_locker* locker) +void pfs_end_idle_wait_v1(PSI_idle_locker* locker) { PSI_idle_locker_state *state= reinterpret_cast<PSI_idle_locker_state*> (locker); DBUG_ASSERT(state != NULL); @@ -3423,7 +3875,7 @@ static void end_idle_wait_v1(PSI_idle_locker* locker) { 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; + event_name_array= thread->write_instr_class_waits_stats(); if (flags & STATE_FLAG_TIMED) { @@ -3443,9 +3895,9 @@ static void end_idle_wait_v1(PSI_idle_locker* locker) wait->m_timer_end= timer_end; wait->m_end_event_id= thread->m_event_id; - if (flag_events_waits_history) + if (thread->m_flag_events_waits_history) insert_events_waits_history(thread, wait); - if (flag_events_waits_history_long) + if (thread->m_flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; @@ -3469,7 +3921,7 @@ static void end_idle_wait_v1(PSI_idle_locker* locker) Implementation of the mutex instrumentation interface. @sa PSI_v1::end_mutex_wait. */ -static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc) +void pfs_end_mutex_wait_v1(PSI_mutex_locker* locker, int rc) { PSI_mutex_locker_state *state= reinterpret_cast<PSI_mutex_locker_state*> (locker); DBUG_ASSERT(state != NULL); @@ -3505,9 +3957,12 @@ static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc) if (flags & STATE_FLAG_THREAD) { PFS_single_stat *event_name_array; - event_name_array= thread->m_instr_class_waits_stats; + event_name_array= thread->write_instr_class_waits_stats(); uint index= mutex->m_class->m_event_name_index; + DBUG_ASSERT(index <= wait_class_max); + DBUG_ASSERT(sanitize_thread(thread) != NULL); + if (flags & STATE_FLAG_TIMED) { /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */ @@ -3526,9 +3981,9 @@ static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc) wait->m_timer_end= timer_end; wait->m_end_event_id= thread->m_event_id; - if (flag_events_waits_history) + if (thread->m_flag_events_waits_history) insert_events_waits_history(thread, wait); - if (flag_events_waits_history_long) + if (thread->m_flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; @@ -3541,7 +3996,7 @@ static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc) Implementation of the rwlock instrumentation interface. @sa PSI_v1::end_rwlock_rdwait. */ -static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc) +void pfs_end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc) { PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker); DBUG_ASSERT(state != NULL); @@ -3586,7 +4041,7 @@ static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc) DBUG_ASSERT(thread != NULL); PFS_single_stat *event_name_array; - event_name_array= thread->m_instr_class_waits_stats; + event_name_array= thread->write_instr_class_waits_stats(); uint index= rwlock->m_class->m_event_name_index; if (state->m_flags & STATE_FLAG_TIMED) @@ -3607,9 +4062,9 @@ static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc) wait->m_timer_end= timer_end; wait->m_end_event_id= thread->m_event_id; - if (flag_events_waits_history) + if (thread->m_flag_events_waits_history) insert_events_waits_history(thread, wait); - if (flag_events_waits_history_long) + if (thread->m_flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; @@ -3622,7 +4077,7 @@ static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc) Implementation of the rwlock instrumentation interface. @sa PSI_v1::end_rwlock_wrwait. */ -static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc) +void pfs_end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc) { PSI_rwlock_locker_state *state= reinterpret_cast<PSI_rwlock_locker_state*> (locker); DBUG_ASSERT(state != NULL); @@ -3652,15 +4107,20 @@ static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc) /* Thread safe : we are protected by the instrumented rwlock */ rwlock->m_writer= thread; rwlock->m_last_written= timer_end; - /* Reset the readers stats, they could be off */ - rwlock->m_readers= 0; - rwlock->m_last_read= 0; + + if ((state->m_operation != PSI_RWLOCK_SHAREDEXCLUSIVELOCK) && + (state->m_operation != PSI_RWLOCK_TRYSHAREDEXCLUSIVELOCK)) + { + /* Reset the readers stats, they could be off */ + rwlock->m_readers= 0; + rwlock->m_last_read= 0; + } } if (state->m_flags & STATE_FLAG_THREAD) { PFS_single_stat *event_name_array; - event_name_array= thread->m_instr_class_waits_stats; + event_name_array= thread->write_instr_class_waits_stats(); uint index= rwlock->m_class->m_event_name_index; if (state->m_flags & STATE_FLAG_TIMED) @@ -3681,9 +4141,9 @@ static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc) wait->m_timer_end= timer_end; wait->m_end_event_id= thread->m_event_id; - if (flag_events_waits_history) + if (thread->m_flag_events_waits_history) insert_events_waits_history(thread, wait); - if (flag_events_waits_history_long) + if (thread->m_flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; @@ -3696,7 +4156,7 @@ static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc) Implementation of the cond instrumentation interface. @sa PSI_v1::end_cond_wait. */ -static void end_cond_wait_v1(PSI_cond_locker* locker, int rc) +void pfs_end_cond_wait_v1(PSI_cond_locker* locker, int rc) { PSI_cond_locker_state *state= reinterpret_cast<PSI_cond_locker_state*> (locker); DBUG_ASSERT(state != NULL); @@ -3726,7 +4186,7 @@ static void end_cond_wait_v1(PSI_cond_locker* locker, int rc) DBUG_ASSERT(thread != NULL); PFS_single_stat *event_name_array; - event_name_array= thread->m_instr_class_waits_stats; + event_name_array= thread->write_instr_class_waits_stats(); uint index= cond->m_class->m_event_name_index; if (state->m_flags & STATE_FLAG_TIMED) @@ -3747,9 +4207,9 @@ static void end_cond_wait_v1(PSI_cond_locker* locker, int rc) wait->m_timer_end= timer_end; wait->m_end_event_id= thread->m_event_id; - if (flag_events_waits_history) + if (thread->m_flag_events_waits_history) insert_events_waits_history(thread, wait); - if (flag_events_waits_history_long) + if (thread->m_flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; @@ -3762,7 +4222,7 @@ 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) +void pfs_end_table_io_wait_v1(PSI_table_locker* locker, ulonglong numrows) { PSI_table_locker_state *state= reinterpret_cast<PSI_table_locker_state*> (locker); DBUG_ASSERT(state != NULL); @@ -3808,11 +4268,11 @@ static void end_table_io_wait_v1(PSI_table_locker* locker) { timer_end= state->m_timer(); wait_time= timer_end - state->m_timer_start; - stat->aggregate_value(wait_time); + stat->aggregate_many_value(wait_time, numrows); } else { - stat->aggregate_counted(); + stat->aggregate_counted(numrows); } if (flags & STATE_FLAG_THREAD) @@ -3821,7 +4281,7 @@ static void end_table_io_wait_v1(PSI_table_locker* locker) DBUG_ASSERT(thread != NULL); PFS_single_stat *event_name_array; - event_name_array= thread->m_instr_class_waits_stats; + event_name_array= thread->write_instr_class_waits_stats(); /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME @@ -3829,11 +4289,11 @@ static void end_table_io_wait_v1(PSI_table_locker* locker) */ if (flags & STATE_FLAG_TIMED) { - event_name_array[GLOBAL_TABLE_IO_EVENT_INDEX].aggregate_value(wait_time); + event_name_array[GLOBAL_TABLE_IO_EVENT_INDEX].aggregate_many_value(wait_time, numrows); } else { - event_name_array[GLOBAL_TABLE_IO_EVENT_INDEX].aggregate_counted(); + event_name_array[GLOBAL_TABLE_IO_EVENT_INDEX].aggregate_counted(numrows); } if (flags & STATE_FLAG_EVENT) @@ -3843,9 +4303,10 @@ static void end_table_io_wait_v1(PSI_table_locker* locker) wait->m_timer_end= timer_end; wait->m_end_event_id= thread->m_event_id; - if (flag_events_waits_history) + wait->m_number_of_bytes= static_cast<size_t>(numrows); + if (thread->m_flag_events_waits_history) insert_events_waits_history(thread, wait); - if (flag_events_waits_history_long) + if (thread->m_flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; @@ -3860,7 +4321,7 @@ static void end_table_io_wait_v1(PSI_table_locker* locker) Implementation of the table instrumentation interface. @sa PSI_v1::end_table_lock_wait. */ -static void end_table_lock_wait_v1(PSI_table_locker* locker) +void pfs_end_table_lock_wait_v1(PSI_table_locker* locker) { PSI_table_locker_state *state= reinterpret_cast<PSI_table_locker_state*> (locker); DBUG_ASSERT(state != NULL); @@ -3892,7 +4353,7 @@ static void end_table_lock_wait_v1(PSI_table_locker* locker) DBUG_ASSERT(thread != NULL); PFS_single_stat *event_name_array; - event_name_array= thread->m_instr_class_waits_stats; + event_name_array= thread->write_instr_class_waits_stats(); /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME @@ -3914,9 +4375,9 @@ static void end_table_lock_wait_v1(PSI_table_locker* locker) wait->m_timer_end= timer_end; wait->m_end_event_id= thread->m_event_id; - if (flag_events_waits_history) + if (thread->m_flag_events_waits_history) insert_events_waits_history(thread, wait); - if (flag_events_waits_history_long) + if (thread->m_flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; @@ -3927,23 +4388,23 @@ static void end_table_lock_wait_v1(PSI_table_locker* locker) table->m_has_lock_stats= true; } -static void start_file_wait_v1(PSI_file_locker *locker, - size_t count, - const char *src_file, - uint src_line); +void pfs_start_file_wait_v1(PSI_file_locker *locker, + size_t count, + const char *src_file, + uint src_line); -static void end_file_wait_v1(PSI_file_locker *locker, - size_t count); +void pfs_end_file_wait_v1(PSI_file_locker *locker, + size_t count); /** Implementation of the file instrumentation interface. @sa PSI_v1::start_file_open_wait. */ -static void start_file_open_wait_v1(PSI_file_locker *locker, - const char *src_file, - uint src_line) +void pfs_start_file_open_wait_v1(PSI_file_locker *locker, + const char *src_file, + uint src_line) { - start_file_wait_v1(locker, 0, src_file, src_line); + pfs_start_file_wait_v1(locker, 0, src_file, src_line); return; } @@ -3952,8 +4413,9 @@ static void start_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* +pfs_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); @@ -3981,7 +4443,7 @@ static PSI_file* end_file_open_wait_v1(PSI_file_locker *locker, break; } - end_file_wait_v1(locker, 0); + pfs_end_file_wait_v1(locker, 0); return state->m_file; } @@ -3990,7 +4452,7 @@ static PSI_file* end_file_open_wait_v1(PSI_file_locker *locker, 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 +void pfs_end_file_open_wait_and_bind_to_descriptor_v1 (PSI_file_locker *locker, File file) { PFS_file *pfs_file= NULL; @@ -4008,7 +4470,7 @@ static void end_file_open_wait_and_bind_to_descriptor_v1 state->m_file= reinterpret_cast<PSI_file*> (pfs_file); } - end_file_wait_v1(locker, 0); + pfs_end_file_wait_v1(locker, 0); if (likely(index >= 0)) { @@ -4025,12 +4487,35 @@ static void end_file_open_wait_and_bind_to_descriptor_v1 /** Implementation of the file instrumentation interface. + @sa PSI_v1::end_temp_file_open_wait_and_bind_to_descriptor. +*/ +void pfs_end_temp_file_open_wait_and_bind_to_descriptor_v1 + (PSI_file_locker *locker, File file, const char *filename) +{ + DBUG_ASSERT(filename != NULL); + PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + /* Set filename that was generated during creation of temporary file. */ + state->m_name= filename; + pfs_end_file_open_wait_and_bind_to_descriptor_v1(locker, file); + + PFS_file *pfs_file= reinterpret_cast<PFS_file *> (state->m_file); + if (pfs_file != NULL) + { + pfs_file->m_temporary= true; + } +} + + +/** + 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) +void pfs_start_file_wait_v1(PSI_file_locker *locker, + size_t count, + const char *src_file, + uint src_line) { ulonglong timer_start= 0; PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker); @@ -4060,8 +4545,8 @@ static void start_file_wait_v1(PSI_file_locker *locker, Implementation of the file instrumentation interface. @sa PSI_v1::end_file_wait. */ -static void end_file_wait_v1(PSI_file_locker *locker, - size_t byte_count) +void pfs_end_file_wait_v1(PSI_file_locker *locker, + size_t byte_count) { PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker); DBUG_ASSERT(state != NULL); @@ -4139,7 +4624,7 @@ static void end_file_wait_v1(PSI_file_locker *locker, DBUG_ASSERT(thread != NULL); PFS_single_stat *event_name_array; - event_name_array= thread->m_instr_class_waits_stats; + event_name_array= thread->write_instr_class_waits_stats(); uint index= klass->m_event_name_index; if (flags & STATE_FLAG_TIMED) @@ -4165,9 +4650,9 @@ static void end_file_wait_v1(PSI_file_locker *locker, wait->m_weak_file= file; wait->m_weak_version= (file ? file->get_version() : 0); - if (flag_events_waits_history) + if (thread->m_flag_events_waits_history) insert_events_waits_history(thread, wait); - if (flag_events_waits_history_long) + if (thread->m_flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; @@ -4180,9 +4665,9 @@ static void end_file_wait_v1(PSI_file_locker *locker, 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) +void pfs_start_file_close_wait_v1(PSI_file_locker *locker, + const char *src_file, + uint src_line) { PFS_thread *thread; const char *name; @@ -4208,7 +4693,7 @@ static void start_file_close_wait_v1(PSI_file_locker *locker, break; } - start_file_wait_v1(locker, 0, src_file, src_line); + pfs_start_file_wait_v1(locker, 0, src_file, src_line); return; } @@ -4217,12 +4702,12 @@ static void start_file_close_wait_v1(PSI_file_locker *locker, 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) +void pfs_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); + pfs_end_file_wait_v1(locker, 0); if (rc == 0) { @@ -4233,6 +4718,17 @@ static void end_file_close_wait_v1(PSI_file_locker *locker, int rc) switch(state->m_operation) { case PSI_FILE_CLOSE: + if (file != NULL) + { + if (file->m_temporary) + { + DBUG_ASSERT(file->m_file_stat.m_open_count <= 1); + destroy_file(thread, file); + } + else + release_file(file); + } + break; case PSI_FILE_STREAM_CLOSE: if (file != NULL) release_file(file); @@ -4249,22 +4745,50 @@ static void end_file_close_wait_v1(PSI_file_locker *locker, int rc) return; } -static void start_stage_v1(PSI_stage_key key, const char *src_file, int src_line) +/** + Implementation of the file instrumentation interface. + @sa PSI_v1::end_file_rename_wait. +*/ +void pfs_end_file_rename_wait_v1(PSI_file_locker *locker, const char *old_name, + const char *new_name, int rc) +{ + PSI_file_locker_state *state= reinterpret_cast<PSI_file_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + DBUG_ASSERT(state->m_operation == PSI_FILE_RENAME); + + if (rc == 0) + { + PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread); + + uint old_len= (uint)strlen(old_name); + uint new_len= (uint)strlen(new_name); + + find_and_rename_file(thread, old_name, old_len, new_name, new_len); + } + + pfs_end_file_wait_v1(locker, 0); + return; +} + +PSI_stage_progress* +pfs_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); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); if (unlikely(pfs_thread == NULL)) - return; + return NULL; /* Always update column threads.processlist_state. */ pfs_thread->m_stage= key; + /* Default value when the stage is not instrumented for progress */ + pfs_thread->m_stage_progress= NULL; if (psi_unlikely(! flag_global_instrumentation)) - return; + return NULL; if (flag_thread_instrumentation && ! pfs_thread->m_enabled) - return; + return NULL; PFS_events_stages *pfs= & pfs_thread->m_stage_current; PFS_events_waits *child_wait= & pfs_thread->m_events_waits_stack[0]; @@ -4274,7 +4798,7 @@ static void start_stage_v1(PSI_stage_key key, const char *src_file, int src_line if (old_class != NULL) { PFS_stage_stat *event_name_array; - event_name_array= pfs_thread->m_instr_class_stages_stats; + event_name_array= pfs_thread->write_instr_class_stages_stats(); uint index= old_class->m_event_name_index; /* Finish old event */ @@ -4296,9 +4820,9 @@ static void start_stage_v1(PSI_stage_key key, const char *src_file, int src_line if (flag_events_stages_current) { pfs->m_end_event_id= pfs_thread->m_event_id; - if (flag_events_stages_history) + if (pfs_thread->m_flag_events_stages_history) insert_events_stages_history(pfs_thread, pfs); - if (flag_events_stages_history_long) + if (pfs_thread->m_flag_events_stages_history_long) insert_events_stages_history_long(pfs); } @@ -4315,10 +4839,10 @@ static void start_stage_v1(PSI_stage_key key, const char *src_file, int src_line PFS_stage_class *new_klass= find_stage_class(key); if (unlikely(new_klass == NULL)) - return; + return NULL; if (! new_klass->m_enabled) - return; + return NULL; pfs->m_class= new_klass; if (new_klass->m_timed) @@ -4337,8 +4861,7 @@ static void start_stage_v1(PSI_stage_key key, const char *src_file, int src_line 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_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; @@ -4348,17 +4871,37 @@ static void start_stage_v1(PSI_stage_key key, const char *src_file, int src_line child_wait->m_event_id= pfs->m_event_id; child_wait->m_event_type= EVENT_TYPE_STAGE; } + + if (new_klass->is_progress()) + { + pfs_thread->m_stage_progress= & pfs->m_progress; + pfs->m_progress.m_work_completed= 0; + pfs->m_progress.m_work_estimated= 0; + } + + return pfs_thread->m_stage_progress; } -static void end_stage_v1() +PSI_stage_progress* +pfs_get_current_stage_progress_v1() +{ + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); + if (unlikely(pfs_thread == NULL)) + return NULL; + + return pfs_thread->m_stage_progress; +} + +void pfs_end_stage_v1() { ulonglong timer_value= 0; - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); if (unlikely(pfs_thread == NULL)) return; pfs_thread->m_stage= 0; + pfs_thread->m_stage_progress= NULL; if (psi_unlikely(! flag_global_instrumentation)) return; @@ -4372,7 +4915,7 @@ static void end_stage_v1() if (old_class != NULL) { PFS_stage_stat *event_name_array; - event_name_array= pfs_thread->m_instr_class_stages_stats; + event_name_array= pfs_thread->write_instr_class_stages_stats(); uint index= old_class->m_event_name_index; /* Finish old event */ @@ -4394,9 +4937,9 @@ static void end_stage_v1() if (flag_events_stages_current) { pfs->m_end_event_id= pfs_thread->m_event_id; - if (flag_events_stages_history) + if (pfs_thread->m_flag_events_stages_history) insert_events_stages_history(pfs_thread, pfs); - if (flag_events_stages_history_long) + if (pfs_thread->m_flag_events_stages_history_long) insert_events_stages_history_long(pfs); } @@ -4411,10 +4954,10 @@ static void end_stage_v1() } } -static PSI_statement_locker* -get_thread_statement_locker_v1(PSI_statement_locker_state *state, - PSI_statement_key key, - const void *charset) +PSI_statement_locker* +pfs_get_thread_statement_locker_v1(PSI_statement_locker_state *state, + PSI_statement_key key, + const void *charset, PSI_sp_share *sp_share) { DBUG_ASSERT(state != NULL); DBUG_ASSERT(charset != NULL); @@ -4431,7 +4974,7 @@ get_thread_statement_locker_v1(PSI_statement_locker_state *state, if (flag_thread_instrumentation) { - PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); if (unlikely(pfs_thread == NULL)) return NULL; if (! pfs_thread->m_enabled) @@ -4448,14 +4991,16 @@ get_thread_statement_locker_v1(PSI_statement_locker_state *state, if (pfs_thread->m_events_statements_count >= statement_stack_max) { + nested_statement_lost++; return NULL; } - pfs_thread->m_stmt_lock.allocated_to_dirty(); + pfs_dirty_state dirty_state; + pfs_thread->m_stmt_lock.allocated_to_dirty(& dirty_state); 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_thread_internal_id= pfs_thread->m_thread_internal_id; pfs->m_event_id= event_id; + pfs->m_event_type= EVENT_TYPE_STATEMENT; pfs->m_end_event_id= 0; pfs->m_class= klass; pfs->m_timer_start= 0; @@ -4497,18 +5042,68 @@ get_thread_statement_locker_v1(PSI_statement_locker_state *state, /* 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; + child_wait->m_event_id= event_id; + child_wait->m_event_type= EVENT_TYPE_STATEMENT; + + PFS_events_statements *parent_statement= NULL; + PFS_events_transactions *parent_transaction= &pfs_thread->m_transaction_current; + ulonglong parent_event= 0; + enum_event_type parent_type= EVENT_TYPE_STATEMENT; + uint parent_level= 0; + + if (pfs_thread->m_events_statements_count > 0) + { + parent_statement= pfs - 1; + parent_event= parent_statement->m_event_id; + parent_type= parent_statement->m_event_type; + parent_level= parent_statement->m_nesting_event_level + 1; + } + + if (parent_transaction->m_state == TRANS_STATE_ACTIVE && + parent_transaction->m_event_id > parent_event) + { + parent_event= parent_transaction->m_event_id; + parent_type= parent_transaction->m_event_type; + } + + pfs->m_nesting_event_id= parent_event; + pfs->m_nesting_event_type= parent_type; + pfs->m_nesting_event_level= parent_level; + + /* Set parent Stored Procedure information for this statement. */ + if(sp_share) + { + PFS_program *parent_sp= reinterpret_cast<PFS_program*>(sp_share); + pfs->m_sp_type= parent_sp->m_type; + memcpy(pfs->m_schema_name, parent_sp->m_schema_name, + parent_sp->m_schema_name_length); + pfs->m_schema_name_length= parent_sp->m_schema_name_length; + memcpy(pfs->m_object_name, parent_sp->m_object_name, + parent_sp->m_object_name_length); + pfs->m_object_name_length= parent_sp->m_object_name_length; + } + else + { + pfs->m_sp_type= NO_OBJECT_TYPE; + pfs->m_schema_name_length= 0; + pfs->m_object_name_length= 0; + } state->m_statement= pfs; flags|= STATE_FLAG_EVENT; pfs_thread->m_events_statements_count++; - pfs_thread->m_stmt_lock.dirty_to_allocated(); + pfs_thread->m_stmt_lock.dirty_to_allocated(& dirty_state); + } + else + { + state->m_statement= NULL; } } else { + state->m_statement= NULL; + if (klass->m_timed) flags= STATE_FLAG_TIMED; else @@ -4542,16 +5137,18 @@ get_thread_statement_locker_v1(PSI_statement_locker_state *state, state->m_no_good_index_used= 0; state->m_digest= NULL; + state->m_cs_number= ((CHARSET_INFO *)charset)->number; state->m_schema_name_length= 0; - state->m_cs_number= ((CHARSET_INFO *)charset)->number; + state->m_parent_sp_share= sp_share; + state->m_parent_prepared_stmt= NULL; 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* +pfs_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) @@ -4597,9 +5194,9 @@ refine_statement_v1(PSI_statement_locker *locker, 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) +void pfs_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); @@ -4636,8 +5233,8 @@ static void start_statement_v1(PSI_statement_locker *locker, } } -static void set_statement_text_v1(PSI_statement_locker *locker, - const char *text, uint text_len) +void pfs_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); @@ -4649,9 +5246,9 @@ static void set_statement_text_v1(PSI_statement_locker *locker, { PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement); DBUG_ASSERT(pfs != NULL); - if (text_len > sizeof (pfs->m_sqltext)) + if (text_len > pfs_max_sqltext) { - text_len= sizeof(pfs->m_sqltext); + text_len= (uint)pfs_max_sqltext; pfs->m_sqltext_truncated= true; } if (text_len) @@ -4697,101 +5294,101 @@ static void set_statement_text_v1(PSI_statement_locker *locker, } \ return; -static void set_statement_lock_time_v1(PSI_statement_locker *locker, - ulonglong count) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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) +void pfs_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); @@ -4823,12 +5420,14 @@ static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) */ const sql_digest_storage *digest_storage= NULL; PFS_statement_stat *digest_stat= NULL; + PFS_program *pfs_program= NULL; + PFS_prepared_stmt *pfs_prepared_stmt= 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; + event_name_array= thread->write_instr_class_statements_stats(); /* Aggregate to EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME */ stat= & event_name_array[index]; @@ -4850,7 +5449,8 @@ static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) PFS_events_statements *pfs= reinterpret_cast<PFS_events_statements*> (state->m_statement); DBUG_ASSERT(pfs != NULL); - thread->m_stmt_lock.allocated_to_dirty(); + pfs_dirty_state dirty_state; + thread->m_stmt_lock.allocated_to_dirty(& dirty_state); switch(da->status()) { @@ -4858,7 +5458,8 @@ static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) case Diagnostics_area::DA_EMPTY: break; case Diagnostics_area::DA_OK: - memcpy(pfs->m_message_text, da->message(), MYSQL_ERRMSG_SIZE); + 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(); @@ -4868,11 +5469,12 @@ static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) pfs->m_warning_count= da->statement_warn_count(); break; case Diagnostics_area::DA_ERROR: - memcpy(pfs->m_message_text, da->message(), MYSQL_ERRMSG_SIZE); + 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); + pfs->m_error_count++; break; case Diagnostics_area::DA_DISABLED: break; @@ -4892,21 +5494,24 @@ static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) pfs->m_digest_storage.copy(digest_storage); } - if (flag_events_statements_history) + pfs_program= reinterpret_cast<PFS_program*>(state->m_parent_sp_share); + pfs_prepared_stmt= reinterpret_cast<PFS_prepared_stmt*>(state->m_parent_prepared_stmt); + + if (thread->m_flag_events_statements_history) insert_events_statements_history(thread, pfs); - if (flag_events_statements_history_long) + if (thread->m_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(); + thread->m_stmt_lock.dirty_to_allocated(& dirty_state); } } else { if (flags & STATE_FLAG_DIGEST) { - PFS_thread *thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); + PFS_thread *thread= my_thread_get_THR_PFS(); /* An instrumented thread is required, for LF_PINS. */ if (thread != NULL) @@ -4929,6 +5534,8 @@ static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) stat= & event_name_array[index]; } + stat->mark_used(); + if (flags & STATE_FLAG_TIMED) { /* Aggregate to EVENTS_STATEMENTS_SUMMARY_..._BY_EVENT_NAME (timed) */ @@ -4959,6 +5566,8 @@ static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) if (digest_stat != NULL) { + digest_stat->mark_used(); + if (flags & STATE_FLAG_TIMED) { digest_stat->aggregate_value(wait_time); @@ -4986,6 +5595,103 @@ static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) digest_stat->m_no_good_index_used+= state->m_no_good_index_used; } + if(pfs_program != NULL) + { + PFS_statement_stat *sub_stmt_stat= NULL; + sub_stmt_stat= &pfs_program->m_stmt_stat; + if(sub_stmt_stat != NULL) + { + sub_stmt_stat->mark_used(); + + if (flags & STATE_FLAG_TIMED) + { + sub_stmt_stat->aggregate_value(wait_time); + } + else + { + sub_stmt_stat->aggregate_counted(); + } + + sub_stmt_stat->m_lock_time+= state->m_lock_time; + sub_stmt_stat->m_rows_sent+= state->m_rows_sent; + sub_stmt_stat->m_rows_examined+= state->m_rows_examined; + sub_stmt_stat->m_created_tmp_disk_tables+= state->m_created_tmp_disk_tables; + sub_stmt_stat->m_created_tmp_tables+= state->m_created_tmp_tables; + sub_stmt_stat->m_select_full_join+= state->m_select_full_join; + sub_stmt_stat->m_select_full_range_join+= state->m_select_full_range_join; + sub_stmt_stat->m_select_range+= state->m_select_range; + sub_stmt_stat->m_select_range_check+= state->m_select_range_check; + sub_stmt_stat->m_select_scan+= state->m_select_scan; + sub_stmt_stat->m_sort_merge_passes+= state->m_sort_merge_passes; + sub_stmt_stat->m_sort_range+= state->m_sort_range; + sub_stmt_stat->m_sort_rows+= state->m_sort_rows; + sub_stmt_stat->m_sort_scan+= state->m_sort_scan; + sub_stmt_stat->m_no_index_used+= state->m_no_index_used; + sub_stmt_stat->m_no_good_index_used+= state->m_no_good_index_used; + } + } + + if (pfs_prepared_stmt != NULL) + { + if(state->m_in_prepare) + { + PFS_single_stat *prepared_stmt_stat= NULL; + prepared_stmt_stat= &pfs_prepared_stmt->m_prepare_stat; + if(prepared_stmt_stat != NULL) + { + if (flags & STATE_FLAG_TIMED) + { + prepared_stmt_stat->aggregate_value(wait_time); + } + else + { + prepared_stmt_stat->aggregate_counted(); + } + } + } + else + { + PFS_statement_stat *prepared_stmt_stat= NULL; + prepared_stmt_stat= &pfs_prepared_stmt->m_execute_stat; + if(prepared_stmt_stat != NULL) + { + if (flags & STATE_FLAG_TIMED) + { + prepared_stmt_stat->aggregate_value(wait_time); + } + else + { + prepared_stmt_stat->aggregate_counted(); + } + + prepared_stmt_stat->m_lock_time+= state->m_lock_time; + prepared_stmt_stat->m_rows_sent+= state->m_rows_sent; + prepared_stmt_stat->m_rows_examined+= state->m_rows_examined; + prepared_stmt_stat->m_created_tmp_disk_tables+= state->m_created_tmp_disk_tables; + prepared_stmt_stat->m_created_tmp_tables+= state->m_created_tmp_tables; + prepared_stmt_stat->m_select_full_join+= state->m_select_full_join; + prepared_stmt_stat->m_select_full_range_join+= state->m_select_full_range_join; + prepared_stmt_stat->m_select_range+= state->m_select_range; + prepared_stmt_stat->m_select_range_check+= state->m_select_range_check; + prepared_stmt_stat->m_select_scan+= state->m_select_scan; + prepared_stmt_stat->m_sort_merge_passes+= state->m_sort_merge_passes; + prepared_stmt_stat->m_sort_range+= state->m_sort_range; + prepared_stmt_stat->m_sort_rows+= state->m_sort_rows; + prepared_stmt_stat->m_sort_scan+= state->m_sort_scan; + prepared_stmt_stat->m_no_index_used+= state->m_no_index_used; + prepared_stmt_stat->m_no_good_index_used+= state->m_no_good_index_used; + } + } + } + + PFS_statement_stat *sub_stmt_stat= NULL; + if (pfs_program != NULL) + sub_stmt_stat= &pfs_program->m_stmt_stat; + + PFS_statement_stat *prepared_stmt_stat= NULL; + if (pfs_prepared_stmt != NULL && !state->m_in_prepare) + prepared_stmt_stat= &pfs_prepared_stmt->m_execute_stat; + switch (da->status()) { case Diagnostics_area::DA_OK_BULK: @@ -4999,6 +5705,16 @@ static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) digest_stat->m_rows_affected+= da->affected_rows(); digest_stat->m_warning_count+= da->statement_warn_count(); } + if(sub_stmt_stat != NULL) + { + sub_stmt_stat->m_rows_affected+= da->affected_rows(); + sub_stmt_stat->m_warning_count+= da->statement_warn_count(); + } + if (prepared_stmt_stat != NULL) + { + prepared_stmt_stat->m_rows_affected+= da->affected_rows(); + prepared_stmt_stat->m_warning_count+= da->statement_warn_count(); + } break; case Diagnostics_area::DA_EOF: stat->m_warning_count+= da->statement_warn_count(); @@ -5006,6 +5722,14 @@ static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) { digest_stat->m_warning_count+= da->statement_warn_count(); } + if(sub_stmt_stat != NULL) + { + sub_stmt_stat->m_warning_count+= da->statement_warn_count(); + } + if (prepared_stmt_stat != NULL) + { + prepared_stmt_stat->m_warning_count+= da->statement_warn_count(); + } break; case Diagnostics_area::DA_ERROR: stat->m_error_count++; @@ -5013,17 +5737,472 @@ static void end_statement_v1(PSI_statement_locker *locker, void *stmt_da) { digest_stat->m_error_count++; } + if (sub_stmt_stat != NULL) + { + sub_stmt_stat->m_error_count++; + } + if (prepared_stmt_stat != NULL) + { + prepared_stmt_stat->m_error_count++; + } break; case Diagnostics_area::DA_DISABLED: break; } } +static inline enum_object_type sp_type_to_object_type(uint sp_type) +{ + enum enum_sp_type value= static_cast<enum enum_sp_type> (sp_type); + + switch (value) + { + case SP_TYPE_FUNCTION: + return OBJECT_TYPE_FUNCTION; + case SP_TYPE_PROCEDURE: + return OBJECT_TYPE_PROCEDURE; + case SP_TYPE_TRIGGER: + return OBJECT_TYPE_TRIGGER; + case SP_TYPE_EVENT: + return OBJECT_TYPE_EVENT; + default: + DBUG_ASSERT(false); + /* Dead code */ + return NO_OBJECT_TYPE; + } +} + +/** + Implementation of the stored program instrumentation interface. + @sa PSI_v1::get_sp_share. +*/ +PSI_sp_share *pfs_get_sp_share_v1(uint sp_type, + const char* schema_name, + uint schema_name_length, + const char* object_name, + uint object_name_length) +{ + + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); + if (unlikely(pfs_thread == NULL)) + return NULL; + + if (object_name_length > COL_OBJECT_NAME_SIZE) + object_name_length= COL_OBJECT_NAME_SIZE; + if (schema_name_length > COL_OBJECT_SCHEMA_SIZE) + schema_name_length= COL_OBJECT_SCHEMA_SIZE; + + PFS_program *pfs_program; + pfs_program= find_or_create_program(pfs_thread, + sp_type_to_object_type(sp_type), + object_name, + object_name_length, + schema_name, + schema_name_length); + + return reinterpret_cast<PSI_sp_share *>(pfs_program); +} + +void pfs_release_sp_share_v1(PSI_sp_share* sp_share) +{ + /* Unused */ + return; +} + +PSI_sp_locker* pfs_start_sp_v1(PSI_sp_locker_state *state, + PSI_sp_share *sp_share) +{ + DBUG_ASSERT(state != NULL); + if (! flag_global_instrumentation) + return NULL; + + if (flag_thread_instrumentation) + { + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); + if (unlikely(pfs_thread == NULL)) + return NULL; + if (! pfs_thread->m_enabled) + return NULL; + } + + /* + sp share might be null in case when stat array is full and no new + stored program stats are being inserted into it. + */ + PFS_program *pfs_program= reinterpret_cast<PFS_program*>(sp_share); + if (pfs_program == NULL || !pfs_program->m_enabled) + return NULL; + + state->m_flags= 0; + + if(pfs_program->m_timed) + { + state->m_flags|= STATE_FLAG_TIMED; + state->m_timer_start= get_timer_raw_value_and_function(statement_timer, + & state->m_timer); + } + + state->m_sp_share= sp_share; + + return reinterpret_cast<PSI_sp_locker*> (state); +} + +void pfs_end_sp_v1(PSI_sp_locker *locker) +{ + PSI_sp_locker_state *state= reinterpret_cast<PSI_sp_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + ulonglong timer_end; + ulonglong wait_time; + + PFS_program *pfs_program= reinterpret_cast<PFS_program *>(state->m_sp_share); + PFS_sp_stat *stat= &pfs_program->m_sp_stat; + + if (state->m_flags & STATE_FLAG_TIMED) + { + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; + + /* Now use this timer_end and wait_time for timing information. */ + stat->aggregate_value(wait_time); + } + else + { + stat->aggregate_counted(); + } +} + +void pfs_drop_sp_v1(uint sp_type, + const char* schema_name, + uint schema_name_length, + const char* object_name, + uint object_name_length) +{ + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); + if (unlikely(pfs_thread == NULL)) + return; + + if (object_name_length > COL_OBJECT_NAME_SIZE) + object_name_length= COL_OBJECT_NAME_SIZE; + if (schema_name_length > COL_OBJECT_SCHEMA_SIZE) + schema_name_length= COL_OBJECT_SCHEMA_SIZE; + + drop_program(pfs_thread, + sp_type_to_object_type(sp_type), + object_name, object_name_length, + schema_name, schema_name_length); +} + +PSI_transaction_locker* +pfs_get_thread_transaction_locker_v1(PSI_transaction_locker_state *state, + const void *xid, + const ulonglong *trxid, + int isolation_level, + my_bool read_only, + my_bool autocommit) +{ + DBUG_ASSERT(state != NULL); + + if (!flag_global_instrumentation) + return NULL; + + if (!global_transaction_class.m_enabled) + return NULL; + + uint flags; + + if (flag_thread_instrumentation) + { + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); + if (unlikely(pfs_thread == NULL)) + return NULL; + if (!pfs_thread->m_enabled) + return NULL; + state->m_thread= reinterpret_cast<PSI_thread *> (pfs_thread); + flags= STATE_FLAG_THREAD; + + if (global_transaction_class.m_timed) + flags|= STATE_FLAG_TIMED; + + if (flag_events_transactions_current) + { + ulonglong event_id= pfs_thread->m_event_id++; + + PFS_events_transactions *pfs= &pfs_thread->m_transaction_current; + pfs->m_thread_internal_id = pfs_thread->m_thread_internal_id; + pfs->m_event_id= event_id; + pfs->m_event_type= EVENT_TYPE_TRANSACTION; + pfs->m_end_event_id= 0; + pfs->m_class= &global_transaction_class; + pfs->m_timer_start= 0; + pfs->m_timer_end= 0; + if (xid != NULL) + pfs->m_xid= *(PSI_xid *)xid; + pfs->m_xa= false; + pfs->m_xa_state= TRANS_STATE_XA_NOTR; + pfs->m_trxid= (trxid == NULL) ? 0 : *trxid; + pfs->m_isolation_level= (enum_isolation_level)isolation_level; + pfs->m_read_only= read_only; + pfs->m_autocommit= autocommit; + pfs->m_savepoint_count= 0; + pfs->m_rollback_to_savepoint_count= 0; + pfs->m_release_savepoint_count= 0; + + uint statements_count= pfs_thread->m_events_statements_count; + if (statements_count > 0) + { + PFS_events_statements *pfs_statement= + &pfs_thread->m_statement_stack[statements_count - 1]; + pfs->m_nesting_event_id= pfs_statement->m_event_id; + pfs->m_nesting_event_type= pfs_statement->m_event_type; + } + else + { + pfs->m_nesting_event_id= 0; + /* pfs->m_nesting_event_type not used when m_nesting_event_id is 0 */ + } + + state->m_transaction= pfs; + flags|= STATE_FLAG_EVENT; + } + } + else + { + if (global_transaction_class.m_timed) + flags= STATE_FLAG_TIMED; + else + flags= 0; + } + + state->m_class= &global_transaction_class; + state->m_flags= flags; + state->m_autocommit= autocommit; + state->m_read_only= read_only; + state->m_savepoint_count= 0; + state->m_rollback_to_savepoint_count= 0; + state->m_release_savepoint_count= 0; + + return reinterpret_cast<PSI_transaction_locker*> (state); +} + +void pfs_start_transaction_v1(PSI_transaction_locker *locker, + const char *src_file, uint src_line) +{ + PSI_transaction_locker_state *state= reinterpret_cast<PSI_transaction_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + uint flags= state->m_flags; + ulonglong timer_start= 0; + + if (flags & STATE_FLAG_TIMED) + { + timer_start= get_timer_raw_value_and_function(transaction_timer, &state->m_timer); + state->m_timer_start= timer_start; + } + + if (flags & STATE_FLAG_EVENT) + { + PFS_events_transactions *pfs= reinterpret_cast<PFS_events_transactions*> (state->m_transaction); + DBUG_ASSERT(pfs != NULL); + + pfs->m_timer_start= timer_start; + pfs->m_source_file= src_file; + pfs->m_source_line= src_line; + pfs->m_state= TRANS_STATE_ACTIVE; + //pfs->m_sid.clear(); + bzero(&pfs->m_gtid_spec, sizeof(pfs->m_gtid_spec)); + } +} + +void pfs_set_transaction_gtid_v1(PSI_transaction_locker *locker, + const void *sid, + const void *gtid_spec) +{ + PSI_transaction_locker_state *state= reinterpret_cast<PSI_transaction_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + DBUG_ASSERT(sid != NULL); + DBUG_ASSERT(gtid_spec != NULL); + + if (state->m_flags & STATE_FLAG_EVENT) + { + PFS_events_transactions *pfs= reinterpret_cast<PFS_events_transactions*> (state->m_transaction); + DBUG_ASSERT(pfs != NULL); + //pfs->m_sid= *(rpl_sid *)sid; + pfs->m_gtid_spec= *(Gtid_specification*)gtid_spec; + } +} + +void pfs_set_transaction_xid_v1(PSI_transaction_locker *locker, + const void *xid, + int xa_state) +{ + PSI_transaction_locker_state *state= reinterpret_cast<PSI_transaction_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + if (state->m_flags & STATE_FLAG_EVENT) + { + PFS_events_transactions *pfs= reinterpret_cast<PFS_events_transactions*> (state->m_transaction); + DBUG_ASSERT(pfs != NULL); + DBUG_ASSERT(xid != NULL); + + pfs->m_xid= *(PSI_xid *)xid; + pfs->m_xa_state= (enum_xa_transaction_state)xa_state; + pfs->m_xa= true; + } + return; +} + +void pfs_set_transaction_xa_state_v1(PSI_transaction_locker *locker, + int xa_state) +{ + PSI_transaction_locker_state *state= reinterpret_cast<PSI_transaction_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + if (state->m_flags & STATE_FLAG_EVENT) + { + PFS_events_transactions *pfs= reinterpret_cast<PFS_events_transactions*> (state->m_transaction); + DBUG_ASSERT(pfs != NULL); + + pfs->m_xa_state= (enum_xa_transaction_state)xa_state; + pfs->m_xa= true; + } + return; +} + +void pfs_set_transaction_trxid_v1(PSI_transaction_locker *locker, + const ulonglong *trxid) +{ + DBUG_ASSERT(trxid != NULL); + + PSI_transaction_locker_state *state= reinterpret_cast<PSI_transaction_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + if (state->m_flags & STATE_FLAG_EVENT) + { + PFS_events_transactions *pfs= reinterpret_cast<PFS_events_transactions*> (state->m_transaction); + DBUG_ASSERT(pfs != NULL); + + if (pfs->m_trxid == 0) + pfs->m_trxid= *trxid; + } +} + +#define INC_TRANSACTION_ATTR_BODY(LOCKER, ATTR, VALUE) \ + PSI_transaction_locker_state *state; \ + state= reinterpret_cast<PSI_transaction_locker_state*> (LOCKER); \ + if (unlikely(state == NULL)) \ + return; \ + state->ATTR+= VALUE; \ + if (state->m_flags & STATE_FLAG_EVENT) \ + { \ + PFS_events_transactions *pfs; \ + pfs= reinterpret_cast<PFS_events_transactions*> (state->m_transaction); \ + DBUG_ASSERT(pfs != NULL); \ + pfs->ATTR+= VALUE; \ + } \ + return; + + +void pfs_inc_transaction_savepoints_v1(PSI_transaction_locker *locker, + ulong count) +{ + INC_TRANSACTION_ATTR_BODY(locker, m_savepoint_count, count); +} + +void pfs_inc_transaction_rollback_to_savepoint_v1(PSI_transaction_locker *locker, + ulong count) +{ + INC_TRANSACTION_ATTR_BODY(locker, m_rollback_to_savepoint_count, count); +} + +void pfs_inc_transaction_release_savepoint_v1(PSI_transaction_locker *locker, + ulong count) +{ + INC_TRANSACTION_ATTR_BODY(locker, m_release_savepoint_count, count); +} + +void pfs_end_transaction_v1(PSI_transaction_locker *locker, my_bool commit) +{ + PSI_transaction_locker_state *state= reinterpret_cast<PSI_transaction_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + ulonglong timer_end= 0; + ulonglong wait_time= 0; + uint flags= state->m_flags; + + if (flags & STATE_FLAG_TIMED) + { + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; + } + + PFS_transaction_stat *stat; + + if (flags & STATE_FLAG_THREAD) + { + PFS_thread *pfs_thread= reinterpret_cast<PFS_thread *> (state->m_thread); + DBUG_ASSERT(pfs_thread != NULL); + + /* Aggregate to EVENTS_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME */ + stat= &pfs_thread->write_instr_class_transactions_stats()[GLOBAL_TRANSACTION_INDEX]; + + if (flags & STATE_FLAG_EVENT) + { + PFS_events_transactions *pfs= reinterpret_cast<PFS_events_transactions*> (state->m_transaction); + DBUG_ASSERT(pfs != NULL); + + /* events_transactions_current may have been cleared while the transaction was active */ + if (unlikely(pfs->m_class == NULL)) + return; + + pfs->m_timer_end= timer_end; + pfs->m_end_event_id= pfs_thread->m_event_id; + + pfs->m_state= (commit ? TRANS_STATE_COMMITTED : TRANS_STATE_ROLLED_BACK); + + if (pfs->m_xa) + pfs->m_xa_state= (commit ? TRANS_STATE_XA_COMMITTED : TRANS_STATE_XA_ROLLBACK_ONLY); + + if (pfs_thread->m_flag_events_transactions_history) + insert_events_transactions_history(pfs_thread, pfs); + if (pfs_thread->m_flag_events_transactions_history_long) + insert_events_transactions_history_long(pfs); + } + } + else + { + /* Aggregate to EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME */ + stat= &global_transaction_stat; + } + + if (flags & STATE_FLAG_TIMED) + { + /* Aggregate to EVENTS_TRANSACTIONS_SUMMARY_..._BY_EVENT_NAME (timed) */ + if(state->m_read_only) + stat->m_read_only_stat.aggregate_value(wait_time); + else + stat->m_read_write_stat.aggregate_value(wait_time); + } + else + { + /* Aggregate to EVENTS_TRANSACTIONS_SUMMARY_..._BY_EVENT_NAME (counted) */ + if(state->m_read_only) + stat->m_read_only_stat.aggregate_counted(); + else + stat->m_read_write_stat.aggregate_counted(); + } + + stat->m_savepoint_count+= state->m_savepoint_count; + stat->m_rollback_to_savepoint_count+= state->m_rollback_to_savepoint_count; + stat->m_release_savepoint_count+= state->m_release_savepoint_count; +} + + /** 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) +void pfs_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); @@ -5096,9 +6275,9 @@ static void end_socket_wait_v1(PSI_socket_locker *locker, size_t byte_count) wait->m_end_event_id= thread->m_event_id; wait->m_number_of_bytes= bytes; - if (flag_events_waits_history) + if (thread->m_flag_events_waits_history) insert_events_waits_history(thread, wait); - if (flag_events_waits_history_long) + if (thread->m_flag_events_waits_history_long) insert_events_waits_history_long(wait); thread->m_events_waits_current--; @@ -5106,7 +6285,7 @@ static void end_socket_wait_v1(PSI_socket_locker *locker, size_t byte_count) } } -static void set_socket_state_v1(PSI_socket *socket, PSI_socket_state state) +void pfs_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); @@ -5119,10 +6298,10 @@ static void set_socket_state_v1(PSI_socket *socket, PSI_socket_state state) /** 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) +void pfs_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); @@ -5148,11 +6327,11 @@ static void set_socket_info_v1(PSI_socket *socket, Implementation of the socket instrumentation interface. @sa PSI_v1::set_socket_info. */ -static void set_socket_thread_owner_v1(PSI_socket *socket) +void pfs_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); + pfs_socket->m_thread_owner= my_thread_get_THR_PFS(); } struct PSI_digest_locker* @@ -5189,30 +6368,86 @@ void pfs_digest_end_v1(PSI_digest_locker *locker, const sql_digest_storage *dige } } +PSI_prepared_stmt* +pfs_create_prepared_stmt_v1(void *identity, uint stmt_id, + PSI_statement_locker *locker, + const char *stmt_name, size_t stmt_name_length, + const char *sql_text, size_t sql_text_length) +{ + PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker); + PFS_events_statements *pfs_stmt= reinterpret_cast<PFS_events_statements*> (state->m_statement); + PFS_program *pfs_program= reinterpret_cast<PFS_program *>(state->m_parent_sp_share); + + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); + if (unlikely(pfs_thread == NULL)) + return NULL; + + if (sql_text_length > COL_INFO_SIZE) + sql_text_length= COL_INFO_SIZE; + + PFS_prepared_stmt *pfs= create_prepared_stmt(identity, + pfs_thread, pfs_program, + pfs_stmt, stmt_id, + stmt_name, stmt_name_length, + sql_text, sql_text_length); + + state->m_parent_prepared_stmt= reinterpret_cast<PSI_prepared_stmt*>(pfs); + state->m_in_prepare= true; + + return reinterpret_cast<PSI_prepared_stmt*>(pfs); +} + +void pfs_execute_prepared_stmt_v1 (PSI_statement_locker *locker, + PSI_prepared_stmt* ps) +{ + PSI_statement_locker_state *state= reinterpret_cast<PSI_statement_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + state->m_parent_prepared_stmt= ps; + state->m_in_prepare= false; +} + +void pfs_destroy_prepared_stmt_v1(PSI_prepared_stmt* prepared_stmt) +{ + PFS_prepared_stmt *pfs_prepared_stmt= reinterpret_cast<PFS_prepared_stmt*>(prepared_stmt); + delete_prepared_stmt(pfs_prepared_stmt); + return; +} + +void pfs_reprepare_prepared_stmt_v1(PSI_prepared_stmt* prepared_stmt) +{ + PFS_prepared_stmt *pfs_prepared_stmt= reinterpret_cast<PFS_prepared_stmt*>(prepared_stmt); + PFS_single_stat *prepared_stmt_stat= &pfs_prepared_stmt->m_reprepare_stat; + + if (prepared_stmt_stat != NULL) + prepared_stmt_stat->aggregate_counted(); + return; +} + /** 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) +int pfs_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); + PFS_thread *thd= my_thread_get_THR_PFS(); DBUG_ASSERT(buffer != NULL); if (likely(thd != NULL) && session_connect_attrs_size_per_thread > 0) { + pfs_dirty_state dirty_state; 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(); + thd->m_session_lock.allocated_to_dirty(& dirty_state); 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(); + thd->m_session_lock.dirty_to_allocated(& dirty_state); if (copy_size == length) return 0; @@ -5223,6 +6458,532 @@ static int set_thread_connect_attrs_v1(const char *buffer, uint length, return 0; } +void pfs_register_memory_v1(const char *category, + PSI_memory_info_v1 *info, + int count) +{ + REGISTER_BODY_V1(PSI_memory_key, + memory_instrument_prefix, + register_memory_class) +} + +PSI_memory_key pfs_memory_alloc_v1(PSI_memory_key key, size_t size, PSI_thread **owner) +{ + PFS_thread ** owner_thread= reinterpret_cast<PFS_thread**>(owner); + DBUG_ASSERT(owner_thread != NULL); + + if (! flag_global_instrumentation) + { + *owner_thread= NULL; + return PSI_NOT_INSTRUMENTED; + } + + PFS_memory_class *klass= find_memory_class(key); + if (klass == NULL) + { + *owner_thread= NULL; + return PSI_NOT_INSTRUMENTED; + } + + if (! klass->m_enabled) + { + *owner_thread= NULL; + return PSI_NOT_INSTRUMENTED; + } + + PFS_memory_stat *event_name_array; + PFS_memory_stat *stat; + uint index= klass->m_event_name_index; + PFS_memory_stat_delta delta_buffer; + PFS_memory_stat_delta *delta; + + if (flag_thread_instrumentation && ! klass->is_global()) + { + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); + if (unlikely(pfs_thread == NULL)) + { + *owner_thread= NULL; + return PSI_NOT_INSTRUMENTED; + } + if (! pfs_thread->m_enabled) + { + *owner_thread= NULL; + return PSI_NOT_INSTRUMENTED; + } + + /* Aggregate to MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME */ + event_name_array= pfs_thread->write_instr_class_memory_stats(); + stat= & event_name_array[index]; + delta= stat->count_alloc(size, &delta_buffer); + + if (delta != NULL) + { + pfs_thread->carry_memory_stat_delta(delta, index); + } + + /* Flag this memory as owned by the current thread. */ + *owner_thread= pfs_thread; + } + else + { + /* Aggregate to MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME */ + event_name_array= global_instr_class_memory_array; + stat= & event_name_array[index]; + (void) stat->count_alloc(size, &delta_buffer); + + *owner_thread= NULL; + } + + return key; +} + +PSI_memory_key pfs_memory_realloc_v1(PSI_memory_key key, size_t old_size, size_t new_size, PSI_thread **owner) +{ + PFS_thread ** owner_thread_hdl= reinterpret_cast<PFS_thread**>(owner); + DBUG_ASSERT(owner != NULL); + + PFS_memory_class *klass= find_memory_class(key); + if (klass == NULL) + { + *owner_thread_hdl= NULL; + return PSI_NOT_INSTRUMENTED; + } + + PFS_memory_stat *event_name_array; + PFS_memory_stat *stat; + uint index= klass->m_event_name_index; + PFS_memory_stat_delta delta_buffer; + PFS_memory_stat_delta *delta; + + if (flag_thread_instrumentation && ! klass->is_global()) + { + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); + if (likely(pfs_thread != NULL)) + { +#ifdef PFS_PARANOID + PFS_thread *owner_thread= *owner_thread_hdl; + if (owner_thread != pfs_thread) + { + owner_thread= sanitize_thread(owner_thread); + if (owner_thread != NULL) + { + report_memory_accounting_error("pfs_memory_realloc_v1", + pfs_thread, old_size, klass, owner_thread); + } + } +#endif /* PFS_PARANOID */ + + /* Aggregate to MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME */ + event_name_array= pfs_thread->write_instr_class_memory_stats(); + stat= & event_name_array[index]; + + if (flag_global_instrumentation && klass->m_enabled) + { + delta= stat->count_realloc(old_size, new_size, &delta_buffer); + *owner_thread_hdl= pfs_thread; + } + else + { + delta= stat->count_free(old_size, &delta_buffer); + *owner_thread_hdl= NULL; + key= PSI_NOT_INSTRUMENTED; + } + + if (delta != NULL) + { + pfs_thread->carry_memory_stat_delta(delta, index); + } + return key; + } + } + + /* Aggregate to MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME */ + event_name_array= global_instr_class_memory_array; + stat= & event_name_array[index]; + + if (flag_global_instrumentation && klass->m_enabled) + { + (void) stat->count_realloc(old_size, new_size, &delta_buffer); + } + else + { + (void) stat->count_free(old_size, &delta_buffer); + key= PSI_NOT_INSTRUMENTED; + } + + *owner_thread_hdl= NULL; + return key; +} + +PSI_memory_key pfs_memory_claim_v1(PSI_memory_key key, size_t size, PSI_thread **owner) +{ + PFS_thread ** owner_thread= reinterpret_cast<PFS_thread**>(owner); + DBUG_ASSERT(owner_thread != NULL); + + PFS_memory_class *klass= find_memory_class(key); + if (klass == NULL) + { + *owner_thread= NULL; + return PSI_NOT_INSTRUMENTED; + } + + /* + Do not check klass->m_enabled. + Do not check flag_global_instrumentation. + If a memory alloc was instrumented, + the corresponding free must be instrumented. + */ + + PFS_memory_stat *event_name_array; + PFS_memory_stat *stat; + uint index= klass->m_event_name_index; + PFS_memory_stat_delta delta_buffer; + PFS_memory_stat_delta *delta; + + if (flag_thread_instrumentation) + { + PFS_thread *old_thread= sanitize_thread(*owner_thread); + PFS_thread *new_thread= my_thread_get_THR_PFS(); + if (old_thread != new_thread) + { + if (old_thread != NULL) + { + event_name_array= old_thread->write_instr_class_memory_stats(); + stat= & event_name_array[index]; + delta= stat->count_free(size, &delta_buffer); + + if (delta != NULL) + { + old_thread->carry_memory_stat_delta(delta, index); + } + } + + if (new_thread != NULL) + { + event_name_array= new_thread->write_instr_class_memory_stats(); + stat= & event_name_array[index]; + delta= stat->count_alloc(size, &delta_buffer); + + if (delta != NULL) + { + new_thread->carry_memory_stat_delta(delta, index); + } + } + + *owner_thread= new_thread; + } + + return key; + } + + *owner_thread= NULL; + return key; +} + +void pfs_memory_free_v1(PSI_memory_key key, size_t size, PSI_thread *owner) +{ + PFS_memory_class *klass= find_memory_class(key); + if (klass == NULL) + return; + + /* + Do not check klass->m_enabled. + Do not check flag_global_instrumentation. + If a memory alloc was instrumented, + the corresponding free must be instrumented. + */ + + PFS_memory_stat *event_name_array; + PFS_memory_stat *stat; + uint index= klass->m_event_name_index; + PFS_memory_stat_delta delta_buffer; + PFS_memory_stat_delta *delta; + + if (flag_thread_instrumentation && ! klass->is_global()) + { + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); + if (likely(pfs_thread != NULL)) + { +#ifdef PFS_PARANOID + PFS_thread *owner_thread= reinterpret_cast<PFS_thread*>(owner); + + if (owner_thread != pfs_thread) + { + owner_thread= sanitize_thread(owner_thread); + if (owner_thread != NULL) + { + report_memory_accounting_error("pfs_memory_free_v1", + pfs_thread, size, klass, owner_thread); + } + } +#endif /* PFS_PARANOID */ + + /* + Do not check pfs_thread->m_enabled. + If a memory alloc was instrumented, + the corresponding free must be instrumented. + */ + /* Aggregate to MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME */ + event_name_array= pfs_thread->write_instr_class_memory_stats(); + stat= & event_name_array[index]; + delta= stat->count_free(size, &delta_buffer); + + if (delta != NULL) + { + pfs_thread->carry_memory_stat_delta(delta, index); + } + return; + } + } + + /* Aggregate to MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME */ + event_name_array= global_instr_class_memory_array; + if (event_name_array) + { + stat= & event_name_array[index]; + (void) stat->count_free(size, &delta_buffer); + } + return; +} + +void pfs_unlock_table_v1(PSI_table *table) +{ + PFS_table *pfs_table= reinterpret_cast<PFS_table*> (table); + + DBUG_ASSERT(pfs_table != NULL); + + pfs_table->m_internal_lock= PFS_TL_NONE; + return; +} + +PSI_metadata_lock * +pfs_create_metadata_lock_v1( + void *identity, + const MDL_key *mdl_key, + opaque_mdl_type mdl_type, + opaque_mdl_duration mdl_duration, + opaque_mdl_status mdl_status, + const char *src_file, + uint src_line) +{ + if (! flag_global_instrumentation) + return NULL; + + if (! global_metadata_class.m_enabled) + return NULL; + + PFS_thread *pfs_thread= my_thread_get_THR_PFS(); + if (pfs_thread == NULL) + return NULL; + + PFS_metadata_lock *pfs; + pfs= create_metadata_lock(identity, mdl_key, + mdl_type, mdl_duration, mdl_status, + src_file, src_line); + + if (pfs != NULL) + { + pfs->m_owner_thread_id= pfs_thread->m_thread_internal_id; + pfs->m_owner_event_id= pfs_thread->m_event_id; + } + + return reinterpret_cast<PSI_metadata_lock *> (pfs); +} + +void +pfs_set_metadata_lock_status_v1(PSI_metadata_lock *lock, opaque_mdl_status mdl_status) +{ + PFS_metadata_lock *pfs= reinterpret_cast<PFS_metadata_lock*> (lock); + DBUG_ASSERT(pfs != NULL); + pfs->m_mdl_status= mdl_status; +} + +void +pfs_destroy_metadata_lock_v1(PSI_metadata_lock *lock) +{ + PFS_metadata_lock *pfs= reinterpret_cast<PFS_metadata_lock*> (lock); + DBUG_ASSERT(pfs != NULL); + destroy_metadata_lock(pfs); +} + +PSI_metadata_locker * +pfs_start_metadata_wait_v1(PSI_metadata_locker_state *state, + PSI_metadata_lock *lock, + const char *src_file, + uint src_line) +{ + PFS_metadata_lock *pfs_lock= reinterpret_cast<PFS_metadata_lock*> (lock); + DBUG_ASSERT(state != NULL); + DBUG_ASSERT(pfs_lock != NULL); + + if (! pfs_lock->m_enabled) + return NULL; + + uint flags; + ulonglong timer_start= 0; + + if (flag_thread_instrumentation) + { + PFS_thread *pfs_thread= my_thread_get_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_lock->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_internal_id= pfs_thread->m_thread_internal_id; + wait->m_class= &global_metadata_class; + wait->m_timer_start= timer_start; + wait->m_timer_end= 0; + wait->m_object_instance_addr= pfs_lock->m_identity; + wait->m_event_id= pfs_thread->m_event_id++; + wait->m_end_event_id= 0; + wait->m_weak_metadata_lock= pfs_lock; + wait->m_weak_version= pfs_lock->get_version(); + wait->m_operation= OPERATION_TYPE_METADATA; + wait->m_source_file= src_file; + wait->m_source_line= src_line; + wait->m_wait_class= WAIT_CLASS_METADATA; + + pfs_thread->m_events_waits_current++; + } + } + else + { + if (pfs_lock->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_GLOBAL_BY_EVENT_NAME (counted) */ + global_metadata_stat.aggregate_counted(); + return NULL; + } + } + + state->m_flags= flags; + state->m_metadata_lock= lock; + return reinterpret_cast<PSI_metadata_locker*> (state); +} + +void +pfs_end_metadata_wait_v1(PSI_metadata_locker *locker, + int rc) +{ + PSI_metadata_locker_state *state= reinterpret_cast<PSI_metadata_locker_state*> (locker); + DBUG_ASSERT(state != NULL); + + ulonglong timer_end= 0; + ulonglong wait_time= 0; + + PFS_thread *thread= reinterpret_cast<PFS_thread *> (state->m_thread); + + uint flags= state->m_flags; + + if (flags & STATE_FLAG_TIMED) + { + timer_end= state->m_timer(); + wait_time= timer_end - state->m_timer_start; + } + + if (flags & STATE_FLAG_THREAD) + { + PFS_single_stat *event_name_array; + event_name_array= thread->write_instr_class_waits_stats(); + + if (flags & STATE_FLAG_TIMED) + { + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (timed) */ + event_name_array[GLOBAL_METADATA_EVENT_INDEX].aggregate_value(wait_time); + } + else + { + /* Aggregate to EVENTS_WAITS_SUMMARY_BY_THREAD_BY_EVENT_NAME (counted) */ + event_name_array[GLOBAL_METADATA_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 (thread->m_flag_events_waits_history) + insert_events_waits_history(thread, wait); + if (thread->m_flag_events_waits_history_long) + insert_events_waits_history_long(wait); + thread->m_events_waits_current--; + + DBUG_ASSERT(wait == thread->m_events_waits_current); + } + } + else + { + if (flags & STATE_FLAG_TIMED) + { + /* Aggregate to EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME (timed) */ + global_metadata_stat.aggregate_value(wait_time); + } + else + { + /* Aggregate to EVENTS_WAITS_SUMMARY_GLOBAL_BY_EVENT_NAME (counted) */ + global_metadata_stat.aggregate_counted(); + } + } +} + +void pfs_set_prepared_stmt_text_v1(PSI_prepared_stmt *prepared_stmt, + const char *text, + uint text_len) +{ + PFS_prepared_stmt *pfs_prepared_stmt = + reinterpret_cast<PFS_prepared_stmt *>(prepared_stmt); + DBUG_ASSERT(pfs_prepared_stmt != NULL); + + uint max_len = COL_INFO_SIZE; + if (text_len > max_len) + { + text_len = max_len; + } + + memcpy(pfs_prepared_stmt->m_sqltext, text, text_len); + pfs_prepared_stmt->m_sqltext_length = text_len; + + return; +} /** Implementation of the instrumentation interface. @@ -5230,103 +6991,140 @@ static int set_thread_connect_attrs_v1(const char *buffer, uint length, */ PSI_v1 PFS_v1= { - register_mutex_v1, - register_rwlock_v1, - register_cond_v1, - register_thread_v1, - register_file_v1, - register_stage_v1, - register_statement_v1, - register_socket_v1, - init_mutex_v1, - destroy_mutex_v1, - init_rwlock_v1, - destroy_rwlock_v1, - init_cond_v1, - destroy_cond_v1, - init_socket_v1, - destroy_socket_v1, - get_table_share_v1, - release_table_share_v1, - drop_table_share_v1, - open_table_v1, - unbind_table_v1, - rebind_table_v1, - close_table_v1, - create_file_v1, - spawn_thread_v1, - new_thread_v1, - set_thread_id_v1, - get_thread_v1, - set_thread_user_v1, - set_thread_account_v1, - set_thread_db_v1, - set_thread_command_v1, - set_thread_start_time_v1, - set_thread_state_v1, - set_thread_info_v1, - set_thread_v1, - delete_current_thread_v1, - delete_thread_v1, - get_thread_file_name_locker_v1, - get_thread_file_stream_locker_v1, - get_thread_file_descriptor_locker_v1, - unlock_mutex_v1, - unlock_rwlock_v1, - signal_cond_v1, - broadcast_cond_v1, - start_idle_wait_v1, - end_idle_wait_v1, - start_mutex_wait_v1, - end_mutex_wait_v1, - start_rwlock_wait_v1, /* read */ - end_rwlock_rdwait_v1, - start_rwlock_wait_v1, /* write */ - end_rwlock_wrwait_v1, - start_cond_wait_v1, - end_cond_wait_v1, - start_table_io_wait_v1, - end_table_io_wait_v1, - start_table_lock_wait_v1, - end_table_lock_wait_v1, - start_file_open_wait_v1, - end_file_open_wait_v1, - end_file_open_wait_and_bind_to_descriptor_v1, - start_file_wait_v1, - end_file_wait_v1, - start_file_close_wait_v1, - end_file_close_wait_v1, - start_stage_v1, - end_stage_v1, - get_thread_statement_locker_v1, - refine_statement_v1, - start_statement_v1, - set_statement_text_v1, - set_statement_lock_time_v1, - set_statement_rows_sent_v1, - set_statement_rows_examined_v1, - inc_statement_created_tmp_disk_tables_v1, - inc_statement_created_tmp_tables_v1, - inc_statement_select_full_join_v1, - inc_statement_select_full_range_join_v1, - inc_statement_select_range_v1, - inc_statement_select_range_check_v1, - inc_statement_select_scan_v1, - inc_statement_sort_merge_passes_v1, - inc_statement_sort_range_v1, - inc_statement_sort_rows_v1, - inc_statement_sort_scan_v1, - set_statement_no_index_used_v1, - set_statement_no_good_index_used_v1, - end_statement_v1, - start_socket_wait_v1, - end_socket_wait_v1, - set_socket_state_v1, - set_socket_info_v1, - set_socket_thread_owner_v1, + pfs_register_mutex_v1, + pfs_register_rwlock_v1, + pfs_register_cond_v1, + pfs_register_thread_v1, + pfs_register_file_v1, + pfs_register_stage_v1, + pfs_register_statement_v1, + pfs_register_socket_v1, + pfs_init_mutex_v1, + pfs_destroy_mutex_v1, + pfs_init_rwlock_v1, + pfs_destroy_rwlock_v1, + pfs_init_cond_v1, + pfs_destroy_cond_v1, + pfs_init_socket_v1, + pfs_destroy_socket_v1, + pfs_get_table_share_v1, + pfs_release_table_share_v1, + pfs_drop_table_share_v1, + pfs_open_table_v1, + pfs_unbind_table_v1, + pfs_rebind_table_v1, + pfs_close_table_v1, + pfs_create_file_v1, + pfs_spawn_thread_v1, + pfs_new_thread_v1, + pfs_set_thread_id_v1, + pfs_set_thread_THD_v1, + pfs_set_thread_os_id_v1, + pfs_get_thread_v1, + pfs_set_thread_user_v1, + pfs_set_thread_account_v1, + pfs_set_thread_db_v1, + pfs_set_thread_command_v1, + pfs_set_connection_type_v1, + pfs_set_thread_start_time_v1, + pfs_set_thread_state_v1, + pfs_set_thread_info_v1, + pfs_set_thread_v1, + pfs_delete_current_thread_v1, + pfs_delete_thread_v1, + pfs_get_thread_file_name_locker_v1, + pfs_get_thread_file_stream_locker_v1, + pfs_get_thread_file_descriptor_locker_v1, + pfs_unlock_mutex_v1, + pfs_unlock_rwlock_v1, + pfs_signal_cond_v1, + pfs_broadcast_cond_v1, + pfs_start_idle_wait_v1, + pfs_end_idle_wait_v1, + pfs_start_mutex_wait_v1, + pfs_end_mutex_wait_v1, + pfs_start_rwlock_rdwait_v1, + pfs_end_rwlock_rdwait_v1, + pfs_start_rwlock_wrwait_v1, + pfs_end_rwlock_wrwait_v1, + pfs_start_cond_wait_v1, + pfs_end_cond_wait_v1, + pfs_start_table_io_wait_v1, + pfs_end_table_io_wait_v1, + pfs_start_table_lock_wait_v1, + pfs_end_table_lock_wait_v1, + pfs_start_file_open_wait_v1, + pfs_end_file_open_wait_v1, + pfs_end_file_open_wait_and_bind_to_descriptor_v1, + pfs_end_temp_file_open_wait_and_bind_to_descriptor_v1, + pfs_start_file_wait_v1, + pfs_end_file_wait_v1, + pfs_start_file_close_wait_v1, + pfs_end_file_close_wait_v1, + pfs_end_file_rename_wait_v1, + pfs_start_stage_v1, + pfs_get_current_stage_progress_v1, + pfs_end_stage_v1, + pfs_get_thread_statement_locker_v1, + pfs_refine_statement_v1, + pfs_start_statement_v1, + pfs_set_statement_text_v1, + pfs_set_statement_lock_time_v1, + pfs_set_statement_rows_sent_v1, + pfs_set_statement_rows_examined_v1, + pfs_inc_statement_created_tmp_disk_tables_v1, + pfs_inc_statement_created_tmp_tables_v1, + pfs_inc_statement_select_full_join_v1, + pfs_inc_statement_select_full_range_join_v1, + pfs_inc_statement_select_range_v1, + pfs_inc_statement_select_range_check_v1, + pfs_inc_statement_select_scan_v1, + pfs_inc_statement_sort_merge_passes_v1, + pfs_inc_statement_sort_range_v1, + pfs_inc_statement_sort_rows_v1, + pfs_inc_statement_sort_scan_v1, + pfs_set_statement_no_index_used_v1, + pfs_set_statement_no_good_index_used_v1, + pfs_end_statement_v1, + pfs_get_thread_transaction_locker_v1, + pfs_start_transaction_v1, + pfs_set_transaction_xid_v1, + pfs_set_transaction_xa_state_v1, + pfs_set_transaction_gtid_v1, + pfs_set_transaction_trxid_v1, + pfs_inc_transaction_savepoints_v1, + pfs_inc_transaction_rollback_to_savepoint_v1, + pfs_inc_transaction_release_savepoint_v1, + pfs_end_transaction_v1, + pfs_start_socket_wait_v1, + pfs_end_socket_wait_v1, + pfs_set_socket_state_v1, + pfs_set_socket_info_v1, + pfs_set_socket_thread_owner_v1, + pfs_create_prepared_stmt_v1, + pfs_destroy_prepared_stmt_v1, + pfs_reprepare_prepared_stmt_v1, + pfs_execute_prepared_stmt_v1, + pfs_set_prepared_stmt_text_v1, pfs_digest_start_v1, pfs_digest_end_v1, - set_thread_connect_attrs_v1, + pfs_set_thread_connect_attrs_v1, + pfs_start_sp_v1, + pfs_end_sp_v1, + pfs_drop_sp_v1, + pfs_get_sp_share_v1, + pfs_release_sp_share_v1, + pfs_register_memory_v1, + pfs_memory_alloc_v1, + pfs_memory_realloc_v1, + pfs_memory_claim_v1, + pfs_memory_free_v1, + pfs_unlock_table_v1, + pfs_create_metadata_lock_v1, + pfs_set_metadata_lock_status_v1, + pfs_destroy_metadata_lock_v1, + pfs_start_metadata_wait_v1, + pfs_end_metadata_wait_v1 }; static void* get_interface(int version) diff --git a/storage/perfschema/pfs.h b/storage/perfschema/pfs.h index 3649143f8fa..69b23be4206 100644 --- a/storage/perfschema/pfs.h +++ b/storage/perfschema/pfs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2008, 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, version 2.0, @@ -30,7 +30,8 @@ #define HAVE_PSI_1 -#include <my_pthread.h> +#include <my_global.h> +#include "my_thread.h" #include <mysql/psi/psi.h> /** @@ -39,9 +40,24 @@ */ 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 pthread_key_t THR_PFS; +extern pthread_key_t THR_PFS_VG; // global_variables +extern pthread_key_t THR_PFS_SV; // session_variables +extern pthread_key_t THR_PFS_VBT; // variables_by_thread +extern pthread_key_t THR_PFS_SG; // global_status +extern pthread_key_t THR_PFS_SS; // session_status +extern pthread_key_t THR_PFS_SBT; // status_by_thread +extern pthread_key_t THR_PFS_SBU; // status_by_user +extern pthread_key_t THR_PFS_SBA; // status_by_host +extern pthread_key_t THR_PFS_SBH; // status_by_account + +/** True when @c THR_PFS and all other Performance Schema TLS keys are initialized. */ extern bool THR_PFS_initialized; +#define PSI_VOLATILITY_UNKNOWN 0 +#define PSI_VOLATILITY_SESSION 1 + +#define PSI_COUNT_VOLATILITY 2 + #endif diff --git a/storage/perfschema/pfs_account.cc b/storage/perfschema/pfs_account.cc index be2153e84ae..9d7a0afb783 100644 --- a/storage/perfschema/pfs_account.cc +++ b/storage/perfschema/pfs_account.cc @@ -22,7 +22,7 @@ /** @file storage/perfschema/pfs_account.cc - Performance schema user@host (implementation). + Performance schema account (implementation). */ #include "my_global.h" @@ -37,21 +37,13 @@ #include "pfs_account.h" #include "pfs_global.h" #include "pfs_instr_class.h" +#include "pfs_buffer_container.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; @@ -62,75 +54,16 @@ static bool account_hash_inited= false; */ 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]; - } + if (global_account_container.init(param->m_account_sizing)) + return 1; return 0; } -/** Cleanup all the user buffers. */ +/** Cleanup all the account 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; + global_account_container.cleanup(); } C_MODE_START @@ -154,13 +87,12 @@ C_MODE_END Initialize the user hash. @return 0 on success */ -int init_account_hash(void) +int init_account_hash(const PFS_global_param *param) { - if ((! account_hash_inited) && (account_max > 0)) + if ((! account_hash_inited) && (param->m_account_sizing != 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; @@ -217,16 +149,10 @@ 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++; + global_account_container.m_lost++; return NULL; } @@ -235,8 +161,10 @@ find_or_create_account(PFS_thread *thread, hostname, hostname_length); PFS_account **entry; + PFS_account *pfs; uint retry_count= 0; const uint retry_max= 3; + pfs_dirty_state dirty_state; search: entry= reinterpret_cast<PFS_account**> @@ -244,7 +172,6 @@ search: 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); @@ -253,93 +180,94 @@ search: 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= global_account_container.allocate(& dirty_state); + if (pfs != NULL) { - PFS_account *pfs= account_array + scan.first(); - PFS_account *pfs_last= account_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + 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; + + if (username_length > 0 && hostname_length > 0) + { + lookup_setup_actor(thread, username, username_length, hostname, hostname_length, + & pfs->m_enabled, & pfs->m_history); + } + else { - if (pfs->m_lock.is_free()) + pfs->m_enabled= true; + pfs->m_history= true; + } + + int res; + pfs->m_lock.dirty_to_allocated(& dirty_state); + res= lf_hash_insert(&account_hash, pins, &pfs); + if (likely(res == 0)) + { + 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; + } + + global_account_container.deallocate(pfs); + + if (res > 0) + { + if (++retry_count > retry_max) { - 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; - } + global_account_container.m_lost++; + return NULL; } + goto search; } + + global_account_container.m_lost++; + return NULL; } - account_lost++; return NULL; } -void PFS_account::aggregate(PFS_user *safe_user, PFS_host *safe_host) +void PFS_account::aggregate(bool alive, 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_transactions(safe_user, safe_host); + aggregate_memory(alive, safe_user, safe_host); + aggregate_status(safe_user, safe_host); aggregate_stats(safe_user, safe_host); } void PFS_account::aggregate_waits(PFS_user *safe_user, PFS_host *safe_host) { + if (read_instr_class_waits_stats() == NULL) + return; + if (likely(safe_user != NULL && safe_host != NULL)) { /* @@ -348,9 +276,9 @@ void PFS_account::aggregate_waits(PFS_user *safe_user, PFS_host *safe_host) - 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); + aggregate_all_event_names(write_instr_class_waits_stats(), + safe_user->write_instr_class_waits_stats(), + safe_host->write_instr_class_waits_stats()); return; } @@ -360,8 +288,8 @@ void PFS_account::aggregate_waits(PFS_user *safe_user, PFS_host *safe_host) 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); + aggregate_all_event_names(write_instr_class_waits_stats(), + safe_user->write_instr_class_waits_stats()); return; } @@ -371,8 +299,8 @@ void PFS_account::aggregate_waits(PFS_user *safe_user, PFS_host *safe_host) 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); + aggregate_all_event_names(write_instr_class_waits_stats(), + safe_host->write_instr_class_waits_stats()); return; } @@ -383,6 +311,9 @@ void PFS_account::aggregate_waits(PFS_user *safe_user, PFS_host *safe_host) void PFS_account::aggregate_stages(PFS_user *safe_user, PFS_host *safe_host) { + if (read_instr_class_stages_stats() == NULL) + return; + if (likely(safe_user != NULL && safe_host != NULL)) { /* @@ -391,9 +322,9 @@ void PFS_account::aggregate_stages(PFS_user *safe_user, PFS_host *safe_host) - 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); + aggregate_all_stages(write_instr_class_stages_stats(), + safe_user->write_instr_class_stages_stats(), + safe_host->write_instr_class_stages_stats()); return; } @@ -405,8 +336,8 @@ void PFS_account::aggregate_stages(PFS_user *safe_user, PFS_host *safe_host) - EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME in parallel. */ - aggregate_all_stages(m_instr_class_stages_stats, - safe_user->m_instr_class_stages_stats, + aggregate_all_stages(write_instr_class_stages_stats(), + safe_user->write_instr_class_stages_stats(), global_instr_class_stages_array); return; } @@ -417,8 +348,8 @@ void PFS_account::aggregate_stages(PFS_user *safe_user, PFS_host *safe_host) 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); + aggregate_all_stages(write_instr_class_stages_stats(), + safe_host->write_instr_class_stages_stats()); return; } @@ -426,13 +357,16 @@ void PFS_account::aggregate_stages(PFS_user *safe_user, PFS_host *safe_host) 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, + aggregate_all_stages(write_instr_class_stages_stats(), global_instr_class_stages_array); return; } void PFS_account::aggregate_statements(PFS_user *safe_user, PFS_host *safe_host) { + if (read_instr_class_statements_stats() == NULL) + return; + if (likely(safe_user != NULL && safe_host != NULL)) { /* @@ -441,9 +375,9 @@ void PFS_account::aggregate_statements(PFS_user *safe_user, PFS_host *safe_host) - 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); + aggregate_all_statements(write_instr_class_statements_stats(), + safe_user->write_instr_class_statements_stats(), + safe_host->write_instr_class_statements_stats()); return; } @@ -455,8 +389,8 @@ void PFS_account::aggregate_statements(PFS_user *safe_user, PFS_host *safe_host) - EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME in parallel. */ - aggregate_all_statements(m_instr_class_statements_stats, - safe_user->m_instr_class_statements_stats, + aggregate_all_statements(write_instr_class_statements_stats(), + safe_user->write_instr_class_statements_stats(), global_instr_class_statements_array); return; } @@ -467,8 +401,8 @@ void PFS_account::aggregate_statements(PFS_user *safe_user, PFS_host *safe_host) 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); + aggregate_all_statements(write_instr_class_statements_stats(), + safe_host->write_instr_class_statements_stats()); return; } @@ -476,11 +410,169 @@ void PFS_account::aggregate_statements(PFS_user *safe_user, PFS_host *safe_host) 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, + aggregate_all_statements(write_instr_class_statements_stats(), global_instr_class_statements_array); return; } +void PFS_account::aggregate_transactions(PFS_user *safe_user, PFS_host *safe_host) +{ + if (read_instr_class_transactions_stats() == NULL) + return; + + if (likely(safe_user != NULL && safe_host != NULL)) + { + /* + Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_transactions(write_instr_class_transactions_stats(), + safe_user->write_instr_class_transactions_stats(), + safe_host->write_instr_class_transactions_stats()); + return; + } + + if (safe_user != NULL) + { + /* + Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME + in parallel. + */ + aggregate_all_transactions(write_instr_class_transactions_stats(), + safe_user->write_instr_class_transactions_stats(), + &global_transaction_stat); + return; + } + + if (safe_host != NULL) + { + /* + Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME + */ + aggregate_all_transactions(write_instr_class_transactions_stats(), + safe_host->write_instr_class_transactions_stats()); + return; + } + + /* + Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME + */ + aggregate_all_transactions(write_instr_class_transactions_stats(), + &global_transaction_stat); + return; +} + +void PFS_account::aggregate_memory(bool alive, PFS_user *safe_user, PFS_host *safe_host) +{ + if (read_instr_class_memory_stats() == NULL) + return; + + if (likely(safe_user != NULL && safe_host != NULL)) + { + /* + Aggregate MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME + - MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_memory(alive, + write_instr_class_memory_stats(), + safe_user->write_instr_class_memory_stats(), + safe_host->write_instr_class_memory_stats()); + return; + } + + if (safe_user != NULL) + { + /* + Aggregate MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME + - MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME + in parallel. + */ + aggregate_all_memory(alive, + write_instr_class_memory_stats(), + safe_user->write_instr_class_memory_stats(), + global_instr_class_memory_array); + return; + } + + if (safe_host != NULL) + { + /* + Aggregate MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME + */ + aggregate_all_memory(alive, + write_instr_class_memory_stats(), + safe_host->write_instr_class_memory_stats()); + return; + } + + /* + Aggregate MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to: + - MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME + */ + aggregate_all_memory(alive, + write_instr_class_memory_stats(), + global_instr_class_memory_array); + return; +} + +void PFS_account::aggregate_status(PFS_user *safe_user, PFS_host *safe_host) +{ + if (likely(safe_user != NULL && safe_host != NULL)) + { + /* + Aggregate STATUS_BY_ACCOUNT to: + - STATUS_BY_USER + - STATUS_BY_HOST + */ + safe_user->m_status_stats.aggregate(& m_status_stats); + safe_host->m_status_stats.aggregate(& m_status_stats); + m_status_stats.reset(); + return; + } + + if (safe_user != NULL) + { + /* + Aggregate STATUS_BY_ACCOUNT to: + - STATUS_BY_USER + - GLOBAL_STATUS + */ + safe_user->m_status_stats.aggregate(& m_status_stats); + m_status_stats.aggregate_to(& global_status_var); + m_status_stats.reset(); + return; + } + + if (safe_host != NULL) + { + /* + Aggregate STATUS_BY_ACCOUNT to: + - STATUS_BY_HOST + */ + safe_host->m_status_stats.aggregate(& m_status_stats); + m_status_stats.reset(); + return; + } + + /* + Aggregate STATUS_BY_ACCOUNT to: + - GLOBAL_STATUS + */ + m_status_stats.aggregate_to(& global_status_var); + m_status_stats.reset(); + return; +} + void PFS_account::aggregate_stats(PFS_user *safe_user, PFS_host *safe_host) { if (likely(safe_user != NULL && safe_host != NULL)) @@ -514,19 +606,42 @@ void PFS_account::release() dec_refcount(); } -PFS_account *sanitize_account(PFS_account *unsafe) +void PFS_account::carry_memory_stat_delta(PFS_memory_stat_delta *delta, uint index) { - if ((&account_array[0] <= unsafe) && - (unsafe < &account_array[account_max])) - return unsafe; - return NULL; + PFS_memory_stat *event_name_array; + PFS_memory_stat *stat; + PFS_memory_stat_delta delta_buffer; + PFS_memory_stat_delta *remaining_delta; + + event_name_array= write_instr_class_memory_stats(); + stat= & event_name_array[index]; + remaining_delta= stat->apply_delta(delta, &delta_buffer); + + if (remaining_delta == NULL) + return; + + if (m_user != NULL) + { + m_user->carry_memory_stat_delta(remaining_delta, index); + /* do not return, need to process m_host below */ + } + + if (m_host != NULL) + { + m_host->carry_memory_stat_delta(remaining_delta, index); + return; + } + + carry_global_memory_stat_delta(remaining_delta, index); } -void purge_account(PFS_thread *thread, PFS_account *account, - PFS_user *safe_user, PFS_host *safe_host) +PFS_account *sanitize_account(PFS_account *unsafe) { - account->aggregate(safe_user, safe_host); + return global_account_container.sanitize(unsafe); +} +void purge_account(PFS_thread *thread, PFS_account *account) +{ LF_PINS *pins= get_account_hash_pins(thread); if (unlikely(pins == NULL)) return; @@ -544,6 +659,7 @@ void purge_account(PFS_thread *thread, PFS_account *account, lf_hash_delete(&account_hash, pins, account->m_key.m_hash_key, account->m_key.m_key_length); + account->aggregate(false, account->m_user, account->m_host); if (account->m_user != NULL) { account->m_user->release(); @@ -554,37 +670,78 @@ void purge_account(PFS_thread *thread, PFS_account *account, account->m_host->release(); account->m_host= NULL; } - account->m_lock.allocated_to_free(); + global_account_container.deallocate(account); } } lf_hash_search_unpin(pins); } -/** Purge non connected user@host, reset stats of connected user@host. */ +class Proc_purge_account + : public PFS_buffer_processor<PFS_account> +{ +public: + Proc_purge_account(PFS_thread *thread) + : m_thread(thread) + {} + + virtual void operator()(PFS_account *pfs) + { + PFS_user *user= sanitize_user(pfs->m_user); + PFS_host *host= sanitize_host(pfs->m_host); + pfs->aggregate(true, user, host); + + if (pfs->get_refcount() == 0) + purge_account(m_thread, pfs); + } + +private: + PFS_thread *m_thread; +}; + +/** Purge non connected accounts, reset stats of connected account. */ 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; + Proc_purge_account proc(thread); + global_account_container.apply(proc); +} - for ( ; pfs < pfs_last; pfs++) +class Proc_update_accounts_derived_flags + : public PFS_buffer_processor<PFS_account> +{ +public: + Proc_update_accounts_derived_flags(PFS_thread *thread) + : m_thread(thread) + {} + + virtual void operator()(PFS_account *pfs) { - if (pfs->m_lock.is_populated()) + if (pfs->m_username_length > 0 && pfs->m_hostname_length > 0) { - 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); + lookup_setup_actor(m_thread, + pfs->m_username, pfs->m_username_length, + pfs->m_hostname, pfs->m_hostname_length, + & pfs->m_enabled, & pfs->m_history); + } + else + { + pfs->m_enabled= true; + pfs->m_history= true; } } + +private: + PFS_thread *m_thread; +}; + +void update_accounts_derived_flags(PFS_thread *thread) +{ + Proc_update_accounts_derived_flags proc(thread); + global_account_container.apply(proc); } /** @} */ diff --git a/storage/perfschema/pfs_account.h b/storage/perfschema/pfs_account.h index cd7b1520df5..8a966f4c4a9 100644 --- a/storage/perfschema/pfs_account.h +++ b/storage/perfschema/pfs_account.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -25,23 +25,26 @@ /** @file storage/perfschema/pfs_account.h - Performance schema user@host (declarations). + Performance schema account (declarations). */ #include "pfs_lock.h" #include "lf.h" #include "pfs_con_slice.h" +#include "mysql_com.h" /* USERNAME_LENGTH */ struct PFS_global_param; struct PFS_user; struct PFS_host; struct PFS_thread; +struct PFS_memory_stat_delta; /** @addtogroup Performance_schema_buffers @{ */ +/** Hash key for an account. */ struct PFS_account_key { /** @@ -53,6 +56,7 @@ struct PFS_account_key uint m_key_length; }; +/** Per account statistics. */ struct PFS_ALIGNED PFS_account : PFS_connection_slice { public: @@ -76,16 +80,25 @@ public: PFS_atomic::add_32(& m_refcount, -1); } - void aggregate(PFS_user *safe_user, PFS_host *safe_host); + void aggregate(bool alive, 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_transactions(PFS_user *safe_user, PFS_host *safe_host); + void aggregate_memory(bool alive, PFS_user *safe_user, PFS_host *safe_host); + void aggregate_status(PFS_user *safe_user, PFS_host *safe_host); void aggregate_stats(PFS_user *safe_user, PFS_host *safe_host); void release(void); + void carry_memory_stat_delta(PFS_memory_stat_delta *delta, uint index); + /** Internal lock. */ pfs_lock m_lock; PFS_account_key m_key; + /** True if this account is enabled, per rules in table SETUP_ACTORS. */ + bool m_enabled; + /** True if this account has history enabled, per rules in table SETUP_ACTORS. */ + bool m_history; const char *m_username; uint m_username_length; const char *m_hostname; @@ -101,7 +114,7 @@ private: int init_account(const PFS_global_param *param); void cleanup_account(void); -int init_account_hash(void); +int init_account_hash(const PFS_global_param *param); void cleanup_account_hash(void); PFS_account * @@ -112,15 +125,9 @@ find_or_create_account(PFS_thread *thread, PFS_account *sanitize_account(PFS_account *unsafe); void purge_all_account(void); +void update_accounts_derived_flags(PFS_thread *thread); -/* For iterators and show status. */ - -extern ulong account_max; -extern ulong account_lost; - -/* Exposing the data directly, for iterators. */ - -extern PFS_account *account_array; +/* For show status. */ extern LF_HASH account_hash; diff --git a/storage/perfschema/pfs_atomic.h b/storage/perfschema/pfs_atomic.h index 00d1197970b..959b66dccb2 100644 --- a/storage/perfschema/pfs_atomic.h +++ b/storage/perfschema/pfs_atomic.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -35,101 +35,101 @@ class PFS_atomic { public: /** Atomic load. */ - static inline int32 load_32(volatile int32 *ptr) + static inline int32 load_32(int32 *ptr) { return my_atomic_load32(ptr); } /** Atomic load. */ - static inline int64 load_64(volatile int64 *ptr) + static inline int64 load_64(int64 *ptr) { return my_atomic_load64(ptr); } /** Atomic load. */ - static inline uint32 load_u32(volatile uint32 *ptr) + static inline uint32 load_u32(uint32 *ptr) { return (uint32) my_atomic_load32((int32*) ptr); } /** Atomic load. */ - static inline uint64 load_u64(volatile uint64 *ptr) + static inline uint64 load_u64(uint64 *ptr) { return (uint64) my_atomic_load64((int64*) ptr); } /** Atomic store. */ - static inline void store_32(volatile int32 *ptr, int32 value) + static inline void store_32(int32 *ptr, int32 value) { my_atomic_store32(ptr, value); } /** Atomic store. */ - static inline void store_64(volatile int64 *ptr, int64 value) + static inline void store_64(int64 *ptr, int64 value) { my_atomic_store64(ptr, value); } /** Atomic store. */ - static inline void store_u32(volatile uint32 *ptr, uint32 value) + static inline void store_u32(uint32 *ptr, uint32 value) { my_atomic_store32((int32*) ptr, (int32) value); } /** Atomic store. */ - static inline void store_u64(volatile uint64 *ptr, uint64 value) + static inline void store_u64(uint64 *ptr, uint64 value) { my_atomic_store64((int64*) ptr, (int64) value); } /** Atomic add. */ - static inline int32 add_32(volatile int32 *ptr, int32 value) + static inline int32 add_32(int32 *ptr, int32 value) { return my_atomic_add32(ptr, value); } /** Atomic add. */ - static inline int64 add_64(volatile int64 *ptr, int64 value) + static inline int64 add_64(int64 *ptr, int64 value) { return my_atomic_add64(ptr, value); } /** Atomic add. */ - static inline uint32 add_u32(volatile uint32 *ptr, uint32 value) + static inline uint32 add_u32(uint32 *ptr, uint32 value) { return (uint32) my_atomic_add32((int32*) ptr, (int32) value); } /** Atomic add. */ - static inline uint64 add_u64(volatile uint64 *ptr, uint64 value) + static inline uint64 add_u64(uint64 *ptr, uint64 value) { return (uint64) my_atomic_add64((int64*) ptr, (int64) value); } /** Atomic compare and swap. */ - static inline bool cas_32(volatile int32 *ptr, int32 *old_value, + static inline bool cas_32(int32 *ptr, int32 *old_value, int32 new_value) { return my_atomic_cas32(ptr, old_value, new_value); } /** Atomic compare and swap. */ - static inline bool cas_64(volatile int64 *ptr, int64 *old_value, + static inline bool cas_64(int64 *ptr, int64 *old_value, int64 new_value) { return my_atomic_cas64(ptr, old_value, new_value); } /** Atomic compare and swap. */ - static inline bool cas_u32(volatile uint32 *ptr, uint32 *old_value, + static inline bool cas_u32(uint32 *ptr, uint32 *old_value, uint32 new_value) { return my_atomic_cas32((int32*) ptr, (int32*) old_value, - (uint32) new_value); + (uint32) new_value); } /** Atomic compare and swap. */ - static inline bool cas_u64(volatile uint64 *ptr, uint64 *old_value, + static inline bool cas_u64(uint64 *ptr, uint64 *old_value, uint64 new_value) { return my_atomic_cas64((int64*) ptr, (int64*) old_value, diff --git a/storage/perfschema/pfs_autosize.cc b/storage/perfschema/pfs_autosize.cc index e15a85fe2d6..024f5519c0e 100644 --- a/storage/perfschema/pfs_autosize.cc +++ b/storage/perfschema/pfs_autosize.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2012, 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, version 2.0, @@ -30,47 +30,17 @@ #include "pfs_server.h" #include "set_var.h" +#include "my_thread.h" /* For pthread_t */ +/* Make sure HAVE_PSI_XXX_INTERFACE flags are set */ +#include "mysql/psi/psi.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; - +/** Performance schema sizing heuristics. */ 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. */ @@ -83,103 +53,46 @@ struct PFS_sizing_data 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_events_transactions_history_sizing. */ + ulong m_events_transactions_history_sizing; + /** Default value for @c PFS_param.m_events_transactions_history_long_sizing. */ + ulong m_events_transactions_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 */ - 10, 100, 10, 100, 10, 100, + 5, 100, 5, 100, 5, 100, 5, 100, /* Digests */ 1000, /* Session connect attrs. */ - 512, - /* Min tables */ - 200, - /* Load factors */ - 0.90f, 0.90f, 0.90f + 512 }; PFS_sizing_data medium_data= { - /* Account / user / host */ - 100, 100, 100, /* History sizes */ - 20, 1000, 20, 1000, 20, 1000, + 10, 1000, 10, 1000, 10, 1000, 10, 1000, /* Digests */ 5000, /* Session connect attrs. */ - 512, - /* Min tables */ - 500, - /* Load factors */ - 0.70f, 0.80f, 0.90f + 512 }; PFS_sizing_data large_data= { - /* Account / user / host */ - 100, 100, 100, /* History sizes */ - 20, 10000, 20, 10000, 20, 10000, + 10, 10000, 10, 10000, 10, 10000, 10, 10000, /* Digests */ 10000, /* Session connect attrs. */ - 512, - /* Min tables */ - 10000, - /* Load factors */ - 0.50f, 0.65f, 0.80f + 512 }; -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) && @@ -204,47 +117,6 @@ PFS_sizing_data *estimate_hints(PFS_global_param *param) 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, @@ -287,107 +159,157 @@ static void apply_heuristic(PFS_global_param *p, PFS_sizing_data *h) h->m_digest_sizing); } - if (p->m_session_connect_attrs_sizing < 0) + if (p->m_events_transactions_history_sizing < 0) { - SYSVAR_AUTOSIZE(p->m_session_connect_attrs_sizing, - h->m_session_connect_attrs_sizing); + SYSVAR_AUTOSIZE(p->m_events_transactions_history_sizing, + h->m_events_transactions_history_sizing); } - if (p->m_mutex_sizing < 0) + if (p->m_events_transactions_history_long_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)); + SYSVAR_AUTOSIZE(p->m_events_transactions_history_long_sizing, + h->m_events_transactions_history_long_sizing); } - 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) + if (p->m_session_connect_attrs_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)); + SYSVAR_AUTOSIZE(p->m_session_connect_attrs_sizing, + h->m_session_connect_attrs_sizing); } +} - if (p->m_socket_sizing < 0) +void pfs_automated_sizing(PFS_global_param *param) +{ + if (param->m_enabled) { - 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)); +#ifndef HAVE_PSI_MUTEX_INTERFACE + param->m_mutex_class_sizing= 0; + param->m_mutex_sizing= 0; +#endif + +#ifndef HAVE_PSI_RWLOCK_INTERFACE + param->m_rwlock_class_sizing= 0; + param->m_rwlock_sizing= 0; +#endif + +#ifndef HAVE_PSI_COND_INTERFACE + param->m_cond_class_sizing= 0; + param->m_cond_sizing= 0; +#endif + +#ifndef HAVE_PSI_FILE_INTERFACE + param->m_file_class_sizing= 0; + param->m_file_sizing= 0; + param->m_file_handle_sizing= 0; +#endif + +#ifndef HAVE_PSI_TABLE_INTERFACE + param->m_table_share_sizing= 0; + param->m_table_sizing= 0; + param->m_table_lock_stat_sizing= 0; + param->m_index_stat_sizing= 0; +#endif + +#ifndef HAVE_PSI_SOCKET_INTERFACE + param->m_socket_class_sizing= 0; + param->m_socket_sizing= 0; +#endif + +#ifndef HAVE_PSI_STAGE_INTERFACE + param->m_stage_class_sizing= 0; + param->m_events_stages_history_sizing= 0; + param->m_events_stages_history_long_sizing= 0; +#endif + +#ifndef HAVE_PSI_STATEMENT_INTERFACE + param->m_statement_class_sizing= 0; + param->m_events_statements_history_sizing= 0; + param->m_events_statements_history_long_sizing= 0; +#endif + +#ifndef HAVE_PSI_SP_INTERFACE + param->m_program_sizing= 0; + if (param->m_statement_stack_sizing > 1) + param->m_statement_stack_sizing= 1; +#endif + +#ifndef HAVE_PSI_PS_INTERFACE + param->m_prepared_stmt_sizing= 0; +#endif + +#ifndef HAVE_PSI_STATEMENT_DIGEST_INTERFACE + param->m_digest_sizing= 0; +#endif + +#ifndef HAVE_PSI_METADATA_INTERFACE + param->m_metadata_lock_sizing= 0; +#endif + +#ifndef HAVE_PSI_MEMORY_INTERFACE + param->m_memory_class_sizing= 0; +#endif + + PFS_sizing_data *heuristic; + heuristic= estimate_hints(param); + apply_heuristic(param, heuristic); + + 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_events_transactions_history_sizing >= 0); + DBUG_ASSERT(param->m_events_transactions_history_long_sizing >= 0); + DBUG_ASSERT(param->m_session_connect_attrs_sizing >= 0); } - - if (p->m_thread_sizing < 0) + else { - 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)); + /* + The Performance Schema is disabled. Set the instrument sizings to zero to + disable all instrumentation while retaining support for the status and + system variable tables, the host cache table and the replication tables. + */ + SYSVAR_AUTOSIZE(param->m_mutex_class_sizing, 0); + SYSVAR_AUTOSIZE(param->m_rwlock_class_sizing, 0); + SYSVAR_AUTOSIZE(param->m_cond_class_sizing, 0); + SYSVAR_AUTOSIZE(param->m_thread_class_sizing, 0); + SYSVAR_AUTOSIZE(param->m_table_share_sizing, 0); + SYSVAR_AUTOSIZE(param->m_table_lock_stat_sizing, 0); + SYSVAR_AUTOSIZE(param->m_index_stat_sizing, 0); + SYSVAR_AUTOSIZE(param->m_file_class_sizing, 0); + SYSVAR_AUTOSIZE(param->m_mutex_sizing, 0); + SYSVAR_AUTOSIZE(param->m_rwlock_sizing, 0); + SYSVAR_AUTOSIZE(param->m_cond_sizing, 0); + SYSVAR_AUTOSIZE(param->m_thread_sizing, 0); + SYSVAR_AUTOSIZE(param->m_table_sizing, 0); + SYSVAR_AUTOSIZE(param->m_file_sizing, 0); + SYSVAR_AUTOSIZE(param->m_file_handle_sizing, 0); + SYSVAR_AUTOSIZE(param->m_socket_sizing, 0); + SYSVAR_AUTOSIZE(param->m_socket_class_sizing, 0); + SYSVAR_AUTOSIZE(param->m_events_waits_history_sizing, 0); + SYSVAR_AUTOSIZE(param->m_events_waits_history_long_sizing, 0); + SYSVAR_AUTOSIZE(param->m_setup_actor_sizing, 0); + SYSVAR_AUTOSIZE(param->m_setup_object_sizing, 0); + SYSVAR_AUTOSIZE(param->m_host_sizing, 0); + SYSVAR_AUTOSIZE(param->m_user_sizing, 0); + SYSVAR_AUTOSIZE(param->m_account_sizing, 0); + SYSVAR_AUTOSIZE(param->m_stage_class_sizing, 0); + SYSVAR_AUTOSIZE(param->m_events_stages_history_sizing, 0); + SYSVAR_AUTOSIZE(param->m_events_stages_history_long_sizing, 0); + SYSVAR_AUTOSIZE(param->m_statement_class_sizing, 0); + SYSVAR_AUTOSIZE(param->m_events_statements_history_sizing, 0); + SYSVAR_AUTOSIZE(param->m_events_statements_history_long_sizing, 0); + SYSVAR_AUTOSIZE(param->m_digest_sizing, 0); + SYSVAR_AUTOSIZE(param->m_program_sizing, 0); + SYSVAR_AUTOSIZE(param->m_prepared_stmt_sizing, 0); + SYSVAR_AUTOSIZE(param->m_events_transactions_history_sizing, 0); + SYSVAR_AUTOSIZE(param->m_events_transactions_history_long_sizing, 0); + SYSVAR_AUTOSIZE(param->m_session_connect_attrs_sizing, 0); + SYSVAR_AUTOSIZE(param->m_statement_stack_sizing, 0); + SYSVAR_AUTOSIZE(param->m_memory_class_sizing, 0); + SYSVAR_AUTOSIZE(param->m_metadata_lock_sizing, 0); + SYSVAR_AUTOSIZE(param->m_max_digest_length, 0); + SYSVAR_AUTOSIZE(param->m_max_sql_text_length, 0); } } - -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_buffer_container.cc b/storage/perfschema/pfs_buffer_container.cc new file mode 100644 index 00000000000..cd87cb247e2 --- /dev/null +++ b/storage/perfschema/pfs_buffer_container.cc @@ -0,0 +1,883 @@ +/* Copyright (c) 2014, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include "my_global.h" +#include "pfs_global.h" +#include "pfs_lock.h" +#include "pfs_account.h" +#include "pfs_user.h" +#include "pfs_host.h" +#include "pfs_buffer_container.h" +#include "pfs_builtin_memory.h" + +PFS_buffer_default_allocator<PFS_mutex> default_mutex_allocator(& builtin_memory_mutex); +PFS_mutex_container global_mutex_container(& default_mutex_allocator); + +PFS_buffer_default_allocator<PFS_rwlock> default_rwlock_allocator(& builtin_memory_rwlock); +PFS_rwlock_container global_rwlock_container(& default_rwlock_allocator); + +PFS_buffer_default_allocator<PFS_cond> default_cond_allocator(& builtin_memory_cond); +PFS_cond_container global_cond_container(& default_cond_allocator); + +PFS_buffer_default_allocator<PFS_file> default_file_allocator(& builtin_memory_file); +PFS_file_container global_file_container(& default_file_allocator); + +PFS_buffer_default_allocator<PFS_socket> default_socket_allocator(& builtin_memory_socket); +PFS_socket_container global_socket_container(& default_socket_allocator); + +PFS_buffer_default_allocator<PFS_metadata_lock> default_mdl_allocator(& builtin_memory_mdl); +PFS_mdl_container global_mdl_container(& default_mdl_allocator); + +PFS_buffer_default_allocator<PFS_setup_actor> default_setup_actor_allocator(& builtin_memory_setup_actor); +PFS_setup_actor_container global_setup_actor_container(& default_setup_actor_allocator); + +PFS_buffer_default_allocator<PFS_setup_object> default_setup_object_allocator(& builtin_memory_setup_object); +PFS_setup_object_container global_setup_object_container(& default_setup_object_allocator); + +PFS_buffer_default_allocator<PFS_table> default_table_allocator(& builtin_memory_table); +PFS_table_container global_table_container(& default_table_allocator); + +PFS_buffer_default_allocator<PFS_table_share> default_table_share_allocator(& builtin_memory_table_share); +PFS_table_share_container global_table_share_container(& default_table_share_allocator); + +PFS_buffer_default_allocator<PFS_table_share_index> default_table_share_index_allocator(& builtin_memory_table_share_index); +PFS_table_share_index_container global_table_share_index_container(& default_table_share_index_allocator); + +PFS_buffer_default_allocator<PFS_table_share_lock> default_table_share_lock_allocator(& builtin_memory_table_share_lock); +PFS_table_share_lock_container global_table_share_lock_container(& default_table_share_lock_allocator); + +PFS_buffer_default_allocator<PFS_program> default_program_allocator(& builtin_memory_program); +PFS_program_container global_program_container(& default_program_allocator); + +PFS_buffer_default_allocator<PFS_prepared_stmt> default_prepared_stmt_allocator(& builtin_memory_prepared_stmt); +PFS_prepared_stmt_container global_prepared_stmt_container(& default_prepared_stmt_allocator); + +int PFS_account_allocator::alloc_array(PFS_account_array *array) +{ + size_t size= array->m_max; + size_t index; + size_t waits_sizing= size * wait_class_max; + size_t stages_sizing= size * stage_class_max; + size_t statements_sizing= size * statement_class_max; + size_t transactions_sizing= size * transaction_class_max; + size_t memory_sizing= size * memory_class_max; + + array->m_ptr= NULL; + array->m_full= true; + array->m_instr_class_waits_array= NULL; + array->m_instr_class_stages_array= NULL; + array->m_instr_class_statements_array= NULL; + array->m_instr_class_transactions_array= NULL; + array->m_instr_class_memory_array= NULL; + + if (size > 0) + { + array->m_ptr= + PFS_MALLOC_ARRAY(& builtin_memory_account, + size, sizeof(PFS_account), PFS_account, MYF(MY_ZEROFILL)); + if (array->m_ptr == NULL) + return 1; + } + + if (waits_sizing > 0) + { + array->m_instr_class_waits_array= + PFS_MALLOC_ARRAY(& builtin_memory_account_waits, + waits_sizing, sizeof(PFS_single_stat), PFS_single_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_waits_array == NULL) + return 1; + + for (index=0; index < waits_sizing; index++) + array->m_instr_class_waits_array[index].reset(); + } + + if (stages_sizing > 0) + { + array->m_instr_class_stages_array= + PFS_MALLOC_ARRAY(& builtin_memory_account_stages, + stages_sizing, sizeof(PFS_stage_stat), PFS_stage_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_stages_array == NULL) + return 1; + + for (index=0; index < stages_sizing; index++) + array->m_instr_class_stages_array[index].reset(); + } + + if (statements_sizing > 0) + { + array->m_instr_class_statements_array= + PFS_MALLOC_ARRAY(& builtin_memory_account_statements, + statements_sizing, sizeof(PFS_statement_stat), PFS_statement_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_statements_array == NULL) + return 1; + + for (index=0; index < statements_sizing; index++) + array->m_instr_class_statements_array[index].reset(); + } + + if (transactions_sizing > 0) + { + array->m_instr_class_transactions_array= + PFS_MALLOC_ARRAY(& builtin_memory_account_transactions, + transactions_sizing, sizeof(PFS_transaction_stat), PFS_transaction_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_transactions_array == NULL) + return 1; + + for (index=0; index < transactions_sizing; index++) + array->m_instr_class_transactions_array[index].reset(); + } + + if (memory_sizing > 0) + { + array->m_instr_class_memory_array= + PFS_MALLOC_ARRAY(& builtin_memory_account_memory, + memory_sizing, sizeof(PFS_memory_stat), PFS_memory_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_memory_array == NULL) + return 1; + + for (index=0; index < memory_sizing; index++) + array->m_instr_class_memory_array[index].reset(); + } + + for (index= 0; index < size; index++) + { + array->m_ptr[index].set_instr_class_waits_stats( + & array->m_instr_class_waits_array[index * wait_class_max]); + array->m_ptr[index].set_instr_class_stages_stats( + & array->m_instr_class_stages_array[index * stage_class_max]); + array->m_ptr[index].set_instr_class_statements_stats( + & array->m_instr_class_statements_array[index * statement_class_max]); + array->m_ptr[index].set_instr_class_transactions_stats( + & array->m_instr_class_transactions_array[index * transaction_class_max]); + array->m_ptr[index].set_instr_class_memory_stats( + & array->m_instr_class_memory_array[index * memory_class_max]); + } + + array->m_full= false; + return 0; +} + +void PFS_account_allocator::free_array(PFS_account_array *array) +{ + size_t size= array->m_max; + size_t waits_sizing= size * wait_class_max; + size_t stages_sizing= size * stage_class_max; + size_t statements_sizing= size * statement_class_max; + size_t transactions_sizing= size * transaction_class_max; + size_t memory_sizing= size * memory_class_max; + + PFS_FREE_ARRAY(& builtin_memory_account, + size, sizeof(PFS_account), array->m_ptr); + array->m_ptr= NULL; + + PFS_FREE_ARRAY(& builtin_memory_account_waits, + waits_sizing, sizeof(PFS_single_stat), + array->m_instr_class_waits_array); + array->m_instr_class_waits_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_account_stages, + stages_sizing, sizeof(PFS_stage_stat), + array->m_instr_class_stages_array); + array->m_instr_class_stages_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_account_statements, + statements_sizing, sizeof(PFS_statement_stat), + array->m_instr_class_statements_array); + array->m_instr_class_statements_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_account_transactions, + transactions_sizing, sizeof(PFS_transaction_stat), + array->m_instr_class_transactions_array); + array->m_instr_class_transactions_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_account_memory, + memory_sizing, sizeof(PFS_memory_stat), + array->m_instr_class_memory_array); + array->m_instr_class_memory_array= NULL; +} + +PFS_account_allocator account_allocator; +PFS_account_container global_account_container(& account_allocator); + +int PFS_host_allocator::alloc_array(PFS_host_array *array) +{ + size_t size= array->m_max; + PFS_host *pfs; + size_t index; + size_t waits_sizing= size * wait_class_max; + size_t stages_sizing= size * stage_class_max; + size_t statements_sizing= size * statement_class_max; + size_t transactions_sizing= size * transaction_class_max; + size_t memory_sizing= size * memory_class_max; + + array->m_ptr= NULL; + array->m_full= true; + array->m_instr_class_waits_array= NULL; + array->m_instr_class_stages_array= NULL; + array->m_instr_class_statements_array= NULL; + array->m_instr_class_transactions_array= NULL; + array->m_instr_class_memory_array= NULL; + + if (size > 0) + { + array->m_ptr= + PFS_MALLOC_ARRAY(& builtin_memory_host, + size, sizeof(PFS_host), PFS_host, MYF(MY_ZEROFILL)); + if (array->m_ptr == NULL) + return 1; + } + + if (waits_sizing > 0) + { + array->m_instr_class_waits_array= + PFS_MALLOC_ARRAY(& builtin_memory_host_waits, + waits_sizing, sizeof(PFS_single_stat), PFS_single_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_waits_array == NULL) + return 1; + + for (index=0; index < waits_sizing; index++) + array->m_instr_class_waits_array[index].reset(); + } + + if (stages_sizing > 0) + { + array->m_instr_class_stages_array= + PFS_MALLOC_ARRAY(& builtin_memory_host_stages, + stages_sizing, sizeof(PFS_stage_stat), PFS_stage_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_stages_array == NULL) + return 1; + + for (index=0; index < stages_sizing; index++) + array->m_instr_class_stages_array[index].reset(); + } + + if (statements_sizing > 0) + { + array->m_instr_class_statements_array= + PFS_MALLOC_ARRAY(& builtin_memory_host_statements, + statements_sizing, sizeof(PFS_statement_stat), PFS_statement_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_statements_array == NULL) + return 1; + + for (index=0; index < statements_sizing; index++) + array->m_instr_class_statements_array[index].reset(); + } + + if (transactions_sizing > 0) + { + array->m_instr_class_transactions_array= + PFS_MALLOC_ARRAY(& builtin_memory_host_transactions, + transactions_sizing, sizeof(PFS_transaction_stat), PFS_transaction_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_transactions_array == NULL) + return 1; + + for (index=0; index < transactions_sizing; index++) + array->m_instr_class_transactions_array[index].reset(); + } + + if (memory_sizing > 0) + { + array->m_instr_class_memory_array= + PFS_MALLOC_ARRAY(& builtin_memory_host_memory, + memory_sizing, sizeof(PFS_memory_stat), PFS_memory_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_memory_array == NULL) + return 1; + + for (index=0; index < memory_sizing; index++) + array->m_instr_class_memory_array[index].reset(); + } + + for (index= 0; index < size; index++) + { + pfs= & array->m_ptr[index]; + + pfs->set_instr_class_waits_stats( + & array->m_instr_class_waits_array[index * wait_class_max]); + pfs->set_instr_class_stages_stats( + & array->m_instr_class_stages_array[index * stage_class_max]); + pfs->set_instr_class_statements_stats( + & array->m_instr_class_statements_array[index * statement_class_max]); + pfs->set_instr_class_transactions_stats( + & array->m_instr_class_transactions_array[index * transaction_class_max]); + pfs->set_instr_class_memory_stats( + & array->m_instr_class_memory_array[index * memory_class_max]); + } + + array->m_full= false; + return 0; +} + +void PFS_host_allocator::free_array(PFS_host_array *array) +{ + size_t size= array->m_max; + size_t waits_sizing= size * wait_class_max; + size_t stages_sizing= size * stage_class_max; + size_t statements_sizing= size * statement_class_max; + size_t transactions_sizing= size * transaction_class_max; + size_t memory_sizing= size * memory_class_max; + + PFS_FREE_ARRAY(& builtin_memory_host, + size, sizeof(PFS_host), array->m_ptr); + array->m_ptr= NULL; + + PFS_FREE_ARRAY(& builtin_memory_host_waits, + waits_sizing, sizeof(PFS_single_stat), + array->m_instr_class_waits_array); + array->m_instr_class_waits_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_host_stages, + stages_sizing, sizeof(PFS_stage_stat), + array->m_instr_class_stages_array); + array->m_instr_class_stages_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_host_statements, + statements_sizing, sizeof(PFS_statement_stat), + array->m_instr_class_statements_array); + array->m_instr_class_statements_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_host_transactions, + transactions_sizing, sizeof(PFS_transaction_stat), + array->m_instr_class_transactions_array); + array->m_instr_class_transactions_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_host_memory, + memory_sizing, sizeof(PFS_memory_stat), + array->m_instr_class_memory_array); + array->m_instr_class_memory_array= NULL; +} + +PFS_host_allocator host_allocator; +PFS_host_container global_host_container(& host_allocator); + +int PFS_thread_allocator::alloc_array(PFS_thread_array *array) +{ + size_t size= array->m_max; + PFS_thread *pfs; + PFS_events_statements *pfs_stmt; + unsigned char *pfs_tokens; + + size_t index; + size_t waits_sizing= size * wait_class_max; + size_t stages_sizing= size * stage_class_max; + size_t statements_sizing= size * statement_class_max; + size_t transactions_sizing= size * transaction_class_max; + size_t memory_sizing= size * memory_class_max; + + size_t waits_history_sizing= size * events_waits_history_per_thread; + size_t stages_history_sizing= size * events_stages_history_per_thread; + size_t statements_history_sizing= size * events_statements_history_per_thread; + size_t statements_stack_sizing= size * statement_stack_max; + size_t transactions_history_sizing= size * events_transactions_history_per_thread; + size_t session_connect_attrs_sizing= size * session_connect_attrs_size_per_thread; + + size_t current_sqltext_sizing= size * pfs_max_sqltext * statement_stack_max; + size_t history_sqltext_sizing= size * pfs_max_sqltext * events_statements_history_per_thread; + size_t current_digest_tokens_sizing= size * pfs_max_digest_length * statement_stack_max; + size_t history_digest_tokens_sizing= size * pfs_max_digest_length * events_statements_history_per_thread; + + array->m_ptr= NULL; + array->m_full= true; + array->m_instr_class_waits_array= NULL; + array->m_instr_class_stages_array= NULL; + array->m_instr_class_statements_array= NULL; + array->m_instr_class_transactions_array= NULL; + array->m_instr_class_memory_array= NULL; + + array->m_waits_history_array= NULL; + array->m_stages_history_array= NULL; + array->m_statements_history_array= NULL; + array->m_statements_stack_array= NULL; + array->m_transactions_history_array= NULL; + array->m_session_connect_attrs_array= NULL; + + array->m_current_stmts_text_array= NULL; + array->m_current_stmts_digest_token_array= NULL; + array->m_history_stmts_text_array= NULL; + array->m_history_stmts_digest_token_array= NULL; + + if (size > 0) + { + array->m_ptr= + PFS_MALLOC_ARRAY(& builtin_memory_thread, + size, sizeof(PFS_thread), PFS_thread, MYF(MY_ZEROFILL)); + if (array->m_ptr == NULL) + return 1; + } + + if (waits_sizing > 0) + { + array->m_instr_class_waits_array= + PFS_MALLOC_ARRAY(& builtin_memory_thread_waits, + waits_sizing, sizeof(PFS_single_stat), PFS_single_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_waits_array == NULL) + return 1; + + for (index=0; index < waits_sizing; index++) + array->m_instr_class_waits_array[index].reset(); + } + + if (stages_sizing > 0) + { + array->m_instr_class_stages_array= + PFS_MALLOC_ARRAY(& builtin_memory_thread_stages, + stages_sizing, sizeof(PFS_stage_stat), PFS_stage_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_stages_array == NULL) + return 1; + + for (index=0; index < stages_sizing; index++) + array->m_instr_class_stages_array[index].reset(); + } + + if (statements_sizing > 0) + { + array->m_instr_class_statements_array= + PFS_MALLOC_ARRAY(& builtin_memory_thread_statements, + statements_sizing, sizeof(PFS_statement_stat), PFS_statement_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_statements_array == NULL) + return 1; + + for (index=0; index < statements_sizing; index++) + array->m_instr_class_statements_array[index].reset(); + } + + if (transactions_sizing > 0) + { + array->m_instr_class_transactions_array= + PFS_MALLOC_ARRAY(& builtin_memory_thread_transactions, + transactions_sizing, sizeof(PFS_transaction_stat), PFS_transaction_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_transactions_array == NULL) + return 1; + + for (index=0; index < transactions_sizing; index++) + array->m_instr_class_transactions_array[index].reset(); + } + + if (memory_sizing > 0) + { + array->m_instr_class_memory_array= + PFS_MALLOC_ARRAY(& builtin_memory_thread_memory, + memory_sizing, sizeof(PFS_memory_stat), PFS_memory_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_memory_array == NULL) + return 1; + + for (index=0; index < memory_sizing; index++) + array->m_instr_class_memory_array[index].reset(); + } + + if (waits_history_sizing > 0) + { + array->m_waits_history_array= + PFS_MALLOC_ARRAY(& builtin_memory_thread_waits_history, + waits_history_sizing, sizeof(PFS_events_waits), PFS_events_waits, MYF(MY_ZEROFILL)); + if (unlikely(array->m_waits_history_array == NULL)) + return 1; + } + + if (stages_history_sizing > 0) + { + array->m_stages_history_array= + PFS_MALLOC_ARRAY(& builtin_memory_thread_stages_history, + stages_history_sizing, sizeof(PFS_events_stages), PFS_events_stages, MYF(MY_ZEROFILL)); + if (unlikely(array->m_stages_history_array == NULL)) + return 1; + } + + if (statements_history_sizing > 0) + { + array->m_statements_history_array= + PFS_MALLOC_ARRAY(& builtin_memory_thread_statements_history, + statements_history_sizing, sizeof(PFS_events_statements), PFS_events_statements, MYF(MY_ZEROFILL)); + if (unlikely(array->m_statements_history_array == NULL)) + return 1; + } + + if (statements_stack_sizing > 0) + { + array->m_statements_stack_array= + PFS_MALLOC_ARRAY(& builtin_memory_thread_statements_stack, + statements_stack_sizing, sizeof(PFS_events_statements), PFS_events_statements, MYF(MY_ZEROFILL)); + if (unlikely(array->m_statements_stack_array == NULL)) + return 1; + } + + if (transactions_history_sizing > 0) + { + array->m_transactions_history_array= + PFS_MALLOC_ARRAY(& builtin_memory_thread_transaction_history, + transactions_history_sizing, sizeof(PFS_events_transactions), PFS_events_transactions, MYF(MY_ZEROFILL)); + if (unlikely(array->m_transactions_history_array == NULL)) + return 1; + } + + if (session_connect_attrs_sizing > 0) + { + array->m_session_connect_attrs_array= + (char *)pfs_malloc(& builtin_memory_thread_session_connect_attrs, + session_connect_attrs_sizing, MYF(MY_ZEROFILL)); + if (unlikely(array->m_session_connect_attrs_array == NULL)) + return 1; + } + + if (current_sqltext_sizing > 0) + { + array->m_current_stmts_text_array= + (char *)pfs_malloc(& builtin_memory_thread_statements_stack_sqltext, + current_sqltext_sizing, MYF(MY_ZEROFILL)); + if (unlikely(array->m_current_stmts_text_array == NULL)) + return 1; + } + + if (history_sqltext_sizing > 0) + { + array->m_history_stmts_text_array= + (char *)pfs_malloc(& builtin_memory_thread_statements_history_sqltext, + history_sqltext_sizing, MYF(MY_ZEROFILL)); + if (unlikely(array->m_history_stmts_text_array == NULL)) + return 1; + } + + if (current_digest_tokens_sizing > 0) + { + array->m_current_stmts_digest_token_array= + (unsigned char *)pfs_malloc(& builtin_memory_thread_statements_stack_tokens, + current_digest_tokens_sizing, MYF(MY_ZEROFILL)); + if (unlikely(array->m_current_stmts_digest_token_array == NULL)) + return 1; + } + + if (history_digest_tokens_sizing > 0) + { + array->m_history_stmts_digest_token_array= + (unsigned char *)pfs_malloc(& builtin_memory_thread_statements_history_tokens, + history_digest_tokens_sizing, MYF(MY_ZEROFILL)); + if (unlikely(array->m_history_stmts_digest_token_array == NULL)) + return 1; + } + + for (index= 0; index < size; index++) + { + pfs= & array->m_ptr[index]; + + pfs->set_instr_class_waits_stats( + & array->m_instr_class_waits_array[index * wait_class_max]); + pfs->set_instr_class_stages_stats( + & array->m_instr_class_stages_array[index * stage_class_max]); + pfs->set_instr_class_statements_stats( + & array->m_instr_class_statements_array[index * statement_class_max]); + pfs->set_instr_class_transactions_stats( + & array->m_instr_class_transactions_array[index * transaction_class_max]); + pfs->set_instr_class_memory_stats( + & array->m_instr_class_memory_array[index * memory_class_max]); + + pfs->m_waits_history= + & array->m_waits_history_array[index * events_waits_history_per_thread]; + pfs->m_stages_history= + & array->m_stages_history_array[index * events_stages_history_per_thread]; + pfs->m_statements_history= + & array->m_statements_history_array[index * events_statements_history_per_thread]; + pfs->m_statement_stack= + & array->m_statements_stack_array[index * statement_stack_max]; + pfs->m_transactions_history= + & array->m_transactions_history_array[index * events_transactions_history_per_thread]; + pfs->m_session_connect_attrs= + & array->m_session_connect_attrs_array[index * session_connect_attrs_size_per_thread]; + } + + for (index= 0; index < statements_stack_sizing; index++) + { + pfs_stmt= & array->m_statements_stack_array[index]; + + pfs_stmt->m_sqltext= & array->m_current_stmts_text_array[index * pfs_max_sqltext]; + + pfs_tokens= & array->m_current_stmts_digest_token_array[index * pfs_max_digest_length]; + pfs_stmt->m_digest_storage.reset(pfs_tokens, pfs_max_digest_length); + } + + for (index= 0; index < statements_history_sizing; index++) + { + pfs_stmt= & array->m_statements_history_array[index]; + + pfs_stmt->m_sqltext= & array->m_history_stmts_text_array[index * pfs_max_sqltext]; + + pfs_tokens= & array->m_history_stmts_digest_token_array[index * pfs_max_digest_length]; + pfs_stmt->m_digest_storage.reset(pfs_tokens, pfs_max_digest_length); + } + + array->m_full= false; + return 0; +} + +void PFS_thread_allocator::free_array(PFS_thread_array *array) +{ + size_t size= array->m_max; + size_t waits_sizing= size * wait_class_max; + size_t stages_sizing= size * stage_class_max; + size_t statements_sizing= size * statement_class_max; + size_t transactions_sizing= size * transaction_class_max; + size_t memory_sizing= size * memory_class_max; + + size_t waits_history_sizing= size * events_waits_history_per_thread; + size_t stages_history_sizing= size * events_stages_history_per_thread; + size_t statements_history_sizing= size * events_statements_history_per_thread; + size_t statements_stack_sizing= size * statement_stack_max; + size_t transactions_history_sizing= size * events_transactions_history_per_thread; + size_t session_connect_attrs_sizing= size * session_connect_attrs_size_per_thread; + + size_t current_sqltext_sizing= size * pfs_max_sqltext * statement_stack_max; + size_t history_sqltext_sizing= size * pfs_max_sqltext * events_statements_history_per_thread; + size_t current_digest_tokens_sizing= size * pfs_max_digest_length * statement_stack_max; + size_t history_digest_tokens_sizing= size * pfs_max_digest_length * events_statements_history_per_thread; + + PFS_FREE_ARRAY(& builtin_memory_thread, + size, sizeof(PFS_thread), array->m_ptr); + array->m_ptr= NULL; + + PFS_FREE_ARRAY(& builtin_memory_thread_waits, + waits_sizing, sizeof(PFS_single_stat), + array->m_instr_class_waits_array); + array->m_instr_class_waits_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_thread_stages, + stages_sizing, sizeof(PFS_stage_stat), + array->m_instr_class_stages_array); + array->m_instr_class_stages_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_thread_statements, + statements_sizing, sizeof(PFS_statement_stat), + array->m_instr_class_statements_array); + array->m_instr_class_statements_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_thread_transactions, + transactions_sizing, sizeof(PFS_transaction_stat), + array->m_instr_class_transactions_array); + array->m_instr_class_transactions_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_thread_memory, + memory_sizing, sizeof(PFS_memory_stat), + array->m_instr_class_memory_array); + array->m_instr_class_memory_array= NULL; + + + PFS_FREE_ARRAY(& builtin_memory_thread_waits_history, + waits_history_sizing, sizeof(PFS_events_waits), + array->m_waits_history_array); + array->m_waits_history_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_thread_stages_history, + stages_history_sizing, sizeof(PFS_events_stages), + array->m_stages_history_array); + array->m_stages_history_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_thread_statements_history, + statements_history_sizing, sizeof(PFS_events_statements), + array->m_statements_history_array); + array->m_statements_history_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_thread_statements_stack, + statements_stack_sizing, sizeof(PFS_events_statements), + array->m_statements_stack_array); + array->m_statements_stack_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_thread_transaction_history, + transactions_history_sizing, sizeof(PFS_events_transactions), + array->m_transactions_history_array); + array->m_transactions_history_array= NULL; + + pfs_free(& builtin_memory_thread_session_connect_attrs, + session_connect_attrs_sizing, + array->m_session_connect_attrs_array); + array->m_session_connect_attrs_array= NULL; + + pfs_free(& builtin_memory_thread_statements_stack_sqltext, + current_sqltext_sizing, + array->m_current_stmts_text_array); + array->m_current_stmts_text_array= NULL; + + pfs_free(& builtin_memory_thread_statements_history_sqltext, + history_sqltext_sizing, + array->m_history_stmts_text_array); + array->m_history_stmts_text_array= NULL; + + pfs_free(& builtin_memory_thread_statements_stack_tokens, + current_digest_tokens_sizing, + array->m_current_stmts_digest_token_array); + array->m_current_stmts_digest_token_array= NULL; + + pfs_free(& builtin_memory_thread_statements_history_tokens, + history_digest_tokens_sizing, + array->m_history_stmts_digest_token_array); + array->m_history_stmts_digest_token_array= NULL; +} + +PFS_thread_allocator thread_allocator; +PFS_thread_container global_thread_container(& thread_allocator); + +int PFS_user_allocator::alloc_array(PFS_user_array *array) +{ + size_t size= array->m_max; + PFS_user *pfs; + size_t index; + size_t waits_sizing= size * wait_class_max; + size_t stages_sizing= size * stage_class_max; + size_t statements_sizing= size * statement_class_max; + size_t transactions_sizing= size * transaction_class_max; + size_t memory_sizing= size * memory_class_max; + + array->m_ptr= NULL; + array->m_full= true; + array->m_instr_class_waits_array= NULL; + array->m_instr_class_stages_array= NULL; + array->m_instr_class_statements_array= NULL; + array->m_instr_class_transactions_array= NULL; + array->m_instr_class_memory_array= NULL; + + if (size > 0) + { + array->m_ptr= + PFS_MALLOC_ARRAY(& builtin_memory_user, + size, sizeof(PFS_user), PFS_user, MYF(MY_ZEROFILL)); + if (array->m_ptr == NULL) + return 1; + } + + if (waits_sizing > 0) + { + array->m_instr_class_waits_array= + PFS_MALLOC_ARRAY(& builtin_memory_user_waits, + waits_sizing, sizeof(PFS_single_stat), PFS_single_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_waits_array == NULL) + return 1; + + for (index=0; index < waits_sizing; index++) + array->m_instr_class_waits_array[index].reset(); + } + + if (stages_sizing > 0) + { + array->m_instr_class_stages_array= + PFS_MALLOC_ARRAY(& builtin_memory_user_stages, + stages_sizing, sizeof(PFS_stage_stat), PFS_stage_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_stages_array == NULL) + return 1; + + for (index=0; index < stages_sizing; index++) + array->m_instr_class_stages_array[index].reset(); + } + + if (statements_sizing > 0) + { + array->m_instr_class_statements_array= + PFS_MALLOC_ARRAY(& builtin_memory_user_statements, + statements_sizing, sizeof(PFS_statement_stat), PFS_statement_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_statements_array == NULL) + return 1; + + for (index=0; index < statements_sizing; index++) + array->m_instr_class_statements_array[index].reset(); + } + + if (transactions_sizing > 0) + { + array->m_instr_class_transactions_array= + PFS_MALLOC_ARRAY(& builtin_memory_user_transactions, + transactions_sizing, sizeof(PFS_transaction_stat), PFS_transaction_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_transactions_array == NULL) + return 1; + + for (index=0; index < transactions_sizing; index++) + array->m_instr_class_transactions_array[index].reset(); + } + + if (memory_sizing > 0) + { + array->m_instr_class_memory_array= + PFS_MALLOC_ARRAY(& builtin_memory_user_memory, + memory_sizing, sizeof(PFS_memory_stat), PFS_memory_stat, MYF(MY_ZEROFILL)); + if (array->m_instr_class_memory_array == NULL) + return 1; + + for (index=0; index < memory_sizing; index++) + array->m_instr_class_memory_array[index].reset(); + } + + for (index= 0; index < size; index++) + { + pfs= & array->m_ptr[index]; + + pfs->set_instr_class_waits_stats( + & array->m_instr_class_waits_array[index * wait_class_max]); + pfs->set_instr_class_stages_stats( + & array->m_instr_class_stages_array[index * stage_class_max]); + pfs->set_instr_class_statements_stats( + & array->m_instr_class_statements_array[index * statement_class_max]); + pfs->set_instr_class_transactions_stats( + & array->m_instr_class_transactions_array[index * transaction_class_max]); + pfs->set_instr_class_memory_stats( + & array->m_instr_class_memory_array[index * memory_class_max]); + } + + array->m_full= false; + return 0; +} + +void PFS_user_allocator::free_array(PFS_user_array *array) +{ + size_t size= array->m_max; + size_t waits_sizing= size * wait_class_max; + size_t stages_sizing= size * stage_class_max; + size_t statements_sizing= size * statement_class_max; + size_t transactions_sizing= size * transaction_class_max; + size_t memory_sizing= size * memory_class_max; + + PFS_FREE_ARRAY(& builtin_memory_user, + size, sizeof(PFS_user), array->m_ptr); + array->m_ptr= NULL; + + PFS_FREE_ARRAY(& builtin_memory_user_waits, + waits_sizing, sizeof(PFS_single_stat), + array->m_instr_class_waits_array); + array->m_instr_class_waits_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_user_stages, + stages_sizing, sizeof(PFS_stage_stat), + array->m_instr_class_stages_array); + array->m_instr_class_stages_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_user_statements, + statements_sizing, sizeof(PFS_statement_stat), + array->m_instr_class_statements_array); + array->m_instr_class_statements_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_user_transactions, + transactions_sizing, sizeof(PFS_transaction_stat), + array->m_instr_class_transactions_array); + array->m_instr_class_transactions_array= NULL; + + PFS_FREE_ARRAY(& builtin_memory_user_memory, + memory_sizing, sizeof(PFS_memory_stat), + array->m_instr_class_memory_array); + array->m_instr_class_memory_array= NULL; +} + +PFS_user_allocator user_allocator; +PFS_user_container global_user_container(& user_allocator); + diff --git a/storage/perfschema/pfs_buffer_container.h b/storage/perfschema/pfs_buffer_container.h new file mode 100644 index 00000000000..911e030209a --- /dev/null +++ b/storage/perfschema/pfs_buffer_container.h @@ -0,0 +1,1625 @@ +/* Copyright (c) 2014, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef PFS_BUFFER_CONTAINER_H +#define PFS_BUFFER_CONTAINER_H + +#include "my_global.h" +#include "pfs.h" // PSI_COUNT_VOLATILITY +#include "pfs_lock.h" +#include "pfs_instr.h" +#include "pfs_setup_actor.h" +#include "pfs_setup_object.h" +#include "pfs_program.h" +#include "pfs_prepared_stmt.h" +#include "pfs_builtin_memory.h" + +#define USE_SCALABLE + +class PFS_opaque_container_page; +class PFS_opaque_container; + +struct PFS_builtin_memory_class; + +template <class T> +class PFS_buffer_const_iterator; + +template <class T> +class PFS_buffer_processor; + +template <class T, class U, class V> +class PFS_buffer_iterator; + +template <class T, int PFS_PAGE_SIZE, int PFS_PAGE_COUNT, class U, class V> +class PFS_buffer_scalable_iterator; + +template <class T> +class PFS_buffer_default_array; + +template <class T> +class PFS_buffer_default_allocator; + +template <class T, class U, class V> +class PFS_buffer_container; + +template <class T, int PFS_PAGE_SIZE, int PFS_PAGE_COUNT, class U, class V> +class PFS_buffer_scalable_container; + +template <class B, int COUNT> +class PFS_partitioned_buffer_scalable_iterator; + +template <class B, int COUNT> +class PFS_partitioned_buffer_scalable_container; + + +template <class T> +class PFS_buffer_default_array +{ +public: + typedef T value_type; + + value_type *allocate(pfs_dirty_state *dirty_state) + { + uint index; + uint monotonic; + uint monotonic_max; + value_type *pfs; + + if (m_full) + return NULL; + + monotonic= PFS_atomic::add_u32(& m_monotonic.m_u32, 1); + monotonic_max= monotonic + m_max; + + while (monotonic < monotonic_max) + { + index= monotonic % m_max; + pfs= m_ptr + index; + + if (pfs->m_lock.free_to_dirty(dirty_state)) + { + return pfs; + } + monotonic= PFS_atomic::add_u32(& m_monotonic.m_u32, 1); + } + + m_full= true; + return NULL; + } + + void deallocate(value_type *pfs) + { + pfs->m_lock.allocated_to_free(); + m_full= false; + } + + T* get_first() + { + return m_ptr; + } + + T* get_last() + { + return m_ptr + m_max; + } + + bool m_full; + PFS_cacheline_uint32 m_monotonic; + T * m_ptr; + size_t m_max; + /** Container. */ + PFS_opaque_container *m_container; +}; + +template <class T> +class PFS_buffer_default_allocator +{ +public: + typedef PFS_buffer_default_array<T> array_type; + + PFS_buffer_default_allocator(PFS_builtin_memory_class *klass) + : m_builtin_class(klass) + {} + + int alloc_array(array_type *array) + { + array->m_ptr= NULL; + array->m_full= true; + array->m_monotonic.m_u32= 0; + + if (array->m_max > 0) + { + array->m_ptr= PFS_MALLOC_ARRAY(m_builtin_class, + array->m_max, sizeof(T), T, MYF(MY_ZEROFILL)); + if (array->m_ptr == NULL) + return 1; + array->m_full= false; + } + return 0; + } + + void free_array(array_type *array) + { + DBUG_ASSERT(array->m_max > 0); + + PFS_FREE_ARRAY(m_builtin_class, + array->m_max, sizeof(T), array->m_ptr); + array->m_ptr= NULL; + } + +private: + PFS_builtin_memory_class *m_builtin_class; +}; + +template <class T, + class U = PFS_buffer_default_array<T>, + class V = PFS_buffer_default_allocator<T> > +class PFS_buffer_container +{ +public: + friend class PFS_buffer_iterator<T, U, V>; + + typedef T value_type; + typedef U array_type; + typedef V allocator_type; + typedef PFS_buffer_const_iterator<T> const_iterator_type; + typedef PFS_buffer_iterator<T, U, V> iterator_type; + typedef PFS_buffer_processor<T> processor_type; + typedef void (*function_type)(value_type *); + + PFS_buffer_container(allocator_type *allocator) + { + m_array.m_full= true; + m_array.m_ptr= NULL; + m_array.m_max= 0; + m_array.m_monotonic.m_u32= 0; + m_lost= 0; + m_max= 0; + m_allocator= allocator; + } + + int init(ulong max_size) + { + if (max_size > 0) + { + m_array.m_max= max_size; + int rc= m_allocator->alloc_array(& m_array); + if (rc != 0) + { + m_allocator->free_array(& m_array); + return 1; + } + m_max= max_size; + m_array.m_full= false; + } + return 0; + } + + void cleanup() + { + m_allocator->free_array(& m_array); + } + + ulong get_row_count() const + { + return m_max; + } + + ulong get_row_size() const + { + return sizeof(value_type); + } + + ulong get_memory() const + { + return get_row_count() * get_row_size(); + } + + value_type *allocate(pfs_dirty_state *dirty_state) + { + value_type *pfs; + + pfs= m_array.allocate(dirty_state, m_max); + if (pfs == NULL) + { + m_lost++; + } + + return pfs; + } + + void deallocate(value_type *pfs) + { + m_array.deallocate(pfs); + } + + iterator_type iterate() + { + return PFS_buffer_iterator<T, U, V>(this, 0); + } + + iterator_type iterate(uint index) + { + DBUG_ASSERT(index <= m_max); + return PFS_buffer_iterator<T, U, V>(this, index); + } + + void apply(function_type fct) + { + value_type *pfs= m_array.get_first(); + value_type *pfs_last= m_array.get_last(); + + while (pfs < pfs_last) + { + if (pfs->m_lock.is_populated()) + { + fct(pfs); + } + pfs++; + } + } + + void apply_all(function_type fct) + { + value_type *pfs= m_array.get_first(); + value_type *pfs_last= m_array.get_last(); + + while (pfs < pfs_last) + { + fct(pfs); + pfs++; + } + } + + void apply(processor_type & proc) + { + value_type *pfs= m_array.get_first(); + value_type *pfs_last= m_array.get_last(); + + while (pfs < pfs_last) + { + if (pfs->m_lock.is_populated()) + { + proc(pfs); + } + pfs++; + } + } + + void apply_all(processor_type & proc) + { + value_type *pfs= m_array.get_first(); + value_type *pfs_last= m_array.get_last(); + + while (pfs < pfs_last) + { + proc(pfs); + pfs++; + } + } + + inline value_type* get(uint index) + { + DBUG_ASSERT(index < m_max); + + value_type *pfs= m_array.m_ptr + index; + if (pfs->m_lock.is_populated()) + { + return pfs; + } + + return NULL; + } + + value_type* get(uint index, bool *has_more) + { + if (index >= m_max) + { + *has_more= false; + return NULL; + } + + *has_more= true; + return get(index); + } + + value_type *sanitize(value_type *unsafe) + { + intptr offset; + value_type *pfs= m_array.get_first(); + value_type *pfs_last= m_array.get_last(); + + if ((pfs <= unsafe) && + (unsafe < pfs_last)) + { + offset= ((intptr) unsafe - (intptr) pfs) % sizeof(value_type); + if (offset == 0) + return unsafe; + } + + return NULL; + } + + ulong m_lost; + +private: + value_type* scan_next(uint & index, uint * found_index) + { + DBUG_ASSERT(index <= m_max); + + value_type *pfs_first= m_array.get_first(); + value_type *pfs= pfs_first + index; + value_type *pfs_last= m_array.get_last(); + + while (pfs < pfs_last) + { + if (pfs->m_lock.is_populated()) + { + uint found= pfs - pfs_first; + *found_index= found; + index= found + 1; + return pfs; + } + pfs++; + } + + index= m_max; + return NULL; + } + + ulong m_max; + array_type m_array; + allocator_type *m_allocator; +}; + +template <class T, + int PFS_PAGE_SIZE, + int PFS_PAGE_COUNT, + class U = PFS_buffer_default_array<T>, + class V = PFS_buffer_default_allocator<T> > +class PFS_buffer_scalable_container +{ +public: + friend class PFS_buffer_scalable_iterator<T, PFS_PAGE_SIZE, PFS_PAGE_COUNT, U, V>; + + /** + Type of elements in the buffer. + The following attributes are required: + - pfs_lock m_lock + - PFS_opaque_container_page *m_page + */ + typedef T value_type; + /** + Type of pages in the buffer. + The following attributes are required: + - PFS_opaque_container *m_container + */ + typedef U array_type; + typedef V allocator_type; + /** This container type */ + typedef PFS_buffer_scalable_container<T, PFS_PAGE_SIZE, PFS_PAGE_COUNT, U, V> container_type; + typedef PFS_buffer_const_iterator<T> const_iterator_type; + typedef PFS_buffer_scalable_iterator<T, PFS_PAGE_SIZE, PFS_PAGE_COUNT, U, V> iterator_type; + typedef PFS_buffer_processor<T> processor_type; + typedef void (*function_type)(value_type *); + + static const size_t MAX_SIZE= PFS_PAGE_SIZE*PFS_PAGE_COUNT; + + PFS_buffer_scalable_container(allocator_type *allocator) + { + m_allocator= allocator; + m_initialized= false; + } + + int init(long max_size) + { + int i; + + m_initialized= true; + m_full= true; + m_max= PFS_PAGE_COUNT * PFS_PAGE_SIZE; + m_max_page_count= PFS_PAGE_COUNT; + m_last_page_size= PFS_PAGE_SIZE; + m_lost= 0; + m_monotonic.m_u32= 0; + m_max_page_index.m_u32= 0; + + for (i=0 ; i < PFS_PAGE_COUNT; i++) + { + m_pages[i]= NULL; + } + + if (max_size == 0) + { + /* No allocation. */ + m_max_page_count= 0; + } + else if (max_size > 0) + { + if (max_size % PFS_PAGE_SIZE == 0) + { + m_max_page_count= max_size / PFS_PAGE_SIZE; + } + else + { + m_max_page_count= max_size / PFS_PAGE_SIZE + 1; + m_last_page_size= max_size % PFS_PAGE_SIZE; + } + /* Bounded allocation. */ + m_full= false; + + if (m_max_page_count > PFS_PAGE_COUNT) + { + m_max_page_count= PFS_PAGE_COUNT; + m_last_page_size= PFS_PAGE_SIZE; + } + } + else + { + /* max_size = -1 means unbounded allocation */ + m_full= false; + } + + DBUG_ASSERT(m_max_page_count <= PFS_PAGE_COUNT); + DBUG_ASSERT(0 < m_last_page_size); + DBUG_ASSERT(m_last_page_size <= PFS_PAGE_SIZE); + + pthread_mutex_init(& m_critical_section, NULL); + return 0; + } + + void cleanup() + { + int i; + array_type *page; + + if (! m_initialized) + return; + + pthread_mutex_lock(& m_critical_section); + + for (i=0 ; i < PFS_PAGE_COUNT; i++) + { + page= m_pages[i]; + if (page != NULL) + { + m_allocator->free_array(page); + delete page; + m_pages[i]= NULL; + } + } + pthread_mutex_unlock(& m_critical_section); + + pthread_mutex_destroy(& m_critical_section); + + m_initialized= false; + } + + ulong get_row_count() + { + ulong page_count= PFS_atomic::load_u32(& m_max_page_index.m_u32); + + return page_count * PFS_PAGE_SIZE; + } + + ulong get_row_size() const + { + return sizeof(value_type); + } + + ulong get_memory() + { + return get_row_count() * get_row_size(); + } + + value_type *allocate(pfs_dirty_state *dirty_state) + { + if (m_full) + { + m_lost++; + return NULL; + } + + uint index; + uint monotonic; + uint monotonic_max; + uint current_page_count; + value_type *pfs; + array_type *array; + + void *addr; + void * volatile * typed_addr; + void *ptr; + + /* + 1: Try to find an available record within the existing pages + */ + current_page_count= PFS_atomic::load_u32(& m_max_page_index.m_u32); + + if (current_page_count != 0) + { + monotonic= PFS_atomic::load_u32(& m_monotonic.m_u32); + monotonic_max= monotonic + current_page_count; + + while (monotonic < monotonic_max) + { + /* + Scan in the [0 .. current_page_count - 1] range, + in parallel with m_monotonic (see below) + */ + index= monotonic % current_page_count; + + /* Atomic Load, array= m_pages[index] */ + addr= & m_pages[index]; + typed_addr= static_cast<void * volatile *>(addr); + ptr= my_atomic_loadptr(typed_addr); + array= static_cast<array_type *>(ptr); + + if (array != NULL) + { + pfs= array->allocate(dirty_state); + if (pfs != NULL) + { + /* Keep a pointer to the parent page, for deallocate(). */ + pfs->m_page= reinterpret_cast<PFS_opaque_container_page *> (array); + return pfs; + } + } + + /* + Parallel scans collaborate to increase + the common monotonic scan counter. + + Note that when all the existing page are full, + one thread will eventually add a new page, + and cause m_max_page_index to increase, + which fools all the modulo logic for scans already in progress, + because the monotonic counter is not folded to the same place + (sometime modulo N, sometime modulo N+1). + + This is actually ok: since all the pages are full anyway, + there is nothing to miss, so better increase the monotonic + counter faster and then move on to the detection of new pages, + in part 2: below. + */ + monotonic= PFS_atomic::add_u32(& m_monotonic.m_u32, 1); + }; + } + + /* + 2: Try to add a new page, beyond the m_max_page_index limit + */ + while (current_page_count < m_max_page_count) + { + /* Peek for pages added by collaborating threads */ + + /* (2-a) Atomic Load, array= m_pages[current_page_count] */ + addr= & m_pages[current_page_count]; + typed_addr= static_cast<void * volatile *>(addr); + ptr= my_atomic_loadptr(typed_addr); + array= static_cast<array_type *>(ptr); + + if (array == NULL) + { + // ================================================================== + // BEGIN CRITICAL SECTION -- buffer expand + // ================================================================== + + /* + On a fresh started server, buffers are typically empty. + When a sudden load spike is seen by the server, + multiple threads may want to expand the buffer at the same time. + + Using a compare and swap to allow multiple pages to be added, + possibly freeing duplicate pages on collisions, + does not work well because the amount of code involved + when creating a new page can be significant (PFS_thread), + causing MANY collisions between (2-b) and (2-d). + + A huge number of collisions (which can happen when thousands + of new connections hits the server after a restart) + leads to a huge memory consumption, and to OOM. + + To mitigate this, we use here a mutex, + to enforce that only ONE page is added at a time, + so that scaling the buffer happens in a predictable + and controlled manner. + */ + pthread_mutex_lock(& m_critical_section); + + /* + Peek again for pages added by collaborating threads, + this time as the only thread allowed to expand the buffer + */ + + /* (2-b) Atomic Load, array= m_pages[current_page_count] */ + + ptr= my_atomic_loadptr(typed_addr); + array= static_cast<array_type *>(ptr); + + if (array == NULL) + { + /* (2-c) Found no page, allocate a new one */ + array= new array_type(); + builtin_memory_scalable_buffer.count_alloc(sizeof (array_type)); + + array->m_max= get_page_logical_size(current_page_count); + int rc= m_allocator->alloc_array(array); + if (rc != 0) + { + m_allocator->free_array(array); + delete array; + builtin_memory_scalable_buffer.count_free(sizeof (array_type)); + m_lost++; + pthread_mutex_unlock(& m_critical_section); + return NULL; + } + + /* Keep a pointer to this container, for static_deallocate(). */ + array->m_container= reinterpret_cast<PFS_opaque_container *> (this); + + /* (2-d) Atomic STORE, m_pages[current_page_count] = array */ + ptr= array; + my_atomic_storeptr(typed_addr, ptr); + + /* Advertise the new page */ + PFS_atomic::add_u32(& m_max_page_index.m_u32, 1); + } + + pthread_mutex_unlock(& m_critical_section); + + // ================================================================== + // END CRITICAL SECTION -- buffer expand + // ================================================================== + } + + DBUG_ASSERT(array != NULL); + pfs= array->allocate(dirty_state); + if (pfs != NULL) + { + /* Keep a pointer to the parent page, for deallocate(). */ + pfs->m_page= reinterpret_cast<PFS_opaque_container_page *> (array); + return pfs; + } + + current_page_count++; + } + + m_lost++; + m_full= true; + return NULL; + } + + void deallocate(value_type *safe_pfs) + { + /* Find the containing page */ + PFS_opaque_container_page *opaque_page= safe_pfs->m_page; + array_type *page= reinterpret_cast<array_type *> (opaque_page); + + /* Mark the object free */ + safe_pfs->m_lock.allocated_to_free(); + + /* Flag the containing page as not full. */ + page->m_full= false; + + /* Flag the overall container as not full. */ + m_full= false; + } + + static void static_deallocate(value_type *safe_pfs) + { + /* Find the containing page */ + PFS_opaque_container_page *opaque_page= safe_pfs->m_page; + array_type *page= reinterpret_cast<array_type *> (opaque_page); + + /* Mark the object free */ + safe_pfs->m_lock.allocated_to_free(); + + /* Flag the containing page as not full. */ + page->m_full= false; + + /* Find the containing buffer */ + PFS_opaque_container *opaque_container= page->m_container; + PFS_buffer_scalable_container *container; + container= reinterpret_cast<container_type *> (opaque_container); + + /* Flag the overall container as not full. */ + container->m_full= false; + } + + iterator_type iterate() + { + return PFS_buffer_scalable_iterator<T, PFS_PAGE_SIZE, PFS_PAGE_COUNT, U, V>(this, 0); + } + + iterator_type iterate(uint index) + { + DBUG_ASSERT(index <= m_max); + return PFS_buffer_scalable_iterator<T, PFS_PAGE_SIZE, PFS_PAGE_COUNT, U, V>(this, index); + } + + void apply(function_type fct) + { + uint i; + array_type *page; + value_type *pfs; + value_type *pfs_last; + + for (i=0 ; i < PFS_PAGE_COUNT; i++) + { + page= m_pages[i]; + if (page != NULL) + { + pfs= page->get_first(); + pfs_last= page->get_last(); + + while (pfs < pfs_last) + { + if (pfs->m_lock.is_populated()) + { + fct(pfs); + } + pfs++; + } + } + } + } + + void apply_all(function_type fct) + { + uint i; + array_type *page; + value_type *pfs; + value_type *pfs_last; + + for (i=0 ; i < PFS_PAGE_COUNT; i++) + { + page= m_pages[i]; + if (page != NULL) + { + pfs= page->get_first(); + pfs_last= page->get_last(); + + while (pfs < pfs_last) + { + fct(pfs); + pfs++; + } + } + } + } + + void apply(processor_type & proc) + { + uint i; + array_type *page; + value_type *pfs; + value_type *pfs_last; + + for (i=0 ; i < PFS_PAGE_COUNT; i++) + { + page= m_pages[i]; + if (page != NULL) + { + pfs= page->get_first(); + pfs_last= page->get_last(); + + while (pfs < pfs_last) + { + if (pfs->m_lock.is_populated()) + { + proc(pfs); + } + pfs++; + } + } + } + } + + void apply_all(processor_type & proc) + { + uint i; + array_type *page; + value_type *pfs; + value_type *pfs_last; + + for (i=0 ; i < PFS_PAGE_COUNT; i++) + { + page= m_pages[i]; + if (page != NULL) + { + pfs= page->get_first(); + pfs_last= page->get_last(); + + while (pfs < pfs_last) + { + proc(pfs); + pfs++; + } + } + } + } + + value_type* get(uint index) + { + DBUG_ASSERT(index < m_max); + + uint index_1= index / PFS_PAGE_SIZE; + array_type *page= m_pages[index_1]; + if (page != NULL) + { + uint index_2= index % PFS_PAGE_SIZE; + + if (index_2 >= page->m_max) + { + return NULL; + } + + value_type *pfs= page->m_ptr + index_2; + + if (pfs->m_lock.is_populated()) + { + return pfs; + } + } + + return NULL; + } + + value_type* get(uint index, bool *has_more) + { + if (index >= m_max) + { + *has_more= false; + return NULL; + } + + uint index_1= index / PFS_PAGE_SIZE; + array_type *page= m_pages[index_1]; + + if (page == NULL) + { + *has_more= false; + return NULL; + } + + uint index_2= index % PFS_PAGE_SIZE; + + if (index_2 >= page->m_max) + { + *has_more= false; + return NULL; + } + + *has_more= true; + value_type *pfs= page->m_ptr + index_2; + + if (pfs->m_lock.is_populated()) + { + return pfs; + } + + return NULL; + } + + value_type *sanitize(value_type *unsafe) + { + intptr offset; + uint i; + array_type *page; + value_type *pfs; + value_type *pfs_last; + + for (i=0 ; i < PFS_PAGE_COUNT; i++) + { + page= m_pages[i]; + if (page != NULL) + { + pfs= page->get_first(); + pfs_last= page->get_last(); + + if ((pfs <= unsafe) && + (unsafe < pfs_last)) + { + offset= ((intptr) unsafe - (intptr) pfs) % sizeof(value_type); + if (offset == 0) + return unsafe; + } + } + } + + return NULL; + } + + ulong m_lost; + +private: + + uint get_page_logical_size(uint page_index) + { + if (page_index + 1 < m_max_page_count) + return PFS_PAGE_SIZE; + DBUG_ASSERT(page_index + 1 == m_max_page_count); + return m_last_page_size; + } + + value_type* scan_next(uint & index, uint * found_index) + { + DBUG_ASSERT(index <= m_max); + + uint index_1= index / PFS_PAGE_SIZE; + uint index_2= index % PFS_PAGE_SIZE; + array_type *page; + value_type *pfs_first; + value_type *pfs; + value_type *pfs_last; + + while (index_1 < PFS_PAGE_COUNT) + { + page= m_pages[index_1]; + + if (page == NULL) + { + index= m_max; + return NULL; + } + + pfs_first= page->get_first(); + pfs= pfs_first + index_2; + pfs_last= page->get_last(); + + while (pfs < pfs_last) + { + if (pfs->m_lock.is_populated()) + { + uint found= index_1 * PFS_PAGE_SIZE + (pfs - pfs_first); + *found_index= found; + index= found + 1; + return pfs; + } + pfs++; + } + + index_1++; + index_2= 0; + } + + index= m_max; + return NULL; + } + + bool m_initialized; + bool m_full; + size_t m_max; + PFS_cacheline_uint32 m_monotonic; + PFS_cacheline_uint32 m_max_page_index; + ulong m_max_page_count; + ulong m_last_page_size; + array_type * m_pages[PFS_PAGE_COUNT]; + allocator_type *m_allocator; + pthread_mutex_t m_critical_section; +}; + +template <class T, class U, class V> +class PFS_buffer_iterator +{ + friend class PFS_buffer_container<T, U, V>; + + typedef T value_type; + typedef PFS_buffer_container<T, U, V> container_type; + +public: + value_type* scan_next() + { + uint unused; + return m_container->scan_next(m_index, & unused); + } + + value_type* scan_next(uint * found_index) + { + return m_container->scan_next(m_index, found_index); + } + +private: + PFS_buffer_iterator(container_type *container, uint index) + : m_container(container), + m_index(index) + {} + + container_type *m_container; + uint m_index; +}; + +template <class T, int page_size, int page_count, class U, class V> +class PFS_buffer_scalable_iterator +{ + friend class PFS_buffer_scalable_container<T, page_size, page_count, U, V>; + + typedef T value_type; + typedef PFS_buffer_scalable_container<T, page_size, page_count, U, V> container_type; + +public: + value_type* scan_next() + { + uint unused; + return m_container->scan_next(m_index, & unused); + } + + value_type* scan_next(uint * found_index) + { + return m_container->scan_next(m_index, found_index); + } + +private: + PFS_buffer_scalable_iterator(container_type *container, uint index) + : m_container(container), + m_index(index) + {} + + container_type *m_container; + uint m_index; +}; + +template <class T> +class PFS_buffer_processor +{ +public: + virtual ~PFS_buffer_processor<T> () + {} + virtual void operator()(T *element) = 0; +}; + +template <class B, int PFS_PARTITION_COUNT> +class PFS_partitioned_buffer_scalable_container +{ +public: + friend class PFS_partitioned_buffer_scalable_iterator<B, PFS_PARTITION_COUNT>; + + typedef typename B::value_type value_type; + typedef typename B::allocator_type allocator_type; + typedef PFS_partitioned_buffer_scalable_iterator<B, PFS_PARTITION_COUNT> iterator_type; + typedef typename B::iterator_type sub_iterator_type; + typedef typename B::processor_type processor_type; + typedef typename B::function_type function_type; + + PFS_partitioned_buffer_scalable_container(allocator_type *allocator) + { + for (int i=0 ; i < PFS_PARTITION_COUNT; i++) + { + m_partitions[i]= new B(allocator); + } + } + + ~PFS_partitioned_buffer_scalable_container() + { + for (int i=0 ; i < PFS_PARTITION_COUNT; i++) + { + delete m_partitions[i]; + } + } + + int init(long max_size) + { + int rc= 0; + // FIXME: we have max_size * PFS_PARTITION_COUNT here + for (int i=0 ; i < PFS_PARTITION_COUNT; i++) + { + rc|= m_partitions[i]->init(max_size); + } + return rc; + } + + void cleanup() + { + for (int i=0 ; i < PFS_PARTITION_COUNT; i++) + { + m_partitions[i]->cleanup(); + } + } + + ulong get_row_count() const + { + ulong sum= 0; + + for (int i=0; i < PFS_PARTITION_COUNT; i++) + { + sum += m_partitions[i]->get_row_count(); + } + + return sum; + } + + ulong get_row_size() const + { + return sizeof(value_type); + } + + ulong get_memory() const + { + ulong sum= 0; + + for (int i=0; i < PFS_PARTITION_COUNT; i++) + { + sum += m_partitions[i]->get_memory(); + } + + return sum; + } + + long get_lost_counter() + { + long sum= 0; + + for (int i=0; i < PFS_PARTITION_COUNT; i++) + { + sum += m_partitions[i]->m_lost; + } + + return sum; + } + + value_type *allocate(pfs_dirty_state *dirty_state, uint partition) + { + DBUG_ASSERT(partition < PFS_PARTITION_COUNT); + + return m_partitions[partition]->allocate(dirty_state); + } + + void deallocate(value_type *safe_pfs) + { + /* + One issue here is that we do not know which partition + the record belongs to. + Each record points to the parent page, + and each page points to the parent buffer, + so using static_deallocate here, + which will find the correct partition by itself. + */ + B::static_deallocate(safe_pfs); + } + + iterator_type iterate() + { + return iterator_type(this, 0, 0); + } + + iterator_type iterate(uint user_index) + { + uint partition_index; + uint sub_index; + unpack_index(user_index, &partition_index, &sub_index); + return iterator_type(this, partition_index, sub_index); + } + + void apply(function_type fct) + { + for (int i=0; i < PFS_PARTITION_COUNT; i++) + { + m_partitions[i]->apply(fct); + } + } + + void apply_all(function_type fct) + { + for (int i=0; i < PFS_PARTITION_COUNT; i++) + { + m_partitions[i]->apply_all(fct); + } + } + + void apply(processor_type & proc) + { + for (int i=0; i < PFS_PARTITION_COUNT; i++) + { + m_partitions[i]->apply(proc); + } + } + + void apply_all(processor_type & proc) + { + for (int i=0; i < PFS_PARTITION_COUNT; i++) + { + m_partitions[i]->apply_all(proc); + } + } + + value_type* get(uint user_index) + { + uint partition_index; + uint sub_index; + unpack_index(user_index, &partition_index, &sub_index); + + if (partition_index >= PFS_PARTITION_COUNT) + { + return NULL; + } + + return m_partitions[partition_index]->get(sub_index); + } + + value_type* get(uint user_index, bool *has_more) + { + uint partition_index; + uint sub_index; + unpack_index(user_index, &partition_index, &sub_index); + + if (partition_index >= PFS_PARTITION_COUNT) + { + *has_more= false; + return NULL; + } + + *has_more= true; + return m_partitions[partition_index]->get(sub_index); + } + + value_type *sanitize(value_type *unsafe) + { + value_type *safe= NULL; + + for (int i=0; i < PFS_PARTITION_COUNT; i++) + { + safe= m_partitions[i]->sanitize(unsafe); + if (safe != NULL) + { + return safe; + } + } + + return safe; + } + +private: + static void pack_index(uint partition_index, uint sub_index, uint *user_index) + { + /* 2^8 = 256 partitions max */ + compile_time_assert(PFS_PARTITION_COUNT <= (1 << 8)); + /* 2^24 = 16777216 max per partitioned buffer. */ + compile_time_assert((B::MAX_SIZE) <= (1 << 24)); + + *user_index= (partition_index << 24) + sub_index; + } + + static void unpack_index(uint user_index, uint *partition_index, uint *sub_index) + { + *partition_index= user_index >> 24; + *sub_index= user_index & 0x00FFFFFF; + } + + value_type* scan_next(uint & partition_index, uint & sub_index, uint * found_partition, uint * found_sub_index) + { + value_type *record= NULL; + DBUG_ASSERT(partition_index < PFS_PARTITION_COUNT); + + while (partition_index < PFS_PARTITION_COUNT) + { + sub_iterator_type sub_iterator= m_partitions[partition_index]->iterate(sub_index); + record= sub_iterator.scan_next(found_sub_index); + if (record != NULL) + { + *found_partition= partition_index; + sub_index= *found_sub_index + 1; + return record; + } + + partition_index++; + sub_index= 0; + } + + *found_partition= PFS_PARTITION_COUNT; + *found_sub_index= 0; + sub_index= 0; + return NULL; + } + + B *m_partitions[PFS_PARTITION_COUNT]; +}; + +template <class B, int PFS_PARTITION_COUNT> +class PFS_partitioned_buffer_scalable_iterator +{ +public: + friend class PFS_partitioned_buffer_scalable_container<B, PFS_PARTITION_COUNT>; + + typedef typename B::value_type value_type; + typedef PFS_partitioned_buffer_scalable_container<B, PFS_PARTITION_COUNT> container_type; + + value_type* scan_next() + { + uint unused_partition; + uint unused_sub_index; + return m_container->scan_next(m_partition, m_sub_index, & unused_partition, & unused_sub_index); + } + + value_type* scan_next(uint *found_user_index) + { + uint found_partition; + uint found_sub_index; + value_type *record; + record= m_container->scan_next(m_partition, m_sub_index, &found_partition, &found_sub_index); + container_type::pack_index(found_partition, found_sub_index, found_user_index); + return record; + } + +private: + PFS_partitioned_buffer_scalable_iterator(container_type *container, uint partition, uint sub_index) + : m_container(container), + m_partition(partition), + m_sub_index(sub_index) + {} + + container_type *m_container; + uint m_partition; + uint m_sub_index; +}; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_mutex, 1024, 1024> PFS_mutex_basic_container; +typedef PFS_partitioned_buffer_scalable_container<PFS_mutex_basic_container, PSI_COUNT_VOLATILITY> PFS_mutex_container; +#else +typedef PFS_buffer_container<PFS_mutex> PFS_mutex_container; +#endif +typedef PFS_mutex_container::iterator_type PFS_mutex_iterator; +extern PFS_mutex_container global_mutex_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_rwlock, 1024, 1024> PFS_rwlock_container; +#else +typedef PFS_buffer_container<PFS_rwlock> PFS_rwlock_container; +#endif +typedef PFS_rwlock_container::iterator_type PFS_rwlock_iterator; +extern PFS_rwlock_container global_rwlock_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_cond, 256, 256> PFS_cond_container; +#else +typedef PFS_buffer_container<PFS_cond> PFS_cond_container; +#endif +typedef PFS_cond_container::iterator_type PFS_cond_iterator; +extern PFS_cond_container global_cond_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_file, 4 * 1024, 4 * 1024> PFS_file_container; +#else +typedef PFS_buffer_container<PFS_file> PFS_file_container; +#endif +typedef PFS_file_container::iterator_type PFS_file_iterator; +extern PFS_file_container global_file_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_socket, 256, 256> PFS_socket_container; +#else +typedef PFS_buffer_container<PFS_socket> PFS_socket_container; +#endif +typedef PFS_socket_container::iterator_type PFS_socket_iterator; +extern PFS_socket_container global_socket_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_metadata_lock, 1024, 1024> PFS_mdl_container; +#else +typedef PFS_buffer_container<PFS_metadata_lock> PFS_mdl_container; +#endif +typedef PFS_mdl_container::iterator_type PFS_mdl_iterator; +extern PFS_mdl_container global_mdl_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_setup_actor, 128, 1024> PFS_setup_actor_container; +#else +typedef PFS_buffer_container<PFS_setup_actor> PFS_setup_actor_container; +#endif +typedef PFS_setup_actor_container::iterator_type PFS_setup_actor_iterator; +extern PFS_setup_actor_container global_setup_actor_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_setup_object, 128, 1024> PFS_setup_object_container; +#else +typedef PFS_buffer_container<PFS_setup_object> PFS_setup_object_container; +#endif +typedef PFS_setup_object_container::iterator_type PFS_setup_object_iterator; +extern PFS_setup_object_container global_setup_object_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_table, 1024, 1024> PFS_table_container; +#else +typedef PFS_buffer_container<PFS_table> PFS_table_container; +#endif +typedef PFS_table_container::iterator_type PFS_table_iterator; +extern PFS_table_container global_table_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_table_share, 4 * 1024, 4 * 1024> PFS_table_share_container; +#else +typedef PFS_buffer_container<PFS_table_share> PFS_table_share_container; +#endif +typedef PFS_table_share_container::iterator_type PFS_table_share_iterator; +extern PFS_table_share_container global_table_share_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_table_share_index, 8 * 1024, 8 * 1024> PFS_table_share_index_container; +#else +typedef PFS_buffer_container<PFS_table_share_index> PFS_table_share_index_container; +#endif +typedef PFS_table_share_index_container::iterator_type PFS_table_share_index_iterator; +extern PFS_table_share_index_container global_table_share_index_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_table_share_lock, 4 * 1024, 4 * 1024> PFS_table_share_lock_container; +#else +typedef PFS_buffer_container<PFS_table_share_lock> PFS_table_share_lock_container; +#endif +typedef PFS_table_share_lock_container::iterator_type PFS_table_share_lock_iterator; +extern PFS_table_share_lock_container global_table_share_lock_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_program, 1024, 1024> PFS_program_container; +#else +typedef PFS_buffer_container<PFS_program> PFS_program_container; +#endif +typedef PFS_program_container::iterator_type PFS_program_iterator; +extern PFS_program_container global_program_container; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_prepared_stmt, 1024, 1024> PFS_prepared_stmt_container; +#else +typedef PFS_buffer_container<PFS_prepared_stmt> PFS_prepared_stmt_container; +#endif +typedef PFS_prepared_stmt_container::iterator_type PFS_prepared_stmt_iterator; +extern PFS_prepared_stmt_container global_prepared_stmt_container; + +class PFS_account_array : public PFS_buffer_default_array<PFS_account> +{ +public: + PFS_single_stat *m_instr_class_waits_array; + PFS_stage_stat *m_instr_class_stages_array; + PFS_statement_stat *m_instr_class_statements_array; + PFS_transaction_stat *m_instr_class_transactions_array; + PFS_memory_stat *m_instr_class_memory_array; +}; + +class PFS_account_allocator +{ +public: + int alloc_array(PFS_account_array *array); + void free_array(PFS_account_array *array); +}; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_account, + 128, + 128, + PFS_account_array, + PFS_account_allocator> PFS_account_container; +#else +typedef PFS_buffer_container<PFS_account, + PFS_account_array, + PFS_account_allocator> PFS_account_container; +#endif +typedef PFS_account_container::iterator_type PFS_account_iterator; +extern PFS_account_container global_account_container; + +class PFS_host_array : public PFS_buffer_default_array<PFS_host> +{ +public: + PFS_single_stat *m_instr_class_waits_array; + PFS_stage_stat *m_instr_class_stages_array; + PFS_statement_stat *m_instr_class_statements_array; + PFS_transaction_stat *m_instr_class_transactions_array; + PFS_memory_stat *m_instr_class_memory_array; +}; + +class PFS_host_allocator +{ +public: + int alloc_array(PFS_host_array *array); + void free_array(PFS_host_array *array); +}; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_host, + 128, + 128, + PFS_host_array, + PFS_host_allocator> PFS_host_container; +#else +typedef PFS_buffer_container<PFS_host, + PFS_host_array, + PFS_host_allocator> PFS_host_container; +#endif +typedef PFS_host_container::iterator_type PFS_host_iterator; +extern PFS_host_container global_host_container; + +class PFS_thread_array : public PFS_buffer_default_array<PFS_thread> +{ +public: + PFS_single_stat *m_instr_class_waits_array; + PFS_stage_stat *m_instr_class_stages_array; + PFS_statement_stat *m_instr_class_statements_array; + PFS_transaction_stat *m_instr_class_transactions_array; + PFS_memory_stat *m_instr_class_memory_array; + + PFS_events_waits *m_waits_history_array; + PFS_events_stages *m_stages_history_array; + PFS_events_statements *m_statements_history_array; + PFS_events_statements *m_statements_stack_array; + PFS_events_transactions *m_transactions_history_array; + char *m_session_connect_attrs_array; + + char *m_current_stmts_text_array; + char *m_history_stmts_text_array; + unsigned char *m_current_stmts_digest_token_array; + unsigned char *m_history_stmts_digest_token_array; +}; + +class PFS_thread_allocator +{ +public: + int alloc_array(PFS_thread_array *array); + void free_array(PFS_thread_array *array); +}; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_thread, + 256, + 256, + PFS_thread_array, + PFS_thread_allocator> PFS_thread_container; +#else +typedef PFS_buffer_container<PFS_thread, + PFS_thread_array, + PFS_thread_allocator> PFS_thread_container; +#endif +typedef PFS_thread_container::iterator_type PFS_thread_iterator; +extern PFS_thread_container global_thread_container; + +class PFS_user_array : public PFS_buffer_default_array<PFS_user> +{ +public: + PFS_single_stat *m_instr_class_waits_array; + PFS_stage_stat *m_instr_class_stages_array; + PFS_statement_stat *m_instr_class_statements_array; + PFS_transaction_stat *m_instr_class_transactions_array; + PFS_memory_stat *m_instr_class_memory_array; +}; + +class PFS_user_allocator +{ +public: + int alloc_array(PFS_user_array *array); + void free_array(PFS_user_array *array); +}; + +#ifdef USE_SCALABLE +typedef PFS_buffer_scalable_container<PFS_user, + 128, + 128, + PFS_user_array, + PFS_user_allocator> PFS_user_container; +#else +typedef PFS_buffer_container<PFS_user, + PFS_user_array, + PFS_user_allocator> PFS_user_container; +#endif +typedef PFS_user_container::iterator_type PFS_user_iterator; +extern PFS_user_container global_user_container; + +#endif + diff --git a/storage/perfschema/pfs_builtin_memory.cc b/storage/perfschema/pfs_builtin_memory.cc new file mode 100644 index 00000000000..6955f1a8ec3 --- /dev/null +++ b/storage/perfschema/pfs_builtin_memory.cc @@ -0,0 +1,382 @@ +/* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include "my_global.h" +#include "m_string.h" +#include "pfs_global.h" +#include "pfs_builtin_memory.h" + +PFS_builtin_memory_class builtin_memory_mutex; +PFS_builtin_memory_class builtin_memory_rwlock; +PFS_builtin_memory_class builtin_memory_cond; +PFS_builtin_memory_class builtin_memory_file; +PFS_builtin_memory_class builtin_memory_socket; +PFS_builtin_memory_class builtin_memory_mdl; +PFS_builtin_memory_class builtin_memory_file_handle; + +PFS_builtin_memory_class builtin_memory_account; +PFS_builtin_memory_class builtin_memory_account_waits; +PFS_builtin_memory_class builtin_memory_account_stages; +PFS_builtin_memory_class builtin_memory_account_statements; +PFS_builtin_memory_class builtin_memory_account_transactions; +PFS_builtin_memory_class builtin_memory_account_memory; + +PFS_builtin_memory_class builtin_memory_global_stages; +PFS_builtin_memory_class builtin_memory_global_statements; +PFS_builtin_memory_class builtin_memory_global_memory; + +PFS_builtin_memory_class builtin_memory_host; +PFS_builtin_memory_class builtin_memory_host_waits; +PFS_builtin_memory_class builtin_memory_host_stages; +PFS_builtin_memory_class builtin_memory_host_statements; +PFS_builtin_memory_class builtin_memory_host_transactions; +PFS_builtin_memory_class builtin_memory_host_memory; + +PFS_builtin_memory_class builtin_memory_thread; +PFS_builtin_memory_class builtin_memory_thread_waits; +PFS_builtin_memory_class builtin_memory_thread_stages; +PFS_builtin_memory_class builtin_memory_thread_statements; +PFS_builtin_memory_class builtin_memory_thread_transactions; +PFS_builtin_memory_class builtin_memory_thread_memory; + +PFS_builtin_memory_class builtin_memory_thread_waits_history; +PFS_builtin_memory_class builtin_memory_thread_stages_history; +PFS_builtin_memory_class builtin_memory_thread_statements_history; +PFS_builtin_memory_class builtin_memory_thread_statements_history_tokens; +PFS_builtin_memory_class builtin_memory_thread_statements_history_sqltext; +PFS_builtin_memory_class builtin_memory_thread_statements_stack; +PFS_builtin_memory_class builtin_memory_thread_statements_stack_tokens; +PFS_builtin_memory_class builtin_memory_thread_statements_stack_sqltext; +PFS_builtin_memory_class builtin_memory_thread_transaction_history; +PFS_builtin_memory_class builtin_memory_thread_session_connect_attrs; + +PFS_builtin_memory_class builtin_memory_user; +PFS_builtin_memory_class builtin_memory_user_waits; +PFS_builtin_memory_class builtin_memory_user_stages; +PFS_builtin_memory_class builtin_memory_user_statements; +PFS_builtin_memory_class builtin_memory_user_transactions; +PFS_builtin_memory_class builtin_memory_user_memory; + +PFS_builtin_memory_class builtin_memory_mutex_class; +PFS_builtin_memory_class builtin_memory_rwlock_class; +PFS_builtin_memory_class builtin_memory_cond_class; +PFS_builtin_memory_class builtin_memory_thread_class; +PFS_builtin_memory_class builtin_memory_file_class; +PFS_builtin_memory_class builtin_memory_socket_class; +PFS_builtin_memory_class builtin_memory_stage_class; +PFS_builtin_memory_class builtin_memory_statement_class; +PFS_builtin_memory_class builtin_memory_memory_class; + +PFS_builtin_memory_class builtin_memory_setup_actor; +PFS_builtin_memory_class builtin_memory_setup_object; + +PFS_builtin_memory_class builtin_memory_digest; +PFS_builtin_memory_class builtin_memory_digest_tokens; + +PFS_builtin_memory_class builtin_memory_stages_history_long; +PFS_builtin_memory_class builtin_memory_statements_history_long; +PFS_builtin_memory_class builtin_memory_statements_history_long_tokens; +PFS_builtin_memory_class builtin_memory_statements_history_long_sqltext; +PFS_builtin_memory_class builtin_memory_transactions_history_long; +PFS_builtin_memory_class builtin_memory_waits_history_long; + +PFS_builtin_memory_class builtin_memory_table; +PFS_builtin_memory_class builtin_memory_table_share; +PFS_builtin_memory_class builtin_memory_table_share_index; +PFS_builtin_memory_class builtin_memory_table_share_lock; + +PFS_builtin_memory_class builtin_memory_program; +PFS_builtin_memory_class builtin_memory_prepared_stmt; + +PFS_builtin_memory_class builtin_memory_scalable_buffer; + +static void init_builtin_memory_class(PFS_builtin_memory_class *klass, const char* name) +{ + klass->m_class.m_type= PFS_CLASS_MEMORY; + klass->m_class.m_enabled= true; /* Immutable */ + klass->m_class.m_timed= false; /* Immutable */ + klass->m_class.m_flags= PSI_FLAG_GLOBAL; + klass->m_class.m_event_name_index= 0; + my_snprintf(klass->m_class.m_name, sizeof(klass->m_class.m_name), "%.*s", + PFS_MAX_INFO_NAME_LENGTH - 1, name); + klass->m_class.m_name_length= strlen(name); + DBUG_ASSERT(klass->m_class.m_name_length < sizeof(klass->m_class.m_name)); + klass->m_class.m_timer= NULL; + + klass->m_stat.reset(); +} + +void init_all_builtin_memory_class() +{ + init_builtin_memory_class( & builtin_memory_mutex, + "memory/performance_schema/mutex_instances"); + init_builtin_memory_class( & builtin_memory_rwlock, + "memory/performance_schema/rwlock_instances"); + init_builtin_memory_class( & builtin_memory_cond, + "memory/performance_schema/cond_instances"); + init_builtin_memory_class( & builtin_memory_file, + "memory/performance_schema/file_instances"); + init_builtin_memory_class( & builtin_memory_socket, + "memory/performance_schema/socket_instances"); + init_builtin_memory_class( & builtin_memory_mdl, + "memory/performance_schema/metadata_locks"); + init_builtin_memory_class( & builtin_memory_file_handle, + "memory/performance_schema/file_handle"); + + init_builtin_memory_class( & builtin_memory_account, + "memory/performance_schema/accounts"); + init_builtin_memory_class( & builtin_memory_account_waits, + "memory/performance_schema/events_waits_summary_by_account_by_event_name"); + init_builtin_memory_class( & builtin_memory_account_stages, + "memory/performance_schema/events_stages_summary_by_account_by_event_name"); + init_builtin_memory_class( & builtin_memory_account_statements, + "memory/performance_schema/events_statements_summary_by_account_by_event_name"); + init_builtin_memory_class( & builtin_memory_account_transactions, + "memory/performance_schema/events_transactions_summary_by_account_by_event_name"); + init_builtin_memory_class( & builtin_memory_account_memory, + "memory/performance_schema/memory_summary_by_account_by_event_name"); + + init_builtin_memory_class( & builtin_memory_global_stages, + "memory/performance_schema/events_stages_summary_global_by_event_name"); + init_builtin_memory_class( & builtin_memory_global_statements, + "memory/performance_schema/events_statements_summary_global_by_event_name"); + init_builtin_memory_class( & builtin_memory_global_memory, + "memory/performance_schema/memory_summary_global_by_event_name"); + + init_builtin_memory_class( & builtin_memory_host, + "memory/performance_schema/hosts"); + init_builtin_memory_class( & builtin_memory_host_waits, + "memory/performance_schema/events_waits_summary_by_host_by_event_name"); + init_builtin_memory_class( & builtin_memory_host_stages, + "memory/performance_schema/events_stages_summary_by_host_by_event_name"); + init_builtin_memory_class( & builtin_memory_host_statements, + "memory/performance_schema/events_statements_summary_by_host_by_event_name"); + init_builtin_memory_class( & builtin_memory_host_transactions, + "memory/performance_schema/events_transactions_summary_by_host_by_event_name"); + init_builtin_memory_class( & builtin_memory_host_memory, + "memory/performance_schema/memory_summary_by_host_by_event_name"); + + init_builtin_memory_class( & builtin_memory_thread, + "memory/performance_schema/threads"); + init_builtin_memory_class( & builtin_memory_thread_waits, + "memory/performance_schema/events_waits_summary_by_thread_by_event_name"); + init_builtin_memory_class( & builtin_memory_thread_stages, + "memory/performance_schema/events_stages_summary_by_thread_by_event_name"); + init_builtin_memory_class( & builtin_memory_thread_statements, + "memory/performance_schema/events_statements_summary_by_thread_by_event_name"); + init_builtin_memory_class( & builtin_memory_thread_transactions, + "memory/performance_schema/events_transactions_summary_by_thread_by_event_name"); + init_builtin_memory_class( & builtin_memory_thread_memory, + "memory/performance_schema/memory_summary_by_thread_by_event_name"); + + init_builtin_memory_class( & builtin_memory_thread_waits_history, + "memory/performance_schema/events_waits_history"); + init_builtin_memory_class( & builtin_memory_thread_stages_history, + "memory/performance_schema/events_stages_history"); + init_builtin_memory_class( & builtin_memory_thread_statements_history, + "memory/performance_schema/events_statements_history"); + init_builtin_memory_class( & builtin_memory_thread_statements_history_tokens, + "memory/performance_schema/events_statements_history.tokens"); + init_builtin_memory_class( & builtin_memory_thread_statements_history_sqltext, + "memory/performance_schema/events_statements_history.sqltext"); + init_builtin_memory_class( & builtin_memory_thread_statements_stack, + "memory/performance_schema/events_statements_current"); + init_builtin_memory_class( & builtin_memory_thread_statements_stack_tokens, + "memory/performance_schema/events_statements_current.tokens"); + init_builtin_memory_class( & builtin_memory_thread_statements_stack_sqltext, + "memory/performance_schema/events_statements_current.sqltext"); + init_builtin_memory_class( & builtin_memory_thread_transaction_history, + "memory/performance_schema/events_transactions_history"); + init_builtin_memory_class( & builtin_memory_thread_session_connect_attrs, + "memory/performance_schema/session_connect_attrs"); + + init_builtin_memory_class( & builtin_memory_user, + "memory/performance_schema/users"); + init_builtin_memory_class( & builtin_memory_user_waits, + "memory/performance_schema/events_waits_summary_by_user_by_event_name"); + init_builtin_memory_class( & builtin_memory_user_stages, + "memory/performance_schema/events_stages_summary_by_user_by_event_name"); + init_builtin_memory_class( & builtin_memory_user_statements, + "memory/performance_schema/events_statements_summary_by_user_by_event_name"); + init_builtin_memory_class( & builtin_memory_user_transactions, + "memory/performance_schema/events_transactions_summary_by_user_by_event_name"); + init_builtin_memory_class( & builtin_memory_user_memory, + "memory/performance_schema/memory_summary_by_user_by_event_name"); + + init_builtin_memory_class( & builtin_memory_mutex_class, + "memory/performance_schema/mutex_class"); + init_builtin_memory_class( & builtin_memory_rwlock_class, + "memory/performance_schema/rwlock_class"); + init_builtin_memory_class( & builtin_memory_cond_class, + "memory/performance_schema/cond_class"); + init_builtin_memory_class( & builtin_memory_thread_class, + "memory/performance_schema/thread_class"); + init_builtin_memory_class( & builtin_memory_file_class, + "memory/performance_schema/file_class"); + init_builtin_memory_class( & builtin_memory_socket_class, + "memory/performance_schema/socket_class"); + init_builtin_memory_class( & builtin_memory_stage_class, + "memory/performance_schema/stage_class"); + init_builtin_memory_class( & builtin_memory_statement_class, + "memory/performance_schema/statement_class"); + init_builtin_memory_class( & builtin_memory_memory_class, + "memory/performance_schema/memory_class"); + + init_builtin_memory_class( & builtin_memory_setup_actor, + "memory/performance_schema/setup_actors"); + init_builtin_memory_class( & builtin_memory_setup_object, + "memory/performance_schema/setup_objects"); + + init_builtin_memory_class( & builtin_memory_digest, + "memory/performance_schema/events_statements_summary_by_digest"); + init_builtin_memory_class( & builtin_memory_digest_tokens, + "memory/performance_schema/events_statements_summary_by_digest.tokens"); + + init_builtin_memory_class( & builtin_memory_stages_history_long, + "memory/performance_schema/events_stages_history_long"); + init_builtin_memory_class( & builtin_memory_statements_history_long, + "memory/performance_schema/events_statements_history_long"); + init_builtin_memory_class( & builtin_memory_statements_history_long_tokens, + "memory/performance_schema/events_statements_history_long.tokens"); + init_builtin_memory_class( & builtin_memory_statements_history_long_sqltext, + "memory/performance_schema/events_statements_history_long.sqltext"); + init_builtin_memory_class( & builtin_memory_transactions_history_long, + "memory/performance_schema/events_transactions_history_long"); + init_builtin_memory_class( & builtin_memory_waits_history_long, + "memory/performance_schema/events_waits_history_long"); + + init_builtin_memory_class( & builtin_memory_table, + "memory/performance_schema/table_handles"); + init_builtin_memory_class( & builtin_memory_table_share, + "memory/performance_schema/table_shares"); + init_builtin_memory_class( & builtin_memory_table_share_index, + "memory/performance_schema/table_io_waits_summary_by_index_usage"); + init_builtin_memory_class( & builtin_memory_table_share_lock, + "memory/performance_schema/table_lock_waits_summary_by_table"); + + init_builtin_memory_class( & builtin_memory_program, + "memory/performance_schema/events_statements_summary_by_program"); + init_builtin_memory_class( & builtin_memory_prepared_stmt, + "memory/performance_schema/prepared_statements_instances"); + + init_builtin_memory_class( & builtin_memory_scalable_buffer, + "memory/performance_schema/scalable_buffer"); +} + +static PFS_builtin_memory_class* all_builtin_memory[]= +{ + & builtin_memory_mutex, + & builtin_memory_rwlock, + & builtin_memory_cond, + & builtin_memory_file, + & builtin_memory_socket, + & builtin_memory_mdl, + & builtin_memory_file_handle, + + & builtin_memory_account, + & builtin_memory_account_waits, + & builtin_memory_account_stages, + & builtin_memory_account_statements, + & builtin_memory_account_transactions, + & builtin_memory_account_memory, + + & builtin_memory_global_stages, + & builtin_memory_global_statements, + & builtin_memory_global_memory, + + & builtin_memory_host, + & builtin_memory_host_waits, + & builtin_memory_host_stages, + & builtin_memory_host_statements, + & builtin_memory_host_transactions, + & builtin_memory_host_memory, + + & builtin_memory_thread, + & builtin_memory_thread_waits, + & builtin_memory_thread_stages, + & builtin_memory_thread_statements, + & builtin_memory_thread_transactions, + & builtin_memory_thread_memory, + + & builtin_memory_thread_waits_history, + & builtin_memory_thread_stages_history, + & builtin_memory_thread_statements_history, + & builtin_memory_thread_statements_history_tokens, + & builtin_memory_thread_statements_history_sqltext, + & builtin_memory_thread_statements_stack, + & builtin_memory_thread_statements_stack_tokens, + & builtin_memory_thread_statements_stack_sqltext, + & builtin_memory_thread_transaction_history, + & builtin_memory_thread_session_connect_attrs, + + & builtin_memory_user, + & builtin_memory_user_waits, + & builtin_memory_user_stages, + & builtin_memory_user_statements, + & builtin_memory_user_transactions, + & builtin_memory_user_memory, + + & builtin_memory_mutex_class, + & builtin_memory_rwlock_class, + & builtin_memory_cond_class, + & builtin_memory_thread_class, + & builtin_memory_file_class, + & builtin_memory_socket_class, + & builtin_memory_stage_class, + & builtin_memory_statement_class, + & builtin_memory_memory_class, + + & builtin_memory_setup_actor, + & builtin_memory_setup_object, + + & builtin_memory_digest, + & builtin_memory_digest_tokens, + + & builtin_memory_stages_history_long, + & builtin_memory_statements_history_long, + & builtin_memory_statements_history_long_tokens, + & builtin_memory_statements_history_long_sqltext, + & builtin_memory_transactions_history_long, + & builtin_memory_waits_history_long, + + & builtin_memory_table, + & builtin_memory_table_share, + & builtin_memory_table_share_index, + & builtin_memory_table_share_lock, + + & builtin_memory_program, + & builtin_memory_prepared_stmt, + + & builtin_memory_scalable_buffer, + + NULL +}; + + +PFS_builtin_memory_class *find_builtin_memory_class(PFS_builtin_memory_key key) +{ + if (key == 0) + return NULL; + + return all_builtin_memory[key - 1]; +} + diff --git a/storage/perfschema/pfs_builtin_memory.h b/storage/perfschema/pfs_builtin_memory.h new file mode 100644 index 00000000000..1c00275d5b9 --- /dev/null +++ b/storage/perfschema/pfs_builtin_memory.h @@ -0,0 +1,143 @@ +/* Copyright (c) 2014, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef PFS_BUILTIN_MEMORY_H +#define PFS_BUILTIN_MEMORY_H + +#include "my_global.h" +#include "pfs_global.h" +#include "pfs_instr_class.h" + +/** + @file storage/perfschema/pfs_builtin_memory.h + Performance schema instruments meta data (declarations). +*/ + +typedef uint PFS_builtin_memory_key; + +struct PFS_builtin_memory_class +{ + PFS_memory_class m_class; + PFS_memory_stat m_stat; + + inline void count_alloc(size_t size) + { + m_stat.count_builtin_alloc(size); + } + + inline void count_free(size_t size) + { + m_stat.count_builtin_free(size); + } +}; + +void init_all_builtin_memory_class(); + +PFS_builtin_memory_class *find_builtin_memory_class(PFS_builtin_memory_key); + +extern PFS_builtin_memory_class builtin_memory_mutex; +extern PFS_builtin_memory_class builtin_memory_rwlock; +extern PFS_builtin_memory_class builtin_memory_cond; +extern PFS_builtin_memory_class builtin_memory_file; +extern PFS_builtin_memory_class builtin_memory_socket; +extern PFS_builtin_memory_class builtin_memory_mdl; +extern PFS_builtin_memory_class builtin_memory_file_handle; + +extern PFS_builtin_memory_class builtin_memory_account; +extern PFS_builtin_memory_class builtin_memory_account_waits; +extern PFS_builtin_memory_class builtin_memory_account_stages; +extern PFS_builtin_memory_class builtin_memory_account_statements; +extern PFS_builtin_memory_class builtin_memory_account_transactions; +extern PFS_builtin_memory_class builtin_memory_account_memory; + +extern PFS_builtin_memory_class builtin_memory_global_stages; +extern PFS_builtin_memory_class builtin_memory_global_statements; +extern PFS_builtin_memory_class builtin_memory_global_memory; + +extern PFS_builtin_memory_class builtin_memory_host; +extern PFS_builtin_memory_class builtin_memory_host_waits; +extern PFS_builtin_memory_class builtin_memory_host_stages; +extern PFS_builtin_memory_class builtin_memory_host_statements; +extern PFS_builtin_memory_class builtin_memory_host_transactions; +extern PFS_builtin_memory_class builtin_memory_host_memory; + +extern PFS_builtin_memory_class builtin_memory_thread; +extern PFS_builtin_memory_class builtin_memory_thread_waits; +extern PFS_builtin_memory_class builtin_memory_thread_stages; +extern PFS_builtin_memory_class builtin_memory_thread_statements; +extern PFS_builtin_memory_class builtin_memory_thread_transactions; +extern PFS_builtin_memory_class builtin_memory_thread_memory; + +extern PFS_builtin_memory_class builtin_memory_thread_waits_history; +extern PFS_builtin_memory_class builtin_memory_thread_stages_history; +extern PFS_builtin_memory_class builtin_memory_thread_statements_history; +extern PFS_builtin_memory_class builtin_memory_thread_statements_history_tokens; +extern PFS_builtin_memory_class builtin_memory_thread_statements_history_sqltext; +extern PFS_builtin_memory_class builtin_memory_thread_statements_stack; +extern PFS_builtin_memory_class builtin_memory_thread_statements_stack_tokens; +extern PFS_builtin_memory_class builtin_memory_thread_statements_stack_sqltext; +extern PFS_builtin_memory_class builtin_memory_thread_transaction_history; +extern PFS_builtin_memory_class builtin_memory_thread_session_connect_attrs; + +extern PFS_builtin_memory_class builtin_memory_user; +extern PFS_builtin_memory_class builtin_memory_user_waits; +extern PFS_builtin_memory_class builtin_memory_user_stages; +extern PFS_builtin_memory_class builtin_memory_user_statements; +extern PFS_builtin_memory_class builtin_memory_user_transactions; +extern PFS_builtin_memory_class builtin_memory_user_memory; + +extern PFS_builtin_memory_class builtin_memory_mutex_class; +extern PFS_builtin_memory_class builtin_memory_rwlock_class; +extern PFS_builtin_memory_class builtin_memory_cond_class; +extern PFS_builtin_memory_class builtin_memory_thread_class; +extern PFS_builtin_memory_class builtin_memory_file_class; +extern PFS_builtin_memory_class builtin_memory_socket_class; +extern PFS_builtin_memory_class builtin_memory_stage_class; +extern PFS_builtin_memory_class builtin_memory_statement_class; +extern PFS_builtin_memory_class builtin_memory_memory_class; + +extern PFS_builtin_memory_class builtin_memory_setup_actor; +extern PFS_builtin_memory_class builtin_memory_setup_object; + +extern PFS_builtin_memory_class builtin_memory_digest; +extern PFS_builtin_memory_class builtin_memory_digest_tokens; + +extern PFS_builtin_memory_class builtin_memory_stages_history_long; +extern PFS_builtin_memory_class builtin_memory_statements_history_long; +extern PFS_builtin_memory_class builtin_memory_statements_history_long_tokens; +extern PFS_builtin_memory_class builtin_memory_statements_history_long_sqltext; +extern PFS_builtin_memory_class builtin_memory_transactions_history_long; +extern PFS_builtin_memory_class builtin_memory_waits_history_long; + +extern PFS_builtin_memory_class builtin_memory_table; +extern PFS_builtin_memory_class builtin_memory_table_share; +extern PFS_builtin_memory_class builtin_memory_table_share_index; +extern PFS_builtin_memory_class builtin_memory_table_share_lock; + +extern PFS_builtin_memory_class builtin_memory_program; +extern PFS_builtin_memory_class builtin_memory_prepared_stmt; + +extern PFS_builtin_memory_class builtin_memory_scalable_buffer; + +/** @} */ +#endif + diff --git a/storage/perfschema/pfs_column_types.h b/storage/perfschema/pfs_column_types.h index 09fce551402..b47f9ab938f 100644 --- a/storage/perfschema/pfs_column_types.h +++ b/storage/perfschema/pfs_column_types.h @@ -63,9 +63,6 @@ /** 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: @@ -114,78 +111,88 @@ enum enum_operation_type OPERATION_TYPE_LOCK= 1, OPERATION_TYPE_TRYLOCK= 2, - /* Rwlock operations */ + /* Rwlock operations (RW-lock) */ OPERATION_TYPE_READLOCK= 3, OPERATION_TYPE_WRITELOCK= 4, OPERATION_TYPE_TRYREADLOCK= 5, OPERATION_TYPE_TRYWRITELOCK= 6, + /* Rwlock operations (SX-lock) */ + OPERATION_TYPE_SHAREDLOCK= 7, + OPERATION_TYPE_SHAREDEXCLUSIVELOCK= 8, + OPERATION_TYPE_EXCLUSIVELOCK= 9, + OPERATION_TYPE_TRYSHAREDLOCK= 10, + OPERATION_TYPE_TRYSHAREDEXCLUSIVELOCK= 11, + OPERATION_TYPE_TRYEXCLUSIVELOCK= 12, + /* Cond operations */ - OPERATION_TYPE_WAIT= 7, - OPERATION_TYPE_TIMEDWAIT= 8, + OPERATION_TYPE_WAIT= 13, + OPERATION_TYPE_TIMEDWAIT= 14, /* File operations */ - OPERATION_TYPE_FILECREATE= 9, - OPERATION_TYPE_FILECREATETMP= 10, - OPERATION_TYPE_FILEOPEN= 11, - OPERATION_TYPE_FILESTREAMOPEN= 12, - OPERATION_TYPE_FILECLOSE= 13, - OPERATION_TYPE_FILESTREAMCLOSE= 14, - OPERATION_TYPE_FILEREAD= 15, - OPERATION_TYPE_FILEWRITE= 16, - OPERATION_TYPE_FILESEEK= 17, - OPERATION_TYPE_FILETELL= 18, - OPERATION_TYPE_FILEFLUSH= 19, - OPERATION_TYPE_FILESTAT= 20, - OPERATION_TYPE_FILEFSTAT= 21, - OPERATION_TYPE_FILECHSIZE= 22, - OPERATION_TYPE_FILEDELETE= 23, - OPERATION_TYPE_FILERENAME= 24, - OPERATION_TYPE_FILESYNC= 25, + OPERATION_TYPE_FILECREATE= 15, + OPERATION_TYPE_FILECREATETMP= 16, + OPERATION_TYPE_FILEOPEN= 17, + OPERATION_TYPE_FILESTREAMOPEN= 18, + OPERATION_TYPE_FILECLOSE= 19, + OPERATION_TYPE_FILESTREAMCLOSE= 20, + OPERATION_TYPE_FILEREAD= 21, + OPERATION_TYPE_FILEWRITE= 22, + OPERATION_TYPE_FILESEEK= 23, + OPERATION_TYPE_FILETELL= 24, + OPERATION_TYPE_FILEFLUSH= 25, + OPERATION_TYPE_FILESTAT= 26, + OPERATION_TYPE_FILEFSTAT= 27, + OPERATION_TYPE_FILECHSIZE= 28, + OPERATION_TYPE_FILEDELETE= 29, + OPERATION_TYPE_FILERENAME= 30, + OPERATION_TYPE_FILESYNC= 31, /* 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, + OPERATION_TYPE_TABLE_FETCH= 32, + OPERATION_TYPE_TABLE_WRITE_ROW= 33, + OPERATION_TYPE_TABLE_UPDATE_ROW= 34, + OPERATION_TYPE_TABLE_DELETE_ROW= 35, /* 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, + OPERATION_TYPE_TL_READ_NORMAL= 36, + OPERATION_TYPE_TL_READ_WITH_SHARED_LOCKS= 37, + OPERATION_TYPE_TL_READ_HIGH_PRIORITY= 38, + OPERATION_TYPE_TL_READ_NO_INSERTS= 39, + OPERATION_TYPE_TL_WRITE_ALLOW_WRITE= 40, + OPERATION_TYPE_TL_WRITE_CONCURRENT_INSERT= 41, + OPERATION_TYPE_TL_WRITE_LOW_PRIORITY= 42, + OPERATION_TYPE_TL_WRITE_NORMAL= 43, + OPERATION_TYPE_TL_READ_EXTERNAL= 44, + OPERATION_TYPE_TL_WRITE_EXTERNAL= 45, /* 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, + OPERATION_TYPE_SOCKETCREATE = 46, + OPERATION_TYPE_SOCKETCONNECT = 47, + OPERATION_TYPE_SOCKETBIND = 48, + OPERATION_TYPE_SOCKETCLOSE = 49, + OPERATION_TYPE_SOCKETSEND = 50, + OPERATION_TYPE_SOCKETRECV = 51, + OPERATION_TYPE_SOCKETSENDTO = 52, + OPERATION_TYPE_SOCKETRECVFROM = 53, + OPERATION_TYPE_SOCKETSENDMSG = 54, + OPERATION_TYPE_SOCKETRECVMSG = 55, + OPERATION_TYPE_SOCKETSEEK = 56, + OPERATION_TYPE_SOCKETOPT = 57, + OPERATION_TYPE_SOCKETSTAT = 58, + OPERATION_TYPE_SOCKETSHUTDOWN = 59, + OPERATION_TYPE_SOCKETSELECT = 60, /* Idle operation */ - OPERATION_TYPE_IDLE= 56 + OPERATION_TYPE_IDLE= 61, + + /* Metadata lock operation */ + OPERATION_TYPE_METADATA= 62 }; /** Integer, first value of @sa enum_operation_type. */ #define FIRST_OPERATION_TYPE (static_cast<int> (OPERATION_TYPE_LOCK)) /** Integer, last value of @sa enum_operation_type. */ -#define LAST_OPERATION_TYPE (static_cast<int> (OPERATION_TYPE_IDLE)) +#define LAST_OPERATION_TYPE (static_cast<int> (OPERATION_TYPE_METADATA)) /** Integer, number of values of @sa enum_operation_type. */ #define COUNT_OPERATION_TYPE (LAST_OPERATION_TYPE - FIRST_OPERATION_TYPE + 1) @@ -194,13 +201,30 @@ enum enum_operation_type */ enum enum_object_type { - OBJECT_TYPE_TABLE= 1, - OBJECT_TYPE_TEMPORARY_TABLE= 2 + NO_OBJECT_TYPE= 0, + + /* Advertised in SQL ENUM */ + + OBJECT_TYPE_EVENT= 1, + OBJECT_TYPE_FUNCTION= 2, + OBJECT_TYPE_PROCEDURE= 3, + OBJECT_TYPE_TABLE= 4, + OBJECT_TYPE_TRIGGER= 5, + + /* Not advertised in SQL ENUM, only displayed as VARCHAR */ + + OBJECT_TYPE_TEMPORARY_TABLE= 6, + OBJECT_TYPE_GLOBAL= 7, + OBJECT_TYPE_SCHEMA= 8, + OBJECT_TYPE_COMMIT= 9, + OBJECT_TYPE_USER_LEVEL_LOCK= 10, + OBJECT_TYPE_TABLESPACE= 11, + OBJECT_TYPE_LOCKING_SERVICE= 12 }; /** Integer, first value of @sa enum_object_type. */ -#define FIRST_OBJECT_TYPE (static_cast<int> (OBJECT_TYPE_TABLE)) +#define FIRST_OBJECT_TYPE (static_cast<int> (OBJECT_TYPE_EVENT)) /** Integer, last value of @sa enum_object_type. */ -#define LAST_OBJECT_TYPE (static_cast<int> (OBJECT_TYPE_TEMPORARY_TABLE)) +#define LAST_OBJECT_TYPE (static_cast<int> (OBJECT_TYPE_LOCKING_SERVICE)) /** Integer, number of values of @sa enum_object_type. */ #define COUNT_OBJECT_TYPE (LAST_OBJECT_TYPE - FIRST_OBJECT_TYPE + 1) @@ -213,17 +237,92 @@ enum enum_object_type */ enum enum_event_type { - EVENT_TYPE_STATEMENT= 1, - EVENT_TYPE_STAGE= 2, - EVENT_TYPE_WAIT= 3 + EVENT_TYPE_TRANSACTION= 1, + EVENT_TYPE_STATEMENT= 2, + EVENT_TYPE_STAGE= 3, + EVENT_TYPE_WAIT= 4 }; /** Integer, first value of @sa enum_event_type. */ -#define FIRST_EVENT_TYPE (static_cast<int> (EVENT_TYPE_STATEMENT)) +#define FIRST_EVENT_TYPE (static_cast<int> (EVENT_TYPE_TRANSACTION)) /** 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) +/** + Enum values for transaction state columns. +*/ +enum enum_transaction_state +{ + TRANS_STATE_ACTIVE= 1, + TRANS_STATE_COMMITTED= 2, + TRANS_STATE_ROLLED_BACK= 3 +}; + +/** Integer, first value of @sa enum_transaction_state. */ +#define FIRST_TRANS_STATE (static_cast<int> (TRANS_STATE_ACTIVE)) +/** Integer, last value of @sa enum_transaction_state. */ +#define LAST_TRANS_STATE (static_cast<int> (TRANS_STATE_ROLLED_BACK)) +/** Integer, number of values of @sa enum_transaction_state. */ +#define COUNT_TRANS_STATE (LAST_TRANS_STATE - FIRST_TRANS_STATE + 1) + +/** + Enum values for XA transaction state columns. Enums 1-5 match those used by + the server. See XID_STATE::enum xa_states in xa.h. +*/ +enum enum_xa_transaction_state +{ + TRANS_STATE_XA_NOTR, + TRANS_STATE_XA_ACTIVE, + TRANS_STATE_XA_IDLE, + TRANS_STATE_XA_PREPARED, + TRANS_STATE_XA_ROLLBACK_ONLY, + TRANS_STATE_XA_COMMITTED +}; + +/** Integer, first value of @sa enum_xa_transaction_state. */ +#define FIRST_TRANS_STATE_XA (static_cast<int> (TRANS_STATE_XA_NOTR)) +/** Integer, last value of @sa enum_xa_transaction_state. */ +#define LAST_TRANS_STATE_XA (static_cast<int> (TRANS_STATE_XA_COMMITTED)) +/** Integer, number of values of @sa enum_xa_transaction_state. */ +#define COUNT_TRANS_STATE_XA (LAST_TRANS_STATE_XA - FIRST_TRANS_STATE_XA + 1) + +/** + Enum values for transaction isolation level columns. + See enum_tx_isolation in handler.h. +*/ +enum enum_isolation_level +{ + TRANS_LEVEL_READ_UNCOMMITTED, + TRANS_LEVEL_READ_COMMITTED, + TRANS_LEVEL_REPEATABLE_READ, + TRANS_LEVEL_SERIALIZABLE +}; + +/** Integer, first value of @sa enum_isolation_level. */ +#define FIRST_TRANS_LEVEL (static_cast<int> (TRANS_LEVEL_READ_UNCOMMITTED)) +/** Integer, last value of @sa enum_isolation_level. */ +#define LAST_TRANS_LEVEL (static_cast<int> (TRANS_LEVEL_SERIALIZABLE)) +/** Integer, number of values of @sa enum_isolation_level. */ +#define COUNT_TRANS_LEVEL (LAST_TRANS_LEVEL - FIRST_TRANS_LEVEL + 1) + +/** + Enum values for transaction acces mode columns. +*/ +enum enum_transaction_mode +{ + TRANS_MODE_READ_ONLY= 1, + TRANS_MODE_READ_WRITE= 2 +}; + +/** Integer, first value of @sa enum_transaction_mode. */ +#define FIRST_TRANS_MODE (static_cast<int> (TRANS_MODE_READ_WRITE)) +/** Integer, last value of @sa enum_transaction_mode. */ +#define LAST_TRANS_MODE (static_cast<int> (TRANS_MODE_READ_ONLY)) +/** Integer, number of values of @sa enum_transaction_mode. */ +#define COUNT_TRANS_MODE (LAST_TRANS_MODE - FIRST_TRANS_MODE + 1) + + #endif diff --git a/storage/perfschema/pfs_column_values.cc b/storage/perfschema/pfs_column_values.cc index 043c8fd2f38..9ce9b3b416d 100644 --- a/storage/perfschema/pfs_column_values.cc +++ b/storage/perfschema/pfs_column_values.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -38,8 +38,11 @@ LEX_CSTRING mutex_instrument_prefix= LEX_CSTRING rwlock_instrument_prefix= { STRING_WITH_LEN("wait/synch/rwlock/") }; +LEX_CSTRING sxlock_instrument_prefix= +{ C_STRING_WITH_LEN("wait/synch/sxlock/") }; + LEX_CSTRING cond_instrument_prefix= -{ STRING_WITH_LEN("wait/synch/cond/") }; +{ C_STRING_WITH_LEN("wait/synch/cond/") }; LEX_CSTRING thread_instrument_prefix= { STRING_WITH_LEN("thread/") }; @@ -53,5 +56,12 @@ LEX_CSTRING stage_instrument_prefix= LEX_CSTRING statement_instrument_prefix= { STRING_WITH_LEN("statement/") }; +LEX_CSTRING transaction_instrument_prefix= +{ C_STRING_WITH_LEN("transaction") }; + LEX_CSTRING socket_instrument_prefix= -{ STRING_WITH_LEN("wait/io/socket/") }; +{ C_STRING_WITH_LEN("wait/io/socket/") }; + +LEX_CSTRING memory_instrument_prefix= +{ C_STRING_WITH_LEN("memory/") }; + diff --git a/storage/perfschema/pfs_column_values.h b/storage/perfschema/pfs_column_values.h index 44f23527881..ea3d9eb97c3 100644 --- a/storage/perfschema/pfs_column_values.h +++ b/storage/perfschema/pfs_column_values.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -23,7 +23,7 @@ #ifndef PFS_COLUMN_VALUES_H #define PFS_COLUMN_VALUES_H -#include "m_string.h" /* LEX_STRING */ +#include "m_string.h" /* LEX_CSTRING */ /** @file storage/perfschema/pfs_column_values.h @@ -38,6 +38,8 @@ extern LEX_CSTRING PERFORMANCE_SCHEMA_str; extern LEX_CSTRING mutex_instrument_prefix; /** String prefix for all rwlock instruments. */ extern LEX_CSTRING rwlock_instrument_prefix; +/** String prefix for all sxlock instruments. */ +extern LEX_CSTRING sxlock_instrument_prefix; /** String prefix for all cond instruments. */ extern LEX_CSTRING cond_instrument_prefix; /** String prefix for all thread instruments. */ @@ -48,7 +50,12 @@ extern LEX_CSTRING file_instrument_prefix; extern LEX_CSTRING stage_instrument_prefix; /** String prefix for all statement instruments. */ extern LEX_CSTRING statement_instrument_prefix; +/** String prefix for all transaction instruments. */ +extern LEX_CSTRING transaction_instrument_prefix; +/** String prefix for all socket instruments. */ extern LEX_CSTRING socket_instrument_prefix; +/** String prefix for all memory instruments. */ +extern LEX_CSTRING memory_instrument_prefix; #endif diff --git a/storage/perfschema/pfs_con_slice.cc b/storage/perfschema/pfs_con_slice.cc index 9f9deb0919c..3733ad9e3d0 100644 --- a/storage/perfschema/pfs_con_slice.cc +++ b/storage/perfschema/pfs_con_slice.cc @@ -22,7 +22,7 @@ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_con_slice.h" #include "pfs_stat.h" #include "pfs_global.h" @@ -38,66 +38,6 @@ @{ */ -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; @@ -122,5 +62,21 @@ void PFS_connection_slice::reset_statements_stats() stat->reset(); } +void PFS_connection_slice::reset_transactions_stats() +{ + PFS_transaction_stat *stat= + &m_instr_class_transactions_stats[GLOBAL_TRANSACTION_INDEX]; + if (stat) + stat->reset(); +} + +void PFS_connection_slice::rebase_memory_stats() +{ + PFS_memory_stat *stat= m_instr_class_memory_stats; + PFS_memory_stat *stat_last= stat + memory_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 index ed17de5f2b0..56497ffe771 100644 --- a/storage/perfschema/pfs_con_slice.h +++ b/storage/perfschema/pfs_con_slice.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -28,12 +28,17 @@ Performance schema connection slice (declarations). */ +#include "sql_class.h" #include "pfs_lock.h" #include "lf.h" +#include "pfs_status.h" struct PFS_single_stat; struct PFS_stage_stat; struct PFS_statement_stat; +struct PFS_transaction_stat; +struct PFS_memory_stat; +class PFS_opaque_container_page; /** @addtogroup Performance_schema_buffers @@ -46,31 +51,15 @@ struct PFS_statement_stat; */ 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(); + m_has_waits_stats= false; + m_has_stages_stats= false; + m_has_statements_stats= false; + m_has_transactions_stats= false; + m_has_memory_stats= false; + reset_status_stats(); } /** Reset all wait statistics. */ @@ -79,6 +68,137 @@ struct PFS_connection_slice void reset_stages_stats(); /** Reset all statements statistics. */ void reset_statements_stats(); + /** Reset all transactions statistics. */ + void reset_transactions_stats(); + /** Reset all memory statistics. */ + void rebase_memory_stats(); + /** Reset all status variable statistics. */ + void reset_status_stats() + { + m_status_stats.reset(); + } + + void set_instr_class_waits_stats(PFS_single_stat *array) + { + m_has_waits_stats= false; + m_instr_class_waits_stats= array; + } + + const PFS_single_stat* read_instr_class_waits_stats() const + { + if (! m_has_waits_stats) + return NULL; + return m_instr_class_waits_stats; + } + + PFS_single_stat* write_instr_class_waits_stats() + { + if (! m_has_waits_stats) + { + reset_waits_stats(); + m_has_waits_stats= true; + } + return m_instr_class_waits_stats; + } + + void set_instr_class_stages_stats(PFS_stage_stat *array) + { + m_has_stages_stats= false; + m_instr_class_stages_stats= array; + } + + const PFS_stage_stat* read_instr_class_stages_stats() const + { + if (! m_has_stages_stats) + return NULL; + return m_instr_class_stages_stats; + } + + PFS_stage_stat* write_instr_class_stages_stats() + { + if (! m_has_stages_stats) + { + reset_stages_stats(); + m_has_stages_stats= true; + } + return m_instr_class_stages_stats; + } + + void set_instr_class_statements_stats(PFS_statement_stat *array) + { + m_has_statements_stats= false; + m_instr_class_statements_stats= array; + } + + const PFS_statement_stat* read_instr_class_statements_stats() const + { + if (! m_has_statements_stats) + return NULL; + return m_instr_class_statements_stats; + } + + PFS_statement_stat* write_instr_class_statements_stats() + { + if (! m_has_statements_stats) + { + reset_statements_stats(); + m_has_statements_stats= true; + } + return m_instr_class_statements_stats; + } + + void set_instr_class_transactions_stats(PFS_transaction_stat *array) + { + m_has_transactions_stats= false; + m_instr_class_transactions_stats= array; + } + + const PFS_transaction_stat* read_instr_class_transactions_stats() const + { + if (! m_has_transactions_stats) + return NULL; + return m_instr_class_transactions_stats; + } + + PFS_transaction_stat* write_instr_class_transactions_stats() + { + if (! m_has_transactions_stats) + { + reset_transactions_stats(); + m_has_transactions_stats= true; + } + return m_instr_class_transactions_stats; + } + + void set_instr_class_memory_stats(PFS_memory_stat *array) + { + m_has_memory_stats= false; + m_instr_class_memory_stats= array; + } + + const PFS_memory_stat* read_instr_class_memory_stats() const + { + if (! m_has_memory_stats) + return NULL; + return m_instr_class_memory_stats; + } + + PFS_memory_stat* write_instr_class_memory_stats() + { + if (! m_has_memory_stats) + { + rebase_memory_stats(); + m_has_memory_stats= true; + } + return m_instr_class_memory_stats; + } + +private: + bool m_has_waits_stats; + bool m_has_stages_stats; + bool m_has_statements_stats; + bool m_has_transactions_stats; + bool m_has_memory_stats; /** Per connection slice waits aggregated statistics. @@ -103,6 +223,37 @@ struct PFS_connection_slice Immutable, safe to use without internal lock. */ PFS_statement_stat *m_instr_class_statements_stats; + + /** + Per connection slice transactions aggregated statistics. + This member holds the data for the table + PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_SUMMARY_BY_*_BY_EVENT_NAME. + Immutable, safe to use without internal lock. + */ + PFS_transaction_stat *m_instr_class_transactions_stats; + + /** + Per connection slice memory aggregated statistics. + This member holds the data for the table + PERFORMANCE_SCHEMA.MEMORY_SUMMARY_BY_*_BY_EVENT_NAME. + Immutable, safe to use without internal lock. + */ + PFS_memory_stat *m_instr_class_memory_stats; + +public: + + void aggregate_status_stats(const STATUS_VAR *status_vars) + { + m_status_stats.aggregate_from(status_vars); + } + + /** + Aggregated status variables. + */ + PFS_status_stats m_status_stats; + + /** Container page. */ + PFS_opaque_container_page *m_page; }; /** @} */ diff --git a/storage/perfschema/pfs_defaults.cc b/storage/perfschema/pfs_defaults.cc index f6183349884..0b615773089 100644 --- a/storage/perfschema/pfs_defaults.cc +++ b/storage/perfschema/pfs_defaults.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -28,12 +28,15 @@ #include <my_global.h> #include "pfs.h" #include "pfs_defaults.h" +#include "pfs_instr_class.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 }; +static PSI_thread_key thread_key; +static PSI_thread_info thread_info= { &thread_key, "setup", PSI_FLAG_GLOBAL }; + +const char* pfs_category= "performance_schema"; void install_default_setup(PSI_bootstrap *boot) { @@ -41,30 +44,62 @@ void install_default_setup(PSI_bootstrap *boot) 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_utf8mb3_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_utf8mb3_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_utf8mb3_bin); - String IS_db("information_schema", 18, &my_charset_utf8mb3_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->register_thread(pfs_category, &thread_info, 1); + PSI_thread *psi_thread= psi->new_thread(thread_key, NULL, 0); + + if (psi_thread != NULL) + { + /* LF_HASH needs a thread, for PINS */ + psi->set_thread(psi_thread); + + String percent("%", 1, &my_charset_utf8mb3_bin); + /* Enable all users on all hosts by default */ + insert_setup_actor(&percent, &percent, &percent, true, true); + + String mysql_db("mysql", 5, &my_charset_utf8mb3_bin); + String PS_db("performance_schema", 18, &my_charset_utf8mb3_bin); + String IS_db("information_schema", 18, &my_charset_utf8mb3_bin); + + /* Disable sp by default in mysql. */ + insert_setup_object(OBJECT_TYPE_EVENT, &mysql_db, &percent, false, false); + /* Disable sp in performance/information schema. */ + insert_setup_object(OBJECT_TYPE_EVENT, &PS_db, &percent, false, false); + insert_setup_object(OBJECT_TYPE_EVENT, &IS_db, &percent, false, false); + /* Enable every other sp. */ + insert_setup_object(OBJECT_TYPE_EVENT, &percent, &percent, true, true); + + /* Disable sp by default in mysql. */ + insert_setup_object(OBJECT_TYPE_FUNCTION, &mysql_db, &percent, false, false); + /* Disable sp in performance/information schema. */ + insert_setup_object(OBJECT_TYPE_FUNCTION, &PS_db, &percent, false, false); + insert_setup_object(OBJECT_TYPE_FUNCTION, &IS_db, &percent, false, false); + /* Enable every other sp. */ + insert_setup_object(OBJECT_TYPE_FUNCTION, &percent, &percent, true, true); + + /* Disable sp by default in mysql. */ + insert_setup_object(OBJECT_TYPE_PROCEDURE, &mysql_db, &percent, false, false); + /* Disable sp in performance/information schema. */ + insert_setup_object(OBJECT_TYPE_PROCEDURE, &PS_db, &percent, false, false); + insert_setup_object(OBJECT_TYPE_PROCEDURE, &IS_db, &percent, false, false); + /* Enable every other sp. */ + insert_setup_object(OBJECT_TYPE_PROCEDURE, &percent, &percent, true, true); + + /* Disable system tables by default */ + insert_setup_object(OBJECT_TYPE_TABLE, &mysql_db, &percent, false, false); + /* Disable performance/information schema tables. */ + 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); + + /* Disable sp by default in mysql. */ + insert_setup_object(OBJECT_TYPE_TRIGGER, &mysql_db, &percent, false, false); + /* Disable sp in performance/information schema. */ + insert_setup_object(OBJECT_TYPE_TRIGGER, &PS_db, &percent, false, false); + insert_setup_object(OBJECT_TYPE_TRIGGER, &IS_db, &percent, false, false); + /* Enable every other sp. */ + insert_setup_object(OBJECT_TYPE_TRIGGER, &percent, &percent, true, true); + } psi->delete_current_thread(); } diff --git a/storage/perfschema/pfs_digest.cc b/storage/perfschema/pfs_digest.cc index 0ddb4c90eb3..6f0b93f9393 100644 --- a/storage/perfschema/pfs_digest.cc +++ b/storage/perfschema/pfs_digest.cc @@ -36,8 +36,10 @@ #include "pfs_instr.h" #include "pfs_digest.h" #include "pfs_global.h" +#include "pfs_builtin_memory.h" #include "table_helper.h" #include "sql_lex.h" +#include "sql_signal.h" #include "sql_get_diagnostics.h" #include "sql_string.h" #include <string.h> @@ -54,7 +56,8 @@ 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; +static PFS_ALIGNED PFS_cacheline_uint32 digest_monotonic_index; + bool digest_full= false; LF_HASH digest_hash; @@ -72,16 +75,16 @@ int init_digest(const PFS_global_param *param) */ digest_max= param->m_digest_sizing; digest_lost= 0; - PFS_atomic::store_u32(& digest_monotonic_index, 1); + PFS_atomic::store_u32(& digest_monotonic_index.m_u32, 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, + PFS_MALLOC_ARRAY(& builtin_memory_digest, + digest_max, + sizeof(PFS_statements_digest_stat), PFS_statements_digest_stat, MYF(MY_ZEROFILL)); if (unlikely(statements_digest_stat_array == NULL)) @@ -96,7 +99,8 @@ int init_digest(const PFS_global_param *param) size_t digest_memory_size= pfs_max_digest_length * sizeof(unsigned char); statements_digest_token_array= - PFS_MALLOC_ARRAY(digest_max, + PFS_MALLOC_ARRAY(& builtin_memory_digest_tokens, + digest_max, digest_memory_size, unsigned char, MYF(MY_ZEROFILL)); @@ -117,15 +121,25 @@ int init_digest(const PFS_global_param *param) /* Set record[0] as allocated. */ statements_digest_stat_array[0].m_lock.set_allocated(); + /* 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); + PFS_FREE_ARRAY(& builtin_memory_digest, + digest_max, + sizeof(PFS_statements_digest_stat), + statements_digest_stat_array); + + PFS_FREE_ARRAY(& builtin_memory_digest_tokens, + digest_max, + (pfs_max_digest_length * sizeof(unsigned char)), + statements_digest_token_array); + statements_digest_stat_array= NULL; statements_digest_token_array= NULL; } @@ -152,14 +166,13 @@ C_MODE_END Initialize the digest hash. @return 0 on success */ -int init_digest_hash(void) +int init_digest_hash(const PFS_global_param *param) { - if ((! digest_hash_inited) && (digest_max > 0)) + if ((! digest_hash_inited) && (param->m_digest_sizing != 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; @@ -225,6 +238,7 @@ find_or_create_digest(PFS_thread *thread, size_t attempts= 0; PFS_statements_digest_stat **entry; PFS_statements_digest_stat *pfs= NULL; + pfs_dirty_state dirty_state; ulonglong now= my_hrtime().val; @@ -248,7 +262,7 @@ search: if (digest_full) { - /* digest_stat array is full. Add stat at index 0 and return. */ + /* digest_stat array is full. Add stat at index 0 and return. */ pfs= &statements_digest_stat_array[0]; digest_lost++; @@ -260,7 +274,7 @@ search: while (++attempts <= digest_max) { - safe_index= PFS_atomic::add_u32(& digest_monotonic_index, 1) % digest_max; + safe_index= PFS_atomic::add_u32(& digest_monotonic_index.m_u32, 1) % digest_max; if (safe_index == 0) { /* Record [0] is reserved. */ @@ -273,7 +287,7 @@ search: if (pfs->m_lock.is_free()) { - if (pfs->m_lock.free_to_dirty()) + if (pfs->m_lock.free_to_dirty(& dirty_state)) { /* Copy digest hash/LF Hash search key. */ memcpy(& pfs->m_digest_key, &hash_key, sizeof(PFS_digest_key)); @@ -290,11 +304,11 @@ search: res= lf_hash_insert(&digest_hash, pins, &pfs); if (likely(res == 0)) { - pfs->m_lock.dirty_to_allocated(); + pfs->m_lock.dirty_to_allocated(& dirty_state); return & pfs->m_stat; } - pfs->m_lock.dirty_to_free(); + pfs->m_lock.dirty_to_free(& dirty_state); if (res > 0) { @@ -349,12 +363,13 @@ void purge_digest(PFS_thread* thread, PFS_digest_key *hash_key) void PFS_statements_digest_stat::reset_data(unsigned char *token_array, size_t length) { - m_lock.set_dirty(); + pfs_dirty_state dirty_state; + m_lock.set_dirty(& dirty_state); m_digest_storage.reset(token_array, length); m_stat.reset(); m_first_seen= 0; m_last_seen= 0; - m_lock.dirty_to_free(); + m_lock.dirty_to_free(& dirty_state); } void PFS_statements_digest_stat::reset_index(PFS_thread *thread) @@ -368,6 +383,8 @@ void PFS_statements_digest_stat::reset_index(PFS_thread *thread) void reset_esms_by_digest() { + uint index; + if (statements_digest_stat_array == NULL) return; @@ -376,7 +393,7 @@ void reset_esms_by_digest() return; /* Reset statements_digest_stat_array. */ - for (size_t index= 0; index < digest_max; index++) + for (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); @@ -389,7 +406,7 @@ void reset_esms_by_digest() 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); + PFS_atomic::store_u32(& digest_monotonic_index.m_u32, 1); digest_full= false; } diff --git a/storage/perfschema/pfs_digest.h b/storage/perfschema/pfs_digest.h index c11852a1510..39fe6109c20 100644 --- a/storage/perfschema/pfs_digest.h +++ b/storage/perfschema/pfs_digest.h @@ -76,7 +76,7 @@ struct PFS_ALIGNED PFS_statements_digest_stat int init_digest(const PFS_global_param *param); void cleanup_digest(); -int init_digest_hash(void); +int init_digest_hash(const PFS_global_param *param); void cleanup_digest_hash(void); PFS_statement_stat* find_or_create_digest(PFS_thread *thread, const sql_digest_storage *digest_storage, @@ -91,3 +91,4 @@ 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 9a18879bc62..98028e38024 100644 --- a/storage/perfschema/pfs_engine_table.cc +++ b/storage/perfschema/pfs_engine_table.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, @@ -26,9 +26,10 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "hostname.h" /* For Host_entry */ #include "pfs_engine_table.h" +#include "pfs_buffer_container.h" #include "table_events_waits.h" #include "table_setup_actors.h" @@ -69,6 +70,14 @@ #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_esms_by_program.h" + +#include "table_events_transactions.h" +#include "table_ets_by_thread_by_event_name.h" +#include "table_ets_by_host_by_event_name.h" +#include "table_ets_by_user_by_event_name.h" +#include "table_ets_by_account_by_event_name.h" +#include "table_ets_global_by_event_name.h" #include "table_users.h" #include "table_accounts.h" @@ -79,6 +88,39 @@ #include "table_socket_summary_by_event_name.h" #include "table_session_connect_attrs.h" #include "table_session_account_connect_attrs.h" +#include "table_mems_global_by_event_name.h" +#include "table_mems_by_account_by_event_name.h" +#include "table_mems_by_host_by_event_name.h" +#include "table_mems_by_thread_by_event_name.h" +#include "table_mems_by_user_by_event_name.h" + +/* For replication related perfschema tables. */ +#include "table_replication_connection_configuration.h" +#include "table_replication_group_members.h" +#include "table_replication_connection_status.h" +#include "table_replication_applier_configuration.h" +#include "table_replication_applier_status.h" +#include "table_replication_applier_status_by_coordinator.h" +#include "table_replication_applier_status_by_worker.h" +#include "table_replication_group_member_stats.h" + +#include "table_prepared_stmt_instances.h" + +#include "table_md_locks.h" +#include "table_table_handles.h" + +#include "table_uvar_by_thread.h" + +#include "table_status_by_account.h" +#include "table_status_by_host.h" +#include "table_status_by_thread.h" +#include "table_status_by_user.h" +#include "table_global_status.h" +#include "table_session_status.h" + +#include "table_variables_by_thread.h" +#include "table_global_variables.h" +#include "table_session_variables.h" /* For show status */ #include "pfs_column_values.h" @@ -91,12 +133,105 @@ #include "sql_base.h" // close_thread_tables #include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT +#include "log.h" /** @addtogroup Performance_schema_engine @{ */ +bool PFS_table_context::initialize(void) +{ + if (m_restore) + { + /* Restore context from TLS. */ + PFS_table_context *context= static_cast<PFS_table_context *>(my_get_thread_local(m_thr_key)); + DBUG_ASSERT(context != NULL); + + if(context) + { + m_last_version= context->m_current_version; + m_map= context->m_map; + DBUG_ASSERT(m_map_size == context->m_map_size); + m_map_size= context->m_map_size; + m_word_size= context->m_word_size; + } + } + else + { + /* Check that TLS is not in use. */ + PFS_table_context *context= static_cast<PFS_table_context *>(my_get_thread_local(m_thr_key)); + //DBUG_ASSERT(context == NULL); + + context= this; + + /* Initialize a new context, store in TLS. */ + m_last_version= m_current_version; + m_map= NULL; + m_word_size= sizeof(ulong) * 8; + + /* Allocate a bitmap to record which threads are materialized. */ + if (m_map_size > 0) + { + THD *thd= current_thd; + ulong words= m_map_size / m_word_size + (m_map_size % m_word_size > 0); + m_map= (ulong *)thd->calloc(words * m_word_size); + } + + /* Write to TLS. */ + my_set_thread_local(m_thr_key, static_cast<void *>(context)); + } + + m_initialized= (m_map_size > 0) ? (m_map != NULL) : true; + + return m_initialized; +} + +/* Constructor for global or single thread tables, map size = 0. */ +PFS_table_context::PFS_table_context(ulonglong current_version, bool restore, thread_local_key_t key) : + m_thr_key(key), m_current_version(current_version), m_last_version(0), + m_map(NULL), m_map_size(0), m_word_size(sizeof(ulong)), + m_restore(restore), m_initialized(false), m_last_item(0) +{ + initialize(); +} + +/* Constructor for by-thread or aggregate tables, map size = max thread/user/host/account. */ +PFS_table_context::PFS_table_context(ulonglong current_version, ulong map_size, bool restore, thread_local_key_t key) : + m_thr_key(key), m_current_version(current_version), m_last_version(0), + m_map(NULL), m_map_size(map_size), m_word_size(sizeof(ulong)), + m_restore(restore), m_initialized(false), m_last_item(0) +{ + initialize(); +} + +PFS_table_context::~PFS_table_context(void) +{ + /* Clear TLS after final use. */ // TODO: How is that determined? +// if (m_restore) +// { +// my_set_thread_local(m_thr_key, NULL); +// } +} + +void PFS_table_context::set_item(ulong n) +{ + if (n == m_last_item) + return; + ulong word= n / m_word_size; + ulong bit= n % m_word_size; + m_map[word] |= (1 << bit); + m_last_item= n; +} + +bool PFS_table_context::is_item_set(ulong n) +{ + ulong word= n / m_word_size; + ulong bit= n % m_word_size; + return (m_map[word] & (1 << bit)); +} + + static PFS_engine_table_share *all_shares[]= { &table_cond_instances::m_share, @@ -145,6 +280,16 @@ static PFS_engine_table_share *all_shares[]= &table_esms_by_host_by_event_name::m_share, &table_esms_global_by_event_name::m_share, &table_esms_by_digest::m_share, + &table_esms_by_program::m_share, + + &table_events_transactions_current::m_share, + &table_events_transactions_history::m_share, + &table_events_transactions_history_long::m_share, + &table_ets_by_thread_by_event_name::m_share, + &table_ets_by_account_by_event_name::m_share, + &table_ets_by_user_by_event_name::m_share, + &table_ets_by_host_by_event_name::m_share, + &table_ets_global_by_event_name::m_share, &table_users::m_share, &table_accounts::m_share, @@ -153,8 +298,41 @@ static PFS_engine_table_share *all_shares[]= &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, + + &table_mems_global_by_event_name::m_share, + &table_mems_by_account_by_event_name::m_share, + &table_mems_by_host_by_event_name::m_share, + &table_mems_by_thread_by_event_name::m_share, + &table_mems_by_user_by_event_name::m_share, + &table_table_handles::m_share, + &table_metadata_locks::m_share, + + &table_replication_connection_configuration::m_share, + &table_replication_group_members::m_share, + &table_replication_connection_status::m_share, + &table_replication_applier_configuration::m_share, + &table_replication_applier_status::m_share, + &table_replication_applier_status_by_coordinator::m_share, + &table_replication_applier_status_by_worker::m_share, + &table_replication_group_member_stats::m_share, + + &table_prepared_stmt_instances::m_share, + + &table_uvar_by_thread::m_share, + &table_status_by_account::m_share, + &table_status_by_host::m_share, + &table_status_by_thread::m_share, + &table_status_by_user::m_share, + &table_global_status::m_share, + &table_session_status::m_share, + + &table_variables_by_thread::m_share, + &table_global_variables::m_share, + &table_session_variables::m_share, + NULL }; @@ -178,11 +356,7 @@ void PFS_engine_table_share::delete_all_locks(void) ha_rows PFS_engine_table_share::get_row_count(void) const { - /* If available, count the exact number or records */ - if (m_get_row_count) - return m_get_row_count(); - /* Otherwise, return an estimate */ - return m_records; + return m_get_row_count(); } int PFS_engine_table_share::write_row(TABLE *table, const unsigned char *buf, @@ -356,6 +530,13 @@ void PFS_engine_table::get_normalizer(PFS_instr_class *instr_class) } } +void PFS_engine_table::set_field_long(Field *f, long value) +{ + DBUG_ASSERT(f->real_type() == MYSQL_TYPE_LONG); + Field_long *f2= (Field_long*) f; + f2->store(value, false); +} + void PFS_engine_table::set_field_ulong(Field *f, ulong value) { DBUG_ASSERT(f->real_type() == MYSQL_TYPE_LONG); @@ -363,6 +544,13 @@ void PFS_engine_table::set_field_ulong(Field *f, ulong value) f2->store(value, true); } +void PFS_engine_table::set_field_longlong(Field *f, longlong value) +{ + DBUG_ASSERT(f->real_type() == MYSQL_TYPE_LONGLONG); + Field_longlong *f2= (Field_longlong*) f; + f2->store(value, false); +} + void PFS_engine_table::set_field_ulonglong(Field *f, ulonglong value) { DBUG_ASSERT(f->real_type() == MYSQL_TYPE_LONGLONG); @@ -378,6 +566,16 @@ void PFS_engine_table::set_field_char_utf8(Field *f, const char* str, f2->store(str, len, &my_charset_utf8mb3_bin); } +void PFS_engine_table::set_field_varchar(Field *f, + const CHARSET_INFO *cs, + const char* str, + uint len) +{ + DBUG_ASSERT(f->real_type() == MYSQL_TYPE_VARCHAR); + Field_varstring *f2= (Field_varstring*) f; + f2->store(str, len, cs); +} + void PFS_engine_table::set_field_varchar_utf8(Field *f, const char* str, uint len) { @@ -394,6 +592,14 @@ void PFS_engine_table::set_field_longtext_utf8(Field *f, const char* str, f2->store(str, len, &my_charset_utf8mb3_bin); } +void PFS_engine_table::set_field_blob(Field *f, const char* val, + uint len) +{ + DBUG_ASSERT(f->real_type() == MYSQL_TYPE_BLOB); + Field_blob *f2= (Field_blob*) f; + f2->store(val, len, &my_charset_utf8_bin); +} + void PFS_engine_table::set_field_enum(Field *f, ulonglong value) { DBUG_ASSERT(f->real_type() == MYSQL_TYPE_ENUM); @@ -408,6 +614,13 @@ void PFS_engine_table::set_field_timestamp(Field *f, ulonglong value) f2->store_TIME((long)(value / 1000000), (value % 1000000)); } +void PFS_engine_table::set_field_double(Field *f, double value) +{ + DBUG_ASSERT(f->real_type() == MYSQL_TYPE_DOUBLE); + Field_double *f2= (Field_double*) f; + f2->store(value); +} + ulonglong PFS_engine_table::get_field_enum(Field *f) { DBUG_ASSERT(f->real_type() == MYSQL_TYPE_ENUM); @@ -508,6 +721,31 @@ void initialize_performance_schema_acl(bool bootstrap) } } +static bool allow_drop_table_privilege() { + /* + The same DROP_ACL privilege is used for different statements, + in particular: + - TRUNCATE TABLE + - DROP TABLE + - ALTER TABLE + Here, we want to prevent DROP / ALTER while allowing TRUNCATE. + Note that we must also allow GRANT to transfer the truncate privilege. + */ + THD *thd= current_thd; + if (thd == NULL) { + return false; + } + + DBUG_ASSERT(thd->lex != NULL); + if ((thd->lex->sql_command != SQLCOM_TRUNCATE) && + (thd->lex->sql_command != SQLCOM_GRANT)) { + return false; + } + + return true; +} + + PFS_readonly_acl pfs_readonly_acl; ACL_internal_access_result @@ -523,6 +761,22 @@ PFS_readonly_acl::check(privilege_t want_access, privilege_t *save_priv) const return ACL_INTERNAL_ACCESS_CHECK_GRANT; } + +PFS_readonly_world_acl pfs_readonly_world_acl; + +ACL_internal_access_result +PFS_readonly_world_acl::check(ulong want_access, ulong *save_priv) const +{ + ACL_internal_access_result res= PFS_readonly_acl::check(want_access, save_priv); + if (res == ACL_INTERNAL_ACCESS_CHECK_GRANT) + { + if (want_access == SELECT_ACL) + res= ACL_INTERNAL_ACCESS_GRANTED; + } + return res; +} + + PFS_truncatable_acl pfs_truncatable_acl; ACL_internal_access_result @@ -538,6 +792,27 @@ PFS_truncatable_acl::check(privilege_t want_access, privilege_t *save_priv) cons return ACL_INTERNAL_ACCESS_CHECK_GRANT; } + +PFS_truncatable_world_acl pfs_truncatable_world_acl; + +ACL_internal_access_result +PFS_truncatable_world_acl::check(ulong want_access, ulong *save_priv) const +{ + ACL_internal_access_result res= PFS_truncatable_acl::check(want_access, save_priv); + if (res == ACL_INTERNAL_ACCESS_CHECK_GRANT) + { + if (want_access == DROP_ACL) + { + if (allow_drop_table_privilege()) + res= ACL_INTERNAL_ACCESS_GRANTED; + } + else if (want_access == SELECT_ACL) + res= ACL_INTERNAL_ACCESS_GRANTED; + } + return res; +} + + PFS_updatable_acl pfs_updatable_acl; ACL_internal_access_result @@ -626,33 +901,33 @@ bool pfs_show_status(handlerton *hton, THD *thd, { switch (i){ case 0: - name= "events_waits_current.row_size"; + name= "events_waits_current.size"; size= sizeof(PFS_events_waits); break; case 1: - name= "events_waits_current.row_count"; - size= WAIT_STACK_SIZE * thread_max; + name= "events_waits_current.count"; + size= WAIT_STACK_SIZE * global_thread_container.get_row_count(); break; case 2: - name= "events_waits_history.row_size"; + name= "events_waits_history.size"; size= sizeof(PFS_events_waits); break; case 3: - name= "events_waits_history.row_count"; - size= events_waits_history_per_thread * thread_max; + name= "events_waits_history.count"; + size= events_waits_history_per_thread * global_thread_container.get_row_count(); break; case 4: name= "events_waits_history.memory"; - size= events_waits_history_per_thread * thread_max + size= events_waits_history_per_thread * global_thread_container.get_row_count() * sizeof(PFS_events_waits); total_memory+= size; break; case 5: - name= "events_waits_history_long.row_size"; + name= "events_waits_history_long.size"; size= sizeof(PFS_events_waits); break; case 6: - name= "events_waits_history_long.row_count"; + name= "events_waits_history_long.count"; size= events_waits_history_long_size; break; case 7: @@ -661,11 +936,11 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 8: - name= "(pfs_mutex_class).row_size"; + name= "(pfs_mutex_class).size"; size= sizeof(PFS_mutex_class); break; case 9: - name= "(pfs_mutex_class).row_count"; + name= "(pfs_mutex_class).count"; size= mutex_class_max; break; case 10: @@ -674,11 +949,11 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 11: - name= "(pfs_rwlock_class).row_size"; + name= "(pfs_rwlock_class).size"; size= sizeof(PFS_rwlock_class); break; case 12: - name= "(pfs_rwlock_class).row_count"; + name= "(pfs_rwlock_class).count"; size= rwlock_class_max; break; case 13: @@ -687,11 +962,11 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 14: - name= "(pfs_cond_class).row_size"; + name= "(pfs_cond_class).size"; size= sizeof(PFS_cond_class); break; case 15: - name= "(pfs_cond_class).row_count"; + name= "(pfs_cond_class).count"; size= cond_class_max; break; case 16: @@ -700,11 +975,11 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 17: - name= "(pfs_thread_class).row_size"; + name= "(pfs_thread_class).size"; size= sizeof(PFS_thread_class); break; case 18: - name= "(pfs_thread_class).row_count"; + name= "(pfs_thread_class).count"; size= thread_class_max; break; case 19: @@ -713,11 +988,11 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 20: - name= "(pfs_file_class).row_size"; + name= "(pfs_file_class).size"; size= sizeof(PFS_file_class); break; case 21: - name= "(pfs_file_class).row_count"; + name= "(pfs_file_class).count"; size= file_class_max; break; case 22: @@ -726,76 +1001,76 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 23: - name= "mutex_instances.row_size"; - size= sizeof(PFS_mutex); + name= "mutex_instances.size"; + size= global_mutex_container.get_row_size(); break; case 24: - name= "mutex_instances.row_count"; - size= mutex_max; + name= "mutex_instances.count"; + size= global_mutex_container.get_row_count(); break; case 25: name= "mutex_instances.memory"; - size= mutex_max * sizeof(PFS_mutex); + size= global_mutex_container.get_memory(); total_memory+= size; break; case 26: - name= "rwlock_instances.row_size"; - size= sizeof(PFS_rwlock); + name= "rwlock_instances.size"; + size= global_rwlock_container.get_row_size(); break; case 27: - name= "rwlock_instances.row_count"; - size= rwlock_max; + name= "rwlock_instances.count"; + size= global_rwlock_container.get_row_count(); break; case 28: name= "rwlock_instances.memory"; - size= rwlock_max * sizeof(PFS_rwlock); + size= global_rwlock_container.get_memory(); total_memory+= size; break; case 29: - name= "cond_instances.row_size"; - size= sizeof(PFS_cond); + name= "cond_instances.size"; + size= global_cond_container.get_row_size(); break; case 30: - name= "cond_instances.row_count"; - size= cond_max; + name= "cond_instances.count"; + size= global_cond_container.get_row_count(); break; case 31: name= "cond_instances.memory"; - size= cond_max * sizeof(PFS_cond); + size= global_cond_container.get_memory(); total_memory+= size; break; case 32: - name= "threads.row_size"; - size= sizeof(PFS_thread); + name= "threads.size"; + size= global_thread_container.get_row_size(); break; case 33: - name= "threads.row_count"; - size= thread_max; + name= "threads.count"; + size= global_thread_container.get_row_count(); break; case 34: name= "threads.memory"; - size= thread_max * sizeof(PFS_thread); + size= global_thread_container.get_memory(); total_memory+= size; break; case 35: - name= "file_instances.row_size"; - size= sizeof(PFS_file); + name= "file_instances.size"; + size= global_file_container.get_row_size(); break; case 36: - name= "file_instances.row_count"; - size= file_max; + name= "file_instances.count"; + size= global_file_container.get_row_count(); break; case 37: name= "file_instances.memory"; - size= file_max * sizeof(PFS_file); + size= global_file_container.get_memory(); total_memory+= size; break; case 38: - name= "(pfs_file_handle).row_size"; + name= "(pfs_file_handle).size"; size= sizeof(PFS_file*); break; case 39: - name= "(pfs_file_handle).row_count"; + name= "(pfs_file_handle).count"; size= file_handle_max; break; case 40: @@ -804,154 +1079,154 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 41: - name= "events_waits_summary_by_thread_by_event_name.row_size"; + name= "events_waits_summary_by_thread_by_event_name.size"; size= sizeof(PFS_single_stat); break; case 42: - name= "events_waits_summary_by_thread_by_event_name.row_count"; - size= thread_max * wait_class_max; + name= "events_waits_summary_by_thread_by_event_name.count"; + size= global_thread_container.get_row_count() * wait_class_max; break; case 43: name= "events_waits_summary_by_thread_by_event_name.memory"; - size= thread_max * wait_class_max * sizeof(PFS_single_stat); + size= global_thread_container.get_row_count() * wait_class_max * sizeof(PFS_single_stat); total_memory+= size; break; case 44: - name= "(pfs_table_share).row_size"; - size= sizeof(PFS_table_share); + name= "(pfs_table_share).size"; + size= global_table_share_container.get_row_size(); break; case 45: - name= "(pfs_table_share).row_count"; - size= table_share_max; + name= "(pfs_table_share).count"; + size= global_table_share_container.get_row_count(); break; case 46: name= "(pfs_table_share).memory"; - size= table_share_max * sizeof(PFS_table_share); + size= global_table_share_container.get_memory(); total_memory+= size; break; case 47: - name= "(pfs_table).row_size"; - size= sizeof(PFS_table); + name= "(pfs_table).size"; + size= global_table_container.get_row_size(); break; case 48: - name= "(pfs_table).row_count"; - size= table_max; + name= "(pfs_table).count"; + size= global_table_container.get_row_count(); break; case 49: name= "(pfs_table).memory"; - size= table_max * sizeof(PFS_table); + size= global_table_container.get_memory(); total_memory+= size; break; case 50: - name= "setup_actors.row_size"; - size= sizeof(PFS_setup_actor); + name= "setup_actors.size"; + size= global_setup_actor_container.get_row_size(); break; case 51: - name= "setup_actors.row_count"; - size= setup_actor_max; + name= "setup_actors.count"; + size= global_setup_actor_container.get_row_count(); break; case 52: name= "setup_actors.memory"; - size= setup_actor_max * sizeof(PFS_setup_actor); + size= global_setup_actor_container.get_memory(); total_memory+= size; break; case 53: - name= "setup_objects.row_size"; - size= sizeof(PFS_setup_object); + name= "setup_objects.size"; + size= global_setup_object_container.get_row_size(); break; case 54: - name= "setup_objects.row_count"; - size= setup_object_max; + name= "setup_objects.count"; + size= global_setup_object_container.get_row_count(); break; case 55: name= "setup_objects.memory"; - size= setup_object_max * sizeof(PFS_setup_object); + size= global_setup_object_container.get_memory(); total_memory+= size; break; case 56: - name= "(pfs_account).row_size"; - size= sizeof(PFS_account); + name= "(pfs_account).size"; + size= global_account_container.get_row_size(); break; case 57: - name= "(pfs_account).row_count"; - size= account_max; + name= "(pfs_account).count"; + size= global_account_container.get_row_count(); break; case 58: name= "(pfs_account).memory"; - size= account_max * sizeof(PFS_account); + size= global_account_container.get_memory(); total_memory+= size; break; case 59: - name= "events_waits_summary_by_account_by_event_name.row_size"; + name= "events_waits_summary_by_account_by_event_name.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; + name= "events_waits_summary_by_account_by_event_name.count"; + size= global_account_container.get_row_count() * 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); + size= global_account_container.get_row_count() * wait_class_max * sizeof(PFS_single_stat); total_memory+= size; break; case 62: - name= "events_waits_summary_by_user_by_event_name.row_size"; + name= "events_waits_summary_by_user_by_event_name.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; + name= "events_waits_summary_by_user_by_event_name.count"; + size= global_user_container.get_row_count() * 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); + size= global_user_container.get_row_count() * wait_class_max * sizeof(PFS_single_stat); total_memory+= size; break; case 65: - name= "events_waits_summary_by_host_by_event_name.row_size"; + name= "events_waits_summary_by_host_by_event_name.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; + name= "events_waits_summary_by_host_by_event_name.count"; + size= global_host_container.get_row_count() * 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); + size= global_host_container.get_row_count() * wait_class_max * sizeof(PFS_single_stat); total_memory+= size; break; case 68: - name= "(pfs_user).row_size"; - size= sizeof(PFS_user); + name= "(pfs_user).size"; + size= global_user_container.get_row_size(); break; case 69: - name= "(pfs_user).row_count"; - size= user_max; + name= "(pfs_user).count"; + size= global_user_container.get_row_count(); break; case 70: name= "(pfs_user).memory"; - size= user_max * sizeof(PFS_user); + size= global_user_container.get_memory(); total_memory+= size; break; case 71: - name= "(pfs_host).row_size"; - size= sizeof(PFS_host); + name= "(pfs_host).size"; + size= global_host_container.get_row_size(); break; case 72: - name= "(pfs_host).row_count"; - size= host_max; + name= "(pfs_host).count"; + size= global_host_container.get_row_count(); break; case 73: name= "(pfs_host).memory"; - size= host_max * sizeof(PFS_host); + size= global_host_container.get_memory(); total_memory+= size; break; case 74: - name= "(pfs_stage_class).row_size"; + name= "(pfs_stage_class).size"; size= sizeof(PFS_stage_class); break; case 75: - name= "(pfs_stage_class).row_count"; + name= "(pfs_stage_class).count"; size= stage_class_max; break; case 76: @@ -960,25 +1235,25 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 77: - name= "events_stages_history.row_size"; + name= "events_stages_history.size"; size= sizeof(PFS_events_stages); break; case 78: - name= "events_stages_history.row_count"; - size= events_stages_history_per_thread * thread_max; + name= "events_stages_history.count"; + size= events_stages_history_per_thread * global_thread_container.get_row_count(); break; case 79: name= "events_stages_history.memory"; - size= events_stages_history_per_thread * thread_max + size= events_stages_history_per_thread * global_thread_container.get_row_count() * sizeof(PFS_events_stages); total_memory+= size; break; case 80: - name= "events_stages_history_long.row_size"; + name= "events_stages_history_long.size"; size= sizeof(PFS_events_stages); break; case 81: - name= "events_stages_history_long.row_count"; + name= "events_stages_history_long.count"; size= events_stages_history_long_size; break; case 82: @@ -987,24 +1262,24 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 83: - name= "events_stages_summary_by_thread_by_event_name.row_size"; + name= "events_stages_summary_by_thread_by_event_name.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; + name= "events_stages_summary_by_thread_by_event_name.count"; + size= global_thread_container.get_row_count() * 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); + size= global_thread_container.get_row_count() * stage_class_max * sizeof(PFS_stage_stat); total_memory+= size; break; case 86: - name= "events_stages_summary_global_by_event_name.row_size"; + name= "events_stages_summary_global_by_event_name.size"; size= sizeof(PFS_stage_stat); break; case 87: - name= "events_stages_summary_global_by_event_name.row_count"; + name= "events_stages_summary_global_by_event_name.count"; size= stage_class_max; break; case 88: @@ -1013,50 +1288,50 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 89: - name= "events_stages_summary_by_account_by_event_name.row_size"; + name= "events_stages_summary_by_account_by_event_name.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; + name= "events_stages_summary_by_account_by_event_name.count"; + size= global_account_container.get_row_count() * 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); + size= global_account_container.get_row_count() * stage_class_max * sizeof(PFS_stage_stat); total_memory+= size; break; case 92: - name= "events_stages_summary_by_user_by_event_name.row_size"; + name= "events_stages_summary_by_user_by_event_name.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; + name= "events_stages_summary_by_user_by_event_name.count"; + size= global_user_container.get_row_count() * 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); + size= global_user_container.get_row_count() * stage_class_max * sizeof(PFS_stage_stat); total_memory+= size; break; case 95: - name= "events_stages_summary_by_host_by_event_name.row_size"; + name= "events_stages_summary_by_host_by_event_name.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; + name= "events_stages_summary_by_host_by_event_name.count"; + size= global_host_container.get_row_count() * 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); + size= global_host_container.get_row_count() * stage_class_max * sizeof(PFS_stage_stat); total_memory+= size; break; case 98: - name= "(pfs_statement_class).row_size"; + name= "(pfs_statement_class).size"; size= sizeof(PFS_statement_class); break; case 99: - name= "(pfs_statement_class).row_count"; + name= "(pfs_statement_class).count"; size= statement_class_max; break; case 100: @@ -1065,51 +1340,51 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 101: - name= "events_statements_history.row_size"; + name= "events_statements_history.size"; size= sizeof(PFS_events_statements); break; case 102: - name= "events_statements_history.row_count"; - size= events_statements_history_per_thread * thread_max; + name= "events_statements_history.count"; + size= events_statements_history_per_thread * global_thread_container.get_row_count(); break; case 103: name= "events_statements_history.memory"; - size= events_statements_history_per_thread * thread_max + size= events_statements_history_per_thread * global_thread_container.get_row_count() * sizeof(PFS_events_statements); total_memory+= size; break; case 104: - name= "events_statements_history_long.row_size"; + name= "events_statements_history_long.size"; size= sizeof(PFS_events_statements); break; case 105: - name= "events_statements_history_long.row_count"; + name= "events_statements_history_long.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); + 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"; + name= "events_statements_summary_by_thread_by_event_name.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; + name= "events_statements_summary_by_thread_by_event_name.count"; + size= global_thread_container.get_row_count() * 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); + size= global_thread_container.get_row_count() * statement_class_max * sizeof(PFS_statement_stat); total_memory+= size; break; case 110: - name= "events_statements_summary_global_by_event_name.row_size"; + name= "events_statements_summary_global_by_event_name.size"; size= sizeof(PFS_statement_stat); break; case 111: - name= "events_statements_summary_global_by_event_name.row_count"; + name= "events_statements_summary_global_by_event_name.count"; size= statement_class_max; break; case 112: @@ -1118,63 +1393,63 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 113: - name= "events_statements_summary_by_account_by_event_name.row_size"; + name= "events_statements_summary_by_account_by_event_name.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; + name= "events_statements_summary_by_account_by_event_name.count"; + size= global_account_container.get_row_count() * 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); + size= global_account_container.get_row_count() * statement_class_max * sizeof(PFS_statement_stat); total_memory+= size; break; case 116: - name= "events_statements_summary_by_user_by_event_name.row_size"; + name= "events_statements_summary_by_user_by_event_name.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; + name= "events_statements_summary_by_user_by_event_name.count"; + size= global_user_container.get_row_count() * 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); + size= global_user_container.get_row_count() * statement_class_max * sizeof(PFS_statement_stat); total_memory+= size; break; case 119: - name= "events_statements_summary_by_host_by_event_name.row_size"; + name= "events_statements_summary_by_host_by_event_name.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; + name= "events_statements_summary_by_host_by_event_name.count"; + size= global_host_container.get_row_count() * 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); + size= global_host_container.get_row_count() * statement_class_max * sizeof(PFS_statement_stat); total_memory+= size; break; case 122: - name= "events_statements_current.row_size"; + name= "events_statements_current.size"; size= sizeof(PFS_events_statements); break; case 123: - name= "events_statements_current.row_count"; - size= thread_max * statement_stack_max; + name= "events_statements_current.count"; + size= global_thread_container.get_row_count() * statement_stack_max; break; case 124: name= "events_statements_current.memory"; - size= thread_max * statement_stack_max * sizeof(PFS_events_statements); + size= global_thread_container.get_row_count() * statement_stack_max * sizeof(PFS_events_statements); total_memory+= size; break; case 125: - name= "(pfs_socket_class).row_size"; + name= "(pfs_socket_class).size"; size= sizeof(PFS_socket_class); break; case 126: - name= "(pfs_socket_class).row_count"; + name= "(pfs_socket_class).count"; size= socket_class_max; break; case 127: @@ -1183,110 +1458,144 @@ bool pfs_show_status(handlerton *hton, THD *thd, total_memory+= size; break; case 128: - name= "socket_instances.row_size"; - size= sizeof(PFS_socket); + name= "socket_instances.size"; + size= global_socket_container.get_row_size(); break; case 129: - name= "socket_instances.row_count"; - size= socket_max; + name= "socket_instances.count"; + size= global_socket_container.get_row_count(); break; case 130: name= "socket_instances.memory"; - size= socket_max * sizeof(PFS_socket); + size= global_socket_container.get_memory(); total_memory+= size; break; case 131: - name= "events_statements_summary_by_digest.row_size"; + name= "events_statements_summary_by_digest.size"; size= sizeof(PFS_statements_digest_stat); break; case 132: - name= "events_statements_summary_by_digest.row_count"; + name= "events_statements_summary_by_digest.count"; size= digest_max; break; case 133: name= "events_statements_summary_by_digest.memory"; - size= digest_max * sizeof(PFS_statements_digest_stat); + size= digest_max * (sizeof(PFS_statements_digest_stat)); total_memory+= size; break; case 134: - name= "session_connect_attrs.row_size"; - size= thread_max; + name= "events_statements_summary_by_program.size"; + size= global_program_container.get_row_size(); break; case 135: - name= "session_connect_attrs.row_count"; - size= session_connect_attrs_size_per_thread; + name= "events_statements_summary_by_program.count"; + size= global_program_container.get_row_count(); break; case 136: + name= "events_statements_summary_by_program.memory"; + size= global_program_container.get_memory(); + total_memory+= size; + break; + case 137: + name= "session_connect_attrs.size"; + size= global_thread_container.get_row_count(); + break; + case 138: + name= "session_connect_attrs.count"; + size= session_connect_attrs_size_per_thread; + break; + case 139: name= "session_connect_attrs.memory"; - size= thread_max * session_connect_attrs_size_per_thread; + size= global_thread_container.get_row_count() * session_connect_attrs_size_per_thread; + total_memory+= size; + break; + case 140: + name= "prepared_statements_instances.size"; + size= global_prepared_stmt_container.get_row_size(); + break; + case 141: + name= "prepared_statements_instances.count"; + size= global_prepared_stmt_container.get_row_count(); + break; + case 142: + name= "prepared_statements_instances.memory"; + size= global_prepared_stmt_container.get_memory(); total_memory+= size; break; - case 137: + case 143: name= "(account_hash).count"; size= account_hash.count; break; - case 138: + case 144: name= "(account_hash).size"; size= account_hash.size; break; - case 139: + case 145: name= "(digest_hash).count"; size= digest_hash.count; break; - case 140: + case 146: name= "(digest_hash).size"; size= digest_hash.size; break; - case 141: + case 147: name= "(filename_hash).count"; size= filename_hash.count; break; - case 142: + case 148: name= "(filename_hash).size"; size= filename_hash.size; break; - case 143: + case 149: name= "(host_hash).count"; size= host_hash.count; break; - case 144: + case 150: name= "(host_hash).size"; size= host_hash.size; break; - case 145: + case 151: name= "(setup_actor_hash).count"; size= setup_actor_hash.count; break; - case 146: + case 152: name= "(setup_actor_hash).size"; size= setup_actor_hash.size; break; - case 147: + case 153: name= "(setup_object_hash).count"; size= setup_object_hash.count; break; - case 148: + case 154: name= "(setup_object_hash).size"; size= setup_object_hash.size; break; - case 149: + case 155: name= "(table_share_hash).count"; size= table_share_hash.count; break; - case 150: + case 156: name= "(table_share_hash).size"; size= table_share_hash.size; break; - case 151: + case 157: name= "(user_hash).count"; size= user_hash.count; break; - case 152: + case 158: name= "(user_hash).size"; size= user_hash.size; break; - case 153: + case 159: + name= "(program_hash).count"; + size= program_hash.count; + break; + case 160: + name= "(program_hash).size"; + size= program_hash.size; + break; + case 161: /* This is not a performance_schema buffer, the data is maintained in the server, @@ -1298,68 +1607,302 @@ bool pfs_show_status(handlerton *hton, THD *thd, name= "host_cache.size"; size= sizeof(Host_entry); break; - case 154: - name= "(history_long_statements_digest_token_array).row_count"; + + case 162: + name= "(pfs_memory_class).row_size"; + size= sizeof(PFS_memory_class); + break; + case 163: + name= "(pfs_memory_class).row_count"; + size= memory_class_max; + break; + case 164: + name= "(pfs_memory_class).memory"; + size= memory_class_max * sizeof(PFS_memory_class); + total_memory+= size; + break; + + case 165: + name= "memory_summary_by_thread_by_event_name.row_size"; + size= sizeof(PFS_memory_stat); + break; + case 166: + name= "memory_summary_by_thread_by_event_name.row_count"; + size= global_thread_container.get_row_count() * memory_class_max; + break; + case 167: + name= "memory_summary_by_thread_by_event_name.memory"; + size= global_thread_container.get_row_count() * memory_class_max * sizeof(PFS_memory_stat); + total_memory+= size; + break; + case 168: + name= "memory_summary_global_by_event_name.row_size"; + size= sizeof(PFS_memory_stat); + break; + case 169: + name= "memory_summary_global_by_event_name.row_count"; + size= memory_class_max; + break; + case 170: + name= "memory_summary_global_by_event_name.memory"; + size= memory_class_max * sizeof(PFS_memory_stat); + total_memory+= size; + break; + case 171: + name= "memory_summary_by_account_by_event_name.row_size"; + size= sizeof(PFS_memory_stat); + break; + case 172: + name= "memory_summary_by_account_by_event_name.row_count"; + size= global_account_container.get_row_count() * memory_class_max; + break; + case 173: + name= "memory_summary_by_account_by_event_name.memory"; + size= global_account_container.get_row_count() * memory_class_max * sizeof(PFS_memory_stat); + total_memory+= size; + break; + case 174: + name= "memory_summary_by_user_by_event_name.row_size"; + size= sizeof(PFS_memory_stat); + break; + case 175: + name= "memory_summary_by_user_by_event_name.row_count"; + size= global_user_container.get_row_count() * memory_class_max; + break; + case 176: + name= "memory_summary_by_user_by_event_name.memory"; + size= global_user_container.get_row_count() * memory_class_max * sizeof(PFS_memory_stat); + total_memory+= size; + break; + case 177: + name= "memory_summary_by_host_by_event_name.row_size"; + size= sizeof(PFS_memory_stat); + break; + case 178: + name= "memory_summary_by_host_by_event_name.row_count"; + size= global_host_container.get_row_count() * memory_class_max; + break; + case 179: + name= "memory_summary_by_host_by_event_name.memory"; + size= global_host_container.get_row_count() * memory_class_max * sizeof(PFS_memory_stat); + total_memory+= size; + break; + case 180: + name= "metadata_locks.row_size"; + size= global_mdl_container.get_row_size(); + break; + case 181: + name= "metadata_locks.row_count"; + size= global_mdl_container.get_row_count(); + break; + case 182: + name= "metadata_locks.memory"; + size= global_mdl_container.get_memory(); + total_memory+= size; + break; + case 183: + name= "events_transactions_history.size"; + size= sizeof(PFS_events_transactions); + break; + case 184: + name= "events_transactions_history.count"; + size= events_transactions_history_per_thread * global_thread_container.get_row_count(); + break; + case 185: + name= "events_transactions_history.memory"; + size= events_transactions_history_per_thread * global_thread_container.get_row_count() + * sizeof(PFS_events_transactions); + total_memory+= size; + break; + case 186: + name= "events_transactions_history_long.size"; + size= sizeof(PFS_events_transactions); + break; + case 187: + name= "events_transactions_history_long.count"; + size= events_transactions_history_long_size; + break; + case 188: + name= "events_transactions_history_long.memory"; + size= events_transactions_history_long_size * sizeof(PFS_events_transactions); + total_memory+= size; + break; + case 189: + name= "events_transactions_summary_by_thread_by_event_name.size"; + size= sizeof(PFS_transaction_stat); + break; + case 190: + name= "events_transactions_summary_by_thread_by_event_name.count"; + size= global_thread_container.get_row_count() * transaction_class_max; + break; + case 191: + name= "events_transactions_summary_by_thread_by_event_name.memory"; + size= global_thread_container.get_row_count() * transaction_class_max * sizeof(PFS_transaction_stat); + total_memory+= size; + break; + case 192: + name= "events_transactions_summary_by_account_by_event_name.size"; + size= sizeof(PFS_transaction_stat); + break; + case 193: + name= "events_transactions_summary_by_account_by_event_name.count"; + size= global_account_container.get_row_count() * transaction_class_max; + break; + case 194: + name= "events_transactions_summary_by_account_by_event_name.memory"; + size= global_account_container.get_row_count() * transaction_class_max * sizeof(PFS_transaction_stat); + total_memory+= size; + break; + case 195: + name= "events_transactions_summary_by_user_by_event_name.size"; + size= sizeof(PFS_transaction_stat); + break; + case 196: + name= "events_transactions_summary_by_user_by_event_name.count"; + size= global_user_container.get_row_count() * transaction_class_max; + break; + case 197: + name= "events_transactions_summary_by_user_by_event_name.memory"; + size= global_user_container.get_row_count() * transaction_class_max * sizeof(PFS_transaction_stat); + total_memory+= size; + break; + case 198: + name= "events_transactions_summary_by_host_by_event_name.size"; + size= sizeof(PFS_transaction_stat); + break; + case 199: + name= "events_transactions_summary_by_host_by_event_name.count"; + size= global_host_container.get_row_count() * transaction_class_max; + break; + case 200: + name= "events_transactions_summary_by_host_by_event_name.memory"; + size= global_host_container.get_row_count() * transaction_class_max * sizeof(PFS_transaction_stat); + total_memory+= size; + break; + case 201: + name= "table_lock_waits_summary_by_table.size"; + size= global_table_share_lock_container.get_row_size(); + break; + case 202: + name= "table_lock_waits_summary_by_table.count"; + size= global_table_share_lock_container.get_row_count(); + break; + case 203: + name= "table_lock_waits_summary_by_table.memory"; + size= global_table_share_lock_container.get_memory(); + total_memory+= size; + break; + case 204: + name= "table_io_waits_summary_by_index_usage.size"; + size= global_table_share_index_container.get_row_size(); + break; + case 205: + name= "table_io_waits_summary_by_index_usage.count"; + size= global_table_share_index_container.get_row_count(); + break; + case 206: + name= "table_io_waits_summary_by_index_usage.memory"; + size= global_table_share_index_container.get_memory(); + total_memory+= size; + break; + case 207: + name= "(history_long_statements_digest_token_array).count"; size= events_statements_history_long_size; break; - case 155: - name= "(history_long_statements_digest_token_array).row_size"; + case 208: + name= "(history_long_statements_digest_token_array).size"; size= pfs_max_digest_length; break; - case 156: + case 209: 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; + case 210: + name= "(history_statements_digest_token_array).count"; + size= global_thread_container.get_row_count() * events_statements_history_per_thread; break; - case 158: - name= "(history_statements_digest_token_array).row_size"; + case 211: + name= "(history_statements_digest_token_array).size"; size= pfs_max_digest_length; break; - case 159: + case 212: name= "(history_statements_digest_token_array).memory"; - size= thread_max * events_statements_history_per_thread * pfs_max_digest_length; + size= global_thread_container.get_row_count() * 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; + case 213: + name= "(current_statements_digest_token_array).count"; + size= global_thread_container.get_row_count() * statement_stack_max; break; - case 161: - name= "(current_statements_digest_token_array).row_size"; + case 214: + name= "(current_statements_digest_token_array).size"; size= pfs_max_digest_length; break; - case 162: + case 215: name= "(current_statements_digest_token_array).memory"; - size= thread_max * statement_stack_max * pfs_max_digest_length; + size= global_thread_container.get_row_count() * statement_stack_max * pfs_max_digest_length; total_memory+= size; break; - case 163: - name= "(statements_digest_token_array).row_count"; + case 216: + name= "(history_long_statements_text_array).count"; + size= events_statements_history_long_size; + break; + case 217: + name= "(history_long_statements_text_array).size"; + size= pfs_max_sqltext; + break; + case 218: + name= "(history_long_statements_text_array).memory"; + size= events_statements_history_long_size * pfs_max_sqltext; + total_memory+= size; + break; + case 219: + name= "(history_statements_text_array).count"; + size= global_thread_container.get_row_count() * events_statements_history_per_thread; + break; + case 220: + name= "(history_statements_text_array).size"; + size= pfs_max_sqltext; + break; + case 221: + name= "(history_statements_text_array).memory"; + size= global_thread_container.get_row_count() * events_statements_history_per_thread * pfs_max_sqltext; + total_memory+= size; + break; + case 222: + name= "(current_statements_text_array).count"; + size= global_thread_container.get_row_count() * statement_stack_max; + break; + case 223: + name= "(current_statements_text_array).size"; + size= pfs_max_sqltext; + break; + case 224: + name= "(current_statements_text_array).memory"; + size= global_thread_container.get_row_count() * statement_stack_max * pfs_max_sqltext; + total_memory+= size; + break; + case 225: + name= "(statements_digest_token_array).count"; size= digest_max; break; - case 164: - name= "(statements_digest_token_array).row_size"; + case 226: + name= "(statements_digest_token_array).size"; size= pfs_max_digest_length; break; - case 165: + case 227: 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 166: + case 228: name= "performance_schema.memory"; size= total_memory; - /* This will fail if something is not advertised here */ - DBUG_ASSERT(size == pfs_allocated_memory); break; default: goto end; diff --git a/storage/perfschema/pfs_engine_table.h b/storage/perfschema/pfs_engine_table.h index a1a01df6e15..b751d48a38f 100644 --- a/storage/perfschema/pfs_engine_table.h +++ b/storage/perfschema/pfs_engine_table.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2008, 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, version 2.0, @@ -23,13 +23,24 @@ #ifndef PFS_ENGINE_TABLE_H #define PFS_ENGINE_TABLE_H -#include "sql_acl.h" /* struct ACL_* */ +#include "table.h" +#include "sql_acl.h" /** @file storage/perfschema/pfs_engine_table.h Performance schema tables (declarations). */ #include "pfs_instr_class.h" +extern pthread_key_t THR_PFS_VG; // global_variables +extern pthread_key_t THR_PFS_SV; // session_variables +extern pthread_key_t THR_PFS_VBT; // variables_by_thread +extern pthread_key_t THR_PFS_SG; // global_status +extern pthread_key_t THR_PFS_SS; // session_status +extern pthread_key_t THR_PFS_SBT; // status_by_thread +extern pthread_key_t THR_PFS_SBU; // status_by_user +extern pthread_key_t THR_PFS_SBH; // status_by_host +extern pthread_key_t THR_PFS_SBA; // status_by_account + class Field; struct PFS_engine_table_share; struct time_normalizer; @@ -40,6 +51,36 @@ struct time_normalizer; */ /** + Store and retrieve table state information during a query. +*/ +class PFS_table_context +{ +public: + PFS_table_context(ulonglong current_version, bool restore, pthread_key_t key); + PFS_table_context(ulonglong current_version, ulong map_size, bool restore, pthread_key_t key); +~PFS_table_context(void); + + bool initialize(void); + bool is_initialized(void) { return m_initialized; } + ulonglong current_version(void) { return m_current_version; } + ulonglong last_version(void) { return m_last_version; } + bool versions_match(void) { return m_last_version == m_current_version; } + void set_item(ulong n); + bool is_item_set(ulong n); + pthread_key_t m_thr_key; + +private: + ulonglong m_current_version; + ulonglong m_last_version; + ulong *m_map; + ulong m_map_size; + ulong m_word_size; + bool m_restore; + bool m_initialized; + ulong m_last_item; +}; + +/** An abstract PERFORMANCE_SCHEMA table. Every table implemented in the performance schema schema and storage engine derives from this class. @@ -88,12 +129,24 @@ public: {} /** + Helper, assign a value to a long field. + @param f the field to set + @param value the value to assign + */ + static void set_field_long(Field *f, long value); + /** 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 longlong field. + @param f the field to set + @param value the value to assign + */ + static void set_field_longlong(Field *f, longlong value); + /** Helper, assign a value to a ulonglong field. @param f the field to set @param value the value to assign @@ -109,6 +162,14 @@ public: /** Helper, assign a value to a varchar utf8 field. @param f the field to set + @param cs the string character set + @param str the string to assign + @param len the length of the string to assign + */ + static void set_field_varchar(Field *f, const CHARSET_INFO *cs, 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 */ @@ -121,6 +182,13 @@ public: */ static void set_field_longtext_utf8(Field *f, const char *str, uint len); /** + Helper, assign a value to a blob field. + @param f the field to set + @param val the value to assign + @param len the length of the string to assign + */ + static void set_field_blob(Field *f, const char *val, uint len); + /** Helper, assign a value to an enum field. @param f the field to set @param value the value to assign @@ -133,6 +201,12 @@ public: */ static void set_field_timestamp(Field *f, ulonglong value); /** + Helper, assign a value to a double field. + @param f the field to set + @param value the value to assign + */ + static void set_field_double(Field *f, double value); + /** Helper, read a value from an enum field. @param f the field to read @return the field value @@ -182,7 +256,6 @@ protected: */ virtual int delete_row_values(TABLE *table, const unsigned char *buf, Field **fields); - /** Constructor. @param share table share @@ -238,19 +311,14 @@ struct PFS_engine_table_share pfs_delete_all_rows_t m_delete_all_rows; /** Get rows count function. */ pfs_get_row_count_t m_get_row_count; - /** - Number or records. - This number does not need to be precise, - it is used by the optimizer to decide if the table - has 0, 1, or many records. - */ - ha_rows m_records; /** Length of the m_pos position structure. */ uint m_ref_length; /** The lock, stored on behalf of the SQL layer. */ THR_LOCK *m_thr_lock_ptr; /** Table definition. */ LEX_STRING sql; + /** Table is available even if the Performance Schema is disabled. */ + bool m_perpetual; }; /** @@ -352,6 +420,45 @@ public: /** Singleton instance of PFS_unknown_acl. */ extern PFS_unknown_acl pfs_unknown_acl; + +/** + Privileges for world readable tables. +*/ +class PFS_readonly_world_acl : public PFS_readonly_acl +{ +public: + PFS_readonly_world_acl() + {} + + ~PFS_readonly_world_acl() + {} + virtual ACL_internal_access_result check(ulong want_access, ulong *save_priv) const; +}; + + +/** Singleton instance of PFS_readonly_world_acl */ +extern PFS_readonly_world_acl pfs_readonly_world_acl; + + +/** +Privileges for world readable truncatable tables. +*/ +class PFS_truncatable_world_acl : public PFS_truncatable_acl +{ +public: + PFS_truncatable_world_acl() + {} + + ~PFS_truncatable_world_acl() + {} + virtual ACL_internal_access_result check(ulong want_access, ulong *save_priv) const; +}; + + +/** Singleton instance of PFS_readonly_world_acl */ +extern PFS_truncatable_world_acl pfs_truncatable_world_acl; + + /** Position of a cursor, for simple iterations. */ struct PFS_simple_index { @@ -368,6 +475,13 @@ struct PFS_simple_index /** Set this index at a given position. + @param index an index + */ + void set_at(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) @@ -404,6 +518,15 @@ struct PFS_double_index /** Set this index at a given position. + */ + void set_at(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) @@ -445,6 +568,16 @@ struct PFS_triple_index /** Set this index at a given position. + */ + void set_at(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) diff --git a/storage/perfschema/pfs_events.h b/storage/perfschema/pfs_events.h index ca2fd8582ad..47c4c9280e6 100644 --- a/storage/perfschema/pfs_events.h +++ b/storage/perfschema/pfs_events.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -43,6 +43,12 @@ struct PFS_events ulonglong m_end_event_id; /** NESTING_EVENT_ID. */ ulonglong m_nesting_event_id; + /** NESTING_EVENT_TYPE */ + enum_event_type m_nesting_event_type; + /** NESTING_EVENT_LEVEL */ + uint m_nesting_event_level; + /** Instrument metadata. */ + PFS_instr_class *m_class; /** Timer start. This member is populated only if m_class->m_timed is true. @@ -53,14 +59,8 @@ struct PFS_events 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; }; diff --git a/storage/perfschema/pfs_events_stages.cc b/storage/perfschema/pfs_events_stages.cc index a68b0729e96..e5a6b9a2007 100644 --- a/storage/perfschema/pfs_events_stages.cc +++ b/storage/perfschema/pfs_events_stages.cc @@ -35,22 +35,24 @@ #include "pfs_user.h" #include "pfs_events_stages.h" #include "pfs_atomic.h" +#include "pfs_buffer_container.h" +#include "pfs_builtin_memory.h" #include "m_string.h" -ulong events_stages_history_long_size= 0; +PFS_ALIGNED ulong events_stages_history_long_size= 0; /** Consumer flag for table EVENTS_STAGES_CURRENT. */ -bool flag_events_stages_current= false; +PFS_ALIGNED bool flag_events_stages_current= false; /** Consumer flag for table EVENTS_STAGES_HISTORY. */ -bool flag_events_stages_history= false; +PFS_ALIGNED bool flag_events_stages_history= false; /** Consumer flag for table EVENTS_STAGES_HISTORY_LONG. */ -bool flag_events_stages_history_long= false; +PFS_ALIGNED bool flag_events_stages_history_long= false; /** True if EVENTS_STAGES_HISTORY_LONG circular buffer is full. */ -bool events_stages_history_long_full= false; +PFS_ALIGNED bool events_stages_history_long_full= false; /** Index in EVENTS_STAGES_HISTORY_LONG circular buffer. */ -volatile uint32 events_stages_history_long_index= 0; +PFS_ALIGNED PFS_cacheline_uint32 events_stages_history_long_index; /** EVENTS_STAGES_HISTORY_LONG circular buffer. */ -PFS_events_stages *events_stages_history_long_array= NULL; +PFS_ALIGNED PFS_events_stages *events_stages_history_long_array= NULL; /** Initialize table EVENTS_STAGES_HISTORY_LONG. @@ -60,14 +62,16 @@ 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); + PFS_atomic::store_u32(&events_stages_history_long_index.m_u32, 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)); + PFS_MALLOC_ARRAY(& builtin_memory_stages_history_long, + events_stages_history_long_size, + sizeof(PFS_events_stages), PFS_events_stages, + MYF(MY_ZEROFILL)); return (events_stages_history_long_array ? 0 : 1); } @@ -75,7 +79,9 @@ int init_events_stages_history_long(uint events_stages_history_long_sizing) /** Cleanup table EVENTS_STAGES_HISTORY_LONG. */ void cleanup_events_stages_history_long(void) { - pfs_free(events_stages_history_long_array); + PFS_FREE_ARRAY(& builtin_memory_stages_history_long, + events_stages_history_long_size, sizeof(PFS_events_stages), + events_stages_history_long_array); events_stages_history_long_array= NULL; } @@ -129,7 +135,7 @@ void insert_events_stages_history_long(PFS_events_stages *stage) DBUG_ASSERT(events_stages_history_long_array != NULL); - uint index= PFS_atomic::add_u32(&events_stages_history_long_index, 1); + uint index= PFS_atomic::add_u32(&events_stages_history_long_index.m_u32, 1); index= index % events_stages_history_long_size; if (index == 0) @@ -139,40 +145,38 @@ void insert_events_stages_history_long(PFS_events_stages *stage) copy_events_stages(&events_stages_history_long_array[index], stage); } +static void fct_reset_events_stages_current(PFS_thread *pfs) +{ + pfs->m_stage_current.m_class= NULL; +} + /** 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; + global_thread_container.apply_all(fct_reset_events_stages_current); +} - for ( ; pfs_thread < pfs_thread_last; pfs_thread++) - { - pfs_thread->m_stage_current.m_class= NULL; - } +static void fct_reset_events_stages_history(PFS_thread *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 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; - } + global_thread_container.apply_all(fct_reset_events_stages_history); } /** Reset table EVENTS_STAGES_HISTORY_LONG data. */ void reset_events_stages_history_long(void) { - PFS_atomic::store_u32(&events_stages_history_long_index, 0); + PFS_atomic::store_u32(&events_stages_history_long_index.m_u32, 0); events_stages_history_long_full= false; PFS_events_stages *pfs= events_stages_history_long_array; @@ -181,70 +185,53 @@ void reset_events_stages_history_long(void) pfs->m_class= NULL; } +static void fct_reset_events_stages_by_thread(PFS_thread *thread) +{ + PFS_account *account= sanitize_account(thread->m_account); + PFS_user *user= sanitize_user(thread->m_user); + PFS_host *host= sanitize_host(thread->m_host); + aggregate_thread_stages(thread, account, user, host); +} + /** 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; + global_thread_container.apply(fct_reset_events_stages_by_thread); +} - 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); - } - } +static void fct_reset_events_stages_by_account(PFS_account *pfs) +{ + PFS_user *user= sanitize_user(pfs->m_user); + PFS_host *host= sanitize_host(pfs->m_host); + pfs->aggregate_stages(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; + global_account_container.apply(fct_reset_events_stages_by_account); +} - 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); - } - } +static void fct_reset_events_stages_by_user(PFS_user *pfs) +{ + pfs->aggregate_stages(); } /** Reset table EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME data. */ void reset_events_stages_by_user() { - PFS_user *pfs= user_array; - PFS_user *pfs_last= user_array + user_max; + global_user_container.apply(fct_reset_events_stages_by_user); +} - for ( ; pfs < pfs_last; pfs++) - { - if (pfs->m_lock.is_populated()) - pfs->aggregate_stages(); - } +static void fct_reset_events_stages_by_host(PFS_host *pfs) +{ + 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(); - } + global_host_container.apply(fct_reset_events_stages_by_host); } /** Reset table EVENTS_STAGES_GLOBAL_BY_EVENT_NAME data. */ diff --git a/storage/perfschema/pfs_events_stages.h b/storage/perfschema/pfs_events_stages.h index f61a7c3c077..0b7d27ded82 100644 --- a/storage/perfschema/pfs_events_stages.h +++ b/storage/perfschema/pfs_events_stages.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -38,7 +38,7 @@ struct PFS_host; /** A stage record. */ struct PFS_events_stages : public PFS_events { - /* No specific attributes */ + PSI_stage_progress m_progress; }; void insert_events_stages_history(PFS_thread *thread, PFS_events_stages *stage); @@ -49,7 +49,7 @@ 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_ALIGNED PFS_cacheline_uint32 events_stages_history_long_index; extern PFS_events_stages *events_stages_history_long_array; extern ulong events_stages_history_long_size; diff --git a/storage/perfschema/pfs_events_statements.cc b/storage/perfschema/pfs_events_statements.cc index 1942787665a..e0f1b2bfb77 100644 --- a/storage/perfschema/pfs_events_statements.cc +++ b/storage/perfschema/pfs_events_statements.cc @@ -35,23 +35,26 @@ #include "pfs_user.h" #include "pfs_events_statements.h" #include "pfs_atomic.h" +#include "pfs_buffer_container.h" +#include "pfs_builtin_memory.h" #include "m_string.h" -size_t events_statements_history_long_size= 0; +PFS_ALIGNED size_t events_statements_history_long_size= 0; /** Consumer flag for table EVENTS_STATEMENTS_CURRENT. */ -bool flag_events_statements_current= false; +PFS_ALIGNED bool flag_events_statements_current= false; /** Consumer flag for table EVENTS_STATEMENTS_HISTORY. */ -bool flag_events_statements_history= false; +PFS_ALIGNED bool flag_events_statements_history= false; /** Consumer flag for table EVENTS_STATEMENTS_HISTORY_LONG. */ -bool flag_events_statements_history_long= false; +PFS_ALIGNED bool flag_events_statements_history_long= false; /** True if EVENTS_STATEMENTS_HISTORY_LONG circular buffer is full. */ -bool events_statements_history_long_full= false; +PFS_ALIGNED bool events_statements_history_long_full= false; /** Index in EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */ -volatile uint32 events_statements_history_long_index= 0; +PFS_ALIGNED PFS_cacheline_uint32 events_statements_history_long_index; /** EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */ -PFS_events_statements *events_statements_history_long_array= NULL; +PFS_ALIGNED PFS_events_statements *events_statements_history_long_array= NULL; static unsigned char *h_long_stmts_digest_token_array= NULL; +static char *h_long_stmts_text_array= NULL; /** Initialize table EVENTS_STATEMENTS_HISTORY_LONG. @@ -61,29 +64,32 @@ int init_events_statements_history_long(size_t events_statements_history_long_si { 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); + PFS_atomic::store_u32(&events_statements_history_long_index.m_u32, 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_MALLOC_ARRAY(& builtin_memory_statements_history_long, + 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; - } + { + cleanup_events_statements_history_long(); + return 1; + } if (pfs_max_digest_length > 0) { - /* Size of each digest token array. */ + /* Size of each digest text 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, + PFS_MALLOC_ARRAY(& builtin_memory_statements_history_long_tokens, + 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(); @@ -91,10 +97,28 @@ int init_events_statements_history_long(size_t events_statements_history_long_si } } + if (pfs_max_sqltext > 0) + { + /* Size of each sql text array. */ + size_t sqltext_size= pfs_max_sqltext * sizeof(char); + + h_long_stmts_text_array= + PFS_MALLOC_ARRAY(& builtin_memory_statements_history_long_sqltext, + events_statements_history_long_size, sqltext_size, + char, MYF(MY_ZEROFILL)); + + if (h_long_stmts_text_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); + events_statements_history_long_array[index].m_sqltext= h_long_stmts_text_array + index * pfs_max_sqltext; } return 0; @@ -103,17 +127,44 @@ int init_events_statements_history_long(size_t events_statements_history_long_si /** 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); + PFS_FREE_ARRAY(& builtin_memory_statements_history_long, + events_statements_history_long_size, + sizeof(PFS_events_statements), + events_statements_history_long_array); + + PFS_FREE_ARRAY(& builtin_memory_statements_history_long_tokens, + events_statements_history_long_size, + (pfs_max_digest_length * sizeof(unsigned char)), + h_long_stmts_digest_token_array); + + PFS_FREE_ARRAY(& builtin_memory_statements_history_long_sqltext, + events_statements_history_long_size, + (pfs_max_sqltext * sizeof(char)), + h_long_stmts_text_array); + events_statements_history_long_array= NULL; h_long_stmts_digest_token_array= NULL; + h_long_stmts_text_array= NULL; } static inline void copy_events_statements(PFS_events_statements *dest, - const PFS_events_statements *source) + const PFS_events_statements *source) { - /* Copy all attributes except DIGEST */ - memcpy(dest, source, my_offsetof(PFS_events_statements, m_digest_storage)); + /* Copy all attributes except SQL TEXT and DIGEST */ + memcpy(dest, source, my_offsetof(PFS_events_statements, m_sqltext)); + + /* Copy SQL TEXT */ + int sqltext_length= source->m_sqltext_length; + + if (sqltext_length > 0) + { + memcpy(dest->m_sqltext, source->m_sqltext, sqltext_length); + dest->m_sqltext_length= sqltext_length; + } + else + { + dest->m_sqltext_length= 0; + } /* Copy DIGEST */ dest->m_digest_storage.copy(& source->m_digest_storage); @@ -163,7 +214,7 @@ void insert_events_statements_history_long(PFS_events_statements *statement) DBUG_ASSERT(events_statements_history_long_array != NULL); - uint index= PFS_atomic::add_u32(&events_statements_history_long_index, 1); + uint index= PFS_atomic::add_u32(&events_statements_history_long_index.m_u32, 1); index= index % events_statements_history_long_size; if (index == 0) @@ -173,44 +224,42 @@ void insert_events_statements_history_long(PFS_events_statements *statement) copy_events_statements(&events_statements_history_long_array[index], statement); } +static void fct_reset_events_statements_current(PFS_thread *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_CURRENT data. */ void reset_events_statements_current(void) { - PFS_thread *pfs_thread= thread_array; - PFS_thread *pfs_thread_last= thread_array + thread_max; + global_thread_container.apply_all(fct_reset_events_statements_current); +} - 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; +static void fct_reset_events_statements_history(PFS_thread *pfs_thread) +{ + PFS_events_statements *pfs= pfs_thread->m_statements_history; + PFS_events_statements *pfs_last= pfs + events_statements_history_per_thread; - for ( ; pfs_stmt < pfs_stmt_last; pfs_stmt++) - pfs_stmt->m_class= NULL; - } + 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 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; - } + global_thread_container.apply_all(fct_reset_events_statements_history); } /** Reset table EVENTS_STATEMENTS_HISTORY_LONG data. */ void reset_events_statements_history_long(void) { - PFS_atomic::store_u32(&events_statements_history_long_index, 0); + PFS_atomic::store_u32(&events_statements_history_long_index.m_u32, 0); events_statements_history_long_full= false; PFS_events_statements *pfs= events_statements_history_long_array; @@ -219,70 +268,53 @@ void reset_events_statements_history_long(void) pfs->m_class= NULL; } +static void fct_reset_events_statements_by_thread(PFS_thread *thread) +{ + PFS_account *account= sanitize_account(thread->m_account); + PFS_user *user= sanitize_user(thread->m_user); + PFS_host *host= sanitize_host(thread->m_host); + aggregate_thread_statements(thread, account, user, host); +} + /** 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; + global_thread_container.apply(fct_reset_events_statements_by_thread); +} - 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); - } - } +static void fct_reset_events_statements_by_account(PFS_account *pfs) +{ + PFS_user *user= sanitize_user(pfs->m_user); + PFS_host *host= sanitize_host(pfs->m_host); + pfs->aggregate_statements(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; + global_account_container.apply(fct_reset_events_statements_by_account); +} - 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); - } - } +static void fct_reset_events_statements_by_user(PFS_user *pfs) +{ + pfs->aggregate_statements(); } /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME data. */ void reset_events_statements_by_user() { - PFS_user *pfs= user_array; - PFS_user *pfs_last= user_array + user_max; + global_user_container.apply(fct_reset_events_statements_by_user); +} - for ( ; pfs < pfs_last; pfs++) - { - if (pfs->m_lock.is_populated()) - pfs->aggregate_statements(); - } +static void fct_reset_events_statements_by_host(PFS_host *pfs) +{ + 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(); - } + global_host_container.apply(fct_reset_events_statements_by_host); } /** Reset table EVENTS_STATEMENTS_GLOBAL_BY_EVENT_NAME data. */ diff --git a/storage/perfschema/pfs_events_statements.h b/storage/perfschema/pfs_events_statements.h index e47e2e79280..8b24a9e75c8 100644 --- a/storage/perfschema/pfs_events_statements.h +++ b/storage/perfschema/pfs_events_statements.h @@ -40,18 +40,20 @@ struct PFS_host; /** A statement record. */ struct PFS_events_statements : public PFS_events { + enum_object_type m_sp_type; + char m_schema_name[NAME_LEN]; + uint m_schema_name_length; + char m_object_name[NAME_LEN]; + uint m_object_name_length; + /** 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. */ @@ -102,6 +104,14 @@ struct PFS_events_statements : public PFS_events uint m_sqltext_cs_number; /** + SQL_TEXT. + This pointer is immutable, + and always point to pre allocated memory. + */ + char *m_sqltext; + /** Length of @ m_info. */ + uint m_sqltext_length; + /** Statement digest. This underlying token array storage pointer is immutable, and always point to pre allocated memory. @@ -112,12 +122,14 @@ struct PFS_events_statements : public PFS_events void insert_events_statements_history(PFS_thread *thread, PFS_events_statements *statement); void insert_events_statements_history_long(PFS_events_statements *statement); +extern ulong nested_statement_lost; + 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_ALIGNED PFS_cacheline_uint32 events_statements_history_long_index; extern PFS_events_statements *events_statements_history_long_array; extern size_t events_statements_history_long_size; diff --git a/storage/perfschema/pfs_events_transactions.cc b/storage/perfschema/pfs_events_transactions.cc new file mode 100644 index 00000000000..884234913e8 --- /dev/null +++ b/storage/perfschema/pfs_events_transactions.cc @@ -0,0 +1,267 @@ +/* Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/pfs_events_transactions.cc + Events transactions 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_transactions.h" +#include "pfs_atomic.h" +#include "pfs_buffer_container.h" +#include "pfs_builtin_memory.h" +#include "m_string.h" + +PFS_ALIGNED ulong events_transactions_history_long_size= 0; +/** Consumer flag for table EVENTS_TRANSACTIONS_CURRENT. */ +PFS_ALIGNED bool flag_events_transactions_current= false; +/** Consumer flag for table EVENTS_TRANSACTIONS_HISTORY. */ +PFS_ALIGNED bool flag_events_transactions_history= false; +/** Consumer flag for table EVENTS_TRANSACTIONS_HISTORY_LONG. */ +PFS_ALIGNED bool flag_events_transactions_history_long= false; + +/** True if EVENTS_TRANSACTIONS_HISTORY_LONG circular buffer is full. */ +PFS_ALIGNED bool events_transactions_history_long_full= false; +/** Index in EVENTS_TRANSACTIONS_HISTORY_LONG circular buffer. */ +PFS_ALIGNED PFS_cacheline_uint32 events_transactions_history_long_index; +/** EVENTS_TRANSACTIONS_HISTORY_LONG circular buffer. */ +PFS_ALIGNED PFS_events_transactions *events_transactions_history_long_array= NULL; + +/** + Initialize table EVENTS_TRANSACTIONS_HISTORY_LONG. + @param events_transactions_history_long_sizing table sizing +*/ +int init_events_transactions_history_long(uint events_transactions_history_long_sizing) +{ + events_transactions_history_long_size= events_transactions_history_long_sizing; + events_transactions_history_long_full= false; + PFS_atomic::store_u32(&events_transactions_history_long_index.m_u32, 0); + + if (events_transactions_history_long_size == 0) + return 0; + + events_transactions_history_long_array= + PFS_MALLOC_ARRAY(& builtin_memory_transactions_history_long, + events_transactions_history_long_size, + sizeof(PFS_events_transactions), PFS_events_transactions, + MYF(MY_ZEROFILL)); + + return (events_transactions_history_long_array ? 0 : 1); +} + +/** Cleanup table EVENTS_TRANSACTIONS_HISTORY_LONG. */ +void cleanup_events_transactions_history_long(void) +{ + PFS_FREE_ARRAY(& builtin_memory_transactions_history_long, + events_transactions_history_long_size, sizeof(PFS_events_transactions), + events_transactions_history_long_array); + events_transactions_history_long_array= NULL; +} + +static inline void copy_events_transactions(PFS_events_transactions *dest, + const PFS_events_transactions *source) +{ + memcpy(dest, source, sizeof(PFS_events_transactions)); +} + +/** + Insert a transaction record in table EVENTS_TRANSACTIONS_HISTORY. + @param thread thread that executed the wait + @param transaction record to insert +*/ +void insert_events_transactions_history(PFS_thread *thread, PFS_events_transactions *transaction) +{ + if (unlikely(events_transactions_history_per_thread == 0)) + return; + + DBUG_ASSERT(thread->m_transactions_history != NULL); + + uint index= thread->m_transactions_history_index; + + /* + A concurrent thread executing TRUNCATE TABLE EVENTS_TRANSACTIONS_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_transactions_history will filter this out. + */ + copy_events_transactions(&thread->m_transactions_history[index], transaction); + + index++; + if (index >= events_transactions_history_per_thread) + { + index= 0; + thread->m_transactions_history_full= true; + } + thread->m_transactions_history_index= index; +} + +/** + Insert a transaction record in table EVENTS_TRANSACTIONS_HISTORY_LONG. + @param transaction record to insert +*/ +void insert_events_transactions_history_long(PFS_events_transactions *transaction) +{ + if (unlikely(events_transactions_history_long_size == 0)) + return ; + + DBUG_ASSERT(events_transactions_history_long_array != NULL); + + uint index= PFS_atomic::add_u32(&events_transactions_history_long_index.m_u32, 1); + + index= index % events_transactions_history_long_size; + if (index == 0) + events_transactions_history_long_full= true; + + /* See related comment in insert_events_transactions_history. */ + copy_events_transactions(&events_transactions_history_long_array[index], transaction); +} + +static void fct_reset_events_transactions_current(PFS_thread *pfs) +{ + pfs->m_transaction_current.m_class= NULL; +} + +/** Reset table EVENTS_TRANSACTIONS_CURRENT data. */ +void reset_events_transactions_current(void) +{ + global_thread_container.apply_all(fct_reset_events_transactions_current); +} + +static void fct_reset_events_transactions_history(PFS_thread *pfs_thread) +{ + PFS_events_transactions *pfs= pfs_thread->m_transactions_history; + PFS_events_transactions *pfs_last= pfs + events_transactions_history_per_thread; + + pfs_thread->m_transactions_history_index= 0; + pfs_thread->m_transactions_history_full= false; + for ( ; pfs < pfs_last; pfs++) + pfs->m_class= NULL; +} + +/** Reset table EVENTS_TRANSACTIONS_HISTORY data. */ +void reset_events_transactions_history(void) +{ + global_thread_container.apply_all(fct_reset_events_transactions_history); +} + +/** Reset table EVENTS_TRANSACTIONS_HISTORY_LONG data. */ +void reset_events_transactions_history_long(void) +{ + PFS_atomic::store_u32(&events_transactions_history_long_index.m_u32, 0); + events_transactions_history_long_full= false; + + PFS_events_transactions *pfs= events_transactions_history_long_array; + PFS_events_transactions *pfs_last= pfs + events_transactions_history_long_size; + for ( ; pfs < pfs_last; pfs++) + pfs->m_class= NULL; +} + +static void fct_reset_events_transactions_by_thread(PFS_thread *thread) +{ + PFS_account *account= sanitize_account(thread->m_account); + PFS_user *user= sanitize_user(thread->m_user); + PFS_host *host= sanitize_host(thread->m_host); + aggregate_thread_transactions(thread, account, user, host); +} + +/** Reset table EVENTS_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */ +void reset_events_transactions_by_thread() +{ + global_thread_container.apply(fct_reset_events_transactions_by_thread); +} + +static void fct_reset_events_transactions_by_account(PFS_account *pfs) +{ + PFS_user *user= sanitize_user(pfs->m_user); + PFS_host *host= sanitize_host(pfs->m_host); + pfs->aggregate_transactions(user, host); +} + +/** Reset table EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */ +void reset_events_transactions_by_account() +{ + global_account_container.apply(fct_reset_events_transactions_by_account); +} + +static void fct_reset_events_transactions_by_user(PFS_user *pfs) +{ + pfs->aggregate_transactions(); +} + +/** Reset table EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME data. */ +void reset_events_transactions_by_user() +{ + global_user_container.apply(fct_reset_events_transactions_by_user); +} + +static void fct_reset_events_transactions_by_host(PFS_host *pfs) +{ + pfs->aggregate_transactions(); +} + +/** Reset table EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME data. */ +void reset_events_transactions_by_host() +{ + global_host_container.apply(fct_reset_events_transactions_by_host); +} + +/** Reset table EVENTS_TRANSACTIONS_GLOBAL_BY_EVENT_NAME data. */ +void reset_events_transactions_global() +{ + global_transaction_stat.reset(); +} + +/** + Check if the XID consists of printable characters, ASCII 32 - 127. + @param xid XID structure + @param offset offset into XID.data[] + @param length number of bytes to process + @return true if all bytes are in printable range +*/ +bool xid_printable(PSI_xid *xid, size_t offset, size_t length) +{ + if (xid->is_null()) + return false; + + DBUG_ASSERT(offset + length <= MYSQL_XIDDATASIZE); + + unsigned char *c= (unsigned char*)&xid->data + offset; + + for (size_t i= 0; i < length; i++, c++) + { + if(*c < 32 || *c > 127) + return false; + } + + return true; +} + diff --git a/storage/perfschema/pfs_events_transactions.h b/storage/perfschema/pfs_events_transactions.h new file mode 100644 index 00000000000..dc4fd8b0b60 --- /dev/null +++ b/storage/perfschema/pfs_events_transactions.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef PFS_EVENTS_TRANSACTIONS_H +#define PFS_EVENTS_TRANSACTIONS_H + +/** + @file storage/perfschema/pfs_events_transactions.h + Events transactions data structures (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_events.h" +#include "rpl_gtid.h" +#include "mysql/plugin.h" /* MYSQL_XIDDATASIZE */ +#include "my_thread.h" + +struct PFS_thread; +struct PFS_account; +struct PFS_user; +struct PFS_host; + +/** + struct PSI_xid is binary compatible with the XID structure as + in the X/Open CAE Specification, Distributed Transaction Processing: + The XA Specification, X/Open Company Ltd., 1991. + http://www.opengroup.org/bookstore/catalog/c193.htm + + A value of -1 in formatID means that the XID is null. + Max length for bqual and gtrid is 64 bytes each. + + @see XID in sql/handler.h + @see MYSQL_XID in mysql/plugin.h +*/ +struct PSI_xid +{ + /** Format identifier. */ + long formatID; + /** GTRID length, value 1-64. */ + long gtrid_length; + /** BQUAL length, value 1-64. */ + long bqual_length; + /** XID raw data, not \0-terminated */ + char data[MYSQL_XIDDATASIZE]; + + PSI_xid() {null();} + bool is_null() { return formatID == -1; } + void null() { formatID= -1; gtrid_length= 0; bqual_length= 0;} +}; +typedef struct PSI_xid PSI_xid; + +/** A transaction record. */ +struct PFS_events_transactions : public PFS_events +{ + /** Source identifier, mapped from internal format. */ + //rpl_sid m_sid; + /** InnoDB transaction ID. */ + ulonglong m_trxid; + /** Status */ + enum_transaction_state m_state; + /** Global Transaction ID specifier. */ + Gtid_specification m_gtid_spec; + /** True if XA transaction. */ + my_bool m_xa; + /** XA transaction ID. */ + PSI_xid m_xid; + /** XA status */ + enum_xa_transaction_state m_xa_state; + /** Transaction isolation level. */ + enum_isolation_level m_isolation_level; + /** True if read-only transaction, otherwise read-write. */ + my_bool m_read_only; + /** True if autocommit transaction. */ + my_bool m_autocommit; + /** Total number of savepoints. */ + ulonglong m_savepoint_count; + /** Number of rollback_to_savepoint. */ + ulonglong m_rollback_to_savepoint_count; + /** Number of release_savepoint. */ + ulonglong m_release_savepoint_count; +}; + +bool xid_printable(PSI_xid *xid, size_t offset, size_t length); + +void insert_events_transactions_history(PFS_thread *thread, PFS_events_transactions *transaction); +void insert_events_transactions_history_long(PFS_events_transactions *transaction); + +extern bool flag_events_transactions_current; +extern bool flag_events_transactions_history; +extern bool flag_events_transactions_history_long; + +extern bool events_transactions_history_long_full; +extern PFS_cacheline_uint32 events_transactions_history_long_index; +extern PFS_events_transactions *events_transactions_history_long_array; +extern ulong events_transactions_history_long_size; + +int init_events_transactions_history_long(uint events_transactions_history_long_sizing); +void cleanup_events_transactions_history_long(); + +void reset_events_transactions_current(); +void reset_events_transactions_history(); +void reset_events_transactions_history_long(); +void reset_events_transactions_by_thread(); +void reset_events_transactions_by_account(); +void reset_events_transactions_by_user(); +void reset_events_transactions_by_host(); +void reset_events_transactions_global(); +void aggregate_account_transactions(PFS_account *account); +void aggregate_user_transactions(PFS_user *user); +void aggregate_host_transactions(PFS_host *host); + +#endif + diff --git a/storage/perfschema/pfs_events_waits.cc b/storage/perfschema/pfs_events_waits.cc index c3961461f34..b51ee5fd2c8 100644 --- a/storage/perfschema/pfs_events_waits.cc +++ b/storage/perfschema/pfs_events_waits.cc @@ -35,26 +35,28 @@ #include "pfs_account.h" #include "pfs_events_waits.h" #include "pfs_atomic.h" +#include "pfs_buffer_container.h" +#include "pfs_builtin_memory.h" #include "m_string.h" -ulong events_waits_history_long_size= 0; +PFS_ALIGNED ulong events_waits_history_long_size= 0; /** Consumer flag for table EVENTS_WAITS_CURRENT. */ -bool flag_events_waits_current= false; +PFS_ALIGNED bool flag_events_waits_current= false; /** Consumer flag for table EVENTS_WAITS_HISTORY. */ -bool flag_events_waits_history= false; +PFS_ALIGNED bool flag_events_waits_history= false; /** Consumer flag for table EVENTS_WAITS_HISTORY_LONG. */ -bool flag_events_waits_history_long= false; +PFS_ALIGNED bool flag_events_waits_history_long= false; /** Consumer flag for the global instrumentation. */ -bool flag_global_instrumentation= false; +PFS_ALIGNED bool flag_global_instrumentation= false; /** Consumer flag for the per thread instrumentation. */ -bool flag_thread_instrumentation= false; +PFS_ALIGNED bool flag_thread_instrumentation= false; /** True if EVENTS_WAITS_HISTORY_LONG circular buffer is full. */ -bool events_waits_history_long_full= false; +PFS_ALIGNED bool events_waits_history_long_full= false; /** Index in EVENTS_WAITS_HISTORY_LONG circular buffer. */ -volatile uint32 events_waits_history_long_index= 0; +PFS_ALIGNED PFS_cacheline_uint32 events_waits_history_long_index; /** EVENTS_WAITS_HISTORY_LONG circular buffer. */ -PFS_events_waits *events_waits_history_long_array= NULL; +PFS_ALIGNED PFS_events_waits *events_waits_history_long_array= NULL; /** Initialize table EVENTS_WAITS_HISTORY_LONG. @@ -64,14 +66,16 @@ int init_events_waits_history_long(uint events_waits_history_long_sizing) { events_waits_history_long_size= events_waits_history_long_sizing; events_waits_history_long_full= false; - PFS_atomic::store_u32(&events_waits_history_long_index, 0); + PFS_atomic::store_u32(&events_waits_history_long_index.m_u32, 0); if (events_waits_history_long_size == 0) return 0; events_waits_history_long_array= - PFS_MALLOC_ARRAY(events_waits_history_long_size, sizeof(PFS_events_waits), - PFS_events_waits, MYF(MY_ZEROFILL)); + PFS_MALLOC_ARRAY(& builtin_memory_waits_history_long, + events_waits_history_long_size, + sizeof(PFS_events_waits), PFS_events_waits, + MYF(MY_ZEROFILL)); return (events_waits_history_long_array ? 0 : 1); } @@ -79,7 +83,9 @@ int init_events_waits_history_long(uint events_waits_history_long_sizing) /** Cleanup table EVENTS_WAITS_HISTORY_LONG. */ void cleanup_events_waits_history_long(void) { - pfs_free(events_waits_history_long_array); + PFS_FREE_ARRAY(& builtin_memory_waits_history_long, + events_waits_history_long_size, sizeof(PFS_events_waits), + events_waits_history_long_array); events_waits_history_long_array= NULL; } @@ -129,7 +135,7 @@ void insert_events_waits_history_long(PFS_events_waits *wait) if (unlikely(events_waits_history_long_size == 0)) return; - uint index= PFS_atomic::add_u32(&events_waits_history_long_index, 1); + uint index= PFS_atomic::add_u32(&events_waits_history_long_index.m_u32, 1); index= index % events_waits_history_long_size; if (index == 0) @@ -139,44 +145,43 @@ void insert_events_waits_history_long(PFS_events_waits *wait) copy_events_waits(&events_waits_history_long_array[index], wait); } +static void fct_reset_events_waits_current(PFS_thread *pfs_thread) +{ + PFS_events_waits *pfs_wait= pfs_thread->m_events_waits_stack; + PFS_events_waits *pfs_wait_last= pfs_wait + WAIT_STACK_SIZE; + + for ( ; pfs_wait < pfs_wait_last; pfs_wait++) + pfs_wait->m_wait_class= NO_WAIT_CLASS; +} + + /** Reset table EVENTS_WAITS_CURRENT data. */ void reset_events_waits_current(void) { - PFS_thread *pfs_thread= thread_array; - PFS_thread *pfs_thread_last= thread_array + thread_max; + global_thread_container.apply_all(fct_reset_events_waits_current); +} - for ( ; pfs_thread < pfs_thread_last; pfs_thread++) - { - PFS_events_waits *pfs_wait= pfs_thread->m_events_waits_stack; - PFS_events_waits *pfs_wait_last= pfs_wait + WAIT_STACK_SIZE; +static void fct_reset_events_waits_history(PFS_thread *pfs_thread) +{ + PFS_events_waits *wait= pfs_thread->m_waits_history; + PFS_events_waits *wait_last= wait + events_waits_history_per_thread; - for ( ; pfs_wait < pfs_wait_last; pfs_wait++) - pfs_wait->m_wait_class= NO_WAIT_CLASS; - } + pfs_thread->m_waits_history_index= 0; + pfs_thread->m_waits_history_full= false; + for ( ; wait < wait_last; wait++) + wait->m_wait_class= NO_WAIT_CLASS; } /** Reset table EVENTS_WAITS_HISTORY data. */ void reset_events_waits_history(void) { - PFS_thread *pfs_thread= thread_array; - PFS_thread *pfs_thread_last= thread_array + thread_max; - - for ( ; pfs_thread < pfs_thread_last; pfs_thread++) - { - PFS_events_waits *wait= pfs_thread->m_waits_history; - PFS_events_waits *wait_last= wait + events_waits_history_per_thread; - - pfs_thread->m_waits_history_index= 0; - pfs_thread->m_waits_history_full= false; - for ( ; wait < wait_last; wait++) - wait->m_wait_class= NO_WAIT_CLASS; - } + global_thread_container.apply_all(fct_reset_events_waits_history); } /** Reset table EVENTS_WAITS_HISTORY_LONG data. */ void reset_events_waits_history_long(void) { - PFS_atomic::store_u32(&events_waits_history_long_index, 0); + PFS_atomic::store_u32(&events_waits_history_long_index.m_u32, 0); events_waits_history_long_full= false; PFS_events_waits *wait= events_waits_history_long_array; @@ -185,141 +190,112 @@ void reset_events_waits_history_long(void) wait->m_wait_class= NO_WAIT_CLASS; } +static void fct_reset_events_waits_by_thread(PFS_thread *thread) +{ + PFS_account *account= sanitize_account(thread->m_account); + PFS_user *user= sanitize_user(thread->m_user); + PFS_host *host= sanitize_host(thread->m_host); + aggregate_thread_waits(thread, account, user, host); +} + /** 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; + global_thread_container.apply(fct_reset_events_waits_by_thread); +} - 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); - } - } +static void fct_reset_events_waits_by_account(PFS_account *pfs) +{ + PFS_user *user= sanitize_user(pfs->m_user); + PFS_host *host= sanitize_host(pfs->m_host); + pfs->aggregate_waits(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; + global_account_container.apply(fct_reset_events_waits_by_account); +} - 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); - } - } +static void fct_reset_events_waits_by_user(PFS_user *pfs) +{ + pfs->aggregate_waits(); } /** Reset table EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME data. */ void reset_events_waits_by_user() { - PFS_user *pfs= user_array; - PFS_user *pfs_last= user_array + user_max; + global_user_container.apply(fct_reset_events_waits_by_user); +} - for ( ; pfs < pfs_last; pfs++) - { - if (pfs->m_lock.is_populated()) - pfs->aggregate_waits(); - } +static void fct_reset_events_waits_by_host(PFS_host *pfs) +{ + 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; + global_host_container.apply(fct_reset_events_waits_by_host); +} - for ( ; pfs < pfs_last; pfs++) - { - if (pfs->m_lock.is_populated()) - pfs->aggregate_waits(); - } +static void fct_reset_table_waits_by_table(PFS_table_share *pfs) +{ + pfs->aggregate(); } void reset_table_waits_by_table() { - PFS_table_share *pfs= table_share_array; - PFS_table_share *pfs_last= pfs + table_share_max; + global_table_share_container.apply(fct_reset_table_waits_by_table); +} - for ( ; pfs < pfs_last; pfs++) - { - if (pfs->m_lock.is_populated()) - pfs->aggregate(); - } +static void fct_reset_table_io_waits_by_table(PFS_table_share *pfs) +{ + pfs->aggregate_io(); } void reset_table_io_waits_by_table() { - PFS_table_share *pfs= table_share_array; - PFS_table_share *pfs_last= pfs + table_share_max; + global_table_share_container.apply(fct_reset_table_io_waits_by_table); +} - for ( ; pfs < pfs_last; pfs++) - { - if (pfs->m_lock.is_populated()) - pfs->aggregate_io(); - } +static void fct_reset_table_lock_waits_by_table(PFS_table_share *pfs) +{ + pfs->aggregate_lock(); } void reset_table_lock_waits_by_table() { - PFS_table_share *pfs= table_share_array; - PFS_table_share *pfs_last= pfs + table_share_max; + global_table_share_container.apply(fct_reset_table_lock_waits_by_table); +} - for ( ; pfs < pfs_last; pfs++) - { - if (pfs->m_lock.is_populated()) - pfs->aggregate_lock(); - } +void fct_reset_table_waits_by_table_handle(PFS_table *pfs) +{ + pfs->sanitized_aggregate(); } void reset_table_waits_by_table_handle() { - PFS_table *pfs= table_array; - PFS_table *pfs_last= pfs + table_max; + global_table_container.apply(fct_reset_table_waits_by_table_handle); +} - for ( ; pfs < pfs_last; pfs++) - { - if (pfs->m_lock.is_populated()) - pfs->sanitized_aggregate(); - } +void fct_reset_table_io_waits_by_table_handle(PFS_table *pfs) +{ + pfs->sanitized_aggregate_io(); } void reset_table_io_waits_by_table_handle() { - PFS_table *pfs= table_array; - PFS_table *pfs_last= pfs + table_max; + global_table_container.apply(fct_reset_table_io_waits_by_table_handle); +} - for ( ; pfs < pfs_last; pfs++) - { - if (pfs->m_lock.is_populated()) - pfs->sanitized_aggregate_io(); - } +void fct_reset_table_lock_waits_by_table_handle(PFS_table *pfs) +{ + pfs->sanitized_aggregate_lock(); } 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(); - } + global_table_container.apply(fct_reset_table_lock_waits_by_table_handle); } diff --git a/storage/perfschema/pfs_events_waits.h b/storage/perfschema/pfs_events_waits.h index 702f7e3ce07..570e1c9b71e 100644 --- a/storage/perfschema/pfs_events_waits.h +++ b/storage/perfschema/pfs_events_waits.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. - Copyright (c) 2017, MariaDB Corporation. +/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, @@ -45,6 +45,7 @@ struct PFS_table_share; struct PFS_account; struct PFS_user; struct PFS_host; +struct PFS_metadata_lock; /** Class of a wait event. */ enum events_waits_class @@ -56,29 +57,13 @@ enum events_waits_class WAIT_CLASS_TABLE, WAIT_CLASS_FILE, WAIT_CLASS_SOCKET, - WAIT_CLASS_IDLE + WAIT_CLASS_IDLE, + WAIT_CLASS_METADATA }; /** 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; - /** - Number of bytes read/written. - This member is populated for file READ/WRITE operations only. - */ - size_t m_number_of_bytes; - /** Flags */ - ulong m_flags; /** The type of wait. Readers: @@ -93,11 +78,25 @@ struct PFS_events_waits : public PFS_events events_waits_class m_wait_class; /** Object type */ enum_object_type m_object_type; + /** Table share, for table operations only. */ + PFS_table_share *m_weak_table_share; + /** File, for file operations only. */ + PFS_file *m_weak_file; + /** Socket, for socket operations only. */ + PFS_socket *m_weak_socket; + /** Metadata lock, for mdl operations only. */ + PFS_metadata_lock *m_weak_metadata_lock; /** For weak pointers, target object version. */ uint32 m_weak_version; /** Operation performed. */ enum_operation_type m_operation; /** + Number of bytes/rows read/written. + This member is populated for FILE READ/WRITE operations, with a number of bytes. + This member is populated for TABLE IO operations, with a number of rows. + */ + size_t m_number_of_bytes; + /** Index used. This member is populated for TABLE IO operations only. */ @@ -124,7 +123,7 @@ 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_ALIGNED PFS_cacheline_uint32 events_waits_history_long_index; extern PFS_events_waits *events_waits_history_long_array; extern ulong events_waits_history_long_size; diff --git a/storage/perfschema/pfs_global.cc b/storage/perfschema/pfs_global.cc index e1b5e3400ca..26cb693d441 100644 --- a/storage/perfschema/pfs_global.cc +++ b/storage/perfschema/pfs_global.cc @@ -1,4 +1,5 @@ -/* Copyright (c) 2008, 2015, 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, version 2.0, @@ -27,37 +28,38 @@ #include <my_global.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 "pfs_builtin_memory.h" +#include "log.h" + +#include <stdlib.h> +#include <string.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif - -#ifdef HAVE_STRING_H -#include <string.h> +#ifdef _WIN32 +#include <winsock2.h> #endif - -#ifdef __WIN__ - #include <winsock2.h> -#else - #include <arpa/inet.h> +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_MALLOC_H +#include <malloc.h> #endif bool pfs_initialized= false; -size_t pfs_allocated_memory= 0; /** Memory allocation for the performance schema. - The memory used internally in the performance schema implementation - is allocated once during startup, and considered static thereafter. + The memory used internally in the performance schema implementation. + It is allocated at startup, or during runtime with scalable buffers. */ -void *pfs_malloc(size_t size, myf flags) +void *pfs_malloc(PFS_builtin_memory_class *klass, size_t size, myf flags) { - DBUG_ASSERT(! pfs_initialized); + DBUG_ASSERT(klass != NULL); DBUG_ASSERT(size > 0); void *ptr= NULL; @@ -91,13 +93,14 @@ void *pfs_malloc(size_t size, myf flags) return NULL; #endif - pfs_allocated_memory+= size; + klass->count_alloc(size); + if (flags & MY_ZEROFILL) memset(ptr, 0, size); return ptr; } -void pfs_free(void *ptr) +void pfs_free(PFS_builtin_memory_class *klass, size_t size, void *ptr) { if (ptr == NULL) return; @@ -119,40 +122,58 @@ void pfs_free(void *ptr) #endif /* HAVE_ALIGNED_MALLOC */ #endif /* HAVE_MEMALIGN */ #endif /* HAVE_POSIX_MEMALIGN */ -} -void pfs_print_error(const char *format, ...) -{ - va_list args; - va_start(args, format); - /* - Printing to anything else, like the error log, would generate even more - recursive calls to the performance schema implementation - (file io is instrumented), so that could lead to catastrophic results. - Printing to something safe, and low level: stderr only. - */ - vfprintf(stderr, format, args); - va_end(args); - fflush(stderr); + klass->count_free(size); } /** Array allocation for the performance schema. Checks for overflow of n * size before allocating. - @param n number of array elements + @param klass performance schema memory class + @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) +void *pfs_malloc_array(PFS_builtin_memory_class *klass, size_t n, size_t size, myf flags) { + DBUG_ASSERT(klass != NULL); DBUG_ASSERT(n > 0); DBUG_ASSERT(size > 0); + void *ptr= NULL; size_t array_size= n * size; /* Check for overflow before allocating. */ if (is_overflow(array_size, n, size)) + { + sql_print_warning("Failed to allocate memory for %zu chunks each of size " + "%zu for buffer '%s' due to overflow", n, size, + klass->m_class.m_name); return NULL; - return pfs_malloc(array_size, flags); + } + + if(NULL == (ptr= pfs_malloc(klass, array_size, flags))) + { + sql_print_warning("Failed to allocate %zu bytes for buffer '%s' due to " + "out-of-memory", array_size, klass->m_class.m_name); + } + return ptr; +} + +/** + Free array allocated by @sa pfs_malloc_array. + @param klass performance schema memory class + @param n number of array elements + @param size element size + @param ptr pointer to memory +*/ +void pfs_free_array(PFS_builtin_memory_class *klass, size_t n, size_t size, void *ptr) +{ + if (ptr == NULL) + return; + size_t array_size= n * size; + /* Overflow should have been detected by pfs_malloc_array. */ + DBUG_ASSERT(!is_overflow(array_size, n, size)); + return pfs_free(klass, array_size, ptr); } /** @@ -170,6 +191,22 @@ bool is_overflow(size_t product, size_t n1, size_t n2) return false; } +void pfs_print_error(const char *format, ...) +{ + va_list args; + va_start(args, format); + /* + Printing to anything else, like the error log, would generate even more + recursive calls to the performance schema implementation + (file io is instrumented), so that could lead to catastrophic results. + Printing to something safe, and low level: stderr only. + */ + vfprintf(stderr, format, args); + va_end(args); + fflush(stderr); +} + + /** Convert raw ip address into readable format. Do not do a reverse DNS lookup. */ uint pfs_get_socket_address(char *host, @@ -192,7 +229,7 @@ uint pfs_get_socket_address(char *host, if (host_len < INET_ADDRSTRLEN+1) return 0; struct sockaddr_in *sa4= (struct sockaddr_in *)(src_addr); - #ifdef __WIN__ + #ifdef _WIN32 /* Older versions of Windows do not support inet_ntop() */ getnameinfo((struct sockaddr *)sa4, sizeof(struct sockaddr_in), host, host_len, NULL, 0, NI_NUMERICHOST); @@ -209,7 +246,7 @@ uint pfs_get_socket_address(char *host, if (host_len < INET6_ADDRSTRLEN+1) return 0; struct sockaddr_in6 *sa6= (struct sockaddr_in6 *)(src_addr); - #ifdef __WIN__ + #ifdef _WIN32 /* Older versions of Windows do not support inet_ntop() */ getnameinfo((struct sockaddr *)sa6, sizeof(struct sockaddr_in6), host, host_len, NULL, 0, NI_NUMERICHOST); @@ -228,4 +265,3 @@ uint pfs_get_socket_address(char *host, /* Return actual IP address string length */ return ((uint)strlen((const char*)host)); } - diff --git a/storage/perfschema/pfs_global.h b/storage/perfschema/pfs_global.h index 58db39e607d..d26e81adae7 100644 --- a/storage/perfschema/pfs_global.h +++ b/storage/perfschema/pfs_global.h @@ -32,7 +32,6 @@ /** 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; @@ -48,23 +47,74 @@ extern size_t pfs_allocated_memory; #define PFS_ALIGNED #endif /* HAVE_POSIX_MEMALIGN || HAVE_MEMALIGN || HAVE_ALIGNED_MALLOC */ -void *pfs_malloc(size_t size, myf flags); +#ifdef CPU_LEVEL1_DCACHE_LINESIZE +#define PFS_CACHE_LINE_SIZE CPU_LEVEL1_DCACHE_LINESIZE +#else +#define PFS_CACHE_LINE_SIZE 128 +#endif + +/** + A uint32 variable, guaranteed to be alone in a CPU cache line. + This is for performance, for variables accessed very frequently. +*/ +struct PFS_cacheline_uint32 +{ + uint32 m_u32; + char m_full_cache_line[PFS_CACHE_LINE_SIZE - sizeof(uint32)]; + + PFS_cacheline_uint32() + : m_u32(0) + {} +}; + +/** + A uint64 variable, guaranteed to be alone in a CPU cache line. + This is for performance, for variables accessed very frequently. +*/ +struct PFS_cacheline_uint64 +{ + uint64 m_u64; + char m_full_cache_line[PFS_CACHE_LINE_SIZE - sizeof(uint64)]; + + PFS_cacheline_uint64() + : m_u64(0) + {} +}; + +struct PFS_builtin_memory_class; + +/** Memory allocation for the performance schema. */ +void *pfs_malloc(PFS_builtin_memory_class *klass, size_t size, myf flags); /** Allocate an array of structures with overflow check. */ -void *pfs_malloc_array(size_t n, size_t size, myf flags); +void *pfs_malloc_array(PFS_builtin_memory_class *klass, size_t n, size_t size, myf flags); /** Helper, to allocate an array of structures. + @param k memory class @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))) +#define PFS_MALLOC_ARRAY(k, n, s, T, f) \ + reinterpret_cast<T*>(pfs_malloc_array((k), (n), (s), (f))) /** Free memory allocated with @sa pfs_malloc. */ -void pfs_free(void *ptr); +void pfs_free(PFS_builtin_memory_class *klass, size_t size, void *ptr); + +/** Free memory allocated with @sa pfs_malloc_array. */ +void pfs_free_array(PFS_builtin_memory_class *klass, size_t n, size_t size, void *ptr); + +/** + Helper, to free an array of structures. + @param k memory class + @param n number of elements in the array + @param s size of array element + @param p the array to free +*/ +#define PFS_FREE_ARRAY(k, n, s, p) \ + pfs_free_array((k), (n), (s), (p)) /** Detect multiplication overflow. */ bool is_overflow(size_t product, size_t n1, size_t n2); diff --git a/storage/perfschema/pfs_host.cc b/storage/perfschema/pfs_host.cc index d6461ef3851..b896215efda 100644 --- a/storage/perfschema/pfs_host.cc +++ b/storage/perfschema/pfs_host.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 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, version 2.0, @@ -34,21 +34,13 @@ #include "pfs_host.h" #include "pfs_global.h" #include "pfs_instr_class.h" +#include "pfs_buffer_container.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; @@ -59,59 +51,8 @@ static bool host_hash_inited= false; */ 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]; - } + if (global_host_container.init(param->m_host_sizing)) + return 1; return 0; } @@ -119,15 +60,7 @@ int init_host(const PFS_global_param *param) /** 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; + global_host_container.cleanup(); } C_MODE_START @@ -151,13 +84,12 @@ C_MODE_END Initialize the host hash. @return 0 on success */ -int init_host_hash(void) +int init_host_hash(const PFS_global_param *param) { - if ((! host_hash_inited) && (host_max > 0)) + if ((! host_hash_inited) && (param->m_host_sizing != 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; @@ -203,16 +135,12 @@ static void set_host_key(PFS_host_key *key, PFS_host *find_or_create_host(PFS_thread *thread, const char *hostname, uint hostname_length) { - if (host_max == 0) - { - host_lost++; - return NULL; - } + static PFS_ALIGNED PFS_cacheline_uint32 monotonic; LF_PINS *pins= get_host_hash_pins(thread); if (unlikely(pins == NULL)) { - host_lost++; + global_host_container.m_lost++; return NULL; } @@ -220,8 +148,10 @@ PFS_host *find_or_create_host(PFS_thread *thread, set_host_key(&key, hostname, hostname_length); PFS_host **entry; + PFS_host *pfs; uint retry_count= 0; const uint retry_max= 3; + pfs_dirty_state dirty_state; search: entry= reinterpret_cast<PFS_host**> @@ -238,68 +168,55 @@ search: 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= global_host_container.allocate(& dirty_state); + if (pfs != NULL) { - PFS_host *pfs= host_array + scan.first(); - PFS_host *pfs_last= host_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + 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; + pfs->m_lock.dirty_to_allocated(& dirty_state); + res= lf_hash_insert(&host_hash, pins, &pfs); + if (likely(res == 0)) { - if (pfs->m_lock.is_free()) + return pfs; + } + + global_host_container.deallocate(pfs); + + if (res > 0) + { + if (++retry_count > retry_max) { - 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; - } + global_host_container.m_lost++; + return NULL; } + goto search; } + + global_host_container.m_lost++; + return NULL; } - host_lost++; return NULL; } -void PFS_host::aggregate() +void PFS_host::aggregate(bool alive) { aggregate_waits(); aggregate_stages(); aggregate_statements(); + aggregate_transactions(); + aggregate_memory(alive); + aggregate_status(); aggregate_stats(); } @@ -311,24 +228,63 @@ void PFS_host::aggregate_waits() void PFS_host::aggregate_stages() { + if (read_instr_class_stages_stats() == NULL) + return; + /* 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, + aggregate_all_stages(write_instr_class_stages_stats(), global_instr_class_stages_array); } void PFS_host::aggregate_statements() { + if (read_instr_class_statements_stats() == NULL) + return; + /* 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, + aggregate_all_statements(write_instr_class_statements_stats(), global_instr_class_statements_array); } +void PFS_host::aggregate_transactions() +{ + if (read_instr_class_transactions_stats() == NULL) + return; + + /* + Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME to: + - EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME + */ + aggregate_all_transactions(write_instr_class_transactions_stats(), + &global_transaction_stat); +} + +void PFS_host::aggregate_memory(bool alive) +{ + if (read_instr_class_memory_stats() == NULL) + return; + + /* + Aggregate MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME to: + - MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME + */ + aggregate_all_memory(alive, + write_instr_class_memory_stats(), + global_instr_class_memory_array); +} + +void PFS_host::aggregate_status() +{ + /* No parent to aggregate to, clean the stats */ + m_status_stats.reset(); +} + void PFS_host::aggregate_stats() { /* No parent to aggregate to, clean the stats */ @@ -340,12 +296,24 @@ void PFS_host::release() dec_refcount(); } +void PFS_host::carry_memory_stat_delta(PFS_memory_stat_delta *delta, uint index) +{ + PFS_memory_stat *event_name_array; + PFS_memory_stat *stat; + PFS_memory_stat_delta delta_buffer; + PFS_memory_stat_delta *remaining_delta; + + event_name_array= write_instr_class_memory_stats(); + stat= & event_name_array[index]; + remaining_delta= stat->apply_delta(delta, &delta_buffer); + + if (remaining_delta != NULL) + carry_global_memory_stat_delta(remaining_delta, index); +} + PFS_host *sanitize_host(PFS_host *unsafe) { - if ((&host_array[0] <= unsafe) && - (unsafe < &host_array[host_max])) - return unsafe; - return NULL; + return global_host_container.sanitize(unsafe); } void purge_host(PFS_thread *thread, PFS_host *host) @@ -365,13 +333,33 @@ void purge_host(PFS_thread *thread, PFS_host *host) { lf_hash_delete(&host_hash, pins, host->m_key.m_hash_key, host->m_key.m_key_length); - host->m_lock.allocated_to_free(); + host->aggregate(false); + global_host_container.deallocate(host); } } lf_hash_search_unpin(pins); } +class Proc_purge_host + : public PFS_buffer_processor<PFS_host> +{ +public: + Proc_purge_host(PFS_thread *thread) + : m_thread(thread) + {} + + virtual void operator()(PFS_host *pfs) + { + pfs->aggregate(true); + if (pfs->get_refcount() == 0) + purge_host(m_thread, pfs); + } + +private: + PFS_thread *m_thread; +}; + /** Purge non connected hosts, reset stats of connected hosts. */ void purge_all_host(void) { @@ -379,18 +367,8 @@ void purge_all_host(void) 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); - } - } + Proc_purge_host proc(thread); + global_host_container.apply(proc); } /** @} */ diff --git a/storage/perfschema/pfs_host.h b/storage/perfschema/pfs_host.h index d52207d3571..3781988237b 100644 --- a/storage/perfschema/pfs_host.h +++ b/storage/perfschema/pfs_host.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -40,6 +40,7 @@ struct PFS_thread; @{ */ +/** Hash key for a host. */ struct PFS_host_key { /** @@ -51,6 +52,7 @@ struct PFS_host_key uint m_key_length; }; +/** Per host statistics. */ struct PFS_ALIGNED PFS_host : PFS_connection_slice { public: @@ -74,13 +76,18 @@ public: PFS_atomic::add_32(& m_refcount, -1); } - void aggregate(void); + void aggregate(bool alive); void aggregate_waits(void); void aggregate_stages(void); void aggregate_statements(void); + void aggregate_transactions(void); + void aggregate_memory(bool alive); + void aggregate_status(void); void aggregate_stats(void); void release(void); + void carry_memory_stat_delta(PFS_memory_stat_delta *delta, uint index); + /* Internal lock. */ pfs_lock m_lock; PFS_host_key m_key; @@ -95,7 +102,7 @@ private: int init_host(const PFS_global_param *param); void cleanup_host(void); -int init_host_hash(void); +int init_host_hash(const PFS_global_param *param); void cleanup_host_hash(void); PFS_host *find_or_create_host(PFS_thread *thread, @@ -104,14 +111,7 @@ PFS_host *find_or_create_host(PFS_thread *thread, 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; +/* For show status. */ extern LF_HASH host_hash; diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc index ca9e0385021..728c503ec4e 100644 --- a/storage/perfschema/pfs_instr.cc +++ b/storage/perfschema/pfs_instr.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2015, 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, version 2.0, @@ -37,115 +37,45 @@ #include "pfs_account.h" #include "pfs_global.h" #include "pfs_instr_class.h" +#include "pfs_buffer_container.h" +#include "pfs_builtin_memory.h" + +ulong nested_statement_lost= 0; /** @addtogroup Performance_schema_buffers @{ */ -/** 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; /** Size of the file handle array. @sa file_handle_array. Signed value, for easier comparisons with a file descriptor number. */ -long file_handle_max; +long file_handle_max= 0; /** 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; +ulong file_handle_lost= 0; /** Number of EVENTS_WAITS_HISTORY records per thread. */ -ulong events_waits_history_per_thread; +ulong events_waits_history_per_thread= 0; /** Number of EVENTS_STAGES_HISTORY records per thread. */ -ulong events_stages_history_per_thread; +ulong events_stages_history_per_thread= 0; /** Number of EVENTS_STATEMENTS_HISTORY records per thread. */ -ulong events_statements_history_per_thread; -uint statement_stack_max; +ulong events_statements_history_per_thread= 0; +uint statement_stack_max= 0; size_t pfs_max_digest_length= 0; +size_t pfs_max_sqltext= 0; /** Number of locker lost. @sa LOCKER_STACK_SIZE. */ ulong locker_lost= 0; -/** Number of statement lost. @sa STATEMENT_STACK_SIZE. */ +/** Number of statements lost. @sa STATEMENT_STACK_SIZE. */ ulong statement_lost= 0; /** Size of connection attribute storage per thread */ ulong session_connect_attrs_size_per_thread; /** Number of connection attributes lost */ ulong session_connect_attrs_lost= 0; -/** - Mutex instrumentation instances array. - @sa mutex_max - @sa mutex_lost -*/ -PFS_mutex *mutex_array= NULL; - -/** - RWLock instrumentation instances array. - @sa rwlock_max - @sa rwlock_lost -*/ -PFS_rwlock *rwlock_array= NULL; - -/** - Condition instrumentation instances array. - @sa cond_max - @sa cond_lost -*/ -PFS_cond *cond_array= NULL; - -/** - Thread instrumentation instances array. - @sa thread_max - @sa thread_lost -*/ -PFS_thread *thread_array= NULL; - -/** - File instrumentation instances array. - @sa file_max - @sa file_lost - @sa filename_hash -*/ -PFS_file *file_array= NULL; +/** Number of EVENTS_TRANSACTIONS_HISTORY records per thread. */ +ulong events_transactions_history_per_thread= 0; /** File instrumentation handle array. @@ -154,39 +84,11 @@ PFS_file *file_array= NULL; */ PFS_file **file_handle_array= NULL; -/** - Table instrumentation instances array. - @sa table_max - @sa table_lost -*/ -PFS_table *table_array= NULL; - -/** - Socket instrumentation instances array. - @sa socket_max - @sa socket_lost -*/ -PFS_socket *socket_array= NULL; - PFS_stage_stat *global_instr_class_stages_array= NULL; PFS_statement_stat *global_instr_class_statements_array= NULL; +PFS_memory_stat *global_instr_class_memory_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; +static PFS_ALIGNED PFS_cacheline_uint64 thread_internal_id_counter; /** Hash table for instrumented files. */ LF_HASH filename_hash; @@ -200,291 +102,76 @@ static bool filename_hash_inited= false; */ int init_instruments(const PFS_global_param *param) { - 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; /* 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; + pfs_max_sqltext= param->m_max_sql_text_length; events_waits_history_per_thread= param->m_events_waits_history_sizing; - thread_waits_history_sizing= param->m_thread_sizing - * events_waits_history_per_thread; - - thread_instr_class_waits_sizing= param->m_thread_sizing - * wait_class_max; events_stages_history_per_thread= param->m_events_stages_history_sizing; - thread_stages_history_sizing= param->m_thread_sizing - * events_stages_history_per_thread; events_statements_history_per_thread= param->m_events_statements_history_sizing; - thread_statements_history_sizing= param->m_thread_sizing - * events_statements_history_per_thread; - statement_stack_max= 1; - thread_statements_stack_sizing= param->m_thread_sizing * statement_stack_max; + statement_stack_max= param->m_statement_stack_sizing; - 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; + events_transactions_history_per_thread= param->m_events_transactions_history_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; - cond_array= NULL; - file_array= NULL; file_handle_array= NULL; - table_array= NULL; - socket_array= NULL; - thread_array= NULL; - thread_waits_history_array= NULL; - thread_stages_history_array= NULL; - thread_statements_history_array= NULL; - thread_statements_stack_array= NULL; - 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, sizeof(PFS_mutex), PFS_mutex, MYF(MY_ZEROFILL)); - if (unlikely(mutex_array == NULL)) - return 1; - } - if (rwlock_max > 0) - { - rwlock_array= PFS_MALLOC_ARRAY(rwlock_max, sizeof(PFS_rwlock), PFS_rwlock, MYF(MY_ZEROFILL)); - if (unlikely(rwlock_array == NULL)) - return 1; - } + thread_internal_id_counter.m_u64= 0; - if (cond_max > 0) - { - cond_array= PFS_MALLOC_ARRAY(cond_max, sizeof(PFS_cond), PFS_cond, MYF(MY_ZEROFILL)); - if (unlikely(cond_array == NULL)) - return 1; - } + if (global_mutex_container.init(param->m_mutex_sizing)) + return 1; - if (file_max > 0) - { - file_array= PFS_MALLOC_ARRAY(file_max, sizeof(PFS_file), PFS_file, MYF(MY_ZEROFILL)); - if (unlikely(file_array == NULL)) - return 1; - } + if (global_rwlock_container.init(param->m_rwlock_sizing)) + return 1; - if (file_handle_max > 0) - { - file_handle_array= PFS_MALLOC_ARRAY(file_handle_max, sizeof(PFS_file*), PFS_file*, MYF(MY_ZEROFILL)); - if (unlikely(file_handle_array == NULL)) - return 1; - } + if (global_cond_container.init(param->m_cond_sizing)) + return 1; - if (table_max > 0) - { - table_array= PFS_MALLOC_ARRAY(table_max, sizeof(PFS_table), PFS_table, MYF(MY_ZEROFILL)); - if (unlikely(table_array == NULL)) - 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, sizeof(PFS_thread), PFS_thread, MYF(MY_ZEROFILL)); - if (unlikely(thread_array == NULL)) - return 1; - } + if (global_file_container.init(param->m_file_sizing)) + return 1; - if (thread_waits_history_sizing > 0) - { - thread_waits_history_array= - PFS_MALLOC_ARRAY(thread_waits_history_sizing, sizeof(PFS_events_waits), PFS_events_waits, - MYF(MY_ZEROFILL)); - if (unlikely(thread_waits_history_array == NULL)) - return 1; - } - - if (thread_instr_class_waits_sizing > 0) - { - thread_instr_class_waits_array= - PFS_MALLOC_ARRAY(thread_instr_class_waits_sizing, - sizeof(PFS_single_stat), PFS_single_stat, MYF(MY_ZEROFILL)); - if (unlikely(thread_instr_class_waits_array == NULL)) - return 1; - - for (index= 0; index < thread_instr_class_waits_sizing; index++) - thread_instr_class_waits_array[index].reset(); - } - - if (thread_stages_history_sizing > 0) - { - thread_stages_history_array= - PFS_MALLOC_ARRAY(thread_stages_history_sizing, sizeof(PFS_events_stages), PFS_events_stages, - MYF(MY_ZEROFILL)); - if (unlikely(thread_stages_history_array == NULL)) - return 1; - } - - if (thread_instr_class_stages_sizing > 0) - { - thread_instr_class_stages_array= - PFS_MALLOC_ARRAY(thread_instr_class_stages_sizing, - 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(); - } - - 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; - } - - 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; - } - - 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(); - } - - 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; - } - - 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; - } - - if (history_digest_tokens_sizing > 0) + if (file_handle_max > 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)) + file_handle_array= PFS_MALLOC_ARRAY(& builtin_memory_file_handle, + file_handle_max, + sizeof(PFS_file*), PFS_file*, + MYF(MY_ZEROFILL)); + if (unlikely(file_handle_array == NULL)) return 1; } - for (index= 0; index < thread_max; index++) - { - thread_array[index].m_waits_history= - &thread_waits_history_array[index * events_waits_history_per_thread]; - thread_array[index].m_instr_class_waits_stats= - &thread_instr_class_waits_array[index * wait_class_max]; - thread_array[index].m_stages_history= - &thread_stages_history_array[index * events_stages_history_per_thread]; - thread_array[index].m_instr_class_stages_stats= - &thread_instr_class_stages_array[index * stage_class_max]; - thread_array[index].m_statements_history= - &thread_statements_history_array[index * events_statements_history_per_thread]; - thread_array[index].m_statement_stack= - &thread_statements_stack_array[index * statement_stack_max]; - thread_array[index].m_instr_class_statements_stats= - &thread_instr_class_statements_array[index * statement_class_max]; - thread_array[index].m_session_connect_attrs= - &thread_session_connect_attrs_array[index * session_connect_attrs_size_per_thread]; - } + if (global_table_container.init(param->m_table_sizing)) + return 1; - for (index= 0; index < thread_statements_stack_sizing; index++) - { - pfs_stmt= & thread_statements_stack_array[index]; + if (global_socket_container.init(param->m_socket_sizing)) + return 1; - pfs_tokens= & current_stmts_digest_token_array[index * pfs_max_digest_length]; - pfs_stmt->m_digest_storage.reset(pfs_tokens, pfs_max_digest_length); - } + if (global_mdl_container.init(param->m_metadata_lock_sizing)) + return 1; - for (index= 0; index < thread_statements_history_sizing; index++) - { - pfs_stmt= & thread_statements_history_array[index]; - - pfs_tokens= & history_stmts_digest_token_array[index * pfs_max_digest_length]; - pfs_stmt->m_digest_storage.reset(pfs_tokens, pfs_max_digest_length); - } + if (global_thread_container.init(param->m_thread_sizing)) + return 1; 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)); + PFS_MALLOC_ARRAY(& builtin_memory_global_stages, + stage_class_max, + sizeof(PFS_stage_stat), PFS_stage_stat, + MYF(MY_ZEROFILL)); if (unlikely(global_instr_class_stages_array == NULL)) return 1; @@ -495,8 +182,10 @@ int init_instruments(const PFS_global_param *param) 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)); + PFS_MALLOC_ARRAY(& builtin_memory_global_statements, + statement_class_max, + sizeof(PFS_statement_stat), PFS_statement_stat, + MYF(MY_ZEROFILL)); if (unlikely(global_instr_class_statements_array == NULL)) return 1; @@ -504,60 +193,59 @@ int init_instruments(const PFS_global_param *param) global_instr_class_statements_array[index].reset(); } + if (memory_class_max > 0) + { + global_instr_class_memory_array= + PFS_MALLOC_ARRAY(& builtin_memory_global_memory, + memory_class_max, + sizeof(PFS_memory_stat), PFS_memory_stat, + MYF(MY_ZEROFILL)); + if (unlikely(global_instr_class_memory_array == NULL)) + return 1; + + for (index= 0; index < memory_class_max; index++) + global_instr_class_memory_array[index].reset(); + } + return 0; } /** Cleanup all the instruments buffers. */ void cleanup_instruments(void) { - pfs_free(mutex_array); - mutex_array= NULL; - mutex_max= 0; - pfs_free(rwlock_array); - rwlock_array= NULL; - rwlock_max= 0; - pfs_free(cond_array); - cond_array= NULL; - cond_max= 0; - pfs_free(file_array); - file_array= NULL; - file_max= 0; - pfs_free(file_handle_array); + global_mutex_container.cleanup(); + global_rwlock_container.cleanup(); + global_cond_container.cleanup(); + global_file_container.cleanup(); + + PFS_FREE_ARRAY(& builtin_memory_file_handle, + file_handle_max, sizeof(PFS_file*), + file_handle_array); file_handle_array= NULL; file_handle_max= 0; - pfs_free(table_array); - table_array= NULL; - table_max= 0; - pfs_free(socket_array); - socket_array= NULL; - socket_max= 0; - pfs_free(thread_array); - thread_array= NULL; - thread_max= 0; - pfs_free(thread_waits_history_array); - thread_waits_history_array= NULL; - pfs_free(thread_stages_history_array); - thread_stages_history_array= NULL; - pfs_free(thread_statements_history_array); - thread_statements_history_array= NULL; - pfs_free(thread_statements_stack_array); - thread_statements_stack_array= NULL; - pfs_free(thread_instr_class_waits_array); - thread_instr_class_waits_array= NULL; - pfs_free(global_instr_class_stages_array); + + global_table_container.cleanup(); + global_socket_container.cleanup(); + global_mdl_container.cleanup(); + global_thread_container.cleanup(); + + PFS_FREE_ARRAY(& builtin_memory_global_stages, + stage_class_max, + sizeof(PFS_stage_stat), + global_instr_class_stages_array); global_instr_class_stages_array= NULL; - pfs_free(global_instr_class_statements_array); + + PFS_FREE_ARRAY(& builtin_memory_global_statements, + statement_class_max, + sizeof(PFS_statement_stat), + 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; + + PFS_FREE_ARRAY(& builtin_memory_global_memory, + memory_class_max, + sizeof(PFS_memory_stat), + global_instr_class_memory_array); + global_instr_class_memory_array= NULL; } C_MODE_START @@ -582,13 +270,12 @@ C_MODE_END Initialize the file name hash. @return 0 on success */ -int init_file_hash(void) +int init_file_hash(const PFS_global_param *param) { - if ((! filename_hash_inited) && (file_max > 0)) + if ((! filename_hash_inited) && (param->m_file_sizing != 0)) { lf_hash_init(&filename_hash, sizeof(PFS_file*), LF_HASH_UNIQUE, 0, 0, filename_hash_get_key, &my_charset_bin); - /* filename_hash.size= file_max; */ filename_hash_inited= true; } return 0; @@ -604,75 +291,6 @@ void cleanup_file_hash(void) } } -void PFS_scan::init(uint random, uint max_size) -{ - m_pass= 0; - - if (max_size == 0) - { - /* Degenerated case, no buffer */ - m_pass_max= 0; - return; - } - - DBUG_ASSERT(random < max_size); - - if (PFS_MAX_ALLOC_RETRY < max_size) - { - /* - The buffer is big compared to PFS_MAX_ALLOC_RETRY, - scan it only partially. - */ - if (random + PFS_MAX_ALLOC_RETRY < max_size) - { - /* - Pass 1: [random, random + PFS_MAX_ALLOC_RETRY - 1] - Pass 2: not used. - */ - m_pass_max= 1; - m_first[0]= random; - m_last[0]= random + PFS_MAX_ALLOC_RETRY; - m_first[1]= 0; - m_last[1]= 0; - } - else - { - /* - Pass 1: [random, max_size - 1] - Pass 2: [0, ...] - The combined length of pass 1 and 2 is PFS_MAX_ALLOC_RETRY. - */ - m_pass_max= 2; - m_first[0]= random; - m_last[0]= max_size; - m_first[1]= 0; - m_last[1]= PFS_MAX_ALLOC_RETRY - (max_size - random); - } - } - else - { - /* - The buffer is small compared to PFS_MAX_ALLOC_RETRY, - scan it in full in two passes. - Pass 1: [random, max_size - 1] - Pass 2: [0, random - 1] - */ - m_pass_max= 2; - m_first[0]= random; - m_last[0]= max_size; - m_first[1]= 0; - m_last[1]= random; - } - - DBUG_ASSERT(m_first[0] < max_size); - DBUG_ASSERT(m_first[1] < max_size); - DBUG_ASSERT(m_last[1] <= max_size); - DBUG_ASSERT(m_last[1] <= max_size); - /* The combined length of all passes should not exceed PFS_MAX_ALLOC_RETRY. */ - DBUG_ASSERT((m_last[0] - m_first[0]) + - (m_last[1] - m_first[1]) <= PFS_MAX_ALLOC_RETRY); -} - /** Create instrumentation for a mutex instance. @param klass the mutex class @@ -681,76 +299,25 @@ void PFS_scan::init(uint random, uint max_size) */ PFS_mutex* create_mutex(PFS_mutex_class *klass, const void *identity) { - static uint PFS_ALIGNED mutex_monotonic_index= 0; - uint index; - uint attempts= 0; PFS_mutex *pfs; + pfs_dirty_state dirty_state; - if (mutex_full) + pfs= global_mutex_container.allocate(& dirty_state, klass->m_volatility); + if (pfs != NULL) { - /* - This is a safety plug. - When mutex_array is severely undersized, - do not spin to death for each call. - */ - mutex_lost++; - return NULL; - } - - while (++attempts <= mutex_max) - { - /* - Problem: - Multiple threads running concurrently may need to create a new - instrumented mutex, and find an empty slot in mutex_array[]. - With N1 threads running on a N2 core hardware: - - up to N2 hardware threads can run concurrently, - causing contention if looking at the same array[i] slot. - - up to N1 threads can run almost concurrently (with thread scheduling), - scanning maybe overlapping regions in the [0-mutex_max] array. - - Solution: - Instead of letting different threads compete on the same array[i] entry, - this code forces all threads to cooperate with the monotonic_index. - Only one thread will be allowed to test a given array[i] slot. - All threads do scan from the same region, starting at monotonic_index. - Serializing on monotonic_index ensures that when a slot is found occupied - in a given loop by a given thread, other threads will not attempt this - slot. - */ - index= PFS_atomic::add_u32(& mutex_monotonic_index, 1) % mutex_max; - pfs= mutex_array + index; - - if (pfs->m_lock.is_free()) - { - if (pfs->m_lock.free_to_dirty()) - { - pfs->m_identity= identity; - pfs->m_class= klass; - pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; - pfs->m_timed= klass->m_timed; - pfs->m_mutex_stat.reset(); - pfs->m_owner= NULL; - pfs->m_last_locked= 0; - pfs->m_lock.dirty_to_allocated(); - if (klass->is_singleton()) - klass->m_singleton= pfs; - return pfs; - } - } + 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(& dirty_state); + if (klass->is_singleton()) + klass->m_singleton= pfs; } - mutex_lost++; - /* - 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; + return pfs; } /** @@ -766,8 +333,8 @@ void destroy_mutex(PFS_mutex *pfs) pfs->m_mutex_stat.reset(); if (klass->is_singleton()) klass->m_singleton= NULL; - pfs->m_lock.allocated_to_free(); - mutex_full= false; + + global_mutex_container.deallocate(pfs); } /** @@ -778,47 +345,27 @@ void destroy_mutex(PFS_mutex *pfs) */ PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity) { - static uint PFS_ALIGNED rwlock_monotonic_index= 0; - uint index; - uint attempts= 0; PFS_rwlock *pfs; + pfs_dirty_state dirty_state; - if (rwlock_full) + pfs= global_rwlock_container.allocate(& dirty_state); + if (pfs != NULL) { - 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.free_to_dirty()) - { - pfs->m_identity= identity; - pfs->m_class= klass; - pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; - pfs->m_timed= klass->m_timed; - pfs->m_rwlock_stat.reset(); - pfs->m_lock.dirty_to_allocated(); - pfs->m_writer= NULL; - pfs->m_readers= 0; - pfs->m_last_written= 0; - pfs->m_last_read= 0; - if (klass->is_singleton()) - klass->m_singleton= pfs; - return pfs; - } - } + 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_writer= NULL; + pfs->m_readers= 0; + pfs->m_last_written= 0; + pfs->m_last_read= 0; + pfs->m_lock.dirty_to_allocated(& dirty_state); + if (klass->is_singleton()) + klass->m_singleton= pfs; } - rwlock_lost++; - rwlock_full= true; - return NULL; + return pfs; } /** @@ -834,8 +381,8 @@ void destroy_rwlock(PFS_rwlock *pfs) pfs->m_rwlock_stat.reset(); if (klass->is_singleton()) klass->m_singleton= NULL; - pfs->m_lock.allocated_to_free(); - rwlock_full= false; + + global_rwlock_container.deallocate(pfs); } /** @@ -846,45 +393,23 @@ void destroy_rwlock(PFS_rwlock *pfs) */ PFS_cond* create_cond(PFS_cond_class *klass, const void *identity) { - static uint PFS_ALIGNED cond_monotonic_index= 0; - uint index; - uint attempts= 0; PFS_cond *pfs; + pfs_dirty_state dirty_state; - if (cond_full) - { - cond_lost++; - return NULL; - } - - while (++attempts <= cond_max) + pfs= global_cond_container.allocate(& dirty_state); + if (pfs != NULL) { - /* See create_mutex() */ - index= PFS_atomic::add_u32(& cond_monotonic_index, 1) % cond_max; - pfs= cond_array + index; - - if (pfs->m_lock.is_free()) - { - if (pfs->m_lock.free_to_dirty()) - { - pfs->m_identity= identity; - pfs->m_class= klass; - pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; - pfs->m_timed= klass->m_timed; - pfs->m_cond_stat.m_signal_count= 0; - pfs->m_cond_stat.m_broadcast_count= 0; - pfs->m_wait_stat.reset(); - pfs->m_lock.dirty_to_allocated(); - if (klass->is_singleton()) - klass->m_singleton= pfs; - return pfs; - } - } + 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.reset(); + pfs->m_lock.dirty_to_allocated(& dirty_state); + if (klass->is_singleton()) + klass->m_singleton= pfs; } - cond_lost++; - cond_full= true; - return NULL; + return pfs; } /** @@ -897,17 +422,16 @@ void destroy_cond(PFS_cond *pfs) 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(); + pfs->m_cond_stat.reset(); if (klass->is_singleton()) klass->m_singleton= NULL; - pfs->m_lock.allocated_to_free(); - cond_full= false; + + global_cond_container.deallocate(pfs); } PFS_thread* PFS_thread::get_current_thread() { - PFS_thread *pfs= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS); - return pfs; + return static_cast<PFS_thread*>(my_get_thread_local(THR_PFS)); } void PFS_thread::reset_session_connect_attrs() @@ -923,6 +447,64 @@ void PFS_thread::reset_session_connect_attrs() } } +void PFS_thread::set_history_derived_flags() +{ + if (m_history) + { + m_flag_events_waits_history= flag_events_waits_history; + m_flag_events_waits_history_long= flag_events_waits_history_long; + m_flag_events_stages_history= flag_events_stages_history; + m_flag_events_stages_history_long= flag_events_stages_history_long; + m_flag_events_statements_history= flag_events_statements_history; + m_flag_events_statements_history_long= flag_events_statements_history_long; + m_flag_events_transactions_history= flag_events_transactions_history; + m_flag_events_transactions_history_long= flag_events_transactions_history_long; + } + else + { + m_flag_events_waits_history= false; + m_flag_events_waits_history_long= false; + m_flag_events_stages_history= false; + m_flag_events_stages_history_long= false; + m_flag_events_statements_history= false; + m_flag_events_statements_history_long= false; + m_flag_events_transactions_history= false; + m_flag_events_transactions_history_long= false; + } +} + +void PFS_thread::carry_memory_stat_delta(PFS_memory_stat_delta *delta, uint index) +{ + if (m_account != NULL) + { + m_account->carry_memory_stat_delta(delta, index); + return; + } + + if (m_user != NULL) + { + m_user->carry_memory_stat_delta(delta, index); + /* do not return, need to process m_host below */ + } + + if (m_host != NULL) + { + m_host->carry_memory_stat_delta(delta, index); + return; + } + + carry_global_memory_stat_delta(delta, index); +} + +void carry_global_memory_stat_delta(PFS_memory_stat_delta *delta, uint index) +{ + PFS_memory_stat *stat; + PFS_memory_stat_delta delta_buffer; + + stat= & global_instr_class_memory_array[index]; + (void) stat->apply_delta(delta, &delta_buffer); +} + /** Create instrumentation for a thread instance. @param klass the thread class @@ -935,158 +517,101 @@ void PFS_thread::reset_session_connect_attrs() PFS_thread* create_thread(PFS_thread_class *klass, const void *identity, ulonglong processlist_id) { - static uint PFS_ALIGNED thread_monotonic_index= 0; - uint index; - uint attempts= 0; PFS_thread *pfs; + pfs_dirty_state dirty_state; + + pfs= global_thread_container.allocate(& dirty_state); + if (pfs != NULL) + { + pfs->m_thread_internal_id= + PFS_atomic::add_u64(&thread_internal_id_counter.m_u64, 1); + pfs->m_parent_thread_internal_id= 0; + pfs->m_processlist_id= static_cast<ulong>(processlist_id); + pfs->m_thread_os_id= 0; + pfs->m_event_id= 1; + pfs->m_stmt_lock.set_allocated(); + pfs->m_session_lock.set_allocated(); + pfs->set_enabled(true); + pfs->set_history(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->m_transactions_history_full= false; + pfs->m_transactions_history_index= 0; + + pfs->reset_stats(); + pfs->reset_session_connect_attrs(); - if (thread_full) - { - thread_lost++; - return NULL; - } + 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_program_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_stage_progress= NULL; + pfs->m_processlist_info[0]= '\0'; + pfs->m_processlist_info_length= 0; + pfs->m_connection_type= VIO_CLOSED; + + pfs->m_thd= NULL; + pfs->m_host= NULL; + pfs->m_user= NULL; + pfs->m_account= NULL; + set_thread_account(pfs); - while (++attempts <= thread_max) - { - /* See create_mutex() */ - index= PFS_atomic::add_u32(& thread_monotonic_index, 1) % thread_max; - pfs= thread_array + index; + /* + For child waits, by default, + - NESTING_EVENT_ID is NULL + - NESTING_EVENT_TYPE is NULL + */ + PFS_events_waits *child_wait= & pfs->m_events_waits_stack[0]; + child_wait->m_event_id= 0; - if (pfs->m_lock.is_free()) - { - if (pfs->m_lock.free_to_dirty()) - { - pfs->m_thread_internal_id= - PFS_atomic::add_u64(&thread_internal_id_counter, 1); - pfs->m_parent_thread_internal_id= 0; - pfs->m_processlist_id= (ulong)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++) - { - 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; - } - } + /* + For child stages, by default, + - NESTING_EVENT_ID is NULL + - NESTING_EVENT_TYPE is NULL + */ + PFS_events_stages *child_stage= & pfs->m_stage_current; + child_stage->m_nesting_event_id= 0; + + pfs->m_events_statements_count= 0; + pfs->m_transaction_current.m_event_id= 0; + + pfs->m_lock.dirty_to_allocated(& dirty_state); } - thread_lost++; - thread_full= true; - return NULL; + return pfs; } PFS_mutex *sanitize_mutex(PFS_mutex *unsafe) { - SANITIZE_ARRAY_BODY(PFS_mutex, mutex_array, mutex_max, unsafe); + return global_mutex_container.sanitize(unsafe); } PFS_rwlock *sanitize_rwlock(PFS_rwlock *unsafe) { - SANITIZE_ARRAY_BODY(PFS_rwlock, rwlock_array, rwlock_max, unsafe); + return global_rwlock_container.sanitize(unsafe); } PFS_cond *sanitize_cond(PFS_cond *unsafe) { - SANITIZE_ARRAY_BODY(PFS_cond, cond_array, cond_max, unsafe); + return global_cond_container.sanitize(unsafe); } /** @@ -1100,17 +625,22 @@ PFS_cond *sanitize_cond(PFS_cond *unsafe) */ PFS_thread *sanitize_thread(PFS_thread *unsafe) { - SANITIZE_ARRAY_BODY(PFS_thread, thread_array, thread_max, unsafe); + return global_thread_container.sanitize(unsafe); } PFS_file *sanitize_file(PFS_file *unsafe) { - SANITIZE_ARRAY_BODY(PFS_file, file_array, file_max, unsafe); + return global_file_container.sanitize(unsafe); } PFS_socket *sanitize_socket(PFS_socket *unsafe) { - SANITIZE_ARRAY_BODY(PFS_socket, socket_array, socket_max, unsafe); + return global_socket_container.sanitize(unsafe); +} + +PFS_metadata_lock *sanitize_metadata_lock(PFS_metadata_lock *unsafe) +{ + return global_mdl_container.sanitize(unsafe); } /** @@ -1181,12 +711,16 @@ void destroy_thread(PFS_thread *pfs) lf_hash_put_pins(pfs->m_digest_hash_pins); pfs->m_digest_hash_pins= NULL; } - pfs->m_lock.allocated_to_free(); - thread_full= false; + if (pfs->m_program_hash_pins) + { + lf_hash_put_pins(pfs->m_program_hash_pins); + pfs->m_program_hash_pins= NULL; + } + global_thread_container.deallocate(pfs); } /** - Get the hash pins for @filename_hash. + Get the hash pins for @c filename_hash. @param thread The running thread. @returns The LF_HASH pins for the thread. */ @@ -1221,7 +755,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, LF_PINS *pins= get_filename_hash_pins(thread); if (unlikely(pins == NULL)) { - file_lost++; + global_file_container.m_lost++; return NULL; } @@ -1272,6 +806,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, char dirbuffer[FN_REFLEN]; size_t dirlen; const char *normalized_filename; + uint normalized_length; dirlen= dirname_length(safe_filename); if (dirlen == 0) @@ -1288,7 +823,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, if (my_realpath(buffer, dirbuffer, MYF(0)) != 0) { - file_lost++; + global_file_container.m_lost++; return NULL; } @@ -1302,14 +837,12 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, *buf_end= '\0'; normalized_filename= buffer; - uint normalized_length= static_cast<uint>(strlen(normalized_filename)); + normalized_length= (uint)strlen(normalized_filename); PFS_file **entry; uint retry_count= 0; const uint retry_max= 3; - static uint PFS_ALIGNED file_monotonic_index= 0; - uint index; - uint attempts= 0; + pfs_dirty_state dirty_state; search: @@ -1332,70 +865,204 @@ search: return NULL; } - if (file_full) + pfs= global_file_container.allocate(& dirty_state); + if (pfs != NULL) { - file_lost++; - return NULL; - } + pfs->m_class= klass; + pfs->m_enabled= klass->m_enabled && flag_global_instrumentation; + pfs->m_timed= klass->m_timed; + memcpy(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; + pfs->m_temporary= false; + + int res; + pfs->m_lock.dirty_to_allocated(& dirty_state); + res= lf_hash_insert(&filename_hash, pins, + &pfs); + if (likely(res == 0)) + { + if (klass->is_singleton()) + klass->m_singleton= pfs; + return pfs; + } - while (++attempts <= file_max) - { - /* See create_mutex() */ - index= PFS_atomic::add_u32(& file_monotonic_index, 1) % file_max; - pfs= file_array + index; + global_file_container.deallocate(pfs); - if (pfs->m_lock.is_free()) + if (res > 0) { - if (pfs->m_lock.free_to_dirty()) + /* Duplicate insert by another thread */ + if (++retry_count > retry_max) { - 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 + 1); - pfs->m_filename[normalized_length]= '\0'; - pfs->m_filename_length= normalized_length; - pfs->m_file_stat.m_open_count= 1; - pfs->m_file_stat.m_io_stat.reset(); - pfs->m_identity= (const void *)pfs; - - int res; - res= lf_hash_insert(&filename_hash, thread->m_filename_hash_pins, - &pfs); - if (likely(res == 0)) - { - pfs->m_lock.dirty_to_allocated(); - if (klass->is_singleton()) - klass->m_singleton= pfs; - return pfs; - } - - pfs->m_lock.dirty_to_free(); - - if (res > 0) - { - /* Duplicate insert by another thread */ - if (++retry_count > retry_max) - { - /* Avoid infinite loops */ - file_lost++; - return NULL; - } - goto search; - } - - /* OOM in lf_hash_insert */ - file_lost++; + /* Avoid infinite loops */ + global_file_container.m_lost++; return NULL; } + goto search; } + + /* OOM in lf_hash_insert */ + global_file_container.m_lost++; + return NULL; } - file_lost++; - file_full= true; return NULL; } /** + Find a file instrumentation instance by name, and rename it + @param thread the executing instrumented thread + @param old_filename the file to be renamed + @param old_len the length in bytes of the old filename + @param new_filename the new file name + @param new_len the length in bytes of the new filename +*/ +void find_and_rename_file(PFS_thread *thread, const char *old_filename, + uint old_len, const char *new_filename, uint new_len) +{ + PFS_file *pfs; + + DBUG_ASSERT(thread != NULL); + + LF_PINS *pins= get_filename_hash_pins(thread); + if (unlikely(pins == NULL)) + { + global_file_container.m_lost++; + return; + } + + /* + Normalize the old file name. + */ + char safe_buffer[FN_REFLEN]; + const char *safe_filename; + + if (old_len >= FN_REFLEN) + { + memcpy(safe_buffer, old_filename, FN_REFLEN - 1); + safe_buffer[FN_REFLEN - 1]= 0; + safe_filename= safe_buffer; + } + else + safe_filename= old_filename; + + char buffer[FN_REFLEN]; + char dirbuffer[FN_REFLEN]; + size_t dirlen; + const char *normalized_filename; + uint normalized_length; + + dirlen= dirname_length(safe_filename); + if (dirlen == 0) + { + dirbuffer[0]= FN_CURLIB; + dirbuffer[1]= FN_LIBCHAR; + dirbuffer[2]= '\0'; + } + else + { + memcpy(dirbuffer, safe_filename, dirlen); + dirbuffer[dirlen]= '\0'; + } + + if (my_realpath(buffer, dirbuffer, MYF(0)) != 0) + { + global_file_container.m_lost++; + return; + } + + /* Append the unresolved file name to the resolved path */ + char *ptr= buffer + strlen(buffer); + char *buf_end= &buffer[sizeof(buffer)-1]; + if ((buf_end > ptr) && (*(ptr-1) != FN_LIBCHAR)) + *ptr++= FN_LIBCHAR; + if (buf_end > ptr) + strncpy(ptr, safe_filename + dirlen, buf_end - ptr); + *buf_end= '\0'; + + normalized_filename= buffer; + normalized_length= (uint)strlen(normalized_filename); + + PFS_file **entry; + entry= reinterpret_cast<PFS_file**> + (lf_hash_search(&filename_hash, pins, + normalized_filename, normalized_length)); + + if (entry && (entry != MY_ERRPTR)) + pfs= *entry; + else + { + lf_hash_search_unpin(pins); + return; + } + + lf_hash_delete(&filename_hash, pins, + pfs->m_filename, pfs->m_filename_length); + + /* + Normalize the new file name. + */ + if (new_len >= FN_REFLEN) + { + memcpy(safe_buffer, new_filename, FN_REFLEN - 1); + safe_buffer[FN_REFLEN - 1]= 0; + safe_filename= safe_buffer; + } + else + safe_filename= new_filename; + + dirlen= dirname_length(safe_filename); + if (dirlen == 0) + { + dirbuffer[0]= FN_CURLIB; + dirbuffer[1]= FN_LIBCHAR; + dirbuffer[2]= '\0'; + } + else + { + memcpy(dirbuffer, safe_filename, dirlen); + dirbuffer[dirlen]= '\0'; + } + + if (my_realpath(buffer, dirbuffer, MYF(0)) != 0) + { + global_file_container.m_lost++; + return; + } + + /* Append the unresolved file name to the resolved path */ + ptr= buffer + strlen(buffer); + buf_end= &buffer[sizeof(buffer)-1]; + if ((buf_end > ptr) && (*(ptr-1) != FN_LIBCHAR)) + *ptr++= FN_LIBCHAR; + if (buf_end > ptr) + strncpy(ptr, safe_filename + dirlen, buf_end - ptr); + *buf_end= '\0'; + + normalized_filename= buffer; + normalized_length= (uint)strlen(normalized_filename); + + memcpy(pfs->m_filename, normalized_filename, normalized_length); + pfs->m_filename[normalized_length]= '\0'; + pfs->m_filename_length= normalized_length; + + int res; + res= lf_hash_insert(&filename_hash, pins, &pfs); + + if (likely(res == 0)) + return; + else + { + global_file_container.deallocate(pfs); + global_file_container.m_lost++; + return; + } +} + +/** Release instrumentation for a file instance. @param pfs the file to release */ @@ -1430,8 +1097,8 @@ void destroy_file(PFS_thread *thread, PFS_file *pfs) pfs->m_filename, pfs->m_filename_length); if (klass->is_singleton()) klass->m_singleton= NULL; - pfs->m_lock.allocated_to_free(); - file_full= false; + + global_file_container.deallocate(pfs); } /** @@ -1444,49 +1111,32 @@ void destroy_file(PFS_thread *thread, PFS_file *pfs) PFS_table* create_table(PFS_table_share *share, PFS_thread *opening_thread, const void *identity) { - static uint PFS_ALIGNED table_monotonic_index= 0; - uint index; - uint attempts= 0; PFS_table *pfs; - - if (table_full) - { - 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.free_to_dirty()) - { - pfs->m_identity= identity; - pfs->m_share= share; - pfs->m_io_enabled= share->m_enabled && - flag_global_instrumentation && global_table_io_class.m_enabled; - pfs->m_io_timed= share->m_timed && global_table_io_class.m_timed; - pfs->m_lock_enabled= share->m_enabled && - flag_global_instrumentation && global_table_lock_class.m_enabled; - pfs->m_lock_timed= share->m_timed && global_table_lock_class.m_timed; - pfs->m_has_io_stats= false; - pfs->m_has_lock_stats= false; - share->inc_refcount(); - pfs->m_table_stat.fast_reset(); - pfs->m_thread_owner= opening_thread; - pfs->m_lock.dirty_to_allocated(); - return pfs; - } - } + pfs_dirty_state dirty_state; + + pfs= global_table_container.allocate(& dirty_state); + if (pfs != NULL) + { + 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; + pfs->m_internal_lock= PFS_TL_NONE; + pfs->m_external_lock= PFS_TL_NONE; + share->inc_refcount(); + pfs->m_table_stat.fast_reset(); + pfs->m_thread_owner= opening_thread; + pfs->m_owner_event_id= opening_thread->m_event_id; + pfs->m_lock.dirty_to_allocated(& dirty_state); } - table_lost++; - table_full= true; - return NULL; + return pfs; } void PFS_table::sanitized_aggregate(void) @@ -1498,18 +1148,12 @@ void PFS_table::sanitized_aggregate(void) PFS_table_share *safe_share= sanitize_table_share(m_share); if (safe_share != NULL) { - if (m_has_io_stats && m_has_lock_stats) + if (m_has_io_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); + safe_aggregate_io(NULL, & m_table_stat, safe_share); m_has_io_stats= false; } - else if (m_has_lock_stats) + if (m_has_lock_stats) { safe_aggregate_lock(& m_table_stat, safe_share); m_has_lock_stats= false; @@ -1522,7 +1166,7 @@ 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); + safe_aggregate_io(NULL, & m_table_stat, safe_share); m_has_io_stats= false; } } @@ -1537,29 +1181,67 @@ void PFS_table::sanitized_aggregate_lock(void) } } -void PFS_table::safe_aggregate(PFS_table_stat *table_stat, - PFS_table_share *table_share) +void PFS_table::safe_aggregate_io(const TABLE_SHARE *optional_server_share, + 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(); -} + PFS_table_share_index *to_stat; + PFS_table_io_stat *from_stat; + uint index; -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); + DBUG_ASSERT(key_count <= MAX_INDEXES); - uint key_count= sanitize_index_count(table_share->m_key_count); + /* Aggregate stats for each index, if any */ + for (index= 0; index < key_count; index++) + { + from_stat= & table_stat->m_index_stat[index]; + if (from_stat->m_has_data) + { + if (optional_server_share != NULL) + { + /* + An instrumented thread is closing a table, + and capable of providing index names when + creating index statistics on the fly. + */ + to_stat= table_share->find_or_create_index_stat(optional_server_share, index); + } + else + { + /* + A monitoring thread, performing TRUNCATE TABLE, + is asking to flush existing stats from table handles, + but it does not know about index names used in handles. + If the index stat already exists, find it and aggregate to it. + It the index stat does not exist yet, drop the stat and do nothing. + */ + to_stat= table_share->find_index_stat(index); + } + if (to_stat != NULL) + { + /* Aggregate to TABLE_IO_SUMMARY */ + to_stat->m_stat.aggregate(from_stat); + } + } + } + + /* Aggregate stats for the table */ + from_stat= & table_stat->m_index_stat[MAX_INDEXES]; + if (from_stat->m_has_data) + { + to_stat= table_share->find_or_create_index_stat(NULL, MAX_INDEXES); + if (to_stat != NULL) + { + /* Aggregate to TABLE_IO_SUMMARY */ + to_stat->m_stat.aggregate(from_stat); + } + } - /* Aggregate to TABLE_IO_SUMMARY */ - table_share->m_table_stat.aggregate_io(table_stat, key_count); table_stat->fast_reset_io(); } @@ -1569,8 +1251,17 @@ void PFS_table::safe_aggregate_lock(PFS_table_stat *table_stat, DBUG_ASSERT(table_stat != NULL); DBUG_ASSERT(table_share != NULL); - /* Aggregate to TABLE_LOCK_SUMMARY */ - table_share->m_table_stat.aggregate_lock(table_stat); + PFS_table_lock_stat *from_stat= & table_stat->m_lock_stat; + + PFS_table_share_lock *to_stat; + + to_stat= table_share->find_or_create_lock_stat(); + if (to_stat != NULL) + { + /* Aggregate to TABLE_LOCK_SUMMARY */ + to_stat->m_stat.aggregate(from_stat); + } + table_stat->fast_reset_lock(); } @@ -1582,29 +1273,22 @@ void destroy_table(PFS_table *pfs) { DBUG_ASSERT(pfs != NULL); pfs->m_share->dec_refcount(); - pfs->m_lock.allocated_to_free(); - table_full= false; + global_table_container.deallocate(pfs); } /** Create instrumentation for a socket instance. @param klass the socket class - @param identity the socket descriptor + @param fd the socket file descriptor + @param addr the socket address + @param addr_len the socket address length @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; - } + pfs_dirty_state dirty_state; uint fd_used= 0; uint addr_len_used= addr_len; @@ -1615,48 +1299,38 @@ PFS_socket* create_socket(PFS_socket_class *klass, const my_socket *fd, if (addr_len_used > sizeof(sockaddr_storage)) addr_len_used= sizeof(sockaddr_storage); - while (++attempts <= socket_max) + pfs= global_socket_container.allocate(& dirty_state); + + if (pfs != NULL) { - index= PFS_atomic::add_u32(& socket_monotonic_index, 1) % socket_max; - pfs= socket_array + index; + 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; - if (pfs->m_lock.is_free()) + pfs->m_addr_len= addr_len_used; + if ((addr != NULL) && (addr_len_used > 0)) { - 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; - } + 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(& dirty_state); + + if (klass->is_singleton()) + klass->m_singleton= pfs; } - socket_lost++; - socket_full= true; - return NULL; + return pfs; } /** @@ -1678,67 +1352,112 @@ void destroy_socket(PFS_socket *pfs) 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); + if (stat.m_count != 0) + { + PFS_single_stat *event_name_array; + event_name_array= thread->write_instr_class_waits_stats(); + uint index= pfs->m_class->m_event_name_index; + + 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(); - socket_full= false; + + global_socket_container.deallocate(pfs); +} + +PFS_metadata_lock* create_metadata_lock(void *identity, + const MDL_key *mdl_key, + opaque_mdl_type mdl_type, + opaque_mdl_duration mdl_duration, + opaque_mdl_status mdl_status, + const char *src_file, + uint src_line) +{ + PFS_metadata_lock *pfs; + pfs_dirty_state dirty_state; + + pfs= global_mdl_container.allocate(& dirty_state); + if (pfs != NULL) + { + pfs->m_identity= identity; + pfs->m_enabled= global_metadata_class.m_enabled && flag_global_instrumentation; + pfs->m_timed= global_metadata_class.m_timed; + pfs->m_mdl_key.mdl_key_init(mdl_key); + pfs->m_mdl_type= mdl_type; + pfs->m_mdl_duration= mdl_duration; + pfs->m_mdl_status= mdl_status; + pfs->m_src_file= src_file; + pfs->m_src_line= src_line; + pfs->m_owner_thread_id= 0; + pfs->m_owner_event_id= 0; + pfs->m_lock.dirty_to_allocated(& dirty_state); + } + + return pfs; +} + +void destroy_metadata_lock(PFS_metadata_lock *pfs) +{ + DBUG_ASSERT(pfs != NULL); + global_mdl_container.deallocate(pfs); +} + +static void fct_reset_mutex_waits(PFS_mutex *pfs) +{ + pfs->m_mutex_stat.reset(); } static void reset_mutex_waits_by_instance(void) { - PFS_mutex *pfs= mutex_array; - PFS_mutex *pfs_last= mutex_array + mutex_max; + global_mutex_container.apply_all(fct_reset_mutex_waits); +} - for ( ; pfs < pfs_last; pfs++) - pfs->m_mutex_stat.reset(); +static void fct_reset_rwlock_waits(PFS_rwlock *pfs) +{ + pfs->m_rwlock_stat.reset(); } static void reset_rwlock_waits_by_instance(void) { - PFS_rwlock *pfs= rwlock_array; - PFS_rwlock *pfs_last= rwlock_array + rwlock_max; + global_rwlock_container.apply_all(fct_reset_rwlock_waits); +} - for ( ; pfs < pfs_last; pfs++) - pfs->m_rwlock_stat.reset(); +static void fct_reset_cond_waits(PFS_cond *pfs) +{ + pfs->m_cond_stat.reset(); } static void reset_cond_waits_by_instance(void) { - PFS_cond *pfs= cond_array; - PFS_cond *pfs_last= cond_array + cond_max; + global_cond_container.apply_all(fct_reset_cond_waits); +} - for ( ; pfs < pfs_last; pfs++) - pfs->m_cond_stat.reset(); +static void fct_reset_file_waits(PFS_file *pfs) +{ + pfs->m_file_stat.reset(); } static void reset_file_waits_by_instance(void) { - PFS_file *pfs= file_array; - PFS_file *pfs_last= file_array + file_max; + global_file_container.apply_all(fct_reset_file_waits); +} - for ( ; pfs < pfs_last; pfs++) - pfs->m_file_stat.reset(); +static void fct_reset_socket_waits(PFS_socket *pfs) +{ + pfs->m_socket_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(); + global_socket_container.apply_all(fct_reset_socket_waits); } /** Reset the wait statistics per object instance. */ @@ -1751,24 +1470,26 @@ void reset_events_waits_by_instance(void) reset_socket_waits_by_instance(); } +static void fct_reset_file_io(PFS_file *pfs) +{ + pfs->m_file_stat.m_io_stat.reset(); +} + /** Reset the io statistics per file instance. */ void reset_file_instance_io(void) { - PFS_file *pfs= file_array; - PFS_file *pfs_last= file_array + file_max; + global_file_container.apply_all(fct_reset_file_io); +} - for ( ; pfs < pfs_last; pfs++) - pfs->m_file_stat.m_io_stat.reset(); +static void fct_reset_socket_io(PFS_socket *pfs) +{ + pfs->m_socket_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(); + global_socket_container.apply_all(fct_reset_socket_io); } void aggregate_all_event_names(PFS_single_stat *from_array, @@ -1909,6 +1630,124 @@ void aggregate_all_statements(PFS_statement_stat *from_array, } } +void aggregate_all_transactions(PFS_transaction_stat *from_array, + PFS_transaction_stat *to_array) +{ + DBUG_ASSERT(from_array != NULL); + DBUG_ASSERT(to_array != NULL); + + if (from_array->count() > 0) + { + to_array->aggregate(from_array); + from_array->reset(); + } +} + +void aggregate_all_transactions(PFS_transaction_stat *from_array, + PFS_transaction_stat *to_array_1, + PFS_transaction_stat *to_array_2) +{ + DBUG_ASSERT(from_array != NULL); + DBUG_ASSERT(to_array_1 != NULL); + DBUG_ASSERT(to_array_2 != NULL); + + if (from_array->count() > 0) + { + to_array_1->aggregate(from_array); + to_array_2->aggregate(from_array); + from_array->reset(); + } +} + +void aggregate_all_memory(bool alive, + PFS_memory_stat *from_array, + PFS_memory_stat *to_array) +{ + PFS_memory_stat *from; + PFS_memory_stat *from_last; + PFS_memory_stat *to; + + from= from_array; + from_last= from_array + memory_class_max; + to= to_array; + + if (alive) + { + for ( ; from < from_last ; from++, to++) + { + from->partial_aggregate_to(to); + } + } + else + { + for ( ; from < from_last ; from++, to++) + { + from->full_aggregate_to(to); + from->reset(); + } + } +} + +void aggregate_all_memory(bool alive, + PFS_memory_stat *from_array, + PFS_memory_stat *to_array_1, + PFS_memory_stat *to_array_2) +{ + PFS_memory_stat *from; + PFS_memory_stat *from_last; + PFS_memory_stat *to_1; + PFS_memory_stat *to_2; + + from= from_array; + from_last= from_array + memory_class_max; + to_1= to_array_1; + to_2= to_array_2; + + if (alive) + { + for ( ; from < from_last ; from++, to_1++, to_2++) + { + from->partial_aggregate_to(to_1, to_2); + } + } + else + { + for ( ; from < from_last ; from++, to_1++, to_2++) + { + from->full_aggregate_to(to_1, to_2); + from->reset(); + } + } +} + +void aggregate_thread_status(PFS_thread *thread, + PFS_account *safe_account, + PFS_user *safe_user, + PFS_host *safe_host) +{ + THD *thd= thread->m_thd; + + if (thd == NULL) + return; + + if (likely(safe_account != NULL)) + { + safe_account->aggregate_status_stats(&thd->status_var); + return; + } + + if (safe_user != NULL) + { + safe_user->aggregate_status_stats(&thd->status_var); + } + + if (safe_host != NULL) + { + safe_host->aggregate_status_stats(&thd->status_var); + } + return; +} + void aggregate_thread_stats(PFS_thread *thread, PFS_account *safe_account, PFS_user *safe_user, @@ -1917,14 +1756,17 @@ void aggregate_thread_stats(PFS_thread *thread, 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; @@ -1935,9 +1777,28 @@ void aggregate_thread(PFS_thread *thread, PFS_user *safe_user, PFS_host *safe_host) { + /* No HAVE_PSI_???_INTERFACE flag, waits cover multiple instrumentations */ aggregate_thread_waits(thread, safe_account, safe_user, safe_host); + +#ifdef HAVE_PSI_STAGE_INTERFACE aggregate_thread_stages(thread, safe_account, safe_user, safe_host); +#endif + +#ifdef HAVE_PSI_STATEMENT_INTERFACE aggregate_thread_statements(thread, safe_account, safe_user, safe_host); +#endif + +#ifdef HAVE_PSI_TRANSACTION_INTERFACE + aggregate_thread_transactions(thread, safe_account, safe_user, safe_host); +#endif + +#ifdef HAVE_PSI_MEMORY_INTERFACE + aggregate_thread_memory(false, thread, safe_account, safe_user, safe_host); +#endif + + if (!show_compatibility_56) + aggregate_thread_status(thread, safe_account, safe_user, safe_host); + aggregate_thread_stats(thread, safe_account, safe_user, safe_host); } @@ -1946,14 +1807,17 @@ void aggregate_thread_waits(PFS_thread *thread, PFS_user *safe_user, PFS_host *safe_host) { + if (thread->read_instr_class_waits_stats() == NULL) + return; + 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); + aggregate_all_event_names(thread->write_instr_class_waits_stats(), + safe_account->write_instr_class_waits_stats()); return; } @@ -1966,9 +1830,9 @@ void aggregate_thread_waits(PFS_thread *thread, - 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); + aggregate_all_event_names(thread->write_instr_class_waits_stats(), + safe_user->write_instr_class_waits_stats(), + safe_host->write_instr_class_waits_stats()); return; } @@ -1978,8 +1842,8 @@ void aggregate_thread_waits(PFS_thread *thread, 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); + aggregate_all_event_names(thread->write_instr_class_waits_stats(), + safe_user->write_instr_class_waits_stats()); return; } @@ -1989,8 +1853,8 @@ void aggregate_thread_waits(PFS_thread *thread, 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); + aggregate_all_event_names(thread->write_instr_class_waits_stats(), + safe_host->write_instr_class_waits_stats()); return; } @@ -2003,14 +1867,17 @@ void aggregate_thread_stages(PFS_thread *thread, PFS_user *safe_user, PFS_host *safe_host) { + if (thread->read_instr_class_stages_stats() == NULL) + return; + 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); + aggregate_all_stages(thread->write_instr_class_stages_stats(), + safe_account->write_instr_class_stages_stats()); return; } @@ -2023,9 +1890,9 @@ void aggregate_thread_stages(PFS_thread *thread, - 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); + aggregate_all_stages(thread->write_instr_class_stages_stats(), + safe_user->write_instr_class_stages_stats(), + safe_host->write_instr_class_stages_stats()); return; } @@ -2037,8 +1904,8 @@ void aggregate_thread_stages(PFS_thread *thread, - 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, + aggregate_all_stages(thread->write_instr_class_stages_stats(), + safe_user->write_instr_class_stages_stats(), global_instr_class_stages_array); return; } @@ -2049,8 +1916,8 @@ void aggregate_thread_stages(PFS_thread *thread, 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); + aggregate_all_stages(thread->write_instr_class_stages_stats(), + safe_host->write_instr_class_stages_stats()); return; } @@ -2058,7 +1925,7 @@ void aggregate_thread_stages(PFS_thread *thread, 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, + aggregate_all_stages(thread->write_instr_class_stages_stats(), global_instr_class_stages_array); } @@ -2067,14 +1934,17 @@ void aggregate_thread_statements(PFS_thread *thread, PFS_user *safe_user, PFS_host *safe_host) { + if (thread->read_instr_class_statements_stats() == NULL) + return; + 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); + aggregate_all_statements(thread->write_instr_class_statements_stats(), + safe_account->write_instr_class_statements_stats()); return; } @@ -2087,9 +1957,9 @@ void aggregate_thread_statements(PFS_thread *thread, - 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); + aggregate_all_statements(thread->write_instr_class_statements_stats(), + safe_user->write_instr_class_statements_stats(), + safe_host->write_instr_class_statements_stats()); return; } @@ -2101,8 +1971,8 @@ void aggregate_thread_statements(PFS_thread *thread, - 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, + aggregate_all_statements(thread->write_instr_class_statements_stats(), + safe_user->write_instr_class_statements_stats(), global_instr_class_statements_array); return; } @@ -2113,8 +1983,8 @@ void aggregate_thread_statements(PFS_thread *thread, 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); + aggregate_all_statements(thread->write_instr_class_statements_stats(), + safe_host->write_instr_class_statements_stats()); return; } @@ -2122,10 +1992,149 @@ void aggregate_thread_statements(PFS_thread *thread, 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, + aggregate_all_statements(thread->write_instr_class_statements_stats(), global_instr_class_statements_array); } +void aggregate_thread_transactions(PFS_thread *thread, + PFS_account *safe_account, + PFS_user *safe_user, + PFS_host *safe_host) +{ + if (thread->read_instr_class_transactions_stats() == NULL) + return; + + if (likely(safe_account != NULL)) + { + /* + Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + */ + aggregate_all_transactions(thread->write_instr_class_transactions_stats(), + safe_account->write_instr_class_transactions_stats()); + + return; + } + + if ((safe_user != NULL) && (safe_host != NULL)) + { + /* + Aggregate EVENTS_TRANSACTION_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - EVENTS_TRANSACTION_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_TRANSACTION_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_transactions(thread->write_instr_class_transactions_stats(), + safe_user->write_instr_class_transactions_stats(), + safe_host->write_instr_class_transactions_stats()); + return; + } + + if (safe_user != NULL) + { + /* + Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME + - EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME + in parallel. + */ + aggregate_all_transactions(thread->write_instr_class_transactions_stats(), + safe_user->write_instr_class_transactions_stats(), + &global_transaction_stat); + return; + } + + if (safe_host != NULL) + { + /* + Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME, directly. + */ + aggregate_all_transactions(thread->write_instr_class_transactions_stats(), + safe_host->write_instr_class_transactions_stats()); + return; + } + + /* + Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME + to EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME. + */ + aggregate_all_transactions(thread->write_instr_class_transactions_stats(), + &global_transaction_stat); +} + +void aggregate_thread_memory(bool alive, PFS_thread *thread, + PFS_account *safe_account, + PFS_user *safe_user, + PFS_host *safe_host) +{ + if (thread->read_instr_class_memory_stats() == NULL) + return; + + if (likely(safe_account != NULL)) + { + /* + Aggregate MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME + to MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + */ + aggregate_all_memory(alive, + thread->write_instr_class_memory_stats(), + safe_account->write_instr_class_memory_stats()); + + return; + } + + if ((safe_user != NULL) && (safe_host != NULL)) + { + /* + Aggregate MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME + - MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME + in parallel. + */ + aggregate_all_memory(alive, + thread->write_instr_class_memory_stats(), + safe_user->write_instr_class_memory_stats(), + safe_host->write_instr_class_memory_stats()); + return; + } + + if (safe_user != NULL) + { + /* + Aggregate MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME to: + - MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME + - MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME + in parallel. + */ + aggregate_all_memory(alive, + thread->write_instr_class_memory_stats(), + safe_user->write_instr_class_memory_stats(), + global_instr_class_memory_array); + return; + } + + if (safe_host != NULL) + { + /* + Aggregate MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME + to MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME, directly. + */ + aggregate_all_memory(alive, + thread->write_instr_class_memory_stats(), + safe_host->write_instr_class_memory_stats()); + return; + } + + /* + Aggregate MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME + to MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME. + */ + aggregate_all_memory(alive, + thread->write_instr_class_memory_stats(), + global_instr_class_memory_array); +} + void clear_thread_account(PFS_thread *thread) { if (thread->m_account != NULL) @@ -2170,142 +2179,151 @@ void set_thread_account(PFS_thread *thread) thread->m_hostname_length); } +static void fct_update_mutex_derived_flags(PFS_mutex *pfs) +{ + PFS_mutex_class *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_mutex_derived_flags() { - PFS_mutex *pfs= mutex_array; - PFS_mutex *pfs_last= mutex_array + mutex_max; - PFS_mutex_class *klass; + global_mutex_container.apply_all(fct_update_mutex_derived_flags); +} - for ( ; pfs < pfs_last; pfs++) +static void fct_update_rwlock_derived_flags(PFS_rwlock *pfs) +{ + PFS_rwlock_class *klass= sanitize_rwlock_class(pfs->m_class); + if (likely(klass != NULL)) { - 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; - } + 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; + global_rwlock_container.apply_all(fct_update_rwlock_derived_flags); +} - for ( ; pfs < pfs_last; pfs++) +static void fct_update_cond_derived_flags(PFS_cond *pfs) +{ + PFS_cond_class *klass= sanitize_cond_class(pfs->m_class); + if (likely(klass != NULL)) { - 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; - } + 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; + global_cond_container.apply_all(fct_update_cond_derived_flags); +} - for ( ; pfs < pfs_last; pfs++) +static void fct_update_file_derived_flags(PFS_file *pfs) +{ + PFS_file_class *klass= sanitize_file_class(pfs->m_class); + if (likely(klass != NULL)) { - 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; - } + 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; + global_file_container.apply_all(fct_update_file_derived_flags); +} - for ( ; pfs < pfs_last; pfs++) +void fct_update_table_derived_flags(PFS_table *pfs) +{ + PFS_table_share *share= sanitize_table_share(pfs->m_share); + if (likely(share != NULL)) { - 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; - } + 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_table_derived_flags() { - PFS_table *pfs= table_array; - PFS_table *pfs_last= table_array + table_max; - PFS_table_share *share; + global_table_container.apply_all(fct_update_table_derived_flags); +} - for ( ; pfs < pfs_last; pfs++) +static void fct_update_socket_derived_flags(PFS_socket *pfs) +{ + PFS_socket_class *klass= sanitize_socket_class(pfs->m_class); + if (likely(klass != NULL)) { - 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; - } + 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_socket_derived_flags() { - PFS_socket *pfs= socket_array; - PFS_socket *pfs_last= socket_array + socket_max; - PFS_socket_class *klass; + global_socket_container.apply_all(fct_update_socket_derived_flags); +} - 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; - } - } +static void fct_update_metadata_derived_flags(PFS_metadata_lock *pfs) +{ + pfs->m_enabled= global_metadata_class.m_enabled && flag_global_instrumentation; + pfs->m_timed= global_metadata_class.m_timed; +} + +void update_metadata_derived_flags() +{ + global_mdl_container.apply_all(fct_update_metadata_derived_flags); +} + +static void fct_update_thread_derived_flags(PFS_thread *pfs) +{ + pfs->set_history_derived_flags(); +} + +void update_thread_derived_flags() +{ + global_thread_container.apply(fct_update_thread_derived_flags); } void update_instruments_derived_flags() @@ -2316,7 +2334,8 @@ void update_instruments_derived_flags() update_file_derived_flags(); update_table_derived_flags(); update_socket_derived_flags(); - /* nothing for stages and statements (no instances) */ + update_metadata_derived_flags(); + /* nothing for stages, statements and transactions (no instances) */ } /** @} */ diff --git a/storage/perfschema/pfs_instr.h b/storage/perfschema/pfs_instr.h index 81bc52d1d75..c15d30b50e9 100644 --- a/storage/perfschema/pfs_instr.h +++ b/storage/perfschema/pfs_instr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2015, 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, version 2.0, @@ -35,11 +35,15 @@ struct PFS_file_class; struct PFS_table_share; struct PFS_thread_class; struct PFS_socket_class; +class PFS_opaque_container_page; + +class THD; #include "my_global.h" -#ifdef __WIN__ +#ifdef _WIN32 #include <winsock2.h> -#else +#endif +#ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif #include "my_compiler.h" @@ -49,9 +53,17 @@ struct PFS_socket_class; #include "pfs_events_waits.h" #include "pfs_events_stages.h" #include "pfs_events_statements.h" +#include "pfs_events_transactions.h" #include "pfs_server.h" #include "lf.h" #include "pfs_con_slice.h" +#include "pfs_column_types.h" +#include "mdl.h" +#include "violite.h" /* enum_vio_type */ + +extern PFS_single_stat *thread_instr_class_waits_array_start; +extern PFS_single_stat *thread_instr_class_waits_array_end; +extern my_bool show_compatibility_56; /** @addtogroup Performance_schema_buffers @@ -72,6 +84,8 @@ struct PFS_instr bool m_enabled; /** Timed flag. */ bool m_timed; + /** Container page. */ + PFS_opaque_container_page *m_page; }; /** Instrumented mutex implementation. @see PSI_mutex. */ @@ -124,8 +138,6 @@ struct PFS_ALIGNED PFS_cond : public PFS_instr const void *m_identity; /** Condition class. */ PFS_cond_class *m_class; - /** Instrument wait statistics. */ - PFS_single_stat m_wait_stat; /** Condition instance usage statistics. */ PFS_cond_stat m_cond_stat; }; @@ -146,6 +158,8 @@ struct PFS_ALIGNED PFS_file : public PFS_instr PFS_file_class *m_class; /** File usage statistics. */ PFS_file_stat m_file_stat; + /** True if a temporary file. */ + bool m_temporary; }; /** Instrumented table implementation. @see PSI_table. */ @@ -184,20 +198,14 @@ public: Only use this method for handles owned by the calling code. @sa sanitized_aggregate. */ - void aggregate(void) + void aggregate(const TABLE_SHARE *server_share) { - 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) + if (m_has_io_stats) { - safe_aggregate_io(& m_table_stat, m_share); + safe_aggregate_io(server_share, & m_table_stat, m_share); m_has_io_stats= false; } - else if (m_has_lock_stats) + if (m_has_lock_stats) { safe_aggregate_lock(& m_table_stat, m_share); m_has_lock_stats= false; @@ -227,19 +235,26 @@ public: /** Internal lock. */ pfs_lock m_lock; - /** Owner. */ + /** Thread Owner. */ PFS_thread *m_thread_owner; + /** Event Owner. */ + ulonglong m_owner_event_id; /** Table share. */ PFS_table_share *m_share; /** Table identity, typically a handler. */ const void *m_identity; /** Table statistics. */ PFS_table_stat m_table_stat; + /** Current internal lock. */ + PFS_TL_LOCK_TYPE m_internal_lock; + /** Current external lock. */ + PFS_TL_LOCK_TYPE m_external_lock; + /** Container page. */ + PFS_opaque_container_page *m_page; private: - static void safe_aggregate(PFS_table_stat *stat, - PFS_table_share *safe_share); - static void safe_aggregate_io(PFS_table_stat *stat, + static void safe_aggregate_io(const TABLE_SHARE *optional_server_share, + PFS_table_stat *stat, PFS_table_share *safe_share); static void safe_aggregate_lock(PFS_table_stat *stat, PFS_table_share *safe_share); @@ -269,6 +284,24 @@ struct PFS_ALIGNED PFS_socket : public PFS_instr PFS_socket_stat m_socket_stat; }; +/** Instrumented metadata lock implementation. @see PSI_metadata_lock. */ +struct PFS_ALIGNED PFS_metadata_lock : public PFS_instr +{ + uint32 get_version() + { return m_lock.get_version(); } + + /** Lock identity. */ + const void *m_identity; + MDL_key m_mdl_key; + opaque_mdl_type m_mdl_type; + opaque_mdl_duration m_mdl_duration; + opaque_mdl_status m_mdl_status; + const char *m_src_file; + uint m_src_line; + ulonglong m_owner_thread_id; + ulonglong m_owner_event_id; +}; + /** @def WAIT_STACK_LOGICAL_SIZE Maximum number of nested waits. @@ -293,7 +326,7 @@ struct PFS_ALIGNED PFS_socket : public PFS_instr /** @def WAIT_STACK_BOTTOM Maximum number dummy waits records. - One dummy record is reserved for the parent stage / statement, + One dummy record is reserved for the parent stage / statement / transaction, at the bottom of the wait stack. */ #define WAIT_STACK_BOTTOM 1 @@ -307,75 +340,84 @@ struct PFS_ALIGNED PFS_socket : public PFS_instr extern uint statement_stack_max; /** Max size of the digests token array. */ extern size_t pfs_max_digest_length; +/** Max size of SQL TEXT. */ +extern size_t pfs_max_sqltext; -/** - @def PFS_MAX_ALLOC_RETRY - Maximum number of times the code attempts to allocate an item - from internal buffers, before giving up. -*/ -#define PFS_MAX_ALLOC_RETRY 1000 +/** Instrumented thread implementation. @see PSI_thread. */ +struct PFS_ALIGNED PFS_thread : PFS_connection_slice +{ + static PFS_thread* get_current_thread(void); -/** The maximun number of passes in @sa PFS_scan. */ -#define PFS_MAX_SCAN_PASS 2 + /** Thread instrumentation flag. */ + bool m_enabled; + /** Thread history instrumentation flag. */ + bool m_history; -/** - Helper to scan circular buffers. - Given a buffer of size [0, max_size - 1], - and a random starting point in the buffer, - this helper returns up to two [first, last -1] intervals that: - - fit into the [0, max_size - 1] range, - - have a maximum combined length of at most PFS_MAX_ALLOC_RETRY. -*/ -struct PFS_scan -{ -public: /** - Initialize a new scan. - @param random a random index to start from - @param max_size the max size of the interval to scan + Derived flag flag_events_waits_history, per thread. + Cached computation of + TABLE SETUP_CONSUMERS[EVENTS_WAITS_HISTORY].ENABLED == 'YES' + AND + TABLE THREADS[THREAD_ID].HISTORY == 'YES' */ - void init(uint random, uint max_size); - + bool m_flag_events_waits_history; /** - Predicate, has a next pass. - @return true if there is a next pass to perform. + Derived flag flag_events_waits_history_long, per thread. + Cached computation of + TABLE SETUP_CONSUMERS[EVENTS_WAITS_HISTORY_LONG].ENABLED == 'YES' + AND + TABLE THREADS[THREAD_ID].HISTORY == 'YES' */ - bool has_pass() const - { return (m_pass < m_pass_max); } - + bool m_flag_events_waits_history_long; /** - Iterator, proceed to the next pass. + Derived flag flag_events_stages_history, per thread. + Cached computation of + TABLE SETUP_CONSUMERS[EVENTS_STAGES_HISTORY].ENABLED == 'YES' + AND + TABLE THREADS[THREAD_ID].HISTORY == 'YES' */ - void next_pass() - { m_pass++; } - - /** First index for this pass. */ - uint first() const - { return m_first[m_pass]; } - - /** Last index for this pass. */ - uint last() const - { return m_last[m_pass]; } - -private: - /** Current pass. */ - uint m_pass; - /** Maximum number of passes. */ - uint m_pass_max; - /** First element for each pass. */ - uint m_first[PFS_MAX_SCAN_PASS]; - /** Last element for each pass. */ - uint m_last[PFS_MAX_SCAN_PASS]; -}; - - -/** Instrumented thread implementation. @see PSI_thread. */ -struct PFS_ALIGNED PFS_thread : PFS_connection_slice -{ - static PFS_thread* get_current_thread(void); + bool m_flag_events_stages_history; + /** + Derived flag flag_events_stages_history_long, per thread. + Cached computation of + TABLE SETUP_CONSUMERS[EVENTS_STAGES_HISTORY_LONG].ENABLED == 'YES' + AND + TABLE THREADS[THREAD_ID].HISTORY == 'YES' + */ + bool m_flag_events_stages_history_long; + /** + Derived flag flag_events_statements_history, per thread. + Cached computation of + TABLE SETUP_CONSUMERS[EVENTS_STATEMENTS_HISTORY].ENABLED == 'YES' + AND + TABLE THREADS[THREAD_ID].HISTORY == 'YES' + */ + bool m_flag_events_statements_history; + /** + Derived flag flag_events_statements_history_long, per thread. + Cached computation of + TABLE SETUP_CONSUMERS[EVENTS_STATEMENTS_HISTORY_LONG].ENABLED == 'YES' + AND + TABLE THREADS[THREAD_ID].HISTORY == 'YES' + */ + bool m_flag_events_statements_history_long; + /** + Derived flag flag_events_transactions_history, per thread. + Cached computation of + TABLE SETUP_CONSUMERS[EVENTS_TRANSACTIONS_HISTORY].ENABLED == 'YES' + AND + TABLE THREADS[THREAD_ID].HISTORY == 'YES' + */ + bool m_flag_events_transactions_history; + /** + Derived flag flag_events_transactions_history_long, per thread. + Cached computation of + TABLE SETUP_CONSUMERS[EVENTS_TRANSACTIONS_HISTORY_LONG].ENABLED == 'YES' + AND + TABLE THREADS[THREAD_ID].HISTORY == 'YES' + */ + bool m_flag_events_transactions_history_long; - /** Thread instrumentation flag. */ - bool m_enabled; /** Current wait event in the event stack. */ PFS_events_waits *m_events_waits_current; /** Event ID counter */ @@ -404,18 +446,22 @@ struct PFS_ALIGNED PFS_thread : PFS_connection_slice LF_PINS *m_account_hash_pins; /** Pins for digest_hash. */ LF_PINS *m_digest_hash_pins; + /** Pins for routine_hash. */ + LF_PINS *m_program_hash_pins; /** Internal thread identifier, unique. */ ulonglong m_thread_internal_id; /** Parent internal thread identifier. */ ulonglong m_parent_thread_internal_id; /** External (SHOW PROCESSLIST) thread identifier, not unique. */ ulong m_processlist_id; + /** External (Operating system) thread identifier, if any. */ + uint32 m_thread_os_id; /** Thread class. */ PFS_thread_class *m_class; /** Stack of events waits. This member holds the data for the table PERFORMANCE_SCHEMA.EVENTS_WAITS_CURRENT. - Note that stack[0] is a dummy record that represents the parent stage/statement. + Note that stack[0] is a dummy record that represents the parent stage/statement/transaction. For example, assuming the following tree: - STAGE ID 100 - WAIT ID 101, parent STAGE 100 @@ -475,12 +521,24 @@ struct PFS_ALIGNED PFS_thread : PFS_connection_slice */ PFS_events_statements *m_statements_history; + /** True if the circular buffer @c m_transactions_history is full. */ + bool m_transactions_history_full; + /** Current index in the circular buffer @c m_transactions_history. */ + uint m_transactions_history_index; + /** + Statements history circular buffer. + This member holds the data for the table + PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_HISTORY. + */ + PFS_events_transactions *m_transactions_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. @@ -513,6 +571,8 @@ struct PFS_ALIGNED PFS_thread : PFS_connection_slice uint m_dbname_length; /** Current command. */ int m_command; + /** Connection type. */ + enum_vio_type m_connection_type; /** Start time. */ time_t m_start_time; /** @@ -523,6 +583,8 @@ struct PFS_ALIGNED PFS_thread : PFS_connection_slice pfs_lock m_stmt_lock; /** Processlist state (derived from stage). */ PFS_stage_key m_stage; + /** Current stage progress. */ + PSI_stage_progress* m_stage_progress; /** Processlist info. Protected by @c m_stmt_lock. @@ -540,6 +602,9 @@ struct PFS_ALIGNED PFS_thread : PFS_connection_slice uint m_events_statements_count; PFS_events_statements *m_statement_stack; + PFS_events_transactions m_transaction_current; + + THD *m_thd; PFS_host *m_host; PFS_user *m_user; PFS_account *m_account; @@ -562,10 +627,28 @@ struct PFS_ALIGNED PFS_thread : PFS_connection_slice Protected by @c m_session_lock. */ uint m_session_connect_attrs_cs_number; + + void carry_memory_stat_delta(PFS_memory_stat_delta *delta, uint index); + + void set_enabled(bool enabled) + { + m_enabled= enabled; + } + + void set_history(bool history) + { + m_history= history; + set_history_derived_flags(); + } + + void set_history_derived_flags(); }; +void carry_global_memory_stat_delta(PFS_memory_stat_delta *delta, uint index); + extern PFS_stage_stat *global_instr_class_stages_array; extern PFS_statement_stat *global_instr_class_statements_array; +extern PFS_memory_stat *global_instr_class_memory_array; PFS_mutex *sanitize_mutex(PFS_mutex *unsafe); PFS_rwlock *sanitize_rwlock(PFS_rwlock *unsafe); @@ -573,10 +656,11 @@ 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); +PFS_metadata_lock *sanitize_metadata_lock(PFS_metadata_lock *unsafe); int init_instruments(const PFS_global_param *param); void cleanup_instruments(); -int init_file_hash(); +int init_file_hash(const PFS_global_param *param); void cleanup_file_hash(); PFS_mutex* create_mutex(PFS_mutex_class *mutex_class, const void *identity); void destroy_mutex(PFS_mutex *pfs); @@ -592,6 +676,9 @@ void destroy_thread(PFS_thread *pfs); PFS_file* find_or_create_file(PFS_thread *thread, PFS_file_class *klass, const char *filename, uint len, bool create); +void find_and_rename_file(PFS_thread *thread, const char *old_filename, + uint old_len, const char *new_filename, + uint new_len); void release_file(PFS_file *pfs); void destroy_file(PFS_thread *thread, PFS_file *pfs); @@ -605,27 +692,23 @@ PFS_socket* create_socket(PFS_socket_class *socket_class, socklen_t addr_len); void destroy_socket(PFS_socket *pfs); +PFS_metadata_lock* create_metadata_lock(void *identity, + const MDL_key *mdl_key, + opaque_mdl_type mdl_type, + opaque_mdl_duration mdl_duration, + opaque_mdl_status mdl_status, + const char *src_file, + uint src_line); +void destroy_metadata_lock(PFS_metadata_lock *pfs); + /* For iterators and show status. */ -extern ulong mutex_max; -extern ulong mutex_lost; -extern ulong rwlock_max; -extern ulong rwlock_lost; -extern ulong cond_max; -extern ulong cond_lost; -extern ulong thread_max; -extern ulong thread_lost; -extern ulong file_max; -extern ulong file_lost; extern long file_handle_max; extern ulong file_handle_lost; -extern ulong table_max; -extern ulong table_lost; -extern ulong socket_max; -extern ulong socket_lost; extern ulong events_waits_history_per_thread; extern ulong events_stages_history_per_thread; extern ulong events_statements_history_per_thread; +extern ulong events_transactions_history_per_thread; extern ulong locker_lost; extern ulong statement_lost; extern ulong session_connect_attrs_lost; @@ -633,14 +716,7 @@ extern ulong session_connect_attrs_size_per_thread; /* Exposing the data directly, for iterators. */ -extern PFS_mutex *mutex_array; -extern PFS_rwlock *rwlock_array; -extern PFS_cond *cond_array; -extern PFS_thread *thread_array; -extern PFS_file *file_array; extern PFS_file **file_handle_array; -extern PFS_table *table_array; -extern PFS_socket *socket_array; void reset_events_waits_by_instance(); void reset_file_instance_io(); @@ -664,6 +740,20 @@ void aggregate_all_statements(PFS_statement_stat *from_array, PFS_statement_stat *to_array_1, PFS_statement_stat *to_array_2); +void aggregate_all_transactions(PFS_transaction_stat *from_array, + PFS_transaction_stat *to_array); +void aggregate_all_transactions(PFS_transaction_stat *from_array, + PFS_transaction_stat *to_array_1, + PFS_transaction_stat *to_array_2); + +void aggregate_all_memory(bool alive, + PFS_memory_stat *from_array, + PFS_memory_stat *to_array); +void aggregate_all_memory(bool alive, + PFS_memory_stat *from_array, + PFS_memory_stat *to_array_1, + PFS_memory_stat *to_array_2); + void aggregate_thread(PFS_thread *thread, PFS_account *safe_account, PFS_user *safe_user, @@ -680,6 +770,21 @@ void aggregate_thread_statements(PFS_thread *thread, PFS_account *safe_account, PFS_user *safe_user, PFS_host *safe_host); +void aggregate_thread_transactions(PFS_thread *thread, + PFS_account *safe_account, + PFS_user *safe_user, + PFS_host *safe_host); + +void aggregate_thread_memory(bool alive, PFS_thread *thread, + PFS_account *safe_account, + PFS_user *safe_user, + PFS_host *safe_host); + +void aggregate_thread_status(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); @@ -695,6 +800,10 @@ void update_file_derived_flags(); void update_table_derived_flags(); /** Update derived flags for all socket instances. */ void update_socket_derived_flags(); +/** Update derived flags for all metadata instances. */ +void update_metadata_derived_flags(); +/** Update derived flags for all thread instances. */ +void update_thread_derived_flags(); /** Update derived flags for all instruments. */ void update_instruments_derived_flags(); diff --git a/storage/perfschema/pfs_instr_class.cc b/storage/perfschema/pfs_instr_class.cc index 2757369cad3..1a6a8b86f03 100644 --- a/storage/perfschema/pfs_instr_class.cc +++ b/storage/perfschema/pfs_instr_class.cc @@ -28,15 +28,17 @@ #include "my_global.h" #include "my_sys.h" -#include "structs.h" #include "table.h" #include "pfs_instr_class.h" +#include "pfs_builtin_memory.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 "pfs_program.h" +#include "pfs_buffer_container.h" #include "mysql/psi/mysql_thread.h" #include "lf.h" @@ -49,11 +51,16 @@ */ /** - PFS_INSTRUMENT option settings array and associated state variable to - serialize access during shutdown. + Global performance schema flag. + Indicate if the performance schema is enabled. + This flag is set at startup, and never changes. +*/ +my_bool pfs_enabled= TRUE; + +/** + PFS_INSTRUMENT option settings array */ -DYNAMIC_ARRAY pfs_instr_config_array; -int pfs_instr_config_state= PFS_INSTR_CONFIG_NOT_INITIALIZED; +Pfs_instr_config_array *pfs_instr_config_array= NULL; static void configure_instr_class(PFS_instr_class *entry); @@ -69,12 +76,12 @@ static void init_instr_class(PFS_instr_class *klass, - the performance schema initialization - a plugin initialization */ -static volatile uint32 mutex_class_dirty_count= 0; -static volatile uint32 mutex_class_allocated_count= 0; -static volatile uint32 rwlock_class_dirty_count= 0; -static volatile uint32 rwlock_class_allocated_count= 0; -static volatile uint32 cond_class_dirty_count= 0; -static volatile uint32 cond_class_allocated_count= 0; +static uint32 mutex_class_dirty_count= 0; +static uint32 mutex_class_allocated_count= 0; +static uint32 rwlock_class_dirty_count= 0; +static uint32 rwlock_class_allocated_count= 0; +static uint32 cond_class_dirty_count= 0; +static uint32 cond_class_allocated_count= 0; /** Size of the mutex class array. @sa mutex_class_array */ ulong mutex_class_max= 0; @@ -104,14 +111,21 @@ ulong stage_class_lost= 0; 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; +/** Size of the memory class array. @sa memory_class_array */ +ulong memory_class_max= 0; +/** Number of memory class lost. @sa memory_class_array */ +ulong memory_class_lost= 0; + +/** + Number of transaction classes. Although there is only one transaction class, + this is used for sizing by other event classes. + @sa global_transaction_class +*/ +ulong transaction_class_max= 0; PFS_mutex_class *mutex_class_array= NULL; PFS_rwlock_class *rwlock_class_array= NULL; @@ -123,47 +137,45 @@ PFS_cond_class *cond_class_array= NULL; - the performance schema initialization - a plugin initialization */ -static volatile uint32 thread_class_dirty_count= 0; -static volatile uint32 thread_class_allocated_count= 0; +static uint32 thread_class_dirty_count= 0; +static uint32 thread_class_allocated_count= 0; static PFS_thread_class *thread_class_array= NULL; -/** - Table instance array. - @sa table_share_max - @sa table_share_lost - @sa table_share_hash -*/ -PFS_table_share *table_share_array= NULL; - PFS_ALIGNED PFS_single_stat global_idle_stat; PFS_ALIGNED PFS_table_io_stat global_table_io_stat; PFS_ALIGNED PFS_table_lock_stat global_table_lock_stat; +PFS_ALIGNED PFS_single_stat global_metadata_stat; +PFS_ALIGNED PFS_transaction_stat global_transaction_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; +PFS_ALIGNED PFS_instr_class global_metadata_class; +PFS_ALIGNED PFS_transaction_class global_transaction_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 */ +{&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 */ + &transaction_timer, /* PFS_CLASS_TRANSACTION */ + &wait_timer, /* PFS_CLASS_SOCKET */ + &wait_timer, /* PFS_CLASS_TABLE_IO */ + &wait_timer, /* PFS_CLASS_TABLE_LOCK */ + &idle_timer, /* PFS_CLASS_IDLE */ + &wait_timer, /* PFS_CLASS_METADATA */ + &wait_timer /* PFS_CLASS_MEMORY */ }; /** 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 @@ -173,26 +185,31 @@ LF_HASH table_share_hash; /** True if table_share_hash is initialized. */ static bool table_share_hash_inited= false; -static volatile uint32 file_class_dirty_count= 0; -static volatile uint32 file_class_allocated_count= 0; +static uint32 file_class_dirty_count= 0; +static uint32 file_class_allocated_count= 0; PFS_file_class *file_class_array= NULL; -static volatile uint32 stage_class_dirty_count= 0; -static volatile uint32 stage_class_allocated_count= 0; +static uint32 stage_class_dirty_count= 0; +static 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 uint32 statement_class_dirty_count= 0; +static 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 uint32 socket_class_dirty_count= 0; +static uint32 socket_class_allocated_count= 0; static PFS_socket_class *socket_class_array= NULL; +static uint32 memory_class_dirty_count= 0; +static uint32 memory_class_allocated_count= 0; + +static PFS_memory_class *memory_class_array= NULL; + uint mutex_class_start= 0; uint rwlock_class_start= 0; uint cond_class_start= 0; @@ -202,7 +219,8 @@ 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 */ + /* global table io, table lock, idle, metadata */ + mutex_class_start= COUNT_GLOBAL_EVENT_INDEX; 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; @@ -223,12 +241,29 @@ void register_global_classes() 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); + + /* Metadata class */ + init_instr_class(&global_metadata_class, "wait/lock/metadata/sql/mdl", 26, + 0, PFS_CLASS_METADATA); + global_metadata_class.m_event_name_index= GLOBAL_METADATA_EVENT_INDEX; + global_metadata_class.m_enabled= false; /* Disabled by default */ + global_metadata_class.m_timed= false; + configure_instr_class(&global_metadata_class); + + /* Transaction class */ + init_instr_class(&global_transaction_class, "transaction", 11, + 0, PFS_CLASS_TRANSACTION); + global_transaction_class.m_event_name_index= GLOBAL_TRANSACTION_INDEX; + global_transaction_class.m_enabled= false; /* Disabled by default */ + global_transaction_class.m_timed= false; + configure_instr_class(&global_transaction_class); + transaction_class_max= 1; /* used for sizing by other event classes */ } /** @@ -256,24 +291,30 @@ int init_sync_class(uint mutex_class_sizing, if (mutex_class_max > 0) { - mutex_class_array= PFS_MALLOC_ARRAY(mutex_class_max, sizeof(PFS_mutex_class), - PFS_mutex_class, MYF(MY_ZEROFILL)); + mutex_class_array= PFS_MALLOC_ARRAY(& builtin_memory_mutex_class, + 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, sizeof(PFS_rwlock_class), - PFS_rwlock_class, MYF(MY_ZEROFILL)); + rwlock_class_array= PFS_MALLOC_ARRAY(& builtin_memory_rwlock_class, + 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, sizeof(PFS_cond_class), - PFS_cond_class, MYF(MY_ZEROFILL)); + cond_class_array= PFS_MALLOC_ARRAY(& builtin_memory_cond_class, + cond_class_max, + sizeof(PFS_cond_class), PFS_cond_class, + MYF(MY_ZEROFILL)); if (unlikely(cond_class_array == NULL)) return 1; } @@ -284,13 +325,21 @@ int init_sync_class(uint mutex_class_sizing, /** Cleanup the instrument synch class buffers. */ void cleanup_sync_class(void) { - pfs_free(mutex_class_array); + PFS_FREE_ARRAY(& builtin_memory_mutex_class, + mutex_class_max, sizeof(PFS_mutex_class), + mutex_class_array); mutex_class_array= NULL; mutex_class_dirty_count= mutex_class_allocated_count= mutex_class_max= 0; - pfs_free(rwlock_class_array); + + PFS_FREE_ARRAY(& builtin_memory_rwlock_class, + rwlock_class_max, sizeof(PFS_rwlock_class), + rwlock_class_array); rwlock_class_array= NULL; rwlock_class_dirty_count= rwlock_class_allocated_count= rwlock_class_max= 0; - pfs_free(cond_class_array); + + PFS_FREE_ARRAY(& builtin_memory_cond_class, + cond_class_max, sizeof(PFS_cond_class), + cond_class_array); cond_class_array= NULL; cond_class_dirty_count= cond_class_allocated_count= cond_class_max= 0; } @@ -309,8 +358,10 @@ int init_thread_class(uint thread_class_sizing) if (thread_class_max > 0) { - thread_class_array= PFS_MALLOC_ARRAY(thread_class_max, sizeof(PFS_thread_class), - PFS_thread_class, MYF(MY_ZEROFILL)); + thread_class_array= PFS_MALLOC_ARRAY(& builtin_memory_thread_class, + thread_class_max, + sizeof(PFS_thread_class), PFS_thread_class, + MYF(MY_ZEROFILL)); if (unlikely(thread_class_array == NULL)) result= 1; } @@ -323,7 +374,9 @@ int init_thread_class(uint thread_class_sizing) /** Cleanup the thread class buffers. */ void cleanup_thread_class(void) { - pfs_free(thread_class_array); + PFS_FREE_ARRAY(& builtin_memory_thread_class, + thread_class_max, sizeof(PFS_thread_class), + thread_class_array); thread_class_array= NULL; thread_class_dirty_count= thread_class_allocated_count= 0; thread_class_max= 0; @@ -336,29 +389,16 @@ void cleanup_thread_class(void) */ int init_table_share(uint table_share_sizing) { - int result= 0; - table_share_max= table_share_sizing; - table_share_lost= 0; - - if (table_share_max > 0) - { - table_share_array= PFS_MALLOC_ARRAY(table_share_max, sizeof(PFS_table_share), - PFS_table_share, MYF(MY_ZEROFILL)); - if (unlikely(table_share_array == NULL)) - result= 1; - } - else - table_share_array= NULL; + if (global_table_share_container.init(table_share_sizing)) + return 1; - return result; + return 0; } /** Cleanup the table share buffers. */ void cleanup_table_share(void) { - pfs_free(table_share_array); - table_share_array= NULL; - table_share_max= 0; + global_table_share_container.cleanup(); } C_MODE_START @@ -380,13 +420,12 @@ static uchar *table_share_hash_get_key(const uchar *entry, size_t *length, C_MODE_END /** Initialize the table share hash table. */ -int init_table_share_hash(void) +int init_table_share_hash(const PFS_global_param *param) { - if ((! table_share_hash_inited) && (table_share_max > 0)) + if ((! table_share_hash_inited) && (param->m_table_share_sizing != 0)) { lf_hash_init(&table_share_hash, sizeof(PFS_table_share*), LF_HASH_UNIQUE, 0, 0, table_share_hash_get_key, &my_charset_bin); - /* table_share_hash.size= table_share_max; */ table_share_hash_inited= true; } return 0; @@ -429,8 +468,8 @@ LF_PINS* get_table_share_hash_pins(PFS_thread *thread) */ 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) + const char *schema_name, size_t schema_name_length, + const char *table_name, size_t table_name_length) { DBUG_ASSERT(schema_name_length <= NAME_LEN); DBUG_ASSERT(table_name_length <= NAME_LEN); @@ -459,13 +498,315 @@ static void set_table_share_key(PFS_table_share_key *key, } } +/** + Find an existing table share lock instrumentation. + @return a table share lock. +*/ +PFS_table_share_lock* +PFS_table_share::find_lock_stat() const +{ + PFS_table_share *that= const_cast<PFS_table_share*>(this); + void *addr= & that->m_race_lock_stat; + void * volatile * typed_addr= static_cast<void * volatile *>(addr); + void *ptr; + + /* Atomic Load */ + ptr= my_atomic_loadptr(typed_addr); + + PFS_table_share_lock *pfs; + pfs= static_cast<PFS_table_share_lock *>(ptr); + return pfs; +} + +/** + Find or create a table share lock instrumentation. + @return a table share lock, or NULL. +*/ +PFS_table_share_lock* +PFS_table_share::find_or_create_lock_stat() +{ + void *addr= & this->m_race_lock_stat; + void * volatile * typed_addr= static_cast<void * volatile *>(addr); + void *ptr; + + /* (1) Atomic Load */ + ptr= my_atomic_loadptr(typed_addr); + + PFS_table_share_lock *pfs; + if (ptr != NULL) + { + pfs= static_cast<PFS_table_share_lock *>(ptr); + return pfs; + } + + /* (2) Create a lock stat */ + pfs= create_table_share_lock_stat(); + if (pfs == NULL) + return NULL; + pfs->m_owner= this; + + void *old_ptr= NULL; + ptr= pfs; + + /* (3) Atomic CAS */ + if (my_atomic_casptr(typed_addr, & old_ptr, ptr)) + { + /* Ok. */ + return pfs; + } + + /* Collision with another thread that also executed (2) and (3). */ + release_table_share_lock_stat(pfs); + + pfs= static_cast<PFS_table_share_lock *>(old_ptr); + return pfs; +} + +/** Destroy a table share lock instrumentation. */ +void PFS_table_share::destroy_lock_stat() +{ + void *addr= & this->m_race_lock_stat; + void * volatile * typed_addr= static_cast<void * volatile *>(addr); + void *new_ptr= NULL; + void *old_ptr; + + old_ptr= my_atomic_fasptr(typed_addr, new_ptr); + if (old_ptr != NULL) + { + PFS_table_share_lock *pfs; + pfs= static_cast<PFS_table_share_lock *>(old_ptr); + release_table_share_lock_stat(pfs); + } +} + +/** + Find an existing table share index instrumentation. + @return a table share index +*/ +PFS_table_share_index* +PFS_table_share::find_index_stat(uint index) const +{ + DBUG_ASSERT(index <= MAX_INDEXES); + + PFS_table_share *that= const_cast<PFS_table_share*>(this); + void *addr= & that->m_race_index_stat[index]; + void * volatile * typed_addr= static_cast<void * volatile *>(addr); + void *ptr; + + /* Atomic Load */ + ptr= my_atomic_loadptr(typed_addr); + + PFS_table_share_index *pfs; + pfs= static_cast<PFS_table_share_index *>(ptr); + return pfs; +} + +/** + Find or create a table share index instrumentation. + @param server_share + @index index + @return a table share index, or NULL +*/ +PFS_table_share_index* +PFS_table_share::find_or_create_index_stat(const TABLE_SHARE *server_share, uint index) +{ + DBUG_ASSERT(index <= MAX_INDEXES); + + void *addr= & this->m_race_index_stat[index]; + void * volatile * typed_addr= static_cast<void * volatile *>(addr); + void *ptr; + + /* (1) Atomic Load */ + ptr= my_atomic_loadptr(typed_addr); + + PFS_table_share_index *pfs; + if (ptr != NULL) + { + pfs= static_cast<PFS_table_share_index *>(ptr); + return pfs; + } + + /* (2) Create an index stat */ + pfs= create_table_share_index_stat(server_share, index); + if (pfs == NULL) + return NULL; + pfs->m_owner= this; + + void *old_ptr= NULL; + ptr= pfs; + + /* (3) Atomic CAS */ + if (my_atomic_casptr(typed_addr, & old_ptr, ptr)) + { + /* Ok. */ + return pfs; + } + + /* Collision with another thread that also executed (2) and (3). */ + release_table_share_index_stat(pfs); + + pfs= static_cast<PFS_table_share_index *>(old_ptr); + return pfs; +} + +/** Destroy table share index instrumentation. */ +void PFS_table_share::destroy_index_stats() +{ + uint index; + + for (index= 0; index <= MAX_INDEXES; index++) + { + void *addr= & this->m_race_index_stat[index]; + void * volatile * typed_addr= static_cast<void * volatile *>(addr); + void *new_ptr= NULL; + void *old_ptr; + + old_ptr= my_atomic_fasptr(typed_addr, new_ptr); + if (old_ptr != NULL) + { + PFS_table_share_index *pfs; + pfs= static_cast<PFS_table_share_index *>(old_ptr); + release_table_share_index_stat(pfs); + } + } +} + void PFS_table_share::refresh_setup_object_flags(PFS_thread *thread) { + bool old_enabled= m_enabled; + 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); + + /* + If instrumentation for this table was enabled earlier and is disabled now, + cleanup slots reserved for lock stats and index stats. + */ + if (old_enabled && ! m_enabled) + { + destroy_lock_stat(); + destroy_index_stats(); + } +} + +/** + Initialize the table lock stat buffer. + @param table_stat_sizing max number of table lock statistics + @return 0 on success +*/ +int init_table_share_lock_stat(uint table_stat_sizing) +{ + if (global_table_share_lock_container.init(table_stat_sizing)) + return 1; + + return 0; +} + +/** + Create a table share lock instrumentation. + @return table share lock instrumentation, or NULL +*/ +PFS_table_share_lock* +create_table_share_lock_stat() +{ + PFS_table_share_lock *pfs= NULL; + pfs_dirty_state dirty_state; + + /* Create a new record in table stat array. */ + pfs= global_table_share_lock_container.allocate(& dirty_state); + if (pfs != NULL) + { + /* Reset the stats. */ + pfs->m_stat.reset(); + + /* Use this stat buffer. */ + pfs->m_lock.dirty_to_allocated(& dirty_state); + } + + return pfs; +} + +/** Release a table share lock instrumentation. */ +void release_table_share_lock_stat(PFS_table_share_lock *pfs) +{ + pfs->m_owner= NULL; + global_table_share_lock_container.deallocate(pfs); + return; +} + +/** Cleanup the table stat buffers. */ +void cleanup_table_share_lock_stat(void) +{ + global_table_share_lock_container.cleanup(); +} + +/** + Initialize table index stat buffer. + @param index_stat_sizing max number of index statistics + @return 0 on success +*/ +int init_table_share_index_stat(uint index_stat_sizing) +{ + if (global_table_share_index_container.init(index_stat_sizing)) + return 1; + + return 0; +} + +/** + Create a table share index instrumentation. + @return table share index instrumentation, or NULL +*/ +PFS_table_share_index* +create_table_share_index_stat(const TABLE_SHARE *server_share, uint server_index) +{ + DBUG_ASSERT((server_share != NULL) || (server_index == MAX_INDEXES)); + + PFS_table_share_index *pfs= NULL; + pfs_dirty_state dirty_state; + + /* Create a new record in index stat array. */ + pfs= global_table_share_index_container.allocate(& dirty_state); + if (pfs != NULL) + { + if (server_index == MAX_INDEXES) + { + pfs->m_key.m_name_length= 0; + } + else + { + KEY *key_info= server_share->key_info + server_index; + size_t len= strlen(key_info->name); + + memcpy(pfs->m_key.m_name, key_info->name, len); + pfs->m_key.m_name_length= len; + } + + /* Reset the stats. */ + pfs->m_stat.reset(); + + /* Use this stat buffer. */ + pfs->m_lock.dirty_to_allocated(& dirty_state); + } + + return pfs; +} + +/** Release a table share index instrumentation. */ +void release_table_share_index_stat(PFS_table_share_index *pfs) +{ + pfs->m_owner= NULL; + global_table_share_index_container.deallocate(pfs); + return; +} + +/** Cleanup the table stat buffers. */ +void cleanup_table_share_index_stat(void) +{ + global_table_share_index_container.cleanup(); } /** @@ -482,8 +823,10 @@ int init_file_class(uint file_class_sizing) if (file_class_max > 0) { - file_class_array= PFS_MALLOC_ARRAY(file_class_max, sizeof(PFS_file_class), - PFS_file_class, MYF(MY_ZEROFILL)); + file_class_array= PFS_MALLOC_ARRAY(& builtin_memory_file_class, + file_class_max, + sizeof(PFS_file_class), PFS_file_class, + MYF(MY_ZEROFILL)); if (unlikely(file_class_array == NULL)) return 1; } @@ -496,7 +839,9 @@ int init_file_class(uint file_class_sizing) /** Cleanup the file class buffers. */ void cleanup_file_class(void) { - pfs_free(file_class_array); + PFS_FREE_ARRAY(& builtin_memory_file_class, + file_class_max, sizeof(PFS_file_class), + file_class_array); file_class_array= NULL; file_class_dirty_count= file_class_allocated_count= 0; file_class_max= 0; @@ -516,8 +861,10 @@ int init_stage_class(uint stage_class_sizing) if (stage_class_max > 0) { - stage_class_array= PFS_MALLOC_ARRAY(stage_class_max, sizeof(PFS_stage_class), - PFS_stage_class, MYF(MY_ZEROFILL)); + stage_class_array= PFS_MALLOC_ARRAY(& builtin_memory_stage_class, + stage_class_max, + sizeof(PFS_stage_class), PFS_stage_class, + MYF(MY_ZEROFILL)); if (unlikely(stage_class_array == NULL)) return 1; } @@ -530,7 +877,9 @@ int init_stage_class(uint stage_class_sizing) /** Cleanup the stage class buffers. */ void cleanup_stage_class(void) { - pfs_free(stage_class_array); + PFS_FREE_ARRAY(& builtin_memory_stage_class, + stage_class_max, sizeof(PFS_stage_class), + stage_class_array); stage_class_array= NULL; stage_class_dirty_count= stage_class_allocated_count= 0; stage_class_max= 0; @@ -550,8 +899,10 @@ int init_statement_class(uint statement_class_sizing) if (statement_class_max > 0) { - statement_class_array= PFS_MALLOC_ARRAY(statement_class_max, sizeof(PFS_statement_class), - PFS_statement_class, MYF(MY_ZEROFILL)); + statement_class_array= PFS_MALLOC_ARRAY(& builtin_memory_statement_class, + statement_class_max, + sizeof(PFS_statement_class), PFS_statement_class, + MYF(MY_ZEROFILL)); if (unlikely(statement_class_array == NULL)) return 1; } @@ -564,7 +915,9 @@ int init_statement_class(uint statement_class_sizing) /** Cleanup the statement class buffers. */ void cleanup_statement_class(void) { - pfs_free(statement_class_array); + PFS_FREE_ARRAY(& builtin_memory_statement_class, + statement_class_max, sizeof(PFS_statement_class), + statement_class_array); statement_class_array= NULL; statement_class_dirty_count= statement_class_allocated_count= 0; statement_class_max= 0; @@ -584,8 +937,10 @@ int init_socket_class(uint socket_class_sizing) if (socket_class_max > 0) { - socket_class_array= PFS_MALLOC_ARRAY(socket_class_max, sizeof(PFS_socket_class), - PFS_socket_class, MYF(MY_ZEROFILL)); + socket_class_array= PFS_MALLOC_ARRAY(& builtin_memory_socket_class, + socket_class_max, + sizeof(PFS_socket_class), PFS_socket_class, + MYF(MY_ZEROFILL)); if (unlikely(socket_class_array == NULL)) return 1; } @@ -598,12 +953,52 @@ int init_socket_class(uint socket_class_sizing) /** Cleanup the socket class buffers. */ void cleanup_socket_class(void) { - pfs_free(socket_class_array); + PFS_FREE_ARRAY(& builtin_memory_socket_class, + socket_class_max, sizeof(PFS_socket_class), + socket_class_array); socket_class_array= NULL; socket_class_dirty_count= socket_class_allocated_count= 0; socket_class_max= 0; } +/** + Initialize the memory class buffer. + @param memory_class_sizing max number of memory class + @return 0 on success +*/ +int init_memory_class(uint memory_class_sizing) +{ + int result= 0; + memory_class_dirty_count= memory_class_allocated_count= 0; + memory_class_max= memory_class_sizing; + memory_class_lost= 0; + + if (memory_class_max > 0) + { + memory_class_array= PFS_MALLOC_ARRAY(& builtin_memory_memory_class, + memory_class_max, + sizeof(PFS_memory_class), PFS_memory_class, + MYF(MY_ZEROFILL)); + if (unlikely(memory_class_array == NULL)) + return 1; + } + else + memory_class_array= NULL; + + return result; +} + +/** Cleanup the memory class buffers. */ +void cleanup_memory_class(void) +{ + PFS_FREE_ARRAY(& builtin_memory_memory_class, + memory_class_max, sizeof(PFS_memory_class), + memory_class_array); + memory_class_array= NULL; + memory_class_dirty_count= memory_class_allocated_count= 0; + memory_class_max= 0; +} + static void init_instr_class(PFS_instr_class *klass, const char *name, uint name_length, @@ -612,7 +1007,7 @@ static void init_instr_class(PFS_instr_class *klass, { DBUG_ASSERT(name_length <= PFS_MAX_INFO_NAME_LENGTH); memset(klass, 0, sizeof(PFS_instr_class)); - strncpy(klass->m_name, name, name_length); + memcpy(klass->m_name, name, name_length); klass->m_name_length= name_length; klass->m_flags= flags; klass->m_enabled= true; @@ -628,10 +1023,13 @@ 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++) + // May be NULL in unit tests + if (pfs_instr_config_array == NULL) + return; + PFS_instr_config **it= pfs_instr_config_array->front(); + for ( ; it != pfs_instr_config_array->end(); it++) { - PFS_instr_config* e; - get_dynamic(&pfs_instr_config_array, (uchar*)&e, i); + PFS_instr_config* e= *it; /** Compare class name to all configuration entries. In case of multiple @@ -757,7 +1155,8 @@ PFS_sync_key register_mutex_class(const char *name, uint name_length, Out of space, report to SHOW STATUS that the allocated memory was too small. */ - mutex_class_lost++; + if (pfs_enabled) + mutex_class_lost++; return 0; } @@ -795,7 +1194,8 @@ PFS_sync_key register_rwlock_class(const char *name, uint name_length, return (index + 1); } - rwlock_class_lost++; + if (pfs_enabled) + rwlock_class_lost++; return 0; } @@ -832,7 +1232,8 @@ PFS_sync_key register_cond_class(const char *name, uint name_length, return (index + 1); } - cond_class_lost++; + if (pfs_enabled) + cond_class_lost++; return 0; } @@ -922,7 +1323,8 @@ PFS_thread_key register_thread_class(const char *name, uint name_length, return (index + 1); } - thread_class_lost++; + if (pfs_enabled) + thread_class_lost++; return 0; } @@ -971,10 +1373,12 @@ PFS_file_key register_file_class(const char *name, uint name_length, /* Set user-defined configuration options for this instrument */ configure_instr_class(entry); PFS_atomic::add_u32(&file_class_allocated_count, 1); + return (index + 1); } - file_class_lost++; + if (pfs_enabled) + file_class_lost++; return 0; } @@ -1006,8 +1410,20 @@ PFS_stage_key register_stage_class(const char *name, 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; + + if (flags & PSI_FLAG_STAGE_PROGRESS) + { + /* Stages with progress information are enabled and timed by default */ + entry->m_enabled= true; + entry->m_timed= true; + } + else + { + /* Stages without progress information are disabled by default */ + entry->m_enabled= false; + 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); @@ -1015,7 +1431,8 @@ PFS_stage_key register_stage_class(const char *name, return (index + 1); } - stage_class_lost++; + if (pfs_enabled) + stage_class_lost++; return 0; } @@ -1052,7 +1469,8 @@ PFS_statement_key register_statement_class(const char *name, uint name_length, return (index + 1); } - statement_class_lost++; + if (pfs_enabled) + statement_class_lost++; return 0; } @@ -1134,7 +1552,8 @@ PFS_socket_key register_socket_class(const char *name, uint name_length, return (index + 1); } - socket_class_lost++; + if (pfs_enabled) + socket_class_lost++; return 0; } @@ -1153,6 +1572,58 @@ PFS_socket_class *sanitize_socket_class(PFS_socket_class *unsafe) SANITIZE_ARRAY_BODY(PFS_socket_class, socket_class_array, socket_class_max, unsafe); } +/** + Register a memory instrumentation metadata. + @param name the instrumented name + @param name_length length in bytes of name + @param flags the instrumentation flags + @return a memory instrumentation key +*/ +PFS_memory_key register_memory_class(const char *name, uint name_length, + int flags) +{ + /* See comments in register_mutex_class */ + uint32 index; + PFS_memory_class *entry; + + REGISTER_CLASS_BODY_PART(index, memory_class_array, memory_class_max, + name, name_length) + + index= PFS_atomic::add_u32(&memory_class_dirty_count, 1); + + if (index < memory_class_max) + { + entry= &memory_class_array[index]; + init_instr_class(entry, name, name_length, flags, PFS_CLASS_MEMORY); + entry->m_event_name_index= index; + entry->m_enabled= false; /* disabled by default */ + /* Set user-defined configuration options for this instrument */ + configure_instr_class(entry); + entry->m_timed= false; /* Immutable */ + PFS_atomic::add_u32(&memory_class_allocated_count, 1); + return (index + 1); + } + + if (pfs_enabled) + memory_class_lost++; + return 0; +} + +/** + Find a memory instrumentation class by key. + @param key the instrument key + @return the instrument class, or NULL +*/ +PFS_memory_class *find_memory_class(PFS_memory_key key) +{ + FIND_CLASS_BODY(key, memory_class_allocated_count, memory_class_array); +} + +PFS_memory_class *sanitize_memory_class(PFS_memory_class *unsafe) +{ + SANITIZE_ARRAY_BODY(PFS_memory_class, memory_class_array, memory_class_max, unsafe); +} + PFS_instr_class *find_table_class(uint index) { if (index == 1) @@ -1184,49 +1655,64 @@ PFS_instr_class *sanitize_idle_class(PFS_instr_class *unsafe) return NULL; } -static void set_keys(PFS_table_share *pfs, const TABLE_SHARE *share) +PFS_instr_class *find_metadata_class(uint index) { - 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; - pfs->m_key_count= share->keys; + if (index == 1) + return & global_metadata_class; + return NULL; +} - for ( ; pfs_key < pfs_key_last; pfs_key++, key_info++) - { - len= (uint)key_info->name.length; - memcpy(pfs_key->m_name, key_info->name.str, len); - pfs_key->m_name_length= len; - } +PFS_instr_class *sanitize_metadata_class(PFS_instr_class *unsafe) +{ + if (likely(& global_metadata_class == unsafe)) + return unsafe; + return NULL; +} - pfs_key_last= pfs->m_keys + MAX_INDEXES; - for ( ; pfs_key < pfs_key_last; pfs_key++) - pfs_key->m_name_length= 0; +PFS_transaction_class *find_transaction_class(uint index) +{ + if (index == 1) + return &global_transaction_class; + return NULL; } -static int compare_keys(PFS_table_share *pfs, const TABLE_SHARE *share) +PFS_transaction_class *sanitize_transaction_class(PFS_transaction_class *unsafe) { - 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 (likely(&global_transaction_class == unsafe)) + return unsafe; + return NULL; +} +static int compare_keys(PFS_table_share *pfs, const TABLE_SHARE *share) +{ if (pfs->m_key_count != share->keys) return 1; - for ( ; pfs_key < pfs_key_last; pfs_key++, key_info++) + size_t len; + uint index= 0; + uint key_count= share->keys; + KEY *key_info= share->key_info; + PFS_table_share_index *index_stat; + + for ( ; index < key_count; key_info++, index++) { - len= (uint)key_info->name.length; - if (len != pfs_key->m_name_length) - return 1; + index_stat= pfs->find_index_stat(index); + if (index_stat != NULL) + { + len= key_info->name.length; - if (memcmp(pfs_key->m_name, key_info->name.str, len) != 0) - return 1; + if (len != index_stat->m_key.m_name_length) + return 1; + + if (memcmp(index_stat->m_key.m_name, key_info->name.str, len) != 0) + return 1; + } } return 0; } + /** Find or create a table share instrumentation. @param thread the executing instrumented thread @@ -1244,14 +1730,14 @@ PFS_table_share* find_or_create_table_share(PFS_thread *thread, LF_PINS *pins= get_table_share_hash_pins(thread); if (unlikely(pins == NULL)) { - table_share_lost++; + global_table_share_container.m_lost++; return NULL; } const char *schema_name= share->db.str; - uint schema_name_length= (uint)share->db.length; + size_t schema_name_length= share->db.length; const char *table_name= share->table_name.str; - uint table_name_length= (uint)share->table_name.length; + size_t table_name_length= share->table_name.length; set_table_share_key(&key, temporary, schema_name, schema_name_length, @@ -1262,10 +1748,8 @@ PFS_table_share* find_or_create_table_share(PFS_thread *thread, 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; + pfs_dirty_state dirty_state; search: entry= reinterpret_cast<PFS_table_share**> @@ -1277,9 +1761,19 @@ search: 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(); + /* + Some DDL was detected. + - keep the lock stats, they are unaffected + - destroy the index stats, indexes changed. + - adjust the expected key count + - recreate index stats + */ + pfs->destroy_index_stats(); + pfs->m_key_count= share->keys; + for (uint index= 0; index < pfs->m_key_count; index++) + { + (void)pfs->find_or_create_index_stat(share, index); + } } lf_hash_search_unpin(pins); return pfs; @@ -1302,85 +1796,136 @@ search: */ } - while (++attempts <= table_share_max) + pfs= global_table_share_container.allocate(& dirty_state); + if (pfs != NULL) { - /* 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()) + 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->destroy_lock_stat(); + pfs->destroy_index_stats(); + pfs->m_key_count= share->keys; + + int res; + pfs->m_lock.dirty_to_allocated(& dirty_state); + res= lf_hash_insert(&table_share_hash, pins, &pfs); + + if (likely(res == 0)) { - if (pfs->m_lock.free_to_dirty()) + /* Create table share index stats. */ + for (uint index= 0; index < pfs->m_key_count; index++) { - pfs->m_key= key; - pfs->m_schema_name= &pfs->m_key.m_hash_key[1]; - pfs->m_schema_name_length= schema_name_length; - pfs->m_table_name= &pfs->m_key.m_hash_key[schema_name_length + 2]; - pfs->m_table_name_length= table_name_length; - pfs->m_enabled= enabled; - pfs->m_timed= timed; - pfs->init_refcount(); - pfs->m_table_stat.fast_reset(); - set_keys(pfs, share); - - int res; - res= lf_hash_insert(&table_share_hash, pins, &pfs); - if (likely(res == 0)) - { - pfs->m_lock.dirty_to_allocated(); - return pfs; - } - - pfs->m_lock.dirty_to_free(); + (void)pfs->find_or_create_index_stat(share, index); + } + return pfs; + } - if (res > 0) - { - /* Duplicate insert by another thread */ - if (++retry_count > retry_max) - { - /* Avoid infinite loops */ - table_share_lost++; - return NULL; - } - goto search; - } + global_table_share_container.deallocate(pfs); - /* OOM in lf_hash_insert */ - table_share_lost++; + if (res > 0) + { + /* Duplicate insert by another thread */ + if (++retry_count > retry_max) + { + /* Avoid infinite loops */ + global_table_share_container.m_lost++; return NULL; } + goto search; } + + /* OOM in lf_hash_insert */ + global_table_share_container.m_lost++; + return NULL; } - table_share_lost++; return NULL; } void PFS_table_share::aggregate_io(void) { + uint index; 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_share_index *from_stat; 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); + for (index= 0; index < safe_key_count; index++) + { + from_stat= find_index_stat(index); + if (from_stat != NULL) + { + sum_io.aggregate(& from_stat->m_stat); + from_stat->m_stat.reset(); + } + } /* Aggregate stats for the table */ - sum_io.aggregate(& m_table_stat.m_index_stat[MAX_INDEXES]); + from_stat= find_index_stat(MAX_INDEXES); + if (from_stat != NULL) + { + sum_io.aggregate(& from_stat->m_stat); + from_stat->m_stat.reset(); + } /* Add this table stats to the global sink. */ global_table_io_stat.aggregate(& sum_io); - m_table_stat.fast_reset_io(); +} + +void PFS_table_share::sum_io(PFS_single_stat *result, uint key_count) +{ + uint index; + PFS_table_share_index *stat; + + DBUG_ASSERT(key_count <= MAX_INDEXES); + + /* Sum stats for each index, if any */ + for (index= 0; index < key_count; index++) + { + stat= find_index_stat(index); + if (stat != NULL) + { + stat->m_stat.sum(result); + } + } + + /* Sum stats for the table */ + stat= find_index_stat(MAX_INDEXES); + if (stat != NULL) + { + stat->m_stat.sum(result); + } +} + +void PFS_table_share::sum_lock(PFS_single_stat *result) +{ + PFS_table_share_lock *lock_stat; + lock_stat= find_lock_stat(); + if (lock_stat != NULL) + lock_stat->m_stat.sum(result); +} + +void PFS_table_share::sum(PFS_single_stat *result, uint key_count) +{ + sum_io(result, key_count); + sum_lock(result); } void PFS_table_share::aggregate_lock(void) { - global_table_lock_stat.aggregate(& m_table_stat.m_lock_stat); - m_table_stat.fast_reset_lock(); + PFS_table_share_lock *lock_stat; + lock_stat= find_lock_stat(); + if (lock_stat != NULL) + { + global_table_lock_stat.aggregate(& lock_stat->m_stat); + /* Reset lock stat. */ + lock_stat->m_stat.reset(); + } } void release_table_share(PFS_table_share *pfs) @@ -1418,6 +1963,9 @@ void drop_table_share(PFS_thread *thread, 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->destroy_lock_stat(); + pfs->destroy_index_stats(); + pfs->m_lock.allocated_to_free(); } @@ -1431,7 +1979,7 @@ void drop_table_share(PFS_thread *thread, */ PFS_table_share *sanitize_table_share(PFS_table_share *unsafe) { - SANITIZE_ARRAY_BODY(PFS_table_share, table_share_array, table_share_max, unsafe); + return global_table_share_container.sanitize(unsafe); } /** Reset the wait statistics per instrument class. */ @@ -1442,6 +1990,7 @@ void reset_events_waits_by_class() global_idle_stat.reset(); global_table_io_stat.reset(); global_table_lock_stat.reset(); + global_metadata_stat.reset(); } /** Reset the io statistics per file class. */ @@ -1464,16 +2013,50 @@ void reset_socket_class_io(void) pfs->m_socket_stat.m_io_stat.reset(); } +class Proc_table_share_derived_flags + : public PFS_buffer_processor<PFS_table_share> +{ +public: + Proc_table_share_derived_flags(PFS_thread *thread) + : m_thread(thread) + {} + + virtual void operator()(PFS_table_share *pfs) + { + pfs->refresh_setup_object_flags(m_thread); + } + +private: + PFS_thread* m_thread; +}; + void update_table_share_derived_flags(PFS_thread *thread) { - PFS_table_share *pfs= table_share_array; - PFS_table_share *pfs_last= table_share_array + table_share_max; + Proc_table_share_derived_flags proc(thread); + global_table_share_container.apply(proc); +} - for ( ; pfs < pfs_last; pfs++) +class Proc_program_share_derived_flags + : public PFS_buffer_processor<PFS_program> +{ +public: + Proc_program_share_derived_flags(PFS_thread *thread) + : m_thread(thread) + {} + + virtual void operator()(PFS_program *pfs) { - if (pfs->m_lock.is_populated()) - pfs->refresh_setup_object_flags(thread); + pfs->refresh_setup_object_flags(m_thread); } + +private: + PFS_thread* m_thread; +}; + +void update_program_share_derived_flags(PFS_thread *thread) +{ + Proc_program_share_derived_flags proc(thread); + global_program_container.apply(proc); } /** @} */ diff --git a/storage/perfschema/pfs_instr_class.h b/storage/perfschema/pfs_instr_class.h index 9d256fac78a..573cfe33ffb 100644 --- a/storage/perfschema/pfs_instr_class.h +++ b/storage/perfschema/pfs_instr_class.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2008, 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, version 2.0, @@ -27,6 +27,8 @@ #include "mysql_com.h" /* NAME_LEN */ #include "lf.h" #include "pfs_global.h" +#include "pfs_atomic.h" +#include "sql_array.h" /** @file storage/perfschema/pfs_instr_class.h @@ -48,7 +50,6 @@ */ #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" @@ -56,6 +57,8 @@ #include "pfs_column_types.h" struct PFS_global_param; +struct PFS_table_share; +class PFS_opaque_container_page; /** @addtogroup Performance_schema_buffers @@ -75,8 +78,12 @@ typedef unsigned int PFS_file_key; typedef unsigned int PFS_stage_key; /** Key, naming a statement instrument. */ typedef unsigned int PFS_statement_key; +/** Key, naming a transaction instrument. */ +typedef unsigned int PFS_transaction_key; /** Key, naming a socket instrument. */ typedef unsigned int PFS_socket_key; +/** Key, naming a memory instrument. */ +typedef unsigned int PFS_memory_key; enum PFS_class_type { @@ -88,11 +95,14 @@ enum PFS_class_type 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_TRANSACTION= 8, + PFS_CLASS_SOCKET= 9, + PFS_CLASS_TABLE_IO= 10, + PFS_CLASS_TABLE_LOCK= 11, + PFS_CLASS_IDLE= 12, + PFS_CLASS_MEMORY= 13, + PFS_CLASS_METADATA= 14, + PFS_CLASS_LAST= PFS_CLASS_METADATA, PFS_CLASS_MAX= PFS_CLASS_LAST + 1 }; @@ -109,12 +119,8 @@ struct PFS_instr_config 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; +typedef Dynamic_array<PFS_instr_config*> Pfs_instr_config_array; +extern Pfs_instr_config_array *pfs_instr_config_array; struct PFS_thread; @@ -136,12 +142,15 @@ struct PFS_instr_class bool m_timed; /** Instrument flags. */ int m_flags; + /** Volatility index. */ + int m_volatility; /** 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 + - EVENTS_TRANSACTIONS_SUMMARY_*_BY_EVENT_NAME for transactions */ uint m_event_name_index; /** Instrument name. */ @@ -161,6 +170,18 @@ struct PFS_instr_class return m_flags & PSI_FLAG_MUTABLE; } + bool is_progress() const + { + DBUG_ASSERT(m_type == PFS_CLASS_STAGE); + return m_flags & PSI_FLAG_STAGE_PROGRESS; + } + + bool is_shared_exclusive() const + { + DBUG_ASSERT(m_type == PFS_CLASS_RWLOCK); + return m_flags & PSI_RWLOCK_FLAG_SX; + } + static void set_enabled(PFS_instr_class *pfs, bool enabled); static void set_timed(PFS_instr_class *pfs, bool timed); @@ -252,6 +273,32 @@ struct PFS_table_key uint m_name_length; }; +/** Index statistics of a table.*/ +struct PFS_table_share_index +{ + pfs_lock m_lock; + /** The index name */ + PFS_table_key m_key; + /** The index stat */ + PFS_table_io_stat m_stat; + /** Owner table share. To be used later. */ + PFS_table_share* m_owner; + /** Container page. */ + PFS_opaque_container_page *m_page; +}; + +/** Lock statistics of a table.*/ +struct PFS_table_share_lock +{ + pfs_lock m_lock; + /** Lock stats. */ + PFS_table_lock_stat m_stat; + /** Owner table share. To be used later. */ + PFS_table_share* m_owner; + /** Container page. */ + PFS_opaque_container_page *m_page; +}; + /** Instrumentation metadata for a table share. */ struct PFS_ALIGNED PFS_table_share { @@ -267,6 +314,10 @@ public: void aggregate_io(void); void aggregate_lock(void); + void sum_io(PFS_single_stat *result, uint key_count); + void sum_lock(PFS_single_stat *result); + void sum(PFS_single_stat *result, uint key_count); + inline void aggregate(void) { aggregate_io(); @@ -307,6 +358,7 @@ public: This flag is computed from the content of table setup_objects. */ bool m_timed; + /** Search key. */ PFS_table_share_key m_key; /** Schema name. */ @@ -319,14 +371,24 @@ public: uint m_table_name_length; /** Number of indexes. */ uint m_key_count; - /** Table statistics. */ - PFS_table_stat m_table_stat; - /** Index names. */ - PFS_table_key m_keys[MAX_INDEXES]; + /** Container page. */ + PFS_opaque_container_page *m_page; + + PFS_table_share_lock *find_lock_stat() const; + PFS_table_share_lock *find_or_create_lock_stat(); + void destroy_lock_stat(); + + PFS_table_share_index *find_index_stat(uint index) const; + PFS_table_share_index *find_or_create_index_stat(const TABLE_SHARE *server_share, uint index); + void destroy_index_stats(); private: /** Number of opened table handles. */ int m_refcount; + /** Table locks statistics. */ + PFS_table_share_lock *m_race_lock_stat; + /** Table indexes' stats. */ + PFS_table_share_index *m_race_index_stat[MAX_INDEXES + 1]; }; /** Statistics for the IDLE instrument. */ @@ -335,6 +397,10 @@ extern PFS_single_stat global_idle_stat; extern PFS_table_io_stat global_table_io_stat; /** Statistics for dropped table lock. */ extern PFS_table_lock_stat global_table_lock_stat; +/** Statistics for the METADATA instrument. */ +extern PFS_single_stat global_metadata_stat; +/** Statistics for the transaction instrument. */ +extern PFS_transaction_stat global_transaction_stat; inline uint sanitize_index_count(uint count) { @@ -346,6 +412,12 @@ inline uint sanitize_index_count(uint count) #define GLOBAL_TABLE_IO_EVENT_INDEX 0 #define GLOBAL_TABLE_LOCK_EVENT_INDEX 1 #define GLOBAL_IDLE_EVENT_INDEX 2 +#define GLOBAL_METADATA_EVENT_INDEX 3 +/** Number of global wait events. */ +#define COUNT_GLOBAL_EVENT_INDEX 4 + +/** Transaction events are not wait events .*/ +#define GLOBAL_TRANSACTION_INDEX 0 /** Instrument controlling all table io. @@ -364,6 +436,8 @@ extern PFS_instr_class global_table_lock_class; */ extern PFS_instr_class global_idle_class; +extern PFS_instr_class global_metadata_class; + struct PFS_file; /** Instrumentation metadata for a file. */ @@ -392,7 +466,14 @@ struct PFS_ALIGNED PFS_statement_class : public PFS_instr_class { }; -struct PFS_socket; +/** Instrumentation metadata for a transaction. */ +struct PFS_ALIGNED PFS_transaction_class : public PFS_instr_class +{ +}; + +extern PFS_transaction_class global_transaction_class; + +struct PFS_socket; /** Instrumentation metadata for a socket. */ struct PFS_ALIGNED PFS_socket_class : public PFS_instr_class @@ -403,6 +484,20 @@ struct PFS_ALIGNED PFS_socket_class : public PFS_instr_class PFS_socket *m_singleton; }; +/** Instrumentation metadata for a memory. */ +struct PFS_ALIGNED PFS_memory_class : public PFS_instr_class +{ + bool is_global() const + { + return m_flags & PSI_FLAG_GLOBAL; + } + + bool is_transferable() const + { + return m_flags & PSI_FLAG_TRANSFER; + } +}; + void init_event_name_sizing(const PFS_global_param *param); void register_global_classes(); @@ -416,7 +511,18 @@ int init_thread_class(uint thread_class_sizing); void cleanup_thread_class(); int init_table_share(uint table_share_sizing); void cleanup_table_share(); -int init_table_share_hash(); + +int init_table_share_lock_stat(uint table_stat_sizing); +void cleanup_table_share_lock_stat(); +PFS_table_share_lock* create_table_share_lock_stat(); +void release_table_share_lock_stat(PFS_table_share_lock *pfs); + +int init_table_share_index_stat(uint index_stat_sizing); +void cleanup_table_share_index_stat(); +PFS_table_share_index* create_table_share_index_stat(const TABLE_SHARE *share, uint index); +void release_table_share_index_stat(PFS_table_share_index *pfs); + +int init_table_share_hash(const PFS_global_param *param); void cleanup_table_share_hash(); int init_file_class(uint file_class_sizing); void cleanup_file_class(); @@ -426,6 +532,8 @@ int init_statement_class(uint statement_class_sizing); void cleanup_statement_class(); int init_socket_class(uint socket_class_sizing); void cleanup_socket_class(); +int init_memory_class(uint memory_class_sizing); +void cleanup_memory_class(); PFS_sync_key register_mutex_class(const char *name, uint name_length, int flags); @@ -453,6 +561,9 @@ PFS_statement_key register_statement_class(const char *name, uint name_length, PFS_socket_key register_socket_class(const char *name, uint name_length, int flags); +PFS_memory_key register_memory_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); @@ -471,8 +582,14 @@ 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_memory_class *find_memory_class(PSI_memory_key key); +PFS_memory_class *sanitize_memory_class(PFS_memory_class *unsafe); PFS_instr_class *find_idle_class(uint index); PFS_instr_class *sanitize_idle_class(PFS_instr_class *unsafe); +PFS_instr_class *find_metadata_class(uint index); +PFS_instr_class *sanitize_metadata_class(PFS_instr_class *unsafe); +PFS_transaction_class *find_transaction_class(uint index); +PFS_transaction_class *sanitize_transaction_class(PFS_transaction_class *unsafe); PFS_table_share *find_or_create_table_share(PFS_thread *thread, bool temporary, @@ -499,10 +616,11 @@ extern ulong stage_class_max; extern ulong stage_class_lost; extern ulong statement_class_max; extern ulong statement_class_lost; +extern ulong transaction_class_max; extern ulong socket_class_max; extern ulong socket_class_lost; -extern ulong table_share_max; -extern ulong table_share_lost; +extern ulong memory_class_max; +extern ulong memory_class_lost; /* Exposing the data directly, for iterators. */ @@ -510,7 +628,6 @@ extern PFS_mutex_class *mutex_class_array; extern PFS_rwlock_class *rwlock_class_array; extern PFS_cond_class *cond_class_array; extern PFS_file_class *file_class_array; -extern PFS_table_share *table_share_array; void reset_events_waits_by_class(); void reset_file_class_io(); @@ -519,6 +636,9 @@ void reset_socket_class_io(); /** Update derived flags for all table shares. */ void update_table_share_derived_flags(PFS_thread *thread); +/** Update derived flags for all stored procedure shares. */ +void update_program_share_derived_flags(PFS_thread *thread); + extern LF_HASH table_share_hash; /** @} */ diff --git a/storage/perfschema/pfs_lock.h b/storage/perfschema/pfs_lock.h index b74131c79e1..836c64ec992 100644 --- a/storage/perfschema/pfs_lock.h +++ b/storage/perfschema/pfs_lock.h @@ -28,8 +28,15 @@ Performance schema internal locks (declarations). */ +#include "my_global.h" + #include "pfs_atomic.h" +/* to cause bugs, testing */ +// #define MEM(X) std::memory_order_relaxed +/* correct code */ +#define MEM(X) X + /** @addtogroup Performance_schema_buffers @{ @@ -61,6 +68,16 @@ #define STATE_MASK 0x00000003 #define VERSION_INC 4 +struct pfs_optimistic_state +{ + uint32 m_version_state; +}; + +struct pfs_dirty_state +{ + uint32 m_version_state; +}; + /** A 'lock' protecting performance schema internal buffers. This lock is used to mark the state of a record. @@ -86,19 +103,34 @@ struct pfs_lock The version number is stored in the high 30 bits. The state is stored in the low 2 bits. */ - volatile uint32 m_version_state; + uint32 m_version_state; + + uint32 copy_version_state() + { + uint32 copy; + + copy= m_version_state; /* dirty read */ + + return copy; + } /** Returns true if the record is free. */ bool is_free(void) { - uint32 copy= m_version_state; /* non volatile copy, and dirty read */ + uint32 copy; + + copy= PFS_atomic::load_u32(&m_version_state); + return ((copy & STATE_MASK) == PFS_LOCK_FREE); } /** Returns true if the record contains values that can be read. */ bool is_populated(void) { - uint32 copy= m_version_state; /* non volatile copy, and dirty read */ + uint32 copy; + + copy= PFS_atomic::load_u32(&m_version_state); + return ((copy & STATE_MASK) == PFS_LOCK_ALLOCATED); } @@ -108,13 +140,28 @@ struct pfs_lock Only one writer will succeed to acquire the record. @return true if the operation succeed */ - bool free_to_dirty(void) + bool free_to_dirty(pfs_dirty_state *copy_ptr) { - 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; + uint32 old_val; + + old_val= PFS_atomic::load_u32(&m_version_state); + + if ((old_val & STATE_MASK) != PFS_LOCK_FREE) + { + return false; + } - return (PFS_atomic::cas_u32(&m_version_state, &old_val, new_val)); + uint32 new_val= (old_val & VERSION_MASK) + PFS_LOCK_DIRTY; + bool pass; + + pass= PFS_atomic::cas_u32(&m_version_state, &old_val, new_val); + + if (pass) + { + copy_ptr->m_version_state= new_val; + } + + return pass; } /** @@ -122,15 +169,18 @@ struct pfs_lock This transition should be executed by the writer that owns the record, before the record is modified. */ - void allocated_to_dirty(void) + void allocated_to_dirty(pfs_dirty_state *copy_ptr) { - uint32 copy= PFS_atomic::load_u32(&m_version_state); + uint32 copy= copy_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); + + copy_ptr->m_version_state= new_val; } /** @@ -138,13 +188,13 @@ struct pfs_lock This transition should be executed by the writer that owns the record, after the record is in a state ready to be read. */ - void dirty_to_allocated(void) + void dirty_to_allocated(const pfs_dirty_state *copy) { - uint32 copy= PFS_atomic::load_u32(&m_version_state); /* Make sure the record was DIRTY. */ - DBUG_ASSERT((copy & STATE_MASK) == PFS_LOCK_DIRTY); + DBUG_ASSERT((copy->m_version_state & STATE_MASK) == PFS_LOCK_DIRTY); /* Increment the version, set the ALLOCATED state */ - uint32 new_val= (copy & VERSION_MASK) + VERSION_INC + PFS_LOCK_ALLOCATED; + uint32 new_val= (copy->m_version_state & VERSION_MASK) + VERSION_INC + PFS_LOCK_ALLOCATED; + PFS_atomic::store_u32(&m_version_state, new_val); } @@ -156,35 +206,52 @@ struct pfs_lock void set_allocated(void) { /* Do not set the version to 0, read the previous value. */ - uint32 copy= PFS_atomic::load_u32(&m_version_state); + uint32 copy= copy_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) + void set_dirty(pfs_dirty_state *copy_ptr) { /* 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); + + copy_ptr->m_version_state= new_val; + } + + /** + Initialize a lock to dirty. + */ + void set_dirty(pfs_dirty_state *copy_ptr) + { + /* 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); + + copy_ptr->m_version_state= new_val; } /** Execute a dirty to free transition. This transition should be executed by the writer that owns the record. */ - void dirty_to_free(void) + void dirty_to_free(const pfs_dirty_state *copy) { - uint32 copy= PFS_atomic::load_u32(&m_version_state); /* Make sure the record was DIRTY. */ - DBUG_ASSERT((copy & STATE_MASK) == PFS_LOCK_DIRTY); + DBUG_ASSERT((copy->m_version_state & STATE_MASK) == PFS_LOCK_DIRTY); /* Keep the same version, set the FREE state */ - uint32 new_val= (copy & VERSION_MASK) + PFS_LOCK_FREE; + uint32 new_val= (copy->m_version_state & VERSION_MASK) + PFS_LOCK_FREE; + PFS_atomic::store_u32(&m_version_state, new_val); } @@ -198,22 +265,22 @@ struct pfs_lock If this record is not in the ALLOCATED state and the caller is trying to free it, this is a bug: the caller is confused, and potentially damaging data owned by another thread or object. - The correct assert to use here to guarantee data integrity is simply: - DBUG_ASSERT(m_state == PFS_LOCK_ALLOCATED); */ - uint32 copy= PFS_atomic::load_u32(&m_version_state); + uint32 copy= copy_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); } /** Start an optimistic read operation. + @param [out] copy Saved lock state @sa end_optimist_lock. */ - void begin_optimistic_lock(struct pfs_lock *copy) + void begin_optimistic_lock(struct pfs_optimistic_state *copy) { copy->m_version_state= PFS_atomic::load_u32(&m_version_state); } @@ -221,16 +288,21 @@ struct pfs_lock /** End an optimistic read operation. @sa begin_optimist_lock. + @param copy Saved lock state @return true if the data read is safe to use. */ - bool end_optimistic_lock(struct pfs_lock *copy) + bool end_optimistic_lock(const struct pfs_optimistic_state *copy) { + uint32 version_state; + /* Check there was valid data to look at. */ if ((copy->m_version_state & STATE_MASK) != PFS_LOCK_ALLOCATED) return false; + version_state= PFS_atomic::load_u32(&m_version_state); + /* Check the version + state has not changed. */ - if (copy->m_version_state != PFS_atomic::load_u32(&m_version_state)) + if (copy->m_version_state != version_state) return false; return true; @@ -238,7 +310,11 @@ struct pfs_lock uint32 get_version() { - return (PFS_atomic::load_u32(&m_version_state) & VERSION_MASK); + uint32 version_state; + + version_state= PFS_atomic::load_u32(&m_version_state); + + return (version_state & VERSION_MASK); } }; diff --git a/storage/perfschema/pfs_memory.cc b/storage/perfschema/pfs_memory.cc new file mode 100644 index 00000000000..c4e92d7d6b0 --- /dev/null +++ b/storage/perfschema/pfs_memory.cc @@ -0,0 +1,98 @@ +/* Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/pfs_memory.cc + Memory statistics aggregation (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_atomic.h" +#include "pfs_buffer_container.h" +#include "m_string.h" + +static void fct_reset_memory_by_thread(PFS_thread *pfs) +{ + PFS_account *account= sanitize_account(pfs->m_account); + PFS_user *user= sanitize_user(pfs->m_user); + PFS_host *host= sanitize_host(pfs->m_host); + aggregate_thread_memory(true, pfs, account, user, host); +} + +/** Reset table MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */ +void reset_memory_by_thread() +{ + global_thread_container.apply(fct_reset_memory_by_thread); +} + +static void fct_reset_memory_by_account(PFS_account *pfs) +{ + PFS_user *user= sanitize_user(pfs->m_user); + PFS_host *host= sanitize_host(pfs->m_host); + pfs->aggregate_memory(true, user, host); +} + +/** Reset table MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */ +void reset_memory_by_account() +{ + global_account_container.apply(fct_reset_memory_by_account); +} + +static void fct_reset_memory_by_user(PFS_user *pfs) +{ + pfs->aggregate_memory(true); +} + +/** Reset table MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME data. */ +void reset_memory_by_user() +{ + global_user_container.apply(fct_reset_memory_by_user); +} + +static void fct_reset_memory_by_host(PFS_host *pfs) +{ + pfs->aggregate_memory(true); +} + +/** Reset table MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME data. */ +void reset_memory_by_host() +{ + global_host_container.apply(fct_reset_memory_by_host); +} + +/** Reset table MEMORY_GLOBAL_BY_EVENT_NAME data. */ +void reset_memory_global() +{ + PFS_memory_stat *stat= global_instr_class_memory_array; + PFS_memory_stat *stat_last= global_instr_class_memory_array + memory_class_max; + + for ( ; stat < stat_last; stat++) + stat->rebase(); +} + diff --git a/storage/perfschema/pfs_memory.h b/storage/perfschema/pfs_memory.h new file mode 100644 index 00000000000..4dc21b892d5 --- /dev/null +++ b/storage/perfschema/pfs_memory.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef PFS_MEMORY_H +#define PFS_MEMORY_H + +/** + @file storage/perfschema/pfs_memory.h + Memory statistics aggregation (declarations). +*/ + +void reset_memory_by_thread(); +void reset_memory_by_account(); +void reset_memory_by_user(); +void reset_memory_by_host(); +void reset_memory_global(); + +#endif + diff --git a/storage/perfschema/pfs_prepared_stmt.cc b/storage/perfschema/pfs_prepared_stmt.cc new file mode 100644 index 00000000000..e3440560691 --- /dev/null +++ b/storage/perfschema/pfs_prepared_stmt.cc @@ -0,0 +1,149 @@ +/* Copyright (c) 2014, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/pfs_prepared_stmt.cc + Prepared Statement data structures (implementation). +*/ + +/* + This code needs extra visibility in the lexer structures +*/ + +#include "my_global.h" +#include "my_sys.h" +#include "pfs_instr.h" +#include "pfs_prepared_stmt.h" +#include "pfs_global.h" +#include "sql_string.h" +#include "pfs_buffer_container.h" +#include <string.h> + +/** + Initialize table PREPARED_STATEMENTS_INSTANCE. + @param param performance schema sizing +*/ +int init_prepared_stmt(const PFS_global_param *param) +{ + if (global_prepared_stmt_container.init(param->m_prepared_stmt_sizing)) + return 1; + + reset_prepared_stmt_instances(); + return 0; +} + +/** Cleanup table PREPARED_STATEMENTS_INSTANCE. */ +void cleanup_prepared_stmt(void) +{ + global_prepared_stmt_container.cleanup(); +} + +void PFS_prepared_stmt::reset_data() +{ + m_prepare_stat.reset(); + m_reprepare_stat.reset(); + m_execute_stat.reset(); +} + +static void fct_reset_prepared_stmt_instances(PFS_prepared_stmt *pfs) +{ + pfs->reset_data(); +} + +void reset_prepared_stmt_instances() +{ + global_prepared_stmt_container.apply_all(fct_reset_prepared_stmt_instances); +} + +PFS_prepared_stmt* +create_prepared_stmt(void *identity, + PFS_thread *thread, PFS_program *pfs_program, + PFS_events_statements *pfs_stmt, uint stmt_id, + const char* stmt_name, uint stmt_name_length, + const char* sqltext, uint sqltext_length) +{ + PFS_prepared_stmt *pfs= NULL; + pfs_dirty_state dirty_state; + + /* Create a new record in prepared stmt stat array. */ + pfs= global_prepared_stmt_container.allocate(& dirty_state); + if (pfs != NULL) + { + /* Reset the stats. */ + pfs->reset_data(); + /* Do the assignments. */ + pfs->m_identity= identity; + /* Set query text if available, else it will be set later. */ + if (sqltext_length > 0) + strncpy(pfs->m_sqltext, sqltext, sqltext_length); + + pfs->m_sqltext_length= sqltext_length; + + if (stmt_name != NULL) + { + pfs->m_stmt_name_length= stmt_name_length; + if (pfs->m_stmt_name_length > PS_NAME_LENGTH) + pfs->m_stmt_name_length= PS_NAME_LENGTH; + strncpy(pfs->m_stmt_name, stmt_name, pfs->m_stmt_name_length); + } + else + pfs->m_stmt_name_length= 0; + + pfs->m_stmt_id= stmt_id; + pfs->m_owner_thread_id= thread->m_thread_internal_id; + + /* If this statement prepare is called from a SP. */ + if (pfs_program) + { + pfs->m_owner_object_type= pfs_program->m_type; + strncpy(pfs->m_owner_object_schema, pfs_program->m_schema_name, pfs_program->m_schema_name_length); + pfs->m_owner_object_schema_length= pfs_program->m_schema_name_length; + strncpy(pfs->m_owner_object_name, pfs_program->m_object_name, pfs_program->m_object_name_length); + pfs->m_owner_object_name_length= pfs_program->m_object_name_length; + } + else + { + pfs->m_owner_object_type= NO_OBJECT_TYPE; + pfs->m_owner_object_schema_length= 0; + pfs->m_owner_object_name_length= 0; + } + + if (pfs_stmt) + { + if (pfs_program) + pfs->m_owner_event_id= pfs_stmt->m_nesting_event_id; + else + pfs->m_owner_event_id= pfs_stmt->m_event_id; + } + + /* Insert this record. */ + pfs->m_lock.dirty_to_allocated(& dirty_state); + } + + return pfs; +} + +void delete_prepared_stmt(PFS_prepared_stmt *pfs) +{ + global_prepared_stmt_container.deallocate(pfs); + return; +} diff --git a/storage/perfschema/pfs_prepared_stmt.h b/storage/perfschema/pfs_prepared_stmt.h new file mode 100644 index 00000000000..4638266cce7 --- /dev/null +++ b/storage/perfschema/pfs_prepared_stmt.h @@ -0,0 +1,96 @@ +/* Copyright (c) 2014, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef PFS_PS_H +#define PFS_PS_H + +/** + @file storage/perfschema/pfs_prepared_statement.h + Stored Program data structures (declarations). +*/ + +#include "pfs_stat.h" +#include "include/mysql/psi/psi.h" +#include "include/mysql/psi/mysql_ps.h" +#include "pfs_program.h" + +#define PS_NAME_LENGTH NAME_LEN + +struct PFS_ALIGNED PFS_prepared_stmt : public PFS_instr +{ + /** Column OBJECT_INSTANCE_BEGIN */ + const void *m_identity; + + /** STATEMENT_ID */ + ulonglong m_stmt_id; + + /** STATEMENT_NAME */ + char m_stmt_name[PS_NAME_LENGTH]; + uint m_stmt_name_length; + + /** SQL_TEXT */ + char m_sqltext[COL_INFO_SIZE]; + uint m_sqltext_length; + + /** Column OWNER_THREAD_ID */ + ulonglong m_owner_thread_id; + + /** Column OWNER_EVENT_ID. */ + ulonglong m_owner_event_id; + + /** Column OBJECT_OWNER_TYPE. */ + enum_object_type m_owner_object_type; + + /** Column OBJECT_OWNER_SCHEMA. */ + char m_owner_object_schema[COL_OBJECT_SCHEMA_SIZE]; + uint m_owner_object_schema_length; + + /** Column OBJECT_OWNER_NAME. */ + char m_owner_object_name[COL_OBJECT_NAME_SIZE]; + uint m_owner_object_name_length; + + /** COLUMN TIMER_PREPARE. Prepared stmt prepare stat. */ + PFS_single_stat m_prepare_stat; + + /** COLUMN COUNT_REPREPARE. Prepared stmt reprepare stat. */ + PFS_single_stat m_reprepare_stat; + + /** Prepared stmt execution stat. */ + PFS_statement_stat m_execute_stat; + + /** Reset data for this record. */ + void reset_data(); +}; + +int init_prepared_stmt(const PFS_global_param *param); +void cleanup_prepared_stmt(void); + +void reset_prepared_stmt_instances(); + +PFS_prepared_stmt* +create_prepared_stmt(void *identity, + PFS_thread *thread, PFS_program *pfs_program, + PFS_events_statements *pfs_stmt, uint stmt_id, + const char* stmt_name, uint stmt_name_length, + const char* sqltext, uint sqltext_length); +void delete_prepared_stmt(PFS_prepared_stmt *pfs_ps); +#endif diff --git a/storage/perfschema/pfs_program.cc b/storage/perfschema/pfs_program.cc new file mode 100644 index 00000000000..e8808b0b63a --- /dev/null +++ b/storage/perfschema/pfs_program.cc @@ -0,0 +1,322 @@ +/* Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/pfs_program.cc + Statement Digest data structures (implementation). +*/ + +/* + This code needs extra visibility in the lexer structures +*/ + +#include "my_global.h" +#include "my_sys.h" +#include "pfs_instr.h" +#include "pfs_program.h" +#include "pfs_global.h" +#include "sql_string.h" +#include "pfs_setup_object.h" +#include "pfs_buffer_container.h" +#include "mysqld.h" //system_charset_info +#include <string.h> + +LF_HASH program_hash; +static bool program_hash_inited= false; + +/** + Initialize table EVENTS_STATEMENTS_SUMMARY_BY_PROGRAM. + @param param performance schema sizing +*/ +int init_program(const PFS_global_param *param) +{ + if (global_program_container.init(param->m_program_sizing)) + return 1; + + reset_esms_by_program(); + return 0; +} + +/** Cleanup table EVENTS_STATEMENTS_SUMMARY_BY_PROGRAM. */ +void cleanup_program(void) +{ + global_program_container.cleanup(); +} + +C_MODE_START +static uchar *program_hash_get_key(const uchar *entry, size_t *length, + my_bool) +{ + const PFS_program * const *typed_entry; + const PFS_program *program; + const void *result; + typed_entry= reinterpret_cast<const PFS_program* const *> (entry); + DBUG_ASSERT(typed_entry != NULL); + program= *typed_entry; + DBUG_ASSERT(program != NULL); + *length= program->m_key.m_key_length; + result= program->m_key.m_hash_key; + return const_cast<uchar*> (reinterpret_cast<const uchar*> (result)); +} +C_MODE_END + +/** + Initialize the program hash. + @return 0 on success +*/ +int init_program_hash(const PFS_global_param *param) +{ + if ((! program_hash_inited) && (param->m_program_sizing != 0)) + { + lf_hash_init(&program_hash, sizeof(PFS_program*), LF_HASH_UNIQUE, + 0, 0, program_hash_get_key, &my_charset_bin); + program_hash_inited= true; + } + return 0; +} + +/** Cleanup the program hash. */ +void cleanup_program_hash(void) +{ + if (program_hash_inited) + { + lf_hash_destroy(&program_hash); + program_hash_inited= false; + } +} + +static void set_program_key(PFS_program_key *key, + enum_object_type object_type, + const char *object_name, uint object_name_length, + const char *schema_name, uint schema_name_length) +{ + DBUG_ASSERT(object_name_length <= COL_OBJECT_NAME_SIZE); + DBUG_ASSERT(schema_name_length <= COL_OBJECT_SCHEMA_SIZE); + + /* + To make sure generated key is case insensitive, + convert object_name/schema_name to lowercase. + */ + + char *ptr= &key->m_hash_key[0]; + + ptr[0]= object_type; + ptr++; + + if (object_name_length > 0) + { + char tmp_object_name[COL_OBJECT_NAME_SIZE + 1]; + memcpy(tmp_object_name, object_name, object_name_length); + tmp_object_name[object_name_length]= '\0'; + my_casedn_str(system_charset_info, tmp_object_name); + memcpy(ptr, tmp_object_name, object_name_length); + ptr+= object_name_length; + } + ptr[0]= 0; + ptr++; + + if (schema_name_length > 0) + { + char tmp_schema_name[COL_OBJECT_SCHEMA_SIZE + 1]; + memcpy(tmp_schema_name, schema_name, schema_name_length); + tmp_schema_name[schema_name_length]='\0'; + my_casedn_str(system_charset_info, tmp_schema_name); + memcpy(ptr, tmp_schema_name, schema_name_length); + ptr+= schema_name_length; + } + ptr[0]= 0; + ptr++; + + key->m_key_length= ptr - &key->m_hash_key[0]; +} + + + +void PFS_program::reset_data() +{ + m_sp_stat.reset(); + m_stmt_stat.reset(); +} + +static void fct_reset_esms_by_program(PFS_program *pfs) +{ + pfs->reset_data(); +} + +void reset_esms_by_program() +{ + global_program_container.apply_all(fct_reset_esms_by_program); +} + +static LF_PINS* get_program_hash_pins(PFS_thread *thread) +{ + if (unlikely(thread->m_program_hash_pins == NULL)) + { + if (! program_hash_inited) + return NULL; + thread->m_program_hash_pins= lf_hash_get_pins(&program_hash); + } + return thread->m_program_hash_pins; +} + +PFS_program* +find_or_create_program(PFS_thread *thread, + enum_object_type object_type, + const char *object_name, + uint object_name_length, + const char *schema_name, + uint schema_name_length) +{ + bool is_enabled, is_timed; + + LF_PINS *pins= get_program_hash_pins(thread); + if (unlikely(pins == NULL)) + { + global_program_container.m_lost++; + return NULL; + } + + /* Prepare program key */ + PFS_program_key key; + set_program_key(&key, object_type, + object_name, object_name_length, + schema_name, schema_name_length); + + PFS_program **entry; + PFS_program *pfs= NULL; + uint retry_count= 0; + const uint retry_max= 3; + pfs_dirty_state dirty_state; + +search: + entry= reinterpret_cast<PFS_program**> + (lf_hash_search(&program_hash, pins, + key.m_hash_key, key.m_key_length)); + + if (entry && (entry != MY_ERRPTR)) + { + /* If record already exists then return its pointer. */ + pfs= *entry; + lf_hash_search_unpin(pins); + return pfs; + } + + lf_hash_search_unpin(pins); + + /* + First time while inserting this record to program array we need to + find out if it is enabled and timed. + */ + lookup_setup_object(thread, object_type, + schema_name, schema_name_length, + object_name, object_name_length, + &is_enabled, &is_timed); + + /* Else create a new record in program stat array. */ + pfs= global_program_container.allocate(& dirty_state); + if (pfs != NULL) + { + /* Do the assignments. */ + memcpy(pfs->m_key.m_hash_key, key.m_hash_key, key.m_key_length); + pfs->m_key.m_key_length= key.m_key_length; + pfs->m_type= object_type; + + pfs->m_object_name= pfs->m_key.m_hash_key + 1; + pfs->m_object_name_length= object_name_length; + pfs->m_schema_name= pfs->m_object_name + object_name_length + 1; + pfs->m_schema_name_length= schema_name_length; + pfs->m_enabled= is_enabled; + pfs->m_timed= is_timed; + + /* Insert this record. */ + pfs->m_lock.dirty_to_allocated(& dirty_state); + int res= lf_hash_insert(&program_hash, pins, &pfs); + + if (likely(res == 0)) + { + return pfs; + } + + global_program_container.deallocate(pfs); + + if (res > 0) + { + /* Duplicate insert by another thread */ + if (++retry_count > retry_max) + { + /* Avoid infinite loops */ + global_program_container.m_lost++; + return NULL; + } + goto search; + } + /* OOM in lf_hash_insert */ + global_program_container.m_lost++; + return NULL; + } + + return NULL; +} + +void drop_program(PFS_thread *thread, + enum_object_type object_type, + const char *object_name, + uint object_name_length, + const char *schema_name, + uint schema_name_length) +{ + LF_PINS *pins= get_program_hash_pins(thread); + if (unlikely(pins == NULL)) + return; + + /* Prepare program key */ + PFS_program_key key; + set_program_key(&key, object_type, + object_name, object_name_length, + schema_name, schema_name_length); + + PFS_program **entry; + entry= reinterpret_cast<PFS_program**> + (lf_hash_search(&program_hash, pins, + key.m_hash_key, key.m_key_length)); + + if (entry && (entry != MY_ERRPTR)) + { + PFS_program *pfs= NULL; + pfs= *entry; + + lf_hash_delete(&program_hash, pins, + key.m_hash_key, key.m_key_length); + global_program_container.deallocate(pfs); + } + + lf_hash_search_unpin(pins); + return; +} + +void PFS_program::refresh_setup_object_flags(PFS_thread *thread) +{ + lookup_setup_object(thread, m_type, + m_schema_name, m_schema_name_length, + m_object_name, m_object_name_length, + &m_enabled, &m_timed); +} diff --git a/storage/perfschema/pfs_program.h b/storage/perfschema/pfs_program.h new file mode 100644 index 00000000000..0cbd24b8699 --- /dev/null +++ b/storage/perfschema/pfs_program.h @@ -0,0 +1,103 @@ +/* Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef PFS_PROGRAM_H +#define PFS_PROGRAM_H + +/** + @file storage/perfschema/pfs_program.h + Stored Program data structures (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_stat.h" + +#define PROGRAM_HASH_KEY_LENGTH sizeof(enum_object_type) + COL_OBJECT_NAME_SIZE + 1 + COL_OBJECT_SCHEMA_SIZE + 1 + +extern LF_HASH program_hash; + +/** + Hash key for a program. +*/ +struct PFS_program_key +{ + /** + Hash search key. + This has to be a string for LF_HASH, + the format is "<object_type><0x00><object_name><0x00><schema_name><0x00>" + */ + char m_hash_key[PROGRAM_HASH_KEY_LENGTH]; + uint m_key_length; +}; + +struct PFS_ALIGNED PFS_program : public PFS_instr +{ + /** Object type. */ + enum_object_type m_type; + + /** Object name. */ + const char *m_object_name; + int m_object_name_length; + + /** Object Schema name. */ + const char *m_schema_name; + int m_schema_name_length; + + /** Hash key */ + PFS_program_key m_key; + + /** Sub statement stat. */ + PFS_statement_stat m_stmt_stat; + + /** Stored program stat. */ + PFS_sp_stat m_sp_stat; + + /** Referesh setup object flags. */ + void refresh_setup_object_flags(PFS_thread* thread); + + /** Reset data for this record. */ + void reset_data(); +}; + +int init_program(const PFS_global_param *param); +void cleanup_program(void); +int init_program_hash(const PFS_global_param *param); +void cleanup_program_hash(void); + +void reset_esms_by_program(); + +PFS_program* +find_or_create_program(PFS_thread *thread, + enum_object_type object_type, + const char *object_name, + uint object_name_length, + const char *schema, + uint schema_length); + +void +drop_program(PFS_thread *thread, + enum_object_type object_type, + const char *object_name, + uint object_name_length, + const char *schema_name, + uint schema_name_length); +#endif diff --git a/storage/perfschema/pfs_server.cc b/storage/perfschema/pfs_server.cc index f3f22bbcf4f..63deba92de8 100644 --- a/storage/perfschema/pfs_server.cc +++ b/storage/perfschema/pfs_server.cc @@ -32,10 +32,12 @@ #include "pfs.h" #include "pfs_global.h" #include "pfs_instr_class.h" +#include "pfs_builtin_memory.h" #include "pfs_instr.h" #include "pfs_events_waits.h" #include "pfs_events_stages.h" #include "pfs_events_statements.h" +#include "pfs_events_transactions.h" #include "pfs_timer.h" #include "pfs_setup_actor.h" #include "pfs_setup_object.h" @@ -44,6 +46,9 @@ #include "pfs_account.h" #include "pfs_defaults.h" #include "pfs_digest.h" +#include "pfs_program.h" +//#include "template_utils.h" +#include "pfs_prepared_stmt.h" PFS_global_param pfs_param; @@ -56,48 +61,69 @@ C_MODE_END static void cleanup_performance_schema(void); void cleanup_instrument_config(void); -struct PSI_bootstrap* -initialize_performance_schema(PFS_global_param *param) +void pre_initialize_performance_schema() { pfs_initialized= false; + init_all_builtin_memory_class(); + 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 (my_create_thread_local_key(&THR_PFS, destroy_pfs_thread)) + return; + if (my_create_thread_local_key(&THR_PFS_VG, NULL)) // global_variables + return; + if (my_create_thread_local_key(&THR_PFS_SV, NULL)) // session_variables + return; + if (my_create_thread_local_key(&THR_PFS_VBT, NULL)) // variables_by_thread + return; + if (my_create_thread_local_key(&THR_PFS_SG, NULL)) // global_status + return; + if (my_create_thread_local_key(&THR_PFS_SS, NULL)) // session_status + return; + if (my_create_thread_local_key(&THR_PFS_SBT, NULL)) // status_by_thread + return; + if (my_create_thread_local_key(&THR_PFS_SBU, NULL)) // status_by_user + return; + if (my_create_thread_local_key(&THR_PFS_SBH, NULL)) // status_by_host + return; + if (my_create_thread_local_key(&THR_PFS_SBA, NULL)) // status_by_account + return; + + THR_PFS_initialized= true; +} - if (! param->m_enabled) +struct PSI_bootstrap* +initialize_performance_schema(PFS_global_param *param) +{ + if (!THR_PFS_initialized) { - /* - The performance schema is disabled in the startup command line. - All the instrumentation is turned off. - */ - pfs_enabled= 0; + /* Pre-initialization failed. */ return NULL; } - pfs_enabled= TRUE; - init_timers(); + pfs_enabled= param->m_enabled; + pfs_automated_sizing(param); + init_timers(); init_event_name_sizing(param); register_global_classes(); - if (pthread_key_create(&THR_PFS, destroy_pfs_thread)) - return NULL; - - THR_PFS_initialized= true; - if (init_sync_class(param->m_mutex_class_sizing, param->m_rwlock_class_sizing, param->m_cond_class_sizing) || init_thread_class(param->m_thread_class_sizing) || init_table_share(param->m_table_share_sizing) || + init_table_share_lock_stat(param->m_table_lock_stat_sizing) || + init_table_share_index_stat(param->m_index_stat_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_memory_class(param->m_memory_class_sizing) || init_instruments(param) || init_events_waits_history_long( param->m_events_waits_history_long_sizing) || @@ -105,20 +131,25 @@ initialize_performance_schema(PFS_global_param *param) 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_events_transactions_history_long( + param->m_events_transactions_history_long_sizing) || + init_file_hash(param) || + init_table_share_hash(param) || init_setup_actor(param) || - init_setup_actor_hash() || + init_setup_actor_hash(param) || init_setup_object(param) || - init_setup_object_hash() || + init_setup_object_hash(param) || init_host(param) || - init_host_hash() || + init_host_hash(param) || init_user(param) || - init_user_hash() || + init_user_hash(param) || init_account(param) || - init_account_hash() || + init_account_hash(param) || init_digest(param) || - init_digest_hash()) + init_digest_hash(param) || + init_program(param) || + init_program_hash(param) || + init_prepared_stmt(param)) { /* The performance schema initialization failed. @@ -128,24 +159,53 @@ initialize_performance_schema(PFS_global_param *param) return NULL; } + if (param->m_enabled) + { + /** 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_transactions_current= param->m_consumer_events_transactions_current_enabled; + flag_events_transactions_history= param->m_consumer_events_transactions_history_enabled; + flag_events_transactions_history_long= param->m_consumer_events_transactions_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; + } + else + { + flag_events_stages_current= false; + flag_events_stages_history= false; + flag_events_stages_history_long= false; + flag_events_statements_current= false; + flag_events_statements_history= false; + flag_events_statements_history_long= false; + flag_events_transactions_current= false; + flag_events_transactions_history= false; + flag_events_transactions_history_long= false; + flag_events_waits_current= false; + flag_events_waits_history= false; + flag_events_waits_history_long= false; + flag_global_instrumentation= false; + flag_thread_instrumentation= false; + flag_statements_digest= false; + } + 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; + if (param->m_enabled) + { + install_default_setup(&PFS_bootstrap); + return &PFS_bootstrap; + } + + return NULL; } static void destroy_pfs_thread(void *key) @@ -169,50 +229,131 @@ static void destroy_pfs_thread(void *key) static void cleanup_performance_schema(void) { + /* + my.cnf options + */ + cleanup_instrument_config(); - cleanup_instruments(); + + /* + All the LF_HASH + */ + + cleanup_setup_actor_hash(); + cleanup_setup_object_hash(); + cleanup_account_hash(); + cleanup_host_hash(); + cleanup_user_hash(); + cleanup_program_hash(); + cleanup_table_share_hash(); + cleanup_file_hash(); + cleanup_digest_hash(); + + /* + Then the lookup tables + */ + + cleanup_setup_actor(); + cleanup_setup_object(); + + /* + Then the history tables + */ + + cleanup_events_waits_history_long(); + cleanup_events_stages_history_long(); + cleanup_events_statements_history_long(); + cleanup_events_transactions_history_long(); + + /* + Then the various aggregations + */ + + cleanup_digest(); + cleanup_account(); + cleanup_host(); + cleanup_user(); + + /* + Then the instrument classes. + Once a class is cleaned up, + find_XXX_class(key) + will return PSI_NOT_INSTRUMENTED + */ + cleanup_program(); + cleanup_prepared_stmt(); cleanup_sync_class(); cleanup_thread_class(); cleanup_table_share(); + cleanup_table_share_lock_stat(); + cleanup_table_share_index_stat(); cleanup_file_class(); cleanup_stage_class(); cleanup_statement_class(); cleanup_socket_class(); - cleanup_events_waits_history_long(); - cleanup_events_stages_history_long(); - cleanup_events_statements_history_long(); - cleanup_table_share_hash(); - cleanup_file_hash(); - cleanup_setup_actor(); - cleanup_setup_actor_hash(); - cleanup_setup_object(); - cleanup_setup_object_hash(); - cleanup_host(); - cleanup_host_hash(); - cleanup_user(); - cleanup_user_hash(); - cleanup_account(); - cleanup_account_hash(); - cleanup_digest(); - cleanup_digest_hash(); + cleanup_memory_class(); + + cleanup_instruments(); } void shutdown_performance_schema(void) { pfs_initialized= false; + + /* disable everything, especially for this thread. */ + flag_events_stages_current= false; + flag_events_stages_history= false; + flag_events_stages_history_long= false; + flag_events_statements_current= false; + flag_events_statements_history= false; + flag_events_statements_history_long= false; + flag_events_transactions_current= false; + flag_events_transactions_history= false; + flag_events_transactions_history_long= false; + flag_events_waits_current= false; + flag_events_waits_history= false; + flag_events_waits_history_long= false; + flag_global_instrumentation= false; + flag_thread_instrumentation= false; + flag_statements_digest= false; + + global_table_io_class.m_enabled= false; + global_table_lock_class.m_enabled= false; + global_idle_class.m_enabled= false; + global_metadata_class.m_enabled= false; + global_transaction_class.m_enabled= false; + cleanup_performance_schema(); -#if 0 /* Be careful to not delete un-initialized keys, this would affect key 0, which is THR_KEY_mysys, */ if (THR_PFS_initialized) { - my_pthread_setspecific_ptr(THR_PFS, NULL); - pthread_key_delete(THR_PFS); + my_set_thread_local(THR_PFS, NULL); + my_set_thread_local(THR_PFS_VG, NULL); // global_variables + my_set_thread_local(THR_PFS_SV, NULL); // session_variables + my_set_thread_local(THR_PFS_VBT, NULL); // variables_by_thread + my_set_thread_local(THR_PFS_SG, NULL); // global_status + my_set_thread_local(THR_PFS_SS, NULL); // session_status + my_set_thread_local(THR_PFS_SBT, NULL); // status_by_thread + my_set_thread_local(THR_PFS_SBU, NULL); // status_by_user + my_set_thread_local(THR_PFS_SBH, NULL); // status_by_host + my_set_thread_local(THR_PFS_SBA, NULL); // status_by_account + + my_delete_thread_local_key(THR_PFS); + my_delete_thread_local_key(THR_PFS_VG); + my_delete_thread_local_key(THR_PFS_SV); + my_delete_thread_local_key(THR_PFS_VBT); + my_delete_thread_local_key(THR_PFS_SG); + my_delete_thread_local_key(THR_PFS_SS); + my_delete_thread_local_key(THR_PFS_SBT); + my_delete_thread_local_key(THR_PFS_SBU); + my_delete_thread_local_key(THR_PFS_SBH); + my_delete_thread_local_key(THR_PFS_SBA); + THR_PFS_initialized= false; } -#endif } /** @@ -221,27 +362,22 @@ void shutdown_performance_schema(void) */ 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; + pfs_instr_config_array= new Pfs_instr_config_array((PSI_memory_key)PSI_NOT_INSTRUMENTED); } /** - 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. + Deallocate the PFS_INSTRUMENT array. */ 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)) + if (pfs_instr_config_array != NULL) { - 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); + PFS_instr_config **it= pfs_instr_config_array->front(); + for ( ; it != pfs_instr_config_array->end(); it++) + my_free(*it); } + delete pfs_instr_config_array; + pfs_instr_config_array= NULL; } /** @@ -260,16 +396,17 @@ int add_pfs_instr_to_array(const char* name, const char* value) size_t 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) + PFS_instr_config* e = (PFS_instr_config*)my_malloc(PSI_NOT_INSTRUMENTED, + 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= (uint)name_length; e->m_name[name_length]= '\0'; - + /* Set flags accordingly */ if (!my_strcasecmp(&my_charset_latin1, value, "counted")) { @@ -301,7 +438,7 @@ int add_pfs_instr_to_array(const char* name, const char* value) } /* Add to the array of default startup options */ - if (insert_dynamic(&pfs_instr_config_array, &e)) + if (pfs_instr_config_array->push(e)) { my_free(e); return 1; diff --git a/storage/perfschema/pfs_server.h b/storage/perfschema/pfs_server.h index 9f904e6545b..68f6f71d619 100644 --- a/storage/perfschema/pfs_server.h +++ b/storage/perfschema/pfs_server.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2015, 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, version 2.0, @@ -28,11 +28,14 @@ Private interface for the server (declarations). */ +#define PFS_AUTOSCALE_VALUE (-1) +#define PFS_AUTOSIZE_VALUE (-1) + #ifndef PFS_MAX_MUTEX_CLASS - #define PFS_MAX_MUTEX_CLASS 200 + #define PFS_MAX_MUTEX_CLASS 210 #endif #ifndef PFS_MAX_RWLOCK_CLASS - #define PFS_MAX_RWLOCK_CLASS 40 + #define PFS_MAX_RWLOCK_CLASS 50 #endif #ifndef PFS_MAX_COND_CLASS #define PFS_MAX_COND_CLASS 90 @@ -41,7 +44,7 @@ #define PFS_MAX_THREAD_CLASS 50 #endif #ifndef PFS_MAX_FILE_CLASS - #define PFS_MAX_FILE_CLASS 50 + #define PFS_MAX_FILE_CLASS 80 #endif #ifndef PFS_MAX_FILE_HANDLE #define PFS_MAX_FILE_HANDLE 32768 @@ -49,28 +52,29 @@ #ifndef PFS_MAX_SOCKET_CLASS #define PFS_MAX_SOCKET_CLASS 10 #endif -#ifndef PFS_MAX_SETUP_ACTOR - #define PFS_MAX_SETUP_ACTOR 100 -#endif -#ifndef PFS_MAX_SETUP_OBJECT - #define PFS_MAX_SETUP_OBJECT 100 -#endif #ifndef PFS_MAX_STAGE_CLASS #define PFS_MAX_STAGE_CLASS 160 #endif #ifndef PFS_STATEMENTS_STACK_SIZE #define PFS_STATEMENTS_STACK_SIZE 10 #endif -#ifndef PFS_CONNECT_ATTRS_SIZE - #define PFS_SESSION_CONNECT_ATTRS_SIZE 2048 +#ifndef PFS_MAX_MEMORY_CLASS + #define PFS_MAX_MEMORY_CLASS 320 #endif +/** Sizing hints, from the server configuration. */ struct PFS_sizing_hints { + /** Value of @c Sys_table_def_size */ long m_table_definition_cache; + /** Value of @c Sys_table_cache_size */ long m_table_open_cache; + /** Value of @c Sys_max_connections */ long m_max_connections; + /** Value of @c Sys_open_files_limit */ long m_open_files_limit; + /** Value of @c Sys_max_prepared_stmt_count */ + long m_max_prepared_stmt_count; }; /** Performance schema global sizing parameters. */ @@ -85,6 +89,9 @@ struct PFS_global_param 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_transactions_current_enabled; + bool m_consumer_events_transactions_history_enabled; + bool m_consumer_events_transactions_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; @@ -121,6 +128,16 @@ struct PFS_global_param */ long m_table_share_sizing; /** + Maximum number of lock statistics collected for tables. + @sa table_lock_stat_lost. + */ + long m_table_lock_stat_sizing; + /** + Maximum number of index statistics collected for tables. + @sa table_index_lost. + */ + long m_index_stat_sizing; + /** Maximum number of instrumented file classes. @sa file_class_lost. */ @@ -162,7 +179,7 @@ struct PFS_global_param long m_file_handle_sizing; /** Maxium number of instrumented socket instances - @sa socket_lost + @sa socket_lost */ long m_socket_sizing; /** @@ -175,9 +192,9 @@ struct PFS_global_param /** 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; + long m_setup_actor_sizing; /** Maximum number of rows in table SETUP_OBJECTS. */ - ulong m_setup_object_sizing; + long m_setup_object_sizing; /** Maximum number of rows in table HOSTS. */ long m_host_sizing; /** Maximum number of rows in table USERS. */ @@ -198,16 +215,36 @@ struct PFS_global_param @sa statement_class_lost. */ ulong m_statement_class_sizing; - /** Maximum number of rows per thread in table EVENTS_STATEMENT_HISTORY. */ + /** Maximum number of rows per thread in table EVENTS_STATEMENTS_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 programs to be captured */ + long m_program_sizing; + /** Maximum number of prepared statements to be captured */ + long m_prepared_stmt_sizing; + /** Maximum number of rows per thread in table EVENTS_TRANSACTIONS_HISTORY. */ + long m_events_transactions_history_sizing; + /** Maximum number of rows in table EVENTS_TRANSACTIONS_HISTORY_LONG. */ + long m_events_transactions_history_long_sizing; + /** Maximum number of session attribute strings per thread */ long m_session_connect_attrs_sizing; + /** Maximum size of statement stack */ + ulong m_statement_stack_sizing; + + /** + Maximum number of instrumented memory classes. + @sa memory_class_lost. + */ + ulong m_memory_class_sizing; + + long m_metadata_lock_sizing; long m_max_digest_length; + ulong m_max_sql_text_length; /** Sizing hints, for auto tuning. */ PFS_sizing_hints m_hints; @@ -220,9 +257,17 @@ struct PFS_global_param extern PFS_global_param pfs_param; /** + Null initialization. + Disable all instrumentation, size all internal buffers to 0. + This pre initialization step is needed to ensure that events can be collected + and discarded, until such time @c initialize_performance_schema() is called. +*/ +void pre_initialize_performance_schema(); + +/** Initialize the performance schema. @param param Size parameters to use. - @return A boostrap handle, or NULL. + @return A bootstrap handle, or NULL. */ struct PSI_bootstrap* initialize_performance_schema(PFS_global_param *param); @@ -233,14 +278,19 @@ 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. + When running in bootstrap mode, ACL restrictions are relaxed, + to allow the bootstrap 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); /** + Reset the aggregated status counter stats. +*/ +void reset_pfs_status_stats(); + +/** Initialize the dynamic array holding individual instrument settings collected from the server configuration options. */ diff --git a/storage/perfschema/pfs_setup_actor.cc b/storage/perfschema/pfs_setup_actor.cc index c4cec6c9ff8..96b367b65db 100644 --- a/storage/perfschema/pfs_setup_actor.cc +++ b/storage/perfschema/pfs_setup_actor.cc @@ -32,23 +32,15 @@ #include "pfs_stat.h" #include "pfs_instr.h" #include "pfs_setup_actor.h" +#include "pfs_account.h" #include "pfs_global.h" +#include "pfs_buffer_container.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. */ @@ -61,27 +53,13 @@ static bool setup_actor_hash_inited= false; */ 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; + return global_setup_actor_container.init(param->m_setup_actor_sizing); } /** Cleanup all the setup actor buffers. */ void cleanup_setup_actor(void) { - pfs_free(setup_actor_array); - setup_actor_array= NULL; - setup_actor_max= 0; + global_setup_actor_container.cleanup(); } C_MODE_START @@ -105,13 +83,13 @@ C_MODE_END Initialize the setup actor hash. @return 0 on success */ -int init_setup_actor_hash(void) +int init_setup_actor_hash(const PFS_global_param *param) { - if ((! setup_actor_hash_inited) && (setup_actor_max > 0)) + if ((! setup_actor_hash_inited) && (param->m_setup_actor_sizing != 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.size= param->m_setup_actor_sizing; */ setup_actor_hash_inited= true; } return 0; @@ -162,11 +140,9 @@ static void set_setup_actor_key(PFS_setup_actor_key *key, key->m_key_length= (uint)(ptr - &key->m_hash_key[0]); } -int insert_setup_actor(const String *user, const String *host, const String *role) +int insert_setup_actor(const String *user, const String *host, const String *role, + bool enabled, bool history) { - 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; @@ -175,46 +151,39 @@ int insert_setup_actor(const String *user, const String *host, const String *rol 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; + pfs_dirty_state dirty_state; - while (++attempts <= setup_actor_max) + pfs= global_setup_actor_container.allocate(& dirty_state); + if (pfs != NULL) { - /* 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()) + 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(); + pfs->m_enabled= enabled; + pfs->m_history= history; + + int res; + pfs->m_lock.dirty_to_allocated(& dirty_state); + res= lf_hash_insert(&setup_actor_hash, pins, &pfs); + if (likely(res == 0)) { - 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; - } + update_setup_actors_derived_flags(); + return 0; } + + global_setup_actor_container.deallocate(pfs); + + if (res > 0) + return HA_ERR_FOUND_DUPP_KEY; + return HA_ERR_OUT_OF_MEM; } return HA_ERR_RECORD_FILE_FULL; @@ -244,14 +213,36 @@ int delete_setup_actor(const String *user, const String *host, const String *rol { 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(); + global_setup_actor_container.deallocate(pfs); } lf_hash_search_unpin(pins); + update_setup_actors_derived_flags(); + return 0; } +class Proc_reset_setup_actor + : public PFS_buffer_processor<PFS_setup_actor> +{ +public: + Proc_reset_setup_actor(LF_PINS* pins) + : m_pins(pins) + {} + + virtual void operator()(PFS_setup_actor *pfs) + { + lf_hash_delete(&setup_actor_hash, m_pins, + pfs->m_key.m_hash_key, pfs->m_key.m_key_length); + + global_setup_actor_container.deallocate(pfs); + } + +private: + LF_PINS* m_pins; +}; + int reset_setup_actor() { PFS_thread *thread= PFS_thread::get_current_thread(); @@ -262,18 +253,11 @@ int reset_setup_actor() 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; + Proc_reset_setup_actor proc(pins); + // FIXME: delete helper instead + global_setup_actor_container.apply(proc); - 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(); - } - } + update_setup_actors_derived_flags(); return 0; } @@ -291,7 +275,7 @@ long setup_actor_count() void lookup_setup_actor(PFS_thread *thread, const char *user, uint user_length, const char *host, uint host_length, - bool *enabled) + bool *enabled, bool *history) { PFS_setup_actor_key key; PFS_setup_actor **entry; @@ -301,6 +285,7 @@ void lookup_setup_actor(PFS_thread *thread, if (unlikely(pins == NULL)) { *enabled= false; + *history= false; return; } @@ -330,15 +315,28 @@ void lookup_setup_actor(PFS_thread *thread, if (entry && (entry != MY_ERRPTR)) { + PFS_setup_actor *pfs= *entry; lf_hash_search_unpin(pins); - *enabled= true; + *enabled= pfs->m_enabled; + *history= pfs->m_history; return; } lf_hash_search_unpin(pins); } *enabled= false; + *history= false; return; } +int update_setup_actors_derived_flags() +{ + PFS_thread *thread= PFS_thread::get_current_thread(); + if (unlikely(thread == NULL)) + return HA_ERR_OUT_OF_MEM; + + update_accounts_derived_flags(thread); + return 0; +} + /** @} */ diff --git a/storage/perfschema/pfs_setup_actor.h b/storage/perfschema/pfs_setup_actor.h index 613d5454a9c..3d00c52aa32 100644 --- a/storage/perfschema/pfs_setup_actor.h +++ b/storage/perfschema/pfs_setup_actor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -33,6 +33,7 @@ #include "lf.h" struct PFS_global_param; +class PFS_opaque_container_page; /* WL#988 Roles Not implemented yet */ #define ROLENAME_LENGTH 64 @@ -74,30 +75,35 @@ struct PFS_ALIGNED PFS_setup_actor const char *m_rolename; /** Length of @c m_rolename. */ uint m_rolename_length; + /** ENABLED flag. */ + bool m_enabled; + /** HISTORY flag. */ + bool m_history; + /** Container page. */ + PFS_opaque_container_page *m_page; }; int init_setup_actor(const PFS_global_param *param); void cleanup_setup_actor(void); -int init_setup_actor_hash(void); +int init_setup_actor_hash(const PFS_global_param *param); 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 insert_setup_actor(const String *user, const String *host, + const String *role, bool enabled, bool history); +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); + bool *enabled, bool *history); -/* For iterators and show status. */ +/** Update derived flags for all setup_actors. */ +int update_setup_actors_derived_flags(); -extern ulong setup_actor_max; - -/* Exposing the data directly, for iterators. */ - -extern PFS_setup_actor *setup_actor_array; +/* For show status. */ extern LF_HASH setup_actor_hash; diff --git a/storage/perfschema/pfs_setup_object.cc b/storage/perfschema/pfs_setup_object.cc index f33030e927f..9325b84997f 100644 --- a/storage/perfschema/pfs_setup_object.cc +++ b/storage/perfschema/pfs_setup_object.cc @@ -34,6 +34,7 @@ #include "pfs_instr.h" #include "pfs_setup_object.h" #include "pfs_global.h" +#include "pfs_buffer_container.h" /** @addtogroup Performance_schema_buffers @@ -42,10 +43,6 @@ 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; @@ -56,27 +53,13 @@ static bool setup_object_hash_inited= false; */ 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; + return global_setup_object_container.init(param->m_setup_object_sizing); } /** Cleanup all the setup object buffers. */ void cleanup_setup_object(void) { - pfs_free(setup_object_array); - setup_object_array= NULL; - setup_object_max= 0; + global_setup_object_container.cleanup(); } C_MODE_START @@ -100,13 +83,12 @@ C_MODE_END Initialize the setup objects hash. @return 0 on success */ -int init_setup_object_hash(void) +int init_setup_object_hash(const PFS_global_param *param) { - if ((! setup_object_hash_inited) && (setup_object_max > 0)) + if ((! setup_object_hash_inited) && (param->m_setup_object_sizing != 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; @@ -158,9 +140,6 @@ static void set_setup_object_key(PFS_setup_object_key *key, 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; @@ -169,47 +148,37 @@ int insert_setup_object(enum_object_type object_type, const String *schema, 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; + pfs_dirty_state dirty_state; - while (++attempts <= setup_object_max) + pfs= global_setup_object_container.allocate(& dirty_state); + if (pfs != NULL) { - /* 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()) + 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; + pfs->m_lock.dirty_to_allocated(& dirty_state); + res= lf_hash_insert(&setup_object_hash, pins, &pfs); + if (likely(res == 0)) { - 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; - } + setup_objects_version++; + return 0; } + + global_setup_object_container.deallocate(pfs); + + 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; @@ -239,7 +208,7 @@ int delete_setup_object(enum_object_type object_type, const String *schema, { 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(); + global_setup_object_container.deallocate(pfs); } lf_hash_search_unpin(pins); @@ -248,6 +217,26 @@ int delete_setup_object(enum_object_type object_type, const String *schema, return 0; } +class Proc_reset_setup_object + : public PFS_buffer_processor<PFS_setup_object> +{ +public: + Proc_reset_setup_object(LF_PINS* pins) + : m_pins(pins) + {} + + virtual void operator()(PFS_setup_object *pfs) + { + lf_hash_delete(&setup_object_hash, m_pins, + pfs->m_key.m_hash_key, pfs->m_key.m_key_length); + + global_setup_object_container.deallocate(pfs); + } + +private: + LF_PINS* m_pins; +}; + int reset_setup_object() { PFS_thread *thread= PFS_thread::get_current_thread(); @@ -258,18 +247,9 @@ int reset_setup_object() 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(); - } - } + Proc_reset_setup_object proc(pins); + // FIXME: delete helper instead + global_setup_object_container.apply(proc); setup_objects_version++; return 0; diff --git a/storage/perfschema/pfs_setup_object.h b/storage/perfschema/pfs_setup_object.h index ee40742941c..d49be341bbe 100644 --- a/storage/perfschema/pfs_setup_object.h +++ b/storage/perfschema/pfs_setup_object.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -33,6 +33,7 @@ class String; struct PFS_global_param; +class PFS_opaque_container_page; /** @addtogroup Performance_schema_buffers @@ -75,11 +76,13 @@ struct PFS_ALIGNED PFS_setup_object bool m_enabled; /** TIMED flag. */ bool m_timed; + /** Container page. */ + PFS_opaque_container_page *m_page; }; int init_setup_object(const PFS_global_param *param); void cleanup_setup_object(void); -int init_setup_object_hash(void); +int init_setup_object_hash(const PFS_global_param *param); void cleanup_setup_object_hash(void); int insert_setup_object(enum_object_type object_type, const String *schema, @@ -95,13 +98,7 @@ void lookup_setup_object(PFS_thread *thread, 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; +/* For show status. */ extern LF_HASH setup_object_hash; diff --git a/storage/perfschema/pfs_stat.h b/storage/perfschema/pfs_stat.h index 8a049e3013b..8667a5f691c 100644 --- a/storage/perfschema/pfs_stat.h +++ b/storage/perfschema/pfs_stat.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, version 2.0, @@ -23,6 +23,7 @@ #ifndef PFS_STAT_H #define PFS_STAT_H +#include <algorithm> #include "sql_const.h" /* memcpy */ #include "string.h" @@ -53,7 +54,7 @@ struct PFS_single_stat { m_count= 0; m_sum= 0; - m_min= ULONGLONG_MAX; + m_min= ULLONG_MAX; m_max= 0; } @@ -61,7 +62,7 @@ struct PFS_single_stat { m_count= 0; m_sum= 0; - m_min= ULONGLONG_MAX; + m_min= ULLONG_MAX; m_max= 0; } @@ -72,6 +73,19 @@ struct PFS_single_stat inline void aggregate(const PFS_single_stat *stat) { + if (stat->m_count != 0) + { + 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_no_check(const PFS_single_stat *stat) + { m_count+= stat->m_count; m_sum+= stat->m_sum; if (unlikely(m_min > stat->m_min)) @@ -99,6 +113,16 @@ struct PFS_single_stat if (unlikely(m_max < value)) m_max= value; } + + inline void aggregate_many_value(ulonglong value, ulonglong count) + { + m_count+= count; + m_sum+= value; + if (unlikely(m_min > value)) + m_min= value; + if (unlikely(m_max < value)) + m_max= value; + } }; /** Combined statistic. */ @@ -107,39 +131,49 @@ struct PFS_byte_stat : public PFS_single_stat /** Byte count statistics */ ulonglong m_bytes; - /* Aggregate wait stats, event count and byte count */ + /** Aggregate wait stats, event count and byte count */ inline void aggregate(const PFS_byte_stat *stat) { - PFS_single_stat::aggregate(stat); + if (stat->m_count != 0) + { + PFS_single_stat::aggregate_no_check(stat); + m_bytes+= stat->m_bytes; + } + } + + /** Aggregate wait stats, event count and byte count */ + inline void aggregate_no_check(const PFS_byte_stat *stat) + { + PFS_single_stat::aggregate_no_check(stat); m_bytes+= stat->m_bytes; } - /* Aggregate individual wait time, event count and byte count */ + /** 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 */ + /** 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 */ + /** Aggregate event count and byte count */ inline void aggregate_counted() { PFS_single_stat::aggregate_counted(); } - /* Aggregate event count and byte count */ + /** Aggregate event count and byte count */ inline void aggregate_counted(ulonglong bytes) { PFS_single_stat::aggregate_counted(); m_bytes+= bytes; } - + PFS_byte_stat() { reset(); @@ -157,22 +191,28 @@ struct PFS_mutex_stat { /** Wait statistics. */ PFS_single_stat m_wait_stat; +#ifdef PFS_LATER /** Lock statistics. This statistic is not exposed in user visible tables yet. */ PFS_single_stat m_lock_stat; +#endif inline void aggregate(const PFS_mutex_stat *stat) { m_wait_stat.aggregate(&stat->m_wait_stat); +#ifdef PFS_LATER m_lock_stat.aggregate(&stat->m_lock_stat); +#endif } inline void reset(void) { m_wait_stat.reset(); +#ifdef PFS_LATER m_lock_stat.reset(); +#endif } }; @@ -181,6 +221,7 @@ struct PFS_rwlock_stat { /** Wait statistics. */ PFS_single_stat m_wait_stat; +#ifdef PFS_LATER /** RWLock read lock usage statistics. This statistic is not exposed in user visible tables yet. @@ -191,19 +232,24 @@ struct PFS_rwlock_stat This statistic is not exposed in user visible tables yet. */ PFS_single_stat m_write_lock_stat; +#endif inline void aggregate(const PFS_rwlock_stat *stat) { m_wait_stat.aggregate(&stat->m_wait_stat); +#ifdef PFS_LATER m_read_lock_stat.aggregate(&stat->m_read_lock_stat); m_write_lock_stat.aggregate(&stat->m_write_lock_stat); +#endif } inline void reset(void) { m_wait_stat.reset(); +#ifdef PFS_LATER m_read_lock_stat.reset(); m_write_lock_stat.reset(); +#endif } }; @@ -212,6 +258,7 @@ struct PFS_cond_stat { /** Wait statistics. */ PFS_single_stat m_wait_stat; +#ifdef PFS_LATER /** Number of times a condition was signalled. This statistic is not exposed in user visible tables yet. @@ -222,19 +269,24 @@ struct PFS_cond_stat This statistic is not exposed in user visible tables yet. */ ulonglong m_broadcast_count; +#endif inline void aggregate(const PFS_cond_stat *stat) { m_wait_stat.aggregate(&stat->m_wait_stat); +#ifdef PFS_LATER m_signal_count+= stat->m_signal_count; m_broadcast_count+= stat->m_broadcast_count; +#endif } inline void reset(void) { m_wait_stat.reset(); +#ifdef PFS_LATER m_signal_count= 0; m_broadcast_count= 0; +#endif } }; @@ -245,7 +297,7 @@ struct PFS_file_io_stat PFS_byte_stat m_read; /** WRITE statistics */ PFS_byte_stat m_write; - /** Miscelleanous statistics */ + /** Miscellaneous statistics */ PFS_byte_stat m_misc; inline void reset(void) @@ -313,11 +365,51 @@ struct PFS_stage_stat inline void aggregate_value(ulonglong value) { m_timer1_stat.aggregate_value(value); } + inline void aggregate(const PFS_stage_stat *stat) + { m_timer1_stat.aggregate(& stat->m_timer1_stat); } +}; + +/** Statistics for stored program usage. */ +struct PFS_sp_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(const PFS_stage_stat *stat) + { m_timer1_stat.aggregate(& stat->m_timer1_stat); } +}; + +/** Statistics for prepared statement usage. */ +struct PFS_prepared_stmt_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. */ +/** + Statistics for statement usage. + This structure uses lazy initialization, + controlled by member @c m_timer1_stat.m_count. +*/ struct PFS_statement_stat { PFS_single_stat m_timer1_stat; @@ -343,80 +435,128 @@ struct PFS_statement_stat 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; + reset(); } - inline void reset(void) + inline void reset() { - 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; + m_timer1_stat.m_count= 0; } + inline void mark_used() + { + delayed_reset(); + } + +private: + inline void delayed_reset(void) + { + if (m_timer1_stat.m_count == 0) + { + 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; + } + } + +public: inline void aggregate_counted() - { m_timer1_stat.aggregate_counted(); } + { + delayed_reset(); + m_timer1_stat.aggregate_counted(); + } inline void aggregate_value(ulonglong value) - { m_timer1_stat.aggregate_value(value); } + { + delayed_reset(); + m_timer1_stat.aggregate_value(value); + } + + inline void aggregate(const PFS_statement_stat *stat) + { + if (stat->m_timer1_stat.m_count != 0) + { + delayed_reset(); + m_timer1_stat.aggregate_no_check(& 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; + } + } +}; + +/** Statistics for transaction usage. */ +struct PFS_transaction_stat +{ + PFS_single_stat m_read_write_stat; + PFS_single_stat m_read_only_stat; + + ulonglong m_savepoint_count; + ulonglong m_rollback_to_savepoint_count; + ulonglong m_release_savepoint_count; + + PFS_transaction_stat() + { + m_savepoint_count= 0; + m_rollback_to_savepoint_count= 0; + m_release_savepoint_count= 0; + } + + ulonglong count(void) + { + return (m_read_write_stat.m_count + m_read_only_stat.m_count); + } + + inline void reset(void) + { + m_read_write_stat.reset(); + m_read_only_stat.reset(); + m_savepoint_count= 0; + m_rollback_to_savepoint_count= 0; + m_release_savepoint_count= 0; + } - 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; + inline void aggregate(const PFS_transaction_stat *stat) + { + m_read_write_stat.aggregate(&stat->m_read_write_stat); + m_read_only_stat.aggregate(&stat->m_read_only_stat); + m_savepoint_count+= stat->m_savepoint_count; + m_rollback_to_savepoint_count+= stat->m_rollback_to_savepoint_count; + m_release_savepoint_count+= stat->m_release_savepoint_count; } }; @@ -480,16 +620,17 @@ enum PFS_TL_LOCK_TYPE 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, + PFS_TL_WRITE_LOW_PRIORITY= 6, + PFS_TL_WRITE= 7, /* Locks for handler::ha_external_lock() */ - PFS_TL_READ_EXTERNAL= 9, - PFS_TL_WRITE_EXTERNAL= 10 + PFS_TL_READ_EXTERNAL= 8, + PFS_TL_WRITE_EXTERNAL= 9, + + PFS_TL_NONE= 99 }; -#define COUNT_PFS_TL_LOCK_TYPE 11 +#define COUNT_PFS_TL_LOCK_TYPE 10 /** Statistics for table locks. */ struct PFS_table_lock_stat @@ -644,7 +785,7 @@ struct PFS_socket_io_stat PFS_byte_stat m_read; /** WRITE statistics */ PFS_byte_stat m_write; - /** Miscelleanous statistics */ + /** Miscellaneous statistics */ PFS_byte_stat m_misc; inline void reset(void) @@ -691,6 +832,478 @@ struct PFS_socket_stat } }; +struct PFS_memory_stat_delta +{ + size_t m_alloc_count_delta; + size_t m_free_count_delta; + size_t m_alloc_size_delta; + size_t m_free_size_delta; + + void reset() + { + m_alloc_count_delta= 0; + m_free_count_delta= 0; + m_alloc_size_delta= 0; + m_free_size_delta= 0; + } +}; + +/** + Memory statistics. + Conceptually, the following statistics are maintained: + - CURRENT_COUNT_USED, + - LOW_COUNT_USED, + - HIGH_COUNT_USED + - CURRENT_SIZE_USED, + - LOW_SIZE_USED, + - HIGH_SIZE_USED + Now, the implementation keeps different counters, + which are easier (less overhead) to maintain while + collecting statistics. + Invariants are as follows: + CURRENT_COUNT_USED = @c m_alloc_count - @c m_free_count + LOW_COUNT_USED + @c m_free_count_capacity = CURRENT_COUNT_USED + CURRENT_COUNT_USED + @c m_alloc_count_capacity = HIGH_COUNT_USED + CURRENT_SIZE_USED = @c m_alloc_size - @c m_free_size + LOW_SIZE_USED + @c m_free_size_capacity = CURRENT_SIZE_USED + CURRENT_SIZE_USED + @c m_alloc_size_capacity = HIGH_SIZE_USED + +*/ +struct PFS_memory_stat +{ + bool m_used; + size_t m_alloc_count; + size_t m_free_count; + size_t m_alloc_size; + size_t m_free_size; + + size_t m_alloc_count_capacity; + size_t m_free_count_capacity; + size_t m_alloc_size_capacity; + size_t m_free_size_capacity; + + inline void reset(void) + { + m_used= false; + m_alloc_count= 0; + m_free_count= 0; + m_alloc_size= 0; + m_free_size= 0; + + m_alloc_count_capacity= 0; + m_free_count_capacity= 0; + m_alloc_size_capacity= 0; + m_free_size_capacity= 0; + } + + inline void rebase(void) + { + if (! m_used) + return; + + size_t base; + + base= std::min<size_t>(m_alloc_count, m_free_count); + m_alloc_count-= base; + m_free_count-= base; + + base= std::min<size_t>(m_alloc_size, m_free_size); + m_alloc_size-= base; + m_free_size-= base; + + m_alloc_count_capacity= 0; + m_free_count_capacity= 0; + m_alloc_size_capacity= 0; + m_free_size_capacity= 0; + } + + inline void partial_aggregate_to(PFS_memory_stat *stat) + { + if (! m_used) + return; + + size_t base; + + stat->m_used= true; + + base= std::min<size_t>(m_alloc_count, m_free_count); + if (base != 0) + { + stat->m_alloc_count+= base; + stat->m_free_count+= base; + m_alloc_count-= base; + m_free_count-= base; + } + + base= std::min<size_t>(m_alloc_size, m_free_size); + if (base != 0) + { + stat->m_alloc_size+= base; + stat->m_free_size+= base; + m_alloc_size-= base; + m_free_size-= base; + } + + stat->m_alloc_count_capacity+= m_alloc_count_capacity; + stat->m_free_count_capacity+= m_free_count_capacity; + stat->m_alloc_size_capacity+= m_alloc_size_capacity; + stat->m_free_size_capacity+= m_free_size_capacity; + + m_alloc_count_capacity= 0; + m_free_count_capacity= 0; + m_alloc_size_capacity= 0; + m_free_size_capacity= 0; + } + + inline void full_aggregate_to(PFS_memory_stat *stat) const + { + if (! m_used) + return; + + stat->m_used= true; + + stat->m_alloc_count+= m_alloc_count; + stat->m_free_count+= m_free_count; + stat->m_alloc_size+= m_alloc_size; + stat->m_free_size+= m_free_size; + + stat->m_alloc_count_capacity+= m_alloc_count_capacity; + stat->m_free_count_capacity+= m_free_count_capacity; + stat->m_alloc_size_capacity+= m_alloc_size_capacity; + stat->m_free_size_capacity+= m_free_size_capacity; + } + + inline void partial_aggregate_to(PFS_memory_stat *stat1, PFS_memory_stat *stat2) + { + if (! m_used) + return; + + size_t base; + + stat1->m_used= true; + stat2->m_used= true; + + base= std::min<size_t>(m_alloc_count, m_free_count); + if (base != 0) + { + stat1->m_alloc_count+= base; + stat2->m_alloc_count+= base; + stat1->m_free_count+= base; + stat2->m_free_count+= base; + m_alloc_count-= base; + m_free_count-= base; + } + + base= std::min<size_t>(m_alloc_size, m_free_size); + if (base != 0) + { + stat1->m_alloc_size+= base; + stat2->m_alloc_size+= base; + stat1->m_free_size+= base; + stat2->m_free_size+= base; + m_alloc_size-= base; + m_free_size-= base; + } + + stat1->m_alloc_count_capacity+= m_alloc_count_capacity; + stat2->m_alloc_count_capacity+= m_alloc_count_capacity; + stat1->m_free_count_capacity+= m_free_count_capacity; + stat2->m_free_count_capacity+= m_free_count_capacity; + stat1->m_alloc_size_capacity+= m_alloc_size_capacity; + stat2->m_alloc_size_capacity+= m_alloc_size_capacity; + stat1->m_free_size_capacity+= m_free_size_capacity; + stat2->m_free_size_capacity+= m_free_size_capacity; + + m_alloc_count_capacity= 0; + m_free_count_capacity= 0; + m_alloc_size_capacity= 0; + m_free_size_capacity= 0; + } + + inline void full_aggregate_to(PFS_memory_stat *stat1, PFS_memory_stat *stat2) const + { + if (! m_used) + return; + + stat1->m_used= true; + stat2->m_used= true; + + stat1->m_alloc_count+= m_alloc_count; + stat2->m_alloc_count+= m_alloc_count; + stat1->m_free_count+= m_free_count; + stat2->m_free_count+= m_free_count; + stat1->m_alloc_size+= m_alloc_size; + stat2->m_alloc_size+= m_alloc_size; + stat1->m_free_size+= m_free_size; + stat2->m_free_size+= m_free_size; + + stat1->m_alloc_count_capacity+= m_alloc_count_capacity; + stat2->m_alloc_count_capacity+= m_alloc_count_capacity; + stat1->m_free_count_capacity+= m_free_count_capacity; + stat2->m_free_count_capacity+= m_free_count_capacity; + stat1->m_alloc_size_capacity+= m_alloc_size_capacity; + stat2->m_alloc_size_capacity+= m_alloc_size_capacity; + stat1->m_free_size_capacity+= m_free_size_capacity; + stat2->m_free_size_capacity+= m_free_size_capacity; + } + + void count_builtin_alloc(size_t size) + { + m_used= true; + + m_alloc_count++; + m_free_count_capacity++; + m_alloc_size+= size; + m_free_size_capacity+= size; + + if (m_alloc_count_capacity >= 1) + { + m_alloc_count_capacity--; + } + + if (m_alloc_size_capacity >= size) + { + m_alloc_size_capacity-= size; + } + + return; + } + + void count_builtin_free(size_t size) + { + m_used= true; + + m_free_count++; + m_alloc_count_capacity++; + m_free_size+= size; + m_alloc_size_capacity+= size; + + if (m_free_count_capacity >= 1) + { + m_free_count_capacity--; + } + + if (m_free_size_capacity >= size) + { + m_free_size_capacity-= size; + } + + return; + } + + inline PFS_memory_stat_delta *count_alloc(size_t size, + PFS_memory_stat_delta *delta) + { + m_used= true; + + m_alloc_count++; + m_free_count_capacity++; + m_alloc_size+= size; + m_free_size_capacity+= size; + + if ((m_alloc_count_capacity >= 1) && + (m_alloc_size_capacity >= size)) + { + m_alloc_count_capacity--; + m_alloc_size_capacity-= size; + return NULL; + } + + delta->reset(); + + if (m_alloc_count_capacity >= 1) + { + m_alloc_count_capacity--; + } + else + { + delta->m_alloc_count_delta= 1; + } + + if (m_alloc_size_capacity >= size) + { + m_alloc_size_capacity-= size; + } + else + { + delta->m_alloc_size_delta= size - m_alloc_size_capacity; + m_alloc_size_capacity= 0; + } + + return delta; + } + + inline PFS_memory_stat_delta *count_realloc(size_t old_size, size_t new_size, + PFS_memory_stat_delta *delta) + { + m_used= true; + + size_t size_delta= new_size - old_size; + m_alloc_count++; + m_alloc_size+= new_size; + m_free_count++; + m_free_size+= old_size; + + if (new_size == old_size) + { + return NULL; + } + + if (new_size > old_size) + { + /* Growing */ + size_delta= new_size - old_size; + m_free_size_capacity+= size_delta; + + if (m_alloc_size_capacity >= size_delta) + { + m_alloc_size_capacity-= size_delta; + return NULL; + } + + delta->reset(); + delta->m_alloc_size_delta= size_delta - m_alloc_size_capacity; + m_alloc_size_capacity= 0; + } + else + { + /* Shrinking */ + size_delta= old_size - new_size; + m_alloc_size_capacity+= size_delta; + + if (m_free_size_capacity >= size_delta) + { + m_free_size_capacity-= size_delta; + return NULL; + } + + delta->reset(); + delta->m_free_size_delta= size_delta - m_free_size_capacity; + m_free_size_capacity= 0; + } + + return delta; + } + + inline PFS_memory_stat_delta *count_free(size_t size, PFS_memory_stat_delta *delta) + { + m_used= true; + + m_free_count++; + m_alloc_count_capacity++; + m_free_size+= size; + m_alloc_size_capacity+= size; + + if ((m_free_count_capacity >= 1) && + (m_free_size_capacity >= size)) + { + m_free_count_capacity--; + m_free_size_capacity-= size; + return NULL; + } + + delta->reset(); + + if (m_free_count_capacity >= 1) + { + m_free_count_capacity--; + } + else + { + delta->m_free_count_delta= 1; + } + + if (m_free_size_capacity >= size) + { + m_free_size_capacity-= size; + } + else + { + delta->m_free_size_delta= size - m_free_size_capacity; + m_free_size_capacity= 0; + } + + return delta; + } + + inline PFS_memory_stat_delta *apply_delta(const PFS_memory_stat_delta *delta, + PFS_memory_stat_delta *delta_buffer) + { + size_t val; + size_t remaining_alloc_count; + size_t remaining_alloc_size; + size_t remaining_free_count; + size_t remaining_free_size; + bool has_remaining= false; + + m_used= true; + + val= delta->m_alloc_count_delta; + if (val <= m_alloc_count_capacity) + { + m_alloc_count_capacity-= val; + remaining_alloc_count= 0; + } + else + { + remaining_alloc_count= val - m_alloc_count_capacity; + m_alloc_count_capacity= 0; + has_remaining= true; + } + + val= delta->m_alloc_size_delta; + if (val <= m_alloc_size_capacity) + { + m_alloc_size_capacity-= val; + remaining_alloc_size= 0; + } + else + { + remaining_alloc_size= val - m_alloc_size_capacity; + m_alloc_size_capacity= 0; + has_remaining= true; + } + + val= delta->m_free_count_delta; + if (val <= m_free_count_capacity) + { + m_free_count_capacity-= val; + remaining_free_count= 0; + } + else + { + remaining_free_count= val - m_free_count_capacity; + m_free_count_capacity= 0; + has_remaining= true; + } + + val= delta->m_free_size_delta; + if (val <= m_free_size_capacity) + { + m_free_size_capacity-= val; + remaining_free_size= 0; + } + else + { + remaining_free_size= val - m_free_size_capacity; + m_free_size_capacity= 0; + has_remaining= true; + } + + if (! has_remaining) + return NULL; + + delta_buffer->m_alloc_count_delta= remaining_alloc_count; + delta_buffer->m_alloc_size_delta= remaining_alloc_size; + delta_buffer->m_free_count_delta= remaining_free_count; + delta_buffer->m_free_size_delta= remaining_free_size; + return delta_buffer; + } +}; + +#define PFS_MEMORY_STAT_INITIALIZER { false, 0, 0, 0, 0, 0, 0, 0, 0} + +/** Connections statistics. */ struct PFS_connection_stat { PFS_connection_stat() diff --git a/storage/perfschema/pfs_status.cc b/storage/perfschema/pfs_status.cc new file mode 100644 index 00000000000..61afcbfccd9 --- /dev/null +++ b/storage/perfschema/pfs_status.cc @@ -0,0 +1,166 @@ +/* Copyright (c) 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/pfs_status.cc + Status variables statistics (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_status.h" +#include "pfs_atomic.h" +#include "pfs_buffer_container.h" + +#include "sql_show.h" /* reset_status_vars */ + +PFS_status_stats::PFS_status_stats() +{ + reset(); +} + +void PFS_status_stats::reset() +{ + m_has_stats= false; + memset(&m_stats, 0, sizeof(m_stats)); +} + +void PFS_status_stats::aggregate(const PFS_status_stats *from) +{ + if (from->m_has_stats) + { + m_has_stats= true; + for (int i= 0; i < COUNT_GLOBAL_STATUS_VARS; i++) + { + m_stats[i] += from->m_stats[i]; + } + } +} + +void PFS_status_stats::aggregate_from(const STATUS_VAR *from) +{ + ulonglong *from_var= (ulonglong*) from; + + m_has_stats= true; + for (int i= 0; + i < COUNT_GLOBAL_STATUS_VARS; + i++, from_var++) + { + m_stats[i] += *from_var; + } +} + +void PFS_status_stats::aggregate_to(STATUS_VAR *to) +{ + if (m_has_stats) + { + ulonglong *to_var= (ulonglong*) to; + + for (int i= 0; + i < COUNT_GLOBAL_STATUS_VARS; + i++, to_var++) + { + *to_var += m_stats[i]; + } + } +} + +static void fct_reset_status_by_thread(PFS_thread *thread) +{ + PFS_account *account; + PFS_user *user; + PFS_host *host; + + 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_status(thread, account, user, host); + } +} + +/** Reset table STATUS_BY_THREAD data. */ +void reset_status_by_thread() +{ + global_thread_container.apply_all(fct_reset_status_by_thread); +} + +static void fct_reset_status_by_account(PFS_account *account) +{ + PFS_user *user; + PFS_host *host; + + if (account->m_lock.is_populated()) + { + user= sanitize_user(account->m_user); + host= sanitize_host(account->m_host); + account->aggregate_status(user, host); + } +} + +/** Reset table STATUS_BY_ACCOUNT data. */ +void reset_status_by_account() +{ + global_account_container.apply_all(fct_reset_status_by_account); +} + +static void fct_reset_status_by_user(PFS_user *user) +{ + if (user->m_lock.is_populated()) + user->aggregate_status(); +} + +/** Reset table STATUS_BY_USER data. */ +void reset_status_by_user() +{ + global_user_container.apply_all(fct_reset_status_by_user); +} + +static void fct_reset_status_by_host(PFS_host *host) +{ + if (host->m_lock.is_populated()) + host->aggregate_status(); +} + +/** Reset table STATUS_BY_HOST data. */ +void reset_status_by_host() +{ + global_host_container.apply_all(fct_reset_status_by_host); +} + +/** Reset table GLOBAL_STATUS data. */ +void reset_global_status() +{ + /* + Do not memset global_status_var, + NO_FLUSH counters need to be preserved + */ + reset_status_vars(); +} + diff --git a/storage/perfschema/pfs_status.h b/storage/perfschema/pfs_status.h new file mode 100644 index 00000000000..0417976e9f2 --- /dev/null +++ b/storage/perfschema/pfs_status.h @@ -0,0 +1,51 @@ +/* Copyright (c) 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef PFS_STATUS_H +#define PFS_STATUS_H + +/** + @file storage/perfschema/pfs_status.h + Status variables statistics (declarations). +*/ + +struct PFS_status_stats +{ + PFS_status_stats(); + + void reset(); + void aggregate(const PFS_status_stats *from); + void aggregate_from(const STATUS_VAR *from); + void aggregate_to(STATUS_VAR *to); + + bool m_has_stats; + ulonglong m_stats[COUNT_GLOBAL_STATUS_VARS]; +}; + +void reset_status_by_thread(); +void reset_status_by_account(); +void reset_status_by_user(); +void reset_status_by_host(); +void reset_global_status(); + +#endif + diff --git a/storage/perfschema/pfs_timer.cc b/storage/perfschema/pfs_timer.cc index 8533dffcb27..ceec4ed9359 100644 --- a/storage/perfschema/pfs_timer.cc +++ b/storage/perfschema/pfs_timer.cc @@ -33,6 +33,7 @@ enum_timer_name idle_timer= TIMER_NAME_MICROSEC; enum_timer_name wait_timer= TIMER_NAME_CYCLE; enum_timer_name stage_timer= TIMER_NAME_NANOSEC; enum_timer_name statement_timer= TIMER_NAME_NANOSEC; +enum_timer_name transaction_timer= TIMER_NAME_NANOSEC; static ulonglong cycle_v0; static ulonglong nanosec_v0; @@ -174,30 +175,35 @@ void init_timers(void) /* Normal case. */ stage_timer= TIMER_NAME_NANOSEC; statement_timer= TIMER_NAME_NANOSEC; + transaction_timer= TIMER_NAME_NANOSEC; } else if (microsec_to_pico != 0) { /* Windows. */ stage_timer= TIMER_NAME_MICROSEC; statement_timer= TIMER_NAME_MICROSEC; + transaction_timer= TIMER_NAME_MICROSEC; } else if (millisec_to_pico != 0) { /* Robustness, no known cases. */ stage_timer= TIMER_NAME_MILLISEC; statement_timer= TIMER_NAME_MILLISEC; + transaction_timer= TIMER_NAME_MILLISEC; } else if (tick_to_pico != 0) { /* Robustness, no known cases. */ stage_timer= TIMER_NAME_TICK; statement_timer= TIMER_NAME_TICK; + transaction_timer= TIMER_NAME_TICK; } else { /* Robustness, no known cases. */ stage_timer= TIMER_NAME_CYCLE; statement_timer= TIMER_NAME_CYCLE; + transaction_timer= TIMER_NAME_CYCLE; } /* diff --git a/storage/perfschema/pfs_timer.h b/storage/perfschema/pfs_timer.h index 222a7f00fae..f2bedc878e7 100644 --- a/storage/perfschema/pfs_timer.h +++ b/storage/perfschema/pfs_timer.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -106,6 +106,11 @@ extern enum_timer_name stage_timer; */ extern enum_timer_name statement_timer; /** + Transaction timer. + The timer used to measure all transaction events. +*/ +extern enum_timer_name transaction_timer; +/** Timer information data. Characteristics about each supported timer. */ diff --git a/storage/perfschema/pfs_user.cc b/storage/perfschema/pfs_user.cc index 14b86e1478e..feb99f41147 100644 --- a/storage/perfschema/pfs_user.cc +++ b/storage/perfschema/pfs_user.cc @@ -34,21 +34,13 @@ #include "pfs_user.h" #include "pfs_global.h" #include "pfs_instr_class.h" +#include "pfs_buffer_container.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; @@ -59,59 +51,8 @@ static bool user_hash_inited= false; */ 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]; - } + if (global_user_container.init(param->m_user_sizing)) + return 1; return 0; } @@ -119,15 +60,7 @@ int init_user(const PFS_global_param *param) /** 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; + global_user_container.cleanup(); } C_MODE_START @@ -151,13 +84,12 @@ C_MODE_END Initialize the user hash. @return 0 on success */ -int init_user_hash(void) +int init_user_hash(const PFS_global_param *param) { - if ((! user_hash_inited) && (user_max > 0)) + if ((! user_hash_inited) && (param->m_user_sizing != 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; @@ -204,16 +136,10 @@ 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++; + global_user_container.m_lost++; return NULL; } @@ -221,8 +147,10 @@ find_or_create_user(PFS_thread *thread, set_user_key(&key, username, username_length); PFS_user **entry; + PFS_user *pfs; uint retry_count= 0; const uint retry_max= 3; + pfs_dirty_state dirty_state; search: entry= reinterpret_cast<PFS_user**> @@ -230,7 +158,6 @@ search: 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); @@ -239,68 +166,55 @@ search: 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= global_user_container.allocate(& dirty_state); + if (pfs != NULL) { - PFS_user *pfs= user_array + scan.first(); - PFS_user *pfs_last= user_array + scan.last(); - for ( ; pfs < pfs_last; pfs++) + 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; + pfs->m_lock.dirty_to_allocated(& dirty_state); + res= lf_hash_insert(&user_hash, pins, &pfs); + if (likely(res == 0)) { - if (pfs->m_lock.is_free()) + return pfs; + } + + global_user_container.deallocate(pfs); + + if (res > 0) + { + if (++retry_count > retry_max) { - 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; - } + global_user_container.m_lost++; + return NULL; } + goto search; } + + global_user_container.m_lost++; + return NULL; } - user_lost++; return NULL; } -void PFS_user::aggregate() +void PFS_user::aggregate(bool alive) { aggregate_waits(); aggregate_stages(); aggregate_statements(); + aggregate_transactions(); + aggregate_memory(alive); + aggregate_status(); aggregate_stats(); } @@ -322,6 +236,24 @@ void PFS_user::aggregate_statements() reset_statements_stats(); } +void PFS_user::aggregate_transactions() +{ + /* No parent to aggregate to, clean the stats */ + reset_transactions_stats(); +} + +void PFS_user::aggregate_memory(bool alive) +{ + /* No parent to aggregate to, clean the stats */ + rebase_memory_stats(); +} + +void PFS_user::aggregate_status() +{ + /* No parent to aggregate to, clean the stats */ + reset_status_stats(); +} + void PFS_user::aggregate_stats() { /* No parent to aggregate to, clean the stats */ @@ -333,12 +265,20 @@ void PFS_user::release() dec_refcount(); } +void PFS_user::carry_memory_stat_delta(PFS_memory_stat_delta *delta, uint index) +{ + PFS_memory_stat *event_name_array; + PFS_memory_stat *stat; + PFS_memory_stat_delta delta_buffer; + + event_name_array= write_instr_class_memory_stats(); + stat= & event_name_array[index]; + (void) stat->apply_delta(delta, &delta_buffer); +} + PFS_user *sanitize_user(PFS_user *unsafe) { - if ((&user_array[0] <= unsafe) && - (unsafe < &user_array[user_max])) - return unsafe; - return NULL; + return global_user_container.sanitize(unsafe); } void purge_user(PFS_thread *thread, PFS_user *user) @@ -358,13 +298,33 @@ void purge_user(PFS_thread *thread, PFS_user *user) { lf_hash_delete(&user_hash, pins, user->m_key.m_hash_key, user->m_key.m_key_length); - user->m_lock.allocated_to_free(); + user->aggregate(false); + global_user_container.deallocate(user); } } lf_hash_search_unpin(pins); } +class Proc_purge_user + : public PFS_buffer_processor<PFS_user> +{ +public: + Proc_purge_user(PFS_thread *thread) + : m_thread(thread) + {} + + virtual void operator()(PFS_user *pfs) + { + pfs->aggregate(true); + if (pfs->get_refcount() == 0) + purge_user(m_thread, pfs); + } + +private: + PFS_thread *m_thread; +}; + /** Purge non connected users, reset stats of connected users. */ void purge_all_user(void) { @@ -372,18 +332,8 @@ void purge_all_user(void) 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); - } - } + Proc_purge_user proc(thread); + global_user_container.apply(proc); } /** @} */ diff --git a/storage/perfschema/pfs_user.h b/storage/perfschema/pfs_user.h index 3d0457eae59..9553ff8cae7 100644 --- a/storage/perfschema/pfs_user.h +++ b/storage/perfschema/pfs_user.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -40,6 +40,7 @@ struct PFS_thread; @{ */ +/** Hash key for a user. */ struct PFS_user_key { /** @@ -51,6 +52,7 @@ struct PFS_user_key uint m_key_length; }; +/** Per user statistics. */ struct PFS_ALIGNED PFS_user : public PFS_connection_slice { public: @@ -74,13 +76,18 @@ public: PFS_atomic::add_32(& m_refcount, -1); } - void aggregate(void); + void aggregate(bool alive); void aggregate_waits(void); void aggregate_stages(void); void aggregate_statements(void); + void aggregate_transactions(void); + void aggregate_memory(bool alive); + void aggregate_status(void); void aggregate_stats(void); void release(void); + void carry_memory_stat_delta(PFS_memory_stat_delta *delta, uint index); + /** Internal lock. */ pfs_lock m_lock; PFS_user_key m_key; @@ -95,7 +102,7 @@ private: int init_user(const PFS_global_param *param); void cleanup_user(void); -int init_user_hash(void); +int init_user_hash(const PFS_global_param *param); void cleanup_user_hash(void); PFS_user * @@ -106,14 +113,7 @@ 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; +/* For show status. */ extern LF_HASH user_hash; diff --git a/storage/perfschema/pfs_variable.cc b/storage/perfschema/pfs_variable.cc new file mode 100644 index 00000000000..933d6ad6ce6 --- /dev/null +++ b/storage/perfschema/pfs_variable.cc @@ -0,0 +1,1348 @@ +/* Copyright (c) 2015, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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-1301, USA */ + +/** + @file storage/perfschema/pfs_variable.cc + Performance schema system variable and status variable (implementation). +*/ +#include "sql_plugin.h" +#include "pfs_variable.h" +#include "my_sys.h" +#include "debug_sync.h" +#include "pfs.h" +#include "pfs_global.h" +#include "pfs_visitor.h" +#include "sql_audit.h" // audit_global_variable_get + +static inline SHOW_SCOPE show_scope_from_type(enum enum_mysql_show_type type) +{ + switch(type) { + case SHOW_BOOL: + case SHOW_CHAR: + case SHOW_CHAR_PTR: + case SHOW_DOUBLE: + case SHOW_HAVE: + case SHOW_HA_ROWS: + case SHOW_KEY_CACHE_LONG: + case SHOW_LEX_STRING: + case SHOW_LONG_NOFLUSH: + case SHOW_MY_BOOL: + case SHOW_SINT: + case SHOW_SLONG: + case SHOW_SLONGLONG: + case SHOW_SYS: + case SHOW_UINT: + case SHOW_ULONG: + case SHOW_ULONGLONG: + return SHOW_SCOPE_GLOBAL; + + case SHOW_DOUBLE_STATUS: + case SHOW_LONGLONG_STATUS: + case SHOW_LONG_STATUS: + return SHOW_SCOPE_ALL; + + case SHOW_ARRAY: + case SHOW_FUNC: + case SHOW_SIMPLE_FUNC: + case SHOW_UNDEF: + default: + return SHOW_SCOPE_UNDEF; + } + return SHOW_SCOPE_UNDEF; +} + + +/** + CLASS PFS_system_variable_cache +*/ + +/** + Build a sorted list of all system variables from the system variable hash. + Filter by scope. Must be called inside of LOCK_plugin_delete. +*/ +bool PFS_system_variable_cache::init_show_var_array(enum_var_type scope, bool strict) +{ + DBUG_ASSERT(!m_initialized); + m_query_scope= scope; + + mysql_rwlock_rdlock(&LOCK_system_variables_hash); + DEBUG_SYNC(m_current_thd, "acquired_LOCK_system_variables_hash"); + + /* Record the system variable hash version to detect subsequent changes. */ + m_version= get_system_variable_hash_version(); + + /* Build the SHOW_VAR array from the system variable hash. */ + SHOW_VAR *vars= enumerate_sys_vars(m_current_thd, true, m_query_scope/*, strict */); + m_show_var_array.reserve(get_system_variable_hash_records()); + for (int i=0; vars[i].name; i++) + m_show_var_array.set(i, vars[i]); + + mysql_rwlock_unlock(&LOCK_system_variables_hash); + + /* Increase cache size if necessary. */ + m_cache.reserve(m_show_var_array.elements()); + + m_initialized= true; + return true; +} + +/** + Build an array of SHOW_VARs from the system variable hash. + Filter for SESSION scope. +*/ +bool PFS_system_variable_cache::do_initialize_session(void) +{ + /* Block plugins from unloading. */ + mysql_mutex_lock(&LOCK_plugin_delete); + + /* Build the array. */ + bool ret= init_show_var_array(OPT_SESSION, true); + + mysql_mutex_unlock(&LOCK_plugin_delete); + return ret; +} + +/** + Match system variable scope to desired scope. +*/ +bool PFS_system_variable_cache::match_scope(int scope) +{ + switch (scope) + { + case sys_var::GLOBAL: + return m_query_scope == OPT_GLOBAL; + break; + + case sys_var::SESSION: + return (m_query_scope == OPT_GLOBAL || m_query_scope == OPT_SESSION); + break; + + case sys_var::ONLY_SESSION: + return m_query_scope == OPT_SESSION; + break; + + default: + return false; + break; + } + return false; +} + +/** + Build a GLOBAL system variable cache. +*/ +int PFS_system_variable_cache::do_materialize_global(void) +{ + /* Block plugins from unloading. */ + mysql_mutex_lock(&LOCK_plugin_delete); + + m_materialized= false; + + /* + Build array of SHOW_VARs from system variable hash. Do this within + LOCK_plugin_delete to ensure that the hash table remains unchanged + during materialization. + */ + if (!m_external_init) + init_show_var_array(OPT_GLOBAL, true); + + /* Resolve the value for each SHOW_VAR in the array, add to cache. */ + for (SHOW_VAR *show_var= m_show_var_array.front(); + show_var->value && (show_var != m_show_var_array.end()); show_var++) + { + const char* name= show_var->name; + sys_var *value= (sys_var *)show_var->value; + DBUG_ASSERT(value); + + if ((m_query_scope == OPT_GLOBAL) && + (!my_strcasecmp(system_charset_info, name, "sql_log_bin"))) + { + /* + PLEASE READ: + http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-6.html + + SQL_LOG_BIN is: + - declared in sys_vars.cc as both GLOBAL and SESSION in 5.7 + - impossible to SET with SET GLOBAL (raises an error) + - and yet can be read with @@global.sql_log_bin + + When show_compatibility_56 = ON, + - SHOW GLOBAL VARIABLES does expose a row for SQL_LOG_BIN + - INFORMATION_SCHEMA.GLOBAL_VARIABLES also does expose a row, + both are for backward compatibility of existing applications, + so that no application logic change is required. + + Now, with show_compatibility_56 = OFF (aka, in this code) + - SHOW GLOBAL VARIABLES does -- not -- expose a row for SQL_LOG_BIN + - PERFORMANCE_SCHEMA.GLOBAL_VARIABLES also does -- not -- expose a row + so that a clean interface is exposed to (upgraded and modified) applications. + + The assert below will fail once SQL_LOG_BIN really is defined + as SESSION_ONLY (in 5.8), so that this special case can be removed. + */ + DBUG_ASSERT(value->scope() == sys_var::SESSION); + continue; + } + + /* Match the system variable scope to the target scope. */ + if (match_scope(value->scope())) + { + /* Resolve value, convert to text, add to cache. */ + System_variable system_var(m_current_thd, show_var, m_query_scope, false); + m_cache.push(system_var); + } + } + + m_materialized= true; + mysql_mutex_unlock(&LOCK_plugin_delete); + return 0; +} + +/** + Build a GLOBAL and SESSION system variable cache. +*/ +int PFS_system_variable_cache::do_materialize_all(THD *unsafe_thd) +{ + int ret= 1; + + m_unsafe_thd= unsafe_thd; + m_safe_thd= NULL; + m_materialized= false; + m_cache.clear(); + + /* Block plugins from unloading. */ + mysql_mutex_lock(&LOCK_plugin_delete); + + /* + Build array of SHOW_VARs from system variable hash. Do this within + LOCK_plugin_delete to ensure that the hash table remains unchanged + while this thread is materialized. + */ + if (!m_external_init) + init_show_var_array(OPT_SESSION, false); + + /* Get and lock a validated THD from the thread manager. */ + if ((m_safe_thd= get_THD(unsafe_thd)) != NULL) + { + DEBUG_SYNC(m_current_thd, "materialize_session_variable_array_THD_locked"); + for (SHOW_VAR *show_var= m_show_var_array.front(); + show_var->value && (show_var != m_show_var_array.end()); show_var++) + { + const char* name= show_var->name; + sys_var *value= (sys_var *)show_var->value; + DBUG_ASSERT(value); + bool ignore= false; + + if (value->scope() == sys_var::SESSION && + (!my_strcasecmp(system_charset_info, name, "gtid_executed"))) + { + /* + GTID_EXECUTED is: + - declared in sys_vars.cc as both GLOBAL and SESSION in 5.7 + - can be read with @@session.gtid_executed + + When show_compatibility_56 = ON, + - SHOW SESSION VARIABLES does expose a row for GTID_EXECUTED + - INFORMATION_SCHEMA.SESSION_VARIABLES also does expose a row, + both are for backward compatibility of existing applications, + so that no application logic change is required. + + Now, with show_compatibility_56 = OFF (aka, in this code) + - SHOW SESSION VARIABLES does -- not -- expose a row for GTID_EXECUTED + - PERFORMANCE_SCHEMA.SESSION_VARIABLES also does -- not -- expose a row + so that a clean interface is exposed to (upgraded and modified) + applications. + + This special case needs be removed once @@SESSION.GTID_EXECUTED is + deprecated. + */ + ignore= true; + } + /* Resolve value, convert to text, add to cache. */ + System_variable system_var(m_safe_thd, show_var, m_query_scope, ignore); + m_cache.push(system_var); + } + + /* Release lock taken in get_THD(). */ + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_data); + + m_materialized= true; + ret= 0; + } + + mysql_mutex_unlock(&LOCK_plugin_delete); + return ret; +} + +/** + Allocate and assign mem_root for system variable materialization. +*/ +void PFS_system_variable_cache::set_mem_root(void) +{ + if (m_mem_sysvar_ptr == NULL) + { + init_sql_alloc(PSI_INSTRUMENT_ME, &m_mem_sysvar, SYSVAR_MEMROOT_BLOCK_SIZE, 0, 0); + m_mem_sysvar_ptr= &m_mem_sysvar; + } + m_mem_thd= my_thread_get_THR_MALLOC(); /* pointer to current THD mem_root */ + m_mem_thd_save= *m_mem_thd; /* restore later */ + *m_mem_thd= &m_mem_sysvar; /* use temporary mem_root */ +} + +/** + Mark memory blocks in the temporary mem_root as free. + Restore THD::mem_root. +*/ +void PFS_system_variable_cache::clear_mem_root(void) +{ + if (m_mem_sysvar_ptr) + { + free_root(&m_mem_sysvar, MYF(MY_MARK_BLOCKS_FREE)); + *m_mem_thd= m_mem_thd_save; /* restore original mem_root */ + m_mem_thd= NULL; + m_mem_thd_save= NULL; + } +} + +/** + Free the temporary mem_root. + Restore THD::mem_root if necessary. +*/ +void PFS_system_variable_cache::free_mem_root(void) +{ + if (m_mem_sysvar_ptr) + { + free_root(&m_mem_sysvar, MYF(0)); + m_mem_sysvar_ptr= NULL; + if (m_mem_thd && m_mem_thd_save) + { + *m_mem_thd= m_mem_thd_save; /* restore original mem_root */ + m_mem_thd= NULL; + m_mem_thd_save= NULL; + } + } +} + +/** + Build a SESSION system variable cache for a pfs_thread. + Requires that init_show_var_array() has already been called. + Return 0 for success. +*/ +int PFS_system_variable_cache::do_materialize_session(PFS_thread *pfs_thread) +{ + int ret= 1; + + m_pfs_thread= pfs_thread; + m_materialized= false; + m_cache.clear(); + + /* Block plugins from unloading. */ + mysql_mutex_lock(&LOCK_plugin_delete); + + /* The SHOW_VAR array must be initialized externally. */ + DBUG_ASSERT(m_initialized); + + /* Use a temporary mem_root to avoid depleting THD mem_root. */ + if (m_use_mem_root) + set_mem_root(); + + /* Get and lock a validated THD from the thread manager. */ + if ((m_safe_thd= get_THD(pfs_thread)) != NULL) + { + for (SHOW_VAR *show_var= m_show_var_array.front(); + show_var->value && (show_var != m_show_var_array.end()); show_var++) + { + sys_var *value= (sys_var *)show_var->value; + + /* Match the system variable scope to the target scope. */ + if (match_scope(value->scope())) + { + const char* name= show_var->name; + bool ignore= false; + + if (value->scope() == sys_var::SESSION && + (!my_strcasecmp(system_charset_info, name, "gtid_executed"))) + { + /* Deprecated. See PFS_system_variable_cache::do_materialize_all. */ +#warning no @@gtid_executed in MariaDB + ignore= true; + } + /* Resolve value, convert to text, add to cache. */ + System_variable system_var(m_safe_thd, show_var, m_query_scope, ignore); + m_cache.push(system_var); + } + } + + /* Release lock taken in get_THD(). */ + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_data); + + m_materialized= true; + ret= 0; + } + + /* Mark mem_root blocks as free. */ + if (m_use_mem_root) + clear_mem_root(); + + mysql_mutex_unlock(&LOCK_plugin_delete); + return ret; +} + +/** + Materialize a single system variable for a pfs_thread. + Requires that init_show_var_array() has already been called. + Return 0 for success. +*/ +int PFS_system_variable_cache::do_materialize_session(PFS_thread *pfs_thread, uint index) +{ + int ret= 1; + + m_pfs_thread= pfs_thread; + m_materialized= false; + m_cache.clear(); + + /* Block plugins from unloading. */ + mysql_mutex_lock(&LOCK_plugin_delete); + + /* The SHOW_VAR array must be initialized externally. */ + DBUG_ASSERT(m_initialized); + + /* Get and lock a validated THD from the thread manager. */ + if ((m_safe_thd= get_THD(pfs_thread)) != NULL) + { + SHOW_VAR *show_var= &m_show_var_array.at(index); + + if (show_var && show_var->value && + (show_var != m_show_var_array.end())) + { + sys_var *value= (sys_var *)show_var->value; + + /* Match the system variable scope to the target scope. */ + if (match_scope(value->scope())) + { + const char* name= show_var->name; + bool ignore= false; + + if (value->scope() == sys_var::SESSION && + (!my_strcasecmp(system_charset_info, name, "gtid_executed"))) + { + /* Deprecated. See PFS_system_variable_cache::do_materialize_all. */ + ignore= true; + } + /* Resolve value, convert to text, add to cache. */ + System_variable system_var(m_safe_thd, show_var, m_query_scope, ignore); + m_cache.push_back(system_var); + } + } + + /* Release lock taken in get_THD(). */ + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_data); + + m_materialized= true; + ret= 0; + } + + mysql_mutex_unlock(&LOCK_plugin_delete); + return ret; +} + +/** + Build a SESSION system variable cache for a THD. +*/ +int PFS_system_variable_cache::do_materialize_session(THD *unsafe_thd) +{ + int ret= 1; + + m_unsafe_thd= unsafe_thd; + m_safe_thd= NULL; + m_materialized= false; + m_cache.clear(); + + /* Block plugins from unloading. */ + mysql_mutex_lock(&LOCK_plugin_delete); + + /* + Build array of SHOW_VARs from system variable hash. Do this within + LOCK_plugin_delete to ensure that the hash table remains unchanged + while this thread is materialized. + */ + if (!m_external_init) + init_show_var_array(OPT_SESSION, true); + + /* Get and lock a validated THD from the thread manager. */ + if ((m_safe_thd= get_THD(unsafe_thd)) != NULL) + { + for (SHOW_VAR *show_var= m_show_var_array.front(); + show_var->value && (show_var != m_show_var_array.end()); show_var++) + { + sys_var *value = (sys_var *)show_var->value; + + /* Match the system variable scope to the target scope. */ + if (match_scope(value->scope())) + { + const char* name= show_var->name; + bool ignore= false; + + if (value->scope() == sys_var::SESSION && + (!my_strcasecmp(system_charset_info, name, "gtid_executed"))) + { + /* Deprecated. See PFS_system_variable_cache::do_materialize_all. */ + ignore= true; + } + /* Resolve value, convert to text, add to cache. */ + System_variable system_var(m_safe_thd, show_var, m_query_scope, ignore); + m_cache.push(system_var); + } + } + + /* Release lock taken in get_THD(). */ + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_data); + + m_materialized= true; + ret= 0; + } + + mysql_mutex_unlock(&LOCK_plugin_delete); + return ret; +} + + +/** + CLASS System_variable +*/ + +/** + Empty placeholder. +*/ +System_variable::System_variable() + : m_name(NULL), m_name_length(0), m_value_length(0), m_type(SHOW_UNDEF), m_scope(0), + m_ignore(false), m_charset(NULL), m_initialized(false) +{ + m_value_str[0]= '\0'; +} + +/** + GLOBAL or SESSION system variable. +*/ +System_variable::System_variable(THD *target_thd, const SHOW_VAR *show_var, + enum_var_type query_scope, bool ignore) + : m_name(NULL), m_name_length(0), m_value_length(0), m_type(SHOW_UNDEF), m_scope(0), + m_ignore(ignore), m_charset(NULL), m_initialized(false) +{ + init(target_thd, show_var, query_scope); +} + +/** + Get sys_var value from global or local source then convert to string. +*/ +void System_variable::init(THD *target_thd, const SHOW_VAR *show_var, + enum_var_type query_scope) +{ + if (show_var == NULL || show_var->name == NULL) + return; + + enum_mysql_show_type show_var_type= show_var->type; + DBUG_ASSERT(show_var_type == SHOW_SYS); + + m_name= show_var->name; + m_name_length= strlen(m_name); + + /* Deprecated variables are ignored but must still be accounted for. */ + if (m_ignore) + { + m_value_str[0]= '\0'; + m_value_length= 0; + m_initialized= true; + return; + } + + THD *current_thread= current_thd; + + /* Block remote target thread from updating this system variable. */ + if (target_thd != current_thread) + /*XXX mysql_mutex_lock(&target_thd->LOCK_thd_sysvar)*/; + /* Block system variable additions or deletions. */ + mysql_mutex_lock(&LOCK_global_system_variables); + + sys_var *system_var= (sys_var *)show_var->value; + DBUG_ASSERT(system_var != NULL); + m_charset= system_var->charset(target_thd); + m_type= system_var->show_type(); + m_scope= system_var->scope(); + + /* Get the value of the system variable. */ + String buf(m_value_str, sizeof(m_value_str) - 1, system_charset_info); + system_var->val_str_nolock(&buf, target_thd, + system_var->value_ptr(target_thd, query_scope, &null_lex_str)); + + m_value_length= MY_MIN(buf.length(), SHOW_VAR_FUNC_BUFF_SIZE); + + /* Returned value may reference a string other than m_value_str. */ + if (buf.ptr() != m_value_str) + memcpy(m_value_str, buf.ptr(), m_value_length); + m_value_str[m_value_length]= 0; + + mysql_mutex_unlock(&LOCK_global_system_variables); + if (target_thd != current_thread) + /*XXX mysql_mutex_unlock(&target_thd->LOCK_thd_sysvar)*/; + + m_initialized= true; +} + + +/** + CLASS PFS_status_variable_cache +*/ + +PFS_status_variable_cache:: +PFS_status_variable_cache(bool external_init) : + PFS_variable_cache<Status_variable>(external_init), + m_show_command(false), m_sum_client_status(NULL) +{ + /* Determine if the originating query is a SHOW command. */ + m_show_command= (m_current_thd->lex->sql_command == SQLCOM_SHOW_STATUS); +} + +/** + Build cache of SESSION status variables for a user. +*/ +int PFS_status_variable_cache::materialize_user(PFS_user *pfs_user) +{ + if (!pfs_user) + return 1; + + if (is_materialized(pfs_user)) + return 0; + + if (!pfs_user->m_lock.is_populated()) + return 1; + + /* Set callback function. */ + m_sum_client_status= sum_user_status; + return do_materialize_client((PFS_client *)pfs_user); +} + +/** + Build cache of SESSION status variables for a host. +*/ +int PFS_status_variable_cache::materialize_host(PFS_host *pfs_host) +{ + if (!pfs_host) + return 1; + + if (is_materialized(pfs_host)) + return 0; + + if (!pfs_host->m_lock.is_populated()) + return 1; + + /* Set callback function. */ + m_sum_client_status= sum_host_status; + return do_materialize_client((PFS_client *)pfs_host); +} + +/** + Build cache of SESSION status variables for an account. +*/ +int PFS_status_variable_cache::materialize_account(PFS_account *pfs_account) +{ + if (!pfs_account) + return 1; + + if (is_materialized(pfs_account)) + return 0; + + if (!pfs_account->m_lock.is_populated()) + return 1; + + /* Set callback function. */ + m_sum_client_status= sum_account_status; + return do_materialize_client((PFS_client *)pfs_account); +} +/** + Compare status variable scope to desired scope. + @param variable_scope Scope of current status variable + @return TRUE if variable matches the query scope +*/ +bool PFS_status_variable_cache::match_scope(SHOW_SCOPE variable_scope, bool strict) +{ + switch (variable_scope) + { + case SHOW_SCOPE_GLOBAL: + return (m_query_scope == OPT_GLOBAL) || (! strict && (m_query_scope == OPT_SESSION)); + break; + case SHOW_SCOPE_SESSION: + /* Ignore session-only vars if aggregating by user, host or account. */ + if (m_aggregate) + return false; + else + return (m_query_scope == OPT_SESSION); + break; + case SHOW_SCOPE_ALL: + return (m_query_scope == OPT_GLOBAL || m_query_scope == OPT_SESSION); + break; + case SHOW_SCOPE_UNDEF: + default: + return false; + break; + } + return false; +} + +/* + Exclude specific status variables from the query by name or prefix. + Return TRUE if variable should be filtered. +*/ +bool PFS_status_variable_cache::filter_by_name(const SHOW_VAR *show_var) +{ + DBUG_ASSERT(show_var); + DBUG_ASSERT(show_var->name); + + if (show_var->type == SHOW_ARRAY) + { + /* The SHOW_ARRAY name is the prefix for the variables in the subarray. */ + const char *prefix= show_var->name; + /* Exclude COM counters if not a SHOW STATUS command. */ + if (!my_strcasecmp(system_charset_info, prefix, "Com") && !m_show_command) + return true; + } + else + { + /* + Slave status resides in Performance Schema replication tables. Exclude + these slave status variables from the SHOW STATUS command and from the + status tables. + Assume null prefix to ensure that only server-defined slave status + variables are filtered. + */ + const char *name= show_var->name; + if (!my_strcasecmp(system_charset_info, name, "Slave_running") || + !my_strcasecmp(system_charset_info, name, "Slave_retried_transactions") || + !my_strcasecmp(system_charset_info, name, "Slave_last_heartbeat") || + !my_strcasecmp(system_charset_info, name, "Slave_received_heartbeats") || + !my_strcasecmp(system_charset_info, name, "Slave_heartbeat_period")) + { + return true; + } + } + + return false; +} + +/** + Check that the variable type is aggregatable. + + @param variable_type Status variable type + @return TRUE if variable type can be aggregated +*/ +bool PFS_status_variable_cache::can_aggregate(enum_mysql_show_type variable_type) +{ + switch(variable_type) + { + /* + All server status counters that are totaled across threads are defined in + system_status_var as either SHOW_LONGLONG_STATUS or SHOW_LONG_STATUS. + These data types are not available to plugins. + */ + case SHOW_LONGLONG_STATUS: + case SHOW_LONG_STATUS: + return true; + break; + + /* Server and plugin */ + case SHOW_UNDEF: + case SHOW_BOOL: + case SHOW_CHAR: + case SHOW_CHAR_PTR: + case SHOW_ARRAY: + case SHOW_FUNC: + case SHOW_INT: + case SHOW_LONG: + case SHOW_LONGLONG: + case SHOW_DOUBLE: + /* Server only */ + case SHOW_HAVE: + case SHOW_MY_BOOL: + case SHOW_SYS: + case SHOW_LEX_STRING: + case SHOW_KEY_CACHE_LONG: + case SHOW_DOUBLE_STATUS: + case SHOW_HA_ROWS: + case SHOW_LONG_NOFLUSH: + case SHOW_SLONG: + default: + return false; + break; + } +} + +/** + Check if a status variable should be excluded from the query. + Return TRUE if the variable should be excluded. +*/ +bool PFS_status_variable_cache::filter_show_var(const SHOW_VAR *show_var, bool strict) +{ + /* Match the variable scope with the query scope. */ + if (!match_scope(show_scope_from_type(show_var->type), strict)) + return true; + + /* Exclude specific status variables by name or prefix. */ + if (filter_by_name(show_var)) + return true; + + /* For user, host or account, ignore variables having non-aggregatable types. */ + if (m_aggregate && !can_aggregate(show_var->type)) + return true; + + return false; +} + + +/** + Build an array of SHOW_VARs from the global status array. Expand nested + subarrays, filter unwanted variables. + NOTE: Must be done inside of LOCK_status to guard against plugin load/unload. +*/ +bool PFS_status_variable_cache::init_show_var_array(enum_var_type scope, bool strict) +{ + DBUG_ASSERT(!m_initialized); + + /* Resize if necessary. */ + m_show_var_array.reserve(all_status_vars.elements + 1); + + m_query_scope= scope; + + for (SHOW_VAR *show_var_iter= dynamic_element(&all_status_vars, 0, SHOW_VAR *); + show_var_iter != dynamic_element(&all_status_vars, all_status_vars.elements, SHOW_VAR *); + show_var_iter++) + { + SHOW_VAR show_var= *show_var_iter; + + /* Check if this status var should be excluded from the query. */ + if (filter_show_var(&show_var, strict)) + continue; + + if (show_var.type == SHOW_ARRAY) + { + /* Expand nested subarray. The name is used as a prefix. */ + expand_show_var_array((SHOW_VAR *)show_var.value, show_var.name, strict); + } + else + { + show_var.name= make_show_var_name(NULL, show_var.name); + m_show_var_array.push(show_var); + } + } + + /* Last element is NULL. */ + st_mysql_show_var empty= {0,0,SHOW_UNDEF}; + m_show_var_array.push(empty); + + /* Get the latest version of all_status_vars. */ + m_version= get_status_vars_version(); + + /* Increase cache size if necessary. */ + m_cache.reserve(m_show_var_array.elements()); + + m_initialized= true; + return true; +} + +/** + Expand a nested subarray of status variables, indicated by a type of SHOW_ARRAY. +*/ +void PFS_status_variable_cache::expand_show_var_array(const SHOW_VAR *show_var_array, const char *prefix, bool strict) +{ + for (const SHOW_VAR *show_var_ptr= show_var_array; + show_var_ptr && show_var_ptr->name; + show_var_ptr++) + { + SHOW_VAR show_var= *show_var_ptr; + + if (filter_show_var(&show_var, strict)) + continue; + + if (show_var.type == SHOW_ARRAY) + { + char name_buf[SHOW_VAR_MAX_NAME_LEN]; + show_var.name= make_show_var_name(prefix, show_var.name, name_buf, sizeof(name_buf)); + /* Expand nested subarray. The name is used as a prefix. */ + expand_show_var_array((SHOW_VAR *)show_var.value, show_var.name, strict); + } + else + { + /* Add the SHOW_VAR element. Make a local copy of the name string. */ + show_var.name= make_show_var_name(prefix, show_var.name); + m_show_var_array.push(show_var); + } + } +} + +/** + Build the complete status variable name, with prefix. Return in buffer provided. +*/ +char * PFS_status_variable_cache::make_show_var_name(const char* prefix, const char* name, + char *name_buf, size_t buf_len) +{ + DBUG_ASSERT(name_buf != NULL); + char *prefix_end= name_buf; + + if (prefix && *prefix) + { + /* Drop the prefix into the front of the name buffer. */ + prefix_end= my_stpnmov(name_buf, prefix, buf_len-1); + *prefix_end++= '_'; + } + + /* Restrict name length to remaining buffer size. */ + size_t max_name_len= name_buf + buf_len - prefix_end; + + /* Load the name into the buffer after the prefix. */ + my_stpnmov(prefix_end, name, max_name_len); + name_buf[buf_len-1]= 0; + + return (name_buf); +} + +/** + Make a copy of the name string prefixed with the subarray name if necessary. +*/ +char * PFS_status_variable_cache::make_show_var_name(const char* prefix, const char* name) +{ + char name_buf[SHOW_VAR_MAX_NAME_LEN]; + size_t buf_len= sizeof(name_buf); + make_show_var_name(prefix, name, name_buf, buf_len); + return m_current_thd->strdup(name_buf); /* freed at statement end */ +} + +/** + Build an internal SHOW_VAR array from the external status variable array. +*/ +bool PFS_status_variable_cache::do_initialize_session(void) +{ + /* Acquire LOCK_status to guard against plugin load/unload. */ + //if (m_current_thd->fill_status_recursion_level++ == 0) + mysql_mutex_lock(&LOCK_status); + + bool ret= init_show_var_array(OPT_SESSION, true); + + //if (m_current_thd->fill_status_recursion_level-- == 1) + mysql_mutex_unlock(&LOCK_status); + + return ret; +} + +/** + For the current THD, use initial_status_vars taken from before the query start. +*/ +STATUS_VAR *PFS_status_variable_cache::set_status_vars(void) +{ + STATUS_VAR *status_vars; + if (m_safe_thd == m_current_thd && m_current_thd->initial_status_var != NULL) + status_vars= m_current_thd->initial_status_var; + else + status_vars= &m_safe_thd->status_var; + + return status_vars; +} + +/** + Build cache for GLOBAL status variables using values totaled from all threads. +*/ +int PFS_status_variable_cache::do_materialize_global(void) +{ + STATUS_VAR status_totals; + + m_materialized= false; + DEBUG_SYNC(m_current_thd, "before_materialize_global_status_array"); + + /* Acquire LOCK_status to guard against plugin load/unload. */ + //if (m_current_thd->fill_status_recursion_level++ == 0) + mysql_mutex_lock(&LOCK_status); + + /* + Build array of SHOW_VARs from global status array. Do this within + LOCK_status to ensure that the array remains unchanged during + materialization. + */ + if (!m_external_init) + init_show_var_array(OPT_GLOBAL, true); + + /* + Collect totals for all active threads. Start with global status vars as a + baseline. + */ + PFS_connection_status_visitor visitor(&status_totals); + PFS_connection_iterator::visit_global(false, /* hosts */ + false, /* users */ + false, /* accounts */ + false, /* threads */ + true, /* THDs */ + &visitor); + /* + Build the status variable cache using the SHOW_VAR array as a reference. + Use the status totals collected from all threads. + */ + manifest(m_current_thd, m_show_var_array.front(), &status_totals, "", false, true); + + //if (m_current_thd->fill_status_recursion_level-- == 1) + mysql_mutex_unlock(&LOCK_status); + + m_materialized= true; + DEBUG_SYNC(m_current_thd, "after_materialize_global_status_array"); + + return 0; +} + +/** + Build GLOBAL and SESSION status variable cache using values for a non-instrumented thread. +*/ +int PFS_status_variable_cache::do_materialize_all(THD* unsafe_thd) +{ + int ret= 1; + DBUG_ASSERT(unsafe_thd != NULL); + + m_unsafe_thd= unsafe_thd; + m_materialized= false; + m_cache.clear(); + + /* Avoid recursive acquisition of LOCK_status. */ + //if (m_current_thd->fill_status_recursion_level++ == 0) + mysql_mutex_lock(&LOCK_status); + + /* + Build array of SHOW_VARs from global status array. Do this within + LOCK_status to ensure that the array remains unchanged while this + thread is materialized. + */ + if (!m_external_init) + init_show_var_array(OPT_SESSION, false); + + /* Get and lock a validated THD from the thread manager. */ + if ((m_safe_thd= get_THD(unsafe_thd)) != NULL) + { + /* + Build the status variable cache using the SHOW_VAR array as a reference. + Use the status values from the THD protected by the thread manager lock. + */ + STATUS_VAR *status_vars= set_status_vars(); + manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, false); + + /* Release lock taken in get_THD(). */ + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_data); + + m_materialized= true; + ret= 0; + } + + //if (m_current_thd->fill_status_recursion_level-- == 1) + mysql_mutex_unlock(&LOCK_status); + return ret; +} + +/** + Build SESSION status variable cache using values for a non-instrumented thread. +*/ +int PFS_status_variable_cache::do_materialize_session(THD* unsafe_thd) +{ + int ret= 1; + DBUG_ASSERT(unsafe_thd != NULL); + + m_unsafe_thd= unsafe_thd; + m_materialized= false; + m_cache.clear(); + + /* Avoid recursive acquisition of LOCK_status. */ + //if (m_current_thd->fill_status_recursion_level++ == 0) + mysql_mutex_lock(&LOCK_status); + + /* + Build array of SHOW_VARs from global status array. Do this within + LOCK_status to ensure that the array remains unchanged while this + thread is materialized. + */ + if (!m_external_init) + init_show_var_array(OPT_SESSION, true); + + /* Get and lock a validated THD from the thread manager. */ + if ((m_safe_thd= get_THD(unsafe_thd)) != NULL) + { + /* + Build the status variable cache using the SHOW_VAR array as a reference. + Use the status values from the THD protected by the thread manager lock. + */ + STATUS_VAR *status_vars= set_status_vars(); + manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, true); + + /* Release lock taken in get_THD(). */ + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_data); + + m_materialized= true; + ret= 0; + } + + //if (m_current_thd->fill_status_recursion_level-- == 1) + mysql_mutex_unlock(&LOCK_status); + return ret; +} + +/** + Build SESSION status variable cache using values for a PFS_thread. + NOTE: Requires that init_show_var_array() has already been called. +*/ +int PFS_status_variable_cache::do_materialize_session(PFS_thread *pfs_thread) +{ + int ret= 1; + DBUG_ASSERT(pfs_thread != NULL); + + m_pfs_thread= pfs_thread; + m_materialized= false; + m_cache.clear(); + + /* Acquire LOCK_status to guard against plugin load/unload. */ + //if (m_current_thd->fill_status_recursion_level++ == 0) + mysql_mutex_lock(&LOCK_status); + + /* The SHOW_VAR array must be initialized externally. */ + DBUG_ASSERT(m_initialized); + + /* Get and lock a validated THD from the thread manager. */ + if ((m_safe_thd= get_THD(pfs_thread)) != NULL) + { + /* + Build the status variable cache using the SHOW_VAR array as a reference. + Use the status values from the THD protected by the thread manager lock. + */ + STATUS_VAR *status_vars= set_status_vars(); + manifest(m_safe_thd, m_show_var_array.front(), status_vars, "", false, true); + + /* Release lock taken in get_THD(). */ + mysql_mutex_unlock(&m_safe_thd->LOCK_thd_data); + + m_materialized= true; + ret= 0; + } + + //if (m_current_thd->fill_status_recursion_level-- == 1) + mysql_mutex_unlock(&LOCK_status); + return ret; +} + +/** + Build cache of SESSION status variables using the status values provided. + The cache is associated with a user, host or account, but not with any + particular thread. + NOTE: Requires that init_show_var_array() has already been called. +*/ +int PFS_status_variable_cache::do_materialize_client(PFS_client *pfs_client) +{ + DBUG_ASSERT(pfs_client != NULL); + STATUS_VAR status_totals; + + m_pfs_client= pfs_client; + m_materialized= false; + m_cache.clear(); + + /* Acquire LOCK_status to guard against plugin load/unload. */ + //if (m_current_thd->fill_status_recursion_level++ == 0) + mysql_mutex_lock(&LOCK_status); + + /* The SHOW_VAR array must be initialized externally. */ + DBUG_ASSERT(m_initialized); + + /* + Generate status totals from active threads and from totals aggregated + from disconnected threads. + */ + m_sum_client_status(pfs_client, &status_totals); + + /* + Build the status variable cache using the SHOW_VAR array as a reference and + the status totals collected from threads associated with this client. + */ + manifest(m_current_thd, m_show_var_array.front(), &status_totals, "", false, true); + + //if (m_current_thd->fill_status_recursion_level-- == 1) + mysql_mutex_unlock(&LOCK_status); + + m_materialized= true; + return 0; +} + +/* + Build the status variable cache from the expanded and sorted SHOW_VAR array. + Resolve status values using the STATUS_VAR struct provided. +*/ +void PFS_status_variable_cache::manifest(THD *thd, const SHOW_VAR *show_var_array, + STATUS_VAR *status_vars, const char *prefix, + bool nested_array, bool strict) +{ + for (const SHOW_VAR *show_var_iter= show_var_array; + show_var_iter && show_var_iter->name; + show_var_iter++) + { + // work buffer, must be aligned to handle long/longlong values + my_aligned_storage<SHOW_VAR_FUNC_BUFF_SIZE+1, MY_ALIGNOF(longlong)> + value_buf; + SHOW_VAR show_var_tmp; + const SHOW_VAR *show_var_ptr= show_var_iter; /* preserve array pointer */ + + /* + If the value is a function reference, then execute the function and + reevaluate the new SHOW_TYPE and value. Handle nested case where + SHOW_FUNC resolves to another SHOW_FUNC. + */ + if (show_var_ptr->type == SHOW_FUNC) + { + show_var_tmp= *show_var_ptr; + /* + Execute the function reference in show_var_tmp->value, which returns + show_var_tmp with a new type and new value. + */ + for (const SHOW_VAR *var= show_var_ptr; var->type == SHOW_FUNC; var= &show_var_tmp) + { + ((mysql_show_var_func)(var->value))(thd, &show_var_tmp, value_buf.data, NULL, m_query_scope); + } + show_var_ptr= &show_var_tmp; + } + + /* + If we are expanding a SHOW_ARRAY, filter variables that were not prefiltered by + init_show_var_array(). + */ + if (nested_array && filter_show_var(show_var_ptr, strict)) + continue; + + if (show_var_ptr->type == SHOW_ARRAY) + { + /* + Status variables of type SHOW_ARRAY were expanded and filtered by + init_show_var_array(), except where a SHOW_FUNC resolves into a + SHOW_ARRAY, such as with InnoDB. Recurse to expand the subarray. + */ + manifest(thd, (SHOW_VAR *)show_var_ptr->value, status_vars, show_var_ptr->name, true, strict); + } + else + { + /* Add the materialized status variable to the cache. */ + SHOW_VAR show_var= *show_var_ptr; + /* + For nested array expansions, make a copy of the variable name, just as + done in init_show_var_array(). + */ + if (nested_array) + show_var.name= make_show_var_name(prefix, show_var_ptr->name); + + /* Convert status value to string format. Add to the cache. */ + Status_variable status_var(&show_var, status_vars, m_query_scope); + m_cache.push(status_var); + } + } +} + +/** + CLASS Status_variable +*/ +Status_variable::Status_variable(const SHOW_VAR *show_var, STATUS_VAR *status_vars, enum_var_type query_scope) + : m_name_length(0), m_value_length(0), m_type(SHOW_UNDEF), + m_charset(NULL), m_initialized(false) +{ + init(show_var, status_vars, query_scope); +} + +/** + Resolve status value, convert to string. + show_var->value is an offset into status_vars. + NOTE: Assumes LOCK_status is held. +*/ +void Status_variable::init(const SHOW_VAR *show_var, STATUS_VAR *status_vars, enum_var_type query_scope) +{ + if (show_var == NULL || show_var->name == NULL) + return; + m_name= show_var->name; + m_name_length= strlen(m_name); + m_type= show_var->type; + + /* Get the value of the status variable. */ + char *value= m_value_str; + m_value_length= get_one_variable(status_vars, m_type, show_var->value, &value); + m_value_length= MY_MIN(m_value_length, SHOW_VAR_FUNC_BUFF_SIZE); + + /* Returned value may reference a string other than m_value_str. */ + if (value != m_value_str) + memcpy(m_value_str, value, m_value_length); + m_value_str[m_value_length]= 0; + + m_initialized= true; +} + +/* + Get status totals for this user from active THDs and related accounts. +*/ +void sum_user_status(PFS_client *pfs_user, STATUS_VAR *status_totals) +{ + PFS_connection_status_visitor visitor(status_totals); + PFS_connection_iterator::visit_user((PFS_user *)pfs_user, + true, /* accounts */ + false, /* threads */ + true, /* THDs */ + &visitor); +} + +/* + Get status totals for this host from active THDs and related accounts. +*/ +void sum_host_status(PFS_client *pfs_host, STATUS_VAR *status_totals) +{ + PFS_connection_status_visitor visitor(status_totals); + PFS_connection_iterator::visit_host((PFS_host *)pfs_host, + true, /* accounts */ + false, /* threads */ + true, /* THDs */ + &visitor); +} + +/* + Get status totals for this account from active THDs and from totals aggregated + from disconnectd threads. +*/ +void sum_account_status(PFS_client *pfs_account, STATUS_VAR *status_totals) +{ + PFS_connection_status_visitor visitor(status_totals); + PFS_connection_iterator::visit_account((PFS_account *)pfs_account, + false, /* threads */ + true, /* THDs */ + &visitor); +} + +/** + Reset aggregated status counter stats for account, user and host. + NOTE: Assumes LOCK_status is held. +*/ +void reset_pfs_status_stats() +{ + reset_status_by_account(); + reset_status_by_user(); + reset_status_by_host(); +} + +/** @} */ diff --git a/storage/perfschema/pfs_variable.h b/storage/perfschema/pfs_variable.h new file mode 100644 index 00000000000..eefca5612ea --- /dev/null +++ b/storage/perfschema/pfs_variable.h @@ -0,0 +1,718 @@ +/* Copyright (c) 2015, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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-1301, USA */ + +#ifndef PFS_VARIABLE_H +#define PFS_VARIABLE_H + +/** + @file storage/perfschema/pfs_variable.h + Performance schema system and status variables (declarations). +*/ + +/** + OVERVIEW + -------- + Status and system variables are implemented differently in the server, but the + steps to process them in the Performance Schema are essentially the same: + + 1. INITIALIZE - Build or acquire a sorted list of variables to use for input. + Use the SHOW_VAR struct as an intermediate format common to system, status + and user vars: + + SHOW_VAR + Name - Text string + Value - Pointer to memory location, function, subarray structure + Type - Scalar, function, or subarray + Scope - SESSION, GLOBAL, BOTH + + Steps: + - Register the server's internal buffer with the class. Acquire locks + if necessary, then scan the contents of the input buffer. + - For system variables, convert each element to SHOW_VAR format, store in + a temporary array. + - For status variables, copy existing global status array into a local + array that can be used without locks. Expand nested subarrays, indicated + by a type of SHOW_ARRAY. + + 2. MATERIALIZE - Convert the list of SHOW_VAR variables to string format, + store in a local cache: + - Resolve each variable according to the type. + - Recursively process unexpanded nested arrays and callback functions. + - Aggregate values across threads for global status. + - Convert numeric values to a string. + - Prefix variable name with the plugin name. + + 3. OUTPUT - Iterate the cache for the SHOW command or table query. + + CLASS OVERVIEW + -------------- + 1. System_variable - A materialized system variable + 2. Status_variable - A materialized status variable + 3. PFS_variable_cache - Base class that defines the interface for the operations above. + public + init_show_var_array() - Build SHOW_VAR list of variables for processing + materialize_global() - Materialize global variables, aggregate across sessions + materialize_session() - Materialize variables for a given PFS_thread or THD + materialize_user() - Materialize variables for a user, aggregate across related threads. + materialize_host() - Materialize variables for a host, aggregate across related threads. + materialize_account() - Materialize variables for a account, aggregate across related threads. + private + m_show_var_array - Prealloc_array of SHOW_VARs for input to Materialize + m_cache - Prealloc_array of materialized variables for output + do_materialize_global() - Implementation of materialize_global() + do_materialize_session() - Implementation of materialize_session() + do_materialize_client() - Implementation of materialize_user/host/account() + + 4. PFS_system_variable_cache - System variable implementation of PFS_variable_cache + 5. PFS_status_variable_cache - Status variable implementation of PFS_variable_cache + 6. Find_THD_variable - Used by the thread manager to find and lock a THD. + + GLOSSARY + -------- + Status variable - Server or plugin status counter. Not dynamic. + System variable - Server or plugin configuration variable. Usually dynamic. + GLOBAL scope - Associated with the server, no context at thread level. + SESSION scope - Associated with a connection or thread, but no global context. + BOTH scope - Globally defined but applies at the session level. + Initialize - Build list of variables in SHOW_VAR format. + Materialize - Convert variables in SHOW_VAR list to string, cache for output. + Manifest - Substep of Materialize. Resolve variable values according to + type. This includes SHOW_FUNC types which are resolved by + executing a callback function (possibly recursively), and + SHOW_ARRAY types that expand into nested subarrays. + LOCK PRIORITIES + --------------- + System Variables + LOCK_plugin_delete (block plugin delete) + LOCK_system_variables_hash + LOCK_thd_data (block THD delete) + LOCK_thd_sysvar (block system variable updates, alloc_and_copy_thd_dynamic_variables) + LOCK_global_system_variables (very briefly held) + + Status Variables + LOCK_status + LOCK_thd_data (block THD delete) +*/ + +/* Iteration on THD from the sql layer. */ +//#include "mysqld_thd_manager.h" +#define PFS_VAR +/* Class sys_var */ +#include "set_var.h" +/* convert_value_to_string */ +#include "sql_show.h" +/* PFS_thread */ +#include "pfs_instr.h" +#include "pfs_user.h" +#include "pfs_host.h" +#include "pfs_account.h" +#include "my_thread.h" + +/* Global array of all server and plugin-defined status variables. */ +extern DYNAMIC_ARRAY all_status_vars; +extern bool status_vars_inited; +static const uint SYSVAR_MEMROOT_BLOCK_SIZE = 4096; + +extern mysql_mutex_t LOCK_plugin_delete; + +class Find_THD_Impl; +class Find_THD_variable; +typedef PFS_connection_slice PFS_client; + +/** + CLASS System_variable - System variable derived from sys_var object. +*/ +class System_variable +{ +public: + System_variable(); + System_variable(THD *target_thd, const SHOW_VAR *show_var, + enum_var_type query_scope, bool ignore); + ~System_variable() {} + + bool is_null() const { return !m_initialized; } + bool is_ignored() const { return m_ignore; } + +public: + const char *m_name; + size_t m_name_length; + char m_value_str[SHOW_VAR_FUNC_BUFF_SIZE+1]; + size_t m_value_length; + enum_mysql_show_type m_type; + int m_scope; + bool m_ignore; + const CHARSET_INFO *m_charset; + +private: + bool m_initialized; + void init(THD *thd, const SHOW_VAR *show_var, enum_var_type query_scope); +}; + + +/** + CLASS Status_variable - Status variable derived from SHOW_VAR. +*/ +class Status_variable +{ +public: + Status_variable() : m_name(NULL), m_name_length(0), m_value_length(0), + m_type(SHOW_UNDEF), + m_charset(NULL), m_initialized(false) {} + + Status_variable(const SHOW_VAR *show_var, STATUS_VAR *status_array, enum_var_type query_scope); + + ~Status_variable() {} + + bool is_null() const {return !m_initialized;}; + +public: + const char *m_name; + size_t m_name_length; + char m_value_str[SHOW_VAR_FUNC_BUFF_SIZE+1]; + size_t m_value_length; + SHOW_TYPE m_type; + const CHARSET_INFO *m_charset; +private: + bool m_initialized; + void init(const SHOW_VAR *show_var, STATUS_VAR *status_array, enum_var_type query_scope); +}; + + +/** + CLASS Find_THD_variable - Get and lock a validated THD from the thread manager. +*/ +class Find_THD_variable //: public Find_THD_Impl +{ +public: + Find_THD_variable() : m_unsafe_thd(NULL) {} + Find_THD_variable(THD *unsafe_thd) : m_unsafe_thd(unsafe_thd) {} + + virtual bool operator()(THD *thd) + { + //TODO: filter bg threads? + if (thd != m_unsafe_thd) + return false; + + /* Hold this lock to keep THD during materialization. */ + mysql_mutex_lock(&thd->LOCK_thd_data); + return true; + } + void set_unsafe_thd(THD *unsafe_thd) { m_unsafe_thd= unsafe_thd; } +private: + THD *m_unsafe_thd; +}; + +/** + CLASS PFS_variable_cache - Base class for a system or status variable cache. +*/ +template <class Var_type> +class PFS_variable_cache +{ +public: + typedef Dynamic_array<Var_type> Variable_array; + + PFS_variable_cache(bool external_init) + : m_safe_thd(NULL), + m_unsafe_thd(NULL), + m_current_thd(current_thd), + m_pfs_thread(NULL), + m_pfs_client(NULL), + //m_thd_finder(), + m_cache(PSI_INSTRUMENT_MEM, 200, 50), + m_initialized(false), + m_external_init(external_init), + m_materialized(false), + m_show_var_array(PSI_INSTRUMENT_MEM, 200, 50), + m_version(0), + m_query_scope(OPT_DEFAULT), + m_use_mem_root(false), + m_aggregate(false) + { } + + virtual ~PFS_variable_cache()= 0; + + /** + Build array of SHOW_VARs from the external variable source. + Filter using session scope. + */ + bool initialize_session(void); + + /** + Build array of SHOW_VARs suitable for aggregation by user, host or account. + Filter using session scope. + */ + bool initialize_client_session(void); + + /** + Build cache of GLOBAL system or status variables. + Aggregate across threads if applicable. + */ + int materialize_global(); + + /** + Build cache of GLOBAL and SESSION variables for a non-instrumented thread. + */ + int materialize_all(THD *thd); + + /** + Build cache of SESSION variables for a non-instrumented thread. + */ + int materialize_session(THD *thd); + + /** + Build cache of SESSION variables for an instrumented thread. + */ + int materialize_session(PFS_thread *pfs_thread, bool use_mem_root= false); + + /** + Cache a single SESSION variable for an instrumented thread. + */ + int materialize_session(PFS_thread *pfs_thread, uint index); + + /** + Build cache of SESSION status variables for a user. + */ + int materialize_user(PFS_user *pfs_user); + + /** + Build cache of SESSION status variables for a host. + */ + int materialize_host(PFS_host *pfs_host); + + /** + Build cache of SESSION status variables for an account. + */ + int materialize_account(PFS_account *pfs_account); + + /** + True if variables have been materialized. + */ + bool is_materialized(void) + { + return m_materialized; + } + + /** + True if variables have been materialized for given THD. + */ + bool is_materialized(THD *unsafe_thd) + { + return (unsafe_thd == m_unsafe_thd && m_materialized); + } + + /** + True if variables have been materialized for given PFS_thread. + */ + bool is_materialized(PFS_thread *pfs_thread) + { + return (pfs_thread == m_pfs_thread && m_materialized); + } + + /** + True if variables have been materialized for given PFS_user. + */ + bool is_materialized(PFS_user *pfs_user) + { + return (static_cast<PFS_client *>(pfs_user) == m_pfs_client && m_materialized); + } + + /** + True if variables have been materialized for given PFS_host. + */ + bool is_materialized(PFS_host *pfs_host) + { + return (static_cast<PFS_client *>(pfs_host) == m_pfs_client && m_materialized); + } + + /** + True if variables have been materialized for given PFS_account. + */ + bool is_materialized(PFS_account *pfs_account) + { + return (static_cast<PFS_client *>(pfs_account) == m_pfs_client && m_materialized); + } + + /** + True if variables have been materialized for given PFS_user/host/account. + */ + bool is_materialized(PFS_client *pfs_client) + { + return (static_cast<PFS_client *>(pfs_client) == m_pfs_client && m_materialized); + } + + /** + Get a validated THD from the thread manager. Execute callback function while + inside of the thread manager locks. + */ + THD *get_THD(THD *thd); + THD *get_THD(PFS_thread *pfs_thread); + + /** + Get a single variable from the cache. + Get the first element in the cache by default. + */ + const Var_type *get(uint index= 0) const + { + if (index >= m_cache.elements()) + return NULL; + + const Var_type *p= &m_cache.at(index); + return p; + } + + /** + Number of elements in the cache. + */ + uint size() + { + return (uint)m_cache.elements(); + } + +private: + virtual bool do_initialize_global(void) { return true; } + virtual bool do_initialize_session(void) { return true; } + virtual int do_materialize_global(void) { return 1; } + virtual int do_materialize_all(THD *thd) { return 1; } + virtual int do_materialize_session(THD *thd) { return 1; } + virtual int do_materialize_session(PFS_thread *) { return 1; } + virtual int do_materialize_session(PFS_thread *, uint index) { return 1; } + +protected: + /* Validated THD */ + THD *m_safe_thd; + + /* Unvalidated THD */ + THD *m_unsafe_thd; + + /* Current THD */ + THD *m_current_thd; + + /* Current PFS_thread. */ + PFS_thread *m_pfs_thread; + + /* Current PFS_user, host or account. */ + PFS_client *m_pfs_client; + + /* Callback for thread iterator. */ + //Find_THD_variable m_thd_finder; + + /* Cache of materialized variables. */ + Variable_array m_cache; + + /* True when list of SHOW_VAR is complete. */ + bool m_initialized; + + /* + True if the SHOW_VAR array must be initialized externally from the + materialization step, such as with aggregations and queries by thread. + */ + bool m_external_init; + + /* True when cache is complete. */ + bool m_materialized; + + /* Array of variables to be materialized. Last element must be null. */ + Dynamic_array<SHOW_VAR> m_show_var_array; + + /* Version of global hash/array. Changes when vars added/removed. */ + ulonglong m_version; + + /* Query scope: GLOBAL or SESSION. */ + enum_var_type m_query_scope; + + /* True if temporary mem_root should be used for materialization. */ + bool m_use_mem_root; + + /* True if summarizing across users, hosts or accounts. */ + bool m_aggregate; + +}; + +#if 0 +/** + Required implementation for pure virtual destructor of a template class. +*/ +template <class Var_type> +PFS_variable_cache<Var_type>::~PFS_variable_cache() +{ +} + +/** + Get a validated THD from the thread manager. Execute callback function while + while inside the thread manager lock. +*/ +template <class Var_type> +THD *PFS_variable_cache<Var_type>::get_THD(THD *unsafe_thd) +{ + if (unsafe_thd == NULL) + { + /* + May happen, precisely because the pointer is unsafe + (THD just disconnected for example). + No need to walk Global_THD_manager for that. + */ + return NULL; + } + + m_thd_finder.set_unsafe_thd(unsafe_thd); + THD* safe_thd= Global_THD_manager::get_instance()->find_thd(&m_thd_finder); + return safe_thd; +} + +template <class Var_type> +THD *PFS_variable_cache<Var_type>::get_THD(PFS_thread *pfs_thread) +{ + DBUG_ASSERT(pfs_thread != NULL); + return get_THD(pfs_thread->m_thd); +} + +/** + Build array of SHOW_VARs from external source of system or status variables. + Filter using session scope. +*/ +template <class Var_type> +bool PFS_variable_cache<Var_type>::initialize_session(void) +{ + if (m_initialized) + return 0; + + return do_initialize_session(); +} + +/** + Build array of SHOW_VARs suitable for aggregation by user, host or account. + Filter using session scope. +*/ +template <class Var_type> +bool PFS_variable_cache<Var_type>::initialize_client_session(void) +{ + if (m_initialized) + return 0; + + /* Requires aggregation by user, host or account. */ + m_aggregate= true; + + return do_initialize_session(); +} + +/** + Build cache of all GLOBAL variables. +*/ +template <class Var_type> +int PFS_variable_cache<Var_type>::materialize_global() +{ + if (is_materialized()) + return 0; + + return do_materialize_global(); +} + +/** + Build cache of GLOBAL and SESSION variables for a non-instrumented thread. +*/ +template <class Var_type> +int PFS_variable_cache<Var_type>::materialize_all(THD *unsafe_thd) +{ + if (!unsafe_thd) + return 1; + + if (is_materialized(unsafe_thd)) + return 0; + + return do_materialize_all(unsafe_thd); +} + +/** + Build cache of SESSION variables for a non-instrumented thread. +*/ +template <class Var_type> +int PFS_variable_cache<Var_type>::materialize_session(THD *unsafe_thd) +{ + if (!unsafe_thd) + return 1; + + if (is_materialized(unsafe_thd)) + return 0; + + return do_materialize_session(unsafe_thd); +} + +/** + Build cache of SESSION variables for a thread. +*/ +template <class Var_type> +int PFS_variable_cache<Var_type>::materialize_session(PFS_thread *pfs_thread, bool use_mem_root) +{ + if (!pfs_thread) + return 1; + + if (is_materialized(pfs_thread)) + return 0; + + if (!pfs_thread->m_lock.is_populated() || pfs_thread->m_thd == NULL) + return 1; + + m_use_mem_root= use_mem_root; + + return do_materialize_session(pfs_thread); +} + +/** + Materialize a single variable for a thread. +*/ +template <class Var_type> +int PFS_variable_cache<Var_type>::materialize_session(PFS_thread *pfs_thread, uint index) +{ + /* No check for is_materialized(). */ + + if (!pfs_thread) + return 1; + + if (!pfs_thread->m_lock.is_populated() || pfs_thread->m_thd == NULL) + return 1; + + return do_materialize_session(pfs_thread, index); +} +#endif + +/** + CLASS PFS_system_variable_cache - System variable cache. +*/ +class PFS_system_variable_cache : public PFS_variable_cache<System_variable> +{ +public: + PFS_system_variable_cache(bool external_init) : + PFS_variable_cache<System_variable>(external_init), + m_mem_thd(NULL), m_mem_thd_save(NULL), + m_mem_sysvar_ptr(NULL) { } + bool match_scope(int scope); + ulonglong get_sysvar_hash_version(void) { return m_version; } + ~PFS_system_variable_cache() { free_mem_root(); } + +private: + /* Build SHOW_var array. */ + bool init_show_var_array(enum_var_type scope, bool strict); + bool do_initialize_session(void); + + /* Global */ + int do_materialize_global(void); + /* Global and Session - THD */ + int do_materialize_all(THD* thd); + /* Session - THD */ + int do_materialize_session(THD* thd); + /* Session - PFS_thread */ + int do_materialize_session(PFS_thread *thread); + /* Single variable - PFS_thread */ + int do_materialize_session(PFS_thread *pfs_thread, uint index); + + /* Temporary mem_root to use for materialization. */ + MEM_ROOT m_mem_sysvar; + /* Pointer to THD::mem_root. */ + MEM_ROOT **m_mem_thd; + /* Save THD::mem_root. */ + MEM_ROOT *m_mem_thd_save; + /* Pointer to temporary mem_root. */ + MEM_ROOT *m_mem_sysvar_ptr; + /* Allocate and/or assign temporary mem_root. */ + void set_mem_root(void); + /* Mark all memory blocks as free in temporary mem_root. */ + void clear_mem_root(void); + /* Free mem_root memory. */ + void free_mem_root(void); +}; + + +/** + CLASS PFS_status_variable_cache - Status variable cache +*/ +class PFS_status_variable_cache : public PFS_variable_cache<Status_variable> +{ +public: + PFS_status_variable_cache(bool external_init); + + int materialize_user(PFS_user *pfs_user); + int materialize_host(PFS_host *pfs_host); + int materialize_account(PFS_account *pfs_account); + + ulonglong get_status_array_version(void) { return m_version; } + +protected: + /* Get PFS_user, account or host associated with a PFS_thread. Implemented by table class. */ + virtual PFS_client *get_pfs(PFS_thread *pfs_thread) { return NULL; } + + /* True if query is a SHOW command. */ + bool m_show_command; + +private: + bool do_initialize_session(void); + + int do_materialize_global(void); + /* Global and Session - THD */ + int do_materialize_all(THD* thd); + int do_materialize_session(THD *thd); + int do_materialize_session(PFS_thread *thread); + int do_materialize_session(PFS_thread *thread, uint index) { return 0; } + int do_materialize_client(PFS_client *pfs_client); + + /* Callback to sum user, host or account status variables. */ + void (*m_sum_client_status)(PFS_client *pfs_client, STATUS_VAR *status_totals); + + /* Build SHOW_VAR array from external source. */ + bool init_show_var_array(enum_var_type scope, bool strict); + + /* Recursively expand nested SHOW_VAR arrays. */ + void expand_show_var_array(const SHOW_VAR *show_var_array, const char *prefix, bool strict); + + /* Exclude unwanted variables from the query. */ + bool filter_show_var(const SHOW_VAR *show_var, bool strict); + + /* Check the variable scope against the query scope. */ + bool match_scope(SHOW_SCOPE variable_scope, bool strict); + + /* Exclude specific status variables by name or prefix. */ + bool filter_by_name(const SHOW_VAR *show_var); + + /* Check if a variable has an aggregatable type. */ + bool can_aggregate(enum_mysql_show_type variable_type); + + /* Build status variable name with prefix. Return in the buffer provided. */ + char *make_show_var_name(const char* prefix, const char* name, char *name_buf, size_t buf_len); + + /* Build status variable name with prefix. Return copy of the string. */ + char *make_show_var_name(const char* prefix, const char* name); + + /* For the current THD, use initial_status_vars taken from before the query start. */ + STATUS_VAR *set_status_vars(void); + + /* Build the list of status variables from SHOW_VAR array. */ + void manifest(THD *thd, const SHOW_VAR *show_var_array, + STATUS_VAR *status_var_array, const char *prefix, bool nested_array, bool strict); +}; + +/* Callback functions to sum status variables for a given user, host or account. */ +void sum_user_status(PFS_client *pfs_user, STATUS_VAR *status_totals); +void sum_host_status(PFS_client *pfs_host, STATUS_VAR *status_totals); +void sum_account_status(PFS_client *pfs_account, STATUS_VAR *status_totals); + + +/** @} */ +#endif diff --git a/storage/perfschema/pfs_visitor.cc b/storage/perfschema/pfs_visitor.cc index 097965fde17..713139ef935 100644 --- a/storage/perfschema/pfs_visitor.cc +++ b/storage/perfschema/pfs_visitor.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -28,6 +28,7 @@ #include "pfs_user.h" #include "pfs_host.h" #include "pfs_account.h" +#include "pfs_buffer_container.h" /** @file storage/perfschema/pfs_visitor.cc @@ -39,182 +40,330 @@ @{ */ +class All_THD_visitor_adapter : public Do_THD_Impl +{ +public: + All_THD_visitor_adapter(PFS_connection_visitor *visitor) + : m_visitor(visitor) + {} + + virtual void operator()(THD *thd) + { + m_visitor->visit_THD(thd); + } + +private: + PFS_connection_visitor *m_visitor; +}; + /** Connection iterator */ void PFS_connection_iterator::visit_global(bool with_hosts, bool with_users, bool with_accounts, bool with_threads, + bool with_THDs, PFS_connection_visitor *visitor) { DBUG_ASSERT(visitor != NULL); + DBUG_ASSERT(! with_threads || ! with_THDs); visitor->visit_global(); if (with_hosts) { - PFS_host *pfs= host_array; - PFS_host *pfs_last= pfs + host_max; - for ( ; pfs < pfs_last; pfs++) + PFS_host_iterator it= global_host_container.iterate(); + PFS_host *pfs= it.scan_next(); + + while (pfs != NULL) { - if (pfs->m_lock.is_populated()) - visitor->visit_host(pfs); + visitor->visit_host(pfs); + pfs= it.scan_next(); } } if (with_users) { - PFS_user *pfs= user_array; - PFS_user *pfs_last= pfs + user_max; - for ( ; pfs < pfs_last; pfs++) + PFS_user_iterator it= global_user_container.iterate(); + PFS_user *pfs= it.scan_next(); + + while (pfs != NULL) { - if (pfs->m_lock.is_populated()) - visitor->visit_user(pfs); + visitor->visit_user(pfs); + pfs= it.scan_next(); } } if (with_accounts) { - PFS_account *pfs= account_array; - PFS_account *pfs_last= pfs + account_max; - for ( ; pfs < pfs_last; pfs++) + PFS_account_iterator it= global_account_container.iterate(); + PFS_account *pfs= it.scan_next(); + + while (pfs != NULL) { - if (pfs->m_lock.is_populated()) - visitor->visit_account(pfs); + visitor->visit_account(pfs); + pfs= it.scan_next(); } } + if (with_threads) { - PFS_thread *pfs= thread_array; - PFS_thread *pfs_last= pfs + thread_max; - for ( ; pfs < pfs_last; pfs++) + PFS_thread_iterator it= global_thread_container.iterate(); + PFS_thread *pfs= it.scan_next(); + + while (pfs != NULL) { - if (pfs->m_lock.is_populated()) - visitor->visit_thread(pfs); + visitor->visit_thread(pfs); + pfs= it.scan_next(); } } + + if (with_THDs) + { + All_THD_visitor_adapter adapter(visitor); + Global_THD_manager::get_instance()->do_for_all_thd(& adapter); + } } +class All_host_THD_visitor_adapter : public Do_THD_Impl +{ +public: + All_host_THD_visitor_adapter(PFS_connection_visitor *visitor, PFS_host *host) + : m_visitor(visitor), m_host(host) + {} + + virtual void operator()(THD *thd) + { + PSI_thread *psi= thd->get_psi(); + PFS_thread *pfs= reinterpret_cast<PFS_thread*>(psi); + pfs= sanitize_thread(pfs); + if (pfs != NULL) + { + PFS_account *account= sanitize_account(pfs->m_account); + if (account != NULL) + { + if (account->m_host == m_host) + { + m_visitor->visit_THD(thd); + } + } + else if (pfs->m_host == m_host) + { + m_visitor->visit_THD(thd); + } + } + } + +private: + PFS_connection_visitor *m_visitor; + PFS_host *m_host; +}; + void PFS_connection_iterator::visit_host(PFS_host *host, bool with_accounts, bool with_threads, + bool with_THDs, PFS_connection_visitor *visitor) { DBUG_ASSERT(visitor != NULL); + DBUG_ASSERT(! with_threads || ! with_THDs); visitor->visit_host(host); if (with_accounts) { - PFS_account *pfs= account_array; - PFS_account *pfs_last= pfs + account_max; - for ( ; pfs < pfs_last; pfs++) + PFS_account_iterator it= global_account_container.iterate(); + PFS_account *pfs= it.scan_next(); + + while (pfs != NULL) { - if ((pfs->m_host == host) && pfs->m_lock.is_populated()) + if (pfs->m_host == host) { visitor->visit_account(pfs); } + pfs= it.scan_next(); } } if (with_threads) { - PFS_thread *pfs= thread_array; - PFS_thread *pfs_last= pfs + thread_max; - for ( ; pfs < pfs_last; pfs++) + PFS_thread_iterator it= global_thread_container.iterate(); + PFS_thread *pfs= it.scan_next(); + + while (pfs != NULL) { - if (pfs->m_lock.is_populated()) + PFS_account *safe_account= sanitize_account(pfs->m_account); + if (((safe_account != NULL) && (safe_account->m_host == host)) /* 1 */ + || (pfs->m_host == host)) /* 2 */ { - 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: + - (1) a known user@host that belongs to this host, + - (2) a 'lost' user@host that belongs to this host + process it. + */ + visitor->visit_thread(pfs); + } + pfs= it.scan_next(); + } + } + + if (with_THDs) + { + All_host_THD_visitor_adapter adapter(visitor, host); + Global_THD_manager::get_instance()->do_for_all_thd(& adapter); + } +} + +class All_user_THD_visitor_adapter : public Do_THD_Impl +{ +public: + All_user_THD_visitor_adapter(PFS_connection_visitor *visitor, PFS_user *user) + : m_visitor(visitor), m_user(user) + {} + + virtual void operator()(THD *thd) + { + PSI_thread *psi= thd->get_psi(); + PFS_thread *pfs= reinterpret_cast<PFS_thread*>(psi); + pfs= sanitize_thread(pfs); + if (pfs != NULL) + { + PFS_account *account= sanitize_account(pfs->m_account); + if (account != NULL) + { + if (account->m_user == m_user) { - /* - If the thread belongs to a 'lost' user@host that belong to this host, - process it. - */ - visitor->visit_thread(pfs); + m_visitor->visit_THD(thd); } } + else if (pfs->m_user == m_user) + { + m_visitor->visit_THD(thd); + } } } -} + +private: + PFS_connection_visitor *m_visitor; + PFS_user *m_user; +}; void PFS_connection_iterator::visit_user(PFS_user *user, bool with_accounts, bool with_threads, + bool with_THDs, PFS_connection_visitor *visitor) { DBUG_ASSERT(visitor != NULL); + DBUG_ASSERT(! with_threads || ! with_THDs); visitor->visit_user(user); if (with_accounts) { - PFS_account *pfs= account_array; - PFS_account *pfs_last= pfs + account_max; - for ( ; pfs < pfs_last; pfs++) + PFS_account_iterator it= global_account_container.iterate(); + PFS_account *pfs= it.scan_next(); + + while (pfs != NULL) { - if ((pfs->m_user == user) && pfs->m_lock.is_populated()) + if (pfs->m_user == user) { visitor->visit_account(pfs); } + pfs= it.scan_next(); } } if (with_threads) { - PFS_thread *pfs= thread_array; - PFS_thread *pfs_last= pfs + thread_max; - for ( ; pfs < pfs_last; pfs++) + PFS_thread_iterator it= global_thread_container.iterate(); + PFS_thread *pfs= it.scan_next(); + + while (pfs != NULL) { - if (pfs->m_lock.is_populated()) + PFS_account *safe_account= sanitize_account(pfs->m_account); + if (((safe_account != NULL) && (safe_account->m_user == user)) /* 1 */ + || (pfs->m_user == user)) /* 2 */ { - 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); - } + /* + If the thread belongs to: + - (1) a known user@host that belongs to this user, + - (2) a 'lost' user@host that belongs to this user + process it. + */ + visitor->visit_thread(pfs); } + pfs= it.scan_next(); } } + + if (with_THDs) + { + All_user_THD_visitor_adapter adapter(visitor, user); + Global_THD_manager::get_instance()->do_for_all_thd(& adapter); + } } +class All_account_THD_visitor_adapter : public Do_THD_Impl +{ +public: + All_account_THD_visitor_adapter(PFS_connection_visitor *visitor, PFS_account *account) + : m_visitor(visitor), m_account(account) + {} + + virtual void operator()(THD *thd) + { + PSI_thread *psi= thd->get_psi(); + PFS_thread *pfs= reinterpret_cast<PFS_thread*>(psi); + pfs= sanitize_thread(pfs); + if (pfs != NULL) + { + if (pfs->m_account == m_account) + { + m_visitor->visit_THD(thd); + } + } + } + +private: + PFS_connection_visitor *m_visitor; + PFS_account *m_account; +}; + void PFS_connection_iterator::visit_account(PFS_account *account, - bool with_threads, - PFS_connection_visitor *visitor) + bool with_threads, + bool with_THDs, + PFS_connection_visitor *visitor) { DBUG_ASSERT(visitor != NULL); + DBUG_ASSERT(! with_threads || ! with_THDs); visitor->visit_account(account); if (with_threads) { - PFS_thread *pfs= thread_array; - PFS_thread *pfs_last= pfs + thread_max; - for ( ; pfs < pfs_last; pfs++) + PFS_thread_iterator it= global_thread_container.iterate(); + PFS_thread *pfs= it.scan_next(); + + while (pfs != NULL) { - if ((pfs->m_account == account) && pfs->m_lock.is_populated()) + if (pfs->m_account == account) { visitor->visit_thread(pfs); } + pfs= it.scan_next(); } } + + if (with_THDs) + { + All_account_THD_visitor_adapter adapter(visitor, account); + Global_THD_manager::get_instance()->do_for_all_thd(& adapter); + } +} + +void PFS_connection_iterator::visit_THD(THD *thd, + PFS_connection_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + visitor->visit_THD(thd); } void PFS_instance_iterator::visit_all(PFS_instance_visitor *visitor) @@ -246,14 +395,13 @@ void PFS_instance_iterator::visit_all_mutex_classes(PFS_instance_visitor *visito 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++) + PFS_mutex_iterator it= global_mutex_container.iterate(); + PFS_mutex *pfs= it.scan_next(); + + while (pfs != NULL) { - if (pfs->m_lock.is_populated()) - { - visitor->visit_mutex(pfs); - } + visitor->visit_mutex(pfs); + pfs= it.scan_next(); } } @@ -278,14 +426,13 @@ void PFS_instance_iterator::visit_all_rwlock_classes(PFS_instance_visitor *visit 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++) + PFS_rwlock_iterator it= global_rwlock_container.iterate(); + PFS_rwlock *pfs= it.scan_next(); + + while (pfs != NULL) { - if (pfs->m_lock.is_populated()) - { - visitor->visit_rwlock(pfs); - } + visitor->visit_rwlock(pfs); + pfs= it.scan_next(); } } @@ -310,14 +457,13 @@ void PFS_instance_iterator::visit_all_cond_classes(PFS_instance_visitor *visitor 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++) + PFS_cond_iterator it= global_cond_container.iterate(); + PFS_cond *pfs= it.scan_next(); + + while (pfs != NULL) { - if (pfs->m_lock.is_populated()) - { - visitor->visit_cond(pfs); - } + visitor->visit_cond(pfs); + pfs= it.scan_next(); } } @@ -342,14 +488,13 @@ void PFS_instance_iterator::visit_all_file_classes(PFS_instance_visitor *visitor 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++) + PFS_file_iterator it= global_file_container.iterate(); + PFS_file *pfs= it.scan_next(); + + while (pfs != NULL) { - if (pfs->m_lock.is_populated()) - { - visitor->visit_file(pfs); - } + visitor->visit_file(pfs); + pfs= it.scan_next(); } } @@ -375,14 +520,16 @@ void PFS_instance_iterator::visit_mutex_instances(PFS_mutex_class *klass, } else { - PFS_mutex *pfs= mutex_array; - PFS_mutex *pfs_last= pfs + mutex_max; - for ( ; pfs < pfs_last; pfs++) + PFS_mutex_iterator it= global_mutex_container.iterate(); + PFS_mutex *pfs= it.scan_next(); + + while (pfs != NULL) { - if ((pfs->m_class == klass) && pfs->m_lock.is_populated()) + if (pfs->m_class == klass) { visitor->visit_mutex(pfs); } + pfs= it.scan_next(); } } } @@ -407,14 +554,16 @@ void PFS_instance_iterator::visit_rwlock_instances(PFS_rwlock_class *klass, } else { - PFS_rwlock *pfs= rwlock_array; - PFS_rwlock *pfs_last= pfs + rwlock_max; - for ( ; pfs < pfs_last; pfs++) + PFS_rwlock_iterator it= global_rwlock_container.iterate(); + PFS_rwlock *pfs= it.scan_next(); + + while (pfs != NULL) { - if ((pfs->m_class == klass) && pfs->m_lock.is_populated()) + if (pfs->m_class == klass) { visitor->visit_rwlock(pfs); } + pfs= it.scan_next(); } } } @@ -439,14 +588,16 @@ void PFS_instance_iterator::visit_cond_instances(PFS_cond_class *klass, } else { - PFS_cond *pfs= cond_array; - PFS_cond *pfs_last= pfs + cond_max; - for ( ; pfs < pfs_last; pfs++) + PFS_cond_iterator it= global_cond_container.iterate(); + PFS_cond *pfs= it.scan_next(); + + while (pfs != NULL) { - if ((pfs->m_class == klass) && pfs->m_lock.is_populated()) + if (pfs->m_class == klass) { visitor->visit_cond(pfs); } + pfs= it.scan_next(); } } } @@ -471,14 +622,16 @@ void PFS_instance_iterator::visit_file_instances(PFS_file_class *klass, } else { - PFS_file *pfs= file_array; - PFS_file *pfs_last= pfs + file_max; - for ( ; pfs < pfs_last; pfs++) + PFS_file_iterator it= global_file_container.iterate(); + PFS_file *pfs= it.scan_next(); + + while (pfs != NULL) { - if ((pfs->m_class == klass) && pfs->m_lock.is_populated()) + if (pfs->m_class == klass) { visitor->visit_file(pfs); } + pfs= it.scan_next(); } } } @@ -505,14 +658,16 @@ void PFS_instance_iterator::visit_socket_instances(PFS_socket_class *klass, } else { - PFS_socket *pfs= socket_array; - PFS_socket *pfs_last= pfs + socket_max; - for ( ; pfs < pfs_last; pfs++) + PFS_socket_iterator it= global_socket_container.iterate(); + PFS_socket *pfs= it.scan_next(); + + while (pfs != NULL) { - if ((pfs->m_class == klass) && pfs->m_lock.is_populated()) + if (pfs->m_class == klass) { visitor->visit_socket(pfs); } + pfs= it.scan_next(); } } } @@ -542,16 +697,17 @@ void PFS_instance_iterator::visit_socket_instances(PFS_socket_class *klass, 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; + PFS_socket_iterator it= global_socket_container.iterate(); + PFS_socket *pfs= it.scan_next(); - for ( ; pfs < pfs_last; pfs++) + while (pfs != NULL) { if (unlikely((pfs->m_class == klass) && (pfs->m_thread_owner == thread))) { visitor->visit_socket(pfs); } + pfs= it.scan_next(); } } } @@ -586,53 +742,127 @@ 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) +class Proc_all_table_shares + : public PFS_buffer_processor<PFS_table_share> { - DBUG_ASSERT(visitor != NULL); +public: + Proc_all_table_shares(PFS_object_visitor *visitor) + : m_visitor(visitor) + {} - visitor->visit_global(); + virtual void operator()(PFS_table_share *pfs) + { + if (pfs->m_enabled) + { + m_visitor->visit_table_share(pfs); + } + } - /* 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++) +private: + PFS_object_visitor* m_visitor; +}; + +class Proc_all_table_handles + : public PFS_buffer_processor<PFS_table> +{ +public: + Proc_all_table_handles(PFS_object_visitor *visitor) + : m_visitor(visitor) + {} + + virtual void operator()(PFS_table *pfs) { - if (share->m_lock.is_populated()) + PFS_table_share *safe_share= sanitize_table_share(pfs->m_share); + if (safe_share != NULL) { - visitor->visit_table_share(share); + if (safe_share->m_enabled) + { + m_visitor->visit_table(pfs); + } } } +private: + PFS_object_visitor* m_visitor; +}; + +void PFS_object_iterator::visit_all_tables(PFS_object_visitor *visitor) +{ + DBUG_ASSERT(visitor != NULL); + + visitor->visit_global(); + + /* For all the table shares ... */ + Proc_all_table_shares proc_shares(visitor); + global_table_share_container.apply(proc_shares); + /* For all the table handles ... */ - PFS_table *table= table_array; - PFS_table *table_last= table_array + table_max; - for ( ; table < table_last; table++) + Proc_all_table_handles proc_handles(visitor); + global_table_container.apply(proc_handles); +} + +class Proc_one_table_share_handles + : public PFS_buffer_processor<PFS_table> +{ +public: + Proc_one_table_share_handles(PFS_object_visitor *visitor, PFS_table_share *share) + : m_visitor(visitor), m_share(share) + {} + + virtual void operator()(PFS_table *pfs) { - if (table->m_lock.is_populated()) + if (pfs->m_share == m_share) { - visitor->visit_table(table); + m_visitor->visit_table(pfs); } } -} + +private: + PFS_object_visitor* m_visitor; + PFS_table_share* m_share; +}; void PFS_object_iterator::visit_tables(PFS_table_share *share, PFS_object_visitor *visitor) { DBUG_ASSERT(visitor != NULL); + if (!share->m_enabled) + return; + visitor->visit_table_share(share); +#ifdef LATER + if (share->get_refcount() == 0) + return; +#endif + /* For all the table handles ... */ - PFS_table *table= table_array; - PFS_table *table_last= table_array + table_max; - for ( ; table < table_last; table++) + Proc_one_table_share_handles proc(visitor, share); + global_table_container.apply(proc); +} + +class Proc_one_table_share_indexes + : public PFS_buffer_processor<PFS_table> +{ +public: + Proc_one_table_share_indexes(PFS_object_visitor *visitor, PFS_table_share *share, uint index) + : m_visitor(visitor), m_share(share), m_index(index) + {} + + virtual void operator()(PFS_table *pfs) { - if ((table->m_share == share) && table->m_lock.is_populated()) + if (pfs->m_share == m_share) { - visitor->visit_table(table); + m_visitor->visit_table_index(pfs, m_index); } } -} + +private: + PFS_object_visitor* m_visitor; + PFS_table_share* m_share; + uint m_index; +}; void PFS_object_iterator::visit_table_indexes(PFS_table_share *share, uint index, @@ -640,18 +870,19 @@ void PFS_object_iterator::visit_table_indexes(PFS_table_share *share, { DBUG_ASSERT(visitor != NULL); + if (!share->m_enabled) + return; + visitor->visit_table_share_index(share, index); +#ifdef LATER + if (share->get_refcount() == 0) + return; +#endif + /* 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); - } - } + Proc_one_table_share_indexes proc(visitor, share, index); + global_table_container.apply(proc); } /** Connection wait visitor */ @@ -668,32 +899,62 @@ PFS_connection_wait_visitor::~PFS_connection_wait_visitor() void PFS_connection_wait_visitor::visit_global() { /* - This visitor is used only for idle instruments. + This visitor is used only for global instruments + that do not have instances. 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); + DBUG_ASSERT( (m_index == global_idle_class.m_event_name_index) + || (m_index == global_metadata_class.m_event_name_index)); + + if (m_index == global_idle_class.m_event_name_index) + { + m_stat.aggregate(& global_idle_stat); + } + else + { + m_stat.aggregate(& global_metadata_stat); + } } void PFS_connection_wait_visitor::visit_host(PFS_host *pfs) { - m_stat.aggregate(& pfs->m_instr_class_waits_stats[m_index]); + const PFS_single_stat *event_name_array; + event_name_array= pfs->read_instr_class_waits_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } } void PFS_connection_wait_visitor::visit_user(PFS_user *pfs) { - m_stat.aggregate(& pfs->m_instr_class_waits_stats[m_index]); + const PFS_single_stat *event_name_array; + event_name_array= pfs->read_instr_class_waits_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } } void PFS_connection_wait_visitor::visit_account(PFS_account *pfs) { - m_stat.aggregate(& pfs->m_instr_class_waits_stats[m_index]); + const PFS_single_stat *event_name_array; + event_name_array= pfs->read_instr_class_waits_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } } void PFS_connection_wait_visitor::visit_thread(PFS_thread *pfs) { - m_stat.aggregate(& pfs->m_instr_class_waits_stats[m_index]); + const PFS_single_stat *event_name_array; + event_name_array= pfs->read_instr_class_waits_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } } PFS_connection_all_wait_visitor @@ -711,11 +972,14 @@ void PFS_connection_all_wait_visitor::visit_global() 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++) + const PFS_single_stat *stat= pfs->read_instr_class_waits_stats(); + if (stat != NULL) { - m_stat.aggregate(stat); + const PFS_single_stat *stat_last= stat + wait_class_max; + for ( ; stat < stat_last; stat++) + { + m_stat.aggregate(stat); + } } } @@ -754,22 +1018,42 @@ void PFS_connection_stage_visitor::visit_global() void PFS_connection_stage_visitor::visit_host(PFS_host *pfs) { - m_stat.aggregate(& pfs->m_instr_class_stages_stats[m_index]); + const PFS_stage_stat *event_name_array; + event_name_array= pfs->read_instr_class_stages_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } } void PFS_connection_stage_visitor::visit_user(PFS_user *pfs) { - m_stat.aggregate(& pfs->m_instr_class_stages_stats[m_index]); + const PFS_stage_stat *event_name_array; + event_name_array= pfs->read_instr_class_stages_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } } void PFS_connection_stage_visitor::visit_account(PFS_account *pfs) { - m_stat.aggregate(& pfs->m_instr_class_stages_stats[m_index]); + const PFS_stage_stat *event_name_array; + event_name_array= pfs->read_instr_class_stages_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } } void PFS_connection_stage_visitor::visit_thread(PFS_thread *pfs) { - m_stat.aggregate(& pfs->m_instr_class_stages_stats[m_index]); + const PFS_stage_stat *event_name_array; + event_name_array= pfs->read_instr_class_stages_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } } PFS_connection_statement_visitor @@ -788,22 +1072,42 @@ void PFS_connection_statement_visitor::visit_global() void PFS_connection_statement_visitor::visit_host(PFS_host *pfs) { - m_stat.aggregate(& pfs->m_instr_class_statements_stats[m_index]); + const PFS_statement_stat *event_name_array; + event_name_array= pfs->read_instr_class_statements_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } } void PFS_connection_statement_visitor::visit_user(PFS_user *pfs) { - m_stat.aggregate(& pfs->m_instr_class_statements_stats[m_index]); + const PFS_statement_stat *event_name_array; + event_name_array= pfs->read_instr_class_statements_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } } void PFS_connection_statement_visitor::visit_account(PFS_account *pfs) { - m_stat.aggregate(& pfs->m_instr_class_statements_stats[m_index]); + const PFS_statement_stat *event_name_array; + event_name_array= pfs->read_instr_class_statements_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } } void PFS_connection_statement_visitor::visit_thread(PFS_thread *pfs) { - m_stat.aggregate(& pfs->m_instr_class_statements_stats[m_index]); + const PFS_statement_stat *event_name_array; + event_name_array= pfs->read_instr_class_statements_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } } /** Instance wait visitor */ @@ -826,11 +1130,14 @@ void PFS_connection_all_statement_visitor::visit_global() 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++) + const PFS_statement_stat *stat= pfs->read_instr_class_statements_stats(); + if (stat != NULL) { - m_stat.aggregate(stat); + const PFS_statement_stat *stat_last= stat + statement_class_max; + for ( ; stat < stat_last; stat++) + { + m_stat.aggregate(stat); + } } } @@ -854,6 +1161,102 @@ void PFS_connection_all_statement_visitor::visit_thread(PFS_thread *pfs) visit_connection_slice(pfs); } +PFS_connection_transaction_visitor +::PFS_connection_transaction_visitor(PFS_transaction_class *klass) +{ + m_index= klass->m_event_name_index; +} + +PFS_connection_transaction_visitor::~PFS_connection_transaction_visitor() +{} + +void PFS_connection_transaction_visitor::visit_global() +{ + m_stat.aggregate(&global_transaction_stat); +} + +void PFS_connection_transaction_visitor::visit_host(PFS_host *pfs) +{ + const PFS_transaction_stat *event_name_array; + event_name_array= pfs->read_instr_class_transactions_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } +} + +void PFS_connection_transaction_visitor::visit_user(PFS_user *pfs) +{ + const PFS_transaction_stat *event_name_array; + event_name_array= pfs->read_instr_class_transactions_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } +} + +void PFS_connection_transaction_visitor::visit_account(PFS_account *pfs) +{ + const PFS_transaction_stat *event_name_array; + event_name_array= pfs->read_instr_class_transactions_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } +} + +void PFS_connection_transaction_visitor::visit_thread(PFS_thread *pfs) +{ + const PFS_transaction_stat *event_name_array; + event_name_array= pfs->read_instr_class_transactions_stats(); + if (event_name_array != NULL) + { + m_stat.aggregate(& event_name_array[m_index]); + } +} + +/** Disabled pending code review */ +#if 0 +/** Instance wait visitor */ +PFS_connection_all_transaction_visitor +::PFS_connection_all_transaction_visitor() +{} + +PFS_connection_all_transaction_visitor::~PFS_connection_all_transaction_visitor() +{} + +void PFS_connection_all_transaction_visitor::visit_global() +{ + m_stat.aggregate(&global_transaction_stat); +} + +void PFS_connection_all_transaction_visitor::visit_connection_slice(PFS_connection_slice *pfs) +{ + PFS_transaction_stat *stat= pfs->m_instr_class_transactions_stats; + m_stat.aggregate(stat); +} + +void PFS_connection_all_transaction_visitor::visit_host(PFS_host *pfs) +{ + visit_connection_slice(pfs); +} + +void PFS_connection_all_transaction_visitor::visit_user(PFS_user *pfs) +{ + visit_connection_slice(pfs); +} + +void PFS_connection_all_transaction_visitor::visit_account(PFS_account *pfs) +{ + visit_connection_slice(pfs); +} + +void PFS_connection_all_transaction_visitor::visit_thread(PFS_thread *pfs) +{ + visit_connection_slice(pfs); +} +#endif + PFS_connection_stat_visitor::PFS_connection_stat_visitor() {} @@ -883,10 +1286,117 @@ void PFS_connection_stat_visitor::visit_thread(PFS_thread *) m_stat.aggregate_active(1); } -PFS_instance_wait_visitor::PFS_instance_wait_visitor() +PFS_connection_memory_visitor +::PFS_connection_memory_visitor(PFS_memory_class *klass) +{ + m_index= klass->m_event_name_index; + m_stat.reset(); +} + +PFS_connection_memory_visitor::~PFS_connection_memory_visitor() +{} + +void PFS_connection_memory_visitor::visit_global() +{ + PFS_memory_stat *stat; + stat= & global_instr_class_memory_array[m_index]; + stat->full_aggregate_to(& m_stat); +} + +void PFS_connection_memory_visitor::visit_host(PFS_host *pfs) +{ + const PFS_memory_stat *event_name_array; + event_name_array= pfs->read_instr_class_memory_stats(); + if (event_name_array != NULL) + { + const PFS_memory_stat *stat; + stat= & event_name_array[m_index]; + stat->full_aggregate_to(& m_stat); + } +} + +void PFS_connection_memory_visitor::visit_user(PFS_user *pfs) { + const PFS_memory_stat *event_name_array; + event_name_array= pfs->read_instr_class_memory_stats(); + if (event_name_array != NULL) + { + const PFS_memory_stat *stat; + stat= & event_name_array[m_index]; + stat->full_aggregate_to(& m_stat); + } } +void PFS_connection_memory_visitor::visit_account(PFS_account *pfs) +{ + const PFS_memory_stat *event_name_array; + event_name_array= pfs->read_instr_class_memory_stats(); + if (event_name_array != NULL) + { + const PFS_memory_stat *stat; + stat= & event_name_array[m_index]; + stat->full_aggregate_to(& m_stat); + } +} + +void PFS_connection_memory_visitor::visit_thread(PFS_thread *pfs) +{ + const PFS_memory_stat *event_name_array; + event_name_array= pfs->read_instr_class_memory_stats(); + if (event_name_array != NULL) + { + const PFS_memory_stat *stat; + stat= & event_name_array[m_index]; + stat->full_aggregate_to(& m_stat); + } +} + + +PFS_connection_status_visitor:: +PFS_connection_status_visitor(STATUS_VAR *status_vars) : m_status_vars(status_vars) +{ + memset(m_status_vars, 0, sizeof(STATUS_VAR)); +} + +PFS_connection_status_visitor::~PFS_connection_status_visitor() +{} + +/** Aggregate from global status. */ +void PFS_connection_status_visitor::visit_global() +{ + /* NOTE: Requires lock on LOCK_status. */ + mysql_mutex_assert_owner(&LOCK_status); + add_to_status(m_status_vars, &global_status_var, false); +} + +void PFS_connection_status_visitor::visit_host(PFS_host *pfs) +{ + pfs->m_status_stats.aggregate_to(m_status_vars); +} + +void PFS_connection_status_visitor::visit_user(PFS_user *pfs) +{ + pfs->m_status_stats.aggregate_to(m_status_vars); +} + +void PFS_connection_status_visitor::visit_account(PFS_account *pfs) +{ + pfs->m_status_stats.aggregate_to(m_status_vars); +} + +void PFS_connection_status_visitor::visit_thread(PFS_thread *pfs) +{ +} + +void PFS_connection_status_visitor::visit_THD(THD *thd) +{ + add_to_status(m_status_vars, &thd->status_var, false); +} + + +PFS_instance_wait_visitor::PFS_instance_wait_visitor() +{} + PFS_instance_wait_visitor::~PFS_instance_wait_visitor() {} @@ -930,7 +1440,7 @@ 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) +void PFS_instance_wait_visitor::visit_file(PFS_file *pfs) { /* Combine per-operation file wait stats before aggregating */ PFS_single_stat stat; @@ -938,7 +1448,7 @@ void PFS_instance_wait_visitor::visit_file(PFS_file *pfs) m_stat.aggregate(&stat); } -void PFS_instance_wait_visitor::visit_socket(PFS_socket *pfs) +void PFS_instance_wait_visitor::visit_socket(PFS_socket *pfs) { /* Combine per-operation socket wait stats before aggregating */ PFS_single_stat stat; @@ -963,7 +1473,7 @@ void PFS_object_wait_visitor::visit_global() 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); + pfs->sum(& m_stat, safe_key_count); } void PFS_object_wait_visitor::visit_table(PFS_table *pfs) @@ -992,13 +1502,20 @@ 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; + PFS_table_share_index *index_stat; /* Aggregate index stats */ for (index= 0; index < safe_key_count; index++) - io_stat.aggregate(& pfs->m_table_stat.m_index_stat[index]); + { + index_stat= pfs->find_index_stat(index); + if (index_stat != NULL) + io_stat.aggregate(& index_stat->m_stat); + } /* Aggregate global stats */ - io_stat.aggregate(& pfs->m_table_stat.m_index_stat[MAX_INDEXES]); + index_stat= pfs->find_index_stat(MAX_INDEXES); + if (index_stat != NULL) + io_stat.aggregate(& index_stat->m_stat); io_stat.sum(& m_stat); } @@ -1036,13 +1553,20 @@ 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; + PFS_table_share_index *index_stat; /* Aggregate index stats */ for (index= 0; index < safe_key_count; index++) - m_stat.aggregate(& pfs->m_table_stat.m_index_stat[index]); + { + index_stat= pfs->find_index_stat(index); + if (index_stat != NULL) + m_stat.aggregate(& index_stat->m_stat); + } /* Aggregate global stats */ - m_stat.aggregate(& pfs->m_table_stat.m_index_stat[MAX_INDEXES]); + index_stat= pfs->find_index_stat(MAX_INDEXES); + if (index_stat != NULL) + m_stat.aggregate(& index_stat->m_stat); } void PFS_table_io_stat_visitor::visit_table(PFS_table *pfs) @@ -1073,7 +1597,11 @@ 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]); + PFS_table_share_index *index_stat; + + index_stat= pfs->find_index_stat(index); + if (index_stat != NULL) + m_stat.aggregate(& index_stat->m_stat); } void PFS_index_io_stat_visitor::visit_table_index(PFS_table *pfs, uint index) @@ -1096,7 +1624,7 @@ void PFS_table_lock_wait_visitor::visit_global() void PFS_table_lock_wait_visitor::visit_table_share(PFS_table_share *pfs) { - pfs->m_table_stat.sum_lock(& m_stat); + pfs->sum_lock(& m_stat); } void PFS_table_lock_wait_visitor::visit_table(PFS_table *pfs) @@ -1114,7 +1642,11 @@ 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); + PFS_table_share_lock *lock_stat; + + lock_stat= pfs->find_lock_stat(); + if (lock_stat != NULL) + m_stat.aggregate(& lock_stat->m_stat); } void PFS_table_lock_stat_visitor::visit_table(PFS_table *pfs) @@ -1128,32 +1660,31 @@ 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) +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) +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) +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) +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 index 120b5928045..a81567e9921 100644 --- a/storage/perfschema/pfs_visitor.h +++ b/storage/perfschema/pfs_visitor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -25,6 +25,8 @@ #include "pfs_stat.h" +typedef struct system_status_var STATUS_VAR; + /** @file storage/perfschema/pfs_visitor.h Visitors (declarations). @@ -45,6 +47,7 @@ struct PFS_rwlock_class; struct PFS_cond_class; struct PFS_file_class; struct PFS_socket_class; +struct PFS_memory_class; struct PFS_table_share; struct PFS_mutex; struct PFS_rwlock; @@ -53,6 +56,7 @@ struct PFS_file; struct PFS_table; struct PFS_stage_class; struct PFS_statement_class; +struct PFS_transaction_class; struct PFS_socket; struct PFS_connection_slice; @@ -75,6 +79,8 @@ public: virtual void visit_user(PFS_user *pfs) {} /** Visit a thread. */ virtual void visit_thread(PFS_thread *pfs) {} + /** Visit a THD associated with a thread. */ + virtual void visit_THD(THD *thd) {} }; /** @@ -90,37 +96,45 @@ public: @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 with_THDs when true, visit also all threads THD. @param visitor the visitor to call */ static void visit_global(bool with_hosts, bool with_users, bool with_accounts, bool with_threads, + bool with_THDs, 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 with_THDs when true, visit also all related threads THD. @param visitor the visitor to call */ static void visit_host(PFS_host *host, bool with_accounts, bool with_threads, + bool with_THDs, 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 with_THDs when true, visit also all related threads THD. @param visitor the visitor to call */ static void visit_user(PFS_user *user, bool with_accounts, bool with_threads, + bool with_THDs, 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 with_THDs when true, visit also all related threads THD. @param visitor the visitor to call */ static void visit_account(PFS_account *account, bool with_threads, - PFS_connection_visitor *visitor); + bool with_THDs, + PFS_connection_visitor *visitor); /** Visit a thread or connection. @param thread the thread to visit. @@ -129,6 +143,13 @@ public: static inline void visit_thread(PFS_thread *thread, PFS_connection_visitor *visitor) { visitor->visit_thread(thread); } + + /** + Visit THD. + @param thd the THD to visit. + @param visitor the visitor to call. + */ + static void visit_THD(THD *thd, PFS_connection_visitor *visitor); }; /** @@ -397,6 +418,54 @@ private: /** A concrete connection visitor that aggregates + transaction statistics for a given event_name. +*/ +class PFS_connection_transaction_visitor : public PFS_connection_visitor +{ +public: + /** Constructor. */ + PFS_connection_transaction_visitor(PFS_transaction_class *klass); + virtual ~PFS_connection_transaction_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_transaction_stat m_stat; +}; + +/** Disabled pending code review */ +#if 0 +/** + A concrete connection visitor that aggregates + transaction statistics for all events. +*/ +class PFS_connection_all_transaction_visitor : public PFS_connection_visitor +{ +public: + /** Constructor. */ + PFS_connection_all_transaction_visitor(); + virtual ~PFS_connection_all_transaction_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_transaction_stat m_stat; + +private: + void visit_connection_slice(PFS_connection_slice *pfs); +}; +#endif + +/** + A concrete connection visitor that aggregates connection statistics. */ class PFS_connection_stat_visitor : public PFS_connection_visitor @@ -416,6 +485,49 @@ public: }; /** + A concrete connection visitor that aggregates + memory statistics for a given event_name. +*/ +class PFS_connection_memory_visitor : public PFS_connection_visitor +{ +public: + /** Constructor. */ + PFS_connection_memory_visitor(PFS_memory_class *klass); + virtual ~PFS_connection_memory_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_memory_stat m_stat; +}; + +/** + A concrete connection visitor that aggregates + status variables. +*/ +class PFS_connection_status_visitor : public PFS_connection_visitor +{ +public: + /** Constructor. */ + PFS_connection_status_visitor(STATUS_VAR *status_vars); + virtual ~PFS_connection_status_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); + virtual void visit_THD(THD *thd); + +private: + STATUS_VAR *m_status_vars; +}; + +/** A concrete instance visitor that aggregates wait statistics. */ diff --git a/storage/perfschema/table_accounts.cc b/storage/perfschema/table_accounts.cc index 708f8269a69..eb3f6481696 100644 --- a/storage/perfschema/table_accounts.cc +++ b/storage/perfschema/table_accounts.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -21,12 +21,15 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "table_accounts.h" #include "pfs_instr_class.h" #include "pfs_instr.h" #include "pfs_account.h" #include "pfs_visitor.h" +#include "pfs_memory.h" +#include "pfs_status.h" +#include "field.h" THR_LOCK table_accounts::m_table_lock; @@ -35,18 +38,18 @@ table_accounts::m_share= { { C_STRING_WITH_LEN("accounts") }, &pfs_truncatable_acl, - &table_accounts::create, + table_accounts::create, NULL, /* write_row */ table_accounts::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + cursor_by_account::get_row_count, sizeof(PFS_simple_index), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE accounts(" - "USER CHAR(16) collate utf8_bin default null," + "USER CHAR(" USERNAME_CHAR_LENGTH_STR ") collate utf8_bin default null," "HOST CHAR(60) collate utf8_bin default null," "CURRENT_CONNECTIONS bigint not null," - "TOTAL_CONNECTIONS bigint not null)") } + "TOTAL_CONNECTIONS bigint not null)") }, + false /* perpetual */ }; PFS_engine_table* table_accounts::create() @@ -63,6 +66,12 @@ table_accounts::delete_all_rows(void) reset_events_stages_by_account(); reset_events_statements_by_thread(); reset_events_statements_by_account(); + reset_events_transactions_by_thread(); + reset_events_transactions_by_account(); + reset_memory_by_thread(); + reset_memory_by_account(); + reset_status_by_thread(); + reset_status_by_account(); purge_all_account(); return 0; } @@ -74,7 +83,7 @@ table_accounts::table_accounts() void table_accounts::make_row(PFS_account *pfs) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; pfs->m_lock.begin_optimistic_lock(&lock); @@ -83,7 +92,10 @@ void table_accounts::make_row(PFS_account *pfs) return; PFS_connection_stat_visitor visitor; - PFS_connection_iterator::visit_account(pfs, true, & visitor); + PFS_connection_iterator::visit_account(pfs, + true, /* threads */ + false, /* THDs */ + & visitor); if (! pfs->m_lock.end_optimistic_lock(& lock)) return; diff --git a/storage/perfschema/table_accounts.h b/storage/perfschema/table_accounts.h index dfc2cc322e0..7563e85c1d7 100644 --- a/storage/perfschema/table_accounts.h +++ b/storage/perfschema/table_accounts.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, diff --git a/storage/perfschema/table_all_instr.cc b/storage/perfschema/table_all_instr.cc index d48028b1539..b030b8824ca 100644 --- a/storage/perfschema/table_all_instr.cc +++ b/storage/perfschema/table_all_instr.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, version 2.0, @@ -26,9 +26,20 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "table_all_instr.h" #include "pfs_global.h" +#include "pfs_buffer_container.h" + +ha_rows +table_all_instr::get_row_count(void) +{ + return global_mutex_container.get_row_count() + + global_rwlock_container.get_row_count() + + global_cond_container.get_row_count() + + global_file_container.get_row_count() + + global_socket_container.get_row_count() ; +} table_all_instr::table_all_instr(const PFS_engine_table_share *share) : PFS_engine_table(share, &m_pos), @@ -55,10 +66,10 @@ int table_all_instr::rnd_next(void) { switch (m_pos.m_index_1) { case pos_all_instr::VIEW_MUTEX: - for ( ; m_pos.m_index_2 < mutex_max; m_pos.m_index_2++) { - mutex= &mutex_array[m_pos.m_index_2]; - if (mutex->m_lock.is_populated()) + PFS_mutex_iterator it= global_mutex_container.iterate(m_pos.m_index_2); + mutex= it.scan_next(& m_pos.m_index_2); + if (mutex != NULL) { make_mutex_row(mutex); m_next_pos.set_after(&m_pos); @@ -67,10 +78,10 @@ int table_all_instr::rnd_next(void) } break; case pos_all_instr::VIEW_RWLOCK: - for ( ; m_pos.m_index_2 < rwlock_max; m_pos.m_index_2++) { - rwlock= &rwlock_array[m_pos.m_index_2]; - if (rwlock->m_lock.is_populated()) + PFS_rwlock_iterator it= global_rwlock_container.iterate(m_pos.m_index_2); + rwlock= it.scan_next(& m_pos.m_index_2); + if (rwlock != NULL) { make_rwlock_row(rwlock); m_next_pos.set_after(&m_pos); @@ -79,10 +90,10 @@ int table_all_instr::rnd_next(void) } break; case pos_all_instr::VIEW_COND: - for ( ; m_pos.m_index_2 < cond_max; m_pos.m_index_2++) { - cond= &cond_array[m_pos.m_index_2]; - if (cond->m_lock.is_populated()) + PFS_cond_iterator it= global_cond_container.iterate(m_pos.m_index_2); + cond= it.scan_next(& m_pos.m_index_2); + if (cond != NULL) { make_cond_row(cond); m_next_pos.set_after(&m_pos); @@ -91,10 +102,10 @@ int table_all_instr::rnd_next(void) } break; case pos_all_instr::VIEW_FILE: - for ( ; m_pos.m_index_2 < file_max; m_pos.m_index_2++) { - file= &file_array[m_pos.m_index_2]; - if (file->m_lock.is_populated()) + PFS_file_iterator it= global_file_container.iterate(m_pos.m_index_2); + file= it.scan_next(& m_pos.m_index_2); + if (file != NULL) { make_file_row(file); m_next_pos.set_after(&m_pos); @@ -103,10 +114,10 @@ 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()) + PFS_socket_iterator it= global_socket_container.iterate(m_pos.m_index_2); + socket= it.scan_next(& m_pos.m_index_2); + if (socket != NULL) { make_socket_row(socket); m_next_pos.set_after(&m_pos); @@ -132,45 +143,40 @@ int table_all_instr::rnd_pos(const void *pos) switch (m_pos.m_index_1) { case pos_all_instr::VIEW_MUTEX: - DBUG_ASSERT(m_pos.m_index_2 < mutex_max); - mutex= &mutex_array[m_pos.m_index_2]; - if (mutex->m_lock.is_populated()) + mutex= global_mutex_container.get(m_pos.m_index_2); + if (mutex != NULL) { make_mutex_row(mutex); return 0; } break; case pos_all_instr::VIEW_RWLOCK: - DBUG_ASSERT(m_pos.m_index_2 < rwlock_max); - rwlock= &rwlock_array[m_pos.m_index_2]; - if (rwlock->m_lock.is_populated()) + rwlock= global_rwlock_container.get(m_pos.m_index_2); + if (rwlock != NULL) { make_rwlock_row(rwlock); return 0; } break; case pos_all_instr::VIEW_COND: - DBUG_ASSERT(m_pos.m_index_2 < cond_max); - cond= &cond_array[m_pos.m_index_2]; - if (cond->m_lock.is_populated()) + cond= global_cond_container.get(m_pos.m_index_2); + if (cond != NULL) { make_cond_row(cond); return 0; } break; case pos_all_instr::VIEW_FILE: - DBUG_ASSERT(m_pos.m_index_2 < file_max); - file= &file_array[m_pos.m_index_2]; - if (file->m_lock.is_populated()) + file= global_file_container.get(m_pos.m_index_2); + if (file != NULL) { make_file_row(file); return 0; } break; case pos_all_instr::VIEW_SOCKET: - DBUG_ASSERT(m_pos.m_index_2 < socket_max); - socket= &socket_array[m_pos.m_index_2]; - if (socket->m_lock.is_populated()) + socket= global_socket_container.get(m_pos.m_index_2); + if (socket != NULL) { make_socket_row(socket); return 0; diff --git a/storage/perfschema/table_all_instr.h b/storage/perfschema/table_all_instr.h index 072221ba86e..3b5388dfb6e 100644 --- a/storage/perfschema/table_all_instr.h +++ b/storage/perfschema/table_all_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, version 2.0, @@ -74,6 +74,8 @@ struct pos_all_instr : public PFS_double_index, class table_all_instr : public PFS_engine_table { public: + static ha_rows get_row_count(); + virtual int rnd_next(); virtual int rnd_pos(const void *pos); virtual void reset_position(void); diff --git a/storage/perfschema/table_esgs_by_account_by_event_name.cc b/storage/perfschema/table_esgs_by_account_by_event_name.cc index 22e4e0040f1..68b7b2f57e2 100644 --- a/storage/perfschema/table_esgs_by_account_by_event_name.cc +++ b/storage/perfschema/table_esgs_by_account_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,13 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_esgs_by_account_by_event_name::m_table_lock; @@ -44,19 +46,19 @@ table_esgs_by_account_by_event_name::m_share= 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 */ + table_esgs_by_account_by_event_name::get_row_count, 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," + "USER CHAR(" USERNAME_CHAR_LENGTH_STR ") 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)") } + "MAX_TIMER_WAIT BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -73,6 +75,12 @@ table_esgs_by_account_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_esgs_by_account_by_event_name::get_row_count(void) +{ + return global_account_container.get_row_count() * stage_class_max; +} + 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() @@ -94,13 +102,14 @@ int table_esgs_by_account_by_event_name::rnd_next(void) { PFS_account *account; PFS_stage_class *stage_class; + bool has_more_account= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_account(); + has_more_account; m_pos.next_account()) { - account= &account_array[m_pos.m_index_1]; - if (account->m_lock.is_populated()) + account= global_account_container.get(m_pos.m_index_1, & has_more_account); + if (account != NULL) { stage_class= find_stage_class(m_pos.m_index_2); if (stage_class) @@ -122,17 +131,16 @@ table_esgs_by_account_by_event_name::rnd_pos(const void *pos) 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) + account= global_account_container.get(m_pos.m_index_1); + if (account != NULL) { - make_row(account, stage_class); - return 0; + 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; @@ -141,7 +149,7 @@ table_esgs_by_account_by_event_name::rnd_pos(const void *pos) void table_esgs_by_account_by_event_name ::make_row(PFS_account *account, PFS_stage_class *klass) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; account->m_lock.begin_optimistic_lock(&lock); @@ -152,7 +160,10 @@ void table_esgs_by_account_by_event_name m_row.m_event_name.make_row(klass); PFS_connection_stage_visitor visitor(klass); - PFS_connection_iterator::visit_account(account, true, & visitor); + PFS_connection_iterator::visit_account(account, + true, /* threads */ + false, /* THDs */ + & visitor); if (! account->m_lock.end_optimistic_lock(&lock)) return; diff --git a/storage/perfschema/table_esgs_by_account_by_event_name.h b/storage/perfschema/table_esgs_by_account_by_event_name.h index ee855d42818..011503aa64b 100644 --- a/storage/perfschema/table_esgs_by_account_by_event_name.h +++ b/storage/perfschema/table_esgs_by_account_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -57,7 +57,7 @@ struct row_esgs_by_account_by_event_name /** Position of a cursor on PERFORMANCE_SCHEMA.EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. - Index 1 on user@host (0 based) + Index 1 on account (0 based) Index 2 on stage class (1 based) */ struct pos_esgs_by_account_by_event_name @@ -73,9 +73,6 @@ struct pos_esgs_by_account_by_event_name m_index_2= 1; } - inline bool has_more_account(void) - { return (m_index_1 < account_max); } - inline void next_account(void) { m_index_1++; @@ -91,6 +88,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_esgs_by_host_by_event_name.cc b/storage/perfschema/table_esgs_by_host_by_event_name.cc index 86cc2eb1b86..1d3f6126862 100644 --- a/storage/perfschema/table_esgs_by_host_by_event_name.cc +++ b/storage/perfschema/table_esgs_by_host_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,7 +26,7 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr_class.h" #include "pfs_column_types.h" #include "pfs_column_values.h" @@ -34,6 +34,8 @@ #include "pfs_global.h" #include "pfs_account.h" #include "pfs_visitor.h" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_esgs_by_host_by_event_name::m_table_lock; @@ -45,8 +47,7 @@ table_esgs_by_host_by_event_name::m_share= 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 */ + table_esgs_by_host_by_event_name::get_row_count, 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(" @@ -56,7 +57,8 @@ table_esgs_by_host_by_event_name::m_share= "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)") } + "MAX_TIMER_WAIT BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -74,6 +76,12 @@ table_esgs_by_host_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_esgs_by_host_by_event_name::get_row_count(void) +{ + return global_host_container.get_row_count() * stage_class_max; +} + 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() @@ -95,13 +103,14 @@ int table_esgs_by_host_by_event_name::rnd_next(void) { PFS_host *host; PFS_stage_class *stage_class; + bool has_more_host= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_host(); + has_more_host; m_pos.next_host()) { - host= &host_array[m_pos.m_index_1]; - if (host->m_lock.is_populated()) + host= global_host_container.get(m_pos.m_index_1, & has_more_host); + if (host != NULL) { stage_class= find_stage_class(m_pos.m_index_2); if (stage_class) @@ -123,17 +132,16 @@ table_esgs_by_host_by_event_name::rnd_pos(const void *pos) 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) + host= global_host_container.get(m_pos.m_index_1); + if (host != NULL) { - make_row(host, stage_class); - return 0; + 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; @@ -142,7 +150,7 @@ table_esgs_by_host_by_event_name::rnd_pos(const void *pos) void table_esgs_by_host_by_event_name ::make_row(PFS_host *host, PFS_stage_class *klass) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; host->m_lock.begin_optimistic_lock(&lock); @@ -153,7 +161,11 @@ void table_esgs_by_host_by_event_name m_row.m_event_name.make_row(klass); PFS_connection_stage_visitor visitor(klass); - PFS_connection_iterator::visit_host(host, true, true, & visitor); + PFS_connection_iterator::visit_host(host, + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); if (! host->m_lock.end_optimistic_lock(&lock)) return; diff --git a/storage/perfschema/table_esgs_by_host_by_event_name.h b/storage/perfschema/table_esgs_by_host_by_event_name.h index 6042e6396af..14ddbb8b338 100644 --- a/storage/perfschema/table_esgs_by_host_by_event_name.h +++ b/storage/perfschema/table_esgs_by_host_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -73,9 +73,6 @@ struct pos_esgs_by_host_by_event_name m_index_2= 1; } - inline bool has_more_host(void) - { return (m_index_1 < host_max); } - inline void next_host(void) { m_index_1++; @@ -91,6 +88,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_esgs_by_thread_by_event_name.cc b/storage/perfschema/table_esgs_by_thread_by_event_name.cc index dfda9702abb..c266bfaf7a6 100644 --- a/storage/perfschema/table_esgs_by_thread_by_event_name.cc +++ b/storage/perfschema/table_esgs_by_thread_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,13 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_esgs_by_thread_by_event_name::m_table_lock; @@ -44,8 +46,7 @@ table_esgs_by_thread_by_event_name::m_share= 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 */ + table_esgs_by_thread_by_event_name::get_row_count, 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(" @@ -55,7 +56,8 @@ table_esgs_by_thread_by_event_name::m_share= "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)") } + "MAX_TIMER_WAIT BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -71,6 +73,12 @@ table_esgs_by_thread_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_esgs_by_thread_by_event_name::get_row_count(void) +{ + return global_thread_container.get_row_count() * stage_class_max; +} + 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() @@ -92,18 +100,14 @@ int table_esgs_by_thread_by_event_name::rnd_next(void) { PFS_thread *thread; PFS_stage_class *stage_class; + bool has_more_thread= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_thread(); + 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()) + thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (thread != NULL) { stage_class= find_stage_class(m_pos.m_index_2); if (stage_class) @@ -125,17 +129,16 @@ table_esgs_by_thread_by_event_name::rnd_pos(const void *pos) 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) + thread= global_thread_container.get(m_pos.m_index_1); + if (thread != NULL) { - make_row(thread, stage_class); - return 0; + 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; @@ -144,7 +147,7 @@ table_esgs_by_thread_by_event_name::rnd_pos(const void *pos) void table_esgs_by_thread_by_event_name ::make_row(PFS_thread *thread, PFS_stage_class *klass) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; /* Protect this reader against a thread termination */ diff --git a/storage/perfschema/table_esgs_by_thread_by_event_name.h b/storage/perfschema/table_esgs_by_thread_by_event_name.h index 6ff677a95e2..d3798e419b6 100644 --- a/storage/perfschema/table_esgs_by_thread_by_event_name.h +++ b/storage/perfschema/table_esgs_by_thread_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -72,9 +72,6 @@ struct pos_esgs_by_thread_by_event_name m_index_2= 1; } - inline bool has_more_thread(void) - { return (m_index_1 < thread_max); } - inline void next_thread(void) { m_index_1++; @@ -95,6 +92,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_esgs_by_user_by_event_name.cc b/storage/perfschema/table_esgs_by_user_by_event_name.cc index af73c1fc5fd..e6e6c321888 100644 --- a/storage/perfschema/table_esgs_by_user_by_event_name.cc +++ b/storage/perfschema/table_esgs_by_user_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,14 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_esgs_by_user_by_event_name::m_table_lock; @@ -45,18 +46,18 @@ table_esgs_by_user_by_event_name::m_share= 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 */ + table_esgs_by_user_by_event_name::get_row_count, 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," + "USER CHAR(" USERNAME_CHAR_LENGTH_STR ") 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)") } + "MAX_TIMER_WAIT BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -74,6 +75,12 @@ table_esgs_by_user_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_esgs_by_user_by_event_name::get_row_count(void) +{ + return global_user_container.get_row_count() * stage_class_max; +} + 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() @@ -95,13 +102,14 @@ int table_esgs_by_user_by_event_name::rnd_next(void) { PFS_user *user; PFS_stage_class *stage_class; + bool has_more_user= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_user(); + has_more_user; m_pos.next_user()) { - user= &user_array[m_pos.m_index_1]; - if (user->m_lock.is_populated()) + user= global_user_container.get(m_pos.m_index_1, & has_more_user); + if (user != NULL) { stage_class= find_stage_class(m_pos.m_index_2); if (stage_class) @@ -123,17 +131,16 @@ table_esgs_by_user_by_event_name::rnd_pos(const void *pos) 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) + user= global_user_container.get(m_pos.m_index_1); + if (user != NULL) { - make_row(user, stage_class); - return 0; + 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; @@ -142,7 +149,7 @@ table_esgs_by_user_by_event_name::rnd_pos(const void *pos) void table_esgs_by_user_by_event_name ::make_row(PFS_user *user, PFS_stage_class *klass) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; user->m_lock.begin_optimistic_lock(&lock); @@ -153,7 +160,11 @@ void table_esgs_by_user_by_event_name m_row.m_event_name.make_row(klass); PFS_connection_stage_visitor visitor(klass); - PFS_connection_iterator::visit_user(user, true, true, & visitor); + PFS_connection_iterator::visit_user(user, + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); if (! user->m_lock.end_optimistic_lock(&lock)) return; diff --git a/storage/perfschema/table_esgs_by_user_by_event_name.h b/storage/perfschema/table_esgs_by_user_by_event_name.h index bc545c2438a..464165a068a 100644 --- a/storage/perfschema/table_esgs_by_user_by_event_name.h +++ b/storage/perfschema/table_esgs_by_user_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -73,9 +73,6 @@ struct pos_esgs_by_user_by_event_name m_index_2= 1; } - inline bool has_more_user(void) - { return (m_index_1 < user_max); } - inline void next_user(void) { m_index_1++; @@ -96,6 +93,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_esgs_global_by_event_name.cc b/storage/perfschema/table_esgs_global_by_event_name.cc index 6c5f0866671..71145844f9d 100644 --- a/storage/perfschema/table_esgs_global_by_event_name.cc +++ b/storage/perfschema/table_esgs_global_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,7 +26,7 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr_class.h" #include "pfs_column_types.h" #include "pfs_column_values.h" @@ -35,6 +35,7 @@ #include "pfs_instr.h" #include "pfs_timer.h" #include "pfs_visitor.h" +#include "field.h" THR_LOCK table_esgs_global_by_event_name::m_table_lock; @@ -46,8 +47,7 @@ table_esgs_global_by_event_name::m_share= 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 */ + table_esgs_global_by_event_name::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_stages_summary_global_by_event_name(" @@ -56,7 +56,8 @@ table_esgs_global_by_event_name::m_share= "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)") } + "MAX_TIMER_WAIT BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -76,6 +77,12 @@ table_esgs_global_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_esgs_global_by_event_name::get_row_count(void) +{ + return stage_class_max; +} + 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) @@ -140,9 +147,12 @@ void table_esgs_global_by_event_name m_row.m_event_name.make_row(klass); PFS_connection_stage_visitor visitor(klass); - PFS_connection_iterator::visit_global(true, /* hosts */ + PFS_connection_iterator::visit_global(true, /* hosts */ false, /* users */ - true, true, & visitor); + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); m_row.m_stat.set(m_normalizer, & visitor.m_stat); m_row_exists= true; diff --git a/storage/perfschema/table_esgs_global_by_event_name.h b/storage/perfschema/table_esgs_global_by_event_name.h index b8884355676..44b3ea5ce7b 100644 --- a/storage/perfschema/table_esgs_global_by_event_name.h +++ b/storage/perfschema/table_esgs_global_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -59,6 +59,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_esms_by_account_by_event_name.cc b/storage/perfschema/table_esms_by_account_by_event_name.cc index 7afdabcbbfe..09b872e8ecb 100644 --- a/storage/perfschema/table_esms_by_account_by_event_name.cc +++ b/storage/perfschema/table_esms_by_account_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,13 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_esms_by_account_by_event_name::m_table_lock; @@ -44,12 +46,11 @@ table_esms_by_account_by_event_name::m_share= 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 */ + table_esms_by_account_by_event_name::get_row_count, 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," + "USER CHAR(" USERNAME_CHAR_LENGTH_STR ") 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," @@ -75,7 +76,8 @@ table_esms_by_account_by_event_name::m_share= "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)") } + "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -92,6 +94,12 @@ table_esms_by_account_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_esms_by_account_by_event_name::get_row_count(void) +{ + return global_account_container.get_row_count() * statement_class_max; +} + 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() @@ -113,13 +121,14 @@ int table_esms_by_account_by_event_name::rnd_next(void) { PFS_account *account; PFS_statement_class *statement_class; + bool has_more_account= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_account(); + has_more_account; m_pos.next_account()) { - account= &account_array[m_pos.m_index_1]; - if (account->m_lock.is_populated()) + account= global_account_container.get(m_pos.m_index_1, & has_more_account); + if (account != NULL) { statement_class= find_statement_class(m_pos.m_index_2); if (statement_class) @@ -141,17 +150,16 @@ table_esms_by_account_by_event_name::rnd_pos(const void *pos) 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) + account= global_account_container.get(m_pos.m_index_1); + if (account != NULL) { - make_row(account, statement_class); - return 0; + 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; @@ -160,7 +168,7 @@ table_esms_by_account_by_event_name::rnd_pos(const void *pos) void table_esms_by_account_by_event_name ::make_row(PFS_account *account, PFS_statement_class *klass) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; if (klass->is_mutable()) @@ -174,7 +182,10 @@ void table_esms_by_account_by_event_name m_row.m_event_name.make_row(klass); PFS_connection_statement_visitor visitor(klass); - PFS_connection_iterator::visit_account(account, true, & visitor); + PFS_connection_iterator::visit_account(account, + true, /* threads */ + false, /* THDs */ + & visitor); if (! account->m_lock.end_optimistic_lock(&lock)) return; diff --git a/storage/perfschema/table_esms_by_account_by_event_name.h b/storage/perfschema/table_esms_by_account_by_event_name.h index 64f2053cff6..3881dd5d978 100644 --- a/storage/perfschema/table_esms_by_account_by_event_name.h +++ b/storage/perfschema/table_esms_by_account_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -57,7 +57,7 @@ struct row_esms_by_account_by_event_name /** Position of a cursor on PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. - Index 1 on user@host (0 based) + Index 1 on account (0 based) Index 2 on statement class (1 based) */ struct pos_esms_by_account_by_event_name @@ -73,9 +73,6 @@ struct pos_esms_by_account_by_event_name m_index_2= 1; } - inline bool has_more_account(void) - { return (m_index_1 < account_max); } - inline void next_account(void) { m_index_1++; @@ -91,6 +88,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_esms_by_digest.cc b/storage/perfschema/table_esms_by_digest.cc index 5295c29dc40..acb9e059711 100644 --- a/storage/perfschema/table_esms_by_digest.cc +++ b/storage/perfschema/table_esms_by_digest.cc @@ -26,7 +26,7 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr_class.h" #include "pfs_column_types.h" #include "pfs_column_values.h" @@ -37,6 +37,7 @@ #include "pfs_visitor.h" #include "table_esms_by_digest.h" #include "pfs_digest.h" +#include "field.h" THR_LOCK table_esms_by_digest::m_table_lock; @@ -48,8 +49,7 @@ table_esms_by_digest::m_share= table_esms_by_digest::create, NULL, /* write_row */ table_esms_by_digest::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_esms_by_digest::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_by_digest(" @@ -81,7 +81,8 @@ table_esms_by_digest::m_share= "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)") } + "LAST_SEEN TIMESTAMP(0) NOT NULL default 0)") }, + false /* perpetual */ }; PFS_engine_table* @@ -97,6 +98,12 @@ table_esms_by_digest::delete_all_rows(void) return 0; } +ha_rows +table_esms_by_digest::get_row_count(void) +{ + return digest_max; +} + 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) @@ -183,7 +190,7 @@ int table_esms_by_digest 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. */ diff --git a/storage/perfschema/table_esms_by_digest.h b/storage/perfschema/table_esms_by_digest.h index 903b86110f6..9aa005bb6cc 100644 --- a/storage/perfschema/table_esms_by_digest.h +++ b/storage/perfschema/table_esms_by_digest.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -62,6 +62,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_esms_by_host_by_event_name.cc b/storage/perfschema/table_esms_by_host_by_event_name.cc index 42629ab6c09..c77f5f1320f 100644 --- a/storage/perfschema/table_esms_by_host_by_event_name.cc +++ b/storage/perfschema/table_esms_by_host_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,7 +26,7 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr_class.h" #include "pfs_column_types.h" #include "pfs_column_values.h" @@ -34,6 +34,8 @@ #include "pfs_global.h" #include "pfs_account.h" #include "pfs_visitor.h" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_esms_by_host_by_event_name::m_table_lock; @@ -45,8 +47,7 @@ table_esms_by_host_by_event_name::m_share= 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 */ + table_esms_by_host_by_event_name::get_row_count, 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(" @@ -75,7 +76,8 @@ table_esms_by_host_by_event_name::m_share= "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)") } + "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -93,6 +95,12 @@ table_esms_by_host_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_esms_by_host_by_event_name::get_row_count(void) +{ + return global_host_container.get_row_count() * statement_class_max; +} + 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() @@ -114,13 +122,14 @@ int table_esms_by_host_by_event_name::rnd_next(void) { PFS_host *host; PFS_statement_class *statement_class; + bool has_more_host= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_host(); + has_more_host; m_pos.next_host()) { - host= &host_array[m_pos.m_index_1]; - if (host->m_lock.is_populated()) + host= global_host_container.get(m_pos.m_index_1, & has_more_host); + if (host != NULL) { statement_class= find_statement_class(m_pos.m_index_2); if (statement_class) @@ -142,17 +151,16 @@ table_esms_by_host_by_event_name::rnd_pos(const void *pos) 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) + host= global_host_container.get(m_pos.m_index_1); + if (host != NULL) { - make_row(host, statement_class); - return 0; + 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; @@ -161,7 +169,7 @@ table_esms_by_host_by_event_name::rnd_pos(const void *pos) void table_esms_by_host_by_event_name ::make_row(PFS_host *host, PFS_statement_class *klass) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; if (klass->is_mutable()) @@ -175,7 +183,11 @@ void table_esms_by_host_by_event_name m_row.m_event_name.make_row(klass); PFS_connection_statement_visitor visitor(klass); - PFS_connection_iterator::visit_host(host, true, true, & visitor); + PFS_connection_iterator::visit_host(host, + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); if (! host->m_lock.end_optimistic_lock(&lock)) return; diff --git a/storage/perfschema/table_esms_by_host_by_event_name.h b/storage/perfschema/table_esms_by_host_by_event_name.h index a6985b48149..807db6d48d3 100644 --- a/storage/perfschema/table_esms_by_host_by_event_name.h +++ b/storage/perfschema/table_esms_by_host_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -73,9 +73,6 @@ struct pos_esms_by_host_by_event_name m_index_2= 1; } - inline bool has_more_host(void) - { return (m_index_1 < host_max); } - inline void next_host(void) { m_index_1++; @@ -91,6 +88,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_esms_by_program.cc b/storage/perfschema/table_esms_by_program.cc new file mode 100644 index 00000000000..3cb2e4a4d46 --- /dev/null +++ b/storage/perfschema/table_esms_by_program.cc @@ -0,0 +1,245 @@ +/* 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_esms_by_program.cc + Table EVENTS_STATEMENTS_SUMMARY_BY_PROGRAM (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_global.h" +#include "pfs_instr.h" +#include "pfs_timer.h" +#include "pfs_visitor.h" +#include "pfs_program.h" +#include "table_esms_by_program.h" +#include "pfs_buffer_container.h" +#include "field.h" + +THR_LOCK table_esms_by_program::m_table_lock; + +PFS_engine_table_share +table_esms_by_program::m_share= +{ + { C_STRING_WITH_LEN("events_statements_summary_by_program") }, + &pfs_truncatable_acl, + table_esms_by_program::create, + NULL, /* write_row */ + table_esms_by_program::delete_all_rows, + table_esms_by_program::get_row_count, + sizeof(PFS_simple_index), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_by_program (" + "OBJECT_TYPE enum('EVENT', 'FUNCTION', 'PROCEDURE', 'TABLE', 'TRIGGER')," + "OBJECT_SCHEMA varchar(64) NOT NULL," + "OBJECT_NAME varchar(64) NOT NULL," + "COUNT_STAR bigint(20) unsigned NOT NULL," + "SUM_TIMER_WAIT bigint(20) unsigned NOT NULL," + "MIN_TIMER_WAIT bigint(20) unsigned NOT NULL," + "AVG_TIMER_WAIT bigint(20) unsigned NOT NULL," + "MAX_TIMER_WAIT bigint(20) unsigned NOT NULL," + "COUNT_STATEMENTS bigint(20) unsigned NOT NULL," + "SUM_STATEMENTS_WAIT bigint(20) unsigned NOT NULL," + "MIN_STATEMENTS_WAIT bigint(20) unsigned NOT NULL," + "AVG_STATEMENTS_WAIT bigint(20) unsigned NOT NULL," + "MAX_STATEMENTS_WAIT bigint(20) unsigned NOT NULL," + "SUM_LOCK_TIME bigint(20) unsigned NOT NULL," + "SUM_ERRORS bigint(20) unsigned NOT NULL," + "SUM_WARNINGS bigint(20) unsigned NOT NULL," + "SUM_ROWS_AFFECTED bigint(20) unsigned NOT NULL," + "SUM_ROWS_SENT bigint(20) unsigned NOT NULL," + "SUM_ROWS_EXAMINED bigint(20) unsigned NOT NULL," + "SUM_CREATED_TMP_DISK_TABLES bigint(20) unsigned NOT NULL," + "SUM_CREATED_TMP_TABLES bigint(20) unsigned NOT NULL," + "SUM_SELECT_FULL_JOIN bigint(20) unsigned NOT NULL," + "SUM_SELECT_FULL_RANGE_JOIN bigint(20) unsigned NOT NULL," + "SUM_SELECT_RANGE bigint(20) unsigned NOT NULL," + "SUM_SELECT_RANGE_CHECK bigint(20) unsigned NOT NULL," + "SUM_SELECT_SCAN bigint(20) unsigned NOT NULL," + "SUM_SORT_MERGE_PASSES bigint(20) unsigned NOT NULL," + "SUM_SORT_RANGE bigint(20) unsigned NOT NULL," + "SUM_SORT_ROWS bigint(20) unsigned NOT NULL," + "SUM_SORT_SCAN bigint(20) unsigned NOT NULL," + "SUM_NO_INDEX_USED bigint(20) unsigned NOT NULL," + "SUM_NO_GOOD_INDEX_USED bigint(20) unsigned NOT NULL)")}, + false /* perpetual */ +}; + +PFS_engine_table* +table_esms_by_program::create(void) +{ + return new table_esms_by_program(); +} + +int +table_esms_by_program::delete_all_rows(void) +{ + reset_esms_by_program(); + return 0; +} + +ha_rows +table_esms_by_program::get_row_count(void) +{ + return global_program_container.get_row_count(); +} + +table_esms_by_program::table_esms_by_program() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_esms_by_program::reset_position(void) +{ + m_pos= 0; + m_next_pos= 0; +} + +int table_esms_by_program::rnd_next(void) +{ + PFS_program* pfs; + + m_pos.set_at(&m_next_pos); + PFS_program_iterator it= global_program_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int +table_esms_by_program::rnd_pos(const void *pos) +{ + PFS_program* pfs; + + set_position(pos); + + pfs= global_program_container.get(m_pos.m_index); + if (pfs != NULL) + { + make_row(pfs); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + + +void table_esms_by_program::make_row(PFS_program* program) +{ + pfs_optimistic_state lock; + m_row_exists= false; + + program->m_lock.begin_optimistic_lock(&lock); + + m_row.m_object_type= program->m_type; + + m_row.m_object_name_length= program->m_object_name_length; + if(m_row.m_object_name_length > 0) + memcpy(m_row.m_object_name, program->m_object_name, + m_row.m_object_name_length); + + m_row.m_schema_name_length= program->m_schema_name_length; + if(m_row.m_schema_name_length > 0) + memcpy(m_row.m_schema_name, program->m_schema_name, + m_row.m_schema_name_length); + + time_normalizer *normalizer= time_normalizer::get(statement_timer); + /* Get stored program's over all stats. */ + m_row.m_sp_stat.set(normalizer, &program->m_sp_stat); + /* Get sub statements' stats. */ + m_row.m_stmt_stat.set(normalizer, & program->m_stmt_stat); + + if (! program->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; +} + +int table_esms_by_program +::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: /* OBJECT_TYPE */ + if(m_row.m_object_type != 0) + set_field_enum(f, m_row.m_object_type); + else + f->set_null(); + break; + case 1: /* OBJECT_SCHEMA */ + if(m_row.m_schema_name_length > 0) + 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 > 0) + set_field_varchar_utf8(f, m_row.m_object_name, + m_row.m_object_name_length); + else + f->set_null(); + break; + case 3: /* COUNT_STAR */ + case 4: /* SUM_TIMER_WAIT */ + case 5: /* MIN_TIMER_WAIT */ + case 6: /* AVG_TIMER_WAIT */ + case 7: /* MAX_TIMER_WAIT */ + m_row.m_sp_stat.set_field(f->field_index - 3, f); + break; + default: /* 8, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_stmt_stat.set_field(f->field_index - 8, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_esms_by_program.h b/storage/perfschema/table_esms_by_program.h new file mode 100644 index 00000000000..cc263878e28 --- /dev/null +++ b/storage/perfschema/table_esms_by_program.h @@ -0,0 +1,113 @@ +/* Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_ESMS_BY_PROGRAM_H +#define TABLE_ESMS_BY_PROGRAM_H + +/** + @file storage/perfschema/table_esms_by_program.h + Table EVENTS_STATEMENTS_SUMMARY_BY_PROGRAM (declarations). +*/ + +#include "table_helper.h" +#include "pfs_program.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_PROGRAM. +*/ +struct row_esms_by_program +{ + /** Column OBJECT_TYPE. */ + enum_object_type m_object_type; + /** Column OBJECT_SCHEMA. */ + char m_schema_name[COL_OBJECT_SCHEMA_SIZE]; + int m_schema_name_length; + /** Column OBJECT_NAME. */ + char m_object_name[COL_OBJECT_NAME_SIZE]; + int m_object_name_length; + + /** + Columns COUNT_STAR + SUM_TIMER_WAIT + MIN_TIMER_WAIT + AVG_TIMER_WAIT + MAX_TIMER_WAIT + */ + PFS_sp_stat_row m_sp_stat; + + /** Columns COUNT_STATEMENTS,SUM_STATEMENTS_WAIT...SUM_NO_GOOD_INDEX_USED. */ + PFS_statement_stat_row m_stmt_stat; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_STATEMENTS_SUMMARY_BY_PROGRAM. */ +class table_esms_by_program : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + 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); + + table_esms_by_program(); + +public: + ~table_esms_by_program() + {} + +protected: + void make_row(PFS_program*); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_esms_by_program 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_thread_by_event_name.cc b/storage/perfschema/table_esms_by_thread_by_event_name.cc index 0a7cf46986c..306edc769c8 100644 --- a/storage/perfschema/table_esms_by_thread_by_event_name.cc +++ b/storage/perfschema/table_esms_by_thread_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,13 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_esms_by_thread_by_event_name::m_table_lock; @@ -44,8 +46,7 @@ table_esms_by_thread_by_event_name::m_share= 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 */ + table_esms_by_thread_by_event_name::get_row_count, 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(" @@ -74,7 +75,8 @@ table_esms_by_thread_by_event_name::m_share= "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)") } + "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -90,6 +92,12 @@ table_esms_by_thread_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_esms_by_thread_by_event_name::get_row_count(void) +{ + return global_thread_container.get_row_count() * statement_class_max; +} + 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() @@ -111,18 +119,14 @@ int table_esms_by_thread_by_event_name::rnd_next(void) { PFS_thread *thread; PFS_statement_class *statement_class; + bool has_more_thread= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_thread(); + 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()) + thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (thread != NULL) { statement_class= find_statement_class(m_pos.m_index_2); if (statement_class) @@ -144,17 +148,16 @@ table_esms_by_thread_by_event_name::rnd_pos(const void *pos) 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) + thread= global_thread_container.get(m_pos.m_index_1); + if (thread != NULL) { - make_row(thread, statement_class); - return 0; + 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; @@ -163,7 +166,7 @@ table_esms_by_thread_by_event_name::rnd_pos(const void *pos) void table_esms_by_thread_by_event_name ::make_row(PFS_thread *thread, PFS_statement_class *klass) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; if (klass->is_mutable()) diff --git a/storage/perfschema/table_esms_by_thread_by_event_name.h b/storage/perfschema/table_esms_by_thread_by_event_name.h index 72645d03389..41fec4e10d7 100644 --- a/storage/perfschema/table_esms_by_thread_by_event_name.h +++ b/storage/perfschema/table_esms_by_thread_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -72,9 +72,6 @@ struct pos_esms_by_thread_by_event_name m_index_2= 1; } - inline bool has_more_thread(void) - { return (m_index_1 < thread_max); } - inline void next_thread(void) { m_index_1++; @@ -95,6 +92,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_esms_by_user_by_event_name.cc b/storage/perfschema/table_esms_by_user_by_event_name.cc index f8708ac9a14..c0517748b99 100644 --- a/storage/perfschema/table_esms_by_user_by_event_name.cc +++ b/storage/perfschema/table_esms_by_user_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,14 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_esms_by_user_by_event_name::m_table_lock; @@ -45,12 +46,11 @@ table_esms_by_user_by_event_name::m_share= 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 */ + table_esms_by_user_by_event_name::get_row_count, 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," + "USER CHAR(" USERNAME_CHAR_LENGTH_STR ") collate utf8_bin default null," "EVENT_NAME VARCHAR(128) not null," "COUNT_STAR BIGINT unsigned not null," "SUM_TIMER_WAIT BIGINT unsigned not null," @@ -75,7 +75,8 @@ table_esms_by_user_by_event_name::m_share= "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)") } + "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -93,6 +94,12 @@ table_esms_by_user_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_esms_by_user_by_event_name::get_row_count(void) +{ + return global_user_container.get_row_count() * statement_class_max; +} + 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() @@ -114,13 +121,14 @@ int table_esms_by_user_by_event_name::rnd_next(void) { PFS_user *user; PFS_statement_class *statement_class; + bool has_more_user= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_user(); + has_more_user; m_pos.next_user()) { - user= &user_array[m_pos.m_index_1]; - if (user->m_lock.is_populated()) + user= global_user_container.get(m_pos.m_index_1, & has_more_user); + if (user != NULL) { statement_class= find_statement_class(m_pos.m_index_2); if (statement_class) @@ -142,17 +150,16 @@ table_esms_by_user_by_event_name::rnd_pos(const void *pos) 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) + user= global_user_container.get(m_pos.m_index_1); + if (user != NULL) { - make_row(user, statement_class); - return 0; + 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; @@ -161,7 +168,7 @@ table_esms_by_user_by_event_name::rnd_pos(const void *pos) void table_esms_by_user_by_event_name ::make_row(PFS_user *user, PFS_statement_class *klass) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; if (klass->is_mutable()) @@ -175,7 +182,11 @@ void table_esms_by_user_by_event_name m_row.m_event_name.make_row(klass); PFS_connection_statement_visitor visitor(klass); - PFS_connection_iterator::visit_user(user, true, true, & visitor); + PFS_connection_iterator::visit_user(user, + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); if (! user->m_lock.end_optimistic_lock(&lock)) return; diff --git a/storage/perfschema/table_esms_by_user_by_event_name.h b/storage/perfschema/table_esms_by_user_by_event_name.h index d1d1e5df85d..0ed9899dcf5 100644 --- a/storage/perfschema/table_esms_by_user_by_event_name.h +++ b/storage/perfschema/table_esms_by_user_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -73,9 +73,6 @@ struct pos_esms_by_user_by_event_name m_index_2= 1; } - inline bool has_more_user(void) - { return (m_index_1 < user_max); } - inline void next_user(void) { m_index_1++; @@ -91,6 +88,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_esms_global_by_event_name.cc b/storage/perfschema/table_esms_global_by_event_name.cc index 7d9584752b0..6e2408be26a 100644 --- a/storage/perfschema/table_esms_global_by_event_name.cc +++ b/storage/perfschema/table_esms_global_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,7 +26,7 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr_class.h" #include "pfs_column_types.h" #include "pfs_column_values.h" @@ -35,6 +35,7 @@ #include "pfs_instr.h" #include "pfs_timer.h" #include "pfs_visitor.h" +#include "field.h" THR_LOCK table_esms_global_by_event_name::m_table_lock; @@ -46,8 +47,7 @@ table_esms_global_by_event_name::m_share= 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 */ + table_esms_global_by_event_name::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_statements_summary_global_by_event_name(" @@ -75,7 +75,8 @@ table_esms_global_by_event_name::m_share= "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)") } + "SUM_NO_GOOD_INDEX_USED BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -95,6 +96,12 @@ table_esms_global_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_esms_global_by_event_name::get_row_count(void) +{ + return statement_class_max; +} + 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) @@ -164,9 +171,12 @@ void table_esms_global_by_event_name m_row.m_event_name.make_row(klass); PFS_connection_statement_visitor visitor(klass); - PFS_connection_iterator::visit_global(true, /* hosts */ + PFS_connection_iterator::visit_global(true, /* hosts */ false, /* users */ - true, true, & visitor); + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); m_row.m_stat.set(m_normalizer, & visitor.m_stat); m_row_exists= true; diff --git a/storage/perfschema/table_esms_global_by_event_name.h b/storage/perfschema/table_esms_global_by_event_name.h index b90c14c0c0f..d4e34b7cc18 100644 --- a/storage/perfschema/table_esms_global_by_event_name.h +++ b/storage/perfschema/table_esms_global_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -59,6 +59,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_ets_by_account_by_event_name.cc b/storage/perfschema/table_ets_by_account_by_event_name.cc new file mode 100644 index 00000000000..f951be2104a --- /dev/null +++ b/storage/perfschema/table_ets_by_account_by_event_name.cc @@ -0,0 +1,225 @@ +/* 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_ets_by_account_by_event_name.cc + Table EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_ets_by_account_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" +#include "pfs_buffer_container.h" +#include "field.h" + +THR_LOCK table_ets_by_account_by_event_name::m_table_lock; + +PFS_engine_table_share +table_ets_by_account_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_transactions_summary_by_account_by_event_name") }, + &pfs_truncatable_acl, + table_ets_by_account_by_event_name::create, + NULL, /* write_row */ + table_ets_by_account_by_event_name::delete_all_rows, + table_ets_by_account_by_event_name::get_row_count, + sizeof(pos_ets_by_account_by_event_name), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE events_transactions_summary_by_account_by_event_name(" + "USER CHAR(32) 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," + "COUNT_READ_WRITE BIGINT unsigned not null," + "SUM_TIMER_READ_WRITE BIGINT unsigned not null," + "MIN_TIMER_READ_WRITE BIGINT unsigned not null," + "AVG_TIMER_READ_WRITE BIGINT unsigned not null," + "MAX_TIMER_READ_WRITE BIGINT unsigned not null," + "COUNT_READ_ONLY BIGINT unsigned not null," + "SUM_TIMER_READ_ONLY BIGINT unsigned not null," + "MIN_TIMER_READ_ONLY BIGINT unsigned not null," + "AVG_TIMER_READ_ONLY BIGINT unsigned not null," + "MAX_TIMER_READ_ONLY BIGINT unsigned not null)")}, + false /* perpetual */ +}; + +PFS_engine_table* +table_ets_by_account_by_event_name::create(void) +{ + return new table_ets_by_account_by_event_name(); +} + +int +table_ets_by_account_by_event_name::delete_all_rows(void) +{ + reset_events_transactions_by_thread(); + reset_events_transactions_by_account(); + return 0; +} + +ha_rows +table_ets_by_account_by_event_name::get_row_count(void) +{ + return global_account_container.get_row_count() * transaction_class_max; +} + +table_ets_by_account_by_event_name::table_ets_by_account_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_ets_by_account_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_ets_by_account_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(transaction_timer); + return 0; +} + +int table_ets_by_account_by_event_name::rnd_next(void) +{ + PFS_account *account; + PFS_transaction_class *transaction_class; + bool has_more_account= true; + + for (m_pos.set_at(&m_next_pos); + has_more_account; + m_pos.next_account()) + { + account= global_account_container.get(m_pos.m_index_1, & has_more_account); + if (account != NULL) + { + transaction_class= find_transaction_class(m_pos.m_index_2); + if (transaction_class) + { + make_row(account, transaction_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_ets_by_account_by_event_name::rnd_pos(const void *pos) +{ + PFS_account *account; + PFS_transaction_class *transaction_class; + + set_position(pos); + + account= global_account_container.get(m_pos.m_index_1); + if (account != NULL) + { + transaction_class= find_transaction_class(m_pos.m_index_2); + if (transaction_class) + { + make_row(account, transaction_class); + return 0; + } + } + + return HA_ERR_RECORD_DELETED; +} + +void table_ets_by_account_by_event_name +::make_row(PFS_account *account, PFS_transaction_class *klass) +{ + pfs_optimistic_state 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_transaction_visitor visitor(klass); + PFS_connection_iterator::visit_account(account, + true, /* threads */ + false, /* THDs */ + &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_ets_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: + /** + COUNT_STAR, SUM/MIN/AVG/MAX_TIMER_WAIT, + COUNT_READ_WRITE, SUM/MIN/AVG/MAX_TIMER_READ_WRITE, + COUNT_READ_ONLY, SUM/MIN/AVG/MAX_TIMER_READ_ONLY + */ + m_row.m_stat.set_field(f->field_index-3, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_ets_by_account_by_event_name.h b/storage/perfschema/table_ets_by_account_by_event_name.h new file mode 100644 index 00000000000..98fb45f79dd --- /dev/null +++ b/storage/perfschema/table_ets_by_account_by_event_name.h @@ -0,0 +1,134 @@ +/* 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_ETS_BY_ACCOUNT_BY_EVENT_NAME_H +#define TABLE_ETS_BY_ACCOUNT_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_ets_by_account_by_event_name.h + Table EVENTS_TRANSACTIONS_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_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. +*/ +struct row_ets_by_account_by_event_name +{ + /** Columns 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, + COUNT_READ_WRITE, SUM/MIN/AVG/MAX_TIMER_READ_WRITE, + COUNT_READ_ONLY, SUM/MIN/AVG/MAX_TIMER_READ_ONLY + */ + PFS_transaction_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + Index 1 on account (0 based) + Index 2 on transaction class (1 based) +*/ +struct pos_ets_by_account_by_event_name +: public PFS_double_index +{ + pos_ets_by_account_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline void next_account(void) + { + m_index_1++; + m_index_2= 1; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. */ +class table_ets_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(); + static ha_rows get_row_count(); + + 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_ets_by_account_by_event_name(); + +public: + ~table_ets_by_account_by_event_name() + {} + +protected: + void make_row(PFS_account *account, PFS_transaction_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_ets_by_account_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_ets_by_account_by_event_name m_pos; + /** Next position. */ + pos_ets_by_account_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_ets_by_host_by_event_name.cc b/storage/perfschema/table_ets_by_host_by_event_name.cc new file mode 100644 index 00000000000..f02936241a0 --- /dev/null +++ b/storage/perfschema/table_ets_by_host_by_event_name.cc @@ -0,0 +1,226 @@ +/* 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_ets_by_host_by_event_name.cc + Table EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_ets_by_host_by_event_name.h" +#include "pfs_global.h" +#include "pfs_account.h" +#include "pfs_visitor.h" +#include "pfs_buffer_container.h" +#include "field.h" + +THR_LOCK table_ets_by_host_by_event_name::m_table_lock; + +PFS_engine_table_share +table_ets_by_host_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_transactions_summary_by_host_by_event_name") }, + &pfs_truncatable_acl, + table_ets_by_host_by_event_name::create, + NULL, /* write_row */ + table_ets_by_host_by_event_name::delete_all_rows, + table_ets_by_host_by_event_name::get_row_count, + sizeof(pos_ets_by_host_by_event_name), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE events_transactions_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," + "COUNT_READ_WRITE BIGINT unsigned not null," + "SUM_TIMER_READ_WRITE BIGINT unsigned not null," + "MIN_TIMER_READ_WRITE BIGINT unsigned not null," + "AVG_TIMER_READ_WRITE BIGINT unsigned not null," + "MAX_TIMER_READ_WRITE BIGINT unsigned not null," + "COUNT_READ_ONLY BIGINT unsigned not null," + "SUM_TIMER_READ_ONLY BIGINT unsigned not null," + "MIN_TIMER_READ_ONLY BIGINT unsigned not null," + "AVG_TIMER_READ_ONLY BIGINT unsigned not null," + "MAX_TIMER_READ_ONLY BIGINT unsigned not null)")}, + false /* perpetual */ +}; + +PFS_engine_table* +table_ets_by_host_by_event_name::create(void) +{ + return new table_ets_by_host_by_event_name(); +} + +int +table_ets_by_host_by_event_name::delete_all_rows(void) +{ + reset_events_transactions_by_thread(); + reset_events_transactions_by_account(); + reset_events_transactions_by_host(); + return 0; +} + +ha_rows +table_ets_by_host_by_event_name::get_row_count(void) +{ + return global_host_container.get_row_count() * transaction_class_max; +} + +table_ets_by_host_by_event_name::table_ets_by_host_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_ets_by_host_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_ets_by_host_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(transaction_timer); + return 0; +} + +int table_ets_by_host_by_event_name::rnd_next(void) +{ + PFS_host *host; + PFS_transaction_class *transaction_class; + bool has_more_host= true; + + for (m_pos.set_at(&m_next_pos); + has_more_host; + m_pos.next_host()) + { + host= global_host_container.get(m_pos.m_index_1, & has_more_host); + if (host != NULL) + { + transaction_class= find_transaction_class(m_pos.m_index_2); + if (transaction_class) + { + make_row(host, transaction_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_ets_by_host_by_event_name::rnd_pos(const void *pos) +{ + PFS_host *host; + PFS_transaction_class *transaction_class; + + set_position(pos); + + host= global_host_container.get(m_pos.m_index_1); + if (host != NULL) + { + transaction_class= find_transaction_class(m_pos.m_index_2); + if (transaction_class) + { + make_row(host, transaction_class); + return 0; + } + } + + return HA_ERR_RECORD_DELETED; +} + +void table_ets_by_host_by_event_name +::make_row(PFS_host *host, PFS_transaction_class *klass) +{ + pfs_optimistic_state 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_transaction_visitor visitor(klass); + PFS_connection_iterator::visit_host(host, + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & 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_ets_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: + /** + COUNT_STAR, SUM/MIN/AVG/MAX_TIMER_WAIT, + COUNT_READ_WRITE, SUM/MIN/AVG/MAX_TIMER_READ_WRITE, + COUNT_READ_ONLY, SUM/MIN/AVG/MAX_TIMER_READ_ONLY + */ + m_row.m_stat.set_field(f->field_index-2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_ets_by_host_by_event_name.h b/storage/perfschema/table_ets_by_host_by_event_name.h new file mode 100644 index 00000000000..341c3878253 --- /dev/null +++ b/storage/perfschema/table_ets_by_host_by_event_name.h @@ -0,0 +1,134 @@ +/* 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_ETS_BY_HOST_BY_EVENT_NAME_H +#define TABLE_ETS_BY_HOST_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_ets_by_host_by_event_name.h + Table EVENTS_TRANSACTIONS_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_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME. +*/ +struct row_ets_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, + COUNT_READ_WRITE, SUM/MIN/AVG/MAX_TIMER_READ_WRITE, + COUNT_READ_ONLY, SUM/MIN/AVG/MAX_TIMER_READ_ONLY + */ + PFS_transaction_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME. + Index 1 on host (0 based) + Index 2 on transaction class (1 based) +*/ +struct pos_ets_by_host_by_event_name +: public PFS_double_index +{ + pos_ets_by_host_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline void next_host(void) + { + m_index_1++; + m_index_2= 1; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME. */ +class table_ets_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(); + static ha_rows get_row_count(); + + 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_ets_by_host_by_event_name(); + +public: + ~table_ets_by_host_by_event_name() + {} + +protected: + void make_row(PFS_host *host, PFS_transaction_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_ets_by_host_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_ets_by_host_by_event_name m_pos; + /** Next position. */ + pos_ets_by_host_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_ets_by_thread_by_event_name.cc b/storage/perfschema/table_ets_by_thread_by_event_name.cc new file mode 100644 index 00000000000..81ebf23bbfb --- /dev/null +++ b/storage/perfschema/table_ets_by_thread_by_event_name.cc @@ -0,0 +1,218 @@ +/* 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_ets_by_thread_by_event_name.cc + Table EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_ets_by_thread_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" +#include "pfs_buffer_container.h" +#include "field.h" + +THR_LOCK table_ets_by_thread_by_event_name::m_table_lock; + +PFS_engine_table_share +table_ets_by_thread_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_transactions_summary_by_thread_by_event_name") }, + &pfs_truncatable_acl, + table_ets_by_thread_by_event_name::create, + NULL, /* write_row */ + table_ets_by_thread_by_event_name::delete_all_rows, + table_ets_by_thread_by_event_name::get_row_count, + sizeof(pos_ets_by_thread_by_event_name), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE events_transactions_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," + "COUNT_READ_WRITE BIGINT unsigned not null," + "SUM_TIMER_READ_WRITE BIGINT unsigned not null," + "MIN_TIMER_READ_WRITE BIGINT unsigned not null," + "AVG_TIMER_READ_WRITE BIGINT unsigned not null," + "MAX_TIMER_READ_WRITE BIGINT unsigned not null," + "COUNT_READ_ONLY BIGINT unsigned not null," + "SUM_TIMER_READ_ONLY BIGINT unsigned not null," + "MIN_TIMER_READ_ONLY BIGINT unsigned not null," + "AVG_TIMER_READ_ONLY BIGINT unsigned not null," + "MAX_TIMER_READ_ONLY BIGINT unsigned not null)")}, + false /* perpetual */ +}; + +PFS_engine_table* +table_ets_by_thread_by_event_name::create(void) +{ + return new table_ets_by_thread_by_event_name(); +} + +int +table_ets_by_thread_by_event_name::delete_all_rows(void) +{ + reset_events_transactions_by_thread(); + return 0; +} + +ha_rows +table_ets_by_thread_by_event_name::get_row_count(void) +{ + return global_thread_container.get_row_count() * transaction_class_max; +} + +table_ets_by_thread_by_event_name::table_ets_by_thread_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_ets_by_thread_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_ets_by_thread_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(transaction_timer); + return 0; +} + +int table_ets_by_thread_by_event_name::rnd_next(void) +{ + PFS_thread *thread; + PFS_transaction_class *transaction_class; + bool has_more_thread= true; + + for (m_pos.set_at(&m_next_pos); + has_more_thread; + m_pos.next_thread()) + { + thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (thread != NULL) + { + transaction_class= find_transaction_class(m_pos.m_index_2); + if (transaction_class) + { + make_row(thread, transaction_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_ets_by_thread_by_event_name::rnd_pos(const void *pos) +{ + PFS_thread *thread; + PFS_transaction_class *transaction_class; + + set_position(pos); + + thread= global_thread_container.get(m_pos.m_index_1); + if (thread != NULL) + { + transaction_class= find_transaction_class(m_pos.m_index_2); + if (transaction_class) + { + make_row(thread, transaction_class); + return 0; + } + } + + return HA_ERR_RECORD_DELETED; +} + +void table_ets_by_thread_by_event_name +::make_row(PFS_thread *thread, PFS_transaction_class *klass) +{ + pfs_optimistic_state 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_transaction_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_ets_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: + /** + COUNT_STAR, SUM/MIN/AVG/MAX_TIMER_WAIT + COUNT_READ_WRITE, SUM/MIN/AVG/MAX_TIMER_READ_WRITE + COUNT_READ_ONLY, SUM/MIN/AVG/MAX_TIMER_READ_ONLY + */ + m_row.m_stat.set_field(f->field_index-2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_ets_by_thread_by_event_name.h b/storage/perfschema/table_ets_by_thread_by_event_name.h new file mode 100644 index 00000000000..ad63efa3f1a --- /dev/null +++ b/storage/perfschema/table_ets_by_thread_by_event_name.h @@ -0,0 +1,138 @@ +/* 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_ETS_BY_THREAD_BY_EVENT_NAME_H +#define TABLE_ETS_BY_THREAD_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_ets_by_thread_by_event_name.h + Table EVENTS_TRANSACTIONS_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_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME. +*/ +struct row_ets_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, + COUNT_READ_WRITE, SUM/MIN/AVG/MAX_TIMER_READ_WRITE, + COUNT_READ_ONLY, SUM/MIN/AVG/MAX_TIMER_READ_ONLY + */ + PFS_transaction_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME. + Index 1 on thread (0 based). + Index 2 on transaction class (1 based). +*/ +struct pos_ets_by_thread_by_event_name +: public PFS_double_index, public PFS_instrument_view_constants +{ + pos_ets_by_thread_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline void next_thread(void) + { + m_index_1++; + m_index_2= 1; + } + + inline void next_transaction(void) + { + m_index_2++; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME. */ +class table_ets_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(); + static ha_rows get_row_count(); + + 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_ets_by_thread_by_event_name(); + +public: + ~table_ets_by_thread_by_event_name() + {} + +protected: + void make_row(PFS_thread *thread, PFS_transaction_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_ets_by_thread_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_ets_by_thread_by_event_name m_pos; + /** Next position. */ + pos_ets_by_thread_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_ets_by_user_by_event_name.cc b/storage/perfschema/table_ets_by_user_by_event_name.cc new file mode 100644 index 00000000000..66aae431782 --- /dev/null +++ b/storage/perfschema/table_ets_by_user_by_event_name.cc @@ -0,0 +1,225 @@ +/* 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_ets_by_user_by_event_name.cc + Table EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_ets_by_user_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" +#include "pfs_buffer_container.h" +#include "field.h" + +THR_LOCK table_ets_by_user_by_event_name::m_table_lock; + +PFS_engine_table_share +table_ets_by_user_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_transactions_summary_by_user_by_event_name") }, + &pfs_truncatable_acl, + table_ets_by_user_by_event_name::create, + NULL, /* write_row */ + table_ets_by_user_by_event_name::delete_all_rows, + table_ets_by_user_by_event_name::get_row_count, + sizeof(pos_ets_by_user_by_event_name), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE events_transactions_summary_by_user_by_event_name(" + "USER CHAR(32) 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," + "COUNT_READ_WRITE BIGINT unsigned not null," + "SUM_TIMER_READ_WRITE BIGINT unsigned not null," + "MIN_TIMER_READ_WRITE BIGINT unsigned not null," + "AVG_TIMER_READ_WRITE BIGINT unsigned not null," + "MAX_TIMER_READ_WRITE BIGINT unsigned not null," + "COUNT_READ_ONLY BIGINT unsigned not null," + "SUM_TIMER_READ_ONLY BIGINT unsigned not null," + "MIN_TIMER_READ_ONLY BIGINT unsigned not null," + "AVG_TIMER_READ_ONLY BIGINT unsigned not null," + "MAX_TIMER_READ_ONLY BIGINT unsigned not null)")}, + false /* perpetual */ +}; + +PFS_engine_table* +table_ets_by_user_by_event_name::create(void) +{ + return new table_ets_by_user_by_event_name(); +} + +int +table_ets_by_user_by_event_name::delete_all_rows(void) +{ + reset_events_transactions_by_thread(); + reset_events_transactions_by_account(); + reset_events_transactions_by_user(); + return 0; +} + +ha_rows +table_ets_by_user_by_event_name::get_row_count(void) +{ + return global_user_container.get_row_count() * transaction_class_max; +} + +table_ets_by_user_by_event_name::table_ets_by_user_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_ets_by_user_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_ets_by_user_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(transaction_timer); + return 0; +} + +int table_ets_by_user_by_event_name::rnd_next(void) +{ + PFS_user *user; + PFS_transaction_class *transaction_class; + bool has_more_user= true; + + for (m_pos.set_at(&m_next_pos); + has_more_user; + m_pos.next_user()) + { + user= global_user_container.get(m_pos.m_index_1, & has_more_user); + if (user != NULL) + { + transaction_class= find_transaction_class(m_pos.m_index_2); + if (transaction_class) + { + make_row(user, transaction_class); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_ets_by_user_by_event_name::rnd_pos(const void *pos) +{ + PFS_user *user; + PFS_transaction_class *transaction_class; + + set_position(pos); + + user= global_user_container.get(m_pos.m_index_1); + if (user != NULL) + { + transaction_class= find_transaction_class(m_pos.m_index_2); + if (transaction_class) + { + make_row(user, transaction_class); + return 0; + } + } + + return HA_ERR_RECORD_DELETED; +} + +void table_ets_by_user_by_event_name +::make_row(PFS_user *user, PFS_transaction_class *klass) +{ + pfs_optimistic_state 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_transaction_visitor visitor(klass); + PFS_connection_iterator::visit_user(user, + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & 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_ets_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: + /** + COUNT_STAR, SUM/MIN/AVG/MAX_TIMER_WAIT, + COUNT_READ_WRITE, SUM/MIN/AVG/MAX_TIMER_READ_WRITE, + COUNT_READ_ONLY, SUM/MIN/AVG/MAX_TIMER_READ_ONLY + */ + m_row.m_stat.set_field(f->field_index-2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_ets_by_user_by_event_name.h b/storage/perfschema/table_ets_by_user_by_event_name.h new file mode 100644 index 00000000000..c3a1d0b5c0a --- /dev/null +++ b/storage/perfschema/table_ets_by_user_by_event_name.h @@ -0,0 +1,134 @@ +/* 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_ETS_BY_USER_BY_EVENT_NAME_H +#define TABLE_ETS_BY_USER_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_ets_by_user_by_event_name.h + Table EVENTS_TRANSACTIONS_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_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME. +*/ +struct row_ets_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, + COUNT_READ_WRITE, SUM/MIN/AVG/MAX_TIMER_READ_WRITE, + COUNT_READ_ONLY, SUM/MIN/AVG/MAX_TIMER_READ_ONLY + */ + PFS_transaction_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME. + Index 1 on user (0 based) + Index 2 on transaction class (1 based) +*/ +struct pos_ets_by_user_by_event_name +: public PFS_double_index +{ + pos_ets_by_user_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline void next_user(void) + { + m_index_1++; + m_index_2= 1; + } +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME. */ +class table_ets_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(); + static ha_rows get_row_count(); + + 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_ets_by_user_by_event_name(); + +public: + ~table_ets_by_user_by_event_name() + {} + +protected: + void make_row(PFS_user *user, PFS_transaction_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_ets_by_user_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_ets_by_user_by_event_name m_pos; + /** Next position. */ + pos_ets_by_user_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_ets_global_by_event_name.cc b/storage/perfschema/table_ets_global_by_event_name.cc new file mode 100644 index 00000000000..6c13871a746 --- /dev/null +++ b/storage/perfschema/table_ets_global_by_event_name.cc @@ -0,0 +1,200 @@ +/* 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_ets_global_by_event_name.cc + Table EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_ets_global_by_event_name.h" +#include "pfs_global.h" +#include "pfs_instr.h" +#include "pfs_timer.h" +#include "pfs_visitor.h" +#include "field.h" + +THR_LOCK table_ets_global_by_event_name::m_table_lock; + +PFS_engine_table_share +table_ets_global_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("events_transactions_summary_global_by_event_name") }, + &pfs_truncatable_acl, + table_ets_global_by_event_name::create, + NULL, /* write_row */ + table_ets_global_by_event_name::delete_all_rows, + table_ets_global_by_event_name::get_row_count, + sizeof(PFS_simple_index), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE events_transactions_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," + "COUNT_READ_WRITE BIGINT unsigned not null," + "SUM_TIMER_READ_WRITE BIGINT unsigned not null," + "MIN_TIMER_READ_WRITE BIGINT unsigned not null," + "AVG_TIMER_READ_WRITE BIGINT unsigned not null," + "MAX_TIMER_READ_WRITE BIGINT unsigned not null," + "COUNT_READ_ONLY BIGINT unsigned not null," + "SUM_TIMER_READ_ONLY BIGINT unsigned not null," + "MIN_TIMER_READ_ONLY BIGINT unsigned not null," + "AVG_TIMER_READ_ONLY BIGINT unsigned not null," + "MAX_TIMER_READ_ONLY BIGINT unsigned not null)")}, + false /* perpetual */ +}; + +PFS_engine_table* +table_ets_global_by_event_name::create(void) +{ + return new table_ets_global_by_event_name(); +} + +int +table_ets_global_by_event_name::delete_all_rows(void) +{ + reset_events_transactions_by_thread(); + reset_events_transactions_by_account(); + reset_events_transactions_by_user(); + reset_events_transactions_by_host(); + reset_events_transactions_global(); + return 0; +} + +ha_rows +table_ets_global_by_event_name::get_row_count(void) +{ + return transaction_class_max; +} + +table_ets_global_by_event_name::table_ets_global_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(1), m_next_pos(1) +{} + +void table_ets_global_by_event_name::reset_position(void) +{ + m_pos= 1; + m_next_pos= 1; +} + +int table_ets_global_by_event_name::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(transaction_timer); + return 0; +} + +int table_ets_global_by_event_name::rnd_next(void) +{ + PFS_transaction_class *transaction_class; + + m_pos.set_at(&m_next_pos); + + transaction_class= find_transaction_class(m_pos.m_index); + if (transaction_class) + { + make_row(transaction_class); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int +table_ets_global_by_event_name::rnd_pos(const void *pos) +{ + PFS_transaction_class *transaction_class; + + set_position(pos); + + transaction_class=find_transaction_class(m_pos.m_index); + if (transaction_class) + { + make_row(transaction_class); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + + +void table_ets_global_by_event_name +::make_row(PFS_transaction_class *klass) +{ + m_row.m_event_name.make_row(klass); + + PFS_connection_transaction_visitor visitor(klass); + PFS_connection_iterator::visit_global(true, /* hosts */ + false, /* users */ + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); + + m_row.m_stat.set(m_normalizer, & visitor.m_stat); + m_row_exists= true; +} + +int table_ets_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: + /** + Columns COUNT_STAR, SUM/MIN/AVG/MAX_TIMER_WAIT, + COUNT_READ_WRITE, SUM/MIN/AVG/MAX_TIMER_READ_WRITE, + COUNT_READ_ONLY, SUM/MIN/AVG/MAX_TIMER_READ_ONLY + */ + m_row.m_stat.set_field(f->field_index - 1, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_ets_global_by_event_name.h b/storage/perfschema/table_ets_global_by_event_name.h new file mode 100644 index 00000000000..47c8828cb47 --- /dev/null +++ b/storage/perfschema/table_ets_global_by_event_name.h @@ -0,0 +1,105 @@ +/* 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_ETS_GLOBAL_BY_EVENT_NAME_H +#define TABLE_ETS_GLOBAL_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_ets_global_by_event_name.h + Table EVENTS_TRANSACTIONS_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_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME. +*/ +struct row_ets_global_by_event_name +{ + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** + Columns COUNT_STAR, SUM/MIN/AVG/MAX_TIMER_WAIT, + COUNT_READ_WRITE, SUM/MIN/AVG/MAX_TIMER_READ_WRITE, + COUNT_READ_ONLY, SUM/MIN/AVG/MAX_TIMER_READ_ONLY + */ + PFS_transaction_stat_row m_stat; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME. */ +class table_ets_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(); + static ha_rows get_row_count(); + + 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_ets_global_by_event_name(); + +public: + ~table_ets_global_by_event_name() + {} + +protected: + void make_row(PFS_transaction_class *klass); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_ets_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 index 95e7f187d24..cd6c79df36c 100644 --- a/storage/perfschema/table_events_stages.cc +++ b/storage/perfschema/table_events_stages.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 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, version 2.0, @@ -26,12 +26,14 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "table_events_stages.h" #include "pfs_instr_class.h" #include "pfs_instr.h" #include "pfs_events_stages.h" #include "pfs_timer.h" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_events_stages_current::m_table_lock; @@ -40,11 +42,10 @@ table_events_stages_current::m_share= { { C_STRING_WITH_LEN("events_stages_current") }, &pfs_truncatable_acl, - &table_events_stages_current::create, + table_events_stages_current::create, NULL, /* write_row */ - &table_events_stages_current::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_events_stages_current::delete_all_rows, + table_events_stages_current::get_row_count, sizeof(PFS_simple_index), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_stages_current(" @@ -56,8 +57,11 @@ table_events_stages_current::m_share= "TIMER_START BIGINT unsigned," "TIMER_END BIGINT unsigned," "TIMER_WAIT BIGINT unsigned," + "WORK_COMPLETED BIGINT unsigned," + "WORK_ESTIMATED BIGINT unsigned," "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") } + "NESTING_EVENT_TYPE ENUM('TRANSACTION', 'STATEMENT', 'STAGE', 'WAIT'))") }, + false /* perpetual */ }; THR_LOCK table_events_stages_history::m_table_lock; @@ -67,11 +71,10 @@ table_events_stages_history::m_share= { { C_STRING_WITH_LEN("events_stages_history") }, &pfs_truncatable_acl, - &table_events_stages_history::create, + table_events_stages_history::create, NULL, /* write_row */ - &table_events_stages_history::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_events_stages_history::delete_all_rows, + table_events_stages_history::get_row_count, sizeof(pos_events_stages_history), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_stages_history(" @@ -83,8 +86,11 @@ table_events_stages_history::m_share= "TIMER_START BIGINT unsigned," "TIMER_END BIGINT unsigned," "TIMER_WAIT BIGINT unsigned," + "WORK_COMPLETED BIGINT unsigned," + "WORK_ESTIMATED BIGINT unsigned," "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") } + "NESTING_EVENT_TYPE ENUM('TRANSACTION', 'STATEMENT', 'STAGE', 'WAIT'))") }, + false /* perpetual */ }; THR_LOCK table_events_stages_history_long::m_table_lock; @@ -94,11 +100,10 @@ table_events_stages_history_long::m_share= { { C_STRING_WITH_LEN("events_stages_history_long") }, &pfs_truncatable_acl, - &table_events_stages_history_long::create, + table_events_stages_history_long::create, NULL, /* write_row */ - &table_events_stages_history_long::delete_all_rows, - NULL, /* get_row_count */ - 10000, /* records */ + table_events_stages_history_long::delete_all_rows, + table_events_stages_history_long::get_row_count, sizeof(PFS_simple_index), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_stages_history_long(" @@ -110,8 +115,11 @@ table_events_stages_history_long::m_share= "TIMER_START BIGINT unsigned," "TIMER_END BIGINT unsigned," "TIMER_WAIT BIGINT unsigned," + "WORK_COMPLETED BIGINT unsigned," + "WORK_ESTIMATED BIGINT unsigned," "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT'))") } + "NESTING_EVENT_TYPE ENUM('TRANSACTION', 'STATEMENT', 'STAGE', 'WAIT'))") }, + false /* perpetual */ }; table_events_stages_common::table_events_stages_common @@ -126,8 +134,6 @@ table_events_stages_common::table_events_stages_common */ 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; @@ -158,15 +164,19 @@ void table_events_stages_common::make_row(PFS_events_stages *stage) 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; + /* Disable source file and line to avoid stale __FILE__ pointers. */ + m_row.m_source_length= 0; - 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, 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); + if (klass->is_progress()) + { + m_row.m_progress= true; + m_row.m_work_completed= stage->m_progress.m_work_completed; + m_row.m_work_estimated= stage->m_progress.m_work_estimated; + } + else + { + m_row.m_progress= false; + } m_row_exists= true; return; @@ -183,8 +193,9 @@ int table_events_stages_common::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++) { @@ -228,13 +239,25 @@ int table_events_stages_common::read_row_values(TABLE *table, else f->set_null(); break; - case 8: /* NESTING_EVENT_ID */ + case 8: /* WORK_COMPLETED */ + if (m_row.m_progress) + set_field_ulonglong(f, m_row.m_work_completed); + else + f->set_null(); + break; + case 9: /* WORK_ESTIMATED */ + if (m_row.m_progress) + set_field_ulonglong(f, m_row.m_work_estimated); + else + f->set_null(); + break; + case 10: /* 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 */ + case 11: /* NESTING_EVENT_TYPE */ if (m_row.m_nesting_event_id != 0) set_field_enum(f, m_row.m_nesting_event_type); else @@ -275,20 +298,12 @@ 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()) + m_pos.set_at(&m_next_pos); + PFS_thread_iterator it= global_thread_container.iterate(m_pos.m_index); + pfs_thread= it.scan_next(& m_pos.m_index); + if (pfs_thread != NULL) { - 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; @@ -303,15 +318,16 @@ int table_events_stages_current::rnd_pos(const void *pos) 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; + pfs_thread= global_thread_container.get(m_pos.m_index); + if (pfs_thread != NULL) + { + stage= &pfs_thread->m_stage_current; + make_row(stage); + return 0; + } - stage= &pfs_thread->m_stage_current; - make_row(stage); - return 0; + return HA_ERR_RECORD_DELETED; } int table_events_stages_current::delete_all_rows(void) @@ -320,6 +336,12 @@ int table_events_stages_current::delete_all_rows(void) return 0; } +ha_rows +table_events_stages_current::get_row_count(void) +{ + return global_thread_container.get_row_count(); +} + PFS_engine_table* table_events_stages_history::create(void) { return new table_events_stages_history(); @@ -346,43 +368,40 @@ int table_events_stages_history::rnd_next(void) { PFS_thread *pfs_thread; PFS_events_stages *stage; + bool has_more_thread= true; 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; + has_more_thread; 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) + pfs_thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (pfs_thread != NULL) { - /* This thread does not have more (full) history */ - 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; - } + 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]; + 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; + 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; + } } } @@ -396,25 +415,26 @@ int table_events_stages_history::rnd_pos(const void *pos) 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; + pfs_thread= global_thread_container.get(m_pos.m_index_1); + if (pfs_thread != NULL) + { + 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]; + stage= &pfs_thread->m_stages_history[m_pos.m_index_2]; - if (stage->m_class == NULL) - return HA_ERR_RECORD_DELETED; + if (stage->m_class != NULL) + { + make_row(stage); + return 0; + } + } - make_row(stage); - return 0; + return HA_ERR_RECORD_DELETED; } int table_events_stages_history::delete_all_rows(void) @@ -423,6 +443,12 @@ int table_events_stages_history::delete_all_rows(void) return 0; } +ha_rows +table_events_stages_history::get_row_count(void) +{ + return events_stages_history_per_thread * global_thread_container.get_row_count(); +} + PFS_engine_table* table_events_stages_history_long::create(void) { return new table_events_stages_history_long(); @@ -456,7 +482,7 @@ int table_events_stages_history_long::rnd_next(void) if (events_stages_history_long_full) limit= events_stages_history_long_size; else - limit= events_stages_history_long_index % events_stages_history_long_size; + limit= events_stages_history_long_index.m_u32 % events_stages_history_long_size; for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next()) { @@ -487,7 +513,7 @@ int table_events_stages_history_long::rnd_pos(const void *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; + limit= events_stages_history_long_index.m_u32 % events_stages_history_long_size; if (m_pos.m_index > limit) return HA_ERR_RECORD_DELETED; @@ -507,3 +533,9 @@ int table_events_stages_history_long::delete_all_rows(void) return 0; } +ha_rows +table_events_stages_history_long::get_row_count(void) +{ + return events_stages_history_long_size; +} + diff --git a/storage/perfschema/table_events_stages.h b/storage/perfschema/table_events_stages.h index ae8760cd953..16e3fc9651a 100644 --- a/storage/perfschema/table_events_stages.h +++ b/storage/perfschema/table_events_stages.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -66,6 +66,11 @@ struct row_events_stages char m_source[COL_SOURCE_SIZE]; /** Length in bytes of @c m_source. */ uint m_source_length; + bool m_progress; + /** Column WORK_COMPLETED. */ + ulonglong m_work_completed; + /** Column WORK_ESTIMATED. */ + ulonglong m_work_estimated; }; /** Position of a cursor on PERFORMANCE_SCHEMA.EVENTS_STAGES_HISTORY. */ @@ -121,6 +126,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); @@ -155,6 +161,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); @@ -186,6 +193,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_events_statements.cc b/storage/perfschema/table_events_statements.cc index 16fc58d626d..24c2ff4ff74 100644 --- a/storage/perfschema/table_events_statements.cc +++ b/storage/perfschema/table_events_statements.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 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, version 2.0, @@ -26,7 +26,7 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "table_events_statements.h" #include "pfs_instr_class.h" #include "pfs_instr.h" @@ -35,6 +35,7 @@ #include "sp_head.h" /* TYPE_ENUM_FUNCTION, ... */ #include "table_helper.h" #include "my_md5.h" +#include "pfs_buffer_container.h" THR_LOCK table_events_statements_current::m_table_lock; @@ -43,11 +44,10 @@ table_events_statements_current::m_share= { { C_STRING_WITH_LEN("events_statements_current") }, &pfs_truncatable_acl, - &table_events_statements_current::create, + table_events_statements_current::create, NULL, /* write_row */ - &table_events_statements_current::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_events_statements_current::delete_all_rows, + table_events_statements_current::get_row_count, sizeof(pos_events_statements_current), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_statements_current(" @@ -90,7 +90,9 @@ table_events_statements_current::m_share= "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'))") } + "NESTING_EVENT_TYPE ENUM('TRANSACTION', 'STATEMENT', 'STAGE', 'WAIT')," + "NESTING_EVENT_LEVEL INT unsigned)") }, + false /* perpetual */ }; THR_LOCK table_events_statements_history::m_table_lock; @@ -100,11 +102,10 @@ table_events_statements_history::m_share= { { C_STRING_WITH_LEN("events_statements_history") }, &pfs_truncatable_acl, - &table_events_statements_history::create, + table_events_statements_history::create, NULL, /* write_row */ - &table_events_statements_history::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_events_statements_history::delete_all_rows, + table_events_statements_history::get_row_count, sizeof(pos_events_statements_history), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_statements_history(" @@ -147,7 +148,9 @@ table_events_statements_history::m_share= "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'))") } + "NESTING_EVENT_TYPE ENUM('TRANSACTION', 'STATEMENT', 'STAGE', 'WAIT')," + "NESTING_EVENT_LEVEL INT unsigned)") }, + false /* perpetual */ }; THR_LOCK table_events_statements_history_long::m_table_lock; @@ -157,11 +160,10 @@ table_events_statements_history_long::m_share= { { C_STRING_WITH_LEN("events_statements_history_long") }, &pfs_truncatable_acl, - &table_events_statements_history_long::create, + table_events_statements_history_long::create, NULL, /* write_row */ - &table_events_statements_history_long::delete_all_rows, - NULL, /* get_row_count */ - 10000, /* records */ + table_events_statements_history_long::delete_all_rows, + table_events_statements_history_long::get_row_count, sizeof(PFS_simple_index), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_statements_history_long(" @@ -204,7 +206,9 @@ table_events_statements_history_long::m_share= "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'))") } + "NESTING_EVENT_TYPE ENUM('TRANSACTION', 'STATEMENT', 'STAGE', 'WAIT')," + "NESTING_EVENT_LEVEL INT unsigned)") }, + false /* perpetual */ }; table_events_statements_common::table_events_statements_common @@ -220,8 +224,6 @@ table_events_statements_common::table_events_statements_common 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; @@ -236,6 +238,7 @@ void table_events_statements_common::make_row_part_1(PFS_events_statements *stat m_row.m_end_event_id= statement->m_end_event_id; m_row.m_nesting_event_id= statement->m_nesting_event_id; m_row.m_nesting_event_type= statement->m_nesting_event_type; + m_row.m_nesting_event_level= statement->m_nesting_event_level; if (m_row.m_end_event_id == 0) { @@ -287,15 +290,18 @@ void table_events_statements_common::make_row_part_1(PFS_events_statements *stat 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; + m_row.m_object_type= statement->m_sp_type; + + m_row.m_schema_name_length= statement->m_schema_name_length; + if (m_row.m_schema_name_length > 0) + memcpy(m_row.m_schema_name, statement->m_schema_name, m_row.m_schema_name_length); - 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); + m_row.m_object_name_length= statement->m_object_name_length; + if (m_row.m_object_name_length > 0) + memcpy(m_row.m_object_name, statement->m_object_name, m_row.m_object_name_length); + + /* Disable source file and line to avoid stale __FILE__ pointers. */ + m_row.m_source_length= 0; 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; @@ -319,6 +325,7 @@ void table_events_statements_common::make_row_part_1(PFS_events_statements *stat 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. */ @@ -328,7 +335,6 @@ void table_events_statements_common::make_row_part_1(PFS_events_statements *stat return; } - void table_events_statements_common::make_row_part_2(const sql_digest_storage *digest) { /* @@ -445,18 +451,30 @@ int table_events_statements_common::read_row_values(TABLE *table, 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); + 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(); + case 13: /* OBJECT_TYPE */ + if (m_row.m_object_name_length > 0) + set_field_object_type(f, m_row.m_object_type); + else + f->set_null(); break; case 14: /* OBJECT_SCHEMA */ - f->set_null(); + 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 15: /* OBJECT_NAME */ - f->set_null(); + 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 16: /* OBJECT_INSTANCE_BEGIN */ f->set_null(); @@ -471,7 +489,7 @@ int table_events_statements_common::read_row_values(TABLE *table, f->set_null(); break; case 19: /* MESSAGE_TEXT */ - len= (uint)strlen(m_row.m_message_text); + len= strlen(m_row.m_message_text); if (len) set_field_varchar_utf8(f, m_row.m_message_text, len); else @@ -543,6 +561,9 @@ int table_events_statements_common::read_row_values(TABLE *table, else f->set_null(); break; + case 40: /* NESTING_EVENT_LEVEL */ + set_field_ulong(f, m_row.m_nesting_event_level); + break; default: DBUG_ASSERT(false); } @@ -577,39 +598,36 @@ int table_events_statements_current::rnd_next(void) { PFS_thread *pfs_thread; PFS_events_statements *statement; + bool has_more_thread= true; for (m_pos.set_at(&m_next_pos); - m_pos.m_index_1 < thread_max; + has_more_thread; m_pos.next_thread()) { - pfs_thread= &thread_array[m_pos.m_index_1]; - - if (! pfs_thread->m_lock.is_populated()) + pfs_thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (pfs_thread != NULL) { - /* This thread does not exist */ - continue; - } - - uint safe_events_statements_count= pfs_thread->m_events_statements_count; + 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; - } + 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]; + 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; + make_row(pfs_thread, statement); + m_next_pos.set_after(&m_pos); + return 0; + } } return HA_ERR_END_OF_FILE; @@ -621,44 +639,45 @@ int table_events_statements_current::rnd_pos(const void *pos) 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 + pfs_thread= global_thread_container.get(m_pos.m_index_1); + if (pfs_thread != NULL) { - /* Display all pending statements, when in progress */ - if (m_pos.m_index_2 >= safe_events_statements_count) - return HA_ERR_RECORD_DELETED; - } + uint safe_events_statements_count= pfs_thread->m_events_statements_count; - DBUG_ASSERT(m_pos.m_index_2 < statement_stack_max); + 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; + } - statement= &pfs_thread->m_statement_stack[m_pos.m_index_2]; + DBUG_ASSERT(m_pos.m_index_2 < statement_stack_max); - if (statement->m_class == NULL) - return HA_ERR_RECORD_DELETED; + statement= &pfs_thread->m_statement_stack[m_pos.m_index_2]; - make_row(pfs_thread, statement); - return 0; + if (statement->m_class != NULL) + { + make_row(pfs_thread, statement); + return 0; + } + } + + return HA_ERR_RECORD_DELETED; } 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; + pfs_optimistic_state lock; + pfs_optimistic_state stmt_lock; digest.reset(m_token_array, MAX_DIGEST_STORAGE_SIZE); /* Protect this reader against thread termination. */ @@ -684,6 +703,12 @@ int table_events_statements_current::delete_all_rows(void) return 0; } +ha_rows +table_events_statements_current::get_row_count(void) +{ + return global_thread_container.get_row_count() * statement_stack_max; +} + PFS_engine_table* table_events_statements_history::create(void) { return new table_events_statements_history(); @@ -710,43 +735,40 @@ int table_events_statements_history::rnd_next(void) { PFS_thread *pfs_thread; PFS_events_statements *statement; + bool has_more_thread= true; 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; + has_more_thread; 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) + pfs_thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (pfs_thread != NULL) { - /* This thread does not have more (full) history */ - 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; - } + 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]; + 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; + 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; + } } } @@ -760,32 +782,32 @@ int table_events_statements_history::rnd_pos(const void *pos) 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; + pfs_thread= global_thread_container.get(m_pos.m_index_1); + if (pfs_thread != NULL) + { + DBUG_ASSERT(m_pos.m_index_2 < events_statements_history_per_thread); - statement= &pfs_thread->m_statements_history[m_pos.m_index_2]; + if ( ! pfs_thread->m_statements_history_full && + (m_pos.m_index_2 >= pfs_thread->m_statements_history_index)) + return HA_ERR_RECORD_DELETED; - if (statement->m_class == NULL) - return HA_ERR_RECORD_DELETED; + statement= &pfs_thread->m_statements_history[m_pos.m_index_2]; + if (statement->m_class != NULL) + { + make_row(pfs_thread, statement); + return 0; + } + } - make_row(pfs_thread, statement); - return 0; + return HA_ERR_RECORD_DELETED; } void table_events_statements_history::make_row(PFS_thread *pfs_thread, PFS_events_statements *statement) { sql_digest_storage digest; - pfs_lock lock; + pfs_optimistic_state lock; digest.reset(m_token_array, MAX_DIGEST_STORAGE_SIZE); /* Protect this reader against thread termination. */ @@ -799,15 +821,22 @@ void table_events_statements_history::make_row(PFS_thread *pfs_thread, return; } table_events_statements_common::make_row_part_2(&digest); - return; + return; } + int table_events_statements_history::delete_all_rows(void) { reset_events_statements_history(); return 0; } +ha_rows +table_events_statements_history::get_row_count(void) +{ + return events_statements_history_per_thread * global_thread_container.get_row_count(); +} + PFS_engine_table* table_events_statements_history_long::create(void) { return new table_events_statements_history_long(); @@ -833,7 +862,7 @@ int table_events_statements_history_long::rnd_init(bool scan) int table_events_statements_history_long::rnd_next(void) { PFS_events_statements *statement; - size_t limit; + uint limit; if (events_statements_history_long_size == 0) return HA_ERR_END_OF_FILE; @@ -841,7 +870,7 @@ int table_events_statements_history_long::rnd_next(void) if (events_statements_history_long_full) limit= events_statements_history_long_size; else - limit= events_statements_history_long_index % events_statements_history_long_size; + limit= events_statements_history_long_index.m_u32 % events_statements_history_long_size; for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next()) { @@ -862,7 +891,7 @@ int table_events_statements_history_long::rnd_next(void) int table_events_statements_history_long::rnd_pos(const void *pos) { PFS_events_statements *statement; - size_t limit; + uint limit; if (events_statements_history_long_size == 0) return HA_ERR_RECORD_DELETED; @@ -872,7 +901,7 @@ int table_events_statements_history_long::rnd_pos(const void *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; + limit= events_statements_history_long_index.m_u32 % events_statements_history_long_size; if (m_pos.m_index >= limit) return HA_ERR_RECORD_DELETED; @@ -903,3 +932,9 @@ int table_events_statements_history_long::delete_all_rows(void) return 0; } +ha_rows +table_events_statements_history_long::get_row_count(void) +{ + return events_statements_history_long_size; +} + diff --git a/storage/perfschema/table_events_statements.h b/storage/perfschema/table_events_statements.h index cec28628f3e..02127cadecc 100644 --- a/storage/perfschema/table_events_statements.h +++ b/storage/perfschema/table_events_statements.h @@ -53,6 +53,8 @@ struct row_events_statements ulonglong m_nesting_event_id; /** Column NESTING_EVENT_TYPE. */ enum_event_type m_nesting_event_type; + /** Column NESTING_EVENT_LEVEL. */ + uint m_nesting_event_level; /** Column EVENT_NAME. */ const char *m_name; /** Length in bytes of @c m_name. */ @@ -73,11 +75,23 @@ struct row_events_statements String m_sqltext; /** Column DIGEST and DIGEST_TEXT. */ PFS_digest_row m_digest; - /** Column CURRENT_SCHEMA. */ + /** 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 OBJECT_TYPE. */ + enum_object_type m_object_type; + /** Column OBJECT_SCHEMA. */ + 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 MESSAGE_TEXT. */ char m_message_text[MYSQL_ERRMSG_SIZE+1]; /** Column MYSQL_ERRNO. */ @@ -199,6 +213,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); @@ -235,6 +250,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); @@ -268,6 +284,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_events_transactions.cc b/storage/perfschema/table_events_transactions.cc new file mode 100644 index 00000000000..31d146fa11a --- /dev/null +++ b/storage/perfschema/table_events_transactions.cc @@ -0,0 +1,718 @@ +/* Copyright (c) 2010, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_events_transactions.cc + Table EVENTS_TRANSACTIONS_xxx (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "table_events_transactions.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_events_transactions.h" +#include "pfs_timer.h" +#include "table_helper.h" +#include "pfs_buffer_container.h" +#include "field.h" +//#include "xa.h" + +THR_LOCK table_events_transactions_current::m_table_lock; + +PFS_engine_table_share +table_events_transactions_current::m_share= +{ + { C_STRING_WITH_LEN("events_transactions_current") }, + &pfs_truncatable_acl, + table_events_transactions_current::create, + NULL, /* write_row */ + table_events_transactions_current::delete_all_rows, + table_events_transactions_current::get_row_count, + sizeof(PFS_simple_index), /* ref length */ + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE events_transactions_current(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_ID BIGINT unsigned not null," + "END_EVENT_ID BIGINT unsigned," + "EVENT_NAME VARCHAR(128) not null," + "STATE ENUM('ACTIVE', 'COMMITTED', 'ROLLED BACK')," + "TRX_ID BIGINT unsigned," + "GTID VARCHAR(64)," + "XID_FORMAT_ID INTEGER," + "XID_GTRID VARCHAR(130)," + "XID_BQUAL VARCHAR(130)," + "XA_STATE VARCHAR(64)," + "SOURCE VARCHAR(64)," + "TIMER_START BIGINT unsigned," + "TIMER_END BIGINT unsigned," + "TIMER_WAIT BIGINT unsigned," + "ACCESS_MODE ENUM('READ ONLY', 'READ WRITE')," + "ISOLATION_LEVEL VARCHAR(64)," + "AUTOCOMMIT ENUM('YES','NO') not null," + "NUMBER_OF_SAVEPOINTS BIGINT unsigned," + "NUMBER_OF_ROLLBACK_TO_SAVEPOINT BIGINT unsigned," + "NUMBER_OF_RELEASE_SAVEPOINT BIGINT unsigned," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned," + "NESTING_EVENT_ID BIGINT unsigned," + "NESTING_EVENT_TYPE ENUM('TRANSACTION', 'STATEMENT', 'STAGE', 'WAIT'))")}, + false /* perpetual */ +}; + +THR_LOCK table_events_transactions_history::m_table_lock; + +PFS_engine_table_share +table_events_transactions_history::m_share= +{ + { C_STRING_WITH_LEN("events_transactions_history") }, + &pfs_truncatable_acl, + table_events_transactions_history::create, + NULL, /* write_row */ + table_events_transactions_history::delete_all_rows, + table_events_transactions_history::get_row_count, + sizeof(pos_events_transactions_history), /* ref length */ + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE events_transactions_history(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_ID BIGINT unsigned not null," + "END_EVENT_ID BIGINT unsigned," + "EVENT_NAME VARCHAR(128) not null," + "STATE ENUM('ACTIVE', 'COMMITTED', 'ROLLED BACK')," + "TRX_ID BIGINT unsigned," + "GTID VARCHAR(64)," + "XID_FORMAT_ID INTEGER," + "XID_GTRID VARCHAR(130)," + "XID_BQUAL VARCHAR(130)," + "XA_STATE VARCHAR(64)," + "SOURCE VARCHAR(64)," + "TIMER_START BIGINT unsigned," + "TIMER_END BIGINT unsigned," + "TIMER_WAIT BIGINT unsigned," + "ACCESS_MODE ENUM('READ ONLY', 'READ WRITE')," + "ISOLATION_LEVEL VARCHAR(64)," + "AUTOCOMMIT ENUM('YES','NO') not null," + "NUMBER_OF_SAVEPOINTS BIGINT unsigned," + "NUMBER_OF_ROLLBACK_TO_SAVEPOINT BIGINT unsigned," + "NUMBER_OF_RELEASE_SAVEPOINT BIGINT unsigned," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned," + "NESTING_EVENT_ID BIGINT unsigned," + "NESTING_EVENT_TYPE ENUM('TRANSACTION', 'STATEMENT', 'STAGE', 'WAIT'))")}, + false /* perpetual */ +}; + +THR_LOCK table_events_transactions_history_long::m_table_lock; + +PFS_engine_table_share +table_events_transactions_history_long::m_share= +{ + { C_STRING_WITH_LEN("events_transactions_history_long") }, + &pfs_truncatable_acl, + table_events_transactions_history_long::create, + NULL, /* write_row */ + table_events_transactions_history_long::delete_all_rows, + table_events_transactions_history_long::get_row_count, + sizeof(PFS_simple_index), /* ref length */ + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE events_transactions_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," + "STATE ENUM('ACTIVE', 'COMMITTED', 'ROLLED BACK')," + "TRX_ID BIGINT unsigned," + "GTID VARCHAR(64)," + "XID_FORMAT_ID INTEGER," + "XID_GTRID VARCHAR(130)," + "XID_BQUAL VARCHAR(130)," + "XA_STATE VARCHAR(64)," + "SOURCE VARCHAR(64)," + "TIMER_START BIGINT unsigned," + "TIMER_END BIGINT unsigned," + "TIMER_WAIT BIGINT unsigned," + "ACCESS_MODE ENUM('READ ONLY', 'READ WRITE')," + "ISOLATION_LEVEL VARCHAR(64)," + "AUTOCOMMIT ENUM('YES','NO') not null," + "NUMBER_OF_SAVEPOINTS BIGINT unsigned," + "NUMBER_OF_ROLLBACK_TO_SAVEPOINT BIGINT unsigned," + "NUMBER_OF_RELEASE_SAVEPOINT BIGINT unsigned," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned," + "NESTING_EVENT_ID BIGINT unsigned," + "NESTING_EVENT_TYPE ENUM('TRANSACTION', 'STATEMENT', 'STAGE', 'WAIT'))")}, + false /* perpetual */ +}; + +table_events_transactions_common::table_events_transactions_common +(const PFS_engine_table_share *share, void *pos) + : PFS_engine_table(share, pos), + m_row_exists(false) +{} + +/** + Build a row. + @param transaction the transaction the cursor is reading +*/ +void table_events_transactions_common::make_row(PFS_events_transactions *transaction) +{ + ulonglong timer_end; + + m_row_exists= false; + + PFS_transaction_class *unsafe= (PFS_transaction_class*) transaction->m_class; + PFS_transaction_class *klass= sanitize_transaction_class(unsafe); + if (unlikely(klass == NULL)) + return; + + m_row.m_thread_internal_id= transaction->m_thread_internal_id; + m_row.m_event_id= transaction->m_event_id; + m_row.m_end_event_id= transaction->m_end_event_id; + m_row.m_nesting_event_id= transaction->m_nesting_event_id; + m_row.m_nesting_event_type= transaction->m_nesting_event_type; + + if (m_row.m_end_event_id == 0) + { + timer_end= get_timer_raw_value(transaction_timer); + } + else + { + timer_end= transaction->m_timer_end; + } + + m_normalizer->to_pico(transaction->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; + + /* Disable source file and line to avoid stale __FILE__ pointers. */ + m_row.m_source_length= 0; + + /* A GTID consists of the SID (source id) and GNO (transaction number). + The SID is stored in transaction->m_sid and the GNO is stored in + transaction->m_gtid_spec.gno. + + On a master, the GTID is assigned when the transaction commit. + On a slave, the GTID is assigned before the transaction starts. + If GTID_MODE = OFF, all transactions have the special GTID + 'ANONYMOUS'. + + Therefore, a transaction can be in three different states wrt GTIDs: + - Before the GTID has been assigned, the state is 'AUTOMATIC'. + On a master, this is the state until the transaction commits. + On a slave, this state does not appear. + - If GTID_MODE = ON, and a GTID is assigned, the GTID is a string + of the form 'UUID:NUMBER'. + - If GTID_MODE = OFF, and a GTID is assigned, the GTID is a string + of the form 'ANONYMOUS'. + + The Gtid_specification contains the GNO, as well as a type code + that specifies which of the three modes is currently in effect. + Given a SID, it can generate the textual representation of the + GTID. + */ + //rpl_sid *sid= &transaction->m_sid; + Gtid_specification *gtid_spec= &transaction->m_gtid_spec; + m_row.m_gtid_length= gtid_spec->to_string(m_row.m_gtid); + + m_row.m_xid= transaction->m_xid; + m_row.m_isolation_level= transaction->m_isolation_level; + m_row.m_read_only= transaction->m_read_only; + m_row.m_trxid= transaction->m_trxid; + m_row.m_state= transaction->m_state; + m_row.m_xa_state= transaction->m_xa_state; + m_row.m_xa= transaction->m_xa; + m_row.m_autocommit= transaction->m_autocommit; + m_row.m_savepoint_count= transaction->m_savepoint_count; + m_row.m_rollback_to_savepoint_count= transaction->m_rollback_to_savepoint_count; + m_row.m_release_savepoint_count= transaction->m_release_savepoint_count; + m_row_exists= true; + return; +} + +/** Size of XID converted to null-terminated hex string prefixed with 0x. */ +static const ulong XID_BUFFER_SIZE= XIDDATASIZE*2 + 2 + 1; + +/** + Convert the XID to HEX string prefixed by '0x' + + @param[out] buf output hex string buffer, null-terminated + @param buf_len size of buffer, must be at least @c XID_BUFFER_SIZE + @param xid XID structure + @param offset offset into XID.data[] + @param length number of bytes to process + @return number of bytes in hex string +*/ +static uint xid_to_hex(char *buf, size_t buf_len, PSI_xid *xid, size_t offset, size_t length) +{ + DBUG_ASSERT(buf_len >= XID_BUFFER_SIZE); + DBUG_ASSERT(offset + length <= XIDDATASIZE); + *buf++= '0'; + *buf++= 'x'; + return bin_to_hex_str(buf, buf_len-2, (char*)(xid->data + offset), length) + 2; +} + +/** + Store the XID in printable format if possible, otherwise convert + to a string of hex digits. + + @param field Record field + @param xid XID structure + @param offset offset into XID.data[] + @param length number of bytes to process +*/ +static void xid_store(Field *field, PSI_xid *xid, size_t offset, size_t length) +{ + DBUG_ASSERT(!xid->is_null()); + if (xid_printable(xid, offset, length)) + { + field->store(xid->data + offset, length, &my_charset_bin); + } + else + { + /* + xid_buf contains enough space for 0x followed by hex representation of + the binary XID data and one null termination character. + */ + char xid_buf[XID_BUFFER_SIZE]; + + size_t xid_str_len= xid_to_hex(xid_buf, sizeof(xid_buf), xid, offset, length); + field->store(xid_buf, xid_str_len, &my_charset_bin); + } +} + +static void xid_store_bqual(Field *field, PSI_xid *xid) +{ + xid_store(field, xid, xid->gtrid_length, xid->bqual_length); +} + +static void xid_store_gtrid(Field *field, PSI_xid *xid) +{ + xid_store(field, xid, 0, xid->gtrid_length); +} + +int table_events_transactions_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 == 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: /* STATE */ + set_field_enum(f, m_row.m_state); + break; + case 5: /* TRX_ID */ + if (m_row.m_trxid != 0) + set_field_ulonglong(f, m_row.m_trxid); + else + f->set_null(); + break; + case 6: /* GTID */ + set_field_varchar_utf8(f, m_row.m_gtid, m_row.m_gtid_length); + break; + case 7: /* XID_FORMAT_ID */ + if (!m_row.m_xa || m_row.m_xid.is_null()) + f->set_null(); + else + set_field_long(f, m_row.m_xid.formatID); + break; + case 8: /* XID_GTRID */ + if (!m_row.m_xa || m_row.m_xid.is_null() || m_row.m_xid.gtrid_length <= 0) + f->set_null(); + else + xid_store_gtrid(f, &m_row.m_xid); + break; + case 9: /* XID_BQUAL */ + if (!m_row.m_xa || m_row.m_xid.is_null() || m_row.m_xid.bqual_length <= 0) + f->set_null(); + else + xid_store_bqual(f, &m_row.m_xid); + break; + case 10: /* XA STATE */ + if (!m_row.m_xa || m_row.m_xid.is_null()) + f->set_null(); + else + set_field_xa_state(f, m_row.m_xa_state); + break; + case 11: /* SOURCE */ + set_field_varchar_utf8(f, m_row.m_source, m_row.m_source_length); + break; + case 12: /* TIMER_START */ + if (m_row.m_timer_start != 0) + set_field_ulonglong(f, m_row.m_timer_start); + else + f->set_null(); + break; + case 13: /* TIMER_END */ + if (m_row.m_timer_end != 0) + set_field_ulonglong(f, m_row.m_timer_end); + else + f->set_null(); + break; + case 14: /* TIMER_WAIT */ + if (m_row.m_timer_wait != 0) + set_field_ulonglong(f, m_row.m_timer_wait); + else + f->set_null(); + break; + case 15: /* ACCESS_MODE */ + set_field_enum(f, m_row.m_read_only ? TRANS_MODE_READ_ONLY + : TRANS_MODE_READ_WRITE); + break; + case 16: /* ISOLATION_LEVEL */ + set_field_isolation_level(f, m_row.m_isolation_level); + break; + case 17: /* AUTOCOMMIT */ + set_field_enum(f, m_row.m_autocommit ? ENUM_YES : ENUM_NO); + break; + case 18: /* NUMBER_OF_SAVEPOINTS */ + set_field_ulonglong(f, m_row.m_savepoint_count); + break; + case 19: /* NUMBER_OF_ROLLBACK_TO_SAVEPOINT */ + set_field_ulonglong(f, m_row.m_rollback_to_savepoint_count); + break; + case 20: /* NUMBER_OF_RELEASE_SAVEPOINT */ + set_field_ulonglong(f, m_row.m_release_savepoint_count); + break; + case 21: /* OBJECT_INSTANCE_BEGIN */ + f->set_null(); + break; + case 22: /* 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 23: /* 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_transactions_current::create(void) +{ + return new table_events_transactions_current(); +} + +table_events_transactions_current::table_events_transactions_current() + : table_events_transactions_common(&m_share, &m_pos), + m_pos(0), m_next_pos(0) +{} + +void table_events_transactions_current::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_events_transactions_current::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(transaction_timer); + return 0; +} + +int table_events_transactions_current::rnd_next(void) +{ + PFS_thread *pfs_thread; + PFS_events_transactions *transaction; + bool has_more_thread= true; + + for (m_pos.set_at(&m_next_pos); + has_more_thread; + m_pos.next()) + { + pfs_thread= global_thread_container.get(m_pos.m_index, & has_more_thread); + if (pfs_thread != NULL) + { + transaction= &pfs_thread->m_transaction_current; + make_row(transaction); + m_next_pos.set_after(&m_pos); + return 0; + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_events_transactions_current::rnd_pos(const void *pos) +{ + PFS_thread *pfs_thread; + PFS_events_transactions *transaction; + + set_position(pos); + + pfs_thread= global_thread_container.get(m_pos.m_index); + if (pfs_thread != NULL) + { + transaction= &pfs_thread->m_transaction_current; + if (transaction->m_class != NULL) + { + make_row(transaction); + return 0; + } + } + + return HA_ERR_RECORD_DELETED; +} + +int table_events_transactions_current::delete_all_rows(void) +{ + reset_events_transactions_current(); + return 0; +} + +ha_rows +table_events_transactions_current::get_row_count(void) +{ + return global_thread_container.get_row_count(); +} + +PFS_engine_table* table_events_transactions_history::create(void) +{ + return new table_events_transactions_history(); +} + +table_events_transactions_history::table_events_transactions_history() + : table_events_transactions_common(&m_share, &m_pos), + m_pos(), m_next_pos() +{} + +void table_events_transactions_history::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_events_transactions_history::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(transaction_timer); + return 0; +} + +int table_events_transactions_history::rnd_next(void) +{ + PFS_thread *pfs_thread; + PFS_events_transactions *transaction; + bool has_more_thread= true; + + if (events_transactions_history_per_thread == 0) + return HA_ERR_END_OF_FILE; + + for (m_pos.set_at(&m_next_pos); + has_more_thread; + m_pos.next_thread()) + { + pfs_thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (pfs_thread != NULL) + { + if (m_pos.m_index_2 >= events_transactions_history_per_thread) + { + /* This thread does not have more (full) history */ + continue; + } + + if ( ! pfs_thread->m_transactions_history_full && + (m_pos.m_index_2 >= pfs_thread->m_transactions_history_index)) + { + /* This thread does not have more (not full) history */ + continue; + } + + transaction= &pfs_thread->m_transactions_history[m_pos.m_index_2]; + if (transaction->m_class != NULL) + { + make_row(transaction); + /* 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_transactions_history::rnd_pos(const void *pos) +{ + PFS_thread *pfs_thread; + PFS_events_transactions *transaction; + + DBUG_ASSERT(events_transactions_history_per_thread != 0); + set_position(pos); + + DBUG_ASSERT(m_pos.m_index_2 < events_transactions_history_per_thread); + + pfs_thread= global_thread_container.get(m_pos.m_index_1); + if (pfs_thread != NULL) + { + if ( ! pfs_thread->m_transactions_history_full && + (m_pos.m_index_2 >= pfs_thread->m_transactions_history_index)) + return HA_ERR_RECORD_DELETED; + + transaction= &pfs_thread->m_transactions_history[m_pos.m_index_2]; + if (transaction->m_class != NULL) + { + make_row(transaction); + return 0; + } + } + + return HA_ERR_RECORD_DELETED; +} + +int table_events_transactions_history::delete_all_rows(void) +{ + reset_events_transactions_history(); + return 0; +} + +ha_rows +table_events_transactions_history::get_row_count(void) +{ + return events_transactions_history_per_thread * global_thread_container.get_row_count(); +} + +PFS_engine_table* table_events_transactions_history_long::create(void) +{ + return new table_events_transactions_history_long(); +} + +table_events_transactions_history_long::table_events_transactions_history_long() + : table_events_transactions_common(&m_share, &m_pos), + m_pos(0), m_next_pos(0) +{} + +void table_events_transactions_history_long::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_events_transactions_history_long::rnd_init(bool scan) +{ + m_normalizer= time_normalizer::get(transaction_timer); + return 0; +} + +int table_events_transactions_history_long::rnd_next(void) +{ + PFS_events_transactions *transaction; + uint limit; + + if (events_transactions_history_long_size == 0) + return HA_ERR_END_OF_FILE; + + if (events_transactions_history_long_full) + limit= events_transactions_history_long_size; + else + limit= events_transactions_history_long_index.m_u32 % events_transactions_history_long_size; + + for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next()) + { + transaction= &events_transactions_history_long_array[m_pos.m_index]; + + if (transaction->m_class != NULL) + { + make_row(transaction); + /* 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_transactions_history_long::rnd_pos(const void *pos) +{ + PFS_events_transactions *transaction; + uint limit; + + if (events_transactions_history_long_size == 0) + return HA_ERR_RECORD_DELETED; + + set_position(pos); + + if (events_transactions_history_long_full) + limit= events_transactions_history_long_size; + else + limit= events_transactions_history_long_index.m_u32 % events_transactions_history_long_size; + + if (m_pos.m_index >= limit) + return HA_ERR_RECORD_DELETED; + + transaction= &events_transactions_history_long_array[m_pos.m_index]; + + if (transaction->m_class == NULL) + return HA_ERR_RECORD_DELETED; + + make_row(transaction); + return 0; +} + +int table_events_transactions_history_long::delete_all_rows(void) +{ + reset_events_transactions_history_long(); + return 0; +} + +ha_rows +table_events_transactions_history_long::get_row_count(void) +{ + return events_transactions_history_long_size; +} + diff --git a/storage/perfschema/table_events_transactions.h b/storage/perfschema/table_events_transactions.h new file mode 100644 index 00000000000..9987319abb2 --- /dev/null +++ b/storage/perfschema/table_events_transactions.h @@ -0,0 +1,254 @@ +/* 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_EVENTS_TRANSACTIONS_H +#define TABLE_EVENTS_TRANSACTIONS_H + +/** + @file storage/perfschema/table_events_HA_ERR_WRONG_COMMAND.h + Table EVENTS_TRANSACTIONS_xxx (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_events_transactions.h" +#include "table_helper.h" +#include "rpl_gtid.h" + +struct PFS_thread; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of table_events_transactions_common. */ +struct row_events_transactions +{ + /** 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; + /** InnoDB transaction id. */ + ulonglong m_trxid; + /** Transaction state. */ + enum_transaction_state m_state; + /** Global Transaction ID. */ + char m_gtid[GTID_MAX_STR_LENGTH + 1]; + /** GTID length in bytes*/ + int m_gtid_length; + /** XA transaction ID. */ + PSI_xid m_xid; + /** XA transaction state. */ + enum_xa_transaction_state m_xa_state; + /** True if XA transaction. */ + bool m_xa; + /** True if autocommit transaction. */ + bool m_autocommit; + /** Isolation level. */ + enum_isolation_level m_isolation_level; + /** True if read-only, read-write otherwise. */ + bool m_read_only; + /** Column NUMBER_OF_SAVEPOINTS. */ + ulonglong m_savepoint_count; + /** Column NUMBER_OF_ROLLBACK_TO_SAVEPOINT. */ + ulonglong m_rollback_to_savepoint_count; + /** Column NUMBER_OF_RELEASE_SAVEPOINT. */ + ulonglong m_release_savepoint_count; +}; + +/** + Position of a cursor on PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_HISTORY. + Index 1 on thread (0 based) + Index 2 on transaction event record in thread history (0 based) +*/ +struct pos_events_transactions_history : public PFS_double_index +{ + pos_events_transactions_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_TRANSACTIONS_CURRENT. +*/ +class table_events_transactions_common : public PFS_engine_table +{ +protected: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_events_transactions_common(const PFS_engine_table_share *share, void *pos); + + ~table_events_transactions_common() + {} + + void make_row(PFS_events_transactions *statement); + + /** Current row. */ + row_events_transactions m_row; + /** True if the current row exists. */ + bool m_row_exists; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_CURRENT. */ +class table_events_transactions_current : public table_events_transactions_common +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + static ha_rows get_row_count(); + + 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_transactions_current(); + +public: + ~table_events_transactions_current() + {} + +private: + friend class table_events_transactions_history; + friend class table_events_transactions_history_long; + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** + Fields definition. + Also used by table_events_transactions_history + and table_events_transactions_history_long. + */ + static TABLE_FIELD_DEF m_field_def; + + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_HISTORY. */ +class table_events_transactions_history : public table_events_transactions_common +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + static ha_rows get_row_count(); + + 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_transactions_history(); + +public: + ~table_events_transactions_history() + {} + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + + /** Current position. */ + pos_events_transactions_history m_pos; + /** Next position. */ + pos_events_transactions_history m_next_pos; +}; + +/** Table PERFORMANCE_SCHEMA.EVENTS_TRANSACTIONS_HISTORY_LONG. */ +class table_events_transactions_history_long : public table_events_transactions_common +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + static ha_rows get_row_count(); + + 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_transactions_history_long(); + +public: + ~table_events_transactions_history_long() + {} + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_events_waits.cc b/storage/perfschema/table_events_waits.cc index 6cfc754f8c2..ae2dde9b39c 100644 --- a/storage/perfschema/table_events_waits.cc +++ b/storage/perfschema/table_events_waits.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2015, 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, version 2.0, @@ -26,7 +26,7 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "table_events_waits.h" #include "pfs_global.h" #include "pfs_instr_class.h" @@ -34,6 +34,8 @@ #include "pfs_events_waits.h" #include "pfs_timer.h" #include "m_string.h" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_events_waits_current::m_table_lock; @@ -42,11 +44,10 @@ table_events_waits_current::m_share= { { C_STRING_WITH_LEN("events_waits_current") }, &pfs_truncatable_acl, - &table_events_waits_current::create, + table_events_waits_current::create, NULL, /* write_row */ - &table_events_waits_current::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_events_waits_current::delete_all_rows, + table_events_waits_current::get_row_count, sizeof(pos_events_waits_current), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_waits_current(" @@ -65,10 +66,11 @@ table_events_waits_current::m_share= "OBJECT_TYPE VARCHAR(64)," "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')," + "NESTING_EVENT_TYPE ENUM('TRANSACTION', 'STATEMENT', 'STAGE', 'WAIT')," "OPERATION VARCHAR(32) not null," "NUMBER_OF_BYTES BIGINT," - "FLAGS INTEGER unsigned)") } + "FLAGS INTEGER unsigned)") }, + false /* perpetual */ }; THR_LOCK table_events_waits_history::m_table_lock; @@ -78,11 +80,10 @@ table_events_waits_history::m_share= { { C_STRING_WITH_LEN("events_waits_history") }, &pfs_truncatable_acl, - &table_events_waits_history::create, + table_events_waits_history::create, NULL, /* write_row */ - &table_events_waits_history::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_events_waits_history::delete_all_rows, + table_events_waits_history::get_row_count, sizeof(pos_events_waits_history), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_waits_history(" @@ -101,10 +102,11 @@ table_events_waits_history::m_share= "OBJECT_TYPE VARCHAR(64)," "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')," + "NESTING_EVENT_TYPE ENUM('TRANSACTION', 'STATEMENT', 'STAGE', 'WAIT')," "OPERATION VARCHAR(32) not null," "NUMBER_OF_BYTES BIGINT," - "FLAGS INTEGER unsigned)") } + "FLAGS INTEGER unsigned)") }, + false /* perpetual */ }; THR_LOCK table_events_waits_history_long::m_table_lock; @@ -114,11 +116,10 @@ table_events_waits_history_long::m_share= { { C_STRING_WITH_LEN("events_waits_history_long") }, &pfs_truncatable_acl, - &table_events_waits_history_long::create, + table_events_waits_history_long::create, NULL, /* write_row */ - &table_events_waits_history_long::delete_all_rows, - NULL, /* get_row_count */ - 10000, /* records */ + table_events_waits_history_long::delete_all_rows, + table_events_waits_history_long::get_row_count, sizeof(PFS_simple_index), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_waits_history_long(" @@ -137,10 +138,11 @@ table_events_waits_history_long::m_share= "OBJECT_TYPE VARCHAR(64)," "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," "NESTING_EVENT_ID BIGINT unsigned," - "NESTING_EVENT_TYPE ENUM('STATEMENT', 'STAGE', 'WAIT')," + "NESTING_EVENT_TYPE ENUM('TRANSACTION', 'STATEMENT', 'STAGE', 'WAIT')," "OPERATION VARCHAR(32) not null," "NUMBER_OF_BYTES BIGINT," - "FLAGS INTEGER unsigned)") } + "FLAGS INTEGER unsigned)") }, + false /* perpetual */ }; table_events_waits_common::table_events_waits_common @@ -151,15 +153,13 @@ table_events_waits_common::table_events_waits_common void table_events_waits_common::clear_object_columns() { - m_row.m_object_type= NULL; m_row.m_object_type_length= 0; m_row.m_object_schema_length= 0; m_row.m_object_name_length= 0; m_row.m_index_name_length= 0; - m_row.m_object_instance_addr= 0; } -int table_events_waits_common::make_table_object_columns(volatile PFS_events_waits *wait) +int table_events_waits_common::make_table_object_columns(PFS_events_waits *wait) { uint safe_index; PFS_table_share *safe_table_share; @@ -200,15 +200,28 @@ int table_events_waits_common::make_table_object_columns(volatile PFS_events_wai 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); + PFS_table_share_index *index_stat; + index_stat= safe_table_share->find_index_stat(safe_index); + + if (index_stat != NULL) + { + m_row.m_index_name_length= index_stat->m_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, index_stat->m_key.m_name, m_row.m_index_name_length); + } + else + { + m_row.m_index_name_length= 0; + } } else + { m_row.m_index_name_length= 0; + } } else { @@ -221,7 +234,7 @@ int table_events_waits_common::make_table_object_columns(volatile PFS_events_wai return 0; } -int table_events_waits_common::make_file_object_columns(volatile PFS_events_waits *wait) +int table_events_waits_common::make_file_object_columns(PFS_events_waits *wait) { PFS_file *safe_file; @@ -253,7 +266,7 @@ int table_events_waits_common::make_file_object_columns(volatile PFS_events_wait return 0; } -int table_events_waits_common::make_socket_object_columns(volatile PFS_events_waits *wait) +int table_events_waits_common::make_socket_object_columns(PFS_events_waits *wait) { PFS_socket *safe_socket; @@ -286,7 +299,7 @@ int table_events_waits_common::make_socket_object_columns(volatile PFS_events_wa safe_socket->m_addr_len); /* Convert port number to a string (length includes ':') */ - int port_len= (int)(int10_to_str(port, (port_str+1), 10) - port_str + 1); + size_t 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; @@ -309,33 +322,133 @@ int table_events_waits_common::make_socket_object_columns(volatile PFS_events_wa return 0; } +int table_events_waits_common::make_metadata_lock_object_columns(PFS_events_waits *wait) +{ + PFS_metadata_lock *safe_metadata_lock; + + safe_metadata_lock= sanitize_metadata_lock(wait->m_weak_metadata_lock); + if (unlikely(safe_metadata_lock == NULL)) + return 1; + + if (safe_metadata_lock->get_version() == wait->m_weak_version) + { + MDL_key *mdl= & safe_metadata_lock->m_mdl_key; + + switch(mdl->mdl_namespace()) + { + case MDL_key::GLOBAL: + m_row.m_object_type= "GLOBAL"; + m_row.m_object_type_length= 6; + m_row.m_object_schema_length= 0; + m_row.m_object_name_length= 0; + break; + case MDL_key::SCHEMA: + m_row.m_object_type= "SCHEMA"; + m_row.m_object_type_length= 6; + m_row.m_object_schema_length= mdl->db_name_length(); + m_row.m_object_name_length= 0; + break; + case MDL_key::TABLE: + m_row.m_object_type= "TABLE"; + m_row.m_object_type_length= 5; + m_row.m_object_schema_length= mdl->db_name_length(); + m_row.m_object_name_length= mdl->name_length(); + break; + case MDL_key::FUNCTION: + m_row.m_object_type= "FUNCTION"; + m_row.m_object_type_length= 8; + m_row.m_object_schema_length= mdl->db_name_length(); + m_row.m_object_name_length= mdl->name_length(); + break; + case MDL_key::PROCEDURE: + m_row.m_object_type= "PROCEDURE"; + m_row.m_object_type_length= 9; + m_row.m_object_schema_length= mdl->db_name_length(); + m_row.m_object_name_length= mdl->name_length(); + break; + case MDL_key::TRIGGER: + m_row.m_object_type= "TRIGGER"; + m_row.m_object_type_length= 7; + m_row.m_object_schema_length= mdl->db_name_length(); + m_row.m_object_name_length= mdl->name_length(); + break; + case MDL_key::EVENT: + m_row.m_object_type= "EVENT"; + m_row.m_object_type_length= 5; + m_row.m_object_schema_length= mdl->db_name_length(); + m_row.m_object_name_length= mdl->name_length(); + break; + case MDL_key::COMMIT: + m_row.m_object_type= "COMMIT"; + m_row.m_object_type_length= 6; + m_row.m_object_schema_length= 0; + m_row.m_object_name_length= 0; + break; + case MDL_key::USER_LOCK: + m_row.m_object_type= "USER LEVEL LOCK"; + m_row.m_object_type_length= 15; + m_row.m_object_schema_length= 0; + m_row.m_object_name_length= mdl->name_length(); + break; +#if 0 + case MDL_key::TABLESPACE: + m_row.m_object_type= "TABLESPACE"; + m_row.m_object_type_length= 10; + m_row.m_object_schema_length= 0; + m_row.m_object_name_length= mdl->name_length(); + break; + case MDL_key::LOCKING_SERVICE: + m_row.m_object_type= "LOCKING SERVICE"; + m_row.m_object_type_length= 15; + m_row.m_object_schema_length= mdl->db_name_length(); + m_row.m_object_name_length= mdl->name_length(); + break; +#endif + case MDL_key::NAMESPACE_END: + default: + m_row.m_object_type_length= 0; + m_row.m_object_schema_length= 0; + m_row.m_object_name_length= 0; + break; + } + + if (m_row.m_object_schema_length > sizeof(m_row.m_object_schema)) + return 1; + if (m_row.m_object_schema_length > 0) + memcpy(m_row.m_object_schema, mdl->db_name(), m_row.m_object_schema_length); + + if (m_row.m_object_name_length > sizeof(m_row.m_object_name)) + return 1; + if (m_row.m_object_name_length > 0) + memcpy(m_row.m_object_name, mdl->name(), m_row.m_object_name_length); + + m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; + } + else + { + m_row.m_object_type_length= 0; + m_row.m_object_schema_length= 0; + m_row.m_object_name_length= 0; + m_row.m_object_instance_addr= 0; + } + + /* INDEX NAME */ + m_row.m_index_name_length= 0; + + return 0; +} + /** Build a row. - @param thread_own_wait True if the memory for the wait - is owned by pfs_thread - @param pfs_thread the thread the cursor is reading @param wait the wait the cursor is reading */ -void table_events_waits_common::make_row(bool thread_own_wait, - PFS_thread *pfs_thread, - volatile PFS_events_waits *wait) +void table_events_waits_common::make_row(PFS_events_waits *wait) { - pfs_lock lock; - PFS_thread *safe_thread; PFS_instr_class *safe_class; - const char *base; - const char *safe_source_file; enum_timer_name timer_name= wait_timer; ulonglong timer_end; m_row_exists= false; - safe_thread= sanitize_thread(pfs_thread); - if (unlikely(safe_thread == NULL)) - return; - - /* Protect this reader against a thread termination */ - if (thread_own_wait) - safe_thread->m_lock.begin_optimistic_lock(&lock); /* Design choice: @@ -362,21 +475,30 @@ void table_events_waits_common::make_row(bool thread_own_wait, */ switch (wait->m_wait_class) { + case WAIT_CLASS_METADATA: + if (make_metadata_lock_object_columns(wait)) + return; + safe_class= sanitize_metadata_class(wait->m_class); + break; case WAIT_CLASS_IDLE: clear_object_columns(); + m_row.m_object_instance_addr= 0; safe_class= sanitize_idle_class(wait->m_class); timer_name= idle_timer; break; case WAIT_CLASS_MUTEX: clear_object_columns(); + m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; safe_class= sanitize_mutex_class((PFS_mutex_class*) wait->m_class); break; case WAIT_CLASS_RWLOCK: clear_object_columns(); + m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; safe_class= sanitize_rwlock_class((PFS_rwlock_class*) wait->m_class); break; case WAIT_CLASS_COND: clear_object_columns(); + m_row.m_object_instance_addr= (intptr) wait->m_object_instance_addr; safe_class= sanitize_cond_class((PFS_cond_class*) wait->m_class); break; case WAIT_CLASS_TABLE: @@ -402,7 +524,7 @@ void table_events_waits_common::make_row(bool thread_own_wait, if (unlikely(safe_class == NULL)) return; - m_row.m_thread_internal_id= safe_thread->m_thread_internal_id; + m_row.m_thread_internal_id= wait->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; @@ -425,39 +547,14 @@ void table_events_waits_common::make_row(bool thread_own_wait, m_row.m_name= safe_class->m_name; m_row.m_name_length= safe_class->m_name_length; - /* - We are assuming this pointer is sane, - since it comes from __FILE__. - */ - safe_source_file= wait->m_source_file; - if (unlikely(safe_source_file == NULL)) - return; + /* Disable source file and line to avoid stale __FILE__ pointers. */ + m_row.m_source_length= 0; - base= base_name(wait->m_source_file); - m_row.m_source_length= (uint)my_snprintf(m_row.m_source, sizeof(m_row.m_source), - "%s:%d", base, wait->m_source_line); - if (m_row.m_source_length > sizeof(m_row.m_source)) - m_row.m_source_length= sizeof(m_row.m_source); m_row.m_operation= wait->m_operation; m_row.m_number_of_bytes= wait->m_number_of_bytes; m_row.m_flags= wait->m_flags; - if (thread_own_wait) - { - if (safe_thread->m_lock.end_optimistic_lock(&lock)) - m_row_exists= true; - } - else - { - /* - For EVENTS_WAITS_HISTORY_LONG (thread_own_wait is false), - the wait record is always valid, because it is not stored - in memory owned by pfs_thread. - Even when the thread terminated, the record is mostly readable, - so this record is displayed. - */ - m_row_exists= true; - } + m_row_exists= true; } /** @@ -474,12 +571,20 @@ static const LEX_STRING operation_names_map[]= { C_STRING_WITH_LEN("lock") }, { C_STRING_WITH_LEN("try_lock") }, - /* RWLock operations */ + /* RWLock operations (RW-lock) */ { C_STRING_WITH_LEN("read_lock") }, { C_STRING_WITH_LEN("write_lock") }, { C_STRING_WITH_LEN("try_read_lock") }, { C_STRING_WITH_LEN("try_write_lock") }, + /* RWLock operations (SX-lock) */ + { C_STRING_WITH_LEN("shared_lock") }, + { C_STRING_WITH_LEN("shared_exclusive_lock") }, + { C_STRING_WITH_LEN("exclusive_lock") }, + { C_STRING_WITH_LEN("try_shared_lock") }, + { C_STRING_WITH_LEN("try_shared_exclusive_lock") }, + { C_STRING_WITH_LEN("try_exclusive_lock") }, + /* Condition operations */ { C_STRING_WITH_LEN("wait") }, { C_STRING_WITH_LEN("timed_wait") }, @@ -516,7 +621,6 @@ static const LEX_STRING operation_names_map[]= { 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") }, @@ -540,7 +644,10 @@ static const LEX_STRING operation_names_map[]= { C_STRING_WITH_LEN("select") }, /* Idle operations */ - { C_STRING_WITH_LEN("idle") } + { C_STRING_WITH_LEN("idle") }, + + /* Medatada lock operations */ + { C_STRING_WITH_LEN("metadata lock") } }; @@ -644,7 +751,7 @@ int table_events_waits_common::read_row_values(TABLE *table, f->set_null(); break; case 12: /* OBJECT_TYPE */ - if (m_row.m_object_type) + if (m_row.m_object_type_length > 0) { set_field_varchar_utf8(f, m_row.m_object_type, m_row.m_object_type_length); @@ -671,14 +778,18 @@ int table_events_waits_common::read_row_values(TABLE *table, operation= &operation_names_map[(int) m_row.m_operation - 1]; set_field_varchar_utf8(f, operation->str, (uint)operation->length); break; - case 17: /* NUMBER_OF_BYTES */ + case 17: /* NUMBER_OF_BYTES (also used for ROWS) */ if ((m_row.m_operation == OPERATION_TYPE_FILEREAD) || (m_row.m_operation == OPERATION_TYPE_FILEWRITE) || (m_row.m_operation == OPERATION_TYPE_FILECHSIZE) || (m_row.m_operation == OPERATION_TYPE_SOCKETSEND) || (m_row.m_operation == OPERATION_TYPE_SOCKETRECV) || (m_row.m_operation == OPERATION_TYPE_SOCKETSENDTO) || - (m_row.m_operation == OPERATION_TYPE_SOCKETRECVFROM)) + (m_row.m_operation == OPERATION_TYPE_SOCKETRECVFROM) || + (m_row.m_operation == OPERATION_TYPE_TABLE_FETCH) || + (m_row.m_operation == OPERATION_TYPE_TABLE_WRITE_ROW) || + (m_row.m_operation == OPERATION_TYPE_TABLE_UPDATE_ROW) || + (m_row.m_operation == OPERATION_TYPE_TABLE_DELETE_ROW)) set_field_ulonglong(f, m_row.m_number_of_bytes); else f->set_null(); @@ -714,28 +825,77 @@ int table_events_waits_current::rnd_next(void) { PFS_thread *pfs_thread; PFS_events_waits *wait; + bool has_more_thread= true; for (m_pos.set_at(&m_next_pos); - m_pos.m_index_1 < thread_max; + has_more_thread; m_pos.next_thread()) { - pfs_thread= &thread_array[m_pos.m_index_1]; - - if (! pfs_thread->m_lock.is_populated()) + pfs_thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (pfs_thread != NULL) { - /* This thread does not exist */ - continue; + /* + We do not show nested events for now, + this will be revised with TABLE io + */ +// #define ONLY_SHOW_ONE_WAIT + +#ifdef ONLY_SHOW_ONE_WAIT + if (m_pos.m_index_2 >= 1) + continue; +#else + /* m_events_waits_stack[0] is a dummy record */ + PFS_events_waits *top_wait = &pfs_thread->m_events_waits_stack[WAIT_STACK_BOTTOM]; + wait= &pfs_thread->m_events_waits_stack[m_pos.m_index_2 + WAIT_STACK_BOTTOM]; + + PFS_events_waits *safe_current = pfs_thread->m_events_waits_current; + + if (safe_current == top_wait) + { + /* Display the last top level wait, when completed */ + if (m_pos.m_index_2 >= 1) + continue; + } + else + { + /* Display all pending waits, when in progress */ + if (wait >= safe_current) + continue; + } +#endif + + if (wait->m_wait_class == NO_WAIT_CLASS) + { + /* + This locker does not exist. + There can not be more lockers in the stack, skip to the next thread + */ + continue; + } + + make_row(pfs_thread, wait); + /* Next iteration, look for the next locker in this thread */ + m_next_pos.set_after(&m_pos); + return 0; } + } - /* - We do not show nested events for now, - this will be revised with TABLE io - */ -// #define ONLY_SHOW_ONE_WAIT + return HA_ERR_END_OF_FILE; +} +int table_events_waits_current::rnd_pos(const void *pos) +{ + PFS_thread *pfs_thread; + PFS_events_waits *wait; + + set_position(pos); + + pfs_thread= global_thread_container.get(m_pos.m_index_1); + if (pfs_thread != NULL) + { #ifdef ONLY_SHOW_ONE_WAIT if (m_pos.m_index_2 >= 1) - continue; + return HA_ERR_RECORD_DELETED; #else /* m_events_waits_stack[0] is a dummy record */ PFS_events_waits *top_wait = &pfs_thread->m_events_waits_stack[WAIT_STACK_BOTTOM]; @@ -747,77 +907,39 @@ int table_events_waits_current::rnd_next(void) { /* Display the last top level wait, when completed */ if (m_pos.m_index_2 >= 1) - continue; + return HA_ERR_RECORD_DELETED; } else { /* Display all pending waits, when in progress */ if (wait >= safe_current) - continue; + return HA_ERR_RECORD_DELETED; } #endif - if (wait->m_wait_class == NO_WAIT_CLASS) + DBUG_ASSERT(m_pos.m_index_2 < WAIT_STACK_LOGICAL_SIZE); + + if (wait->m_wait_class != NO_WAIT_CLASS) { - /* - This locker does not exist. - There can not be more lockers in the stack, skip to the next thread - */ - continue; + make_row(pfs_thread, wait); + return 0; } - - make_row(true, pfs_thread, wait); - /* Next iteration, look for the next locker in this thread */ - m_next_pos.set_after(&m_pos); - return 0; } - return HA_ERR_END_OF_FILE; + return HA_ERR_RECORD_DELETED; } -int table_events_waits_current::rnd_pos(const void *pos) +void table_events_waits_current::make_row(PFS_thread *thread, PFS_events_waits *wait) { - PFS_thread *pfs_thread; - PFS_events_waits *wait; - - set_position(pos); - DBUG_ASSERT(m_pos.m_index_1 < thread_max); - pfs_thread= &thread_array[m_pos.m_index_1]; + pfs_optimistic_state lock; - if (! pfs_thread->m_lock.is_populated()) - return HA_ERR_RECORD_DELETED; - -#ifdef ONLY_SHOW_ONE_WAIT - if (m_pos.m_index_2 >= 1) - return HA_ERR_RECORD_DELETED; -#else - /* m_events_waits_stack[0] is a dummy record */ - PFS_events_waits *top_wait = &pfs_thread->m_events_waits_stack[WAIT_STACK_BOTTOM]; - wait= &pfs_thread->m_events_waits_stack[m_pos.m_index_2 + WAIT_STACK_BOTTOM]; - - PFS_events_waits *safe_current = pfs_thread->m_events_waits_current; - - if (safe_current == top_wait) - { - /* Display the last top level wait, when completed */ - if (m_pos.m_index_2 >= 1) - return HA_ERR_RECORD_DELETED; - } - else - { - /* Display all pending waits, when in progress */ - if (wait >= safe_current) - return HA_ERR_RECORD_DELETED; - } -#endif - - DBUG_ASSERT(m_pos.m_index_2 < WAIT_STACK_LOGICAL_SIZE); + /* Protect this reader against a thread termination */ + thread->m_lock.begin_optimistic_lock(&lock); - if (wait->m_wait_class == NO_WAIT_CLASS) - return HA_ERR_RECORD_DELETED; + table_events_waits_common::make_row(wait); - make_row(true, pfs_thread, wait); - return 0; + if (! thread->m_lock.end_optimistic_lock(&lock)) + m_row_exists= false; } int table_events_waits_current::delete_all_rows(void) @@ -826,6 +948,12 @@ int table_events_waits_current::delete_all_rows(void) return 0; } +ha_rows +table_events_waits_current::get_row_count(void) +{ + return WAIT_STACK_SIZE * global_thread_container.get_row_count(); +} + PFS_engine_table* table_events_waits_history::create(void) { return new table_events_waits_history(); @@ -846,51 +974,40 @@ int table_events_waits_history::rnd_next(void) { PFS_thread *pfs_thread; PFS_events_waits *wait; + bool has_more_thread= true; if (events_waits_history_per_thread == 0) return HA_ERR_END_OF_FILE; for (m_pos.set_at(&m_next_pos); - m_pos.m_index_1 < thread_max; + has_more_thread; m_pos.next_thread()) { - pfs_thread= &thread_array[m_pos.m_index_1]; - - if (! pfs_thread->m_lock.is_populated()) + pfs_thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (pfs_thread != NULL) { - /* This thread does not exist */ - continue; - } - - if (m_pos.m_index_2 >= events_waits_history_per_thread) - { - /* This thread does not have more (full) history */ - continue; - } + if (m_pos.m_index_2 >= events_waits_history_per_thread) + { + /* This thread does not have more (full) history */ + continue; + } - if ( ! pfs_thread->m_waits_history_full && - (m_pos.m_index_2 >= pfs_thread->m_waits_history_index)) - { - /* This thread does not have more (not full) history */ - continue; - } + if ( ! pfs_thread->m_waits_history_full && + (m_pos.m_index_2 >= pfs_thread->m_waits_history_index)) + { + /* This thread does not have more (not full) history */ + continue; + } - if (pfs_thread->m_waits_history[m_pos.m_index_2].m_wait_class - == NO_WAIT_CLASS) - { - /* - This locker does not exist. - There can not be more lockers in the stack, skip to the next thread - */ - continue; + wait= &pfs_thread->m_waits_history[m_pos.m_index_2]; + if (wait->m_wait_class != NO_WAIT_CLASS) + { + make_row(pfs_thread, wait); + /* Next iteration, look for the next history in this thread */ + m_next_pos.set_after(&m_pos); + return 0; + } } - - wait= &pfs_thread->m_waits_history[m_pos.m_index_2]; - - make_row(true, pfs_thread, wait); - /* Next iteration, look for the next history in this thread */ - m_next_pos.set_after(&m_pos); - return 0; } return HA_ERR_END_OF_FILE; @@ -903,25 +1020,39 @@ int table_events_waits_history::rnd_pos(const void *pos) DBUG_ASSERT(events_waits_history_per_thread != 0); set_position(pos); - DBUG_ASSERT(m_pos.m_index_1 < thread_max); - pfs_thread= &thread_array[m_pos.m_index_1]; - if (! pfs_thread->m_lock.is_populated()) - return HA_ERR_RECORD_DELETED; + pfs_thread= global_thread_container.get(m_pos.m_index_1); + if (pfs_thread != NULL) + { + DBUG_ASSERT(m_pos.m_index_2 < events_waits_history_per_thread); + + if ( ! pfs_thread->m_waits_history_full && + (m_pos.m_index_2 >= pfs_thread->m_waits_history_index)) + return HA_ERR_RECORD_DELETED; - DBUG_ASSERT(m_pos.m_index_2 < events_waits_history_per_thread); + wait= &pfs_thread->m_waits_history[m_pos.m_index_2]; - if ( ! pfs_thread->m_waits_history_full && - (m_pos.m_index_2 >= pfs_thread->m_waits_history_index)) - return HA_ERR_RECORD_DELETED; + if (wait->m_wait_class != NO_WAIT_CLASS) + { + make_row(pfs_thread, wait); + return 0; + } + } - wait= &pfs_thread->m_waits_history[m_pos.m_index_2]; + return HA_ERR_RECORD_DELETED; +} - if (wait->m_wait_class == NO_WAIT_CLASS) - return HA_ERR_RECORD_DELETED; +void table_events_waits_history::make_row(PFS_thread *thread, PFS_events_waits *wait) +{ + pfs_optimistic_state lock; - make_row(true, pfs_thread, wait); - return 0; + /* Protect this reader against a thread termination */ + thread->m_lock.begin_optimistic_lock(&lock); + + table_events_waits_common::make_row(wait); + + if (! thread->m_lock.end_optimistic_lock(&lock)) + m_row_exists= false; } int table_events_waits_history::delete_all_rows(void) @@ -930,6 +1061,12 @@ int table_events_waits_history::delete_all_rows(void) return 0; } +ha_rows +table_events_waits_history::get_row_count(void) +{ + return events_waits_history_per_thread * global_thread_container.get_row_count(); +} + PFS_engine_table* table_events_waits_history_long::create(void) { return new table_events_waits_history_long(); @@ -957,7 +1094,7 @@ int table_events_waits_history_long::rnd_next(void) if (events_waits_history_long_full) limit= events_waits_history_long_size; else - limit= events_waits_history_long_index % events_waits_history_long_size; + limit= events_waits_history_long_index.m_u32 % events_waits_history_long_size; for (m_pos.set_at(&m_next_pos); m_pos.m_index < limit; m_pos.next()) { @@ -965,7 +1102,7 @@ int table_events_waits_history_long::rnd_next(void) if (wait->m_wait_class != NO_WAIT_CLASS) { - make_row(false, wait->m_thread, wait); + make_row(wait); /* Next iteration, look for the next entry */ m_next_pos.set_after(&m_pos); return 0; @@ -988,7 +1125,7 @@ int table_events_waits_history_long::rnd_pos(const void *pos) if (events_waits_history_long_full) limit= events_waits_history_long_size; else - limit= events_waits_history_long_index % events_waits_history_long_size; + limit= events_waits_history_long_index.m_u32 % events_waits_history_long_size; if (m_pos.m_index >= limit) return HA_ERR_RECORD_DELETED; @@ -998,7 +1135,7 @@ int table_events_waits_history_long::rnd_pos(const void *pos) if (wait->m_wait_class == NO_WAIT_CLASS) return HA_ERR_RECORD_DELETED; - make_row(false, wait->m_thread, wait); + make_row(wait); return 0; } @@ -1008,3 +1145,9 @@ int table_events_waits_history_long::delete_all_rows(void) return 0; } +ha_rows +table_events_waits_history_long::get_row_count(void) +{ + return events_waits_history_long_size; +} + diff --git a/storage/perfschema/table_events_waits.h b/storage/perfschema/table_events_waits.h index 90c1d341e5d..9173ec30594 100644 --- a/storage/perfschema/table_events_waits.h +++ b/storage/perfschema/table_events_waits.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -150,12 +150,12 @@ 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); + int make_table_object_columns(PFS_events_waits *wait); + int make_file_object_columns(PFS_events_waits *wait); + int make_socket_object_columns(PFS_events_waits *wait); + int make_metadata_lock_object_columns(PFS_events_waits *wait); - void make_row(bool thread_own_wait, PFS_thread *pfs_thread, - volatile PFS_events_waits *wait); + void make_row(PFS_events_waits *wait); /** Current row. */ row_events_waits m_row; @@ -171,6 +171,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); @@ -190,6 +191,8 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; + void make_row(PFS_thread *thread, PFS_events_waits *wait); + /** Current position. */ pos_events_waits_current m_pos; /** Next position. */ @@ -204,6 +207,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); @@ -220,6 +224,8 @@ private: /** Table share lock. */ static THR_LOCK m_table_lock; + void make_row(PFS_thread *thread, PFS_events_waits *wait); + /** Current position. */ pos_events_waits_history m_pos; /** Next position. */ @@ -234,6 +240,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_events_waits_summary.cc b/storage/perfschema/table_events_waits_summary.cc index 03477f6d542..71ae6eae685 100644 --- a/storage/perfschema/table_events_waits_summary.cc +++ b/storage/perfschema/table_events_waits_summary.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, version 2.0, @@ -26,12 +26,13 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr_class.h" #include "pfs_column_types.h" #include "pfs_column_values.h" #include "table_events_waits_summary.h" #include "pfs_global.h" +#include "field.h" THR_LOCK table_events_waits_summary_by_instance::m_table_lock; @@ -40,11 +41,10 @@ table_events_waits_summary_by_instance::m_share= { { C_STRING_WITH_LEN("events_waits_summary_by_instance") }, &pfs_truncatable_acl, - &table_events_waits_summary_by_instance::create, + 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 */ + table_events_waits_summary_by_instance::delete_all_rows, + table_all_instr::get_row_count, sizeof(pos_all_instr), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_by_instance(" @@ -54,7 +54,8 @@ table_events_waits_summary_by_instance::m_share= "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)") } + "MAX_TIMER_WAIT BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* table_events_waits_summary_by_instance::create(void) @@ -78,7 +79,7 @@ void table_events_waits_summary_by_instance const void *object_instance_begin, PFS_single_stat *pfs_stat) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; /* diff --git a/storage/perfschema/table_events_waits_summary.h b/storage/perfschema/table_events_waits_summary.h index 53f1bed7987..51d8a62e02d 100644 --- a/storage/perfschema/table_events_waits_summary.h +++ b/storage/perfschema/table_events_waits_summary.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, version 2.0, diff --git a/storage/perfschema/table_ews_by_account_by_event_name.cc b/storage/perfschema/table_ews_by_account_by_event_name.cc index fa6258ec9ac..062450f3dbf 100644 --- a/storage/perfschema/table_ews_by_account_by_event_name.cc +++ b/storage/perfschema/table_ews_by_account_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,13 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_ews_by_account_by_event_name::m_table_lock; @@ -44,19 +46,19 @@ table_ews_by_account_by_event_name::m_share= 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 */ + table_ews_by_account_by_event_name::get_row_count, 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," + "USER CHAR(" USERNAME_CHAR_LENGTH_STR ") 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)") } + "MAX_TIMER_WAIT BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -73,6 +75,12 @@ table_ews_by_account_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_ews_by_account_by_event_name::get_row_count(void) +{ + return global_account_container.get_row_count() * wait_class_max; +} + 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() @@ -88,13 +96,14 @@ int table_ews_by_account_by_event_name::rnd_next(void) { PFS_account *account; PFS_instr_class *instr_class; + bool has_more_account= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_account(); + has_more_account; m_pos.next_account()) { - account= &account_array[m_pos.m_index_1]; - if (account->m_lock.is_populated()) + account= global_account_container.get(m_pos.m_index_1, & has_more_account); + if (account != NULL) { for ( ; m_pos.has_more_view(); @@ -123,6 +132,9 @@ int table_ews_by_account_by_event_name::rnd_next(void) case pos_ews_by_account_by_event_name::VIEW_IDLE: instr_class= find_idle_class(m_pos.m_index_3); break; + case pos_ews_by_account_by_event_name::VIEW_METADATA: + instr_class= find_metadata_class(m_pos.m_index_3); + break; default: instr_class= NULL; DBUG_ASSERT(false); @@ -149,10 +161,9 @@ table_ews_by_account_by_event_name::rnd_pos(const void *pos) 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()) + account= global_account_container.get(m_pos.m_index_1); + if (account == NULL) return HA_ERR_RECORD_DELETED; switch (m_pos.m_index_2) @@ -178,6 +189,9 @@ table_ews_by_account_by_event_name::rnd_pos(const void *pos) case pos_ews_by_account_by_event_name::VIEW_IDLE: instr_class= find_idle_class(m_pos.m_index_3); break; + case pos_ews_by_account_by_event_name::VIEW_METADATA: + instr_class= find_metadata_class(m_pos.m_index_3); + break; default: instr_class= NULL; DBUG_ASSERT(false); @@ -194,7 +208,7 @@ table_ews_by_account_by_event_name::rnd_pos(const void *pos) void table_ews_by_account_by_event_name ::make_row(PFS_account *account, PFS_instr_class *klass) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; account->m_lock.begin_optimistic_lock(&lock); @@ -205,7 +219,10 @@ void table_ews_by_account_by_event_name m_row.m_event_name.make_row(klass); PFS_connection_wait_visitor visitor(klass); - PFS_connection_iterator::visit_account(account, true, & visitor); + PFS_connection_iterator::visit_account(account, + true, /* threads */ + false, /* THDs */ + & visitor); if (! account->m_lock.end_optimistic_lock(&lock)) return; diff --git a/storage/perfschema/table_ews_by_account_by_event_name.h b/storage/perfschema/table_ews_by_account_by_event_name.h index 7cde09183e3..e64a61b229c 100644 --- a/storage/perfschema/table_ews_by_account_by_event_name.h +++ b/storage/perfschema/table_ews_by_account_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -57,7 +57,7 @@ struct row_ews_by_account_by_event_name /** Position of a cursor on PERFORMANCE_SCHEMA.EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. - Index 1 on user@host (0 based) + Index 1 on account (0 based) Index 2 on instrument view Index 3 on instrument class (1 based) */ @@ -75,9 +75,6 @@ struct pos_ews_by_account_by_event_name m_index_3= 1; } - inline bool has_more_account(void) - { return (m_index_1 < account_max); } - inline void next_account(void) { m_index_1++; @@ -103,6 +100,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_ews_by_host_by_event_name.cc b/storage/perfschema/table_ews_by_host_by_event_name.cc index e3ef7ca3720..25f0edc900c 100644 --- a/storage/perfschema/table_ews_by_host_by_event_name.cc +++ b/storage/perfschema/table_ews_by_host_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,7 +26,7 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr_class.h" #include "pfs_column_types.h" #include "pfs_column_values.h" @@ -34,6 +34,8 @@ #include "pfs_global.h" #include "pfs_account.h" #include "pfs_visitor.h" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_ews_by_host_by_event_name::m_table_lock; @@ -45,8 +47,7 @@ table_ews_by_host_by_event_name::m_share= 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 */ + table_ews_by_host_by_event_name::get_row_count, 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(" @@ -56,7 +57,8 @@ table_ews_by_host_by_event_name::m_share= "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)") } + "MAX_TIMER_WAIT BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -74,6 +76,12 @@ table_ews_by_host_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_ews_by_host_by_event_name::get_row_count(void) +{ + return global_host_container.get_row_count() * wait_class_max; +} + 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() @@ -89,13 +97,14 @@ int table_ews_by_host_by_event_name::rnd_next(void) { PFS_host *host; PFS_instr_class *instr_class; + bool has_more_host= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_host(); + has_more_host; m_pos.next_host()) { - host= &host_array[m_pos.m_index_1]; - if (host->m_lock.is_populated()) + host= global_host_container.get(m_pos.m_index_1, & has_more_host); + if (host != NULL) { for ( ; m_pos.has_more_view(); @@ -124,6 +133,9 @@ int table_ews_by_host_by_event_name::rnd_next(void) case pos_ews_by_host_by_event_name::VIEW_IDLE: instr_class= find_idle_class(m_pos.m_index_3); break; + case pos_ews_by_host_by_event_name::VIEW_METADATA: + instr_class= find_metadata_class(m_pos.m_index_3); + break; default: instr_class= NULL; DBUG_ASSERT(false); @@ -150,10 +162,9 @@ table_ews_by_host_by_event_name::rnd_pos(const void *pos) 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()) + host= global_host_container.get(m_pos.m_index_1); + if (host == NULL) return HA_ERR_RECORD_DELETED; switch (m_pos.m_index_2) @@ -179,6 +190,9 @@ table_ews_by_host_by_event_name::rnd_pos(const void *pos) case pos_ews_by_host_by_event_name::VIEW_IDLE: instr_class= find_idle_class(m_pos.m_index_3); break; + case pos_ews_by_host_by_event_name::VIEW_METADATA: + instr_class= find_metadata_class(m_pos.m_index_3); + break; default: instr_class= NULL; DBUG_ASSERT(false); @@ -196,7 +210,7 @@ table_ews_by_host_by_event_name::rnd_pos(const void *pos) void table_ews_by_host_by_event_name ::make_row(PFS_host *host, PFS_instr_class *klass) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; host->m_lock.begin_optimistic_lock(&lock); @@ -207,7 +221,11 @@ void table_ews_by_host_by_event_name m_row.m_event_name.make_row(klass); PFS_connection_wait_visitor visitor(klass); - PFS_connection_iterator::visit_host(host, true, true, & visitor); + PFS_connection_iterator::visit_host(host, + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); if (! host->m_lock.end_optimistic_lock(&lock)) return; diff --git a/storage/perfschema/table_ews_by_host_by_event_name.h b/storage/perfschema/table_ews_by_host_by_event_name.h index 8ce44a96617..074ec0be822 100644 --- a/storage/perfschema/table_ews_by_host_by_event_name.h +++ b/storage/perfschema/table_ews_by_host_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -75,9 +75,6 @@ struct pos_ews_by_host_by_event_name m_index_3= 1; } - inline bool has_more_host(void) - { return (m_index_1 < host_max); } - inline void next_host(void) { m_index_1++; @@ -103,6 +100,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_ews_by_thread_by_event_name.cc b/storage/perfschema/table_ews_by_thread_by_event_name.cc index 33f9765310b..11b8a84dd46 100644 --- a/storage/perfschema/table_ews_by_thread_by_event_name.cc +++ b/storage/perfschema/table_ews_by_thread_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,13 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_ews_by_thread_by_event_name::m_table_lock; @@ -44,8 +46,7 @@ table_ews_by_thread_by_event_name::m_share= 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 */ + table_ews_by_thread_by_event_name::get_row_count, 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(" @@ -55,7 +56,8 @@ table_ews_by_thread_by_event_name::m_share= "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)") } + "MAX_TIMER_WAIT BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -71,6 +73,12 @@ table_ews_by_thread_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_ews_by_thread_by_event_name::get_row_count(void) +{ + return global_thread_container.get_row_count() * wait_class_max; +} + 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() @@ -86,18 +94,14 @@ int table_ews_by_thread_by_event_name::rnd_next(void) { PFS_thread *thread; PFS_instr_class *instr_class; + bool has_more_thread= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_thread(); + 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()) + thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (thread != NULL) { for ( ; m_pos.has_more_view(); @@ -126,6 +130,9 @@ int table_ews_by_thread_by_event_name::rnd_next(void) case pos_ews_by_thread_by_event_name::VIEW_IDLE: instr_class= find_idle_class(m_pos.m_index_3); break; + case pos_ews_by_thread_by_event_name::VIEW_METADATA: + instr_class= find_metadata_class(m_pos.m_index_3); + break; default: DBUG_ASSERT(false); instr_class= NULL; @@ -152,52 +159,55 @@ table_ews_by_thread_by_event_name::rnd_pos(const void *pos) 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) + thread= global_thread_container.get(m_pos.m_index_1); + if (thread != NULL) { - 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; - } + 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; + case pos_ews_by_thread_by_event_name::VIEW_METADATA: + instr_class= find_metadata_class(m_pos.m_index_3); + break; + default: + DBUG_ASSERT(false); + instr_class= NULL; + } - if (instr_class) - { - make_row(thread, instr_class); - return 0; + 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; + pfs_optimistic_state lock; m_row_exists= false; /* Protect this reader against a thread termination */ @@ -211,9 +221,9 @@ void table_ews_by_thread_by_event_name 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 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. */ diff --git a/storage/perfschema/table_ews_by_thread_by_event_name.h b/storage/perfschema/table_ews_by_thread_by_event_name.h index b67664bfced..d3850e93c0a 100644 --- a/storage/perfschema/table_ews_by_thread_by_event_name.h +++ b/storage/perfschema/table_ews_by_thread_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -74,9 +74,6 @@ struct pos_ews_by_thread_by_event_name m_index_3= 1; } - inline bool has_more_thread(void) - { return (m_index_1 < thread_max); } - inline void next_thread(void) { m_index_1++; @@ -102,6 +99,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_ews_by_user_by_event_name.cc b/storage/perfschema/table_ews_by_user_by_event_name.cc index cb99f749a9c..5425d773f85 100644 --- a/storage/perfschema/table_ews_by_user_by_event_name.cc +++ b/storage/perfschema/table_ews_by_user_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,14 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_ews_by_user_by_event_name::m_table_lock; @@ -45,18 +46,18 @@ table_ews_by_user_by_event_name::m_share= 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 */ + table_ews_by_user_by_event_name::get_row_count, 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," + "USER CHAR(" USERNAME_CHAR_LENGTH_STR ") 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)") } + "MAX_TIMER_WAIT BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -74,6 +75,12 @@ table_ews_by_user_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_ews_by_user_by_event_name::get_row_count(void) +{ + return global_user_container.get_row_count() * wait_class_max; +} + 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() @@ -89,13 +96,14 @@ int table_ews_by_user_by_event_name::rnd_next(void) { PFS_user *user; PFS_instr_class *instr_class; + bool has_more_user= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_user(); + has_more_user; m_pos.next_user()) { - user= &user_array[m_pos.m_index_1]; - if (user->m_lock.is_populated()) + user= global_user_container.get(m_pos.m_index_1, & has_more_user); + if (user != NULL) { for ( ; m_pos.has_more_view(); @@ -124,6 +132,9 @@ int table_ews_by_user_by_event_name::rnd_next(void) case pos_ews_by_user_by_event_name::VIEW_IDLE: instr_class= find_idle_class(m_pos.m_index_3); break; + case pos_ews_by_user_by_event_name::VIEW_METADATA: + instr_class= find_metadata_class(m_pos.m_index_3); + break; default: instr_class= NULL; DBUG_ASSERT(false); @@ -150,10 +161,9 @@ table_ews_by_user_by_event_name::rnd_pos(const void *pos) 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()) + user= global_user_container.get(m_pos.m_index_1); + if (user == NULL) return HA_ERR_RECORD_DELETED; switch (m_pos.m_index_2) @@ -179,6 +189,9 @@ table_ews_by_user_by_event_name::rnd_pos(const void *pos) case pos_ews_by_user_by_event_name::VIEW_IDLE: instr_class= find_idle_class(m_pos.m_index_3); break; + case pos_ews_by_user_by_event_name::VIEW_METADATA: + instr_class= find_metadata_class(m_pos.m_index_3); + break; default: instr_class= NULL; DBUG_ASSERT(false); @@ -196,7 +209,7 @@ table_ews_by_user_by_event_name::rnd_pos(const void *pos) void table_ews_by_user_by_event_name ::make_row(PFS_user *user, PFS_instr_class *klass) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; user->m_lock.begin_optimistic_lock(&lock); @@ -207,7 +220,11 @@ void table_ews_by_user_by_event_name m_row.m_event_name.make_row(klass); PFS_connection_wait_visitor visitor(klass); - PFS_connection_iterator::visit_user(user, true, true, & visitor); + PFS_connection_iterator::visit_user(user, + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); if (! user->m_lock.end_optimistic_lock(&lock)) return; diff --git a/storage/perfschema/table_ews_by_user_by_event_name.h b/storage/perfschema/table_ews_by_user_by_event_name.h index f4f29534be4..b088c8e2015 100644 --- a/storage/perfschema/table_ews_by_user_by_event_name.h +++ b/storage/perfschema/table_ews_by_user_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -75,9 +75,6 @@ struct pos_ews_by_user_by_event_name m_index_3= 1; } - inline bool has_more_user(void) - { return (m_index_1 < user_max); } - inline void next_user(void) { m_index_1++; @@ -103,6 +100,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_ews_global_by_event_name.cc b/storage/perfschema/table_ews_global_by_event_name.cc index 7420c6351fd..13839ddba2b 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, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,7 +26,7 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr_class.h" #include "pfs_column_types.h" #include "pfs_column_values.h" @@ -35,6 +35,7 @@ #include "pfs_instr.h" #include "pfs_timer.h" #include "pfs_visitor.h" +#include "field.h" THR_LOCK table_ews_global_by_event_name::m_table_lock; @@ -46,8 +47,7 @@ table_ews_global_by_event_name::m_share= table_ews_global_by_event_name::create, NULL, /* write_row */ table_ews_global_by_event_name::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_ews_global_by_event_name::get_row_count, sizeof(pos_ews_global_by_event_name), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE events_waits_summary_global_by_event_name(" @@ -56,7 +56,8 @@ table_ews_global_by_event_name::m_share= "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)") } + "MAX_TIMER_WAIT BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -75,6 +76,12 @@ table_ews_global_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_ews_global_by_event_name::get_row_count(void) +{ + return wait_class_max; +} + 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() @@ -169,6 +176,15 @@ int table_ews_global_by_event_name::rnd_next(void) return 0; } break; + case pos_ews_global_by_event_name::VIEW_METADATA: + instr_class= find_metadata_class(m_pos.m_index_2); + if (instr_class) + { + make_metadata_row(instr_class); + m_next_pos.set_after(&m_pos); + return 0; + } + break; default: break; } @@ -247,6 +263,17 @@ table_ews_global_by_event_name::rnd_pos(const void *pos) return 0; } break; + case pos_ews_global_by_event_name::VIEW_METADATA: + instr_class= find_metadata_class(m_pos.m_index_2); + if (instr_class) + { + make_metadata_row(instr_class); + return 0; + } + break; + default: + DBUG_ASSERT(false); + break; } return HA_ERR_RECORD_DELETED; @@ -324,7 +351,7 @@ void table_ews_global_by_event_name 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; @@ -351,8 +378,27 @@ void table_ews_global_by_event_name PFS_connection_wait_visitor visitor(klass); PFS_connection_iterator::visit_global(false, /* hosts */ false, /* users */ - false, /* accts */ - true, /* threads */ &visitor); + false, /* accounts */ + true, /* threads */ + false, /* THDs */ + &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_metadata_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 */ + true, /* users */ + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + &visitor); get_normalizer(klass); m_row.m_stat.set(m_normalizer, &visitor.m_stat); m_row_exists= true; diff --git a/storage/perfschema/table_ews_global_by_event_name.h b/storage/perfschema/table_ews_global_by_event_name.h index 8157d274112..a9deb97a52d 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, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -88,6 +88,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); @@ -114,6 +115,7 @@ protected: 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); + void make_metadata_row(PFS_instr_class *klass); private: /** Table share lock. */ diff --git a/storage/perfschema/table_file_instances.cc b/storage/perfschema/table_file_instances.cc index b323df83ad2..ca77b606200 100644 --- a/storage/perfschema/table_file_instances.cc +++ b/storage/perfschema/table_file_instances.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, version 2.0, @@ -26,12 +26,14 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr.h" #include "pfs_column_types.h" #include "pfs_column_values.h" #include "table_file_instances.h" #include "pfs_global.h" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_file_instances::m_table_lock; @@ -40,17 +42,17 @@ table_file_instances::m_share= { { C_STRING_WITH_LEN("file_instances") }, &pfs_readonly_acl, - &table_file_instances::create, + table_file_instances::create, NULL, /* write_row */ NULL, /* delete_all_rows */ - NULL, /* get_row_count */ - 1000, /* records */ + table_file_instances::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { 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)") } + "OPEN_COUNT INTEGER unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* table_file_instances::create(void) @@ -58,6 +60,12 @@ PFS_engine_table* table_file_instances::create(void) return new table_file_instances(); } +ha_rows +table_file_instances::get_row_count(void) +{ + return global_file_container.get_row_count(); +} + table_file_instances::table_file_instances() : PFS_engine_table(&m_share, &m_pos), m_row_exists(false), m_pos(0), m_next_pos(0) @@ -73,17 +81,14 @@ int table_file_instances::rnd_next(void) { PFS_file *pfs; - for (m_pos.set_at(&m_next_pos); - m_pos.m_index < file_max; - m_pos.next()) + m_pos.set_at(&m_next_pos); + PFS_file_iterator it= global_file_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - 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; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -94,19 +99,20 @@ int table_file_instances::rnd_pos(const void *pos) PFS_file *pfs; set_position(pos); - DBUG_ASSERT(m_pos.m_index < file_max); - pfs= &file_array[m_pos.m_index]; - if (! pfs->m_lock.is_populated()) - return HA_ERR_RECORD_DELETED; + pfs= global_file_container.get(m_pos.m_index); + if (pfs != NULL) + { + make_row(pfs); + return 0; + } - make_row(pfs); - return 0; + return HA_ERR_RECORD_DELETED; } void table_file_instances::make_row(PFS_file *pfs) { - pfs_lock lock; + pfs_optimistic_state lock; PFS_file_class *safe_class; m_row_exists= false; diff --git a/storage/perfschema/table_file_instances.h b/storage/perfschema/table_file_instances.h index 5b44e63028e..cb3d39d46fb 100644 --- a/storage/perfschema/table_file_instances.h +++ b/storage/perfschema/table_file_instances.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, version 2.0, @@ -58,6 +58,7 @@ public: /** Table share */ static PFS_engine_table_share m_share; static PFS_engine_table* create(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_file_summary_by_event_name.cc b/storage/perfschema/table_file_summary_by_event_name.cc index 459b2bf99a6..404b58187ff 100644 --- a/storage/perfschema/table_file_summary_by_event_name.cc +++ b/storage/perfschema/table_file_summary_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -21,18 +21,19 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** - @file storage/perfschema/table_file_summary.cc + @file storage/perfschema/table_file_summary_by_event_name.cc Table FILE_SUMMARY_BY_EVENT_NAME(implementation). */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "field.h" THR_LOCK table_file_summary_by_event_name::m_table_lock; @@ -41,11 +42,10 @@ 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, + 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 */ + table_file_summary_by_event_name::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE file_summary_by_event_name(" @@ -71,7 +71,8 @@ table_file_summary_by_event_name::m_share= "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)") } + "MAX_TIMER_MISC BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* table_file_summary_by_event_name::create(void) @@ -86,6 +87,12 @@ int table_file_summary_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_file_summary_by_event_name::get_row_count(void) +{ + return file_class_max; +} + 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) @@ -132,7 +139,7 @@ int table_file_summary_by_event_name::rnd_pos(const void *pos) /** Build a row. - @param klass the file class the cursor is reading + @param file_class the file class the cursor is reading */ void table_file_summary_by_event_name::make_row(PFS_file_class *file_class) { @@ -142,7 +149,7 @@ void table_file_summary_by_event_name::make_row(PFS_file_class *file_class) 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; diff --git a/storage/perfschema/table_file_summary_by_event_name.h b/storage/perfschema/table_file_summary_by_event_name.h index b8cb293cb07..ae2124fe763 100644 --- a/storage/perfschema/table_file_summary_by_event_name.h +++ b/storage/perfschema/table_file_summary_by_event_name.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -59,6 +59,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_file_summary_by_instance.cc b/storage/perfschema/table_file_summary_by_instance.cc index 3a30984405c..b05d1f24b60 100644 --- a/storage/perfschema/table_file_summary_by_instance.cc +++ b/storage/perfschema/table_file_summary_by_instance.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -21,17 +21,19 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ /** - @file storage/perfschema/table_file_summary.cc + @file storage/perfschema/table_file_summary_by_instance.cc Table FILE_SUMMARY_BY_INSTANCE (implementation). */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_file_summary_by_instance::m_table_lock; @@ -40,11 +42,10 @@ table_file_summary_by_instance::m_share= { { C_STRING_WITH_LEN("file_summary_by_instance") }, &pfs_truncatable_acl, - &table_file_summary_by_instance::create, + table_file_summary_by_instance::create, NULL, /* write_row */ table_file_summary_by_instance::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_file_summary_by_instance::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE file_summary_by_instance(" @@ -72,7 +73,8 @@ table_file_summary_by_instance::m_share= "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)") } + "MAX_TIMER_MISC BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* table_file_summary_by_instance::create(void) @@ -86,6 +88,12 @@ int table_file_summary_by_instance::delete_all_rows(void) return 0; } +ha_rows +table_file_summary_by_instance::get_row_count(void) +{ + return global_file_container.get_row_count(); +} + 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) @@ -101,17 +109,14 @@ 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()) + m_pos.set_at(&m_next_pos); + PFS_file_iterator it= global_file_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - 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; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -122,14 +127,15 @@ 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; + pfs= global_file_container.get(m_pos.m_index); + if (pfs != NULL) + { + make_row(pfs); + return 0; + } - make_row(pfs); - return 0; + return HA_ERR_RECORD_DELETED; } /** @@ -138,7 +144,7 @@ int table_file_summary_by_instance::rnd_pos(const void *pos) */ void table_file_summary_by_instance::make_row(PFS_file *pfs) { - pfs_lock lock; + pfs_optimistic_state lock; PFS_file_class *safe_class; m_row_exists= false; diff --git a/storage/perfschema/table_file_summary_by_instance.h b/storage/perfschema/table_file_summary_by_instance.h index 0e7ce6958b2..7ea90bac056 100644 --- a/storage/perfschema/table_file_summary_by_instance.h +++ b/storage/perfschema/table_file_summary_by_instance.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011 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, version 2.0, @@ -67,6 +67,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_global_status.cc b/storage/perfschema/table_global_status.cc new file mode 100644 index 00000000000..a8d5bacf2f3 --- /dev/null +++ b/storage/perfschema/table_global_status.cc @@ -0,0 +1,190 @@ +/* Copyright (c) 2015, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_global_status.cc + Table global_status (implementation). +*/ + +#include "my_global.h" +#include "table_global_status.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_global.h" + +THR_LOCK table_global_status::m_table_lock; + +PFS_engine_table_share +table_global_status::m_share= +{ + { C_STRING_WITH_LEN("global_status") }, + &pfs_truncatable_world_acl, + table_global_status::create, + NULL, /* write_row */ + table_global_status::delete_all_rows, + table_global_status::get_row_count, + sizeof(pos_t), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE global_status(" + "VARIABLE_NAME VARCHAR(64) not null," + "VARIABLE_VALUE VARCHAR(1024))") }, + true /* perpetual */ +}; + +PFS_engine_table* +table_global_status::create(void) +{ + return new table_global_status(); +} + +int table_global_status::delete_all_rows(void) +{ + mysql_mutex_lock(&LOCK_status); + reset_status_by_thread(); + reset_status_by_account(); + reset_status_by_user(); + reset_status_by_host(); + reset_global_status(); + mysql_mutex_unlock(&LOCK_status); + return 0; +} + +ha_rows table_global_status::get_row_count(void) +{ + mysql_mutex_lock(&LOCK_status); + ha_rows status_var_count= all_status_vars.elements; + mysql_mutex_unlock(&LOCK_status); + return status_var_count; +} + +table_global_status::table_global_status() + : PFS_engine_table(&m_share, &m_pos), + m_status_cache(false), m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_global_status::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_global_status::rnd_init(bool scan) +{ + /* Build a cache of all global status variables. Sum across threads. */ + m_status_cache.materialize_global(); + + /* Record the current number of status variables to detect subsequent changes. */ + ulonglong status_version= m_status_cache.get_status_array_version(); + + /* + The table context holds the current version of the global status array. + If scan == true, then allocate a new context from mem_root and store in TLS. + If scan == false, then restore from TLS. + */ + m_context= (table_global_status_context *)current_thd->alloc(sizeof(table_global_status_context)); + new(m_context) table_global_status_context(status_version, !scan); + return 0; +} + +int table_global_status::rnd_next(void) +{ + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < m_status_cache.size(); + m_pos.next()) + { + const Status_variable *status_var= m_status_cache.get(m_pos.m_index); + if (status_var != NULL) + { + make_row(status_var); + m_next_pos.set_after(&m_pos); + return 0; + } + } + return HA_ERR_END_OF_FILE; +} + +int table_global_status::rnd_pos(const void *pos) +{ + /* If global status array has changed, do nothing. */ // TODO: Issue warning + if (!m_context->versions_match()) + return HA_ERR_RECORD_DELETED; + + set_position(pos); + const Status_variable *status_var= m_status_cache.get(m_pos.m_index); + if (status_var != NULL) + { + make_row(status_var); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_global_status +::make_row(const Status_variable *status_var) +{ + m_row_exists= false; + if (status_var->is_null()) + return; + m_row.m_variable_name.make_row(status_var->m_name, status_var->m_name_length); + m_row.m_variable_value.make_row(status_var); + m_row_exists= true; +} + +int table_global_status +::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: /* VARIABLE_NAME */ + set_field_varchar_utf8(f, m_row.m_variable_name.m_str, m_row.m_variable_name.m_length); + break; + case 1: /* VARIABLE_VALUE */ + m_row.m_variable_value.set_field(f); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_global_status.h b/storage/perfschema/table_global_status.h new file mode 100644 index 00000000000..a97ea9d0041 --- /dev/null +++ b/storage/perfschema/table_global_status.h @@ -0,0 +1,118 @@ +/* Copyright (c) 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_GLOBAL_STATUS_H +#define TABLE_GLOBAL_STATUS_H + +/** + @file storage/perfschema/table_global_status.h + Table global_status (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_variable.h" +#include "table_helper.h" +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.GLOBAL_STATUS. +*/ +struct row_global_status +{ + /** Column VARIABLE_NAME. */ + PFS_variable_name_row m_variable_name; + /** Column VARIABLE_VALUE. */ + PFS_variable_value_row m_variable_value; +}; + +/** + Store and retrieve table state information for queries that reinstantiate + the table object. +*/ +class table_global_status_context : public PFS_table_context +{ +public: + table_global_status_context(ulonglong current_version, bool restore) : + PFS_table_context(current_version, restore, THR_PFS_SG) { } +}; + +/** Table PERFORMANCE_SCHEMA.GLOBAL_STATUS. */ +class table_global_status : public PFS_engine_table +{ + typedef PFS_simple_index pos_t; + +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + static ha_rows get_row_count(); + + 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_global_status(); + +public: + ~table_global_status() + {} + +protected: + void make_row(const Status_variable *system_var); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current THD variables. */ + PFS_status_variable_cache m_status_cache; + /** Current row. */ + row_global_status m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + + /** Table context with global status array version. */ + table_global_status_context *m_context; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_global_variables.cc b/storage/perfschema/table_global_variables.cc new file mode 100644 index 00000000000..9e8c1af2ece --- /dev/null +++ b/storage/perfschema/table_global_variables.cc @@ -0,0 +1,184 @@ +/* Copyright (c) 2015, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_global_variables.cc + Table GLOBAL_VARIABLES (implementation). +*/ + +#include "my_global.h" +#include "table_global_variables.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_global.h" + +THR_LOCK table_global_variables::m_table_lock; + +PFS_engine_table_share +table_global_variables::m_share= +{ + { C_STRING_WITH_LEN("global_variables") }, + &pfs_readonly_world_acl, + table_global_variables::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_global_variables::get_row_count, + sizeof(pos_t), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE global_variables(" + "VARIABLE_NAME VARCHAR(64) not null," + "VARIABLE_VALUE VARCHAR(1024))") }, + true /* perpetual */ +}; + +PFS_engine_table* +table_global_variables::create(void) +{ + return new table_global_variables(); +} + +ha_rows table_global_variables::get_row_count(void) +{ + mysql_mutex_lock(&LOCK_plugin_delete); + mysql_rwlock_rdlock(&LOCK_system_variables_hash); + ha_rows system_var_count= get_system_variable_hash_records(); + mysql_rwlock_unlock(&LOCK_system_variables_hash); + mysql_mutex_unlock(&LOCK_plugin_delete); + return system_var_count; +} + +table_global_variables::table_global_variables() + : PFS_engine_table(&m_share, &m_pos), + m_sysvar_cache(false), m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_global_variables::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_global_variables::rnd_init(bool scan) +{ + /* + Build a list of system variables from the global system variable hash. + Filter by scope. + */ + m_sysvar_cache.materialize_global(); + + /* Record the version of the system variable hash. */ + ulonglong hash_version= m_sysvar_cache.get_sysvar_hash_version(); + + /* + The table context holds the current version of the system variable hash. + If scan == true, then allocate a new context from mem_root and store in TLS. + If scan == false, then restore from TLS. + */ + m_context= (table_global_variables_context *)current_thd->alloc(sizeof(table_global_variables_context)); + new(m_context) table_global_variables_context(hash_version, !scan); + return 0; +} + +int table_global_variables::rnd_next(void) +{ + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < m_sysvar_cache.size(); + m_pos.next()) + { + const System_variable *system_var= m_sysvar_cache.get(m_pos.m_index); + if (system_var != NULL) + { + make_row(system_var); + m_next_pos.set_after(&m_pos); + return 0; + } + } + return HA_ERR_END_OF_FILE; +} + +int table_global_variables::rnd_pos(const void *pos) +{ + /* If system variable hash changes, do nothing. */ // TODO: Issue warning + if (!m_context->versions_match()) + return HA_ERR_RECORD_DELETED; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < m_sysvar_cache.size()); + + const System_variable *system_var= m_sysvar_cache.get(m_pos.m_index); + if (system_var != NULL) + { + make_row(system_var); + return 0; + } + return HA_ERR_RECORD_DELETED; +} + +void table_global_variables +::make_row(const System_variable *system_var) +{ + m_row_exists= false; + if (system_var->is_null() || system_var->is_ignored()) + return; + m_row.m_variable_name.make_row(system_var->m_name, system_var->m_name_length); + m_row.m_variable_value.make_row(system_var); + m_row_exists= true; +} + +int table_global_variables +::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: /* VARIABLE_NAME */ + set_field_varchar_utf8(f, m_row.m_variable_name.m_str, m_row.m_variable_name.m_length); + break; + case 1: /* VARIABLE_VALUE */ + m_row.m_variable_value.set_field(f); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_global_variables.h b/storage/perfschema/table_global_variables.h new file mode 100644 index 00000000000..b9124e76f65 --- /dev/null +++ b/storage/perfschema/table_global_variables.h @@ -0,0 +1,117 @@ +/* Copyright (c) 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_GLOBAL_VARIABLES_H +#define TABLE_GLOBAL_VARIABLES_H + +/** + @file storage/perfschema/table_global_variables.h + Table GLOBAL_VARIABLES (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "pfs_variable.h" +#include "table_helper.h" +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + Store and retrieve table state information during queries that reinstantiate + the table object. +*/ +class table_global_variables_context : public PFS_table_context +{ +public: + table_global_variables_context(ulonglong hash_version, bool restore) : + PFS_table_context(hash_version, restore, THR_PFS_VG) {} +}; + +/** + A row of table + PERFORMANCE_SCHEMA.GLOBAL_VARIABLES. +*/ +struct row_global_variables +{ + /** Column VARIABLE_NAME. */ + PFS_variable_name_row m_variable_name; + /** Column VARIABLE_VALUE. */ + PFS_variable_value_row m_variable_value; +}; + +/** Table PERFORMANCE_SCHEMA.GLOBAL_VARIABLES. */ +class table_global_variables : public PFS_engine_table +{ + typedef PFS_simple_index pos_t; + +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + + 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_global_variables(); + +public: + ~table_global_variables() + {} + +protected: + void make_row(const System_variable *system_var); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current THD variables. */ + PFS_system_variable_cache m_sysvar_cache; + /** Current row. */ + row_global_variables m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + + /** Table context with system variable hash version. */ + table_global_variables_context *m_context; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_helper.cc b/storage/perfschema/table_helper.cc index d6bdd894483..749e15a7113 100644 --- a/storage/perfschema/table_helper.cc +++ b/storage/perfschema/table_helper.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,13 +26,16 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_program.h" +#include "field.h" +#include "pfs_variable.h" int PFS_host_row::make_row(PFS_host *pfs) { @@ -147,7 +150,6 @@ int PFS_digest_row::make_row(PFS_statements_digest_stat* pfs) else { m_digest_length= 0; - m_digest_text.length(0); } return 0; @@ -203,6 +205,107 @@ int PFS_object_row::make_row(PFS_table_share *pfs) return 0; } +int PFS_object_row::make_row(PFS_program *pfs) +{ + m_object_type= pfs->m_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_object_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_object_name, sizeof(m_object_name)); + + return 0; +} + +int PFS_object_row::make_row(const MDL_key *mdl) +{ + switch(mdl->mdl_namespace()) + { + case MDL_key::GLOBAL: + m_object_type= OBJECT_TYPE_GLOBAL; + m_schema_name_length= 0; + m_object_name_length= 0; + break; + case MDL_key::SCHEMA: + m_object_type= OBJECT_TYPE_SCHEMA; + m_schema_name_length= mdl->db_name_length(); + m_object_name_length= 0; + break; + case MDL_key::TABLE: + m_object_type= OBJECT_TYPE_TABLE; + m_schema_name_length= mdl->db_name_length(); + m_object_name_length= mdl->name_length(); + break; + case MDL_key::FUNCTION: + m_object_type= OBJECT_TYPE_FUNCTION; + m_schema_name_length= mdl->db_name_length(); + m_object_name_length= mdl->name_length(); + break; + case MDL_key::PROCEDURE: + m_object_type= OBJECT_TYPE_PROCEDURE; + m_schema_name_length= mdl->db_name_length(); + m_object_name_length= mdl->name_length(); + break; + case MDL_key::TRIGGER: + m_object_type= OBJECT_TYPE_TRIGGER; + m_schema_name_length= mdl->db_name_length(); + m_object_name_length= mdl->name_length(); + break; + case MDL_key::EVENT: + m_object_type= OBJECT_TYPE_EVENT; + m_schema_name_length= mdl->db_name_length(); + m_object_name_length= mdl->name_length(); + break; + case MDL_key::COMMIT: + m_object_type= OBJECT_TYPE_COMMIT; + m_schema_name_length= 0; + m_object_name_length= 0; + break; + case MDL_key::USER_LOCK: + m_object_type= OBJECT_TYPE_USER_LEVEL_LOCK; + m_schema_name_length= 0; + m_object_name_length= mdl->name_length(); + break; +#if 0 + case MDL_key::TABLESPACE: + m_object_type= OBJECT_TYPE_TABLESPACE; + m_schema_name_length= 0; + m_object_name_length= mdl->name_length(); + break; + case MDL_key::LOCKING_SERVICE: + m_object_type= OBJECT_TYPE_LOCKING_SERVICE; + m_schema_name_length= mdl->db_name_length(); + m_object_name_length= mdl->name_length(); + break; +#endif + case MDL_key::NAMESPACE_END: + default: + m_object_type= NO_OBJECT_TYPE; + m_schema_name_length= 0; + m_object_name_length= 0; + break; + } + + if (m_schema_name_length > sizeof(m_schema_name)) + return 1; + if (m_schema_name_length > 0) + memcpy(m_schema_name, mdl->db_name(), m_schema_name_length); + + if (m_object_name_length > sizeof(m_object_name)) + return 1; + if (m_object_name_length > 0) + memcpy(m_object_name, mdl->name(), m_object_name_length); + + return 0; +} + void PFS_object_row::set_field(uint index, Field *f) { switch(index) @@ -221,21 +324,65 @@ void PFS_object_row::set_field(uint index, Field *f) } } -int PFS_index_row::make_row(PFS_table_share *pfs, uint table_index) +void PFS_object_row::set_nullable_field(uint index, Field *f) +{ + switch(index) + { + case 0: /* OBJECT_TYPE */ + if (m_object_type != NO_OBJECT_TYPE) + set_field_object_type(f, m_object_type); + else + f->set_null(); + break; + case 1: /* 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 2: /* OBJECT_NAME */ + if (m_object_name_length > 0) + PFS_engine_table::set_field_varchar_utf8(f, m_object_name, m_object_name_length); + else + f->set_null(); + break; + default: + DBUG_ASSERT(false); + } +} + +int PFS_index_row::make_row(PFS_table_share *pfs, + PFS_table_share_index *pfs_index, + uint table_index) { if (m_object_row.make_row(pfs)) return 1; + if (pfs_index == NULL) + { + if (table_index < MAX_INDEXES) + { + m_index_name_length= sprintf(m_index_name, "(index %d)", table_index); + } + else + { + m_index_name_length= 0; + } + return 0; + } + if (table_index < MAX_INDEXES) { - PFS_table_key *key= &pfs->m_keys[table_index]; - m_index_name_length= key->m_name_length; + m_index_name_length= pfs_index->m_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)); + + memcpy(m_index_name, pfs_index->m_key.m_name, sizeof(m_index_name)); } else + { m_index_name_length= 0; + } return 0; } @@ -334,6 +481,37 @@ void PFS_statement_stat_row::set_field(uint index, Field *f) } } +void PFS_transaction_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: /* COUNT_READ_WRITE */ + case 6: /* SUM_TIMER_READ_WRITE */ + case 7: /* MIN_TIMER_READ_WRITE */ + case 8: /* AVG_TIMER_READ_WRITE */ + case 9: /* MAX_TIMER_READ_WRITE */ + m_read_write_row.set_field(index-5, f); + break; + case 10: /* COUNT_READ_ONLY */ + case 11: /* SUM_TIMER_READ_ONLY */ + case 12: /* MIN_TIMER_READ_ONLY */ + case 13: /* AVG_TIMER_READ_ONLY */ + case 14: /* MAX_TIMER_READ_ONLY */ + m_read_only_row.set_field(index-10, f); + break; + default: + DBUG_ASSERT(false); + break; + } +} + void PFS_connection_stat_row::set_field(uint index, Field *f) { switch (index) @@ -354,14 +532,324 @@ void set_field_object_type(Field *f, enum_object_type object_type) { switch (object_type) { + case OBJECT_TYPE_EVENT: + PFS_engine_table::set_field_varchar_utf8(f, "EVENT", 5); + break; + case OBJECT_TYPE_FUNCTION: + PFS_engine_table::set_field_varchar_utf8(f, "FUNCTION", 8); + break; + case OBJECT_TYPE_PROCEDURE: + PFS_engine_table::set_field_varchar_utf8(f, "PROCEDURE", 9); + break; 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; + case OBJECT_TYPE_TRIGGER: + PFS_engine_table::set_field_varchar_utf8(f, "TRIGGER", 7); + break; + case OBJECT_TYPE_GLOBAL: + PFS_engine_table::set_field_varchar_utf8(f, "GLOBAL", 6); + break; + case OBJECT_TYPE_SCHEMA: + PFS_engine_table::set_field_varchar_utf8(f, "SCHEMA", 6); + break; + case OBJECT_TYPE_COMMIT: + PFS_engine_table::set_field_varchar_utf8(f, "COMMIT", 6); + break; + case OBJECT_TYPE_USER_LEVEL_LOCK: + PFS_engine_table::set_field_varchar_utf8(f, "USER LEVEL LOCK", 15); + break; + case OBJECT_TYPE_TABLESPACE: + PFS_engine_table::set_field_varchar_utf8(f, "TABLESPACE", 10); + break; + case OBJECT_TYPE_LOCKING_SERVICE: + PFS_engine_table::set_field_varchar_utf8(f, "LOCKING SERVICE", 15); + break; + case NO_OBJECT_TYPE: default: DBUG_ASSERT(false); + PFS_engine_table::set_field_varchar_utf8(f, "", 0); + break; + } +} + +void set_field_lock_type(Field *f, PFS_TL_LOCK_TYPE lock_type) +{ + switch (lock_type) + { + case PFS_TL_READ: + PFS_engine_table::set_field_varchar_utf8(f, "READ", 4); + break; + case PFS_TL_READ_WITH_SHARED_LOCKS: + PFS_engine_table::set_field_varchar_utf8(f, "READ WITH SHARED LOCKS", 22); + break; + case PFS_TL_READ_HIGH_PRIORITY: + PFS_engine_table::set_field_varchar_utf8(f, "READ HIGH PRIORITY", 18); + break; + case PFS_TL_READ_NO_INSERT: + PFS_engine_table::set_field_varchar_utf8(f, "READ NO INSERT", 14); + break; + case PFS_TL_WRITE_ALLOW_WRITE: + PFS_engine_table::set_field_varchar_utf8(f, "WRITE ALLOW WRITE", 17); + break; + case PFS_TL_WRITE_CONCURRENT_INSERT: + PFS_engine_table::set_field_varchar_utf8(f, "WRITE CONCURRENT INSERT", 23); + break; + case PFS_TL_WRITE_LOW_PRIORITY: + PFS_engine_table::set_field_varchar_utf8(f, "WRITE LOW PRIORITY", 18); + break; + case PFS_TL_WRITE: + PFS_engine_table::set_field_varchar_utf8(f, "WRITE", 5); + break; + case PFS_TL_READ_EXTERNAL: + PFS_engine_table::set_field_varchar_utf8(f, "READ EXTERNAL", 13); + break; + case PFS_TL_WRITE_EXTERNAL: + PFS_engine_table::set_field_varchar_utf8(f, "WRITE EXTERNAL", 14); + break; + case PFS_TL_NONE: + f->set_null(); + break; + default: + DBUG_ASSERT(false); + } +} + +void set_field_mdl_type(Field *f, opaque_mdl_type mdl_type) +{ + enum_mdl_type e= (enum_mdl_type) mdl_type; + switch (e) + { + case MDL_INTENTION_EXCLUSIVE: + PFS_engine_table::set_field_varchar_utf8(f, "INTENTION_EXCLUSIVE", 19); + break; + case MDL_SHARED: + PFS_engine_table::set_field_varchar_utf8(f, "SHARED", 6); + break; + case MDL_SHARED_HIGH_PRIO: + PFS_engine_table::set_field_varchar_utf8(f, "SHARED_HIGH_PRIO", 16); + break; + case MDL_SHARED_READ: + PFS_engine_table::set_field_varchar_utf8(f, "SHARED_READ", 11); + break; + case MDL_SHARED_WRITE: + PFS_engine_table::set_field_varchar_utf8(f, "SHARED_WRITE", 12); + break; + case MDL_SHARED_UPGRADABLE: + PFS_engine_table::set_field_varchar_utf8(f, "SHARED_UPGRADABLE", 17); + break; + case MDL_SHARED_NO_WRITE: + PFS_engine_table::set_field_varchar_utf8(f, "SHARED_NO_WRITE", 15); + break; + case MDL_SHARED_NO_READ_WRITE: + PFS_engine_table::set_field_varchar_utf8(f, "SHARED_NO_READ_WRITE", 20); + break; + case MDL_EXCLUSIVE: + PFS_engine_table::set_field_varchar_utf8(f, "EXCLUSIVE", 9); + break; + default: + DBUG_ASSERT(false); + } +} + +void set_field_mdl_duration(Field *f, opaque_mdl_duration mdl_duration) +{ + enum_mdl_duration e= (enum_mdl_duration) mdl_duration; + switch (e) + { + case MDL_STATEMENT: + PFS_engine_table::set_field_varchar_utf8(f, "STATEMENT", 9); + break; + case MDL_TRANSACTION: + PFS_engine_table::set_field_varchar_utf8(f, "TRANSACTION", 11); + break; + case MDL_EXPLICIT: + PFS_engine_table::set_field_varchar_utf8(f, "EXPLICIT", 8); + break; + case MDL_DURATION_END: + default: + DBUG_ASSERT(false); + } +} + +void set_field_mdl_status(Field *f, opaque_mdl_status mdl_status) +{ + enum_psi_status e= static_cast<enum_psi_status>(mdl_status); + switch (e) + { + case PENDING: + PFS_engine_table::set_field_varchar_utf8(f, "PENDING", 7); + break; + case GRANTED: + PFS_engine_table::set_field_varchar_utf8(f, "GRANTED", 7); + break; + case PRE_ACQUIRE_NOTIFY: + PFS_engine_table::set_field_varchar_utf8(f, "PRE_ACQUIRE_NOTIFY", 18); + break; + case POST_RELEASE_NOTIFY: + PFS_engine_table::set_field_varchar_utf8(f, "POST_RELEASE_NOTIFY", 19); + break; + default: + DBUG_ASSERT(false); + } +} + +void PFS_memory_stat_row::set_field(uint index, Field *f) +{ + ssize_t val; + + switch (index) + { + case 0: /* COUNT_ALLOC */ + PFS_engine_table::set_field_ulonglong(f, m_stat.m_alloc_count); + break; + case 1: /* COUNT_FREE */ + PFS_engine_table::set_field_ulonglong(f, m_stat.m_free_count); + break; + case 2: /* SUM_NUMBER_OF_BYTES_ALLOC */ + PFS_engine_table::set_field_ulonglong(f, m_stat.m_alloc_size); + break; + case 3: /* SUM_NUMBER_OF_BYTES_FREE */ + PFS_engine_table::set_field_ulonglong(f, m_stat.m_free_size); + break; + case 4: /* LOW_COUNT_USED */ + val= m_stat.m_alloc_count - m_stat.m_free_count - m_stat.m_free_count_capacity; + PFS_engine_table::set_field_longlong(f, val); + break; + case 5: /* CURRENT_COUNT_USED */ + val= m_stat.m_alloc_count - m_stat.m_free_count; + PFS_engine_table::set_field_longlong(f, val); + break; + case 6: /* HIGH_COUNT_USED */ + val= m_stat.m_alloc_count - m_stat.m_free_count + m_stat.m_alloc_count_capacity; + PFS_engine_table::set_field_longlong(f, val); + break; + case 7: /* LOW_NUMBER_OF_BYTES_USED */ + val= m_stat.m_alloc_size - m_stat.m_free_size - m_stat.m_free_size_capacity; + PFS_engine_table::set_field_longlong(f, val); + break; + case 8: /* CURRENT_NUMBER_OF_BYTES_USED */ + val= m_stat.m_alloc_size - m_stat.m_free_size; + PFS_engine_table::set_field_longlong(f, val); + break; + case 9: /* HIGH_NUMBER_OF_BYTES_USED */ + val= m_stat.m_alloc_size - m_stat.m_free_size + m_stat.m_alloc_size_capacity; + PFS_engine_table::set_field_longlong(f, val); + break; + default: + DBUG_ASSERT(false); + break; + } +} + +void set_field_isolation_level(Field *f, enum_isolation_level iso_level) +{ + switch (iso_level) + { + case TRANS_LEVEL_READ_UNCOMMITTED: + PFS_engine_table::set_field_varchar_utf8(f, "READ UNCOMMITTED", 16); + break; + case TRANS_LEVEL_READ_COMMITTED: + PFS_engine_table::set_field_varchar_utf8(f, "READ COMMITTED", 14); + break; + case TRANS_LEVEL_REPEATABLE_READ: + PFS_engine_table::set_field_varchar_utf8(f, "REPEATABLE READ", 15); + break; + case TRANS_LEVEL_SERIALIZABLE: + PFS_engine_table::set_field_varchar_utf8(f, "SERIALIZABLE", 12); + break; + default: + DBUG_ASSERT(false); + } +} + +void set_field_xa_state(Field *f, enum_xa_transaction_state xa_state) +{ + switch (xa_state) + { + case TRANS_STATE_XA_NOTR: + PFS_engine_table::set_field_varchar_utf8(f, "NOTR", 4); + break; + case TRANS_STATE_XA_ACTIVE: + PFS_engine_table::set_field_varchar_utf8(f, "ACTIVE", 6); + break; + case TRANS_STATE_XA_IDLE: + PFS_engine_table::set_field_varchar_utf8(f, "IDLE", 4); + break; + case TRANS_STATE_XA_PREPARED: + PFS_engine_table::set_field_varchar_utf8(f, "PREPARED", 8); + break; + case TRANS_STATE_XA_ROLLBACK_ONLY: + PFS_engine_table::set_field_varchar_utf8(f, "ROLLBACK ONLY", 13); + break; + case TRANS_STATE_XA_COMMITTED: + PFS_engine_table::set_field_varchar_utf8(f, "COMMITTED", 9); + break; + default: + DBUG_ASSERT(false); + } +} + +void PFS_variable_name_row::make_row(const char* str, size_t length) +{ + DBUG_ASSERT(length <= sizeof(m_str)); + DBUG_ASSERT(length <= NAME_CHAR_LEN); + + m_length= MY_MIN(length, NAME_CHAR_LEN); /* enforce max name length */ + if (m_length > 0) + memcpy(m_str, str, length); + m_str[m_length]= '\0'; +} + +void PFS_variable_value_row::make_row(const Status_variable *var) +{ + make_row(var->m_charset, var->m_value_str, var->m_value_length); +} + +void PFS_variable_value_row::make_row(const System_variable *var) +{ + make_row(var->m_charset, var->m_value_str, var->m_value_length); +} + +void PFS_variable_value_row::make_row(const CHARSET_INFO *cs, const char* str, size_t length) +{ + DBUG_ASSERT(cs != NULL); + DBUG_ASSERT(length <= sizeof(m_str)); + if (length > 0) + { + memcpy(m_str, str, length); + } + m_length= length; + m_charset= cs; +} + +void PFS_variable_value_row::set_field(Field *f) +{ + PFS_engine_table::set_field_varchar(f, m_charset, m_str, m_length); +} + +void PFS_user_variable_value_row::clear() +{ + my_free(m_value); + m_value= NULL; + m_value_length= 0; +} + +void PFS_user_variable_value_row::make_row(const char* val, size_t length) +{ + if (length > 0) + { + m_value= (char*) my_malloc(PSI_NOT_INSTRUMENTED, length, MYF(0)); + m_value_length= length; + memcpy(m_value, val, length); + } + else + { + m_value= NULL; + m_value_length= 0; } } diff --git a/storage/perfschema/table_helper.h b/storage/perfschema/table_helper.h index 62f94826754..bf431802900 100644 --- a/storage/perfschema/table_helper.h +++ b/storage/perfschema/table_helper.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2008, 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, version 2.0, @@ -31,7 +31,7 @@ #include "pfs_digest.h" /* - Write MD5 hash value in a string to be used + Write MD5 hash value in a string to be used as DIGEST for the statement. */ #define MD5_HASH_TO_STRING(_hash, _str) \ @@ -47,6 +47,10 @@ struct PFS_host; struct PFS_user; struct PFS_account; +struct PFS_object_name; +struct PFS_program; +class System_variable; +class Status_variable; /** @file storage/perfschema/table_helper.h @@ -69,7 +73,8 @@ struct PFS_instrument_view_constants static const uint VIEW_TABLE= 5; static const uint VIEW_SOCKET= 6; static const uint VIEW_IDLE= 7; - static const uint LAST_VIEW= 7; + static const uint VIEW_METADATA= 8; + static const uint LAST_VIEW= 8; }; /** Namespace, internal views used within object summaries. */ @@ -77,12 +82,8 @@ 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; + static const uint VIEW_PROGRAM= 2; + static const uint LAST_VIEW= 2; }; /** Row fragment for column HOST. */ @@ -189,8 +190,11 @@ struct PFS_object_row /** Build a row from a memory buffer. */ int make_row(PFS_table_share *pfs); + int make_row(PFS_program *pfs); + int make_row(const MDL_key *pfs); /** Set a table field from the row. */ void set_field(uint index, Field *f); + void set_nullable_field(uint index, Field *f); }; /** Row fragment for columns OBJECT_TYPE, SCHEMA_NAME, OBJECT_NAME, INDEX_NAME. */ @@ -203,7 +207,8 @@ struct PFS_index_row uint m_index_name_length; /** Build a row from a memory buffer. */ - int make_row(PFS_table_share *pfs, uint table_index); + int make_row(PFS_table_share *pfs, PFS_table_share_index *pfs_index, + uint table_index); /** Set a table field from the row. */ void set_field(uint index, Field *f); }; @@ -222,6 +227,15 @@ struct PFS_stat_row /** Column MAX_TIMER_WAIT. */ ulonglong m_max; + inline void reset() + { + m_count= 0; + m_sum= 0; + m_min= 0; + m_avg= 0; + m_max= 0; + } + /** Build a row with timer fields from a memory buffer. */ inline void set(time_normalizer *normalizer, const PFS_single_stat *stat) { @@ -335,7 +349,6 @@ struct PFS_table_lock_stat_row 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; @@ -361,14 +374,12 @@ struct PFS_table_lock_stat_row 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]); @@ -427,33 +438,106 @@ struct PFS_statement_stat_row /** Build a row from a memory buffer. */ inline void set(time_normalizer *normalizer, const PFS_statement_stat *stat) { + if (stat->m_timer1_stat.m_count != 0) + { + 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; + } + else + { + m_timer1_row.reset(); + + m_error_count= 0; + m_warning_count= 0; + m_lock_time= 0; + m_rows_affected= 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; + } + } + + /** Set a table field from the row. */ + void set_field(uint index, Field *f); +}; + +/** Row fragment for stored program statistics. */ +struct PFS_sp_stat_row +{ + PFS_stat_row m_timer1_row; + + /** Build a row from a memory buffer. */ + inline void set(time_normalizer *normalizer, const PFS_sp_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. */ + inline void set_field(uint index, Field *f) + { + m_timer1_row.set_field(index, f); + } +}; + +/** Row fragment for transaction statistics columns. */ +struct PFS_transaction_stat_row +{ + PFS_stat_row m_timer1_row; + PFS_stat_row m_read_write_row; + PFS_stat_row m_read_only_row; + ulonglong m_savepoint_count; + ulonglong m_rollback_to_savepoint_count; + ulonglong m_release_savepoint_count; + + /** Build a row from a memory buffer. */ + inline void set(time_normalizer *normalizer, const PFS_transaction_stat *stat) + { + /* Combine read write/read only stats */ + PFS_single_stat all; + all.aggregate(&stat->m_read_only_stat); + all.aggregate(&stat->m_read_write_stat); + + m_timer1_row.set(normalizer, &all); + m_read_write_row.set(normalizer, &stat->m_read_write_stat); + m_read_only_row.set(normalizer, &stat->m_read_only_stat); } /** Set a table field from the row. */ void set_field(uint index, Field *f); }; +/** Row fragment for connection statistics. */ struct PFS_connection_stat_row { ulonglong m_current_connections; @@ -470,6 +554,12 @@ struct PFS_connection_stat_row }; void set_field_object_type(Field *f, enum_object_type object_type); +void set_field_lock_type(Field *f, PFS_TL_LOCK_TYPE lock_type); +void set_field_mdl_type(Field *f, opaque_mdl_type mdl_type); +void set_field_mdl_duration(Field *f, opaque_mdl_duration mdl_duration); +void set_field_mdl_status(Field *f, opaque_mdl_status mdl_status); +void set_field_isolation_level(Field *f, enum_isolation_level iso_level); +void set_field_xa_state(Field *f, enum_xa_transaction_state xa_state); /** Row fragment for socket io statistics columns. */ struct PFS_socket_io_stat_row @@ -478,7 +568,7 @@ struct PFS_socket_io_stat_row 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; @@ -486,7 +576,7 @@ struct PFS_socket_io_stat_row 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); @@ -503,7 +593,7 @@ struct PFS_file_io_stat_row 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; @@ -511,7 +601,7 @@ struct PFS_file_io_stat_row 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); @@ -521,6 +611,88 @@ struct PFS_file_io_stat_row } }; +/** Row fragment for memory statistics columns. */ +struct PFS_memory_stat_row +{ + PFS_memory_stat m_stat; + + /** Build a row from a memory buffer. */ + inline void set(const PFS_memory_stat *stat) + { + m_stat= *stat; + } + + /** Set a table field from the row. */ + void set_field(uint index, Field *f); +}; + +struct PFS_variable_name_row +{ +public: + PFS_variable_name_row() + { + m_str[0]= '\0'; + m_length= 0; + } + + void make_row(const char* str, size_t length); + + char m_str[NAME_CHAR_LEN+1]; + uint m_length; +}; + +struct PFS_variable_value_row +{ +public: + /** Set the row from a status variable. */ + void make_row(const Status_variable *var); + + /** Set the row from a system variable. */ + void make_row(const System_variable *var); + + /** Set a table field from the row. */ + void set_field(Field *f); + +private: + void make_row(const CHARSET_INFO *cs, const char* str, size_t length); + + char m_str[1024]; + uint m_length; + const CHARSET_INFO *m_charset; +}; + +struct PFS_user_variable_value_row +{ +public: + PFS_user_variable_value_row() + : m_value(NULL), m_value_length(0) + {} + + PFS_user_variable_value_row(const PFS_user_variable_value_row& rhs) + { + make_row(rhs.m_value, rhs.m_value_length); + } + + ~PFS_user_variable_value_row() + { + clear(); + } + + void make_row(const char* val, size_t length); + + const char *get_value() const + { return m_value; } + + size_t get_value_length() const + { return m_value_length; } + + void clear(); + +private: + char *m_value; + size_t m_value_length; +}; + /** @} */ #endif diff --git a/storage/perfschema/table_host_cache.cc b/storage/perfschema/table_host_cache.cc index 501894df9b1..e482ead215c 100644 --- a/storage/perfschema/table_host_cache.cc +++ b/storage/perfschema/table_host_cache.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -26,9 +26,11 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "table_host_cache.h" #include "hostname.h" +#include "field.h" +#include "sql_class.h" THR_LOCK table_host_cache::m_table_lock; @@ -37,11 +39,10 @@ table_host_cache::m_share= { { C_STRING_WITH_LEN("host_cache") }, &pfs_truncatable_acl, - &table_host_cache::create, + table_host_cache::create, NULL, /* write_row */ table_host_cache::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_host_cache::get_row_count, sizeof(PFS_simple_index), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE host_cache(" @@ -73,7 +74,8 @@ table_host_cache::m_share= "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)") } + "LAST_ERROR_SEEN TIMESTAMP(0) null default 0)") }, + false /* perpetual */ }; PFS_engine_table* table_host_cache::create(void) @@ -100,6 +102,16 @@ table_host_cache::delete_all_rows(void) return 0; } +ha_rows +table_host_cache::get_row_count(void) +{ + ha_rows count; + hostname_cache_lock(); + count= hostname_cache_size(); + hostname_cache_unlock(); + return count; +} + table_host_cache::table_host_cache() : PFS_engine_table(&m_share, &m_pos), m_all_rows(NULL), m_row_count(0), diff --git a/storage/perfschema/table_host_cache.h b/storage/perfschema/table_host_cache.h index 8add0b5049c..57cd0fa02ad 100644 --- a/storage/perfschema/table_host_cache.h +++ b/storage/perfschema/table_host_cache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -111,6 +111,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_hosts.cc b/storage/perfschema/table_hosts.cc index 8bc5310817c..8d8b6201ec8 100644 --- a/storage/perfschema/table_hosts.cc +++ b/storage/perfschema/table_hosts.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -21,13 +21,16 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_memory.h" +#include "pfs_status.h" +#include "field.h" THR_LOCK table_hosts::m_table_lock; @@ -36,17 +39,17 @@ table_hosts::m_share= { { C_STRING_WITH_LEN("hosts") }, &pfs_truncatable_acl, - &table_hosts::create, + table_hosts::create, NULL, /* write_row */ table_hosts::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + cursor_by_host::get_row_count, 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)") } + "TOTAL_CONNECTIONS bigint not null)") }, + false /* perpetual */ }; PFS_engine_table* table_hosts::create() @@ -66,6 +69,15 @@ table_hosts::delete_all_rows(void) reset_events_statements_by_thread(); reset_events_statements_by_account(); reset_events_statements_by_host(); + reset_events_transactions_by_thread(); + reset_events_transactions_by_account(); + reset_events_transactions_by_host(); + reset_memory_by_thread(); + reset_memory_by_account(); + reset_memory_by_host(); + reset_status_by_thread(); + reset_status_by_account(); + reset_status_by_host(); purge_all_account(); purge_all_host(); return 0; @@ -78,7 +90,7 @@ table_hosts::table_hosts() void table_hosts::make_row(PFS_host *pfs) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; pfs->m_lock.begin_optimistic_lock(&lock); @@ -87,7 +99,11 @@ void table_hosts::make_row(PFS_host *pfs) return; PFS_connection_stat_visitor visitor; - PFS_connection_iterator::visit_host(pfs, true, true, & visitor); + PFS_connection_iterator::visit_host(pfs, + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); if (! pfs->m_lock.end_optimistic_lock(& lock)) return; diff --git a/storage/perfschema/table_hosts.h b/storage/perfschema/table_hosts.h index 422b6449b25..61c04d12179 100644 --- a/storage/perfschema/table_hosts.h +++ b/storage/perfschema/table_hosts.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, diff --git a/storage/perfschema/table_md_locks.cc b/storage/perfschema/table_md_locks.cc new file mode 100644 index 00000000000..1f771e105d6 --- /dev/null +++ b/storage/perfschema/table_md_locks.cc @@ -0,0 +1,207 @@ +/* Copyright (c) 2012, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_md_locks.cc + Table METADATA_LOCKS (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_md_locks.h" +#include "pfs_global.h" +#include "pfs_buffer_container.h" +#include "field.h" + +THR_LOCK table_metadata_locks::m_table_lock; + +PFS_engine_table_share +table_metadata_locks::m_share= +{ + { C_STRING_WITH_LEN("metadata_locks") }, + &pfs_readonly_acl, + table_metadata_locks::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_metadata_locks::get_row_count, + sizeof(PFS_simple_index), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE metadata_locks(" + "OBJECT_TYPE VARCHAR(64) not null," + "OBJECT_SCHEMA VARCHAR(64)," + "OBJECT_NAME VARCHAR(64)," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," + "LOCK_TYPE VARCHAR(32) not null," + "LOCK_DURATION VARCHAR(32) not null," + "LOCK_STATUS VARCHAR(32) not null," + "SOURCE VARCHAR(64)," + "OWNER_THREAD_ID BIGINT unsigned," + "OWNER_EVENT_ID BIGINT unsigned)")}, + false /* perpetual */ +}; + +PFS_engine_table* table_metadata_locks::create(void) +{ + return new table_metadata_locks(); +} + +ha_rows +table_metadata_locks::get_row_count(void) +{ + return global_mdl_container.get_row_count(); +} + +table_metadata_locks::table_metadata_locks() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_metadata_locks::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_metadata_locks::rnd_next(void) +{ + PFS_metadata_lock *pfs; + + m_pos.set_at(&m_next_pos); + PFS_mdl_iterator it= global_mdl_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int table_metadata_locks::rnd_pos(const void *pos) +{ + PFS_metadata_lock *pfs; + + set_position(pos); + + pfs= global_mdl_container.get(m_pos.m_index); + if (pfs != NULL) + { + make_row(pfs); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_metadata_locks::make_row(PFS_metadata_lock *pfs) +{ + pfs_optimistic_state lock; + + m_row_exists= false; + + /* Protect this reader against a metadata lock destroy */ + pfs->m_lock.begin_optimistic_lock(&lock); + + m_row.m_identity= pfs->m_identity; + m_row.m_mdl_type= pfs->m_mdl_type; + m_row.m_mdl_duration= pfs->m_mdl_duration; + m_row.m_mdl_status= pfs->m_mdl_status; + + /* Disable source file and line to avoid stale __FILE__ pointers. */ + m_row.m_source_length= 0; + + m_row.m_owner_thread_id= static_cast<ulong>(pfs->m_owner_thread_id); + m_row.m_owner_event_id= static_cast<ulong>(pfs->m_owner_event_id); + + if (m_row.m_object.make_row(& pfs->m_mdl_key)) + return; + + if (pfs->m_lock.end_optimistic_lock(&lock)) + m_row_exists= true; +} + +int table_metadata_locks::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: /* OBJECT_SCHEMA */ + case 2: /* OBJECT_NAME */ + m_row.m_object.set_nullable_field(f->field_index, f); + break; + case 3: /* OBJECT_INSTANCE */ + set_field_ulonglong(f, (intptr) m_row.m_identity); + break; + case 4: /* LOCK_TYPE */ + set_field_mdl_type(f, m_row.m_mdl_type); + break; + case 5: /* LOCK_DURATION */ + set_field_mdl_duration(f, m_row.m_mdl_duration); + break; + case 6: /* LOCK_STATUS */ + set_field_mdl_status(f, m_row.m_mdl_status); + break; + case 7: /* SOURCE */ + set_field_varchar_utf8(f, m_row.m_source, m_row.m_source_length); + break; + case 8: /* OWNER_THREAD_ID */ + if (m_row.m_owner_thread_id != 0) + set_field_ulonglong(f, m_row.m_owner_thread_id); + else + f->set_null(); + break; + case 9: /* OWNER_EVENT_ID */ + if (m_row.m_owner_event_id != 0) + set_field_ulonglong(f, m_row.m_owner_event_id); + else + f->set_null(); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_md_locks.h b/storage/perfschema/table_md_locks.h new file mode 100644 index 00000000000..40b6d2f6efb --- /dev/null +++ b/storage/perfschema/table_md_locks.h @@ -0,0 +1,106 @@ +/* Copyright (c) 2012, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_METADATA_LOCK_H +#define TABLE_METADATA_LOCK_H + +/** + @file storage/perfschema/table_md_locks.h + Table METADATA_LOCKS (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "table_helper.h" + +struct PFS_metadata_lock; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of table PERFORMANCE_SCHEMA.MUTEX_INSTANCES. */ +struct row_metadata_lock +{ + /** Column OBJECT_INSTANCE_BEGIN. */ + const void *m_identity; + opaque_mdl_type m_mdl_type; + opaque_mdl_duration m_mdl_duration; + opaque_mdl_status m_mdl_status; + /** Column SOURCE. */ + char m_source[COL_SOURCE_SIZE]; + /** Length in bytes of @c m_source. */ + uint m_source_length; + /** Column OWNER_THREAD_ID. */ + ulong m_owner_thread_id; + /** Column OWNER_EVENT_ID. */ + ulong m_owner_event_id; + /** Columns OBJECT_TYPE, OBJECT_SCHEMA, OBJECT_NAME. */ + PFS_object_row m_object; +}; + +/** Table PERFORMANCE_SCHEMA.METADATA_LOCKS. */ +class table_metadata_locks : public PFS_engine_table +{ +public: + /** Table share. */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + + 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_metadata_locks(); + +public: + ~table_metadata_locks() + {} + +private: + void make_row(PFS_metadata_lock *pfs); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_metadata_lock 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_mems_by_account_by_event_name.cc b/storage/perfschema/table_mems_by_account_by_event_name.cc new file mode 100644 index 00000000000..5c83c225d11 --- /dev/null +++ b/storage/perfschema/table_mems_by_account_by_event_name.cc @@ -0,0 +1,221 @@ +/* Copyright (c) 2011, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_mems_by_account_by_event_name.cc + Table MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_mems_by_account_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" +#include "pfs_memory.h" +#include "pfs_buffer_container.h" +#include "field.h" + +THR_LOCK table_mems_by_account_by_event_name::m_table_lock; + +PFS_engine_table_share +table_mems_by_account_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("memory_summary_by_account_by_event_name") }, + &pfs_readonly_acl, + table_mems_by_account_by_event_name::create, + NULL, /* write_row */ + table_mems_by_account_by_event_name::delete_all_rows, + table_mems_by_account_by_event_name::get_row_count, + sizeof(pos_mems_by_account_by_event_name), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE memory_summary_by_account_by_event_name(" + "USER CHAR(32) collate utf8_bin default null," + "HOST CHAR(60) collate utf8_bin default null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_ALLOC BIGINT unsigned not null," + "COUNT_FREE BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_ALLOC BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_FREE BIGINT unsigned not null," + "LOW_COUNT_USED BIGINT not null," + "CURRENT_COUNT_USED BIGINT not null," + "HIGH_COUNT_USED BIGINT not null," + "LOW_NUMBER_OF_BYTES_USED BIGINT not null," + "CURRENT_NUMBER_OF_BYTES_USED BIGINT not null," + "HIGH_NUMBER_OF_BYTES_USED BIGINT not null)")}, + false /* perpetual */ +}; + +PFS_engine_table* table_mems_by_account_by_event_name::create(void) +{ + return new table_mems_by_account_by_event_name(); +} + +int +table_mems_by_account_by_event_name::delete_all_rows(void) +{ + reset_memory_by_thread(); + reset_memory_by_account(); + return 0; +} + +ha_rows +table_mems_by_account_by_event_name::get_row_count(void) +{ + return global_account_container.get_row_count() * memory_class_max; +} + +table_mems_by_account_by_event_name::table_mems_by_account_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_mems_by_account_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_mems_by_account_by_event_name::rnd_next(void) +{ + PFS_account *account; + PFS_memory_class *memory_class; + bool has_more_account= true; + + for (m_pos.set_at(&m_next_pos); + has_more_account; + m_pos.next_account()) + { + account= global_account_container.get(m_pos.m_index_1, & has_more_account); + if (account != NULL) + { + do + { + memory_class= find_memory_class(m_pos.m_index_2); + if (memory_class != NULL) + { + if (! memory_class->is_global()) + { + make_row(account, memory_class); + m_next_pos.set_after(&m_pos); + return 0; + } + + m_pos.next_class(); + } + } + while (memory_class != NULL); + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_mems_by_account_by_event_name::rnd_pos(const void *pos) +{ + PFS_account *account; + PFS_memory_class *memory_class; + + set_position(pos); + + account= global_account_container.get(m_pos.m_index_1); + if (account != NULL) + { + memory_class= find_memory_class(m_pos.m_index_2); + if (memory_class != NULL) + { + if (! memory_class->is_global()) + { + make_row(account, memory_class); + return 0; + } + } + } + + return HA_ERR_RECORD_DELETED; +} + +void table_mems_by_account_by_event_name +::make_row(PFS_account *account, PFS_memory_class *klass) +{ + pfs_optimistic_state 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_memory_visitor visitor(klass); + PFS_connection_iterator::visit_account(account, + true, /* threads */ + false, /* THDs */ + & visitor); + + if (! account->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(& visitor.m_stat); +} + +int table_mems_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, ... HIGH_NUMBER_OF_BYTES_USED */ + m_row.m_stat.set_field(f->field_index - 3, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_mems_by_account_by_event_name.h b/storage/perfschema/table_mems_by_account_by_event_name.h new file mode 100644 index 00000000000..b6151246f34 --- /dev/null +++ b/storage/perfschema/table_mems_by_account_by_event_name.h @@ -0,0 +1,129 @@ +/* Copyright (c) 2011, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME_H +#define TABLE_MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_mems_by_account_by_event_name.h + Table MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_account.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of PERFORMANCE_SCHEMA.MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. */ +struct row_mems_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_ALLOC, ... */ + PFS_memory_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. + Index 1 on account (0 based) + Index 2 on memory class (1 based) +*/ +struct pos_mems_by_account_by_event_name +: public PFS_double_index +{ + pos_mems_by_account_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline void next_account(void) + { + m_index_1++; + m_index_2= 1; + } + + inline void next_class(void) + { + m_index_2++; + } +}; + +/** Table PERFORMANCE_SCHEMA.MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME. */ +class table_mems_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(); + static ha_rows get_row_count(); + + 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_mems_by_account_by_event_name(); + +public: + ~table_mems_by_account_by_event_name() + {} + +private: + void make_row(PFS_account *account, PFS_memory_class *klass); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_mems_by_account_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_mems_by_account_by_event_name m_pos; + /** Next position. */ + pos_mems_by_account_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_mems_by_host_by_event_name.cc b/storage/perfschema/table_mems_by_host_by_event_name.cc new file mode 100644 index 00000000000..0921dfa49c8 --- /dev/null +++ b/storage/perfschema/table_mems_by_host_by_event_name.cc @@ -0,0 +1,221 @@ +/* Copyright (c) 2011, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_mems_by_host_by_event_name.cc + Table MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_mems_by_host_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" +#include "pfs_memory.h" +#include "pfs_buffer_container.h" +#include "field.h" + +THR_LOCK table_mems_by_host_by_event_name::m_table_lock; + +PFS_engine_table_share +table_mems_by_host_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("memory_summary_by_host_by_event_name") }, + &pfs_readonly_acl, + table_mems_by_host_by_event_name::create, + NULL, /* write_row */ + table_mems_by_host_by_event_name::delete_all_rows, + table_mems_by_host_by_event_name::get_row_count, + sizeof(PFS_simple_index), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE memory_summary_by_host_by_event_name(" + "HOST CHAR(60) collate utf8_bin default null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_ALLOC BIGINT unsigned not null," + "COUNT_FREE BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_ALLOC BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_FREE BIGINT unsigned not null," + "LOW_COUNT_USED BIGINT not null," + "CURRENT_COUNT_USED BIGINT not null," + "HIGH_COUNT_USED BIGINT not null," + "LOW_NUMBER_OF_BYTES_USED BIGINT not null," + "CURRENT_NUMBER_OF_BYTES_USED BIGINT not null," + "HIGH_NUMBER_OF_BYTES_USED BIGINT not null)")}, + false /* perpetual */ +}; + +PFS_engine_table* table_mems_by_host_by_event_name::create(void) +{ + return new table_mems_by_host_by_event_name(); +} + +int +table_mems_by_host_by_event_name::delete_all_rows(void) +{ + reset_memory_by_thread(); + reset_memory_by_account(); + reset_memory_by_host(); + return 0; +} + +ha_rows +table_mems_by_host_by_event_name::get_row_count(void) +{ + return global_host_container.get_row_count() * memory_class_max; +} + +table_mems_by_host_by_event_name::table_mems_by_host_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_mems_by_host_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_mems_by_host_by_event_name::rnd_next(void) +{ + PFS_host *host; + PFS_memory_class *memory_class; + bool has_more_host= true; + + for (m_pos.set_at(&m_next_pos); + has_more_host; + m_pos.next_host()) + { + host= global_host_container.get(m_pos.m_index_1, & has_more_host); + if (host != NULL) + { + do + { + memory_class= find_memory_class(m_pos.m_index_2); + if (memory_class != NULL) + { + if (! memory_class->is_global()) + { + make_row(host, memory_class); + m_next_pos.set_after(&m_pos); + return 0; + } + + m_pos.next_class(); + } + } + while (memory_class != NULL); + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_mems_by_host_by_event_name::rnd_pos(const void *pos) +{ + PFS_host *host; + PFS_memory_class *memory_class; + + set_position(pos); + + host= global_host_container.get(m_pos.m_index_1); + if (host != NULL) + { + memory_class= find_memory_class(m_pos.m_index_2); + if (memory_class != NULL) + { + if (! memory_class->is_global()) + { + make_row(host, memory_class); + return 0; + } + } + } + + return HA_ERR_RECORD_DELETED; +} + +void table_mems_by_host_by_event_name +::make_row(PFS_host *host, PFS_memory_class *klass) +{ + pfs_optimistic_state 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_memory_visitor visitor(klass); + PFS_connection_iterator::visit_host(host, + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); + + if (! host->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(& visitor.m_stat); +} + +int table_mems_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, ... HIGH_NUMBER_OF_BYTES_USED */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_mems_by_host_by_event_name.h b/storage/perfschema/table_mems_by_host_by_event_name.h new file mode 100644 index 00000000000..1a55db2c9b3 --- /dev/null +++ b/storage/perfschema/table_mems_by_host_by_event_name.h @@ -0,0 +1,129 @@ +/* Copyright (c) 2011, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME_H +#define TABLE_MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_mems_by_host_by_event_name.h + Table MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_host.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of PERFORMANCE_SCHEMA.MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME. */ +struct row_mems_by_host_by_event_name +{ + /** Column HOST */ + PFS_host_row m_host; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_ALLOC, ... */ + PFS_memory_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME. + Index 1 on host (0 based) + Index 2 on memory class (1 based) +*/ +struct pos_mems_by_host_by_event_name +: public PFS_double_index +{ + pos_mems_by_host_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline void next_host(void) + { + m_index_1++; + m_index_2= 1; + } + + inline void next_class(void) + { + m_index_2++; + } +}; + +/** Table PERFORMANCE_SCHEMA.MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME. */ +class table_mems_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(); + static ha_rows get_row_count(); + + 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_mems_by_host_by_event_name(); + +public: + ~table_mems_by_host_by_event_name() + {} + +private: + void make_row(PFS_host *host, PFS_memory_class *klass); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_mems_by_host_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_mems_by_host_by_event_name m_pos; + /** Next position. */ + pos_mems_by_host_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_mems_by_thread_by_event_name.cc b/storage/perfschema/table_mems_by_thread_by_event_name.cc new file mode 100644 index 00000000000..9e36cb76dd7 --- /dev/null +++ b/storage/perfschema/table_mems_by_thread_by_event_name.cc @@ -0,0 +1,214 @@ +/* Copyright (c) 2011, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_mems_by_thread_by_event_name.cc + Table MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_mems_by_thread_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" +#include "pfs_memory.h" +#include "pfs_buffer_container.h" +#include "field.h" + +THR_LOCK table_mems_by_thread_by_event_name::m_table_lock; + +PFS_engine_table_share +table_mems_by_thread_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("memory_summary_by_thread_by_event_name") }, + &pfs_readonly_acl, + table_mems_by_thread_by_event_name::create, + NULL, /* write_row */ + table_mems_by_thread_by_event_name::delete_all_rows, + table_mems_by_thread_by_event_name::get_row_count, + sizeof(PFS_simple_index), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE memory_summary_by_thread_by_event_name(" + "THREAD_ID BIGINT unsigned not null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_ALLOC BIGINT unsigned not null," + "COUNT_FREE BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_ALLOC BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_FREE BIGINT unsigned not null," + "LOW_COUNT_USED BIGINT not null," + "CURRENT_COUNT_USED BIGINT not null," + "HIGH_COUNT_USED BIGINT not null," + "LOW_NUMBER_OF_BYTES_USED BIGINT not null," + "CURRENT_NUMBER_OF_BYTES_USED BIGINT not null," + "HIGH_NUMBER_OF_BYTES_USED BIGINT not null)")}, + false /* perpetual */ +}; + +PFS_engine_table* table_mems_by_thread_by_event_name::create(void) +{ + return new table_mems_by_thread_by_event_name(); +} + +int +table_mems_by_thread_by_event_name::delete_all_rows(void) +{ + reset_memory_by_thread(); + return 0; +} + +ha_rows +table_mems_by_thread_by_event_name::get_row_count(void) +{ + return global_thread_container.get_row_count() * memory_class_max; +} + +table_mems_by_thread_by_event_name::table_mems_by_thread_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_mems_by_thread_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_mems_by_thread_by_event_name::rnd_next(void) +{ + PFS_thread *thread; + PFS_memory_class *memory_class; + bool has_more_thread= true; + + for (m_pos.set_at(&m_next_pos); + has_more_thread; + m_pos.next_thread()) + { + thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (thread != NULL) + { + do + { + memory_class= find_memory_class(m_pos.m_index_2); + if (memory_class != NULL) + { + if (! memory_class->is_global()) + { + make_row(thread, memory_class); + m_next_pos.set_after(&m_pos); + return 0; + } + + m_pos.next_class(); + } + } + while (memory_class != NULL); + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_mems_by_thread_by_event_name::rnd_pos(const void *pos) +{ + PFS_thread *thread; + PFS_memory_class *memory_class; + + set_position(pos); + + thread= global_thread_container.get(m_pos.m_index_1); + if (thread != NULL) + { + memory_class= find_memory_class(m_pos.m_index_2); + if (memory_class != NULL) + { + if (! memory_class->is_global()) + { + make_row(thread, memory_class); + return 0; + } + } + } + + return HA_ERR_RECORD_DELETED; +} + +void table_mems_by_thread_by_event_name +::make_row(PFS_thread *thread, PFS_memory_class *klass) +{ + pfs_optimistic_state 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_memory_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(& visitor.m_stat); +} + +int table_mems_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, ... HIGH_NUMBER_OF_BYTES_USED */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_mems_by_thread_by_event_name.h b/storage/perfschema/table_mems_by_thread_by_event_name.h new file mode 100644 index 00000000000..f8608198c2a --- /dev/null +++ b/storage/perfschema/table_mems_by_thread_by_event_name.h @@ -0,0 +1,129 @@ +/* Copyright (c) 2011, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME_H +#define TABLE_MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_mems_by_thread_by_event_name.h + Table MEMORY_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 PERFORMANCE_SCHEMA.MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME. */ +struct row_mems_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_ALLOC, ... */ + PFS_memory_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME. + Index 1 on thread (0 based). + Index 2 on memory class (1 based). +*/ +struct pos_mems_by_thread_by_event_name +: public PFS_double_index +{ + pos_mems_by_thread_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline void next_thread(void) + { + m_index_1++; + m_index_2= 1; + } + + inline void next_class(void) + { + m_index_2++; + } +}; + +/** Table PERFORMANCE_SCHEMA.MEMORY_SUMMARY_BY_THREAD_BY_EVENT_NAME. */ +class table_mems_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(); + static ha_rows get_row_count(); + + 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_mems_by_thread_by_event_name(); + +public: + ~table_mems_by_thread_by_event_name() + {} + +private: + void make_row(PFS_thread *thread, PFS_memory_class *klass); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_mems_by_thread_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_mems_by_thread_by_event_name m_pos; + /** Next position. */ + pos_mems_by_thread_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_mems_by_user_by_event_name.cc b/storage/perfschema/table_mems_by_user_by_event_name.cc new file mode 100644 index 00000000000..5d5ee89d6bd --- /dev/null +++ b/storage/perfschema/table_mems_by_user_by_event_name.cc @@ -0,0 +1,221 @@ +/* Copyright (c) 2011, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_mems_by_user_by_event_name.cc + Table MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_mems_by_user_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" +#include "pfs_memory.h" +#include "pfs_buffer_container.h" +#include "field.h" + +THR_LOCK table_mems_by_user_by_event_name::m_table_lock; + +PFS_engine_table_share +table_mems_by_user_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("memory_summary_by_user_by_event_name") }, + &pfs_readonly_acl, + table_mems_by_user_by_event_name::create, + NULL, /* write_row */ + table_mems_by_user_by_event_name::delete_all_rows, + table_mems_by_user_by_event_name::get_row_count, + sizeof(PFS_simple_index), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE memory_summary_by_user_by_event_name(" + "USER CHAR(32) collate utf8_bin default null," + "EVENT_NAME VARCHAR(128) not null," + "COUNT_ALLOC BIGINT unsigned not null," + "COUNT_FREE BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_ALLOC BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_FREE BIGINT unsigned not null," + "LOW_COUNT_USED BIGINT not null," + "CURRENT_COUNT_USED BIGINT not null," + "HIGH_COUNT_USED BIGINT not null," + "LOW_NUMBER_OF_BYTES_USED BIGINT not null," + "CURRENT_NUMBER_OF_BYTES_USED BIGINT not null," + "HIGH_NUMBER_OF_BYTES_USED BIGINT not null)")}, + false /* perpetual */ +}; + +PFS_engine_table* table_mems_by_user_by_event_name::create(void) +{ + return new table_mems_by_user_by_event_name(); +} + +int +table_mems_by_user_by_event_name::delete_all_rows(void) +{ + reset_memory_by_thread(); + reset_memory_by_account(); + reset_memory_by_user(); + return 0; +} + +ha_rows +table_mems_by_user_by_event_name::get_row_count(void) +{ + return global_user_container.get_row_count() * memory_class_max; +} + +table_mems_by_user_by_event_name::table_mems_by_user_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_mems_by_user_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_mems_by_user_by_event_name::rnd_next(void) +{ + PFS_user *user; + PFS_memory_class *memory_class; + bool has_more_user= true; + + for (m_pos.set_at(&m_next_pos); + has_more_user; + m_pos.next_user()) + { + user= global_user_container.get(m_pos.m_index_1, & has_more_user); + if (user != NULL) + { + do + { + memory_class= find_memory_class(m_pos.m_index_2); + if (memory_class != NULL) + { + if (! memory_class->is_global()) + { + make_row(user, memory_class); + m_next_pos.set_after(&m_pos); + return 0; + } + + m_pos.next_class(); + } + } + while (memory_class != NULL); + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_mems_by_user_by_event_name::rnd_pos(const void *pos) +{ + PFS_user *user; + PFS_memory_class *memory_class; + + set_position(pos); + + user= global_user_container.get(m_pos.m_index_1); + if (user != NULL) + { + memory_class= find_memory_class(m_pos.m_index_2); + if (memory_class != NULL) + { + if (! memory_class->is_global()) + { + make_row(user, memory_class); + return 0; + } + } + } + + return HA_ERR_RECORD_DELETED; +} + +void table_mems_by_user_by_event_name +::make_row(PFS_user *user, PFS_memory_class *klass) +{ + pfs_optimistic_state 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_memory_visitor visitor(klass); + PFS_connection_iterator::visit_user(user, + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); + + if (! user->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; + m_row.m_stat.set(& visitor.m_stat); +} + +int table_mems_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, ... HIGH_NUMBER_OF_BYTES_USED */ + m_row.m_stat.set_field(f->field_index - 2, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_mems_by_user_by_event_name.h b/storage/perfschema/table_mems_by_user_by_event_name.h new file mode 100644 index 00000000000..2791e1d3587 --- /dev/null +++ b/storage/perfschema/table_mems_by_user_by_event_name.h @@ -0,0 +1,129 @@ +/* Copyright (c) 2011, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME_H +#define TABLE_MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_mems_by_user_by_event_name.h + Table MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_user.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of PERFORMANCE_SCHEMA.MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME. */ +struct row_mems_by_user_by_event_name +{ + /** Column USER. */ + PFS_user_row m_user; + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_ALLOC, ... */ + PFS_memory_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.EVENTS_MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME. + Index 1 on user (0 based) + Index 2 on memory class (1 based) +*/ +struct pos_mems_by_user_by_event_name +: public PFS_double_index +{ + pos_mems_by_user_by_event_name() + : PFS_double_index(0, 1) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 1; + } + + inline void next_user(void) + { + m_index_1++; + m_index_2= 1; + } + + inline void next_class(void) + { + m_index_2++; + } +}; + +/** Table PERFORMANCE_SCHEMA.MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME. */ +class table_mems_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(); + static ha_rows get_row_count(); + + 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_mems_by_user_by_event_name(); + +public: + ~table_mems_by_user_by_event_name() + {} + +private: + void make_row(PFS_user *user, PFS_memory_class *klass); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_mems_by_user_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_mems_by_user_by_event_name m_pos; + /** Next position. */ + pos_mems_by_user_by_event_name m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_mems_global_by_event_name.cc b/storage/perfschema/table_mems_global_by_event_name.cc new file mode 100644 index 00000000000..93496e38cf4 --- /dev/null +++ b/storage/perfschema/table_mems_global_by_event_name.cc @@ -0,0 +1,241 @@ +/* Copyright (c) 2011, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_mems_global_by_event_name.cc + Table MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_mems_global_by_event_name.h" +#include "pfs_global.h" +#include "pfs_visitor.h" +#include "pfs_builtin_memory.h" +#include "pfs_memory.h" +#include "field.h" + +THR_LOCK table_mems_global_by_event_name::m_table_lock; + +PFS_engine_table_share +table_mems_global_by_event_name::m_share= +{ + { C_STRING_WITH_LEN("memory_summary_global_by_event_name") }, + &pfs_readonly_acl, + table_mems_global_by_event_name::create, + NULL, /* write_row */ + table_mems_global_by_event_name::delete_all_rows, + table_mems_global_by_event_name::get_row_count, + sizeof(pos_t), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE memory_summary_global_by_event_name(" + "EVENT_NAME VARCHAR(128) not null," + "COUNT_ALLOC BIGINT unsigned not null," + "COUNT_FREE BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_ALLOC BIGINT unsigned not null," + "SUM_NUMBER_OF_BYTES_FREE BIGINT unsigned not null," + "LOW_COUNT_USED BIGINT not null," + "CURRENT_COUNT_USED BIGINT not null," + "HIGH_COUNT_USED BIGINT not null," + "LOW_NUMBER_OF_BYTES_USED BIGINT not null," + "CURRENT_NUMBER_OF_BYTES_USED BIGINT not null," + "HIGH_NUMBER_OF_BYTES_USED BIGINT not null)")}, + false /* perpetual */ +}; + +PFS_engine_table* table_mems_global_by_event_name::create(void) +{ + return new table_mems_global_by_event_name(); +} + +int +table_mems_global_by_event_name::delete_all_rows(void) +{ + reset_memory_by_thread(); + reset_memory_by_account(); + reset_memory_by_user(); + reset_memory_by_host(); + reset_memory_global(); + return 0; +} + +ha_rows +table_mems_global_by_event_name::get_row_count(void) +{ + return memory_class_max; +} + +table_mems_global_by_event_name::table_mems_global_by_event_name() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_mems_global_by_event_name::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_mems_global_by_event_name::rnd_next(void) +{ + PFS_memory_class *pfs; + PFS_builtin_memory_class *pfs_builtin; + + /* Do not advertise hard coded instruments when disabled. */ + if (! pfs_initialized) + return HA_ERR_END_OF_FILE; + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_view(); + m_pos.next_view()) + { + switch (m_pos.m_index_1) + { + case pos_mems_global_by_event_name::VIEW_BUILTIN_MEMORY: + pfs_builtin= find_builtin_memory_class(m_pos.m_index_2); + if (pfs_builtin != NULL) + { + make_row(pfs_builtin); + m_next_pos.set_after(&m_pos); + return 0; + } + break; + case pos_mems_global_by_event_name::VIEW_MEMORY: + pfs= find_memory_class(m_pos.m_index_2); + if (pfs != NULL) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + break; + } + } + + return HA_ERR_END_OF_FILE; +} + +int table_mems_global_by_event_name::rnd_pos(const void *pos) +{ + PFS_builtin_memory_class *pfs_builtin; + PFS_memory_class *pfs; + + /* Do not advertise hard coded instruments when disabled. */ + if (! pfs_initialized) + return HA_ERR_END_OF_FILE; + + set_position(pos); + + switch(m_pos.m_index_1) + { + case pos_mems_global_by_event_name::VIEW_BUILTIN_MEMORY: + pfs_builtin= find_builtin_memory_class(m_pos.m_index_2); + if (pfs_builtin != NULL) + { + make_row(pfs_builtin); + return 0; + } + break; + case pos_mems_global_by_event_name::VIEW_MEMORY: + pfs= find_memory_class(m_pos.m_index_2); + if (pfs != NULL) + { + make_row(pfs); + return 0; + } + break; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_mems_global_by_event_name::make_row(PFS_memory_class *klass) +{ + m_row.m_event_name.make_row(klass); + + PFS_connection_memory_visitor visitor(klass); + + if (klass->is_global()) + { + PFS_connection_iterator::visit_global(false, /* hosts */ + false, /* users */ + false, /* accounts */ + false, /* threads */ + false, /* THDs */ + &visitor); + } + else + { + PFS_connection_iterator::visit_global(true, /* hosts */ + false, /* users */ + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + &visitor); + } + + m_row.m_stat.set(& visitor.m_stat); + m_row_exists= true; +} + +void table_mems_global_by_event_name::make_row(PFS_builtin_memory_class *klass) +{ + m_row.m_event_name.make_row(& klass->m_class); + m_row.m_stat.set(& klass->m_stat); + m_row_exists= true; +} + +int table_mems_global_by_event_name::read_row_values(TABLE *table, + unsigned char *, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + /* Set the null bits */ + DBUG_ASSERT(table->s->null_bytes == 0); + + for (; (f= *fields) ; fields++) + { + if (read_all || bitmap_is_set(table->read_set, f->field_index)) + { + switch(f->field_index) + { + case 0: /* EVENT_NAME */ + m_row.m_event_name.set_field(f); + break; + default: /* 1, ... HIGH_NUMBER_OF_BYTES_USED */ + m_row.m_stat.set_field(f->field_index - 1, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_mems_global_by_event_name.h b/storage/perfschema/table_mems_global_by_event_name.h new file mode 100644 index 00000000000..14a54142f4e --- /dev/null +++ b/storage/perfschema/table_mems_global_by_event_name.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2011, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME_H +#define TABLE_MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME_H + +/** + @file storage/perfschema/table_mems_global_by_event_name.h + Table MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_builtin_memory.h" +#include "table_helper.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row of PERFORMANCE_SCHEMA.MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME. */ +struct row_mems_global_by_event_name +{ + /** Column EVENT_NAME. */ + PFS_event_name_row m_event_name; + /** Columns COUNT_ALLOC, ... */ + PFS_memory_stat_row m_stat; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME. + Index 1 on view + Index 2 on instrument key (1 based) +*/ +struct pos_mems_global_by_event_name : public PFS_double_index +{ + static const uint FIRST_VIEW= 1; + static const uint VIEW_BUILTIN_MEMORY= 1; + static const uint VIEW_MEMORY= 2; + static const uint LAST_VIEW= 2; + + pos_mems_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.MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME. */ +class table_mems_global_by_event_name : public PFS_engine_table +{ + typedef pos_mems_global_by_event_name pos_t; + +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + 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); + +private: + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_mems_global_by_event_name(); + +public: + ~table_mems_global_by_event_name() + {} + +private: + void make_row(PFS_builtin_memory_class *klass); + void make_row(PFS_memory_class *klass); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_mems_global_by_event_name m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_os_global_by_type.cc b/storage/perfschema/table_os_global_by_type.cc index b549b0c22e7..f693a0f16da 100644 --- a/storage/perfschema/table_os_global_by_type.cc +++ b/storage/perfschema/table_os_global_by_type.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,12 +26,14 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_os_global_by_type::m_table_lock; @@ -43,8 +45,7 @@ table_os_global_by_type::m_share= table_os_global_by_type::create, NULL, /* write_row */ table_os_global_by_type::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_os_global_by_type::get_row_count, sizeof(pos_os_global_by_type), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE objects_summary_global_by_type(" @@ -55,7 +56,8 @@ table_os_global_by_type::m_share= "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)") } + "MAX_TIMER_WAIT BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -72,6 +74,13 @@ table_os_global_by_type::delete_all_rows(void) return 0; } +ha_rows +table_os_global_by_type::get_row_count(void) +{ + return global_table_share_container.get_row_count() + + global_program_container.get_row_count(); +} + 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() @@ -85,22 +94,46 @@ void table_os_global_by_type::reset_position(void) 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()) + PFS_table_share *table_share; + bool has_more_share= true; + + for (; + has_more_share; + m_pos.m_index_2++) { - make_row(table_share); - m_next_pos.set_after(&m_pos); - return 0; + table_share= global_table_share_container.get(m_pos.m_index_2, & has_more_share); + if (table_share != NULL) + { + make_table_row(table_share); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + break; + case pos_os_global_by_type::VIEW_PROGRAM: + { + PFS_program *pfs_program; + bool has_more_program= true; + + for (; + has_more_program; + m_pos.m_index_2++) + { + pfs_program= global_program_container.get(m_pos.m_index_2, & has_more_program); + if (pfs_program != NULL) + { + make_program_row(pfs_program); + m_next_pos.set_after(&m_pos); + return 0; + } } } break; @@ -115,18 +148,29 @@ int table_os_global_by_type::rnd_next(void) 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; + PFS_table_share *table_share; + table_share= global_table_share_container.get(m_pos.m_index_2); + if (table_share != NULL) + { + make_table_row(table_share); + return 0; + } + } + break; + case pos_os_global_by_type::VIEW_PROGRAM: + { + PFS_program *pfs_program; + pfs_program= global_program_container.get(m_pos.m_index_2); + if (pfs_program != NULL) + { + make_program_row(pfs_program); + return 0; + } } break; default: @@ -136,9 +180,29 @@ table_os_global_by_type::rnd_pos(const void *pos) return HA_ERR_RECORD_DELETED; } -void table_os_global_by_type::make_row(PFS_table_share *share) +void table_os_global_by_type::make_program_row(PFS_program *pfs_program) { - pfs_lock lock; + pfs_optimistic_state lock; + PFS_single_stat cumulated_stat; + + m_row_exists= false; + + pfs_program->m_lock.begin_optimistic_lock(&lock); + + m_row.m_object.make_row(pfs_program); + + time_normalizer *normalizer= time_normalizer::get(wait_timer); + m_row.m_stat.set(normalizer, &pfs_program->m_sp_stat.m_timer1_stat); + + if (! pfs_program->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; +} + +void table_os_global_by_type::make_table_row(PFS_table_share *share) +{ + pfs_optimistic_state lock; PFS_single_stat cumulated_stat; uint safe_key_count; @@ -146,16 +210,12 @@ void table_os_global_by_type::make_row(PFS_table_share *share) 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; + m_row.m_object.make_row(share); /* 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); + share->sum(& cumulated_stat, safe_key_count); if (! share->m_lock.end_optimistic_lock(&lock)) return; @@ -165,11 +225,12 @@ void table_os_global_by_type::make_row(PFS_table_share *share) 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++) + PFS_table_iterator it= global_table_container.iterate(); + PFS_table *table= it.scan_next(); + + while (table != NULL) { - if ((table->m_share == share) && (table->m_lock.is_populated())) + if (table->m_share == share) { /* If the opened table handle is for this table share, @@ -177,6 +238,7 @@ void table_os_global_by_type::make_row(PFS_table_share *share) */ table->m_table_stat.sum(& cumulated_stat, safe_key_count); } + table= it.scan_next(); } } @@ -205,15 +267,15 @@ int table_os_global_by_type::read_row_values(TABLE *table, switch(f->field_index) { case 0: /* OBJECT_TYPE */ - set_field_object_type(f, m_row.m_object_type); + set_field_object_type(f, m_row.m_object.m_object_type); break; case 1: /* SCHEMA_NAME */ - set_field_varchar_utf8(f, m_row.m_schema_name, - m_row.m_schema_name_length); + set_field_varchar_utf8(f, m_row.m_object.m_schema_name, + m_row.m_object.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); + set_field_varchar_utf8(f, m_row.m_object.m_object_name, + m_row.m_object.m_object_name_length); break; case 3: /* COUNT */ set_field_ulonglong(f, m_row.m_stat.m_count); diff --git a/storage/perfschema/table_os_global_by_type.h b/storage/perfschema/table_os_global_by_type.h index 2b9293ece06..37e6db1ed94 100644 --- a/storage/perfschema/table_os_global_by_type.h +++ b/storage/perfschema/table_os_global_by_type.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -32,6 +32,7 @@ #include "pfs_engine_table.h" #include "pfs_instr_class.h" #include "pfs_instr.h" +#include "pfs_program.h" #include "table_helper.h" /** @@ -45,16 +46,9 @@ */ 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; + /** Column OBJECT_TYPE, SCHEMA_NAME, OBJECT_NAME. */ + PFS_object_row m_object; + /** Columns COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT. */ PFS_stat_row m_stat; }; @@ -96,6 +90,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); @@ -114,7 +109,8 @@ public: {} protected: - void make_row(PFS_table_share *table_share); + void make_table_row(PFS_table_share *table_share); + void make_program_row(PFS_program *pfs_program); private: /** Table share lock. */ diff --git a/storage/perfschema/table_performance_timers.cc b/storage/perfschema/table_performance_timers.cc index a77f005ab62..1c1d9c5afef 100644 --- a/storage/perfschema/table_performance_timers.cc +++ b/storage/perfschema/table_performance_timers.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, version 2.0, @@ -26,10 +26,11 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "table_performance_timers.h" #include "pfs_timer.h" #include "pfs_global.h" +#include "field.h" THR_LOCK table_performance_timers::m_table_lock; @@ -38,18 +39,18 @@ table_performance_timers::m_share= { { C_STRING_WITH_LEN("performance_timers") }, &pfs_readonly_acl, - &table_performance_timers::create, + table_performance_timers::create, NULL, /* write_row */ NULL, /* delete_all_rows */ - NULL, /* get_row_count */ - COUNT_TIMER_NAME, /* records */ + table_performance_timers::get_row_count, sizeof(PFS_simple_index), /* ref length */ &m_table_lock, { 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)") } + "TIMER_OVERHEAD BIGINT)") }, + false /* perpetual */ }; PFS_engine_table* table_performance_timers::create(void) @@ -57,6 +58,12 @@ PFS_engine_table* table_performance_timers::create(void) return new table_performance_timers(); } +ha_rows +table_performance_timers::get_row_count(void) +{ + return COUNT_TIMER_NAME; +} + table_performance_timers::table_performance_timers() : PFS_engine_table(&m_share, &m_pos), m_row(NULL), m_pos(0), m_next_pos(0) diff --git a/storage/perfschema/table_performance_timers.h b/storage/perfschema/table_performance_timers.h index 93210ac9882..fe5f9cd5f4a 100644 --- a/storage/perfschema/table_performance_timers.h +++ b/storage/perfschema/table_performance_timers.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, version 2.0, @@ -56,6 +56,7 @@ public: /** Table share. */ static PFS_engine_table_share m_share; static PFS_engine_table* create(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_prepared_stmt_instances.cc b/storage/perfschema/table_prepared_stmt_instances.cc new file mode 100644 index 00000000000..6e93523deb4 --- /dev/null +++ b/storage/perfschema/table_prepared_stmt_instances.cc @@ -0,0 +1,294 @@ +/* Copyright (c) 2014, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_prepared_stmt_instances.cc + Table PREPARED_STATEMENTS_INSTANCES (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_global.h" +#include "pfs_instr.h" +#include "pfs_timer.h" +#include "pfs_visitor.h" +#include "pfs_prepared_stmt.h" +#include "table_prepared_stmt_instances.h" +#include "pfs_buffer_container.h" +#include "field.h" + +THR_LOCK table_prepared_stmt_instances::m_table_lock; + +PFS_engine_table_share +table_prepared_stmt_instances::m_share= +{ + { C_STRING_WITH_LEN("prepared_statements_instances") }, + &pfs_truncatable_acl, + table_prepared_stmt_instances::create, + NULL, /* write_row */ + table_prepared_stmt_instances::delete_all_rows, + table_prepared_stmt_instances::get_row_count, + sizeof(PFS_simple_index), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE prepared_statements_instances(" + "OBJECT_INSTANCE_BEGIN bigint(20) unsigned NOT NULL," + "STATEMENT_ID bigint(20) unsigned NOT NULL," + "STATEMENT_NAME varchar(64) default NULL," + "SQL_TEXT longtext NOT NULL," + "OWNER_THREAD_ID bigint(20) unsigned NOT NULL," + "OWNER_EVENT_ID bigint(20) unsigned NOT NULL," + "OWNER_OBJECT_TYPE enum('EVENT','FUNCTION','PROCEDURE','TABLE','TRIGGER') DEFAULT NULL," + "OWNER_OBJECT_SCHEMA varchar(64) DEFAULT NULL," + "OWNER_OBJECT_NAME varchar(64) DEFAULT NULL," + "TIMER_PREPARE bigint(20) unsigned NOT NULL," + "COUNT_REPREPARE bigint(20) unsigned NOT NULL," + "COUNT_EXECUTE bigint(20) unsigned NOT NULL," + "SUM_TIMER_EXECUTE bigint(20) unsigned NOT NULL," + "MIN_TIMER_EXECUTE bigint(20) unsigned NOT NULL," + "AVG_TIMER_EXECUTE bigint(20) unsigned NOT NULL," + "MAX_TIMER_EXECUTE bigint(20) unsigned NOT NULL," + "SUM_LOCK_TIME bigint(20) unsigned NOT NULL," + "SUM_ERRORS bigint(20) unsigned NOT NULL," + "SUM_WARNINGS bigint(20) unsigned NOT NULL," + "SUM_ROWS_AFFECTED bigint(20) unsigned NOT NULL," + "SUM_ROWS_SENT bigint(20) unsigned NOT NULL," + "SUM_ROWS_EXAMINED bigint(20) unsigned NOT NULL," + "SUM_CREATED_TMP_DISK_TABLES bigint(20) unsigned NOT NULL," + "SUM_CREATED_TMP_TABLES bigint(20) unsigned NOT NULL," + "SUM_SELECT_FULL_JOIN bigint(20) unsigned NOT NULL," + "SUM_SELECT_FULL_RANGE_JOIN bigint(20) unsigned NOT NULL," + "SUM_SELECT_RANGE bigint(20) unsigned NOT NULL," + "SUM_SELECT_RANGE_CHECK bigint(20) unsigned NOT NULL," + "SUM_SELECT_SCAN bigint(20) unsigned NOT NULL," + "SUM_SORT_MERGE_PASSES bigint(20) unsigned NOT NULL," + "SUM_SORT_RANGE bigint(20) unsigned NOT NULL," + "SUM_SORT_ROWS bigint(20) unsigned NOT NULL," + "SUM_SORT_SCAN bigint(20) unsigned NOT NULL," + "SUM_NO_INDEX_USED bigint(20) unsigned NOT NULL," + "SUM_NO_GOOD_INDEX_USED bigint(20) unsigned NOT NULL)")}, + false /* perpetual */ +}; + +PFS_engine_table* +table_prepared_stmt_instances::create(void) +{ + return new table_prepared_stmt_instances(); +} + +int +table_prepared_stmt_instances::delete_all_rows(void) +{ + reset_prepared_stmt_instances(); + return 0; +} + +ha_rows +table_prepared_stmt_instances::get_row_count(void) +{ + return global_prepared_stmt_container.get_row_count(); +} + +table_prepared_stmt_instances::table_prepared_stmt_instances() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_prepared_stmt_instances::reset_position(void) +{ + m_pos= 0; + m_next_pos= 0; +} + +int table_prepared_stmt_instances::rnd_next(void) +{ + PFS_prepared_stmt* pfs; + + m_pos.set_at(&m_next_pos); + PFS_prepared_stmt_iterator it= global_prepared_stmt_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int +table_prepared_stmt_instances::rnd_pos(const void *pos) +{ + PFS_prepared_stmt* pfs; + + set_position(pos); + + pfs= global_prepared_stmt_container.get(m_pos.m_index); + if (pfs != NULL) + { + make_row(pfs); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + + +void table_prepared_stmt_instances::make_row(PFS_prepared_stmt* prepared_stmt) +{ + pfs_optimistic_state lock; + m_row_exists= false; + + prepared_stmt->m_lock.begin_optimistic_lock(&lock); + + m_row.m_identity= prepared_stmt->m_identity; + + m_row.m_stmt_id= prepared_stmt->m_stmt_id; + + m_row.m_owner_thread_id= prepared_stmt->m_owner_thread_id; + m_row.m_owner_event_id= prepared_stmt->m_owner_event_id; + + m_row.m_stmt_name_length= prepared_stmt->m_stmt_name_length; + if(m_row.m_stmt_name_length > 0) + memcpy(m_row.m_stmt_name, prepared_stmt->m_stmt_name, + m_row.m_stmt_name_length); + + m_row.m_sql_text_length= prepared_stmt->m_sqltext_length; + if(m_row.m_sql_text_length > 0) + memcpy(m_row.m_sql_text, prepared_stmt->m_sqltext, + m_row.m_sql_text_length); + + m_row.m_owner_object_type= prepared_stmt->m_owner_object_type; + + m_row.m_owner_object_name_length= prepared_stmt->m_owner_object_name_length; + if(m_row.m_owner_object_name_length > 0) + memcpy(m_row.m_owner_object_name, prepared_stmt->m_owner_object_name, + m_row.m_owner_object_name_length); + + m_row.m_owner_object_schema_length= prepared_stmt->m_owner_object_schema_length; + if(m_row.m_owner_object_schema_length > 0) + memcpy(m_row.m_owner_object_schema, prepared_stmt->m_owner_object_schema, + m_row.m_owner_object_schema_length); + + time_normalizer *normalizer= time_normalizer::get(statement_timer); + /* Get prepared statement prepare stats. */ + m_row.m_prepare_stat.set(normalizer, & prepared_stmt->m_prepare_stat); + /* Get prepared statement reprepare stats. */ + m_row.m_reprepare_stat.set(normalizer, & prepared_stmt->m_reprepare_stat); + /* Get prepared statement execute stats. */ + m_row.m_execute_stat.set(normalizer, & prepared_stmt->m_execute_stat); + + if (! prepared_stmt->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; +} + +int table_prepared_stmt_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: /* OBJECT_INSTANCE_BEGIN */ + set_field_ulonglong(f, (intptr)m_row.m_identity); + break; + case 1: /* STATEMENT_ID */ + set_field_ulonglong(f, m_row.m_stmt_id); + break; + case 2: /* STATEMENT_NAME */ + if(m_row.m_stmt_name_length > 0) + set_field_varchar_utf8(f, m_row.m_stmt_name, + m_row.m_stmt_name_length); + else + f->set_null(); + break; + case 3: /* SQL_TEXT */ + if(m_row.m_sql_text_length > 0) + set_field_longtext_utf8(f, m_row.m_sql_text, + m_row.m_sql_text_length); + else + f->set_null(); + break; + case 4: /* OWNER_THREAD_ID */ + set_field_ulonglong(f, m_row.m_owner_thread_id); + break; + case 5: /* OWNER_EVENT_ID */ + if(m_row.m_owner_event_id > 0) + set_field_ulonglong(f, m_row.m_owner_event_id); + else + f->set_null(); + break; + case 6: /* OWNER_OBJECT_TYPE */ + if(m_row.m_owner_object_type != 0) + set_field_enum(f, m_row.m_owner_object_type); + else + f->set_null(); + break; + case 7: /* OWNER_OBJECT_SCHEMA */ + if(m_row.m_owner_object_schema_length > 0) + set_field_varchar_utf8(f, m_row.m_owner_object_schema, + m_row.m_owner_object_schema_length); + else + f->set_null(); + break; + case 8: /* OWNER_OBJECT_NAME */ + if(m_row.m_owner_object_name_length > 0) + set_field_varchar_utf8(f, m_row.m_owner_object_name, + m_row.m_owner_object_name_length); + else + f->set_null(); + break; + case 9: /* TIMER_PREPARE */ + m_row.m_prepare_stat.set_field(1, f); + break; + case 10: /* COUNT_REPREPARE */ + m_row.m_reprepare_stat.set_field(0, f); + break; + default: /* 14, ... COUNT/SUM/MIN/AVG/MAX */ + m_row.m_execute_stat.set_field(f->field_index - 11, f); + break; + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_prepared_stmt_instances.h b/storage/perfschema/table_prepared_stmt_instances.h new file mode 100644 index 00000000000..a17184d4312 --- /dev/null +++ b/storage/perfschema/table_prepared_stmt_instances.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2014, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_PREPARED_STMT_INSTANCES +#define TABLE_PREPARED_STMT_INSTANCES + +/** + @file storage/perfschema/table_prepared_stmt_instances.h + Table PREPARED_STATEMENT_INSTANCE(declarations). +*/ + +#include "table_helper.h" +#include "pfs_prepared_stmt.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.PREPARED_STATEMENT_INSTANCES. +*/ +struct row_prepared_stmt_instances +{ + /** Column OBJECT_INSTANCE_BEGIN. */ + const void *m_identity; + + /** Column STMT_ID. */ + ulonglong m_stmt_id; + + /** Column STMT_NAME. */ + char m_stmt_name[COL_INFO_SIZE]; + int m_stmt_name_length; + + /** Column SQL_TEXT. */ + char m_sql_text[COL_INFO_SIZE]; + int m_sql_text_length; + + /** Column OWNER_THREAD_ID. */ + ulonglong m_owner_thread_id; + + /** Column OWNER_EVENT_ID. */ + ulonglong m_owner_event_id; + + /** Column OWNER_OBJECT_TYPE. */ + enum_object_type m_owner_object_type; + + /** Column OWNER_OBJECT_SCHEMA */ + char m_owner_object_schema[COL_OBJECT_SCHEMA_SIZE]; + int m_owner_object_schema_length; + + /** Column OWNER_OBJECT_NAME */ + char m_owner_object_name[COL_OBJECT_NAME_SIZE]; + int m_owner_object_name_length; + + /** Columns TIMER_PREPARE. */ + PFS_stat_row m_prepare_stat; + + /** Columns COUNT_REPREPARE. */ + PFS_stat_row m_reprepare_stat; + + /** Columns COUNT_STAR...SUM_NO_GOOD_INDEX_USED. */ + PFS_statement_stat_row m_execute_stat; +}; + +/** Table PERFORMANCE_SCHEMA.PREPARED_STATEMENT_INSTANCES. */ +class table_prepared_stmt_instances : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + 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); + + table_prepared_stmt_instances(); + +public: + ~table_prepared_stmt_instances() + {} + +protected: + void make_row(PFS_prepared_stmt*); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_prepared_stmt_instances 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_replication_applier_configuration.cc b/storage/perfschema/table_replication_applier_configuration.cc new file mode 100644 index 00000000000..cb5dfd05e69 --- /dev/null +++ b/storage/perfschema/table_replication_applier_configuration.cc @@ -0,0 +1,192 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_replication_applier_configuration.cc + Table replication_applier_configuration (implementation). +*/ + +#define HAVE_REPLICATION + +#include "my_global.h" +#include "table_replication_applier_configuration.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "slave.h" +//#include "rpl_info.h" +#include "rpl_rli.h" +#include "rpl_mi.h" +#include "sql_parse.h" +//#include "rpl_msr.h" /* Multisource replication */ + +THR_LOCK table_replication_applier_configuration::m_table_lock; + +PFS_engine_table_share +table_replication_applier_configuration::m_share= +{ + { C_STRING_WITH_LEN("replication_applier_configuration") }, + &pfs_readonly_acl, + table_replication_applier_configuration::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_replication_applier_configuration::get_row_count, + sizeof(pos_t), /* ref length */ + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE replication_applier_configuration(" + "CHANNEL_NAME CHAR(64) collate utf8_general_ci not null," + "DESIRED_DELAY INTEGER not null)") }, + false /* perpetual */ +}; + +PFS_engine_table* table_replication_applier_configuration::create(void) +{ + return new table_replication_applier_configuration(); +} + +table_replication_applier_configuration + ::table_replication_applier_configuration() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +table_replication_applier_configuration + ::~table_replication_applier_configuration() +{} + +void table_replication_applier_configuration::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + + +ha_rows table_replication_applier_configuration::get_row_count() +{ + return master_info_index->master_info_hash.records; +} + + +int table_replication_applier_configuration::rnd_next(void) +{ + Master_info *mi; + mysql_mutex_lock(&LOCK_active_mi); + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < master_info_index->master_info_hash.records; + m_pos.next()) + { + mi= (Master_info *)my_hash_element(&master_info_index->master_info_hash, m_pos.m_index); + + if (mi && mi->host[0]) + { + make_row(mi); + m_next_pos.set_after(&m_pos); + channel_map.unlock(); + return 0; + } + } + + mysql_mutex_unlock(&LOCK_active_mi); + return HA_ERR_END_OF_FILE; +} + +int table_replication_applier_configuration::rnd_pos(const void *pos) +{ + Master_info *mi; + int res= HA_ERR_RECORD_DELETED; + + set_position(pos); + + mysql_mutex_lock(&LOCK_active_mi); + + if ((mi= (Master_info *)my_hash_element(&master_info_index->master_info_hash, m_pos.m_index))) + { + make_row(mi); + res= 0; + } + + mysql_mutex_unlock(&LOCK_active_mi); + return res; +} + +void table_replication_applier_configuration::make_row(Master_info *mi) +{ + m_row_exists= false; + + DBUG_ASSERT(mi != NULL); + + mysql_mutex_lock(&mi->data_lock); + mysql_mutex_lock(&mi->rli.data_lock); + + m_row.channel_name_length= mi->connection_name.length; + memcpy(m_row.channel_name, mi->connection_name.str, m_row.channel_name_length); + m_row.desired_delay= 0; //mi->rli->get_sql_delay(); + + mysql_mutex_unlock(&mi->rli.data_lock); + mysql_mutex_unlock(&mi->data_lock); + + m_row_exists= true; +} + +int table_replication_applier_configuration::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; + + /* + Note: + There are no NULL columns in this table, + so there are no null bits reserved for NULL flags per column. + There are no VARCHAR columns either, so the record is not + in HA_OPTION_PACK_RECORD format as most other performance_schema tables. + When HA_OPTION_PACK_RECORD is not set, + the table record reserves an extra null byte, see open_binary_frm(). + */ + + 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: /**channel_name*/ + set_field_char_utf8(f, m_row.channel_name, m_row.channel_name_length); + break; + case 1: /** desired_delay */ + set_field_ulong(f, static_cast<ulong>(m_row.desired_delay)); + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} diff --git a/storage/perfschema/table_replication_applier_configuration.h b/storage/perfschema/table_replication_applier_configuration.h new file mode 100644 index 00000000000..18321ac079e --- /dev/null +++ b/storage/perfschema/table_replication_applier_configuration.h @@ -0,0 +1,107 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#ifndef TABLE_REPLICATION_APPLIER_CONFIGURATION_H +#define TABLE_REPLICATION_APPLIER_CONFIGURATION_H + +/** + @file storage/perfschema/table_replication_applier_configuration.h + Table replication_applier_configuration (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "rpl_mi.h" +#include "mysql_com.h" +#include "my_thread.h" +//#include "rpl_msr.h" +//#include "rpl_info.h" /*CHANNEL_NAME_LENGTH*/ + +class Master_info; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** A row in the table*/ +struct st_row_applier_config { + char channel_name[CHANNEL_NAME_LENGTH]; + uint channel_name_length; + time_t desired_delay; + bool desired_delay_is_set; +}; + +/** Table PERFORMANCE_SCHEMA.replication_applier_configuration */ +class table_replication_applier_configuration: public PFS_engine_table +{ + typedef PFS_simple_index pos_t; + +private: + void make_row(Master_info *mi); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + /** Current row */ + st_row_applier_config m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + +protected: + /** + Read the current row values. + @param table Table handle + @param buf row buffer + @param fields Table fields + @param read_all true if all columns are read. + */ + + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_replication_applier_configuration(); + +public: + ~table_replication_applier_configuration(); + + /** Table share. */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_replication_applier_status.cc b/storage/perfschema/table_replication_applier_status.cc new file mode 100644 index 00000000000..b6d06ff442c --- /dev/null +++ b/storage/perfschema/table_replication_applier_status.cc @@ -0,0 +1,219 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_replication_applier_status.cc + Table replication_applier_status (implementation). +*/ + +#define HAVE_REPLICATION + +#include "my_global.h" +#include "table_replication_applier_status.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "slave.h" +//#include "rpl_info.h" +#include "rpl_rli.h" +#include "rpl_mi.h" +#include "sql_parse.h" +//#include "rpl_msr.h" /*Multi source replication */ + +THR_LOCK table_replication_applier_status::m_table_lock; + +PFS_engine_table_share +table_replication_applier_status::m_share= +{ + { C_STRING_WITH_LEN("replication_applier_status") }, + &pfs_readonly_acl, + table_replication_applier_status::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_replication_applier_status::get_row_count, /* records */ + sizeof(pos_t), /* ref length */ + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE replication_applier_status(" + "CHANNEL_NAME CHAR(64) collate utf8_general_ci not null," + "SERVICE_STATE ENUM('ON','OFF') not null," + "REMAINING_DELAY INTEGER unsigned," + "COUNT_TRANSACTIONS_RETRIES BIGINT unsigned not null)") }, + false /* perpetual */ +}; + + +PFS_engine_table* table_replication_applier_status::create(void) +{ + return new table_replication_applier_status(); +} + +table_replication_applier_status::table_replication_applier_status() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +table_replication_applier_status::~table_replication_applier_status() +{} + +void table_replication_applier_status::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +ha_rows table_replication_applier_status::get_row_count() +{ + return master_info_index->master_info_hash.records; +} + + +int table_replication_applier_status::rnd_next(void) +{ + Master_info *mi; + mysql_mutex_lock(&LOCK_active_mi); + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < master_info_index->master_info_hash.records; + m_pos.next()) + { + mi= (Master_info *)my_hash_element(&master_info_index->master_info_hash, m_pos.m_index); + + if (mi && mi->host[0]) + { + make_row(mi); + m_next_pos.set_after(&m_pos); + mysql_mutex_unlock(&LOCK_active_mi); + return 0; + } + } + + mysql_mutex_unlock(&LOCK_active_mi); + return HA_ERR_END_OF_FILE; +} + + +int table_replication_applier_status::rnd_pos(const void *pos) +{ + Master_info *mi=NULL; + int res= HA_ERR_RECORD_DELETED; + + set_position(pos); + + mysql_mutex_lock(&LOCK_active_mi); + + if ((mi= (Master_info *)my_hash_element(&master_info_index->master_info_hash, m_pos.m_index))) + { + make_row(mi); + res= 0; + } + + mysql_mutex_unlock(&LOCK_active_mi); + return res; +} + +void table_replication_applier_status::make_row(Master_info *mi) +{ + char *slave_sql_running_state= NULL; + + m_row_exists= false; + + DBUG_ASSERT(mi != NULL); + + m_row.channel_name_length= mi->connection_name.length; + memcpy(m_row.channel_name, mi->connection_name.str, m_row.channel_name_length); + + //mysql_mutex_lock(&mi->rli->info_thd_lock); + + slave_sql_running_state= const_cast<char *> + (mi->rli.sql_driver_thd ? + mi->rli.sql_driver_thd->get_proc_info() : ""); + //mysql_mutex_unlock(&mi->rli->info_thd_lock); + + + mysql_mutex_lock(&mi->data_lock); + mysql_mutex_lock(&mi->rli.data_lock); + + if (mi->rli.slave_running) + m_row.service_state= PS_RPL_YES; + else + m_row.service_state= PS_RPL_NO; + + m_row.remaining_delay= 0; + if (slave_sql_running_state == stage_sql_thd_waiting_until_delay.m_name) + { + time_t t= my_time(0), sql_delay_end= 0; //mi->rli.>get_sql_delay_end(); + m_row.remaining_delay= (uint)(t < sql_delay_end ? + sql_delay_end - t : 0); + m_row.remaining_delay_is_set= true; + } + else + m_row.remaining_delay_is_set= false; + + m_row.count_transactions_retries= mi->rli.retried_trans; + + mysql_mutex_unlock(&mi->rli.data_lock); + mysql_mutex_unlock(&mi->data_lock); + + m_row_exists= true; +} + +int table_replication_applier_status::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; + + 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: /**channel_name*/ + set_field_char_utf8(f, m_row.channel_name, m_row.channel_name_length); + break; + case 1: /* service_state */ + set_field_enum(f, m_row.service_state); + break; + case 2: /* remaining_delay */ + if (m_row.remaining_delay_is_set) + set_field_ulong(f, m_row.remaining_delay); + else + f->set_null(); + break; + case 3: /* total number of times transactions were retried */ + set_field_ulonglong(f, m_row.count_transactions_retries); + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} diff --git a/storage/perfschema/table_replication_applier_status.h b/storage/perfschema/table_replication_applier_status.h new file mode 100644 index 00000000000..95845f38925 --- /dev/null +++ b/storage/perfschema/table_replication_applier_status.h @@ -0,0 +1,118 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#ifndef TABLE_REPLICATION_APPLIER_STATUS_H +#define TABLE_REPLICATION_APPLIER_STATUS_H + +/** + @file storage/perfschema/table_replication_applier_status.h + Table replication_applier_status (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "rpl_mi.h" +#include "mysql_com.h" +//#include "rpl_msr.h" +//#include "rpl_info.h" /*CHANNEL_NAME_LENGTH*/ +#include "my_thread.h" + +class Master_info; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +#ifndef ENUM_RPL_YES_NO +#define ENUM_RPL_YES_NO +/** enum values for Service_State field*/ +enum enum_rpl_yes_no { + PS_RPL_YES= 1, + PS_RPL_NO +}; +#endif + +/** A row in the table. */ +struct st_row_applier_status { + char channel_name[CHANNEL_NAME_LENGTH]; + uint channel_name_length; + enum_rpl_yes_no service_state; + uint remaining_delay; + bool remaining_delay_is_set; + ulong count_transactions_retries; +}; + +/** Table PERFORMANCE_SCHEMA.replication_applier_status */ +class table_replication_applier_status: public PFS_engine_table +{ + typedef PFS_simple_index pos_t; + +private: + void make_row(Master_info *mi); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + /** Current row */ + st_row_applier_status m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + +protected: + /** + Read the current row values. + @param table Table handle + @param buf row buffer + @param fields Table fields + @param read_all true if all columns are read. + */ + + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_replication_applier_status(); + +public: + ~table_replication_applier_status(); + + /** Table share. */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_replication_applier_status_by_coordinator.cc b/storage/perfschema/table_replication_applier_status_by_coordinator.cc new file mode 100644 index 00000000000..5201bdc6de8 --- /dev/null +++ b/storage/perfschema/table_replication_applier_status_by_coordinator.cc @@ -0,0 +1,246 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_replication_applier_status_by_cordinator.cc + Table replication_applier_status_by_coordinator (implementation). +*/ + +#define HAVE_REPLICATION + +#include "my_global.h" +#include "table_replication_applier_status_by_coordinator.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "slave.h" +//#include "rpl_info.h" +#include "rpl_rli.h" +#include "rpl_mi.h" +#include "sql_parse.h" +//#include "rpl_msr.h" /* Multisource replication */ + +THR_LOCK table_replication_applier_status_by_coordinator::m_table_lock; + +PFS_engine_table_share +table_replication_applier_status_by_coordinator::m_share= +{ + { C_STRING_WITH_LEN("replication_applier_status_by_coordinator") }, + &pfs_readonly_acl, + table_replication_applier_status_by_coordinator::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_replication_applier_status_by_coordinator::get_row_count, + sizeof(pos_t), /* ref length */ + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE replication_applier_status_by_coordinator(" + "CHANNEL_NAME CHAR(64) collate utf8_general_ci not null," + "THREAD_ID BIGINT UNSIGNED," + "SERVICE_STATE ENUM('ON','OFF') not null," + "LAST_ERROR_NUMBER INTEGER not null," + "LAST_ERROR_MESSAGE VARCHAR(1024) not null," + "LAST_ERROR_TIMESTAMP TIMESTAMP(0) not null)") }, + false /* perpetual */ +}; + +PFS_engine_table* table_replication_applier_status_by_coordinator::create(void) +{ + return new table_replication_applier_status_by_coordinator(); +} + +table_replication_applier_status_by_coordinator + ::table_replication_applier_status_by_coordinator() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +table_replication_applier_status_by_coordinator + ::~table_replication_applier_status_by_coordinator() +{} + +void table_replication_applier_status_by_coordinator::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +ha_rows table_replication_applier_status_by_coordinator::get_row_count() +{ + return master_info_index->master_info_hash.records; +} + + +int table_replication_applier_status_by_coordinator::rnd_next(void) +{ + Master_info *mi; + + mysql_mutex_lock(&LOCK_active_mi); + + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < master_info_index->master_info_hash.records; + m_pos.next()) + { + mi= (Master_info *)my_hash_element(&master_info_index->master_info_hash, m_pos.m_index); + + /* + Construct and display SQL Thread's (Coordinator) information in + 'replication_applier_status_by_coordinator' table only in the case of + multi threaded slave mode. Code should do nothing in the case of single + threaded slave mode. In case of single threaded slave mode SQL Thread's + status will be reported as part of + 'replication_applier_status_by_worker' table. + */ + if (mi && mi->host[0] && /*mi->rli.get_worker_count() > */ 0) + { + make_row(mi); + m_next_pos.set_after(&m_pos); + channel_map.unlock(); + return 0; + } + } + + mysql_mutex_unlock(&LOCK_active_mi); + return HA_ERR_END_OF_FILE; +} + +int table_replication_applier_status_by_coordinator::rnd_pos(const void *pos) +{ + Master_info *mi=NULL; + int res= HA_ERR_RECORD_DELETED; + + set_position(pos); + + mysql_mutex_lock(&LOCK_active_mi); + + if ((mi= (Master_info *)my_hash_element(&master_info_index->master_info_hash, m_pos.m_index))) + { + make_row(mi); + res= 0; + } + + mysql_mutex_unlock(&LOCK_active_mi); + return res; +} + +void table_replication_applier_status_by_coordinator::make_row(Master_info *mi) +{ + m_row_exists= false; + + DBUG_ASSERT(mi != NULL); + + mysql_mutex_lock(&mi->rli.data_lock); + + m_row.channel_name_length= mi->connection_name.length; + memcpy(m_row.channel_name, mi->connection_name.str, m_row.channel_name_length); + + if (mi->rli.slave_running) + { + PSI_thread *psi= thd_get_psi(mi->rli.sql_driver_thd); + PFS_thread *pfs= reinterpret_cast<PFS_thread *> (psi); + if(pfs) + { + m_row.thread_id= pfs->m_thread_internal_id; + m_row.thread_id_is_null= false; + } + else + m_row.thread_id_is_null= true; + } + else + m_row.thread_id_is_null= true; + + if (mi->rli.slave_running) + m_row.service_state= PS_RPL_YES; + else + m_row.service_state= PS_RPL_NO; + + mysql_mutex_lock(&mi->rli.err_lock); + + m_row.last_error_number= (long int) mi->rli.last_error().number; + m_row.last_error_message_length= 0; + m_row.last_error_timestamp= 0; + + /** if error, set error message and timestamp */ + if (m_row.last_error_number) + { + char *temp_store= (char*) mi->rli.last_error().message; + m_row.last_error_message_length= strlen(temp_store); + memcpy(m_row.last_error_message, temp_store, + m_row.last_error_message_length); + + /** time in millisecond since epoch */ + m_row.last_error_timestamp= 0;//(ulonglong)mi->rli.last_error().skr*1000000; + } + + mysql_mutex_unlock(&mi->rli.err_lock); + mysql_mutex_unlock(&mi->rli.data_lock); + + m_row_exists= true; +} + +int table_replication_applier_status_by_coordinator + ::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; + + 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: /* channel_name */ + set_field_char_utf8(f, m_row.channel_name, m_row.channel_name_length); + break; + case 1: /*thread_id*/ + if (!m_row.thread_id_is_null) + set_field_ulonglong(f, m_row.thread_id); + else + f->set_null(); + break; + case 2: /*service_state*/ + set_field_enum(f, m_row.service_state); + break; + case 3: /*last_error_number*/ + set_field_ulong(f, m_row.last_error_number); + break; + case 4: /*last_error_message*/ + set_field_varchar_utf8(f, m_row.last_error_message, + m_row.last_error_message_length); + break; + case 5: /*last_error_timestamp*/ + set_field_timestamp(f, m_row.last_error_timestamp); + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} diff --git a/storage/perfschema/table_replication_applier_status_by_coordinator.h b/storage/perfschema/table_replication_applier_status_by_coordinator.h new file mode 100644 index 00000000000..8c1d4c4f029 --- /dev/null +++ b/storage/perfschema/table_replication_applier_status_by_coordinator.h @@ -0,0 +1,124 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#ifndef TABLE_REPLICATION_APPLIER_STATUS_BY_COORDINATOR_H +#define TABLE_REPLICATION_APPLIER_STATUS_BY_COORDINATOR_H + +/** + @file storage/perfschema/table_replication_applier_applier_by_coordinator.h + Table replication_applier_status_by_coordinator(declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "rpl_mi.h" +#include "mysql_com.h" +//#include "rpl_msr.h" +//#include "rpl_info.h" /*CHANNEL_NAME_LENGTH*/ +#include "my_thread.h" + +class Master_info; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +#ifndef ENUM_RPL_YES_NO +#define ENUM_RPL_YES_NO +/** enum values for Service_State of coordinator thread */ +enum enum_rpl_yes_no { + PS_RPL_YES= 1, /* Service_State= on */ + PS_RPL_NO /* Service_State= off */ +}; +#endif + +/* + A row in coordinator's table. The fields with string values have an + additional length field denoted by <field_name>_length. +*/ +struct st_row_coordinator { + char channel_name[CHANNEL_NAME_LENGTH]; + uint channel_name_length; + ulonglong thread_id; + bool thread_id_is_null; + enum_rpl_yes_no service_state; + uint last_error_number; + char last_error_message[MAX_SLAVE_ERRMSG]; + uint last_error_message_length; + ulonglong last_error_timestamp; +}; + +/** Table PERFORMANCE_SCHEMA.replication_applier_status_by_coordinator */ +class table_replication_applier_status_by_coordinator: public PFS_engine_table +{ + typedef PFS_simple_index pos_t; + +private: + void make_row(Master_info *mi); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + /** Current row */ + st_row_coordinator m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + +protected: + /** + Read the current row values. + @param table Table handle + @param buf row buffer + @param fields Table fields + @param read_all true if all columns are read. + */ + + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_replication_applier_status_by_coordinator(); + +public: + ~table_replication_applier_status_by_coordinator(); + + /** Table share. */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_replication_applier_status_by_worker.cc b/storage/perfschema/table_replication_applier_status_by_worker.cc new file mode 100644 index 00000000000..65a1e277805 --- /dev/null +++ b/storage/perfschema/table_replication_applier_status_by_worker.cc @@ -0,0 +1,412 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_replication_applier_status_by_worker.cc + Table replication_applier_status_by_worker (implementation). +*/ + +#define HAVE_REPLICATION + +#include "my_global.h" +#include "table_replication_applier_status_by_worker.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "slave.h" +//#include "rpl_info.h" +#include "rpl_rli.h" +#include "rpl_mi.h" +#include "sql_parse.h" +//#include "rpl_rli_pdb.h" +//#include "rpl_msr.h" /*Multi source replication */ + +THR_LOCK table_replication_applier_status_by_worker::m_table_lock; + +PFS_engine_table_share +table_replication_applier_status_by_worker::m_share= +{ + { C_STRING_WITH_LEN("replication_applier_status_by_worker") }, + &pfs_readonly_acl, + table_replication_applier_status_by_worker::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_replication_applier_status_by_worker::get_row_count, /*records*/ + sizeof(pos_t), /* ref length */ + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE replication_applier_status_by_worker(" + "CHANNEL_NAME CHAR(64) collate utf8_general_ci not null," + "WORKER_ID BIGINT UNSIGNED not null," + "THREAD_ID BIGINT UNSIGNED," + "SERVICE_STATE ENUM('ON','OFF') not null," + "LAST_SEEN_TRANSACTION CHAR(57) not null," + "LAST_ERROR_NUMBER INTEGER not null," + "LAST_ERROR_MESSAGE VARCHAR(1024) not null," + "LAST_ERROR_TIMESTAMP TIMESTAMP(0) not null)") }, + false /* perpetual */ +}; + +PFS_engine_table* table_replication_applier_status_by_worker::create(void) +{ + return new table_replication_applier_status_by_worker(); +} + +table_replication_applier_status_by_worker + ::table_replication_applier_status_by_worker() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +table_replication_applier_status_by_worker + ::~table_replication_applier_status_by_worker() +{} + +void table_replication_applier_status_by_worker::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +ha_rows table_replication_applier_status_by_worker::get_row_count() +{ + /* + Return an estimate, number of master info's multipled by worker threads + */ + return master_info_index->master_info_hash.records*32; +} + + +int table_replication_applier_status_by_worker::rnd_next(void) +{ + Slave_worker *worker; + Master_info *mi; + size_t wc; + + mysql_mutex_lock(&LOCK_active_mi); + + for (m_pos.set_at(&m_next_pos); + m_pos.has_more_channels(master_info_index->master_info_hash.records); + m_pos.next_channel()) + { + mi= (Master_info *)my_hash_element(&master_info_index->master_info_hash, m_pos.m_index_1); + + if (mi && mi->host[0]) + { + wc= mi->rli->get_worker_count(); + + if (wc == 0) + { + /* Single Thread Slave */ + make_row(mi); + m_next_pos.set_channel_after(&m_pos); + channel_map.unlock(); + return 0; + } + + for (; m_pos.m_index_2 < wc; m_pos.next_worker()) + { + /* Multi Thread Slave */ + + worker = mi->rli->get_worker(m_pos.m_index_2); + if (worker) + { + make_row(worker); + m_next_pos.set_after(&m_pos); + channel_map.unlock(); + return 0; + } + } + } + } + + mysql_mutex_unlock(&LOCK_active_mi); + return HA_ERR_END_OF_FILE; +} + +int table_replication_applier_status_by_worker::rnd_pos(const void *pos) +{ + Slave_worker *worker; + Master_info *mi; + int res= HA_ERR_RECORD_DELETED; + size_t wc; + + set_position(pos); + + mysql_mutex_lock(&LOCK_active_mi); + + mi= (Master_info *)my_hash_element(&master_info_index->master_info_hash, m_pos.m_index_1); + + if (!mi || !mi->host[0]) + goto end; + + wc = mi->rli->get_worker_count(); + + if (wc == 0) + { + /* Single Thread Slave */ + make_row(mi); + res=0; + } + else + { + /* Multi Thread Slave */ + if (m_pos.m_index_2 < wc) + { + worker = mi->rli->get_worker(m_pos.m_index_2); + if (worker != NULL) + { + make_row(worker); + res=0; + } + } + } + +end: + mysql_mutex_unlock(&LOCK_active_mi); + return res; +} + +/** + Function to display SQL Thread's status as part of + 'replication_applier_status_by_worker' in single threaded slave mode. + + @param[in] Master_info + + @retval void +*/ +void table_replication_applier_status_by_worker::make_row(Master_info *mi) +{ + m_row_exists= false; + + m_row.worker_id= 0; + + m_row.thread_id= 0; + + DBUG_ASSERT(mi != NULL); + DBUG_ASSERT(mi->rli != NULL); + + mysql_mutex_lock(&mi->rli->data_lock); + + m_row.channel_name_length= strlen(mi->get_channel()); + memcpy(m_row.channel_name, (char*)mi->get_channel(), m_row.channel_name_length); + + if (mi->rli->slave_running) + { + PSI_thread *psi= thd_get_psi(mi->rli->info_thd); + PFS_thread *pfs= reinterpret_cast<PFS_thread *> (psi); + if(pfs) + { + m_row.thread_id= pfs->m_thread_internal_id; + m_row.thread_id_is_null= false; + } + else + m_row.thread_id_is_null= true; + } + else + m_row.thread_id_is_null= true; + + if (mi->rli->slave_running) + m_row.service_state= PS_RPL_YES; + else + m_row.service_state= PS_RPL_NO; + + if (mi->rli->currently_executing_gtid.type == GTID_GROUP) + { + global_sid_lock->rdlock(); + m_row.last_seen_transaction_length= + mi->rli->currently_executing_gtid.to_string(global_sid_map, + m_row.last_seen_transaction); + global_sid_lock->unlock(); + } + else if (mi->rli->currently_executing_gtid.type == ANONYMOUS_GROUP) + { + m_row.last_seen_transaction_length= + mi->rli->currently_executing_gtid.to_string((rpl_sid *)NULL, + m_row.last_seen_transaction); + } + else + { + /* + For SQL thread currently_executing_gtid, type is set to + AUTOMATIC_GROUP when the SQL thread is not executing any + transaction. For this case, the field should be empty. + */ + DBUG_ASSERT(mi->rli->currently_executing_gtid.type == AUTOMATIC_GROUP); + m_row.last_seen_transaction_length= 0; + memcpy(m_row.last_seen_transaction, "", 1); + } + + mysql_mutex_lock(&mi->rli->err_lock); + + m_row.last_error_number= (long int) mi->rli->last_error().number; + m_row.last_error_message_length= 0; + m_row.last_error_timestamp= 0; + + /** if error, set error message and timestamp */ + if (m_row.last_error_number) + { + char *temp_store= (char*) mi->rli->last_error().message; + m_row.last_error_message_length= strlen(temp_store); + memcpy(m_row.last_error_message, temp_store, + m_row.last_error_message_length); + + /** time in millisecond since epoch */ + m_row.last_error_timestamp= (ulonglong)mi->rli->last_error().skr*1000000; + } + + mysql_mutex_unlock(&mi->rli->err_lock); + mysql_mutex_unlock(&mi->rli->data_lock); + m_row_exists= true; +} + +void table_replication_applier_status_by_worker::make_row(Slave_worker *w) +{ + m_row_exists= false; + + m_row.worker_id= w->get_internal_id(); + + m_row.thread_id= 0; + + m_row.channel_name_length= strlen(w->get_channel()); + memcpy(m_row.channel_name, (char*)w->get_channel(), m_row.channel_name_length); + + mysql_mutex_lock(&w->jobs_lock); + if (w->running_status == Slave_worker::RUNNING) + { + PSI_thread *psi= thd_get_psi(w->info_thd); + PFS_thread *pfs= reinterpret_cast<PFS_thread *> (psi); + if(pfs) + { + m_row.thread_id= pfs->m_thread_internal_id; + m_row.thread_id_is_null= false; + } + else /* no instrumentation found */ + m_row.thread_id_is_null= true; + } + else + m_row.thread_id_is_null= true; + + if (w->running_status == Slave_worker::RUNNING) + m_row.service_state= PS_RPL_YES; + else + m_row.service_state= PS_RPL_NO; + + m_row.last_error_number= (unsigned int) w->last_error().number; + + if (w->currently_executing_gtid.type == GTID_GROUP) + { + global_sid_lock->rdlock(); + m_row.last_seen_transaction_length= + w->currently_executing_gtid.to_string(global_sid_map, + m_row.last_seen_transaction); + global_sid_lock->unlock(); + } + else if (w->currently_executing_gtid.type == ANONYMOUS_GROUP) + { + m_row.last_seen_transaction_length= + w->currently_executing_gtid.to_string((rpl_sid *)NULL, + m_row.last_seen_transaction); + } + else + { + /* + For worker->currently_executing_gtid, type is set to + AUTOMATIC_GROUP when the worker is not executing any + transaction. For this case, the field should be empty. + */ + DBUG_ASSERT(w->currently_executing_gtid.type == AUTOMATIC_GROUP); + m_row.last_seen_transaction_length= 0; + memcpy(m_row.last_seen_transaction, "", 1); + } + + m_row.last_error_number= (unsigned int) w->last_error().number; + m_row.last_error_message_length= 0; + m_row.last_error_timestamp= 0; + + /** if error, set error message and timestamp */ + if (m_row.last_error_number) + { + char * temp_store= (char*)w->last_error().message; + m_row.last_error_message_length= strlen(temp_store); + memcpy(m_row.last_error_message, w->last_error().message, + m_row.last_error_message_length); + + /** time in millisecond since epoch */ + m_row.last_error_timestamp= (ulonglong)w->last_error().skr*1000000; + } + mysql_mutex_unlock(&w->jobs_lock); + + m_row_exists= true; +} + +int table_replication_applier_status_by_worker + ::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; + + 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: /** channel_name */ + set_field_char_utf8(f, m_row.channel_name, m_row.channel_name_length); + break; + case 1: /*worker_id*/ + set_field_ulonglong(f, m_row.worker_id); + break; + case 2: /*thread_id*/ + if(m_row.thread_id_is_null) + f->set_null(); + else + set_field_ulonglong(f, m_row.thread_id); + break; + case 3: /*service_state*/ + set_field_enum(f, m_row.service_state); + break; + case 4: /*last_seen_transaction*/ + set_field_char_utf8(f, m_row.last_seen_transaction, m_row.last_seen_transaction_length); + break; + case 5: /*last_error_number*/ + set_field_ulong(f, m_row.last_error_number); + break; + case 6: /*last_error_message*/ + set_field_varchar_utf8(f, m_row.last_error_message, m_row.last_error_message_length); + break; + case 7: /*last_error_timestamp*/ + set_field_timestamp(f, m_row.last_error_timestamp); + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} diff --git a/storage/perfschema/table_replication_applier_status_by_worker.h b/storage/perfschema/table_replication_applier_status_by_worker.h new file mode 100644 index 00000000000..0a881dae73f --- /dev/null +++ b/storage/perfschema/table_replication_applier_status_by_worker.h @@ -0,0 +1,182 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#ifndef TABLE_REPLICATION_APPLIER_STATUS_BY_WORKER_H +#define TABLE_REPLICATION_APPLIER_STATUS_BY_WORKER_H + +/** + @file storage/perfschema/table_replication_applier_status_by_worker.h + Table replication_applier_status_by_worker (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "rpl_mi.h" +#include "mysql_com.h" +//#include "rpl_rli_pdb.h" +//#include "rpl_msr.h" +//#include "rpl_info.h" /*CHANNEL_NAME_LENGTH*/ +#include "my_thread.h" + +class Slave_worker; +class Master_info; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +#ifndef ENUM_RPL_YES_NO +#define ENUM_RPL_YES_NO +/** enumerated values for service_state of worker thread*/ +enum enum_rpl_yes_no { + PS_RPL_YES= 1, /* service_state= on */ + PS_RPL_NO /* service_state= off */ +}; +#endif + +/* + A row in worker's table. The fields with string values have an additional + length field denoted by <field_name>_length. +*/ +struct st_row_worker { + + char channel_name[CHANNEL_NAME_LENGTH]; + uint channel_name_length; + /* + worker_id is added to the table because thread is killed at STOP SLAVE + but the status needs to show up, so worker_id is used as a permanent + identifier. + */ + ulonglong worker_id; + ulonglong thread_id; + uint thread_id_is_null; + enum_rpl_yes_no service_state; + char last_seen_transaction[GTID_MAX_STR_LENGTH + 1]; + uint last_seen_transaction_length; + uint last_error_number; + char last_error_message[MAX_SLAVE_ERRMSG]; + uint last_error_message_length; + ulonglong last_error_timestamp; +}; + +/** + Position in table replication_applier_status_by_worker. + Index 1 for replication channel. + Index 2 for worker: + - position [0] is for Single Thread Slave (Master_info) + - position [1] .. [N] is for Multi Thread Slave (Slave_worker) +*/ +struct pos_replication_applier_status_by_worker : public PFS_double_index +{ + + pos_replication_applier_status_by_worker() : PFS_double_index(0, 0) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 0; + } + + inline bool has_more_channels(uint num) + { return (m_index_1 < num); } + + inline void next_channel(void) + { + m_index_1++; + m_index_2= 0; + } + + inline void next_worker() + { + m_index_2++; + } + + inline void + set_channel_after(const pos_replication_applier_status_by_worker *other) + { + m_index_1 = other->m_index_1 + 1; + m_index_2 = 0; + } +}; + + +/** Table PERFORMANCE_SCHEMA.replication_applier_status_by_worker */ +class table_replication_applier_status_by_worker: public PFS_engine_table +{ + typedef pos_replication_applier_status_by_worker pos_t; + +private: + void make_row(Slave_worker *); + /* + Master_info to construct a row to display SQL Thread's status + information in STS mode + */ + void make_row(Master_info *); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + /** current row*/ + st_row_worker m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + +protected: + /** + Read the current row values. + @param table Table handle + @param buf row buffer + @param fields Table fields + @param read_all true if all columns are read. + */ + + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_replication_applier_status_by_worker(); + +public: + ~table_replication_applier_status_by_worker(); + + /** Table share. */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_replication_connection_configuration.cc b/storage/perfschema/table_replication_connection_configuration.cc new file mode 100644 index 00000000000..219d6b8259c --- /dev/null +++ b/storage/perfschema/table_replication_connection_configuration.cc @@ -0,0 +1,331 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_replication_connection_configuration.cc + Table replication_connection_configuration (implementation). +*/ + +#define HAVE_REPLICATION + +#include "my_global.h" +#include "table_replication_connection_configuration.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "slave.h" +//#include "rpl_info.h" +#include "rpl_rli.h" +#include "rpl_mi.h" +#include "sql_parse.h" +//#include "rpl_msr.h" /* Multisource replciation */ + +THR_LOCK table_replication_connection_configuration::m_table_lock; + +PFS_engine_table_share +table_replication_connection_configuration::m_share= +{ + { C_STRING_WITH_LEN("replication_connection_configuration") }, + &pfs_readonly_acl, + table_replication_connection_configuration::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_replication_connection_configuration::get_row_count, /* records */ + sizeof(pos_t), /* ref length */ + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE replication_connection_configuration(" + "CHANNEL_NAME CHAR(64) collate utf8_general_ci not null," + "HOST CHAR(60) collate utf8_bin not null," + "PORT INTEGER not null," + "USER CHAR(32) collate utf8_bin not null," + "NETWORK_INTERFACE CHAR(60) collate utf8_bin not null," + "AUTO_POSITION ENUM('1','0') not null," + "SSL_ALLOWED ENUM('YES','NO','IGNORED') not null," + "SSL_CA_FILE VARCHAR(512) not null," + "SSL_CA_PATH VARCHAR(512) not null," + "SSL_CERTIFICATE VARCHAR(512) not null," + "SSL_CIPHER VARCHAR(512) not null," + "SSL_KEY VARCHAR(512) not null," + "SSL_VERIFY_SERVER_CERTIFICATE ENUM('YES','NO') not null," + "SSL_CRL_FILE VARCHAR(255) not null," + "SSL_CRL_PATH VARCHAR(255) not null," + "CONNECTION_RETRY_INTERVAL INTEGER not null," + "CONNECTION_RETRY_COUNT BIGINT unsigned not null," + "HEARTBEAT_INTERVAL DOUBLE(10,3) unsigned not null COMMENT 'Number of seconds after which a heartbeat will be sent .'," + "TLS_VERSION VARCHAR(255) not null)") }, + false /* perpetual */ +}; + + +PFS_engine_table* table_replication_connection_configuration::create(void) +{ + return new table_replication_connection_configuration(); +} + +table_replication_connection_configuration + ::table_replication_connection_configuration() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +table_replication_connection_configuration + ::~table_replication_connection_configuration() +{} + +void table_replication_connection_configuration::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +ha_rows table_replication_connection_configuration::get_row_count() +{ + /* + We actually give the MAX_CHANNELS rather than the current + number of channels + */ + + return master_info_index->master_info_hash.records; +} + +int table_replication_connection_configuration::rnd_next(void) +{ + Master_info *mi; + + mysql_mutex_lock(&LOCK_active_mi); + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < master_info_index->master_info_hash.records; + m_pos.next()) + { + mi= (Master_info *)my_hash_element(&master_info_index->master_info_hash, m_pos.m_index); + + if (mi && mi->host[0]) + { + make_row(mi); + m_next_pos.set_after(&m_pos); + channel_map.unlock(); + return 0; + } + } + + mysql_mutex_unlock(&LOCK_active_mi); + return HA_ERR_END_OF_FILE; +} + +int table_replication_connection_configuration::rnd_pos(const void *pos) +{ + Master_info *mi; + int res= HA_ERR_RECORD_DELETED; + + mysql_mutex_lock(&LOCK_active_mi); + + set_position(pos); + + if ((mi= (Master_info *)my_hash_element(&master_info_index->master_info_hash, m_pos.m_index))) + { + make_row(mi); + res= 0; + } + + mysql_mutex_unlock(&LOCK_active_mi); + return res; +} + +void table_replication_connection_configuration::make_row(Master_info *mi) +{ + char * temp_store; + + m_row_exists= false; + + + DBUG_ASSERT(mi != NULL); + + mysql_mutex_lock(&mi->data_lock); + mysql_mutex_lock(&mi->rli.data_lock); + + m_row.channel_name_length= mi->connection_name.length; + memcpy(m_row.channel_name, mi->connection_name.str, m_row.channel_name_length); + + m_row.host_length= strlen(mi->host); + memcpy(m_row.host, mi->host, m_row.host_length); + + m_row.port= (unsigned int) mi->port; + + /* can't the user be NULL? */ + temp_store= (char*)mi->user; + m_row.user_length= strlen(temp_store); + memcpy(m_row.user, temp_store, m_row.user_length); + + temp_store= const_cast<char*>(""); //(char*)mi->bind_addr; + m_row.network_interface_length= strlen(temp_store); + memcpy(m_row.network_interface, temp_store, m_row.network_interface_length); + + if (mi->using_gtid) + m_row.auto_position= PS_RPL_YES; + else + m_row.auto_position= PS_RPL_NO; + +#ifdef HAVE_OPENSSL + m_row.ssl_allowed= mi->ssl? PS_SSL_ALLOWED_YES:PS_SSL_ALLOWED_NO; +#else + m_row.ssl_allowed= mi->ssl? PS_SSL_ALLOWED_IGNORED:PS_SSL_ALLOWED_NO; +#endif + + temp_store= (char*)mi->ssl_ca; + m_row.ssl_ca_file_length= strlen(temp_store); + memcpy(m_row.ssl_ca_file, temp_store, m_row.ssl_ca_file_length); + + temp_store= (char*)mi->ssl_capath; + m_row.ssl_ca_path_length= strlen(temp_store); + memcpy(m_row.ssl_ca_path, temp_store, m_row.ssl_ca_path_length); + + temp_store= (char*)mi->ssl_cert; + m_row.ssl_certificate_length= strlen(temp_store); + memcpy(m_row.ssl_certificate, temp_store, m_row.ssl_certificate_length); + + temp_store= (char*)mi->ssl_cipher; + m_row.ssl_cipher_length= strlen(temp_store); + memcpy(m_row.ssl_cipher, temp_store, m_row.ssl_cipher_length); + + temp_store= (char*)mi->ssl_key; + m_row.ssl_key_length= strlen(temp_store); + memcpy(m_row.ssl_key, temp_store, m_row.ssl_key_length); + + if (mi->ssl_verify_server_cert) + m_row.ssl_verify_server_certificate= PS_RPL_YES; + else + m_row.ssl_verify_server_certificate= PS_RPL_NO; + + temp_store= (char*)mi->ssl_crl; + m_row.ssl_crl_file_length= strlen(temp_store); + memcpy(m_row.ssl_crl_file, temp_store, m_row.ssl_crl_file_length); + + temp_store= (char*)mi->ssl_crlpath; + m_row.ssl_crl_path_length= strlen(temp_store); + memcpy(m_row.ssl_crl_path, temp_store, m_row.ssl_crl_path_length); + + m_row.connection_retry_interval= (unsigned int) mi->connect_retry; + + m_row.connection_retry_count= 0; //(ulong) mi->retry_count; + + m_row.heartbeat_interval= (double)mi->heartbeat_period; + + temp_store= (char*)""; //mi->tls_version; + m_row.tls_version_length= strlen(temp_store); + memcpy(m_row.tls_version, temp_store, m_row.tls_version_length); + + mysql_mutex_unlock(&mi->rli.data_lock); + mysql_mutex_unlock(&mi->data_lock); + + m_row_exists= true; +} + +int table_replication_connection_configuration::read_row_values(TABLE *table, + unsigned char *, + Field **fields, + bool read_all) +{ + Field *f; + + if (unlikely(! m_row_exists)) + return HA_ERR_RECORD_DELETED; + + 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: /** channel_name */ + set_field_char_utf8(f, m_row.channel_name, m_row.channel_name_length); + break; + case 1: /** host */ + set_field_char_utf8(f, m_row.host, m_row.host_length); + break; + case 2: /** port */ + set_field_ulong(f, m_row.port); + break; + case 3: /** user */ + set_field_char_utf8(f, m_row.user, m_row.user_length); + break; + case 4: /** network_interface */ + set_field_char_utf8(f, m_row.network_interface, + m_row.network_interface_length); + break; + case 5: /** auto_position */ + set_field_enum(f, m_row.auto_position); + break; + case 6: /** ssl_allowed */ + set_field_enum(f, m_row. ssl_allowed); + break; + case 7: /**ssl_ca_file */ + set_field_varchar_utf8(f, m_row.ssl_ca_file, + m_row.ssl_ca_file_length); + break; + case 8: /** ssl_ca_path */ + set_field_varchar_utf8(f, m_row.ssl_ca_path, + m_row.ssl_ca_path_length); + break; + case 9: /** ssl_certificate */ + set_field_varchar_utf8(f, m_row.ssl_certificate, + m_row.ssl_certificate_length); + break; + case 10: /** ssl_cipher */ + set_field_varchar_utf8(f, m_row.ssl_cipher, m_row.ssl_cipher_length); + break; + case 11: /** ssl_key */ + set_field_varchar_utf8(f, m_row.ssl_key, m_row.ssl_key_length); + break; + case 12: /** ssl_verify_server_certificate */ + set_field_enum(f, m_row.ssl_verify_server_certificate); + break; + case 13: /** ssl_crl_file */ + set_field_varchar_utf8(f, m_row.ssl_crl_file, + m_row.ssl_crl_file_length); + break; + case 14: /** ssl_crl_path */ + set_field_varchar_utf8(f, m_row.ssl_crl_path, + m_row.ssl_crl_path_length); + break; + case 15: /** connection_retry_interval */ + set_field_ulong(f, m_row.connection_retry_interval); + break; + case 16: /** connect_retry_count */ + set_field_ulonglong(f, m_row.connection_retry_count); + break; + case 17:/** number of seconds after which heartbeat will be sent */ + set_field_double(f, m_row.heartbeat_interval); + break; + case 18: /** tls_version */ + set_field_varchar_utf8(f, m_row.tls_version, + m_row.tls_version_length); + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} diff --git a/storage/perfschema/table_replication_connection_configuration.h b/storage/perfschema/table_replication_connection_configuration.h new file mode 100644 index 00000000000..d1c8861cf0d --- /dev/null +++ b/storage/perfschema/table_replication_connection_configuration.h @@ -0,0 +1,152 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#ifndef TABLE_REPLICATION_CONFIGURATION_H +#define TABLE_REPLICATION_CONFIGURATION_H + +/** + @file storage/perfschema/table_replication_connection_configuration.h + Table replication_connection_configuration (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "rpl_mi.h" +#include "mysql_com.h" +#include "my_thread.h" +//#include "rpl_msr.h" +//#include "rpl_info.h" /* CHANNEL_NAME_LENGTH*/ + +class Master_info; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +#ifndef ENUM_RPL_YES_NO +#define ENUM_RPL_YES_NO +enum enum_rpl_yes_no { + PS_RPL_YES= 1, + PS_RPL_NO +}; +#endif + +/** enum values for SSL_Allowed*/ +enum enum_ssl_allowed { + PS_SSL_ALLOWED_YES= 1, + PS_SSL_ALLOWED_NO, + PS_SSL_ALLOWED_IGNORED +}; + +/** + A row in the table. The fields with string values have an additional + length field denoted by <field_name>_length. +*/ +struct st_row_connect_config { + char channel_name[CHANNEL_NAME_LENGTH]; + uint channel_name_length; + char host[HOSTNAME_LENGTH]; + uint host_length; + uint port; + char user[USERNAME_LENGTH]; + uint user_length; + char network_interface[HOSTNAME_LENGTH]; + uint network_interface_length; + enum_rpl_yes_no auto_position; + enum_ssl_allowed ssl_allowed; + char ssl_ca_file[FN_REFLEN]; + uint ssl_ca_file_length; + char ssl_ca_path[FN_REFLEN]; + uint ssl_ca_path_length; + char ssl_certificate[FN_REFLEN]; + uint ssl_certificate_length; + char ssl_cipher[FN_REFLEN]; + uint ssl_cipher_length; + char ssl_key[FN_REFLEN]; + uint ssl_key_length; + enum_rpl_yes_no ssl_verify_server_certificate; + char ssl_crl_file[FN_REFLEN]; + uint ssl_crl_file_length; + char ssl_crl_path[FN_REFLEN]; + uint ssl_crl_path_length; + uint connection_retry_interval; + ulong connection_retry_count; + double heartbeat_interval; + char tls_version[FN_REFLEN]; + uint tls_version_length; +}; + +/** Table PERFORMANCE_SCHEMA.TABLE_REPLICATION_CONNECTION_CONFIGURATION. */ +class table_replication_connection_configuration: public PFS_engine_table +{ + typedef PFS_simple_index pos_t; + +private: + void make_row(Master_info *); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + /** True if the current row exists. */ + bool m_row_exists; + /** Current row */ + st_row_connect_config m_row; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + +protected: + /** + Read the current row values. + @param table Table handle + @param buf row buffer + @param fields Table fields + @param read_all true if all columns are read. + */ + + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_replication_connection_configuration(); + +public: + ~table_replication_connection_configuration(); + + /** Table share. */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_replication_connection_status.cc b/storage/perfschema/table_replication_connection_status.cc new file mode 100644 index 00000000000..eb1d3c8ef71 --- /dev/null +++ b/storage/perfschema/table_replication_connection_status.cc @@ -0,0 +1,440 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_replication_connection_status.cc + Table replication_connection_status (implementation). +*/ + +#define HAVE_REPLICATION + +#include "my_global.h" +#include "table_replication_connection_status.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "slave.h" +//#include "rpl_info.h" +#include "rpl_rli.h" +#include "rpl_mi.h" +#include "sql_parse.h" +//#include "rpl_msr.h" /* Multi source replication */ +#include "log.h" +//#include "rpl_group_replication.h" + +/* + Callbacks implementation for GROUP_REPLICATION_CONNECTION_STATUS_CALLBACKS. +*/ +static void set_channel_name(void* const context, const char& value, + size_t length) +{ +} + +static void set_group_name(void* const context, const char& value, + size_t length) +{ + struct st_row_connect_status* row= + static_cast<struct st_row_connect_status*>(context); + const size_t max= UUID_LENGTH; + length= std::min(length, max); + + row->group_name_is_null= false; + memcpy(row->group_name, &value, length); +} + +static void set_source_uuid(void* const context, const char& value, + size_t length) +{ + struct st_row_connect_status* row= + static_cast<struct st_row_connect_status*>(context); + const size_t max= UUID_LENGTH; + length= std::min(length, max); + + row->source_uuid_is_null= false; + memcpy(row->source_uuid, &value, length); +} + +static void set_service_state(void* const context, bool value) +{ + struct st_row_connect_status* row= + static_cast<struct st_row_connect_status*>(context); + + row->service_state= value ? PS_RPL_CONNECT_SERVICE_STATE_YES + : PS_RPL_CONNECT_SERVICE_STATE_NO; +} + + +THR_LOCK table_replication_connection_status::m_table_lock; + + +/* Numbers in varchar count utf8 characters. */ +static const TABLE_FIELD_TYPE field_types[]= +{ + { + {C_STRING_WITH_LEN("CHANNEL_NAME")}, + {C_STRING_WITH_LEN("char(64)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("GROUP_NAME")}, + {C_STRING_WITH_LEN("char(36)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("SOURCE_UUID")}, + {C_STRING_WITH_LEN("char(36)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("THREAD_ID")}, + {C_STRING_WITH_LEN("bigint(20)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("SERVICE_STATE")}, + {C_STRING_WITH_LEN("enum('ON','OFF','CONNECTING')")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("COUNT_RECEIVED_HEARTBEATS")}, + {C_STRING_WITH_LEN("bigint(20)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("LAST_HEARTBEAT_TIMESTAMP")}, + {C_STRING_WITH_LEN("timestamp")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("RECEIVED_TRANSACTION_SET")}, + {C_STRING_WITH_LEN("longtext")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("LAST_ERROR_NUMBER")}, + {C_STRING_WITH_LEN("int(11)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("LAST_ERROR_MESSAGE")}, + {C_STRING_WITH_LEN("varchar(1024)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("LAST_ERROR_TIMESTAMP")}, + {C_STRING_WITH_LEN("timestamp")}, + {NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_replication_connection_status::m_field_def= { 11, field_types }; + +PFS_engine_table_share +table_replication_connection_status::m_share= +{ + { C_STRING_WITH_LEN("replication_connection_status") }, + &pfs_readonly_acl, + table_replication_connection_status::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_replication_connection_status::get_row_count, /* records */ + sizeof(pos_t), /* ref length */ + &m_table_lock, + &m_field_def, + false, /* checked */ + false /* perpetual */ +}; + +PFS_engine_table* table_replication_connection_status::create(void) +{ + return new table_replication_connection_status(); +} + +table_replication_connection_status::table_replication_connection_status() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{ +} + +table_replication_connection_status::~table_replication_connection_status() +{ +} + +void table_replication_connection_status::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +ha_rows table_replication_connection_status::get_row_count() +{ + /*A lock is not needed for an estimate */ + return channel_map.get_max_channels(); +} + + + +int table_replication_connection_status::rnd_next(void) +{ + Master_info *mi= NULL; + channel_map.rdlock(); + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < channel_map.get_max_channels(); + m_pos.next()) + { + mi= channel_map.get_mi_at_pos(m_pos.m_index); + + if (mi && mi->host[0]) + { + make_row(mi); + m_next_pos.set_after(&m_pos); + channel_map.unlock(); + return 0; + } + } + + channel_map.unlock(); + return HA_ERR_END_OF_FILE; +} + +int table_replication_connection_status::rnd_pos(const void *pos) +{ + Master_info *mi; + int res= HA_ERR_RECORD_DELETED; + + set_position(pos); + + channel_map.rdlock(); + + if ((mi= channel_map.get_mi_at_pos(m_pos.m_index))) + { + make_row(mi); + res= 0; + } + + channel_map.unlock(); + return res; +} + +void table_replication_connection_status::make_row(Master_info *mi) +{ + DBUG_ENTER("table_replication_connection_status::make_row"); + m_row_exists= false; + bool error= false; + + /* Default values */ + m_row.group_name_is_null= true; + m_row.source_uuid_is_null= true; + m_row.thread_id_is_null= true; + m_row.service_state= PS_RPL_CONNECT_SERVICE_STATE_NO; + + DBUG_ASSERT(mi != NULL); + DBUG_ASSERT(mi->rli != NULL); + + mysql_mutex_lock(&mi->data_lock); + mysql_mutex_lock(&mi->rli->data_lock); + + m_row.channel_name_length= mi->get_channel() ? strlen(mi->get_channel()):0; + memcpy(m_row.channel_name, mi->get_channel(), m_row.channel_name_length); + + if (is_group_replication_plugin_loaded() && + channel_map.is_group_replication_channel_name(mi->get_channel(), true)) + { + /* + Group Replication applier channel. + Set callbacks on GROUP_REPLICATION_GROUP_MEMBER_STATS_CALLBACKS. + */ + const GROUP_REPLICATION_CONNECTION_STATUS_CALLBACKS callbacks= + { + &m_row, + &set_channel_name, + &set_group_name, + &set_source_uuid, + &set_service_state, + }; + + // Query plugin and let callbacks do their job. + if (get_group_replication_connection_status_info(callbacks)) + { + DBUG_PRINT("info", ("Group Replication stats not available!")); + } + } + else + { + /* Slave channel. */ + if (mi->master_uuid[0] != 0) + { + memcpy(m_row.source_uuid, mi->master_uuid, UUID_LENGTH); + m_row.source_uuid_is_null= false; + } + + if (mi->slave_running == MYSQL_SLAVE_RUN_CONNECT) + m_row.service_state= PS_RPL_CONNECT_SERVICE_STATE_YES; + else + { + if (mi->slave_running == MYSQL_SLAVE_RUN_NOT_CONNECT) + m_row.service_state= PS_RPL_CONNECT_SERVICE_STATE_CONNECTING; + else + m_row.service_state= PS_RPL_CONNECT_SERVICE_STATE_NO; + } + } + + if (mi->slave_running == MYSQL_SLAVE_RUN_CONNECT) + { + PSI_thread *psi= thd_get_psi(mi->info_thd); + PFS_thread *pfs= reinterpret_cast<PFS_thread *> (psi); + if(pfs) + { + m_row.thread_id= pfs->m_thread_internal_id; + m_row.thread_id_is_null= false; + } + } + + m_row.count_received_heartbeats= mi->received_heartbeats; + /* + Time in Milliseconds since epoch. active_mi->last_heartbeat contains + number of seconds so we multiply by 1000000. + */ + m_row.last_heartbeat_timestamp= (ulonglong)mi->last_heartbeat*1000000; + + { + global_sid_lock->wrlock(); + const Gtid_set* io_gtid_set= mi->rli->get_gtid_set(); + + if ((m_row.received_transaction_set_length= + io_gtid_set->to_string(&m_row.received_transaction_set)) < 0) + { + my_free(m_row.received_transaction_set); + m_row.received_transaction_set_length= 0; + global_sid_lock->unlock(); + error= true; + goto end; + } + global_sid_lock->unlock(); + } + + /* Errors */ + mysql_mutex_lock(&mi->err_lock); + mysql_mutex_lock(&mi->rli->err_lock); + m_row.last_error_number= (unsigned int) mi->last_error().number; + m_row.last_error_message_length= 0; + m_row.last_error_timestamp= 0; + + /** If error, set error message and timestamp */ + if (m_row.last_error_number) + { + char* temp_store= (char*)mi->last_error().message; + m_row.last_error_message_length= strlen(temp_store); + memcpy(m_row.last_error_message, temp_store, + m_row.last_error_message_length); + + /* + Time in millisecond since epoch. active_mi->last_error().skr contains + number of seconds so we multiply by 1000000. */ + m_row.last_error_timestamp= (ulonglong)mi->last_error().skr*1000000; + } + mysql_mutex_unlock(&mi->rli->err_lock); + mysql_mutex_unlock(&mi->err_lock); + +end: + mysql_mutex_unlock(&mi->rli->data_lock); + mysql_mutex_unlock(&mi->data_lock); + + if (!error) + m_row_exists= true; + DBUG_VOID_RETURN; +} + +int table_replication_connection_status::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; + + 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: /** channel_name*/ + set_field_char_utf8(f, m_row.channel_name,m_row.channel_name_length); + break; + case 1: /** group_name */ + if (m_row.group_name_is_null) + f->set_null(); + else + set_field_char_utf8(f, m_row.group_name, UUID_LENGTH); + break; + case 2: /** source_uuid */ + if (m_row.source_uuid_is_null) + f->set_null(); + else + set_field_char_utf8(f, m_row.source_uuid, UUID_LENGTH); + break; + case 3: /** thread_id */ + if(m_row.thread_id_is_null) + f->set_null(); + else + set_field_ulonglong(f, m_row.thread_id); + break; + case 4: /** service_state */ + set_field_enum(f, m_row.service_state); + break; + case 5: /** number of heartbeat events received **/ + set_field_ulonglong(f, m_row.count_received_heartbeats); + break; + case 6: /** time of receipt of last heartbeat event **/ + set_field_timestamp(f, m_row.last_heartbeat_timestamp); + break; + case 7: /** received_transaction_set */ + set_field_longtext_utf8(f, m_row.received_transaction_set, + m_row.received_transaction_set_length); + break; + case 8: /*last_error_number*/ + set_field_ulong(f, m_row.last_error_number); + break; + case 9: /*last_error_message*/ + set_field_varchar_utf8(f, m_row.last_error_message, + m_row.last_error_message_length); + break; + case 10: /*last_error_timestamp*/ + set_field_timestamp(f, m_row.last_error_timestamp); + break; + default: + DBUG_ASSERT(false); + } + } + } + m_row.cleanup(); + + return 0; +} diff --git a/storage/perfschema/table_replication_connection_status.h b/storage/perfschema/table_replication_connection_status.h new file mode 100644 index 00000000000..a1a5eb116bc --- /dev/null +++ b/storage/perfschema/table_replication_connection_status.h @@ -0,0 +1,150 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#ifndef TABLE_REPLICATION_CONNECTION_STATUS_H +#define TABLE_REPLICATION_CONNECTION_STATUS_H + +/** + @file storage/perfschema/table_replication_connection_status.h + Table replication_connection_status (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "rpl_mi.h" +#include "rpl_reporting.h" /* MAX_SLAVE_ERRMSG */ +#include "mysql_com.h" +//#include "rpl_msr.h" +//#include "rpl_info.h" /*CHANNEL_NAME_LENGTH */ +#include "my_thread.h" + +class Master_info; + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +#ifndef ENUM_RPL_YES_NO +#define ENUM_RPL_YES_NO +enum enum_rpl_yes_no { + PS_RPL_YES= 1, + PS_RPL_NO +}; +#endif + +enum enum_rpl_connect_status_service_state { + PS_RPL_CONNECT_SERVICE_STATE_YES= 1, + PS_RPL_CONNECT_SERVICE_STATE_NO, + PS_RPL_CONNECT_SERVICE_STATE_CONNECTING +}; + +/* + A row in the table. The fields with string values have an additional + length field denoted by <field_name>_length. +*/ +struct st_row_connect_status { + char group_name[NAME_LEN]; + bool group_name_is_null; + char channel_name[CHANNEL_NAME_LENGTH]; + uint channel_name_length; + char source_uuid[11]; // typeof(server_id) == uint32 + bool source_uuid_is_null; + ulonglong thread_id; + bool thread_id_is_null; + enum_rpl_connect_status_service_state service_state; + ulonglong count_received_heartbeats; + ulonglong last_heartbeat_timestamp; + char* received_transaction_set; + int received_transaction_set_length; + uint last_error_number; + char last_error_message[MAX_SLAVE_ERRMSG]; + uint last_error_message_length; + ulonglong last_error_timestamp; + + st_row_connect_status() : received_transaction_set(NULL) {} + + void cleanup() + { + if (received_transaction_set != NULL) + { + my_free(received_transaction_set); + received_transaction_set= NULL; + } + } +}; + + +/** Table PERFORMANCE_SCHEMA.REPLICATION_CONNECTION_STATUS. */ +class table_replication_connection_status: public PFS_engine_table +{ + typedef PFS_simple_index pos_t; + +private: + void make_row(Master_info *mi); + + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + /** True if the current row exists. */ + bool m_row_exists; + /** Current row */ + st_row_connect_status m_row; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + +protected: + /** + Read the current row values. + @param table Table handle + @param buf row buffer + @param fields Table fields + @param read_all true if all columns are read. + */ + + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_replication_connection_status(); + +public: + ~table_replication_connection_status(); + + /** Table share. */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_replication_group_member_stats.cc b/storage/perfschema/table_replication_group_member_stats.cc new file mode 100644 index 00000000000..9c7f61817d1 --- /dev/null +++ b/storage/perfschema/table_replication_group_member_stats.cc @@ -0,0 +1,372 @@ +/* + Copyright (c) 2014, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_replication_group_member_stats.cc + Table replication_group_member_stats (implementation). +*/ + +#define HAVE_REPLICATION + +#include "my_global.h" +#include "table_replication_group_member_stats.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "log.h" +#include "rpl_group_replication.h" + +/* + Callbacks implementation for GROUP_REPLICATION_GROUP_MEMBER_STATS_CALLBACKS. +*/ +static void set_channel_name(void* const context, const char& value, + size_t length) +{ + struct st_row_group_member_stats* row= + static_cast<struct st_row_group_member_stats*>(context); + const size_t max= CHANNEL_NAME_LENGTH; + length= std::min(length, max); + + row->channel_name_length= length; + memcpy(row->channel_name, &value, length); +} + +static void set_view_id(void* const context, const char& value, size_t length) +{ + struct st_row_group_member_stats* row= + static_cast<struct st_row_group_member_stats*>(context); + const size_t max= HOSTNAME_LENGTH; + length= std::min(length, max); + + row->view_id_length= length; + memcpy(row->view_id, &value, length); +} + +static void set_member_id(void* const context, const char& value, size_t length) +{ + struct st_row_group_member_stats* row= + static_cast<struct st_row_group_member_stats*>(context); + const size_t max= UUID_LENGTH; + length= std::min(length, max); + + row->member_id_length= length; + memcpy(row->member_id, &value, length); +} + +static void set_transactions_committed(void* const context, const char& value, + size_t length) +{ + struct st_row_group_member_stats* row= + static_cast<struct st_row_group_member_stats*>(context); + + if (row->trx_committed != NULL) + my_free(row->trx_committed); + + row->trx_committed_length= length; + row->trx_committed= (char*) my_malloc(PSI_NOT_INSTRUMENTED, + length, + MYF(0)); + memcpy(row->trx_committed, &value, length); +} + +static void set_last_conflict_free_transaction(void* const context, + const char& value, size_t length) +{ + struct st_row_group_member_stats* row= + static_cast<struct st_row_group_member_stats*>(context); + const size_t max= Gtid::MAX_TEXT_LENGTH+1; + length= std::min(length, max); + + row->last_cert_trx_length= length; + memcpy(row->last_cert_trx, &value, length); +} + +static void set_transactions_in_queue(void* const context, + unsigned long long int value) +{ + struct st_row_group_member_stats* row= + static_cast<struct st_row_group_member_stats*>(context); + row->trx_in_queue= value; +} + +static void set_transactions_certified(void* const context, + unsigned long long int value) +{ + struct st_row_group_member_stats* row= + static_cast<struct st_row_group_member_stats*>(context); + row->trx_checked= value; +} + +static void set_transactions_conflicts_detected(void* const context, + unsigned long long int value) +{ + struct st_row_group_member_stats* row= + static_cast<struct st_row_group_member_stats*>(context); + row->trx_conflicts= value; +} + +static void set_transactions_rows_in_validation(void* const context, + unsigned long long int value) +{ + struct st_row_group_member_stats* row= + static_cast<struct st_row_group_member_stats*>(context); + row->trx_rows_validating= value; +} + + +THR_LOCK table_replication_group_member_stats::m_table_lock; + +static const TABLE_FIELD_TYPE field_types[]= +{ + { + {C_STRING_WITH_LEN("CHANNEL_NAME")}, + {C_STRING_WITH_LEN("char(64)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("VIEW_ID")}, + {C_STRING_WITH_LEN("char(60)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("MEMBER_ID")}, + {C_STRING_WITH_LEN("char(36)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("COUNT_TRANSACTIONS_IN_QUEUE")}, + {C_STRING_WITH_LEN("bigint")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("COUNT_TRANSACTIONS_CHECKED")}, + {C_STRING_WITH_LEN("bigint")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("COUNT_CONFLICTS_DETECTED")}, + {C_STRING_WITH_LEN("bigint")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("COUNT_TRANSACTIONS_ROWS_VALIDATING")}, + {C_STRING_WITH_LEN("bigint")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("TRANSACTIONS_COMMITTED_ALL_MEMBERS")}, + {C_STRING_WITH_LEN("longtext")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("LAST_CONFLICT_FREE_TRANSACTION")}, + {C_STRING_WITH_LEN("text")}, + {NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_replication_group_member_stats::m_field_def= +{ 9, field_types }; + +PFS_engine_table_share +table_replication_group_member_stats::m_share= +{ + { C_STRING_WITH_LEN("replication_group_member_stats") }, + &pfs_readonly_acl, + &table_replication_group_member_stats::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_replication_group_member_stats::get_row_count, + sizeof(PFS_simple_index), /* ref length */ + &m_table_lock, + &m_field_def, + false, /* checked */ + false /* perpetual */ +}; + +PFS_engine_table* table_replication_group_member_stats::create(void) +{ + return new table_replication_group_member_stats(); +} + +table_replication_group_member_stats::table_replication_group_member_stats() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{ + m_row.trx_committed= NULL; +} + +table_replication_group_member_stats::~table_replication_group_member_stats() +{ + if (m_row.trx_committed != NULL) + { + my_free(m_row.trx_committed); + m_row.trx_committed= NULL; + } +} + +void table_replication_group_member_stats::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +ha_rows table_replication_group_member_stats::get_row_count() +{ + uint row_count= 0; + + if (is_group_replication_plugin_loaded()) + row_count= 1; + + return row_count; +} + +int table_replication_group_member_stats::rnd_next(void) +{ + if (!is_group_replication_plugin_loaded()) + return HA_ERR_END_OF_FILE; + + m_pos.set_at(&m_next_pos); + if (m_pos.m_index == 0) + { + make_row(); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int table_replication_group_member_stats::rnd_pos(const void *pos) +{ + if (get_row_count() == 0) + return HA_ERR_END_OF_FILE; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < 1); + make_row(); + + return 0; +} + +void table_replication_group_member_stats::make_row() +{ + DBUG_ENTER("table_replication_group_member_stats::make_row"); + // Set default values. + m_row_exists= false; + m_row.channel_name_length= 0; + m_row.view_id_length= 0; + m_row.member_id_length= 0; + m_row.trx_committed_length= 0; + m_row.last_cert_trx_length= 0; + m_row.trx_in_queue= 0; + m_row.trx_checked= 0; + m_row.trx_conflicts= 0; + m_row.trx_rows_validating= 0; + + // Set callbacks on GROUP_REPLICATION_GROUP_MEMBER_STATS_CALLBACKS. + const GROUP_REPLICATION_GROUP_MEMBER_STATS_CALLBACKS callbacks= + { + &m_row, + &set_channel_name, + &set_view_id, + &set_member_id, + &set_transactions_committed, + &set_last_conflict_free_transaction, + &set_transactions_in_queue, + &set_transactions_certified, + &set_transactions_conflicts_detected, + &set_transactions_rows_in_validation, + }; + + // Query plugin and let callbacks do their job. + if (get_group_replication_group_member_stats_info(callbacks)) + { + DBUG_PRINT("info", ("Group Replication stats not available!")); + } + else + { + m_row_exists= true; + } + + DBUG_VOID_RETURN; +} + + +int table_replication_group_member_stats::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; + + DBUG_ASSERT(table->s->null_bytes == 0); + 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: /** channel_name */ + set_field_char_utf8(f, m_row.channel_name, + m_row.channel_name_length); + break; + case 1: /** view id */ + set_field_char_utf8(f, m_row.view_id, m_row.view_id_length); + break; + case 2: /** member_id */ + set_field_char_utf8(f, m_row.member_id, m_row.member_id_length); + break; + case 3: /** transaction_in_queue */ + set_field_ulonglong(f, m_row.trx_in_queue); + break; + case 4: /** transactions_certified */ + set_field_ulonglong(f, m_row.trx_checked); + break; + case 5: /** negatively_certified_transaction */ + set_field_ulonglong(f, m_row.trx_conflicts); + break; + case 6: /** certification_db_size */ + set_field_ulonglong(f, m_row.trx_rows_validating); + break; + case 7: /** stable_set */ + set_field_longtext_utf8(f, m_row.trx_committed, + m_row.trx_committed_length); + break; + case 8: /** last_certified_transaction */ + set_field_longtext_utf8(f, m_row.last_cert_trx, + m_row.last_cert_trx_length); + + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} diff --git a/storage/perfschema/table_replication_group_member_stats.h b/storage/perfschema/table_replication_group_member_stats.h new file mode 100644 index 00000000000..f2fcaf553b4 --- /dev/null +++ b/storage/perfschema/table_replication_group_member_stats.h @@ -0,0 +1,116 @@ +/* + Copyright (c) 2014, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#ifndef TABLE_REPLICATION_GROUP_MEMBER_STATS_H +#define TABLE_REPLICATION_GROUP_MEMBER_STATS_H + +/** + @file storage/perfschema/table_replication_group_member_stats.h + Table replication_group_member_stats (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "mysql_com.h" +//#include "rpl_info.h" +//#include "rpl_gtid.h" +//#include <mysql/plugin_group_replication.h> + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row in node status table. The fields with string values have an additional + length field denoted by <field_name>_length. +*/ + +struct st_row_group_member_stats { + char channel_name[CHANNEL_NAME_LENGTH]; + uint channel_name_length; + char view_id[HOSTNAME_LENGTH]; + uint view_id_length; + char member_id[11]; // typeof(server_id) == uint32 + uint member_id_length; + ulonglong trx_in_queue; + ulonglong trx_checked; + ulonglong trx_conflicts; + ulonglong trx_rows_validating; + char *trx_committed; + size_t trx_committed_length; + char last_cert_trx[GTID_MAX_STR_LENGTH + 1]; + int last_cert_trx_length; +}; + +/** Table PERFORMANCE_SCHEMA.REPLICATION_GROUP_MEMBER_STATS. */ +class table_replication_group_member_stats: public PFS_engine_table +{ +private: + void make_row(); + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + /** True if the current row exists. */ + bool m_row_exists; + /** Current row */ + st_row_group_member_stats m_row; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; + +protected: + /** + Read the current row values. + @param table Table handle + @param buf row buffer + @param fields Table fields + @param read_all true if all columns are read. + */ + + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_replication_group_member_stats(); + +public: + ~table_replication_group_member_stats(); + + /** Table share. */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +}; + +/** @} */ +#endif + diff --git a/storage/perfschema/table_replication_group_members.cc b/storage/perfschema/table_replication_group_members.cc new file mode 100644 index 00000000000..d86052d687f --- /dev/null +++ b/storage/perfschema/table_replication_group_members.cc @@ -0,0 +1,281 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_replication_group_members.cc + Table replication_group_members (implementation). +*/ + +#define HAVE_REPLICATION + +#include "my_global.h" +#include "table_replication_group_members.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "log.h" +//#include "rpl_group_replication.h" + +/* + Callbacks implementation for GROUP_REPLICATION_GROUP_MEMBERS_CALLBACKS. +*/ +static void set_channel_name(void* const context, const char& value, + size_t length) +{ + struct st_row_group_members* row= + static_cast<struct st_row_group_members*>(context); + const size_t max= CHANNEL_NAME_LENGTH; + length= std::min(length, max); + + row->channel_name_length= length; + memcpy(row->channel_name, &value, length); +} + +static void set_member_id(void* const context, const char& value, + size_t length) +{ + struct st_row_group_members* row= + static_cast<struct st_row_group_members*>(context); + const size_t max= UUID_LENGTH; + length= std::min(length, max); + + row->member_id_length= length; + memcpy(row->member_id, &value, length); +} + +static void set_member_host(void* const context, const char& value, + size_t length) +{ + struct st_row_group_members* row= + static_cast<struct st_row_group_members*>(context); + const size_t max= HOSTNAME_LENGTH; + length= std::min(length, max); + + row->member_host_length= length; + memcpy(row->member_host, &value, length); +} + +static void set_member_port(void* const context, unsigned int value) +{ + struct st_row_group_members* row= + static_cast<struct st_row_group_members*>(context); + row->member_port= value; +} + +static void set_member_state(void* const context, const char& value, + size_t length) +{ + struct st_row_group_members* row= + static_cast<struct st_row_group_members*>(context); + const size_t max= NAME_LEN; + length= std::min(length, max); + + row->member_state_length= length; + memcpy(row->member_state, &value, length); +} + + +THR_LOCK table_replication_group_members::m_table_lock; + +/* Numbers in varchar count utf8 characters. */ +static const TABLE_FIELD_TYPE field_types[]= +{ + { + {C_STRING_WITH_LEN("CHANNEL_NAME")}, + {C_STRING_WITH_LEN("char(64)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("MEMBER_ID")}, + {C_STRING_WITH_LEN("char(36)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("MEMBER_HOST")}, + {C_STRING_WITH_LEN("char(60)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("MEMBER_PORT")}, + {C_STRING_WITH_LEN("int(11)")}, + {NULL, 0} + }, + { + {C_STRING_WITH_LEN("MEMBER_STATE")}, + {C_STRING_WITH_LEN("char(64)")}, + {NULL, 0} + } +}; + +TABLE_FIELD_DEF +table_replication_group_members::m_field_def= +{ 5, field_types }; + +PFS_engine_table_share +table_replication_group_members::m_share= +{ + { C_STRING_WITH_LEN("replication_group_members") }, + &pfs_readonly_acl, + &table_replication_group_members::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_replication_group_members::get_row_count, + sizeof(PFS_simple_index), /* ref length */ + &m_table_lock, + &m_field_def, + false, /* checked */ + false /* perpetual */ +}; + +PFS_engine_table* table_replication_group_members::create(void) +{ + return new table_replication_group_members(); +} + +table_replication_group_members::table_replication_group_members() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +table_replication_group_members::~table_replication_group_members() +{} + +void table_replication_group_members::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +ha_rows table_replication_group_members::get_row_count() +{ + return get_group_replication_members_number_info(); +} + +int table_replication_group_members::rnd_next(void) +{ + if (!is_group_replication_plugin_loaded()) + return HA_ERR_END_OF_FILE; + + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < get_row_count(); + m_pos.next()) + { + make_row(m_pos.m_index); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int table_replication_group_members::rnd_pos(const void *pos) +{ + if (!is_group_replication_plugin_loaded()) + return HA_ERR_END_OF_FILE; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < get_row_count()); + make_row(m_pos.m_index); + + return 0; +} + +void table_replication_group_members::make_row(uint index) +{ + DBUG_ENTER("table_replication_group_members::make_row"); + // Set default values. + m_row_exists= false; + m_row.channel_name_length= 0; + m_row.member_id_length= 0; + m_row.member_host_length= 0; + m_row.member_port= 0; + m_row.member_state_length= 0; + + // Set callbacks on GROUP_REPLICATION_GROUP_MEMBERS_CALLBACKS. + const GROUP_REPLICATION_GROUP_MEMBERS_CALLBACKS callbacks= + { + &m_row, + &set_channel_name, + &set_member_id, + &set_member_host, + &set_member_port, + &set_member_state, + }; + + // Query plugin and let callbacks do their job. + if (get_group_replication_group_members_info(index, callbacks)) + { + DBUG_PRINT("info", ("Group Replication stats not available!")); + } + else + { + m_row_exists= true; + } + + DBUG_VOID_RETURN; +} + + +int table_replication_group_members::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; + + 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: /** channel_name */ + set_field_char_utf8(f, m_row.channel_name, m_row.channel_name_length); + break; + case 1: /** member_id */ + set_field_char_utf8(f, m_row.member_id, m_row.member_id_length); + break; + case 2: /** member_host */ + set_field_char_utf8(f, m_row.member_host, m_row.member_host_length); + break; + case 3: /** member_port */ + if (m_row.member_port > 0) + set_field_ulong(f, m_row.member_port); + else + f->set_null(); + break; + case 4: /** member_state */ + set_field_char_utf8(f, m_row.member_state, m_row.member_state_length); + break; + default: + DBUG_ASSERT(false); + } + } + } + return 0; +} diff --git a/storage/perfschema/table_replication_group_members.h b/storage/perfschema/table_replication_group_members.h new file mode 100644 index 00000000000..8ce875eba3a --- /dev/null +++ b/storage/perfschema/table_replication_group_members.h @@ -0,0 +1,108 @@ +/* + Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + + +#ifndef TABLE_REPLICATION_GROUP_MEMBERS_H +#define TABLE_REPLICATION_GROUP_MEMBERS_H + +/** + @file storage/perfschema/table_replication_group_members.h + Table replication_group_members (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "mysql_com.h" +//#include "rpl_info.h" +//#include <mysql/plugin_group_replication.h> + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row in connection nodes table. The fields with string values have an additional + length field denoted by <field_name>_length. +*/ +struct st_row_group_members { + char channel_name[CHANNEL_NAME_LENGTH]; + uint channel_name_length; + char member_id[11]; // typeof(server_id) == uint32 + uint member_id_length; + char member_host[HOSTNAME_LENGTH]; + uint member_host_length; + uint member_port; + char member_state[NAME_LEN]; + uint member_state_length; +}; + +/** Table PERFORMANCE_SCHEMA.replication_group_members. */ +class table_replication_group_members: public PFS_engine_table +{ +private: + void make_row(uint index); + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + /** True if the current row exists. */ + bool m_row_exists; + /** Current row */ + st_row_group_members m_row; + /** Current position. */ + PFS_simple_index m_pos; + /** Next position. */ + PFS_simple_index m_next_pos; + +protected: + /** + Read the current row values. + @param table Table handle + @param buf row buffer + @param fields Table fields + @param read_all true if all columns are read. + */ + + virtual int read_row_values(TABLE *table, + unsigned char *buf, + Field **fields, + bool read_all); + + table_replication_group_members(); + +public: + ~table_replication_group_members(); + + /** Table share. */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + virtual int rnd_next(); + virtual int rnd_pos(const void *pos); + virtual void reset_position(void); + +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_session_account_connect_attrs.cc b/storage/perfschema/table_session_account_connect_attrs.cc index fcb4f001ba7..0e8be68d602 100644 --- a/storage/perfschema/table_session_account_connect_attrs.cc +++ b/storage/perfschema/table_session_account_connect_attrs.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -29,12 +29,11 @@ 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, + &pfs_readonly_world_acl, + table_session_account_connect_attrs::create, NULL, /* write_row */ NULL, /* delete_all_rows */ - NULL, /* get_row_count */ - 1000, /* records */ + cursor_by_thread_connect_attr::get_row_count, sizeof(pos_connect_attr_by_thread_by_attr), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE session_account_connect_attrs(" @@ -42,7 +41,8 @@ table_session_account_connect_attrs::m_share= "ATTR_NAME VARCHAR(32) NOT NULL," "ATTR_VALUE VARCHAR(1024)," "ORDINAL_POSITION INT" - ") CHARACTER SET utf8 COLLATE utf8_bin") } + ") CHARACTER SET utf8 COLLATE utf8_bin") }, + false /* perpetual */ }; PFS_engine_table* table_session_account_connect_attrs::create() diff --git a/storage/perfschema/table_session_account_connect_attrs.h b/storage/perfschema/table_session_account_connect_attrs.h index 483001fcb91..043f83da184 100644 --- a/storage/perfschema/table_session_account_connect_attrs.h +++ b/storage/perfschema/table_session_account_connect_attrs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2012, 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, version 2.0, diff --git a/storage/perfschema/table_session_connect.cc b/storage/perfschema/table_session_connect.cc index 0d12ab2562e..09f32feaa4d 100644 --- a/storage/perfschema/table_session_connect.cc +++ b/storage/perfschema/table_session_connect.cc @@ -22,13 +22,14 @@ #include <my_global.h> #include "table_session_connect.h" +#include "field.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, */ + m_copy_session_connect_attrs= (char *) my_malloc(PSI_INSTRUMENT_ME, session_connect_attrs_size_per_thread, MYF(0)); } @@ -146,7 +147,7 @@ bool read_nth_attr(const char *connect_attrs, if (idx == ordinal) *attr_name_length= copy_length; - + /* read the value */ if (parse_length_encoded_string(&ptr, attr_value, max_attr_value, ©_length, @@ -168,8 +169,8 @@ bool read_nth_attr(const char *connect_attrs, void table_session_connect::make_row(PFS_thread *pfs, uint ordinal) { - pfs_lock lock; - pfs_lock session_lock; + pfs_optimistic_state lock; + pfs_optimistic_state session_lock; PFS_thread_class *safe_class; const CHARSET_INFO *cs; diff --git a/storage/perfschema/table_session_connect.h b/storage/perfschema/table_session_connect.h index ee1019fe7f2..55433e2571a 100644 --- a/storage/perfschema/table_session_connect.h +++ b/storage/perfschema/table_session_connect.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2012, 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, version 2.0, @@ -59,6 +59,7 @@ struct row_session_connect_attrs ulong m_ordinal_position; }; +/** Abstract table PERFORMANCE_SCHEMA.SESSION_CONNECT_ATTRS. */ class table_session_connect : public cursor_by_thread_connect_attr { protected: diff --git a/storage/perfschema/table_session_connect_attrs.cc b/storage/perfschema/table_session_connect_attrs.cc index cb7b64a7fdf..cc3fae46290 100644 --- a/storage/perfschema/table_session_connect_attrs.cc +++ b/storage/perfschema/table_session_connect_attrs.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -30,11 +30,10 @@ table_session_connect_attrs::m_share= { { C_STRING_WITH_LEN("session_connect_attrs") }, &pfs_readonly_acl, - &table_session_connect_attrs::create, + table_session_connect_attrs::create, NULL, /* write_row */ NULL, /* delete_all_rows */ - NULL, /* get_row_count */ - 1000, /* records */ + cursor_by_thread_connect_attr::get_row_count, sizeof(pos_connect_attr_by_thread_by_attr), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE session_connect_attrs(" @@ -42,7 +41,8 @@ table_session_connect_attrs::m_share= "ATTR_NAME VARCHAR(32) NOT NULL," "ATTR_VALUE VARCHAR(1024)," "ORDINAL_POSITION INT" - ") CHARACTER SET utf8 COLLATE utf8_bin") } + ") CHARACTER SET utf8 COLLATE utf8_bin") }, + false /* perpetual */ }; PFS_engine_table* table_session_connect_attrs::create() diff --git a/storage/perfschema/table_session_connect_attrs.h b/storage/perfschema/table_session_connect_attrs.h index 927c3a92af2..09b9d1c49e1 100644 --- a/storage/perfschema/table_session_connect_attrs.h +++ b/storage/perfschema/table_session_connect_attrs.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2012, 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, version 2.0, diff --git a/storage/perfschema/table_session_status.cc b/storage/perfschema/table_session_status.cc new file mode 100644 index 00000000000..acff99caed0 --- /dev/null +++ b/storage/perfschema/table_session_status.cc @@ -0,0 +1,185 @@ +/* Copyright (c) 2015, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_session_status.cc + Table SESSION_STATUS (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "table_session_status.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_global.h" + +THR_LOCK table_session_status::m_table_lock; + +PFS_engine_table_share +table_session_status::m_share= +{ + { C_STRING_WITH_LEN("session_status") }, + &pfs_readonly_world_acl, + table_session_status::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_session_status::get_row_count, + sizeof(pos_t), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE session_status(" + "VARIABLE_NAME VARCHAR(64) not null," + "VARIABLE_VALUE VARCHAR(1024))") }, + true /* perpetual */ +}; + +PFS_engine_table* +table_session_status::create(void) +{ + return new table_session_status(); +} + +ha_rows table_session_status::get_row_count(void) +{ + mysql_mutex_lock(&LOCK_status); + ha_rows status_var_count= all_status_vars.elements; + mysql_mutex_unlock(&LOCK_status); + return status_var_count; +} + +table_session_status::table_session_status() + : PFS_engine_table(&m_share, &m_pos), + m_status_cache(false), m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_session_status::reset_position(void) +{ + m_pos.m_index = 0; + m_next_pos.m_index = 0; +} + +int table_session_status::rnd_init(bool scan) +{ + /* Build a cache of all status variables for this thread. */ + m_status_cache.materialize_all(current_thd); + + /* Record the current number of status variables to detect subsequent changes. */ + ulonglong status_version= m_status_cache.get_status_array_version(); + + /* + The table context holds the current version of the global status array. + If scan == true, then allocate a new context from mem_root and store in TLS. + If scan == false, then restore from TLS. + */ + m_context= (table_session_status_context *)current_thd->alloc(sizeof(table_session_status_context)); + new(m_context) table_session_status_context(status_version, !scan); + return 0; +} + +int table_session_status::rnd_next(void) +{ + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < m_status_cache.size(); + m_pos.next()) + { + if (m_status_cache.is_materialized()) + { + const Status_variable *stat_var= m_status_cache.get(m_pos.m_index); + if (stat_var != NULL) + { + make_row(stat_var); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + return HA_ERR_END_OF_FILE; +} + +int +table_session_status::rnd_pos(const void *pos) +{ + /* If global status array has changed, do nothing. */ // TODO: warning + if (!m_context->versions_match()) + return HA_ERR_RECORD_DELETED; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < m_status_cache.size()); + + if (m_status_cache.is_materialized()) + { + const Status_variable *stat_var= m_status_cache.get(m_pos.m_index); + if (stat_var != NULL) + { + make_row(stat_var); + return 0; + } + } + + return HA_ERR_RECORD_DELETED; +} + +void table_session_status +::make_row(const Status_variable *status_var) +{ + m_row_exists= false; + m_row.m_variable_name.make_row(status_var->m_name, status_var->m_name_length); + m_row.m_variable_value.make_row(status_var); + m_row_exists= true; +} + +int table_session_status +::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: /* VARIABLE_NAME */ + set_field_varchar_utf8(f, m_row.m_variable_name.m_str, m_row.m_variable_name.m_length); + break; + case 1: /* VARIABLE_VALUE */ + m_row.m_variable_value.set_field(f); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_session_status.h b/storage/perfschema/table_session_status.h new file mode 100644 index 00000000000..24634fe47b5 --- /dev/null +++ b/storage/perfschema/table_session_status.h @@ -0,0 +1,119 @@ +/* Copyright (c) 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_SESSION_STATUS_H +#define TABLE_SESSION_STATUS_H + +/** + @file storage/perfschema/table_session_status.h + Table SESSION_STATUS (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" +#include "pfs_variable.h" +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.SESSION_STATUS. +*/ +struct row_session_status +{ + /** Column THREAD_ID. */ + ulonglong m_thread_internal_id; + /** Column VARIABLE_NAME. */ + PFS_variable_name_row m_variable_name; + /** Column VARIABLE_VALUE. */ + PFS_variable_value_row m_variable_value; +}; + +/** + Store and retrieve table state information for queries that reinstantiate + the table object. +*/ +class table_session_status_context : public PFS_table_context +{ +public: + table_session_status_context(ulonglong current_version, bool restore) : + PFS_table_context(current_version, restore, THR_PFS_SS) { } +}; + +/** Table PERFORMANCE_SCHEMA.SESSION_STATUS. */ +class table_session_status : public PFS_engine_table +{ + typedef PFS_simple_index pos_t; + +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + + 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_session_status(); + +public: + ~table_session_status() + {} + +protected: + void make_row(const Status_variable *status_var); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current THD variables. */ + PFS_status_variable_cache m_status_cache; + /** Current row. */ + row_session_status m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + + /** Table context with global status array version. */ + table_session_status_context *m_context; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_session_variables.cc b/storage/perfschema/table_session_variables.cc new file mode 100644 index 00000000000..f293af4a1cf --- /dev/null +++ b/storage/perfschema/table_session_variables.cc @@ -0,0 +1,187 @@ +/* Copyright (c) 2015, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_session_variables.cc + Table SESSION_VARIABLES (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "table_session_variables.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_global.h" + +THR_LOCK table_session_variables::m_table_lock; + +PFS_engine_table_share +table_session_variables::m_share= +{ + { C_STRING_WITH_LEN("session_variables") }, + &pfs_readonly_world_acl, + table_session_variables::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_session_variables::get_row_count, + sizeof(pos_t), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE session_variables(" + "VARIABLE_NAME VARCHAR(64) not null," + "VARIABLE_VALUE VARCHAR(1024))") }, + true /* perpetual */ +}; + +PFS_engine_table* +table_session_variables::create(void) +{ + return new table_session_variables(); +} + +ha_rows table_session_variables::get_row_count(void) +{ + mysql_mutex_lock(&LOCK_plugin_delete); + mysql_rwlock_rdlock(&LOCK_system_variables_hash); + ha_rows system_var_count= get_system_variable_hash_records(); + mysql_rwlock_unlock(&LOCK_system_variables_hash); + mysql_mutex_unlock(&LOCK_plugin_delete); + return system_var_count; +} + +table_session_variables::table_session_variables() + : PFS_engine_table(&m_share, &m_pos), + m_sysvar_cache(false), m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_session_variables::reset_position(void) +{ + m_pos.m_index = 0; + m_next_pos.m_index = 0; +} + +int table_session_variables::rnd_init(bool scan) +{ + /* Build a cache of system variables for this thread. */ + m_sysvar_cache.materialize_all(current_thd); + + /* Record the version of the system variable hash. */ + ulonglong hash_version= m_sysvar_cache.get_sysvar_hash_version(); + + /* + The table context holds the current version of the system variable hash. + If scan == true, then allocate a new context from mem_root and store in TLS. + If scan == false, then restore from TLS. + */ + m_context= (table_session_variables_context *)current_thd->alloc(sizeof(table_session_variables_context)); + new(m_context) table_session_variables_context(hash_version, !scan); + return 0; +} + +int table_session_variables::rnd_next(void) +{ + for (m_pos.set_at(&m_next_pos); + m_pos.m_index < m_sysvar_cache.size(); + m_pos.next()) + { + if (m_sysvar_cache.is_materialized()) + { + const System_variable *system_var= m_sysvar_cache.get(m_pos.m_index); + if (system_var != NULL) + { + make_row(system_var); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + return HA_ERR_END_OF_FILE; +} + +int table_session_variables::rnd_pos(const void *pos) +{ + /* If system variable hash changes, do nothing. */ + if (!m_context->versions_match()) + return HA_ERR_RECORD_DELETED; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index < m_sysvar_cache.size()); + + if (m_sysvar_cache.is_materialized()) + { + const System_variable *system_var= m_sysvar_cache.get(m_pos.m_index); + if (system_var != NULL) + { + make_row(system_var); + return 0; + } + } + return HA_ERR_RECORD_DELETED; +} + +void table_session_variables +::make_row(const System_variable *system_var) +{ + m_row_exists= false; + if (system_var->is_null() || system_var->is_ignored()) + return; + m_row.m_variable_name.make_row(system_var->m_name, system_var->m_name_length); + m_row.m_variable_value.make_row(system_var); + m_row_exists= true; +} + +int table_session_variables +::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: /* VARIABLE_NAME */ + set_field_varchar_utf8(f, m_row.m_variable_name.m_str, m_row.m_variable_name.m_length); + break; + case 1: /* VARIABLE_VALUE */ + m_row.m_variable_value.set_field(f); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_session_variables.h b/storage/perfschema/table_session_variables.h new file mode 100644 index 00000000000..576bf73edbb --- /dev/null +++ b/storage/perfschema/table_session_variables.h @@ -0,0 +1,117 @@ +/* Copyright (c) 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_SESSION_VARIABLES_H +#define TABLE_SESSION_VARIABLES_H + +/** + @file storage/perfschema/table_session_variables.h + Table SESSION_VARIABLES (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" +#include "pfs_variable.h" +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + Store and retrieve table state information during queries that reinstantiate + the table object. +*/ +class table_session_variables_context : public PFS_table_context +{ +public: + table_session_variables_context(ulonglong hash_version, bool restore) : + PFS_table_context(hash_version, restore, THR_PFS_SV) {} +}; + +/** + A row of table + PERFORMANCE_SCHEMA.SESSION_VARIABLES. +*/ +struct row_session_variables +{ + /** Column VARIABLE_NAME. */ + PFS_variable_name_row m_variable_name; + /** Column VARIABLE_VALUE. */ + PFS_variable_value_row m_variable_value; +}; + +/** Table PERFORMANCE_SCHEMA.SESSION_VARIABLES. */ +class table_session_variables : public PFS_engine_table +{ + typedef PFS_simple_index pos_t; + +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + + 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_session_variables(); + +public: + ~table_session_variables() + {} + +protected: + void make_row(const System_variable *system_var); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current THD variables. */ + PFS_system_variable_cache m_sysvar_cache; + /** Current row. */ + row_session_variables m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + + /** Table context with system variable hash version. */ + table_session_variables_context *m_context; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_setup_actors.cc b/storage/perfschema/table_setup_actors.cc index 007081a83c9..5004dbc7c16 100644 --- a/storage/perfschema/table_setup_actors.cc +++ b/storage/perfschema/table_setup_actors.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,13 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_setup_actors::m_table_lock; @@ -45,13 +47,15 @@ table_setup_actors::m_share= 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)") } + "USER CHAR(" USERNAME_CHAR_LENGTH_STR ") collate utf8_bin default '%' not null," + "ROLE CHAR(16) collate utf8_bin default '%' not null," + "ENABLED ENUM('YES', 'NO') not null," + "HISTORY ENUM('YES', 'NO') not null)") }, + false /* perpetual */ }; PFS_engine_table* table_setup_actors::create() @@ -69,6 +73,10 @@ int table_setup_actors::write_row(TABLE *table, const unsigned char *buf, String *user= &user_data; String *host= &host_data; String *role= &role_data; + enum_yes_no enabled_value= ENUM_YES; + enum_yes_no history_value= ENUM_YES; + bool enabled; + bool history; for (; (f= *fields) ; fields++) { @@ -85,16 +93,34 @@ int table_setup_actors::write_row(TABLE *table, const unsigned char *buf, case 2: /* ROLE */ role= get_field_char_utf8(f, &role_data); break; + case 3: /* ENABLED */ + enabled_value= (enum_yes_no) get_field_enum(f); + break; + case 4: /* HISTORY */ + history_value= (enum_yes_no) get_field_enum(f); + break; default: DBUG_ASSERT(false); } } } + /* 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 HISTORY */ + if ((history_value != ENUM_YES) && (history_value != ENUM_NO)) + return HA_ERR_NO_REFERENCED_ROW; + + /* Reject if any of user/host/role is not provided */ if (user->length() == 0 || host->length() == 0 || role->length() == 0) return HA_ERR_WRONG_COMMAND; - return insert_setup_actor(user, host, role); + enabled= (enabled_value == ENUM_YES) ? true : false; + history= (history_value == ENUM_YES) ? true : false; + + return insert_setup_actor(user, host, role, enabled, history); } int table_setup_actors::delete_all_rows(void) @@ -104,7 +130,7 @@ int table_setup_actors::delete_all_rows(void) ha_rows table_setup_actors::get_row_count(void) { - return setup_actor_count(); + return global_setup_actor_container.get_row_count(); } table_setup_actors::table_setup_actors() @@ -122,17 +148,14 @@ 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()) + m_pos.set_at(&m_next_pos); + PFS_setup_actor_iterator it= global_setup_actor_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - 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; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -144,9 +167,8 @@ int table_setup_actors::rnd_pos(const void *pos) 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()) + pfs= global_setup_actor_container.get(m_pos.m_index); + if (pfs != NULL) { make_row(pfs); return 0; @@ -157,7 +179,7 @@ int table_setup_actors::rnd_pos(const void *pos) void table_setup_actors::make_row(PFS_setup_actor *pfs) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; @@ -181,6 +203,9 @@ void table_setup_actors::make_row(PFS_setup_actor *pfs) return; memcpy(m_row.m_rolename, pfs->m_rolename, m_row.m_rolename_length); + m_row.m_enabled_ptr= &pfs->m_enabled; + m_row.m_history_ptr= &pfs->m_history; + if (pfs->m_lock.end_optimistic_lock(&lock)) m_row_exists= true; } @@ -213,6 +238,12 @@ int table_setup_actors::read_row_values(TABLE *table, case 2: /* ROLE */ set_field_char_utf8(f, m_row.m_rolename, m_row.m_rolename_length); break; + case 3: /* ENABLED */ + set_field_enum(f, (*m_row.m_enabled_ptr) ? ENUM_YES : ENUM_NO); + break; + case 4: /* HISTORY */ + set_field_enum(f, (*m_row.m_history_ptr) ? ENUM_YES : ENUM_NO); + break; default: DBUG_ASSERT(false); } @@ -227,7 +258,9 @@ int table_setup_actors::update_row_values(TABLE *table, const unsigned char *new_buf, Field **fields) { + int result; Field *f; + enum_yes_no value; for (; (f= *fields) ; fields++) { @@ -239,6 +272,19 @@ int table_setup_actors::update_row_values(TABLE *table, case 1: /* USER */ case 2: /* ROLE */ 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: /* HISTORY */ + value= (enum_yes_no) get_field_enum(f); + /* Reject illegal enum values in HISTORY */ + if ((value != ENUM_YES) && (value != ENUM_NO)) + return HA_ERR_NO_REFERENCED_ROW; + *m_row.m_history_ptr= (value == ENUM_YES) ? true : false; break; default: DBUG_ASSERT(false); @@ -246,7 +292,8 @@ int table_setup_actors::update_row_values(TABLE *table, } } - return 0; + result= update_setup_actors_derived_flags(); + return result; } int table_setup_actors::delete_row_values(TABLE *table, diff --git a/storage/perfschema/table_setup_actors.h b/storage/perfschema/table_setup_actors.h index 6bfc480a9c5..32a603317b9 100644 --- a/storage/perfschema/table_setup_actors.h +++ b/storage/perfschema/table_setup_actors.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, version 2.0, @@ -52,6 +52,10 @@ struct row_setup_actors char m_rolename[16]; /** Length in bytes of @c m_rolename. */ uint m_rolename_length; + /** Column ENABLED. */ + bool *m_enabled_ptr; + /** Column HISTORY. */ + bool *m_history_ptr; }; /** Table PERFORMANCE_SCHEMA.SETUP_ACTORS. */ diff --git a/storage/perfschema/table_setup_consumers.cc b/storage/perfschema/table_setup_consumers.cc index 7355efae45b..1745bf35c56 100644 --- a/storage/perfschema/table_setup_consumers.cc +++ b/storage/perfschema/table_setup_consumers.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -26,73 +26,105 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "table_setup_consumers.h" #include "pfs_instr.h" #include "pfs_events_waits.h" #include "pfs_digest.h" +#include "field.h" + +#define COUNT_SETUP_CONSUMERS 15 -#define COUNT_SETUP_CONSUMERS 12 static row_setup_consumers all_setup_consumers_data[COUNT_SETUP_CONSUMERS]= { { { C_STRING_WITH_LEN("events_stages_current") }, &flag_events_stages_current, + false, false }, { { C_STRING_WITH_LEN("events_stages_history") }, &flag_events_stages_history, - false + false, + true }, { { C_STRING_WITH_LEN("events_stages_history_long") }, &flag_events_stages_history_long, - false + false, + true }, { { C_STRING_WITH_LEN("events_statements_current") }, &flag_events_statements_current, + false, false }, { { C_STRING_WITH_LEN("events_statements_history") }, &flag_events_statements_history, - false + false, + true }, { { C_STRING_WITH_LEN("events_statements_history_long") }, &flag_events_statements_history_long, + false, + true + }, + { + { C_STRING_WITH_LEN("events_transactions_current") }, + &flag_events_transactions_current, + false, false }, { + { C_STRING_WITH_LEN("events_transactions_history") }, + &flag_events_transactions_history, + false, + true + }, + { + { C_STRING_WITH_LEN("events_transactions_history_long") }, + &flag_events_transactions_history_long, + false, + true + }, + { { C_STRING_WITH_LEN("events_waits_current") }, &flag_events_waits_current, + false, false }, { { C_STRING_WITH_LEN("events_waits_history") }, &flag_events_waits_history, - false + false, + true }, { { C_STRING_WITH_LEN("events_waits_history_long") }, &flag_events_waits_history_long, - false + false, + true }, { { C_STRING_WITH_LEN("global_instrumentation") }, &flag_global_instrumentation, + true, true }, { { C_STRING_WITH_LEN("thread_instrumentation") }, &flag_thread_instrumentation, - false + false, + true }, { { C_STRING_WITH_LEN("statements_digest") }, &flag_statements_digest, + false, false } }; @@ -104,16 +136,16 @@ table_setup_consumers::m_share= { { C_STRING_WITH_LEN("setup_consumers") }, &pfs_updatable_acl, - &table_setup_consumers::create, + table_setup_consumers::create, NULL, /* write_row */ NULL, /* delete_all_rows */ - NULL, /* get_row_count */ - COUNT_SETUP_CONSUMERS, /* records */ + table_setup_consumers::get_row_count, sizeof(PFS_simple_index), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE setup_consumers(" "NAME VARCHAR(64) not null," - "ENABLED ENUM ('YES', 'NO') not null)") } + "ENABLED ENUM ('YES', 'NO') not null)") }, + false /* perpetual */ }; PFS_engine_table* table_setup_consumers::create(void) @@ -121,6 +153,12 @@ PFS_engine_table* table_setup_consumers::create(void) return new table_setup_consumers(); } +ha_rows +table_setup_consumers::get_row_count(void) +{ + return COUNT_SETUP_CONSUMERS; +} + table_setup_consumers::table_setup_consumers() : PFS_engine_table(&m_share, &m_pos), m_row(NULL), m_pos(0), m_next_pos(0) @@ -225,9 +263,12 @@ int table_setup_consumers::update_row_values(TABLE *table, } } - if (m_row->m_refresh) + if (m_row->m_instrument_refresh) update_instruments_derived_flags(); + if (m_row->m_thread_refresh) + update_thread_derived_flags(); + return 0; } diff --git a/storage/perfschema/table_setup_consumers.h b/storage/perfschema/table_setup_consumers.h index 90da55920c6..9d601622adf 100644 --- a/storage/perfschema/table_setup_consumers.h +++ b/storage/perfschema/table_setup_consumers.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, version 2.0, @@ -43,8 +43,10 @@ struct row_setup_consumers LEX_STRING m_name; /** Column ENABLED. */ bool *m_enabled_ptr; - /** Hidden column, refresh. */ - bool m_refresh; + /** Hidden column, instrument refresh. */ + bool m_instrument_refresh; + /** Hidden column, thread refresh. */ + bool m_thread_refresh; }; /** Table PERFORMANCE_SCHEMA.SETUP_CONSUMERS. */ @@ -54,6 +56,7 @@ public: /** Table share. */ static PFS_engine_table_share m_share; static PFS_engine_table* create(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_setup_instruments.cc b/storage/perfschema/table_setup_instruments.cc index 490226c7c83..69e48b9c2ad 100644 --- a/storage/perfschema/table_setup_instruments.cc +++ b/storage/perfschema/table_setup_instruments.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -26,14 +26,16 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr_class.h" +#include "pfs_builtin_memory.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" +#include "field.h" THR_LOCK table_setup_instruments::m_table_lock; @@ -42,17 +44,17 @@ table_setup_instruments::m_share= { { C_STRING_WITH_LEN("setup_instruments") }, &pfs_updatable_acl, - &table_setup_instruments::create, + table_setup_instruments::create, NULL, /* write_row */ NULL, /* delete_all_rows */ - NULL, /* get_row_count */ - 1000, /* records */ + table_setup_instruments::get_row_count, sizeof(pos_setup_instruments), &m_table_lock, { 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)") } + "TIMED ENUM ('YES', 'NO') not null)") }, + false /* perpetual */ }; PFS_engine_table* table_setup_instruments::create(void) @@ -60,6 +62,16 @@ PFS_engine_table* table_setup_instruments::create(void) return new table_setup_instruments(); } +ha_rows +table_setup_instruments::get_row_count(void) +{ + return wait_class_max + + stage_class_max + + statement_class_max + + transaction_class_max + + memory_class_max; +} + table_setup_instruments::table_setup_instruments() : PFS_engine_table(&m_share, &m_pos), m_pos(), m_next_pos() @@ -74,6 +86,9 @@ void table_setup_instruments::reset_position(void) int table_setup_instruments::rnd_next(void) { PFS_instr_class *instr_class= NULL; + PFS_builtin_memory_class *pfs_builtin; + bool update_enabled; + bool update_timed; /* Do not advertise hard coded instruments when disabled. */ if (! pfs_initialized) @@ -83,6 +98,9 @@ int table_setup_instruments::rnd_next(void) m_pos.has_more_view(); m_pos.next_view()) { + update_enabled= true; + update_timed= true; + switch (m_pos.m_index_1) { case pos_setup_instruments::VIEW_MUTEX: @@ -109,16 +127,35 @@ int table_setup_instruments::rnd_next(void) case pos_setup_instruments::VIEW_STATEMENT: instr_class= find_statement_class(m_pos.m_index_2); break; + case pos_setup_instruments::VIEW_TRANSACTION: + instr_class= find_transaction_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; + case pos_setup_instruments::VIEW_BUILTIN_MEMORY: + update_enabled= false; + update_timed= false; + pfs_builtin= find_builtin_memory_class(m_pos.m_index_2); + if (pfs_builtin != NULL) + instr_class= & pfs_builtin->m_class; + else + instr_class= NULL; + break; + case pos_setup_instruments::VIEW_MEMORY: + update_timed= false; + instr_class= find_memory_class(m_pos.m_index_2); + break; + case pos_setup_instruments::VIEW_METADATA: + instr_class= find_metadata_class(m_pos.m_index_2); + break; } if (instr_class) { - make_row(instr_class); + make_row(instr_class, update_enabled, update_timed); m_next_pos.set_after(&m_pos); return 0; } @@ -130,6 +167,9 @@ int table_setup_instruments::rnd_next(void) int table_setup_instruments::rnd_pos(const void *pos) { PFS_instr_class *instr_class= NULL; + PFS_builtin_memory_class *pfs_builtin; + bool update_enabled; + bool update_timed; /* Do not advertise hard coded instruments when disabled. */ if (! pfs_initialized) @@ -137,6 +177,9 @@ int table_setup_instruments::rnd_pos(const void *pos) set_position(pos); + update_enabled= true; + update_timed= true; + switch (m_pos.m_index_1) { case pos_setup_instruments::VIEW_MUTEX: @@ -163,25 +206,46 @@ int table_setup_instruments::rnd_pos(const void *pos) case pos_setup_instruments::VIEW_STATEMENT: instr_class= find_statement_class(m_pos.m_index_2); break; + case pos_setup_instruments::VIEW_TRANSACTION: + instr_class= find_transaction_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; + case pos_setup_instruments::VIEW_BUILTIN_MEMORY: + update_enabled= false; + update_timed= false; + pfs_builtin= find_builtin_memory_class(m_pos.m_index_2); + if (pfs_builtin != NULL) + instr_class= & pfs_builtin->m_class; + else + instr_class= NULL; + break; + case pos_setup_instruments::VIEW_MEMORY: + update_timed= false; + instr_class= find_memory_class(m_pos.m_index_2); + break; + case pos_setup_instruments::VIEW_METADATA: + instr_class= find_metadata_class(m_pos.m_index_2); + break; } if (instr_class) { - make_row(instr_class); + make_row(instr_class, update_enabled, update_timed); return 0; } return HA_ERR_RECORD_DELETED; } -void table_setup_instruments::make_row(PFS_instr_class *klass) +void table_setup_instruments::make_row(PFS_instr_class *klass, bool update_enabled, bool update_timed) { m_row.m_instr_class= klass; + m_row.m_update_enabled= update_enabled; + m_row.m_update_timed= update_timed; } int table_setup_instruments::read_row_values(TABLE *table, @@ -239,12 +303,20 @@ int table_setup_instruments::update_row_values(TABLE *table, case 0: /* NAME */ return HA_ERR_WRONG_COMMAND; case 1: /* ENABLED */ - value= (enum_yes_no) get_field_enum(f); - m_row.m_instr_class->m_enabled= (value == ENUM_YES) ? true : false; + /* Do not raise error if m_update_enabled is false, silently ignore. */ + if (m_row.m_update_enabled) + { + value= (enum_yes_no) get_field_enum(f); + m_row.m_instr_class->m_enabled= (value == ENUM_YES) ? true : false; + } break; case 2: /* TIMED */ - value= (enum_yes_no) get_field_enum(f); - m_row.m_instr_class->m_timed= (value == ENUM_YES) ? true : false; + /* Do not raise error if m_update_timed is false, silently ignore. */ + if (m_row.m_update_timed) + { + value= (enum_yes_no) get_field_enum(f); + m_row.m_instr_class->m_timed= (value == ENUM_YES) ? true : false; + } break; default: DBUG_ASSERT(false); @@ -274,6 +346,7 @@ int table_setup_instruments::update_row_values(TABLE *table, break; case pos_setup_instruments::VIEW_STAGE: case pos_setup_instruments::VIEW_STATEMENT: + case pos_setup_instruments::VIEW_TRANSACTION: /* No flag to update. */ break; case pos_setup_instruments::VIEW_SOCKET: @@ -282,6 +355,13 @@ int table_setup_instruments::update_row_values(TABLE *table, case pos_setup_instruments::VIEW_IDLE: /* No flag to update. */ break; + case pos_setup_instruments::VIEW_BUILTIN_MEMORY: + case pos_setup_instruments::VIEW_MEMORY: + /* No flag to update. */ + break; + case pos_setup_instruments::VIEW_METADATA: + update_metadata_derived_flags(); + break; default: DBUG_ASSERT(false); break; diff --git a/storage/perfschema/table_setup_instruments.h b/storage/perfschema/table_setup_instruments.h index cd3715cfe55..42aa2dd91d0 100644 --- a/storage/perfschema/table_setup_instruments.h +++ b/storage/perfschema/table_setup_instruments.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -41,6 +41,10 @@ struct row_setup_instruments { /** Columns NAME, ENABLED, TIMED. */ PFS_instr_class *m_instr_class; + /** True if column ENABLED can be updated. */ + bool m_update_enabled; + /** True if column TIMED can be updated. */ + bool m_update_timed; }; /** Position of a cursor on PERFORMANCE_SCHEMA.SETUP_INSTRUMENTS. */ @@ -55,9 +59,13 @@ struct pos_setup_instruments : public PFS_double_index 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; + static const uint VIEW_TRANSACTION=9; + static const uint VIEW_SOCKET= 10; + static const uint VIEW_IDLE= 11; + static const uint VIEW_BUILTIN_MEMORY= 12; + static const uint VIEW_MEMORY= 13; + static const uint VIEW_METADATA= 14; + static const uint LAST_VIEW= 14; pos_setup_instruments() : PFS_double_index(FIRST_VIEW, 1) @@ -86,6 +94,7 @@ public: /** Table share. */ static PFS_engine_table_share m_share; static PFS_engine_table* create(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); @@ -109,7 +118,7 @@ public: {} private: - void make_row(PFS_instr_class *klass); + void make_row(PFS_instr_class *klass, bool update_enabled, bool update_timed); /** Table share lock. */ static THR_LOCK m_table_lock; diff --git a/storage/perfschema/table_setup_objects.cc b/storage/perfschema/table_setup_objects.cc index ce8b7e73927..23d4bcaab0f 100644 --- a/storage/perfschema/table_setup_objects.cc +++ b/storage/perfschema/table_setup_objects.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, version 2.0, @@ -26,7 +26,7 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr.h" #include "pfs_column_types.h" #include "pfs_column_values.h" @@ -34,6 +34,8 @@ #include "table_setup_objects.h" #include "table_helper.h" #include "pfs_global.h" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_setup_objects::m_table_lock; @@ -46,15 +48,16 @@ table_setup_objects::m_share= 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_TYPE ENUM ('EVENT','FUNCTION','PROCEDURE','TABLE','TRIGGER') not null default 'EVENT'," + "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')") } + "TIMED ENUM ('YES', 'NO') not null default 'YES')") }, + false /* perpetual */ }; int update_derived_flags() @@ -64,6 +67,7 @@ int update_derived_flags() return HA_ERR_OUT_OF_MEM; update_table_share_derived_flags(thread); + update_program_share_derived_flags(thread); update_table_derived_flags(); return 0; } @@ -116,7 +120,9 @@ int table_setup_objects::write_row(TABLE *table, const unsigned char *buf, } /* Reject illegal enum values in OBJECT_TYPE */ - if (object_type != OBJECT_TYPE_TABLE) + if (object_type < FIRST_OBJECT_TYPE || + object_type > LAST_OBJECT_TYPE || + object_type == OBJECT_TYPE_TEMPORARY_TABLE) return HA_ERR_NO_REFERENCED_ROW; /* Reject illegal enum values in ENABLED */ @@ -147,7 +153,7 @@ int table_setup_objects::delete_all_rows(void) ha_rows table_setup_objects::get_row_count(void) { - return setup_object_count(); + return global_setup_object_container.get_row_count(); } table_setup_objects::table_setup_objects() @@ -165,17 +171,14 @@ 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()) + m_pos.set_at(&m_next_pos); + PFS_setup_object_iterator it= global_setup_object_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - 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; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -187,9 +190,8 @@ int table_setup_objects::rnd_pos(const void *pos) 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()) + pfs= global_setup_object_container.get(m_pos.m_index); + if (pfs != NULL) { make_row(pfs); return 0; @@ -200,7 +202,7 @@ int table_setup_objects::rnd_pos(const void *pos) void table_setup_objects::make_row(PFS_setup_object *pfs) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; diff --git a/storage/perfschema/table_setup_objects.h b/storage/perfschema/table_setup_objects.h index 570acc865ad..abe36f73818 100644 --- a/storage/perfschema/table_setup_objects.h +++ b/storage/perfschema/table_setup_objects.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, version 2.0, diff --git a/storage/perfschema/table_setup_timers.cc b/storage/perfschema/table_setup_timers.cc index a2d34828f08..e43a9943fc6 100644 --- a/storage/perfschema/table_setup_timers.cc +++ b/storage/perfschema/table_setup_timers.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, version 2.0, @@ -26,12 +26,14 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "table_setup_timers.h" #include "pfs_column_values.h" #include "pfs_timer.h" +#include "field.h" +#include "derror.h" /* ER_THD */ -#define COUNT_SETUP_TIMERS 4 +#define COUNT_SETUP_TIMERS 5 static row_setup_timers all_setup_timers_data[COUNT_SETUP_TIMERS]= { @@ -50,6 +52,10 @@ static row_setup_timers all_setup_timers_data[COUNT_SETUP_TIMERS]= { { C_STRING_WITH_LEN("statement") }, &statement_timer + }, + { + { C_STRING_WITH_LEN("transaction") }, + &transaction_timer } }; @@ -60,23 +66,36 @@ table_setup_timers::m_share= { { C_STRING_WITH_LEN("setup_timers") }, &pfs_updatable_acl, - &table_setup_timers::create, + table_setup_timers::create, NULL, /* write_row */ NULL, /* delete_all_rows */ - NULL, /* get_row_count */ - COUNT_SETUP_TIMERS, + table_setup_timers::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE setup_timers(" "NAME VARCHAR(64) not null," - "TIMER_NAME ENUM ('CYCLE', 'NANOSECOND', 'MICROSECOND', 'MILLISECOND', 'TICK') not null)") } + "TIMER_NAME ENUM ('CYCLE', 'NANOSECOND', 'MICROSECOND', 'MILLISECOND', 'TICK') not null)") }, + false /* perpetual */ }; PFS_engine_table* table_setup_timers::create(void) { + THD *thd = current_thd; + push_warning_printf(thd, + Sql_condition::SL_WARNING, + ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT, + ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT), + "performance_schema.setup_timers"); + return new table_setup_timers(); } +ha_rows +table_setup_timers::get_row_count(void) +{ + return COUNT_SETUP_TIMERS; +} + table_setup_timers::table_setup_timers() : PFS_engine_table(&m_share, &m_pos), m_row(NULL), m_pos(0), m_next_pos(0) diff --git a/storage/perfschema/table_setup_timers.h b/storage/perfschema/table_setup_timers.h index d591f3e0b67..43100bf3dd0 100644 --- a/storage/perfschema/table_setup_timers.h +++ b/storage/perfschema/table_setup_timers.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, version 2.0, @@ -52,6 +52,7 @@ public: /** Table share. */ static PFS_engine_table_share m_share; static PFS_engine_table* create(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_socket_instances.cc b/storage/perfschema/table_socket_instances.cc index 920531136d5..24c9b0d02a9 100644 --- a/storage/perfschema/table_socket_instances.cc +++ b/storage/perfschema/table_socket_instances.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, version 2.0, @@ -26,12 +26,14 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr.h" #include "pfs_column_types.h" #include "pfs_column_values.h" #include "table_socket_instances.h" #include "pfs_global.h" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_socket_instances::m_table_lock; @@ -40,11 +42,10 @@ table_socket_instances::m_share= { { C_STRING_WITH_LEN("socket_instances") }, &pfs_readonly_acl, - &table_socket_instances::create, + table_socket_instances::create, NULL, /* write_row */ NULL, /* delete_all_rows */ - NULL, /* get_row_count */ - 1000, /* records */ + table_socket_instances::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE socket_instances(" @@ -54,7 +55,8 @@ table_socket_instances::m_share= "SOCKET_ID INTEGER not null," "IP VARCHAR(64) not null," "PORT INTEGER not null," - "STATE ENUM('IDLE','ACTIVE') not null)") } + "STATE ENUM('IDLE','ACTIVE') not null)") }, + false /* perpetual */ }; PFS_engine_table* table_socket_instances::create(void) @@ -62,6 +64,12 @@ PFS_engine_table* table_socket_instances::create(void) return new table_socket_instances(); } +ha_rows +table_socket_instances::get_row_count(void) +{ + return global_socket_container.get_row_count(); +} + table_socket_instances::table_socket_instances() : PFS_engine_table(&m_share, &m_pos), m_row_exists(false), m_pos(0), m_next_pos(0) @@ -77,17 +85,14 @@ 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()) + m_pos.set_at(&m_next_pos); + PFS_socket_iterator it= global_socket_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - 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; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -98,19 +103,20 @@ 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; + pfs= global_socket_container.get(m_pos.m_index); + if (pfs != NULL) + { + make_row(pfs); + return 0; + } - make_row(pfs); - return 0; + return HA_ERR_RECORD_DELETED; } void table_socket_instances::make_row(PFS_socket *pfs) { - pfs_lock lock; + pfs_optimistic_state lock; PFS_socket_class *safe_class; m_row_exists= false; diff --git a/storage/perfschema/table_socket_instances.h b/storage/perfschema/table_socket_instances.h index 41b5ee3fd21..4e32bbdcd00 100644 --- a/storage/perfschema/table_socket_instances.h +++ b/storage/perfschema/table_socket_instances.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, version 2.0, @@ -70,6 +70,7 @@ public: /** Table share */ static PFS_engine_table_share m_share; static PFS_engine_table* create(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_socket_summary_by_event_name.cc b/storage/perfschema/table_socket_summary_by_event_name.cc index c813d45b732..bdfff75614d 100644 --- a/storage/perfschema/table_socket_summary_by_event_name.cc +++ b/storage/perfschema/table_socket_summary_by_event_name.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -26,13 +26,14 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "field.h" THR_LOCK table_socket_summary_by_event_name::m_table_lock; @@ -41,11 +42,10 @@ 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, + 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 */ + table_socket_summary_by_event_name::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE socket_summary_by_event_name(" @@ -71,7 +71,8 @@ table_socket_summary_by_event_name::m_share= "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)") } + "MAX_TIMER_MISC BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* table_socket_summary_by_event_name::create(void) @@ -91,6 +92,12 @@ int table_socket_summary_by_event_name::delete_all_rows(void) return 0; } +ha_rows +table_socket_summary_by_event_name::get_row_count(void) +{ + return socket_class_max; +} + void table_socket_summary_by_event_name::reset_position(void) { m_pos.m_index= 1; @@ -138,7 +145,7 @@ void table_socket_summary_by_event_name::make_row(PFS_socket_class *socket_class 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; diff --git a/storage/perfschema/table_socket_summary_by_event_name.h b/storage/perfschema/table_socket_summary_by_event_name.h index 4f679d89b09..e25d38b9bfa 100644 --- a/storage/perfschema/table_socket_summary_by_event_name.h +++ b/storage/perfschema/table_socket_summary_by_event_name.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, version 2.0, @@ -60,6 +60,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_socket_summary_by_instance.cc b/storage/perfschema/table_socket_summary_by_instance.cc index a4b1477aa90..372cde61a87 100644 --- a/storage/perfschema/table_socket_summary_by_instance.cc +++ b/storage/perfschema/table_socket_summary_by_instance.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -26,12 +26,14 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_socket_summary_by_instance::m_table_lock; @@ -40,11 +42,10 @@ table_socket_summary_by_instance::m_share= { { C_STRING_WITH_LEN("socket_summary_by_instance") }, &pfs_readonly_acl, - &table_socket_summary_by_instance::create, + table_socket_summary_by_instance::create, NULL, /* write_row */ table_socket_summary_by_instance::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_socket_summary_by_instance::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE socket_summary_by_instance(" @@ -71,7 +72,8 @@ table_socket_summary_by_instance::m_share= "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)") } + "MAX_TIMER_MISC BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* table_socket_summary_by_instance::create(void) @@ -90,6 +92,12 @@ int table_socket_summary_by_instance::delete_all_rows(void) return 0; } +ha_rows +table_socket_summary_by_instance::get_row_count(void) +{ + return global_socket_container.get_row_count(); +} + void table_socket_summary_by_instance::reset_position(void) { m_pos.m_index= 0; @@ -100,17 +108,14 @@ 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()) + m_pos.set_at(&m_next_pos); + PFS_socket_iterator it= global_socket_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - 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; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -121,19 +126,20 @@ 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; + pfs= global_socket_container.get(m_pos.m_index); + if (pfs != NULL) + { + make_row(pfs); + return 0; + } - make_row(pfs); - return 0; + return HA_ERR_RECORD_DELETED; } void table_socket_summary_by_instance::make_row(PFS_socket *pfs) { - pfs_lock lock; + pfs_optimistic_state lock; PFS_socket_class *safe_class; m_row_exists= false; diff --git a/storage/perfschema/table_socket_summary_by_instance.h b/storage/perfschema/table_socket_summary_by_instance.h index a9eab8d18b6..3f6d1295728 100644 --- a/storage/perfschema/table_socket_summary_by_instance.h +++ b/storage/perfschema/table_socket_summary_by_instance.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -63,6 +63,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_status_by_account.cc b/storage/perfschema/table_status_by_account.cc new file mode 100644 index 00000000000..30a1b6db036 --- /dev/null +++ b/storage/perfschema/table_status_by_account.cc @@ -0,0 +1,246 @@ +/* Copyright (c) 2015, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_status_by_account.cc + Table STATUS_BY_ACCOUNT (implementation). +*/ + +#include "my_global.h" +#include "table_status_by_account.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_global.h" +#include "pfs_account.h" + +THR_LOCK table_status_by_account::m_table_lock; + +PFS_engine_table_share +table_status_by_account::m_share= +{ + { C_STRING_WITH_LEN("status_by_account") }, + &pfs_truncatable_acl, + table_status_by_account::create, + NULL, /* write_row */ + table_status_by_account::delete_all_rows, + table_status_by_account::get_row_count, + sizeof(pos_t), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE status_by_account(" + "USER CHAR(32) collate utf8_bin default null," + "HOST CHAR(60) collate utf8_bin default null," + "VARIABLE_NAME VARCHAR(64) not null," + "VARIABLE_VALUE VARCHAR(1024))") }, + false /* perpetual */ +}; + +PFS_engine_table* +table_status_by_account::create(void) +{ + return new table_status_by_account(); +} + +int table_status_by_account::delete_all_rows(void) +{ + mysql_mutex_lock(&LOCK_status); + reset_status_by_thread(); + reset_status_by_account(); + mysql_mutex_unlock(&LOCK_status); + return 0; +} + +ha_rows table_status_by_account::get_row_count(void) +{ + mysql_mutex_lock(&LOCK_status); + size_t status_var_count= all_status_vars.elements; + mysql_mutex_unlock(&LOCK_status); + return (global_account_container.get_row_count() * status_var_count); +} + +table_status_by_account::table_status_by_account() + : PFS_engine_table(&m_share, &m_pos), + m_status_cache(true), m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_status_by_account::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_status_by_account::rnd_init(bool scan) +{ + if (show_compatibility_56) + return 0; + + /* + Build array of SHOW_VARs from the global status array prior to materializing + threads in rnd_next() or rnd_pos(). + */ + m_status_cache.initialize_client_session(); + + /* Use the current number of status variables to detect changes. */ + ulonglong status_version= m_status_cache.get_status_array_version(); + + /* + The table context holds the current version of the global status array + and a record of which accounts were materialized. If scan == true, then + allocate a new context from mem_root and store in TLS. If scan == false, + then restore from TLS. + */ + m_context= (table_status_by_account_context *)current_thd->alloc(sizeof(table_status_by_account_context)); + new(m_context) table_status_by_account_context(status_version, !scan); + return 0; +} + +int table_status_by_account::rnd_next(void) +{ + if (show_compatibility_56) + return HA_ERR_END_OF_FILE; + + /* If status array changes, exit with warning. */ // TODO: Issue warning + if (!m_context->versions_match()) + return HA_ERR_END_OF_FILE; + + /* + For each account, build a cache of status variables using totals from all + threads associated with the account. + */ + bool has_more_account= true; + + for (m_pos.set_at(&m_next_pos); + has_more_account; + m_pos.next_account()) + { + PFS_account *pfs_account= global_account_container.get(m_pos.m_index_1, &has_more_account); + + if (m_status_cache.materialize_account(pfs_account) == 0) + { + /* Mark this account as materialized. */ + m_context->set_item(m_pos.m_index_1); + + /* Get the next status variable. */ + const Status_variable *stat_var= m_status_cache.get(m_pos.m_index_2); + if (stat_var != NULL) + { + make_row(pfs_account, stat_var); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + return HA_ERR_END_OF_FILE; +} + +int +table_status_by_account::rnd_pos(const void *pos) +{ + if (show_compatibility_56) + return HA_ERR_RECORD_DELETED; + + /* If status array changes, exit with warning. */ // TODO: Issue warning + if (!m_context->versions_match()) + return HA_ERR_END_OF_FILE; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < global_account_container.get_row_count()); + + PFS_account *pfs_account= global_account_container.get(m_pos.m_index_1); + + /* + Only materialize threads that were previously materialized by rnd_next(). + If a account cannot be rematerialized, then do nothing. + */ + if (m_context->is_item_set(m_pos.m_index_1) && + m_status_cache.materialize_account(pfs_account) == 0) + { + const Status_variable *stat_var= m_status_cache.get(m_pos.m_index_2); + if (stat_var != NULL) + { + make_row(pfs_account, stat_var); + return 0; + } + } + return HA_ERR_RECORD_DELETED; +} + +void table_status_by_account +::make_row(PFS_account *pfs_account, const Status_variable *status_var) +{ + pfs_optimistic_state lock; + m_row_exists= false; + pfs_account->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_account.make_row(pfs_account)) + return; + + m_row.m_variable_name.make_row(status_var->m_name, status_var->m_name_length); + m_row.m_variable_value.make_row(status_var); + + if (!pfs_account->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; +} + +int table_status_by_account +::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: /* VARIABLE_NAME */ + set_field_varchar_utf8(f, m_row.m_variable_name.m_str, m_row.m_variable_name.m_length); + break; + case 3: /* VARIABLE_VALUE */ + m_row.m_variable_value.set_field(f); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_status_by_account.h b/storage/perfschema/table_status_by_account.h new file mode 100644 index 00000000000..401a184d8f1 --- /dev/null +++ b/storage/perfschema/table_status_by_account.h @@ -0,0 +1,156 @@ +/* Copyright (c) 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_STATUS_BY_ACCOUNT_H +#define TABLE_STATUS_BY_ACCOUNT_H + +/** + @file storage/perfschema/table_status_by_account.h + Table STATUS_BY_ACCOUNT (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 "pfs_account.h" +#include "pfs_host.h" +#include "table_helper.h" +#include "pfs_variable.h" +#include "pfs_buffer_container.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.STATUS_BY_ACCOUNT. +*/ +struct row_status_by_account +{ + /** Column USER, HOST. */ + PFS_account_row m_account; + /** Column VARIABLE_NAME. */ + PFS_variable_name_row m_variable_name; + /** Column VARIABLE_VALUE. */ + PFS_variable_value_row m_variable_value; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.STATUS_BY_ACCOUNT. + Index 1 on account (0 based) + Index 2 on status variable (0 based) +*/ +struct pos_status_by_account +: public PFS_double_index +{ + pos_status_by_account() + : PFS_double_index(0, 0) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 0; + } + + inline bool has_more_account(void) + { return (m_index_1 < global_account_container.get_row_count()); } + + inline void next_account(void) + { + m_index_1++; + m_index_2= 0; + } +}; + +/** + Store and retrieve table state information for queries that reinstantiate + the table object. +*/ +class table_status_by_account_context : public PFS_table_context +{ +public: + table_status_by_account_context(ulonglong current_version, bool restore) : + PFS_table_context(current_version, global_account_container.get_row_count(), restore, THR_PFS_SBH) { } +}; + +/** Table PERFORMANCE_SCHEMA.STATUS_BY_ACCOUNT. */ +class table_status_by_account : public PFS_engine_table +{ + typedef pos_status_by_account pos_t; + +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + static ha_rows get_row_count(); + + 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_status_by_account(); + +public: + ~table_status_by_account() + {} + +protected: + int materialize(PFS_thread *pfs_thread); + void make_row(PFS_account *pfs_account, const Status_variable *status_var); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Status variable cache for one account. */ + PFS_status_variable_cache m_status_cache; + + /** Current row. */ + row_status_by_account m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + + /** Table context with global status array version and map of materialized threads. */ + table_status_by_account_context *m_context; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_status_by_host.cc b/storage/perfschema/table_status_by_host.cc new file mode 100644 index 00000000000..cd41fcaa469 --- /dev/null +++ b/storage/perfschema/table_status_by_host.cc @@ -0,0 +1,245 @@ +/* Copyright (c) 2015, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_status_by_host.cc + Table STATUS_BY_HOST (implementation). +*/ + +#include "my_global.h" +#include "table_status_by_host.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_global.h" +#include "pfs_account.h" + +THR_LOCK table_status_by_host::m_table_lock; + +PFS_engine_table_share +table_status_by_host::m_share= +{ + { C_STRING_WITH_LEN("status_by_host") }, + &pfs_truncatable_acl, + table_status_by_host::create, + NULL, /* write_row */ + table_status_by_host::delete_all_rows, + table_status_by_host::get_row_count, + sizeof(pos_t), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE status_by_host(" + "HOST CHAR(60) collate utf8_bin default null," + "VARIABLE_NAME VARCHAR(64) not null," + "VARIABLE_VALUE VARCHAR(1024))") }, + false /* perpetual */ +}; + +PFS_engine_table* +table_status_by_host::create(void) +{ + return new table_status_by_host(); +} + +int table_status_by_host::delete_all_rows(void) +{ + mysql_mutex_lock(&LOCK_status); + reset_status_by_thread(); + reset_status_by_account(); + reset_status_by_host(); + mysql_mutex_unlock(&LOCK_status); + return 0; +} + +ha_rows table_status_by_host::get_row_count(void) +{ + mysql_mutex_lock(&LOCK_status); + size_t status_var_count= all_status_vars.elements; + mysql_mutex_unlock(&LOCK_status); + return (global_host_container.get_row_count() * status_var_count); +} + +table_status_by_host::table_status_by_host() + : PFS_engine_table(&m_share, &m_pos), + m_status_cache(true), m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_status_by_host::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_status_by_host::rnd_init(bool scan) +{ + if (show_compatibility_56) + return 0; + + /* + Build array of SHOW_VARs from the global status array prior to materializing + threads in rnd_next() or rnd_pos(). + */ + m_status_cache.initialize_client_session(); + + /* Use the current number of status variables to detect changes. */ + ulonglong status_version= m_status_cache.get_status_array_version(); + + /* + The table context holds the current version of the global status array + and a record of which hosts were materialized. If scan == true, then + allocate a new context from mem_root and store in TLS. If scan == false, + then restore from TLS. + */ + m_context= (table_status_by_host_context *)current_thd->alloc(sizeof(table_status_by_host_context)); + new(m_context) table_status_by_host_context(status_version, !scan); + return 0; +} + +int table_status_by_host::rnd_next(void) +{ + if (show_compatibility_56) + return HA_ERR_END_OF_FILE; + + /* If status array changes, exit with warning. */ // TODO: Issue warning + if (!m_context->versions_match()) + return HA_ERR_END_OF_FILE; + + /* + For each user, build a cache of status variables using totals from all + threads associated with the host. + */ + bool has_more_host= true; + + for (m_pos.set_at(&m_next_pos); + has_more_host; + m_pos.next_host()) + { + PFS_host *pfs_host= global_host_container.get(m_pos.m_index_1, &has_more_host); + + if (m_status_cache.materialize_host(pfs_host) == 0) + { + /* Mark this host as materialized. */ + m_context->set_item(m_pos.m_index_1); + + /* Get the next status variable. */ + const Status_variable *stat_var= m_status_cache.get(m_pos.m_index_2); + if (stat_var != NULL) + { + make_row(pfs_host, stat_var); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + return HA_ERR_END_OF_FILE; +} + +int +table_status_by_host::rnd_pos(const void *pos) +{ + if (show_compatibility_56) + return 0; + + /* If status array changes, exit with warning. */ // TODO: Issue warning + if (!m_context->versions_match()) + return HA_ERR_END_OF_FILE; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < global_host_container.get_row_count()); + + PFS_host *pfs_host= global_host_container.get(m_pos.m_index_1); + + /* + Only materialize threads that were previously materialized by rnd_next(). + If a host cannot be rematerialized, then do nothing. + */ + if (m_context->is_item_set(m_pos.m_index_1) && + m_status_cache.materialize_host(pfs_host) == 0) + { + const Status_variable *stat_var= m_status_cache.get(m_pos.m_index_2); + if (stat_var != NULL) + { + make_row(pfs_host, stat_var); + return 0; + } + } + return HA_ERR_RECORD_DELETED; +} + +void table_status_by_host +::make_row(PFS_host *pfs_host, const Status_variable *status_var) +{ + pfs_optimistic_state lock; + m_row_exists= false; + pfs_host->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_host.make_row(pfs_host)) + return; + + m_row.m_variable_name.make_row(status_var->m_name, status_var->m_name_length); + m_row.m_variable_value.make_row(status_var); + + if (!pfs_host->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; +} + +int table_status_by_host +::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: /* VARIABLE_NAME */ + set_field_varchar_utf8(f, m_row.m_variable_name.m_str, m_row.m_variable_name.m_length); + break; + case 2: /* VARIABLE_VALUE */ + m_row.m_variable_value.set_field(f); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_status_by_host.h b/storage/perfschema/table_status_by_host.h new file mode 100644 index 00000000000..e4c6bf256ef --- /dev/null +++ b/storage/perfschema/table_status_by_host.h @@ -0,0 +1,154 @@ +/* Copyright (c) 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_STATUS_BY_HOST_H +#define TABLE_STATUS_BY_HOST_H + +/** + @file storage/perfschema/table_status_by_host.h + Table STATUS_BY_HOST (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" +#include "pfs_variable.h" +#include "pfs_buffer_container.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.STATUS_BY_HOST. +*/ +struct row_status_by_host +{ + /** Column HOST */ + PFS_host_row m_host; + /** Column VARIABLE_NAME. */ + PFS_variable_name_row m_variable_name; + /** Column VARIABLE_VALUE. */ + PFS_variable_value_row m_variable_value; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.STATUS_BY_HOST. + Index 1 on host (0 based) + Index 2 on status variable (0 based) +*/ +struct pos_status_by_host +: public PFS_double_index +{ + pos_status_by_host() + : PFS_double_index(0, 0) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 0; + } + + inline bool has_more_host(void) + { return (m_index_1 < global_host_container.get_row_count()); } + + inline void next_host(void) + { + m_index_1++; + m_index_2= 0; + } +}; + +/** + Store and retrieve table state information for queries that reinstantiate + the table object. +*/ +class table_status_by_host_context : public PFS_table_context +{ +public: + table_status_by_host_context(ulonglong current_version, bool restore) : + PFS_table_context(current_version, global_host_container.get_row_count(), restore, THR_PFS_SBH) { } +}; + +/** Table PERFORMANCE_SCHEMA.STATUS_BY_HOST. */ +class table_status_by_host : public PFS_engine_table +{ + typedef pos_status_by_host pos_t; + +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + static ha_rows get_row_count(); + + 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_status_by_host(); + +public: + ~table_status_by_host() + {} + +protected: + int materialize(PFS_thread *thread); + void make_row(PFS_host *pfs_host, const Status_variable *status_var); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Status variable cache for one host. */ + PFS_status_variable_cache m_status_cache; + + /** Current row. */ + row_status_by_host m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + + /** Table context with global status array version and map of materialized threads. */ + table_status_by_host_context *m_context; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_status_by_thread.cc b/storage/perfschema/table_status_by_thread.cc new file mode 100644 index 00000000000..d9af7e49aa4 --- /dev/null +++ b/storage/perfschema/table_status_by_thread.cc @@ -0,0 +1,239 @@ +/* Copyright (c) 2015, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_status_by_thread.cc + Table STATUS_BY_THREAD (implementation). +*/ + +#include "my_global.h" +#include "table_status_by_thread.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_global.h" + +THR_LOCK table_status_by_thread::m_table_lock; + +PFS_engine_table_share +table_status_by_thread::m_share= +{ + { C_STRING_WITH_LEN("status_by_thread") }, + &pfs_truncatable_acl, + table_status_by_thread::create, + NULL, /* write_row */ + table_status_by_thread::delete_all_rows, + table_status_by_thread::get_row_count, + sizeof(pos_t), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE status_by_thread(" + "THREAD_ID BIGINT unsigned not null," + "VARIABLE_NAME VARCHAR(64) not null," + "VARIABLE_VALUE VARCHAR(1024))") }, + false /* perpetual */ +}; + +PFS_engine_table* +table_status_by_thread::create(void) +{ + return new table_status_by_thread(); +} + +int table_status_by_thread::delete_all_rows(void) +{ + /* Lock required to aggregate to global_status_vars. */ + mysql_mutex_lock(&LOCK_status); + + reset_status_by_thread(); + + mysql_mutex_unlock(&LOCK_status); + return 0; +} + +ha_rows table_status_by_thread::get_row_count(void) +{ + mysql_mutex_lock(&LOCK_status); + size_t status_var_count= all_status_vars.elements; + mysql_mutex_unlock(&LOCK_status); + return (global_thread_container.get_row_count() * status_var_count); +} + +table_status_by_thread::table_status_by_thread() + : PFS_engine_table(&m_share, &m_pos), + m_status_cache(true), m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_status_by_thread::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_status_by_thread::rnd_init(bool scan) +{ + if (show_compatibility_56) + return 0; + + /* + Build array of SHOW_VARs from the global status array prior to materializing + threads in rnd_next() or rnd_pos(). + */ + m_status_cache.initialize_session(); + + /* Record the current number of status variables to detect subsequent changes. */ + ulonglong status_version= m_status_cache.get_status_array_version(); + + /* + The table context holds the current version of the global status array + and a record of which threads were materialized. If scan == true, then + allocate a new context from mem_root and store in TLS. If scan == false, + then restore from TLS. + */ + m_context= (table_status_by_thread_context *)current_thd->alloc(sizeof(table_status_by_thread_context)); + new(m_context) table_status_by_thread_context(status_version, !scan); + return 0; +} + +int table_status_by_thread::rnd_next(void) +{ + if (show_compatibility_56) + return HA_ERR_END_OF_FILE; + + /* If global status array changes, exit with warning. */ // TODO: Issue warning + if (!m_context->versions_match()) + return HA_ERR_END_OF_FILE; + + bool has_more_thread= true; + + for (m_pos.set_at(&m_next_pos); + has_more_thread; + m_pos.next_thread()) + { + PFS_thread *pfs_thread= global_thread_container.get(m_pos.m_index_1, &has_more_thread); + if (m_status_cache.materialize_session(pfs_thread) == 0) + { + /* Mark this thread as materialized. */ + m_context->set_item(m_pos.m_index_1); + const Status_variable *stat_var= m_status_cache.get(m_pos.m_index_2); + if (stat_var != NULL) + { + make_row(pfs_thread, stat_var); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + return HA_ERR_END_OF_FILE; +} + +int +table_status_by_thread::rnd_pos(const void *pos) +{ + if (show_compatibility_56) + return HA_ERR_RECORD_DELETED; + + /* If global status array has changed, do nothing. */ + if (!m_context->versions_match()) + return HA_ERR_RECORD_DELETED; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < global_thread_container.get_row_count()); + + PFS_thread *pfs_thread= global_thread_container.get(m_pos.m_index_1); + /* + Only materialize threads that were previously materialized by rnd_next(). + If a thread cannot be rematerialized, then do nothing. + */ + if (m_context->is_item_set(m_pos.m_index_1) && + m_status_cache.materialize_session(pfs_thread) == 0) + { + const Status_variable *stat_var= m_status_cache.get(m_pos.m_index_2); + if (stat_var != NULL) + { + make_row(pfs_thread, stat_var); + return 0; + } + } + return HA_ERR_RECORD_DELETED; +} + +void table_status_by_thread +::make_row(PFS_thread *thread, const Status_variable *status_var) +{ + pfs_optimistic_state lock; + m_row_exists= false; + if (status_var->is_null()) + 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_variable_name.make_row(status_var->m_name, status_var->m_name_length); + m_row.m_variable_value.make_row(status_var); + + if (!thread->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; +} + +int table_status_by_thread +::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: /* VARIABLE_NAME */ + set_field_varchar_utf8(f, m_row.m_variable_name.m_str, m_row.m_variable_name.m_length); + break; + case 2: /* VARIABLE_VALUE */ + m_row.m_variable_value.set_field(f); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_status_by_thread.h b/storage/perfschema/table_status_by_thread.h new file mode 100644 index 00000000000..f8de21dc41e --- /dev/null +++ b/storage/perfschema/table_status_by_thread.h @@ -0,0 +1,151 @@ +/* Copyright (c) 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_STATUS_BY_THREAD_H +#define TABLE_STATUS_BY_THREAD_H + +/** + @file storage/perfschema/table_status_by_thread.h + Table STATUS_BY_THREAD (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" +#include "pfs_variable.h" +#include "pfs_buffer_container.h" +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.STATUS_BY_THREAD. +*/ +struct row_status_by_thread +{ + /** Column THREAD_ID. */ + ulonglong m_thread_internal_id; + /** Column VARIABLE_NAME. */ + PFS_variable_name_row m_variable_name; + /** Column VARIABLE_VALUE. */ + PFS_variable_value_row m_variable_value; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.STATUS_BY_THREAD. + Index 1 on thread (0 based) + Index 2 on status variable (0 based) +*/ +struct pos_status_by_thread +: public PFS_double_index +{ + pos_status_by_thread() + : PFS_double_index(0, 0) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 0; + } + + inline bool has_more_thread(void) + { return (m_index_1 < global_thread_container.get_row_count()); } + + inline void next_thread(void) + { + m_index_1++; + m_index_2= 0; + } +}; + +/** + Store and retrieve table state information for queries that reinstantiate + the table object. +*/ +class table_status_by_thread_context : public PFS_table_context +{ +public: + table_status_by_thread_context(ulonglong current_version, bool restore) : + PFS_table_context(current_version, global_thread_container.get_row_count(), restore, THR_PFS_SBT) { } +}; + +/** Table PERFORMANCE_SCHEMA.STATUS_BY_THREAD. */ +class table_status_by_thread : public PFS_engine_table +{ + typedef pos_status_by_thread pos_t; + +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + static ha_rows get_row_count(); + + 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_status_by_thread(); + +public: + ~table_status_by_thread() + {} + +protected: + int materialize(PFS_thread *thread); + void make_row(PFS_thread *thread, const Status_variable *status_var); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current THD variables. */ + PFS_status_variable_cache m_status_cache; + /** Current row. */ + row_status_by_thread m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + + /** Table context with global status array version and map of materialized threads. */ + table_status_by_thread_context *m_context; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_status_by_user.cc b/storage/perfschema/table_status_by_user.cc new file mode 100644 index 00000000000..921a72247b6 --- /dev/null +++ b/storage/perfschema/table_status_by_user.cc @@ -0,0 +1,246 @@ +/* Copyright (c) 2015, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_status_by_user.cc + Table STATUS_BY_USER (implementation). +*/ + +#include "my_global.h" +#include "table_status_by_user.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_global.h" +#include "pfs_account.h" +#include "pfs_visitor.h" + +THR_LOCK table_status_by_user::m_table_lock; + +PFS_engine_table_share +table_status_by_user::m_share= +{ + { C_STRING_WITH_LEN("status_by_user") }, + &pfs_truncatable_acl, + table_status_by_user::create, + NULL, /* write_row */ + table_status_by_user::delete_all_rows, + table_status_by_user::get_row_count, + sizeof(pos_t), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE status_by_user(" + "USER CHAR(32) collate utf8_bin default null," + "VARIABLE_NAME VARCHAR(64) not null," + "VARIABLE_VALUE VARCHAR(1024))") }, + false /* perpetual */ +}; + +PFS_engine_table* +table_status_by_user::create(void) +{ + return new table_status_by_user(); +} + +int table_status_by_user::delete_all_rows(void) +{ + mysql_mutex_lock(&LOCK_status); + reset_status_by_thread(); + reset_status_by_account(); + reset_status_by_user(); + mysql_mutex_unlock(&LOCK_status); + return 0; +} + +ha_rows table_status_by_user::get_row_count(void) +{ + mysql_mutex_lock(&LOCK_status); + size_t status_var_count= all_status_vars.elements; + mysql_mutex_unlock(&LOCK_status); + return (global_user_container.get_row_count() * status_var_count); +} + +table_status_by_user::table_status_by_user() + : PFS_engine_table(&m_share, &m_pos), + m_status_cache(true), m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_status_by_user::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_status_by_user::rnd_init(bool scan) +{ + if (show_compatibility_56) + return 0; + + /* + Build array of SHOW_VARs from the global status array prior to materializing + threads in rnd_next() or rnd_pos(). + */ + m_status_cache.initialize_client_session(); + + /* Use the current number of status variables to detect changes. */ + ulonglong status_version= m_status_cache.get_status_array_version(); + + /* + The table context holds the current version of the global status array + and a record of which users were materialized. If scan == true, then + allocate a new context from mem_root and store in TLS. If scan == false, + then restore from TLS. + */ + m_context= (table_status_by_user_context *)current_thd->alloc(sizeof(table_status_by_user_context)); + new(m_context) table_status_by_user_context(status_version, !scan); + return 0; +} + +int table_status_by_user::rnd_next(void) +{ + if (show_compatibility_56) + return HA_ERR_END_OF_FILE; + + /* If status array changes, exit with warning. */ // TODO: Issue warning + if (!m_context->versions_match()) + return HA_ERR_END_OF_FILE; + + /* + For each user, build a cache of status variables using totals from all + threads associated with the user. + */ + bool has_more_user= true; + + for (m_pos.set_at(&m_next_pos); + has_more_user; + m_pos.next_user()) + { + PFS_user *pfs_user= global_user_container.get(m_pos.m_index_1, &has_more_user); + + if (m_status_cache.materialize_user(pfs_user) == 0) + { + /* Mark this user as materialized. */ + m_context->set_item(m_pos.m_index_1); + + /* Get the next status variable. */ + const Status_variable *stat_var= m_status_cache.get(m_pos.m_index_2); + if (stat_var != NULL) + { + make_row(pfs_user, stat_var); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + return HA_ERR_END_OF_FILE; +} + +int +table_status_by_user::rnd_pos(const void *pos) +{ + if (show_compatibility_56) + return HA_ERR_RECORD_DELETED; + + /* If status array changes, exit with warning. */ // TODO: Issue warning + if (!m_context->versions_match()) + return HA_ERR_END_OF_FILE; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < global_user_container.get_row_count()); + + PFS_user *pfs_user= global_user_container.get(m_pos.m_index_1); + + /* + Only materialize threads that were previously materialized by rnd_next(). + If a user cannot be rematerialized, then do nothing. + */ + if (m_context->is_item_set(m_pos.m_index_1) && + m_status_cache.materialize_user(pfs_user) == 0) + { + const Status_variable *stat_var= m_status_cache.get(m_pos.m_index_2); + if (stat_var != NULL) + { + make_row(pfs_user, stat_var); + return 0; + } + } + return HA_ERR_RECORD_DELETED; +} + +void table_status_by_user +::make_row(PFS_user *user, const Status_variable *status_var) +{ + pfs_optimistic_state lock; + m_row_exists= false; + user->m_lock.begin_optimistic_lock(&lock); + + if (m_row.m_user.make_row(user)) + return; + + m_row.m_variable_name.make_row(status_var->m_name, status_var->m_name_length); + m_row.m_variable_value.make_row(status_var); + + if (!user->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; +} + +int table_status_by_user +::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: /* VARIABLE_NAME */ + set_field_varchar_utf8(f, m_row.m_variable_name.m_str, m_row.m_variable_name.m_length); + break; + case 2: /* VARIABLE_VALUE */ + m_row.m_variable_value.set_field(f); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_status_by_user.h b/storage/perfschema/table_status_by_user.h new file mode 100644 index 00000000000..6b4a67b4e3f --- /dev/null +++ b/storage/perfschema/table_status_by_user.h @@ -0,0 +1,153 @@ +/* Copyright (c) 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_STATUS_BY_USER_H +#define TABLE_STATUS_BY_USER_H + +/** + @file storage/perfschema/table_status_by_user.h + Table STATUS_BY_USER (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" +#include "pfs_variable.h" +#include "pfs_buffer_container.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.STATUS_BY_USER. +*/ +struct row_status_by_user +{ + /** Column USER */ + PFS_user_row m_user; + /** Column VARIABLE_NAME. */ + PFS_variable_name_row m_variable_name; + /** Column VARIABLE_VALUE. */ + PFS_variable_value_row m_variable_value; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.STATUS_BY_USER. + Index 1 on user (0 based) + Index 2 on status variable (0 based) +*/ +struct pos_status_by_user +: public PFS_double_index +{ + pos_status_by_user() + : PFS_double_index(0, 0) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 0; + } + + inline bool has_more_user(void) + { return (m_index_1 < global_user_container.get_row_count()); } + + inline void next_user(void) + { + m_index_1++; + m_index_2= 0; + } +}; + +/** + Store and retrieve table state information for queries that reinstantiate + the table object. +*/ +class table_status_by_user_context : public PFS_table_context +{ +public: + table_status_by_user_context(ulonglong current_version, bool restore) : + PFS_table_context(current_version, global_user_container.get_row_count(), restore, THR_PFS_SBU) { } +}; + +/** Table PERFORMANCE_SCHEMA.STATUS_BY_USER. */ +class table_status_by_user : public PFS_engine_table +{ + typedef pos_status_by_user pos_t; + +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static int delete_all_rows(); + static ha_rows get_row_count(); + + 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_status_by_user(); + +public: + ~table_status_by_user() { } + +protected: + int materialize(PFS_thread *thread); + void make_row(PFS_user *user, const Status_variable *status_var); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Status variable cache for one user. */ + PFS_status_variable_cache m_status_cache; + + /** Current row. */ + row_status_by_user m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + + /** Table context with global status array version and map of materialized threads. */ + table_status_by_user_context *m_context; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_sync_instances.cc b/storage/perfschema/table_sync_instances.cc index f0c7800d24a..5b9f90c1092 100644 --- a/storage/perfschema/table_sync_instances.cc +++ b/storage/perfschema/table_sync_instances.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, version 2.0, @@ -27,12 +27,14 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "pfs_instr.h" #include "pfs_column_types.h" #include "pfs_column_values.h" #include "table_sync_instances.h" #include "pfs_global.h" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_mutex_instances::m_table_lock; @@ -41,17 +43,17 @@ table_mutex_instances::m_share= { { C_STRING_WITH_LEN("mutex_instances") }, &pfs_readonly_acl, - &table_mutex_instances::create, + table_mutex_instances::create, NULL, /* write_row */ NULL, /* delete_all_rows */ - NULL, /* get_row_count */ - 1000, /* records */ + table_mutex_instances::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { 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)") } + "LOCKED_BY_THREAD_ID BIGINT unsigned)") }, + false /* perpetual */ }; PFS_engine_table* table_mutex_instances::create(void) @@ -59,6 +61,12 @@ PFS_engine_table* table_mutex_instances::create(void) return new table_mutex_instances(); } +ha_rows +table_mutex_instances::get_row_count(void) +{ + return global_mutex_container.get_row_count(); +} + table_mutex_instances::table_mutex_instances() : PFS_engine_table(&m_share, &m_pos), m_row_exists(false), m_pos(0), m_next_pos(0) @@ -74,15 +82,14 @@ int table_mutex_instances::rnd_next(void) { PFS_mutex *pfs; - for (m_pos.set_at(&m_next_pos); m_pos.m_index < mutex_max; m_pos.next()) + m_pos.set_at(&m_next_pos); + PFS_mutex_iterator it= global_mutex_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - pfs= &mutex_array[m_pos.m_index]; - if (pfs->m_lock.is_populated()) - { - make_row(pfs); - m_next_pos.set_after(&m_pos); - return 0; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -93,9 +100,9 @@ int table_mutex_instances::rnd_pos(const void *pos) PFS_mutex *pfs; set_position(pos); - DBUG_ASSERT(m_pos.m_index < mutex_max); - pfs= &mutex_array[m_pos.m_index]; - if (pfs->m_lock.is_populated()) + + pfs= global_mutex_container.get(m_pos.m_index); + if (pfs != NULL) { make_row(pfs); return 0; @@ -106,7 +113,7 @@ int table_mutex_instances::rnd_pos(const void *pos) void table_mutex_instances::make_row(PFS_mutex *pfs) { - pfs_lock lock; + pfs_optimistic_state lock; PFS_mutex_class *safe_class; m_row_exists= false; @@ -184,18 +191,18 @@ table_rwlock_instances::m_share= { { C_STRING_WITH_LEN("rwlock_instances") }, &pfs_readonly_acl, - &table_rwlock_instances::create, + table_rwlock_instances::create, NULL, /* write_row */ NULL, /* delete_all_rows */ - NULL, /* get_row_count */ - 1000, /* records */ + table_rwlock_instances::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { 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)") } + "READ_LOCKED_BY_COUNT INTEGER unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* table_rwlock_instances::create(void) @@ -203,6 +210,12 @@ PFS_engine_table* table_rwlock_instances::create(void) return new table_rwlock_instances(); } +ha_rows +table_rwlock_instances::get_row_count(void) +{ + return global_rwlock_container.get_row_count(); +} + table_rwlock_instances::table_rwlock_instances() : PFS_engine_table(&m_share, &m_pos), m_row_exists(false), m_pos(0), m_next_pos(0) @@ -218,15 +231,14 @@ int table_rwlock_instances::rnd_next(void) { PFS_rwlock *pfs; - for (m_pos.set_at(&m_next_pos); m_pos.m_index < rwlock_max; m_pos.next()) + m_pos.set_at(&m_next_pos); + PFS_rwlock_iterator it= global_rwlock_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - pfs= &rwlock_array[m_pos.m_index]; - if (pfs->m_lock.is_populated()) - { - make_row(pfs); - m_next_pos.set_after(&m_pos); - return 0; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -237,9 +249,9 @@ int table_rwlock_instances::rnd_pos(const void *pos) PFS_rwlock *pfs; set_position(pos); - DBUG_ASSERT(m_pos.m_index < rwlock_max); - pfs= &rwlock_array[m_pos.m_index]; - if (pfs->m_lock.is_populated()) + + pfs= global_rwlock_container.get(m_pos.m_index); + if (pfs != NULL) { make_row(pfs); return 0; @@ -250,7 +262,7 @@ int table_rwlock_instances::rnd_pos(const void *pos) void table_rwlock_instances::make_row(PFS_rwlock *pfs) { - pfs_lock lock; + pfs_optimistic_state lock; PFS_rwlock_class *safe_class; m_row_exists= false; @@ -335,16 +347,16 @@ table_cond_instances::m_share= { { C_STRING_WITH_LEN("cond_instances") }, &pfs_readonly_acl, - &table_cond_instances::create, + table_cond_instances::create, NULL, /* write_row */ NULL, /* delete_all_rows */ - NULL, /* get_row_count */ - 1000, /* records */ + table_cond_instances::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE cond_instances(" "NAME VARCHAR(128) not null," - "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null)") } + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* table_cond_instances::create(void) @@ -352,6 +364,12 @@ PFS_engine_table* table_cond_instances::create(void) return new table_cond_instances(); } +ha_rows +table_cond_instances::get_row_count(void) +{ + return global_cond_container.get_row_count(); +} + table_cond_instances::table_cond_instances() : PFS_engine_table(&m_share, &m_pos), m_row_exists(false), m_pos(0), m_next_pos(0) @@ -367,15 +385,14 @@ int table_cond_instances::rnd_next(void) { PFS_cond *pfs; - for (m_pos.set_at(&m_next_pos); m_pos.m_index < cond_max; m_pos.next()) + m_pos.set_at(&m_next_pos); + PFS_cond_iterator it= global_cond_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - pfs= &cond_array[m_pos.m_index]; - if (pfs->m_lock.is_populated()) - { - make_row(pfs); - m_next_pos.set_after(&m_pos); - return 0; - } + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; } return HA_ERR_END_OF_FILE; @@ -386,9 +403,9 @@ int table_cond_instances::rnd_pos(const void *pos) PFS_cond *pfs; set_position(pos); - DBUG_ASSERT(m_pos.m_index < cond_max); - pfs= &cond_array[m_pos.m_index]; - if (pfs->m_lock.is_populated()) + + pfs= global_cond_container.get(m_pos.m_index); + if (pfs != NULL) { make_row(pfs); return 0; @@ -399,7 +416,7 @@ int table_cond_instances::rnd_pos(const void *pos) void table_cond_instances::make_row(PFS_cond *pfs) { - pfs_lock lock; + pfs_optimistic_state lock; PFS_cond_class *safe_class; m_row_exists= false; diff --git a/storage/perfschema/table_sync_instances.h b/storage/perfschema/table_sync_instances.h index 6f7e1bf5523..6cf8f0f3669 100644 --- a/storage/perfschema/table_sync_instances.h +++ b/storage/perfschema/table_sync_instances.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, version 2.0, @@ -62,6 +62,7 @@ public: /** Table share. */ static PFS_engine_table_share m_share; static PFS_engine_table* create(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); @@ -119,6 +120,7 @@ public: /** Table share */ static PFS_engine_table_share m_share; static PFS_engine_table* create(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); @@ -170,6 +172,7 @@ public: /** Table share. */ static PFS_engine_table_share m_share; static PFS_engine_table* create(); + static ha_rows get_row_count(); virtual int rnd_next(); virtual int rnd_pos(const void *pos); diff --git a/storage/perfschema/table_table_handles.cc b/storage/perfschema/table_table_handles.cc new file mode 100644 index 00000000000..ab6ed357687 --- /dev/null +++ b/storage/perfschema/table_table_handles.cc @@ -0,0 +1,214 @@ +/* Copyright (c) 2012, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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, Suite 500, Boston, MA 02110-1335 USA */ + +/** + @file storage/perfschema/table_table_handles.cc + Table TABLE_TABLE_HANDLES (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_table_handles.h" +#include "pfs_global.h" +#include "pfs_stat.h" +#include "pfs_buffer_container.h" +#include "field.h" + +THR_LOCK table_table_handles::m_table_lock; + +PFS_engine_table_share +table_table_handles::m_share= +{ + { C_STRING_WITH_LEN("table_handles") }, + &pfs_readonly_acl, + table_table_handles::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_table_handles::get_row_count, + sizeof(PFS_simple_index), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE table_handles(" + "OBJECT_TYPE VARCHAR(64) not null," + "OBJECT_SCHEMA VARCHAR(64) not null," + "OBJECT_NAME VARCHAR(64) not null," + "OBJECT_INSTANCE_BEGIN BIGINT unsigned not null," + "OWNER_THREAD_ID BIGINT unsigned," + "OWNER_EVENT_ID BIGINT unsigned," + "INTERNAL_LOCK VARCHAR(64)," + "EXTERNAL_LOCK VARCHAR(64))") }, + false /* perpetual */ +}; + +PFS_engine_table* +table_table_handles::create(void) +{ + return new table_table_handles(); +} + +ha_rows +table_table_handles::get_row_count(void) +{ + return global_table_container.get_row_count(); +} + +table_table_handles::table_table_handles() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(0), m_next_pos(0) +{} + +void table_table_handles::reset_position(void) +{ + m_pos.m_index= 0; + m_next_pos.m_index= 0; +} + +int table_table_handles::rnd_init(bool scan) +{ + return 0; +} + +int table_table_handles::rnd_next(void) +{ + PFS_table *pfs; + + m_pos.set_at(&m_next_pos); + PFS_table_iterator it= global_table_container.iterate(m_pos.m_index); + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } + + return HA_ERR_END_OF_FILE; +} + +int +table_table_handles::rnd_pos(const void *pos) +{ + PFS_table *pfs; + + set_position(pos); + + pfs= global_table_container.get(m_pos.m_index); + if (pfs != NULL) + { + make_row(pfs); + return 0; + } + + return HA_ERR_RECORD_DELETED; +} + +void table_table_handles::make_row(PFS_table *table) +{ + pfs_optimistic_state lock; + PFS_table_share *share; + PFS_thread *thread; + + m_row_exists= false; + + table->m_lock.begin_optimistic_lock(&lock); + + share= sanitize_table_share(table->m_share); + if (share == NULL) + return; + + if (m_row.m_object.make_row(share)) + return; + + m_row.m_identity= table->m_identity; + + thread= sanitize_thread(table->m_thread_owner); + if (thread != NULL) + { + m_row.m_owner_thread_id= thread->m_thread_internal_id; + m_row.m_owner_event_id= table->m_owner_event_id; + } + else + { + m_row.m_owner_thread_id= 0; + m_row.m_owner_event_id= 0; + } + + m_row.m_internal_lock= table->m_internal_lock; + m_row.m_external_lock= table->m_external_lock; + + if (! table->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; +} + +int table_table_handles::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: /* OBJECT_INSTANCE_BEGIN */ + set_field_ulonglong(f, (intptr) m_row.m_identity); + break; + case 4: /* OWNER_THREAD_ID */ + set_field_ulonglong(f, m_row.m_owner_thread_id); + break; + case 5: /* OWNER_EVENT_ID */ + set_field_ulonglong(f, m_row.m_owner_event_id); + break; + case 6: /* INTERNAL_LOCK */ + set_field_lock_type(f, m_row.m_internal_lock); + break; + case 7: /* EXTERNAL_LOCK */ + set_field_lock_type(f, m_row.m_external_lock); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_table_handles.h b/storage/perfschema/table_table_handles.h new file mode 100644 index 00000000000..0f1f76f4846 --- /dev/null +++ b/storage/perfschema/table_table_handles.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2012, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + 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, Suite 500, Boston, MA 02110-1335 USA */ + +#ifndef TABLE_TABLE_HANDLES_H +#define TABLE_TABLE_HANDLES_H + +/** + @file storage/perfschema/table_table_handles.h + Table TABLE_HANDLES (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_HANDLES. +*/ +struct row_table_handles +{ + /** Column OBJECT_TYPE, SCHEMA_NAME, OBJECT_NAME. */ + PFS_object_row m_object; + /** Column OBJECT_INSTANCE_BEGIN. */ + const void *m_identity; + /** Column OWNER_THREAD_ID. */ + ulonglong m_owner_thread_id; + /** Column OWNER_EVENT_ID. */ + ulonglong m_owner_event_id; + /** Column INTERNAL_LOCK. */ + PFS_TL_LOCK_TYPE m_internal_lock; + /** Column EXTERNAL_LOCK. */ + PFS_TL_LOCK_TYPE m_external_lock; +}; + +/** Table PERFORMANCE_SCHEMA.TABLE_HANDLES. */ +class table_table_handles : public PFS_engine_table +{ +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + + 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_table_handles(); + +public: + ~table_table_handles() + {} + +protected: + void make_row(PFS_table *table); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current row. */ + row_table_handles 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_threads.cc b/storage/perfschema/table_threads.cc index b396db1a814..6d83b6531b6 100644 --- a/storage/perfschema/table_threads.cc +++ b/storage/perfschema/table_threads.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2014, 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, version 2.0, @@ -21,12 +21,40 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.h" #include "table_threads.h" #include "sql_parse.h" #include "pfs_instr_class.h" #include "pfs_instr.h" +static const LEX_CSTRING vio_type_names[] = +{ + { STRING_WITH_LEN("Error") }, // cannot happen + { STRING_WITH_LEN("TCP/IP") }, + { STRING_WITH_LEN("Socket") }, + { STRING_WITH_LEN("Named Pipe") }, + { STRING_WITH_LEN("SSL/TLS") }, + { STRING_WITH_LEN("Shared Memory") } +}; + +static void get_vio_type_name(enum enum_vio_type vio_type, const char **str, int *len) +{ + int index; + + if ((vio_type >= FIRST_VIO_TYPE) && (vio_type <= LAST_VIO_TYPE)) + { + index= vio_type; + } + else + { + index= 0; + } + *str= vio_type_names[index].str; + *len= vio_type_names[index].length; + return; +} + + THR_LOCK table_threads::m_table_lock; PFS_engine_table_share @@ -34,11 +62,10 @@ table_threads::m_share= { { C_STRING_WITH_LEN("threads") }, &pfs_updatable_acl, - &table_threads::create, + table_threads::create, NULL, /* write_row */ NULL, /* delete_all_rows */ - NULL, /* get_row_count */ - 1000, /* records */ + cursor_by_thread::get_row_count, sizeof(PFS_simple_index), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE threads(" @@ -46,7 +73,7 @@ table_threads::m_share= "NAME VARCHAR(128) not null," "TYPE VARCHAR(10) not null," "PROCESSLIST_ID BIGINT unsigned," - "PROCESSLIST_USER VARCHAR(16)," + "PROCESSLIST_USER VARCHAR(" USERNAME_CHAR_LENGTH_STR ")," "PROCESSLIST_HOST VARCHAR(60)," "PROCESSLIST_DB VARCHAR(64)," "PROCESSLIST_COMMAND VARCHAR(16)," @@ -55,7 +82,11 @@ table_threads::m_share= "PROCESSLIST_INFO LONGTEXT," "PARENT_THREAD_ID BIGINT unsigned," "ROLE VARCHAR(64)," - "INSTRUMENTED ENUM ('YES', 'NO') not null)") } + "INSTRUMENTED ENUM ('YES', 'NO') not null," + "HISTORY ENUM ('YES', 'NO') not null," + "CONNECTION_TYPE VARCHAR(16)" + "THREAD_OS_ID BIGINT unsigned)") }, + false /* perpetual */ }; PFS_engine_table* table_threads::create() @@ -70,9 +101,9 @@ table_threads::table_threads() void table_threads::make_row(PFS_thread *pfs) { - pfs_lock lock; - pfs_lock session_lock; - pfs_lock stmt_lock; + pfs_optimistic_state lock; + pfs_optimistic_state session_lock; + pfs_optimistic_state stmt_lock; PFS_stage_class *stage_class; PFS_thread_class *safe_class; @@ -88,6 +119,7 @@ void table_threads::make_row(PFS_thread *pfs) m_row.m_thread_internal_id= pfs->m_thread_internal_id; m_row.m_parent_thread_internal_id= pfs->m_parent_thread_internal_id; m_row.m_processlist_id= pfs->m_processlist_id; + m_row.m_thread_os_id= pfs->m_thread_os_id; m_row.m_name= safe_class->m_name; m_row.m_name_length= safe_class->m_name_length; @@ -165,8 +197,12 @@ void table_threads::make_row(PFS_thread *pfs) { m_row.m_processlist_state_length= 0; } + m_row.m_connection_type = pfs->m_connection_type; - m_row.m_enabled_ptr= &pfs->m_enabled; + + m_row.m_enabled= pfs->m_enabled; + m_row.m_history= pfs->m_history; + m_row.m_psi= pfs; if (pfs->m_lock.end_optimistic_lock(& lock)) m_row_exists= true; @@ -178,6 +214,8 @@ int table_threads::read_row_values(TABLE *table, bool read_all) { Field *f; + const char *str= NULL; + int len= 0; if (unlikely(! m_row_exists)) return HA_ERR_RECORD_DELETED; @@ -250,23 +288,16 @@ int table_threads::read_row_values(TABLE *table, f->set_null(); break; case 9: /* PROCESSLIST_STATE */ + /* This column's datatype is declared as varchar(64). Thread's state + message cannot be more than 64 characters. Otherwise, we will end up + in 'data truncated' warning/error (depends sql_mode setting) when + server is updating this column for those threads. To prevent this + kind of issue, an assert is added. + */ + DBUG_ASSERT(m_row.m_processlist_state_length <= f->char_length()); 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, - MY_MIN(m_row.m_processlist_state_length, - f->char_length())); - } + m_row.m_processlist_state_length); else f->set_null(); break; @@ -287,7 +318,23 @@ int table_threads::read_row_values(TABLE *table, f->set_null(); break; case 13: /* INSTRUMENTED */ - set_field_enum(f, (*m_row.m_enabled_ptr) ? ENUM_YES : ENUM_NO); + set_field_enum(f, m_row.m_enabled ? ENUM_YES : ENUM_NO); + break; + case 14: /* HISTORY */ + set_field_enum(f, m_row.m_history ? ENUM_YES : ENUM_NO); + break; + case 15: /* CONNECTION_TYPE */ + get_vio_type_name(m_row.m_connection_type, & str, & len); + if (len > 0) + set_field_varchar_utf8(f, str, len); + else + f->set_null(); + break; + case 16: /* THREAD_OS_ID */ + if (m_row.m_thread_os_id > 0) + set_field_ulonglong(f, m_row.m_thread_os_id); + else + f->set_null(); break; default: DBUG_ASSERT(false); @@ -327,8 +374,15 @@ int table_threads::update_row_values(TABLE *table, 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; + m_row.m_psi->set_enabled((value == ENUM_YES) ? true : false); break; + case 14: /* HISTORY */ + value= (enum_yes_no) get_field_enum(f); + m_row.m_psi->set_history((value == ENUM_YES) ? true : false); + break; + case 15: /* CONNECTION_TYPE */ + case 16: /* THREAD_OS_ID */ + return HA_ERR_WRONG_COMMAND; default: DBUG_ASSERT(false); } diff --git a/storage/perfschema/table_threads.h b/storage/perfschema/table_threads.h index 841b8102bca..88302ea61de 100644 --- a/storage/perfschema/table_threads.h +++ b/storage/perfschema/table_threads.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2011, 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, version 2.0, @@ -70,10 +70,18 @@ struct row_threads 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 INSTRUMENTED (read). */ + bool m_enabled; + /** Column HISTORY (read). */ + bool m_history; + /** INSTRUMENTED and HISTORY (write). */ + PFS_thread *m_psi; /** Column PARENT_THREAD_ID. */ ulonglong m_parent_thread_internal_id; + /** Column CONNECTION_TYPE. */ + enum_vio_type m_connection_type; + /** Column THREAD_OS_ID. */ + my_thread_os_id_t m_thread_os_id; }; /** Table PERFORMANCE_SCHEMA.THREADS. */ diff --git a/storage/perfschema/table_tiws_by_index_usage.cc b/storage/perfschema/table_tiws_by_index_usage.cc index b49e9280469..a1a7343e65b 100644 --- a/storage/perfschema/table_tiws_by_index_usage.cc +++ b/storage/perfschema/table_tiws_by_index_usage.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,13 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_tiws_by_index_usage::m_table_lock; @@ -44,8 +46,7 @@ table_tiws_by_index_usage::m_share= table_tiws_by_index_usage::create, NULL, /* write_row */ table_tiws_by_index_usage::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_tiws_by_index_usage::get_row_count, sizeof(pos_tiws_by_index_usage), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE table_io_waits_summary_by_index_usage(" @@ -87,7 +88,8 @@ table_tiws_by_index_usage::m_share= "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)") } + "MAX_TIMER_DELETE BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -104,6 +106,12 @@ table_tiws_by_index_usage::delete_all_rows(void) return 0; } +ha_rows +table_tiws_by_index_usage::get_row_count(void) +{ + return global_table_share_index_container.get_row_count(); +} + 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() @@ -124,27 +132,31 @@ int table_tiws_by_index_usage::rnd_init(bool scan) int table_tiws_by_index_usage::rnd_next(void) { PFS_table_share *table_share; + bool has_more_table= true; for (m_pos.set_at(&m_next_pos); - m_pos.has_more_table(); + has_more_table; m_pos.next_table()) { - table_share= &table_share_array[m_pos.m_index_1]; - if (table_share->m_lock.is_populated()) + table_share= global_table_share_container.get(m_pos.m_index_1, & has_more_table); + if (table_share != NULL) { - uint safe_key_count= sanitize_index_count(table_share->m_key_count); - if (m_pos.m_index_2 < safe_key_count) + if (table_share->m_enabled) { - 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; + 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; + } } } } @@ -159,40 +171,58 @@ table_tiws_by_index_usage::rnd_pos(const void *pos) set_position(pos); - table_share= &table_share_array[m_pos.m_index_1]; - if (table_share->m_lock.is_populated()) + table_share= global_table_share_container.get(m_pos.m_index_1); + if (table_share != NULL) { - 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) + if (table_share->m_enabled) { - make_row(table_share, m_pos.m_index_2); - return 0; + 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) +void table_tiws_by_index_usage::make_row(PFS_table_share *pfs_share, + uint index) { - pfs_lock lock; + PFS_table_share_index *pfs_index; + pfs_optimistic_state lock; - m_row_exists= false; + DBUG_ASSERT(index <= MAX_INDEXES); - share->m_lock.begin_optimistic_lock(&lock); + m_row_exists= false; - if (m_row.m_index.make_row(share, index)) - return; + pfs_share->m_lock.begin_optimistic_lock(&lock); PFS_index_io_stat_visitor visitor; - PFS_object_iterator::visit_table_indexes(share, index, & visitor); + PFS_object_iterator::visit_table_indexes(pfs_share, index, & visitor); + + if (! visitor.m_stat.m_has_data) + { + pfs_index= pfs_share->find_index_stat(index); + if (pfs_index == NULL) + return; + } + else + { + pfs_index= pfs_share->find_index_stat(index); + } + + if (m_row.m_index.make_row(pfs_share, pfs_index, index)) + return; - if (! share->m_lock.end_optimistic_lock(&lock)) + if (! pfs_share->m_lock.end_optimistic_lock(&lock)) return; m_row_exists= true; diff --git a/storage/perfschema/table_tiws_by_index_usage.h b/storage/perfschema/table_tiws_by_index_usage.h index a284bc7f0bc..cc6ee5ebfe7 100644 --- a/storage/perfschema/table_tiws_by_index_usage.h +++ b/storage/perfschema/table_tiws_by_index_usage.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -54,7 +54,7 @@ struct row_tiws_by_index_usage /** Position of a cursor on PERFORMANCE_SCHEMA.TABLE_IO_WAIT_SUMMARY_BY_INDEX. - Index 1 on table_share_array (0 based) + Index 1 on global_table_share_container (0 based) Index 2 on index (0 based) */ struct pos_tiws_by_index_usage : public PFS_double_index @@ -69,11 +69,6 @@ struct pos_tiws_by_index_usage : public PFS_double_index 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++; @@ -89,6 +84,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_tiws_by_table.cc b/storage/perfschema/table_tiws_by_table.cc index db00fd2409e..abd45a7bf3a 100644 --- a/storage/perfschema/table_tiws_by_table.cc +++ b/storage/perfschema/table_tiws_by_table.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,13 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_tiws_by_table::m_table_lock; @@ -44,8 +46,7 @@ table_tiws_by_table::m_share= table_tiws_by_table::create, NULL, /* write_row */ table_tiws_by_table::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_tiws_by_table::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE table_io_waits_summary_by_table(" @@ -86,7 +87,8 @@ table_tiws_by_table::m_share= "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)") } + "MAX_TIMER_DELETE BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -103,6 +105,12 @@ table_tiws_by_table::delete_all_rows(void) return 0; } +ha_rows +table_tiws_by_table::get_row_count(void) +{ + return global_table_share_container.get_row_count(); +} + 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) @@ -122,20 +130,23 @@ int table_tiws_by_table::rnd_init(bool scan) int table_tiws_by_table::rnd_next(void) { - PFS_table_share *table_share; + PFS_table_share *pfs; - for (m_pos.set_at(&m_next_pos); - m_pos.m_index < table_share_max; - m_pos.m_index++) + m_pos.set_at(&m_next_pos); + PFS_table_share_iterator it= global_table_share_container.iterate(m_pos.m_index); + do { - table_share= &table_share_array[m_pos.m_index]; - if (table_share->m_lock.is_populated()) + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - make_row(table_share); - m_next_pos.set_after(&m_pos); - return 0; + if (pfs->m_enabled) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } } - } + } while (pfs != NULL); return HA_ERR_END_OF_FILE; } @@ -143,15 +154,18 @@ int table_tiws_by_table::rnd_next(void) int table_tiws_by_table::rnd_pos(const void *pos) { - PFS_table_share *table_share; + PFS_table_share *pfs; set_position(pos); - table_share= &table_share_array[m_pos.m_index]; - if (table_share->m_lock.is_populated()) + pfs= global_table_share_container.get(m_pos.m_index); + if (pfs != NULL) { - make_row(table_share); - return 0; + if (pfs->m_enabled) + { + make_row(pfs); + return 0; + } } return HA_ERR_RECORD_DELETED; @@ -159,7 +173,7 @@ table_tiws_by_table::rnd_pos(const void *pos) void table_tiws_by_table::make_row(PFS_table_share *share) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; diff --git a/storage/perfschema/table_tiws_by_table.h b/storage/perfschema/table_tiws_by_table.h index 7427ca797fa..4100a99156b 100644 --- a/storage/perfschema/table_tiws_by_table.h +++ b/storage/perfschema/table_tiws_by_table.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -59,6 +59,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_tlws_by_table.cc b/storage/perfschema/table_tlws_by_table.cc index d802127d10d..0b0758469d7 100644 --- a/storage/perfschema/table_tlws_by_table.cc +++ b/storage/perfschema/table_tlws_by_table.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -26,13 +26,15 @@ */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_buffer_container.h" +#include "field.h" THR_LOCK table_tlws_by_table::m_table_lock; @@ -44,8 +46,7 @@ table_tlws_by_table::m_share= table_tlws_by_table::create, NULL, /* write_row */ table_tlws_by_table::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + table_tlws_by_table::get_row_count, sizeof(PFS_simple_index), &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE table_lock_waits_summary_by_table(" @@ -102,11 +103,6 @@ table_tlws_by_table::m_share= "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," @@ -121,7 +117,8 @@ table_tlws_by_table::m_share= "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)") } + "MAX_TIMER_WRITE_EXTERNAL BIGINT unsigned not null)") }, + false /* perpetual */ }; PFS_engine_table* @@ -138,6 +135,12 @@ table_tlws_by_table::delete_all_rows(void) return 0; } +ha_rows +table_tlws_by_table::get_row_count(void) +{ + return global_table_share_container.get_row_count(); +} + 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) @@ -157,20 +160,23 @@ int table_tlws_by_table::rnd_init(bool scan) int table_tlws_by_table::rnd_next(void) { - PFS_table_share *table_share; + PFS_table_share *pfs; - for (m_pos.set_at(&m_next_pos); - m_pos.m_index < table_share_max; - m_pos.m_index++) + m_pos.set_at(&m_next_pos); + PFS_table_share_iterator it= global_table_share_container.iterate(m_pos.m_index); + do { - table_share= &table_share_array[m_pos.m_index]; - if (table_share->m_lock.is_populated()) + pfs= it.scan_next(& m_pos.m_index); + if (pfs != NULL) { - make_row(table_share); - m_next_pos.set_after(&m_pos); - return 0; + if (pfs->m_enabled) + { + make_row(pfs); + m_next_pos.set_after(&m_pos); + return 0; + } } - } + } while (pfs != NULL); return HA_ERR_END_OF_FILE; } @@ -178,15 +184,18 @@ int table_tlws_by_table::rnd_next(void) int table_tlws_by_table::rnd_pos(const void *pos) { - PFS_table_share *table_share; + PFS_table_share *pfs; set_position(pos); - table_share= &table_share_array[m_pos.m_index]; - if (table_share->m_lock.is_populated()) + pfs= global_table_share_container.get(m_pos.m_index); + if (pfs != NULL) { - make_row(table_share); - return 0; + if (pfs->m_enabled) + { + make_row(pfs); + return 0; + } } return HA_ERR_RECORD_DELETED; @@ -194,7 +203,7 @@ table_tlws_by_table::rnd_pos(const void *pos) void table_tlws_by_table::make_row(PFS_table_share *share) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; @@ -396,67 +405,51 @@ int table_tlws_by_table::read_row_values(TABLE *table, 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 */ + case 53: /* 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 */ + case 54: /* 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 */ + case 55: /* 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 */ + case 56: /* 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 */ + case 57: /* 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 */ + case 58: /* COUNT_WRITE_NORMAL */ set_field_ulonglong(f, m_row.m_stat.m_write_normal.m_count); break; - case 64: /* SUM_TIMER_WRITE_NORMAL */ + case 59: /* SUM_TIMER_WRITE_NORMAL */ set_field_ulonglong(f, m_row.m_stat.m_write_normal.m_sum); break; - case 65: /* MIN_TIMER_WRITE_NORMAL */ + case 60: /* MIN_TIMER_WRITE_NORMAL */ set_field_ulonglong(f, m_row.m_stat.m_write_normal.m_min); break; - case 66: /* AVG_TIMER_WRITE_NORMAL */ + case 61: /* AVG_TIMER_WRITE_NORMAL */ set_field_ulonglong(f, m_row.m_stat.m_write_normal.m_avg); break; - case 67: /* MAX_TIMER_WRITE_NORMAL */ + case 62: /* MAX_TIMER_WRITE_NORMAL */ set_field_ulonglong(f, m_row.m_stat.m_write_normal.m_max); break; - case 68: /* COUNT_WRITE_EXTERNAL */ + case 63: /* COUNT_WRITE_EXTERNAL */ set_field_ulonglong(f, m_row.m_stat.m_write_external.m_count); break; - case 69: /* SUM_TIMER_WRITE_EXTERNAL */ + case 64: /* SUM_TIMER_WRITE_EXTERNAL */ set_field_ulonglong(f, m_row.m_stat.m_write_external.m_sum); break; - case 70: /* MIN_TIMER_WRITE_EXTERNAL */ + case 65: /* MIN_TIMER_WRITE_EXTERNAL */ set_field_ulonglong(f, m_row.m_stat.m_write_external.m_min); break; - case 71: /* AVG_TIMER_WRITE_EXTERNAL */ + case 66: /* AVG_TIMER_WRITE_EXTERNAL */ set_field_ulonglong(f, m_row.m_stat.m_write_external.m_avg); break; - case 72: /* MAX_TIMER_WRITE_EXTERNAL */ + case 67: /* MAX_TIMER_WRITE_EXTERNAL */ set_field_ulonglong(f, m_row.m_stat.m_write_external.m_max); break; diff --git a/storage/perfschema/table_tlws_by_table.h b/storage/perfschema/table_tlws_by_table.h index b5872a07762..7cc4b666908 100644 --- a/storage/perfschema/table_tlws_by_table.h +++ b/storage/perfschema/table_tlws_by_table.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. +/* 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, version 2.0, @@ -59,6 +59,7 @@ public: static PFS_engine_table_share m_share; static PFS_engine_table* create(); static int delete_all_rows(); + static ha_rows get_row_count(); virtual int rnd_init(bool scan); virtual int rnd_next(); diff --git a/storage/perfschema/table_users.cc b/storage/perfschema/table_users.cc index 883ebd36633..734ff7a4e51 100644 --- a/storage/perfschema/table_users.cc +++ b/storage/perfschema/table_users.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, @@ -21,13 +21,16 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include "my_global.h" -#include "my_pthread.h" +#include "my_thread.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" +#include "pfs_memory.h" +#include "pfs_status.h" +#include "field.h" THR_LOCK table_users::m_table_lock; @@ -36,17 +39,17 @@ table_users::m_share= { { C_STRING_WITH_LEN("users") }, &pfs_truncatable_acl, - &table_users::create, + table_users::create, NULL, /* write_row */ table_users::delete_all_rows, - NULL, /* get_row_count */ - 1000, /* records */ + cursor_by_user::get_row_count, sizeof(PFS_simple_index), /* ref length */ &m_table_lock, { C_STRING_WITH_LEN("CREATE TABLE users(" - "USER CHAR(16) collate utf8_bin default null," + "USER CHAR(" USERNAME_CHAR_LENGTH_STR ") collate utf8_bin default null," "CURRENT_CONNECTIONS bigint not null," - "TOTAL_CONNECTIONS bigint not null)") } + "TOTAL_CONNECTIONS bigint not null)") }, + false /* perpetual */ }; PFS_engine_table* table_users::create() @@ -66,6 +69,15 @@ table_users::delete_all_rows(void) reset_events_statements_by_thread(); reset_events_statements_by_account(); reset_events_statements_by_user(); + reset_events_transactions_by_thread(); + reset_events_transactions_by_account(); + reset_events_transactions_by_user(); + reset_memory_by_thread(); + reset_memory_by_account(); + reset_memory_by_user(); + reset_status_by_thread(); + reset_status_by_account(); + reset_status_by_user(); purge_all_account(); purge_all_user(); return 0; @@ -78,7 +90,7 @@ table_users::table_users() void table_users::make_row(PFS_user *pfs) { - pfs_lock lock; + pfs_optimistic_state lock; m_row_exists= false; pfs->m_lock.begin_optimistic_lock(&lock); @@ -87,7 +99,11 @@ void table_users::make_row(PFS_user *pfs) return; PFS_connection_stat_visitor visitor; - PFS_connection_iterator::visit_user(pfs, true, true, & visitor); + PFS_connection_iterator::visit_user(pfs, + true, /* accounts */ + true, /* threads */ + false, /* THDs */ + & visitor); if (! pfs->m_lock.end_optimistic_lock(& lock)) return; diff --git a/storage/perfschema/table_users.h b/storage/perfschema/table_users.h index 912f0f43714..1c3cc647a9d 100644 --- a/storage/perfschema/table_users.h +++ b/storage/perfschema/table_users.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2011, 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, version 2.0, diff --git a/storage/perfschema/table_uvar_by_thread.cc b/storage/perfschema/table_uvar_by_thread.cc new file mode 100644 index 00000000000..724fc9271d1 --- /dev/null +++ b/storage/perfschema/table_uvar_by_thread.cc @@ -0,0 +1,329 @@ +/* Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_uvar_by_thread.cc + Table USER_VARIABLES_BY_THREAD (implementation). +*/ + +#include "my_global.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "table_uvar_by_thread.h" +#include "pfs_global.h" +#include "pfs_visitor.h" +#include "pfs_buffer_container.h" + +/* Iteration on THD from the sql layer. */ +#include "sql_class.h" +//#include "mysqld_thd_manager.h" + +class Find_thd_user_var //: public Find_THD_Impl +{ +public: + Find_thd_user_var(THD *unsafe_thd) + : m_unsafe_thd(unsafe_thd) + {} + + virtual bool operator()(THD *thd) + { + if (thd != m_unsafe_thd) + return false; + + if (thd->user_vars.records == 0) + return false; + + mysql_mutex_lock(&thd->LOCK_thd_data); + return true; + } + +private: + THD *m_unsafe_thd; +}; + +void User_variables::materialize(PFS_thread *pfs, THD *thd) +{ + reset(); + + m_pfs= pfs; + m_thread_internal_id= pfs->m_thread_internal_id; + m_array.reserve(thd->user_vars.records); + + user_var_entry *sql_uvar; + + uint index= 0; + User_variable empty; + + /* Protects thd->user_vars. */ + mysql_mutex_assert_owner(&thd->LOCK_thd_data); + + for (;;) + { + sql_uvar= reinterpret_cast<user_var_entry*> (my_hash_element(& thd->user_vars, index)); + if (sql_uvar == NULL) + break; + + /* + m_array is a container of objects (not pointers) + + Naive code can: + - build locally a new entry + - add it to the container + but this causes useless object construction, destruction, and deep copies. + + What we do here: + - add a dummy (empty) entry + - the container does a deep copy on something empty, + so that there is nothing to copy. + - get a reference to the entry added in the container + - complete -- in place -- the entry initialization + */ + m_array.push(empty); + User_variable & pfs_uvar= *m_array.back(); + + /* Copy VARIABLE_NAME */ + const char *name= sql_uvar->name.str; + size_t name_length= sql_uvar->name.length; + DBUG_ASSERT(name_length <= sizeof(pfs_uvar.m_name)); + pfs_uvar.m_name.make_row(name, name_length); + + /* Copy VARIABLE_VALUE */ + bool null_value; + String *str_value; + String str_buffer; + uint decimals= 0; + str_value= sql_uvar->val_str(& null_value, & str_buffer, decimals); + if (str_value != NULL) + { + pfs_uvar.m_value.make_row(str_value->ptr(), str_value->length()); + } + else + { + pfs_uvar.m_value.make_row(NULL, 0); + } + + index++; + } +} + +THR_LOCK table_uvar_by_thread::m_table_lock; + +PFS_engine_table_share +table_uvar_by_thread::m_share= +{ + { C_STRING_WITH_LEN("user_variables_by_thread") }, + &pfs_readonly_acl, + table_uvar_by_thread::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_uvar_by_thread::get_row_count, + sizeof(pos_t), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE user_variables_by_thread(" + "THREAD_ID BIGINT unsigned not null," + "VARIABLE_NAME VARCHAR(64) not null," + "VARIABLE_VALUE LONGBLOB)") }, + false /* perpetual */ +}; + +PFS_engine_table* +table_uvar_by_thread::create(void) +{ + return new table_uvar_by_thread(); +} + +ha_rows +table_uvar_by_thread::get_row_count(void) +{ + /* + This is an estimate only, not a hard limit. + The row count is given as a multiple of thread_max, + so that a join between: + - table performance_schema.threads + - table performance_schema.user_variables_by_thread + will still evaluate relative table sizes correctly + when deciding a join order. + */ + return global_thread_container.get_row_count() * 10; +} + +table_uvar_by_thread::table_uvar_by_thread() + : PFS_engine_table(&m_share, &m_pos), + m_row_exists(false), m_pos(), m_next_pos() +{} + +void table_uvar_by_thread::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_uvar_by_thread::rnd_next(void) +{ + PFS_thread *thread; + bool has_more_thread= true; + + for (m_pos.set_at(&m_next_pos); + has_more_thread; + m_pos.next_thread()) + { + thread= global_thread_container.get(m_pos.m_index_1, & has_more_thread); + if (thread != NULL) + { + if (materialize(thread) == 0) + { + const User_variable *uvar= m_THD_cache.get(m_pos.m_index_2); + if (uvar != NULL) + { + make_row(thread, uvar); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + } + + return HA_ERR_END_OF_FILE; +} + +int +table_uvar_by_thread::rnd_pos(const void *pos) +{ + PFS_thread *thread; + + set_position(pos); + + thread= global_thread_container.get(m_pos.m_index_1); + if (thread != NULL) + { + if (materialize(thread) == 0) + { + const User_variable *uvar= m_THD_cache.get(m_pos.m_index_2); + if (uvar != NULL) + { + make_row(thread, uvar); + return 0; + } + } + } + + return HA_ERR_RECORD_DELETED; +} + +int table_uvar_by_thread::materialize(PFS_thread *thread) +{ + if (m_THD_cache.is_materialized(thread)) + return 0; + + if (! thread->m_lock.is_populated()) + return 1; + + THD *unsafe_thd= thread->m_thd; + if (unsafe_thd == NULL) + return 1; + + Find_thd_user_var finder(unsafe_thd); + THD *safe_thd= NULL;//Global_THD_manager::get_instance()->find_thd(&finder); + if (safe_thd == NULL) + return 1; + + m_THD_cache.materialize(thread, safe_thd); + mysql_mutex_unlock(&safe_thd->LOCK_thd_data); + return 0; +} + +void table_uvar_by_thread +::make_row(PFS_thread *thread, const User_variable *uvar) +{ + pfs_optimistic_state 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; + + /* uvar is materialized, pointing to it directly. */ + m_row.m_variable_name= & uvar->m_name; + m_row.m_variable_value= & uvar->m_value; + + if (! thread->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; +} + +int table_uvar_by_thread +::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; + + DBUG_ASSERT(m_row.m_variable_name != NULL); + DBUG_ASSERT(m_row.m_variable_value != NULL); + + 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: /* VARIABLE_NAME */ + set_field_varchar_utf8(f, + m_row.m_variable_name->m_str, + m_row.m_variable_name->m_length); + break; + case 2: /* VARIABLE_VALUE */ + if (m_row.m_variable_value->get_value_length() > 0) + { + set_field_blob(f, + m_row.m_variable_value->get_value(), + m_row.m_variable_value->get_value_length()); + } + else + { + f->set_null(); + } + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_uvar_by_thread.h b/storage/perfschema/table_uvar_by_thread.h new file mode 100644 index 00000000000..8d7beace481 --- /dev/null +++ b/storage/perfschema/table_uvar_by_thread.h @@ -0,0 +1,193 @@ +/* Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_UVAR_BY_THREAD_H +#define TABLE_UVAR_BY_THREAD_H + +/** + @file storage/perfschema/table_uvar_by_thread.h + Table USER_VARIABLES_BY_THREAD (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 + @{ +*/ + +struct User_variable +{ +public: + User_variable() + {} + + User_variable(const User_variable& uv) + : m_name(uv.m_name), m_value(uv.m_value) + {} + + ~User_variable() + {} + + PFS_variable_name_row m_name; + PFS_user_variable_value_row m_value; +}; + +class User_variables +{ + typedef Dynamic_array<User_variable> User_variable_array; + +public: + User_variables() + : m_pfs(NULL), m_thread_internal_id(0), m_array(PSI_INSTRUMENT_MEM) + { + } + + void reset() + { + m_pfs= NULL; + m_thread_internal_id= 0; + m_array.clear(); + } + + void materialize(PFS_thread *pfs, THD *thd); + + bool is_materialized(PFS_thread *pfs) + { + DBUG_ASSERT(pfs != NULL); + if (m_pfs != pfs) + return false; + if (m_thread_internal_id != pfs->m_thread_internal_id) + return false; + return true; + } + + const User_variable *get(uint index) const + { + if (index >= m_array.elements()) + return NULL; + + const User_variable *p= & m_array.at(index); + return p; + } + +private: + PFS_thread *m_pfs; + ulonglong m_thread_internal_id; + User_variable_array m_array; +}; + +/** + A row of table + PERFORMANCE_SCHEMA.USER_VARIABLES_BY_THREAD. +*/ +struct row_uvar_by_thread +{ + /** Column THREAD_ID. */ + ulonglong m_thread_internal_id; + /** Column VARIABLE_NAME. */ + const PFS_variable_name_row *m_variable_name; + /** Column VARIABLE_VALUE. */ + const PFS_user_variable_value_row *m_variable_value; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.USER_VARIABLES_BY_THREAD. + Index 1 on thread (0 based) + Index 2 on user variable (0 based) +*/ +struct pos_uvar_by_thread +: public PFS_double_index +{ + pos_uvar_by_thread() + : 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; + } +}; + +/** Table PERFORMANCE_SCHEMA.USER_VARIABLES_BY_THREAD. */ +class table_uvar_by_thread : public PFS_engine_table +{ + typedef pos_uvar_by_thread pos_t; + +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + 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); + + table_uvar_by_thread(); + +public: + ~table_uvar_by_thread() + { m_THD_cache.reset(); } + +protected: + int materialize(PFS_thread *thread); + void make_row(PFS_thread *thread, const User_variable *uvar); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current THD user variables. */ + User_variables m_THD_cache; + /** Current row. */ + row_uvar_by_thread m_row; + /** True is the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/table_variables_by_thread.cc b/storage/perfschema/table_variables_by_thread.cc new file mode 100644 index 00000000000..0e1c1021635 --- /dev/null +++ b/storage/perfschema/table_variables_by_thread.cc @@ -0,0 +1,229 @@ +/* Copyright (c) 2015, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +/** + @file storage/perfschema/table_variables_by_thread.cc + Table VARIABLES_BY_THREAD (implementation). +*/ + +#include "my_global.h" +#include "table_variables_by_thread.h" +#include "my_thread.h" +#include "pfs_instr_class.h" +#include "pfs_column_types.h" +#include "pfs_column_values.h" +#include "pfs_global.h" + +THR_LOCK table_variables_by_thread::m_table_lock; + +PFS_engine_table_share +table_variables_by_thread::m_share= +{ + { C_STRING_WITH_LEN("variables_by_thread") }, + &pfs_readonly_acl, + table_variables_by_thread::create, + NULL, /* write_row */ + NULL, /* delete_all_rows */ + table_variables_by_thread::get_row_count, + sizeof(pos_t), + &m_table_lock, + { C_STRING_WITH_LEN("CREATE TABLE user_variables_by_thread(" + "THREAD_ID BIGINT unsigned not null," + "VARIABLE_NAME VARCHAR(64) not null," + "VARIABLE_VALUE LONGBLOB)") }, + true /* perpetual */ +}; + +PFS_engine_table* +table_variables_by_thread::create(void) +{ + return new table_variables_by_thread(); +} + +ha_rows table_variables_by_thread::get_row_count(void) +{ + mysql_mutex_lock(&LOCK_plugin_delete); + mysql_rwlock_rdlock(&LOCK_system_variables_hash); + ulong system_var_count= get_system_variable_hash_records(); + mysql_rwlock_unlock(&LOCK_system_variables_hash); + mysql_mutex_unlock(&LOCK_plugin_delete); + return (global_thread_container.get_row_count() * system_var_count); +} + +table_variables_by_thread::table_variables_by_thread() + : PFS_engine_table(&m_share, &m_pos), + m_sysvar_cache(true), m_row_exists(false), m_pos(), m_next_pos(), m_context(NULL) +{} + +void table_variables_by_thread::reset_position(void) +{ + m_pos.reset(); + m_next_pos.reset(); +} + +int table_variables_by_thread::rnd_init(bool scan) +{ + /* + Build array of SHOW_VARs from system variable hash prior to materializing + threads in rnd_next() or rnd_pos(). + */ + m_sysvar_cache.initialize_session(); + + /* Record the version of the system variable hash. */ + ulonglong hash_version= m_sysvar_cache.get_sysvar_hash_version(); + + /* + The table context holds the current version of the system variable hash and + a record of which threads were materialized. + If scan == true, then allocate a new context from mem_root and store in TLS. + If scan == false, then restore from TLS. + */ + m_context= (table_variables_by_thread_context *)current_thd->alloc(sizeof(table_variables_by_thread_context)); + new(m_context) table_variables_by_thread_context(hash_version, !scan); + return 0; +} + +int table_variables_by_thread::rnd_next(void) +{ + /* If system variable hash changes, exit with warning. */ // TODO: Issue warning + if (!m_context->versions_match()) + return HA_ERR_END_OF_FILE; + + bool has_more_thread= true; + + for (m_pos.set_at(&m_next_pos); + has_more_thread; + m_pos.next_thread()) + { + PFS_thread *pfs_thread= global_thread_container.get(m_pos.m_index_1, &has_more_thread); + + /* Materialize all variables for the current thread. Assign a dedicated mem_root. */ + if (m_sysvar_cache.materialize_session(pfs_thread, true) == 0) + { + /* Mark this thread as materialized. */ + m_context->set_item(m_pos.m_index_1); + + const System_variable *system_var= m_sysvar_cache.get(m_pos.m_index_2); + if (system_var != NULL) + { + make_row(pfs_thread, system_var); + m_next_pos.set_after(&m_pos); + return 0; + } + } + } + return HA_ERR_END_OF_FILE; +} + +int +table_variables_by_thread::rnd_pos(const void *pos) +{ + /* If system variable hash changes, do nothing. */ + if (!m_context->versions_match()) + return HA_ERR_RECORD_DELETED; + + set_position(pos); + DBUG_ASSERT(m_pos.m_index_1 < global_thread_container.get_row_count()); + + PFS_thread *pfs_thread= global_thread_container.get(m_pos.m_index_1); + /* + Only materialize threads that were previously materialized by rnd_next(). + If a thread cannot be rematerialized, then do nothing. + Only materialize the requested system variable to avoid repeated + materialization of each thread, such as with ORDER BY variable_name. + */ + if (m_context->is_item_set(m_pos.m_index_1) && + /* Materialize only the requested variable. */ + m_sysvar_cache.materialize_session(pfs_thread, m_pos.m_index_2) == 0) + { + /* Get the first (and only) element from the cache. */ + const System_variable *system_var= m_sysvar_cache.get(); + if (system_var != NULL) + { + make_row(pfs_thread, system_var); + m_next_pos.set_after(&m_pos); + return 0; + } + } + return HA_ERR_RECORD_DELETED; +} + +void table_variables_by_thread +::make_row(PFS_thread *thread, const System_variable *system_var) +{ + pfs_optimistic_state lock; + m_row_exists= false; + if (system_var->is_null() || system_var->is_ignored()) + 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_variable_name.make_row(system_var->m_name, system_var->m_name_length); + m_row.m_variable_value.make_row(system_var); + + if (!thread->m_lock.end_optimistic_lock(&lock)) + return; + + m_row_exists= true; +} + +int table_variables_by_thread +::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: /* VARIABLE_NAME */ + set_field_varchar_utf8(f, m_row.m_variable_name.m_str, m_row.m_variable_name.m_length); + break; + case 2: /* VARIABLE_VALUE */ + m_row.m_variable_value.set_field(f); + break; + default: + DBUG_ASSERT(false); + } + } + } + + return 0; +} + diff --git a/storage/perfschema/table_variables_by_thread.h b/storage/perfschema/table_variables_by_thread.h new file mode 100644 index 00000000000..d628707f9b4 --- /dev/null +++ b/storage/perfschema/table_variables_by_thread.h @@ -0,0 +1,151 @@ +/* Copyright (c) 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TABLE_VARIABLES_BY_THREAD_H +#define TABLE_VARIABLES_BY_THREAD_H + +/** + @file storage/perfschema/table_variables_by_thread.h + Table VARIABLES_BY_THREAD (declarations). +*/ + +#include "pfs_column_types.h" +#include "pfs_engine_table.h" +#include "pfs_instr_class.h" +#include "pfs_instr.h" +#include "table_helper.h" +#include "pfs_variable.h" +#include "pfs_buffer_container.h" + +/** + @addtogroup Performance_schema_tables + @{ +*/ + +/** + A row of table + PERFORMANCE_SCHEMA.VARIABLES_BY_THREAD. +*/ +struct row_variables_by_thread +{ + /** Column THREAD_ID. */ + ulonglong m_thread_internal_id; + /** Column VARIABLE_NAME. */ + PFS_variable_name_row m_variable_name; + /** Column VARIABLE_VALUE. */ + PFS_variable_value_row m_variable_value; +}; + +/** + Position of a cursor on + PERFORMANCE_SCHEMA.VARIABLES_BY_THREAD. + Index 1 on thread (0 based) + Index 2 on system variable (0 based) +*/ +struct pos_variables_by_thread +: public PFS_double_index +{ + pos_variables_by_thread() + : PFS_double_index(0, 0) + {} + + inline void reset(void) + { + m_index_1= 0; + m_index_2= 0; + } + + inline bool has_more_thread(void) + { return (m_index_1 < global_thread_container.get_row_count()); } + + inline void next_thread(void) + { + m_index_1++; + m_index_2= 0; + } +}; + +/** + Store and retrieve table state information during queries that reinstantiate + the table object. +*/ +class table_variables_by_thread_context : public PFS_table_context +{ +public: + table_variables_by_thread_context(ulonglong hash_version, bool restore) : + PFS_table_context(hash_version, global_thread_container.get_row_count(), restore, THR_PFS_VBT) { } +}; + +/** Table PERFORMANCE_SCHEMA.VARIABLES_BY_THREAD. */ +class table_variables_by_thread : public PFS_engine_table +{ + typedef pos_variables_by_thread pos_t; + +public: + /** Table share */ + static PFS_engine_table_share m_share; + static PFS_engine_table* create(); + static ha_rows get_row_count(); + + 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_variables_by_thread(); + +public: + ~table_variables_by_thread() + {} + +protected: + int materialize(PFS_thread *thread); + void make_row(PFS_thread *thread, const System_variable *system_var); + +private: + /** Table share lock. */ + static THR_LOCK m_table_lock; + /** Fields definition. */ + static TABLE_FIELD_DEF m_field_def; + + /** Current THD variables. */ + PFS_system_variable_cache m_sysvar_cache; + /** Current row. */ + row_variables_by_thread m_row; + /** True if the current row exists. */ + bool m_row_exists; + /** Current position. */ + pos_t m_pos; + /** Next position. */ + pos_t m_next_pos; + + /** Table context with system variable hash version and map of materialized threads. */ + table_variables_by_thread_context *m_context; +}; + +/** @} */ +#endif diff --git a/storage/perfschema/unittest/CMakeLists.txt b/storage/perfschema/unittest/CMakeLists.txt index 7b8c906a4e6..1bba2673a1a 100644 --- a/storage/perfschema/unittest/CMakeLists.txt +++ b/storage/perfschema/unittest/CMakeLists.txt @@ -35,5 +35,6 @@ 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 + pfs_account-oom pfs_host-oom pfs_timer pfs_user-oom pfs_noop pfs + pfs_misc EXT "cc" LINK_LIBRARIES perfschema mysys pfs_server_stubs) diff --git a/storage/perfschema/unittest/pfs-t.cc b/storage/perfschema/unittest/pfs-t.cc index f5f38367691..43d9d8d233d 100644 --- a/storage/perfschema/unittest/pfs-t.cc +++ b/storage/perfschema/unittest/pfs-t.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2018, 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, version 2.0, @@ -21,11 +21,12 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include <my_global.h> -#include <my_pthread.h> +#include <my_thread.h> #include <pfs_server.h> #include <pfs_instr_class.h> #include <pfs_instr.h> #include <pfs_global.h> +#include <pfs_buffer_container.h> #include <tap.h> #include <string.h> @@ -33,6 +34,7 @@ #include "stub_print_error.h" #include "stub_pfs_defaults.h" +#include "stub_global_status_var.h" void unload_performance_schema(); @@ -48,30 +50,30 @@ void setup_thread(PSI_thread *t, bool enabled) PFS_file* lookup_file_by_name(const char* name) { - uint i; PFS_file *pfs; size_t len= strlen(name); size_t dirlen; const char *filename; - size_t filename_length;; + size_t filename_length; - for (i= 0; i < file_max; i++) + PFS_file_iterator it= global_file_container.iterate(); + pfs= it.scan_next(); + + while (pfs != NULL) { - pfs= & file_array[i]; - if (pfs->m_lock.is_populated()) - { - /* - When a file "foo" is instrumented, the name is normalized - to "/path/to/current/directory/foo", so we remove the - directory name here to find it back. - */ - dirlen= dirname_length(pfs->m_filename); - filename= pfs->m_filename + dirlen; - filename_length= pfs->m_filename_length - dirlen; - if ((len == filename_length) && - (strncmp(name, filename, filename_length) == 0)) - return pfs; - } + /* + When a file "foo" is instrumented, the name is normalized + to "/path/to/current/directory/foo", so we remove the + directory name here to find it back. + */ + dirlen= dirname_length(pfs->m_filename); + filename= pfs->m_filename + dirlen; + filename_length= pfs->m_filename_length - dirlen; + if ((len == filename_length) && + (strncmp(name, filename, filename_length) == 0)) + return pfs; + + pfs= it.scan_next(); } return NULL; @@ -118,10 +120,24 @@ void test_bootstrap() param.m_statement_class_sizing= 0; param.m_events_statements_history_sizing= 0; param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; param.m_digest_sizing= 0; param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 0; + param.m_metadata_lock_sizing= 0; param.m_max_digest_length= 0; + param.m_max_sql_text_length= 0; + + param.m_hints.m_table_definition_cache = 100; + param.m_hints.m_table_open_cache = 100; + param.m_hints.m_max_connections = 100; + param.m_hints.m_open_files_limit = 100; + param.m_hints.m_max_prepared_stmt_count= 100; + pre_initialize_performance_schema(); boot= initialize_performance_schema(& param); ok(boot != NULL, "boot"); ok(boot->get_interface != NULL, "boot->get_interface"); @@ -143,7 +159,7 @@ void test_bootstrap() */ PSI * load_perfschema() { - void *psi; + PSI *psi; PSI_bootstrap *boot; PFS_global_param param; @@ -177,13 +193,27 @@ PSI * load_perfschema() param.m_statement_class_sizing= 0; param.m_events_statements_history_sizing= 0; param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; param.m_digest_sizing= 0; param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_statement_stack_sizing= 10; + param.m_memory_class_sizing= 10; + param.m_metadata_lock_sizing= 10; param.m_max_digest_length= 0; + param.m_max_sql_text_length= 1000; + + param.m_hints.m_table_definition_cache = 100; + param.m_hints.m_table_open_cache = 100; + param.m_hints.m_max_connections = 100; + param.m_hints.m_open_files_limit = 100; + param.m_hints.m_max_prepared_stmt_count= 100; + pre_initialize_performance_schema(); /* test_bootstrap() covered this, assuming it just works */ boot= initialize_performance_schema(& param); - psi= boot->get_interface(PSI_VERSION_1); + psi= (PSI *)boot->get_interface(PSI_VERSION_1); /* Reset every consumer to a known state */ flag_global_instrumentation= true; @@ -335,6 +365,20 @@ void test_bad_registration() ok(dummy_rwlock_key == 0, "zero key"); dummy_rwlock_key= 9999; + PSI_rwlock_info bad_rwlock_2_sx[]= + { + { & dummy_rwlock_key, + /* 109 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "123456789", + PSI_RWLOCK_FLAG_SX} + }; + + psi->register_rwlock("Y", bad_rwlock_2_sx, 1); + ok(dummy_rwlock_key == 0, "zero key SX"); + + dummy_rwlock_key= 9999; PSI_rwlock_info bad_rwlock_3[]= { { & dummy_rwlock_key, @@ -351,6 +395,23 @@ void test_bad_registration() psi->register_rwlock("X", bad_rwlock_3, 1); ok(dummy_rwlock_key == 2, "assigned key"); + dummy_rwlock_key= 9999; + PSI_rwlock_info bad_rwlock_3_sx[]= + { + { & dummy_rwlock_key, + /* 108 chars name */ + "12345678901234567890123456789012345678901234567890" + "12345678901234567890123456789012345678901234567890" + "12345678", + PSI_RWLOCK_FLAG_SX} + }; + + psi->register_rwlock("YY", bad_rwlock_3_sx, 1); + ok(dummy_rwlock_key == 0, "zero key SX"); + + psi->register_rwlock("Y", bad_rwlock_3_sx, 1); + ok(dummy_rwlock_key == 3, "assigned key SX"); + /* Test that length('wait/synch/cond/' (16) + category + '/' (1)) < 32 --> category can be up to 14 chars for a cond. @@ -698,23 +759,27 @@ void test_init_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 */ + /* + Pretend thread T-1 is running, and disabled, with thread_instrumentation. + Disabled instruments are still created so they can be enabled later. + */ + /* ------------------------------------------------------------------------ */ psi->set_thread(thread_1); setup_thread(thread_1, false); - /* disabled M-A + disabled T-1: no instrumentation */ + /* disabled M-A + disabled T-1: instrumentation */ mutex_class_A->m_enabled= false; mutex_A1= psi->init_mutex(mutex_key_A, NULL); - ok(mutex_A1 == NULL, "mutex_A1 not instrumented"); + ok(mutex_A1 != NULL, "mutex_A1 disabled, instrumented"); /* enabled M-A + disabled T-1: instrumentation (for later) */ mutex_class_A->m_enabled= true; mutex_A1= psi->init_mutex(mutex_key_A, NULL); - ok(mutex_A1 != NULL, "mutex_A1 instrumented"); + ok(mutex_A1 != NULL, "mutex_A1 enabled, instrumented"); /* broken key + disabled T-1: no instrumentation */ @@ -728,13 +793,13 @@ void test_init_disabled() rwlock_class_A->m_enabled= false; rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); - ok(rwlock_A1 == NULL, "rwlock_A1 not instrumented"); + ok(rwlock_A1 != NULL, "rwlock_A1 disabled, instrumented"); /* enabled RW-A + disabled T-1: instrumentation (for later) */ rwlock_class_A->m_enabled= true; rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); - ok(rwlock_A1 != NULL, "rwlock_A1 instrumented"); + ok(rwlock_A1 != NULL, "rwlock_A1 enabled, instrumented"); /* broken key + disabled T-1: no instrumentation */ @@ -748,13 +813,13 @@ void test_init_disabled() cond_class_A->m_enabled= false; cond_A1= psi->init_cond(cond_key_A, NULL); - ok(cond_A1 == NULL, "cond_A1 not instrumented"); + ok(cond_A1 != NULL, "cond_A1 disabled, instrumented"); /* enabled C-A + disabled T-1: instrumentation (for later) */ cond_class_A->m_enabled= true; cond_A1= psi->init_cond(cond_key_A, NULL); - ok(cond_A1 != NULL, "cond_A1 instrumented"); + ok(cond_A1 != NULL, "cond_A1 enabled, instrumented"); /* broken key + disabled T-1: no instrumentation */ @@ -783,22 +848,22 @@ void test_init_disabled() 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_A1 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, "file_A1 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"); + ok(socket_A1 != NULL, "socket_A1 disabled, 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"); + ok(socket_A1 != NULL, "socket_A1 enabled, instrumented"); /* broken key + disabled T-1: no instrumentation */ @@ -807,7 +872,7 @@ void test_init_disabled() 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 */ /* ----------------------------- */ @@ -817,85 +882,85 @@ 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 disabled, instrumented"); /* enabled M-A + enabled T-1: instrumentation */ mutex_class_A->m_enabled= true; mutex_A1= psi->init_mutex(mutex_key_A, NULL); - ok(mutex_A1 != NULL, "instrumented"); + ok(mutex_A1 != NULL, "mutex_A1 enabled, instrumented"); psi->destroy_mutex(mutex_A1); /* broken key + enabled T-1: no instrumentation */ mutex_class_A->m_enabled= true; mutex_A1= psi->init_mutex(0, NULL); - ok(mutex_A1 == NULL, "not instrumented"); + ok(mutex_A1 == NULL, "mutex_A1 not instrumented"); mutex_A1= psi->init_mutex(99, NULL); - ok(mutex_A1 == NULL, "not instrumented"); + ok(mutex_A1 == NULL, "mutex_A1 not instrumented"); /* disabled RW-A + enabled T-1: no instrumentation */ rwlock_class_A->m_enabled= false; rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); - ok(rwlock_A1 == NULL, "not instrumented"); + ok(rwlock_A1 != NULL, "rwlock_A1 disabled, instrumented"); /* enabled RW-A + enabled T-1: instrumentation */ rwlock_class_A->m_enabled= true; rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); - ok(rwlock_A1 != NULL, "instrumented"); + ok(rwlock_A1 != NULL, "rwlock_A1 enabled, instrumented"); psi->destroy_rwlock(rwlock_A1); /* broken key + enabled T-1: no instrumentation */ rwlock_class_A->m_enabled= true; rwlock_A1= psi->init_rwlock(0, NULL); - ok(rwlock_A1 == NULL, "not instrumented"); + ok(rwlock_A1 == NULL, "rwlock_A1 not instrumented"); rwlock_A1= psi->init_rwlock(99, NULL); - ok(rwlock_A1 == NULL, "not instrumented"); + ok(rwlock_A1 == NULL, "rwlock_A1 not instrumented"); /* disabled C-A + enabled T-1: no instrumentation */ cond_class_A->m_enabled= false; cond_A1= psi->init_cond(cond_key_A, NULL); - ok(cond_A1 == NULL, "not instrumented"); + ok(cond_A1 != NULL, "cond_A1 disabled, instrumented"); /* enabled C-A + enabled T-1: instrumentation */ cond_class_A->m_enabled= true; cond_A1= psi->init_cond(cond_key_A, NULL); - ok(cond_A1 != NULL, "instrumented"); + ok(cond_A1 != NULL, "cond_A1 enabled, instrumented"); psi->destroy_cond(cond_A1); /* broken key + enabled T-1: no instrumentation */ cond_class_A->m_enabled= true; cond_A1= psi->init_cond(0, NULL); - ok(cond_A1 == NULL, "not instrumented"); + ok(cond_A1 == NULL, "cond_A1 not instrumented"); cond_A1= psi->init_cond(99, NULL); - ok(cond_A1 == NULL, "not instrumented"); + ok(cond_A1 == NULL, "cond_A1 not instrumented"); /* disabled F-A + enabled T-1: no instrumentation */ file_class_A->m_enabled= false; psi->create_file(file_key_A, "foo", (File) 12); file_A1= lookup_file_by_name("foo"); - ok(file_A1 == NULL, "not instrumented"); + ok(file_A1 == NULL, "file_A1 not instrumented"); /* enabled F-A + open failed + enabled T-1: no instrumentation */ file_class_A->m_enabled= true; psi->create_file(file_key_A, "foo", (File) -1); file_A1= lookup_file_by_name("foo"); - ok(file_A1 == NULL, "not instrumented"); + ok(file_A1 == NULL, "file_A1 not instrumented"); /* enabled F-A + out-of-descriptors + enabled T-1: no instrumentation */ file_class_A->m_enabled= true; psi->create_file(file_key_A, "foo", (File) 65000); file_A1= lookup_file_by_name("foo"); - ok(file_A1 == NULL, "not instrumented"); + ok(file_A1 == NULL, "file_A1 not instrumented"); ok(file_handle_lost == 1, "lost a file handle"); file_handle_lost= 0; @@ -920,22 +985,22 @@ void test_init_disabled() /* disabled S-A + enabled T-1: no instrumentation */ socket_class_A->m_enabled= false; - ok(socket_A1 == NULL, "not instrumented"); + ok(socket_A1 == NULL, "socket_A1 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"); + ok(socket_A1 != NULL, "socket_A1 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"); + ok(socket_A1 == NULL, "socket_A1 not instrumented"); socket_A1= psi->init_socket(99, NULL, NULL, 0); - ok(socket_A1 == NULL, "not instrumented"); + ok(socket_A1 == NULL, "socket_A1 not instrumented"); /* Pretend the running thread is not instrumented */ /* ---------------------------------------------- */ @@ -946,13 +1011,13 @@ void test_init_disabled() mutex_class_A->m_enabled= false; mutex_A1= psi->init_mutex(mutex_key_A, NULL); - ok(mutex_A1 == NULL, "mutex_A1 not instrumented"); + ok(mutex_A1 != NULL, "mutex_A1 disabled, instrumented"); /* enabled M-A + unknown thread: instrumentation (for later) */ mutex_class_A->m_enabled= true; mutex_A1= psi->init_mutex(mutex_key_A, NULL); - ok(mutex_A1 != NULL, "mutex_A1 instrumented"); + ok(mutex_A1 != NULL, "mutex_A1 enabled, instrumented"); /* broken key + unknown thread: no instrumentation */ @@ -966,13 +1031,13 @@ void test_init_disabled() rwlock_class_A->m_enabled= false; rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); - ok(rwlock_A1 == NULL, "rwlock_A1 not instrumented"); + ok(rwlock_A1 != NULL, "rwlock_A1 disabled, instrumented"); /* enabled RW-A + unknown thread: instrumentation (for later) */ rwlock_class_A->m_enabled= true; rwlock_A1= psi->init_rwlock(rwlock_key_A, NULL); - ok(rwlock_A1 != NULL, "rwlock_A1 instrumented"); + ok(rwlock_A1 != NULL, "rwlock_A1 enabled, instrumented"); /* broken key + unknown thread: no instrumentation */ @@ -986,13 +1051,13 @@ void test_init_disabled() cond_class_A->m_enabled= false; cond_A1= psi->init_cond(cond_key_A, NULL); - ok(cond_A1 == NULL, "cond_A1 not instrumented"); + ok(cond_A1 != NULL, "cond_A1 disabled, instrumented"); /* enabled C-A + unknown thread: instrumentation (for later) */ cond_class_A->m_enabled= true; cond_A1= psi->init_cond(cond_key_A, NULL); - ok(cond_A1 != NULL, "cond_A1 instrumented"); + ok(cond_A1 != NULL, "cond_A1 enabled, instrumented"); /* broken key + unknown thread: no instrumentation */ @@ -1007,14 +1072,14 @@ void test_init_disabled() file_class_A->m_enabled= false; psi->create_file(file_key_A, "foo", (File) 12); file_A1= lookup_file_by_name("foo"); - ok(file_A1 == NULL, "not instrumented"); + ok(file_A1 == NULL, "file_A1 not instrumented"); /* enabled F-A + unknown thread: no instrumentation */ file_class_A->m_enabled= true; psi->create_file(file_key_A, "foo", (File) 12); file_A1= lookup_file_by_name("foo"); - ok(file_A1 == NULL, "not instrumented"); + ok(file_A1 == NULL, "file_A1 not instrumented"); /* broken key + unknown thread: no instrumentation */ @@ -1030,13 +1095,13 @@ void test_init_disabled() 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"); + ok(socket_A1 != NULL, "socket_A1 disabled, 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"); + ok(socket_A1 != NULL, "socket_A1 enabled, instrumented"); /* broken key + unknown thread: no instrumentation */ @@ -1521,7 +1586,7 @@ void 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 */ + /* NOTE: Need to add 4 to each index: table io, table lock, idle, metadata lock */ /* Per mutex info waits should be at [0..9] */ param.m_mutex_class_sizing= 10; @@ -1546,9 +1611,16 @@ void test_event_name_index() param.m_statement_class_sizing= 0; param.m_events_statements_history_sizing= 0; param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; param.m_digest_sizing= 0; param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_statement_stack_sizing= 10; + param.m_memory_class_sizing= 12; + param.m_metadata_lock_sizing= 10; param.m_max_digest_length= 0; + param.m_max_sql_text_length= 1000; param.m_mutex_sizing= 0; param.m_rwlock_sizing= 0; @@ -1563,6 +1635,13 @@ void test_event_name_index() param.m_setup_actor_sizing= 0; param.m_setup_object_sizing= 0; + param.m_hints.m_table_definition_cache = 100; + param.m_hints.m_table_open_cache = 100; + param.m_hints.m_max_connections = 100; + param.m_hints.m_open_files_limit = 100; + param.m_hints.m_max_prepared_stmt_count= 100; + + pre_initialize_performance_schema(); boot= initialize_performance_schema(& param); ok(boot != NULL, "bootstrap"); psi= (PSI*) boot->get_interface(PSI_VERSION_1); @@ -1580,10 +1659,10 @@ void test_event_name_index() 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"); + ok(mutex_class->m_event_name_index == 4, "index 4"); 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"); + ok(mutex_class->m_event_name_index == 5, "index 5"); PFS_rwlock_class *rwlock_class; PSI_rwlock_key dummy_rwlock_key_1; @@ -1597,10 +1676,10 @@ void test_event_name_index() 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"); + ok(rwlock_class->m_event_name_index == 14, "index 14"); 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"); + ok(rwlock_class->m_event_name_index == 15, "index 15"); PFS_cond_class *cond_class; PSI_cond_key dummy_cond_key_1; @@ -1614,10 +1693,10 @@ void test_event_name_index() 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"); + ok(cond_class->m_event_name_index == 34, "index 34"); 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"); + ok(cond_class->m_event_name_index == 35, "index 35"); PFS_file_class *file_class; PSI_file_key dummy_file_key_1; @@ -1631,10 +1710,10 @@ void test_event_name_index() 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"); + ok(file_class->m_event_name_index == 74, "index 74"); 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"); + ok(file_class->m_event_name_index == 75, "index 75"); PFS_socket_class *socket_class; PSI_socket_key dummy_socket_key_1; @@ -1648,14 +1727,162 @@ void test_event_name_index() 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"); + ok(socket_class->m_event_name_index == 154, "index 154"); 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(socket_class->m_event_name_index == 155, "index 155"); 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 + ok(wait_class_max= 314, "314 event names"); // 4 global classes + + shutdown_performance_schema(); +} + +void test_memory_instruments() +{ + PSI *psi; + PSI_thread *owner; + + diag("test_memory_instruments"); + + psi= load_perfschema(); + + PSI_memory_key memory_key_A; + PSI_memory_info all_memory[]= + { + { & memory_key_A, "M-A", 0} + }; + + PSI_thread_key thread_key_1; + PSI_thread_info all_thread[]= + { + { & thread_key_1, "T-1", 0} + }; + + psi->register_memory("test", all_memory, 1); + psi->register_thread("test", all_thread, 1); + + PFS_memory_class *memory_class_A; + PSI_thread *thread_1; + PSI_memory_key key; + + /* Preparation */ + + thread_1= psi->new_thread(thread_key_1, NULL, 0); + ok(thread_1 != NULL, "T-1"); + psi->set_thread_id(thread_1, 1); + + memory_class_A= find_memory_class(memory_key_A); + ok(memory_class_A != NULL, "memory info A"); + + /* Pretend thread T-1 is running, and enabled */ + /* ------------------------------------------ */ + + psi->set_thread(thread_1); + setup_thread(thread_1, true); + + /* Enable all instruments */ + + memory_class_A->m_enabled= true; + + /* for coverage, need to print stats collected. */ + + key= psi->memory_alloc(memory_key_A, 100, & owner); + ok(key == memory_key_A, "alloc memory info A"); + key= psi->memory_realloc(memory_key_A, 100, 200, & owner); + ok(key == memory_key_A, "realloc memory info A"); + key= psi->memory_realloc(memory_key_A, 200, 300, & owner); + ok(key == memory_key_A, "realloc up memory info A"); + key= psi->memory_realloc(memory_key_A, 300, 50, & owner); + ok(key == memory_key_A, "realloc down memory info A"); + psi->memory_free(memory_key_A, 50, owner); + + /* Use global instrumentation only */ + /* ------------------------------- */ + + flag_thread_instrumentation= false; + + key= psi->memory_alloc(memory_key_A, 100, & owner); + ok(key == memory_key_A, "alloc memory info A"); + key= psi->memory_realloc(memory_key_A, 100, 200, & owner); + ok(key == memory_key_A, "realloc memory info A"); + key= psi->memory_realloc(memory_key_A, 200, 300, & owner); + ok(key == memory_key_A, "realloc up memory info A"); + key= psi->memory_realloc(memory_key_A, 300, 50, & owner); + ok(key == memory_key_A, "realloc down memory info A"); + psi->memory_free(memory_key_A, 50, owner); + + /* Garbage, for robustness */ + /* ----------------------- */ + + key= psi->memory_alloc(9999, 100, & owner); + ok(key == PSI_NOT_INSTRUMENTED, "alloc with unknown key"); + key= psi->memory_realloc(PSI_NOT_INSTRUMENTED, 100, 200, & owner); + ok(key == PSI_NOT_INSTRUMENTED, "realloc with unknown key"); + psi->memory_free(PSI_NOT_INSTRUMENTED, 200, owner); + + shutdown_performance_schema(); +} + +void test_leaks() +{ + PSI_bootstrap *boot; + PFS_global_param param; + + /* Allocate everything, to make sure cleanup does not forget anything. */ + + memset(& param, 0xFF, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 10; + param.m_rwlock_class_sizing= 10; + param.m_cond_class_sizing= 10; + param.m_thread_class_sizing= 10; + param.m_table_share_sizing= 10; + param.m_file_class_sizing= 10; + param.m_socket_class_sizing= 10; + param.m_mutex_sizing= 1000; + param.m_rwlock_sizing= 1000; + param.m_cond_sizing= 1000; + param.m_thread_sizing= 1000; + param.m_table_sizing= 1000; + param.m_file_sizing= 1000; + param.m_file_handle_sizing= 1000; + param.m_socket_sizing= 1000; + param.m_events_waits_history_sizing= 10; + param.m_events_waits_history_long_sizing= 1000; + param.m_setup_actor_sizing= 1000; + param.m_setup_object_sizing= 1000; + param.m_host_sizing= 1000; + param.m_user_sizing= 1000; + param.m_account_sizing= 1000; + param.m_stage_class_sizing= 10; + param.m_events_stages_history_sizing= 10; + param.m_events_stages_history_long_sizing= 1000; + param.m_statement_class_sizing= 10; + param.m_events_statements_history_sizing= 10; + param.m_events_statements_history_long_sizing= 1000; + param.m_session_connect_attrs_sizing= 1000; + param.m_memory_class_sizing= 10; + param.m_metadata_lock_sizing= 1000; + param.m_digest_sizing= 1000; + param.m_program_sizing= 1000; + param.m_statement_stack_sizing= 10; + param.m_max_digest_length= 1000; + param.m_max_sql_text_length= 1000; + + param.m_hints.m_table_definition_cache = 100; + param.m_hints.m_table_open_cache = 100; + param.m_hints.m_max_connections = 100; + param.m_hints.m_open_files_limit = 100; + param.m_hints.m_max_prepared_stmt_count= 100; + + pre_initialize_performance_schema(); + boot= initialize_performance_schema(& param); + ok(boot != NULL, "bootstrap"); + shutdown_performance_schema(); + + /* Leaks will be reported with valgrind */ } void do_all_tests() @@ -1668,11 +1895,13 @@ void do_all_tests() test_locker_disabled(); test_file_instrumentation_leak(); test_event_name_index(); + test_memory_instruments(); + test_leaks(); } int main(int argc, char **argv) { - plan(216); + plan(232); MY_INIT(argv[0]); do_all_tests(); my_end(0); diff --git a/storage/perfschema/unittest/pfs_account-oom-t.cc b/storage/perfschema/unittest/pfs_account-oom-t.cc index 1ca66445e0c..185b0a6594c 100644 --- a/storage/perfschema/unittest/pfs_account-oom-t.cc +++ b/storage/perfschema/unittest/pfs_account-oom-t.cc @@ -21,87 +21,142 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include <my_global.h> -#include <my_pthread.h> +#include <my_thread.h> #include <pfs_instr.h> #include <pfs_stat.h> #include <pfs_global.h> +#include <pfs_defaults.h> +#include <pfs_user.h> +#include <pfs_host.h> #include <pfs_account.h> +#include <pfs_buffer_container.h> #include <tap.h> #include "stub_pfs_global.h" +#include "stub_global_status_var.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 */ +PFS_thread pfs_thread; +void initialize_performance_schema_helper(PFS_global_param *param) +{ 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"); + param->m_enabled= true; + param->m_thread_class_sizing= 10; + param->m_thread_sizing= 1000; + param->m_account_sizing= 1000; + transaction_class_max= 0; + + pfs_thread.m_account_hash_pins= NULL; + + init_event_name_sizing(param); + init_sync_class(param->m_mutex_class_sizing, param->m_rwlock_class_sizing, param->m_cond_class_sizing); + init_thread_class(param->m_thread_class_sizing); + init_table_share(param->m_table_share_sizing); + init_table_share_lock_stat(param->m_table_lock_stat_sizing); + init_table_share_index_stat(param->m_index_stat_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_memory_class(param->m_memory_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_events_transactions_history_long(param->m_events_transactions_history_long_sizing); + init_file_hash(param); + init_table_share_hash(param); + init_setup_actor(param); + init_setup_actor_hash(param); + init_setup_object(param); + init_setup_object_hash(param); + init_host(param); + init_host_hash(param); + init_user(param); + init_user_hash(param); + init_account(param); + init_account_hash(param); + init_digest(param); + init_digest_hash(param); + init_program(param); + init_program_hash(param); + init_prepared_stmt(param); + pfs_initialized= true; +} + +void test_oom() +{ + PFS_global_param param; + PFS_account *pfs_account; + const char *username= "username"; + const char *hostname= "hostname"; - /* Tests */ + uint user_len= (uint)strlen(username); + uint host_len= (uint)strlen(hostname); + /* Account. */ + memset(¶m, 0, sizeof(param)); + initialize_performance_schema_helper(¶m); stub_alloc_fails_after_count= 1; - rc= init_account(& param); - ok(rc == 1, "oom (account)"); - cleanup_account(); - + pfs_account= find_or_create_account(&pfs_thread, username, user_len, hostname, host_len); + ok(pfs_account == NULL, "oom (account)"); + ok(global_account_container.m_lost == 1, "lost (account)"); + shutdown_performance_schema(); + + /* Account waits. */ + memset(¶m, 0, sizeof(param)); + param.m_mutex_class_sizing= 10; + initialize_performance_schema_helper(¶m); stub_alloc_fails_after_count= 2; - rc= init_account(& param); - ok(rc == 1, "oom (account waits)"); - cleanup_account(); + pfs_account= find_or_create_account(&pfs_thread, username, user_len, hostname, host_len); + ok(pfs_account == NULL, "oom (account waits)"); + ok(global_account_container.m_lost == 1, "lost (account waits)"); + shutdown_performance_schema(); - 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(); + /* Account stages. */ + memset(¶m, 0, sizeof(param)); + param.m_stage_class_sizing= 10; + initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + pfs_account= find_or_create_account(&pfs_thread, username, user_len, hostname, host_len); + ok(pfs_account == NULL, "oom (account stages)"); + ok(global_account_container.m_lost == 1, "lost (account stages)"); + shutdown_performance_schema(); + + /* Account statements. */ + memset(¶m, 0, sizeof(param)); + param.m_statement_class_sizing= 10; + initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + pfs_account= find_or_create_account(&pfs_thread, username, user_len, hostname, host_len); + ok(pfs_account == NULL, "oom (account statements)"); + ok(global_account_container.m_lost == 1, "lost (account statements)"); + shutdown_performance_schema(); + + /* Account transactions. */ + memset(¶m, 0, sizeof(param)); + initialize_performance_schema_helper(¶m); + transaction_class_max= 1; + stub_alloc_fails_after_count= 3; + pfs_account= find_or_create_account(&pfs_thread, username, user_len, hostname, host_len); + ok(pfs_account == NULL, "oom (account transactions)"); + ok(global_account_container.m_lost == 1, "lost (account transactions)"); + shutdown_performance_schema(); + + /* Account memory. */ + memset(¶m, 0, sizeof(param)); + param.m_memory_class_sizing= 10; + initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + pfs_account= find_or_create_account(&pfs_thread, username, user_len, hostname, host_len); + ok(pfs_account == NULL, "oom (account memory)"); + ok(global_account_container.m_lost == 1, "lost (account memory)"); + shutdown_performance_schema(); } void do_all_tests() @@ -111,10 +166,9 @@ void do_all_tests() int main(int, char **) { - plan(6); + plan(12); 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 index 06b0f8ad014..b57ead3ec26 100644 --- a/storage/perfschema/unittest/pfs_connect_attr-t.cc +++ b/storage/perfschema/unittest/pfs_connect_attr-t.cc @@ -21,7 +21,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include <my_global.h> -#include <my_pthread.h> +#include <my_thread.h> #include <pfs_server.h> #include <pfs_instr_class.h> #include <pfs_instr.h> @@ -258,7 +258,7 @@ void test_utf8_parser_bad_encoding() ptr= packet; *ptr++= strlen(attr); memcpy(ptr, attr, strlen(attr)); - ptr[0]= 0xFA; // invalid UTF-8 char + ptr[0]= (char)0xFA; // invalid UTF-8 char ptr+= strlen(attr); *ptr++= strlen(val); memcpy(ptr, val, strlen(val)); diff --git a/storage/perfschema/unittest/pfs_host-oom-t.cc b/storage/perfschema/unittest/pfs_host-oom-t.cc index 14af1af0352..e97a1170eb2 100644 --- a/storage/perfschema/unittest/pfs_host-oom-t.cc +++ b/storage/perfschema/unittest/pfs_host-oom-t.cc @@ -21,21 +21,26 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include <my_global.h> -#include <my_pthread.h> +#include <my_thread.h> #include <pfs_instr.h> #include <pfs_stat.h> #include <pfs_global.h> #include <pfs_host.h> +#include <pfs_buffer_container.h> #include <tap.h> #include "stub_pfs_global.h" +#include "stub_global_status_var.h" #include <string.h> /* memset */ +extern struct PSI_bootstrap PFS_bootstrap; + void test_oom() { - int rc; + PSI *psi; PFS_global_param param; + PSI_bootstrap *boot; memset(& param, 0xFF, sizeof(param)); param.m_enabled= true; @@ -45,6 +50,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; @@ -52,12 +58,13 @@ 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= 1000; param.m_user_sizing= 0; + param.m_host_sizing= 1000; param.m_account_sizing= 0; param.m_stage_class_sizing= 50; param.m_events_stages_history_sizing= 0; @@ -65,43 +72,64 @@ void test_oom() param.m_statement_class_sizing= 50; param.m_events_statements_history_sizing= 0; param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; + param.m_digest_sizing= 0; param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 10; + param.m_metadata_lock_sizing= 0; + param.m_max_digest_length= 0; + param.m_max_sql_text_length= 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"); + pre_initialize_performance_schema(); + boot= initialize_performance_schema(¶m); + psi= (PSI *)boot->get_interface(PSI_VERSION_1); + + PSI_thread_key thread_key_1; + PSI_thread_info all_thread[]= + { + {&thread_key_1, "T-1", 0} + }; + psi->register_thread("test", all_thread, 1); + + PSI_thread *thread_1= psi->new_thread(thread_key_1, NULL, 0); + psi->set_thread(thread_1); /* Tests */ - stub_alloc_fails_after_count= 1; - rc= init_host(& param); - ok(rc == 1, "oom (host)"); - cleanup_host(); + int first_fail= 1; + stub_alloc_fails_after_count= first_fail; + psi->set_thread_account("", 0, "host1", 5); + ok(global_host_container.m_lost == 1, "oom (host)"); + + stub_alloc_fails_after_count= first_fail + 1; + psi->set_thread_account("", 0, "host2", 5); + ok(global_host_container.m_lost == 2, "oom (host waits)"); + + stub_alloc_fails_after_count= first_fail + 2; + psi->set_thread_account("", 0, "host3", 5); + ok(global_host_container.m_lost == 3, "oom (host stages)"); - stub_alloc_fails_after_count= 2; - rc= init_host(& param); - ok(rc == 1, "oom (host waits)"); - cleanup_host(); + stub_alloc_fails_after_count= first_fail + 3; + psi->set_thread_account("", 0, "host4", 5); + ok(global_host_container.m_lost == 4, "oom (host statements)"); - stub_alloc_fails_after_count= 3; - rc= init_host(& param); - ok(rc == 1, "oom (host stages)"); - cleanup_host(); + stub_alloc_fails_after_count= first_fail + 4; + psi->set_thread_account("", 0, "host5", 5); + ok(global_host_container.m_lost == 5, "oom (host transactions)"); - stub_alloc_fails_after_count= 4; - rc= init_host(& param); - ok(rc == 1, "oom (host statements)"); - cleanup_host(); + stub_alloc_fails_after_count= first_fail + 5; + psi->set_thread_account("", 0, "host6", 5); + ok(global_host_container.m_lost == 6, "oom (host memory)"); - cleanup_statement_class(); - cleanup_stage_class(); + shutdown_performance_schema(); } void do_all_tests() diff --git a/storage/perfschema/unittest/pfs_instr-oom-t.cc b/storage/perfschema/unittest/pfs_instr-oom-t.cc index 231fd1e100b..9472d8aa001 100644 --- a/storage/perfschema/unittest/pfs_instr-oom-t.cc +++ b/storage/perfschema/unittest/pfs_instr-oom-t.cc @@ -18,46 +18,139 @@ 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 */ + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #include <my_global.h> -#include <my_pthread.h> +#include <my_thread.h> #include <pfs_instr.h> #include <pfs_stat.h> #include <pfs_global.h> +#include <pfs_user.h> +#include <pfs_host.h> +#include <pfs_account.h> #include <pfs_instr_class.h> +#include <pfs_buffer_container.h> #include <tap.h> #include "stub_pfs_global.h" +#include "stub_global_status_var.h" #include <string.h> /* memset */ +extern struct PSI_bootstrap PFS_bootstrap; + +PSI_thread_key thread_key_1; +PSI_thread_info all_thread[]= +{ + {&thread_key_1, "T-1", 0} +}; + +/** Simulate initialize_performance_schema(). */ + +PSI * initialize_performance_schema_helper(PFS_global_param *param) +{ + PSI *psi; + + stub_alloc_always_fails= false; + stub_alloc_fails_after_count= 1000; + + param->m_enabled= true; + param->m_thread_class_sizing= 10; + param->m_thread_sizing= 1000; + + pre_initialize_performance_schema(); + + init_event_name_sizing(param); + init_sync_class(param->m_mutex_class_sizing, param->m_rwlock_class_sizing, param->m_cond_class_sizing); + init_thread_class(param->m_thread_class_sizing); + init_table_share(param->m_table_share_sizing); + init_table_share_lock_stat(param->m_table_lock_stat_sizing); + init_table_share_index_stat(param->m_index_stat_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_memory_class(param->m_memory_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_events_transactions_history_long(param->m_events_transactions_history_long_sizing); + init_file_hash(param); + init_table_share_hash(param); + init_setup_actor(param); + init_setup_actor_hash(param); + init_setup_object(param); + init_setup_object_hash(param); + init_host(param); + init_host_hash(param); + init_user(param); + init_user_hash(param); + init_account(param); + init_account_hash(param); + init_digest(param); + init_digest_hash(param); + init_program(param); + init_program_hash(param); + init_prepared_stmt(param); + pfs_initialized= true; + + PSI_bootstrap *boot= &PFS_bootstrap; + psi= (PSI *)boot->get_interface(PSI_VERSION_1); + psi->register_thread("test", all_thread, 1); + return (psi); +} + void test_oom() { int rc; + PSI *psi; PFS_global_param param; - stub_alloc_always_fails= true; + stub_alloc_always_fails= false; + stub_alloc_fails_after_count= 1000; + + PFS_mutex_class dummy_mutex_class; + PFS_rwlock_class dummy_rwlock_class; + PFS_cond_class dummy_cond_class; + PFS_thread_class dummy_thread_class; + PFS_file_class dummy_file_class; + PFS_socket_class dummy_socket_class; + PFS_table_share dummy_table_share; + PFS_mutex *mutex_1; + PFS_mutex *mutex_2; + PFS_rwlock *rwlock_1; + PFS_rwlock *rwlock_2; + PFS_cond *cond_1; + PFS_cond *cond_2; + PFS_thread *thread_1; + PFS_thread *thread_2; + PFS_file *file_1; + PFS_file *file_2; + PFS_socket *socket_1; + PFS_socket *socket_2; + PFS_table *table_1; + PFS_table *table_2; memset(& param, 0xFF, sizeof(param)); param.m_enabled= true; - param.m_mutex_class_sizing= 10; - param.m_rwlock_class_sizing= 0; - param.m_cond_class_sizing= 0; - param.m_thread_class_sizing= 0; - param.m_table_share_sizing= 0; - param.m_file_class_sizing= 0; - param.m_socket_class_sizing= 0; - param.m_mutex_sizing= 1000; - param.m_rwlock_sizing= 0; - param.m_cond_sizing= 0; - param.m_thread_sizing= 0; - param.m_table_sizing= 0; - param.m_file_sizing= 0; - param.m_file_handle_sizing= 0; - param.m_socket_sizing= 0; - param.m_events_waits_history_sizing= 0; - param.m_events_waits_history_long_sizing= 0; + param.m_mutex_class_sizing= 1; + param.m_rwlock_class_sizing= 1; + param.m_cond_class_sizing= 1; + param.m_thread_class_sizing= 1; + param.m_table_share_sizing= 1; + param.m_file_class_sizing= 1; + param.m_socket_class_sizing= 1; + param.m_mutex_sizing= 1; + param.m_rwlock_sizing= 1; + param.m_cond_sizing= 1; + param.m_thread_sizing= 1; + param.m_table_sizing= 1; + param.m_file_sizing= 1; + 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; @@ -69,614 +162,285 @@ void test_oom() param.m_statement_class_sizing= 0; param.m_events_statements_history_sizing= 0; param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; + param.m_digest_sizing= 0; param.m_session_connect_attrs_sizing= 0; - - init_event_name_sizing(& param); - rc= init_instruments(& param); - ok(rc == 1, "oom (mutex)"); + param.m_program_sizing= 0; + param.m_prepared_stmt_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 1; + param.m_metadata_lock_sizing= 0; + param.m_max_digest_length= 0; + param.m_max_sql_text_length= 0; + + init_event_name_sizing(¶m); + rc= init_instruments(¶m); + ok(rc == 0, "instances init"); + + dummy_mutex_class.m_event_name_index= 0; + dummy_mutex_class.m_flags= 0; + dummy_mutex_class.m_enabled= true; + dummy_mutex_class.m_volatility= PSI_VOLATILITY_UNKNOWN; + dummy_rwlock_class.m_event_name_index= 1; + dummy_rwlock_class.m_flags= 0; + dummy_rwlock_class.m_enabled= true; + dummy_rwlock_class.m_volatility= PSI_VOLATILITY_UNKNOWN; + dummy_cond_class.m_event_name_index= 2; + dummy_cond_class.m_flags= 0; + dummy_cond_class.m_enabled= true; + dummy_cond_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_file_class.m_event_name_index= 3; + dummy_file_class.m_flags= 0; + dummy_file_class.m_enabled= true; + dummy_file_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_socket_class.m_event_name_index= 4; + dummy_socket_class.m_flags= 0; + dummy_socket_class.m_enabled= true; + dummy_socket_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_table_share.m_enabled= true; + dummy_table_share.m_timed= true; + + /* Create mutex. */ + stub_alloc_always_fails= false; + mutex_1= create_mutex(&dummy_mutex_class, NULL); + ok(mutex_1 != NULL, "create mutex"); + destroy_mutex(mutex_1); cleanup_instruments(); - param.m_enabled= true; - param.m_mutex_class_sizing= 0; - param.m_rwlock_class_sizing= 10; - param.m_cond_class_sizing= 0; - param.m_thread_class_sizing= 0; - param.m_table_share_sizing= 0; - param.m_file_class_sizing= 0; - param.m_socket_class_sizing= 0; - param.m_mutex_sizing= 0; - param.m_rwlock_sizing= 1000; - param.m_cond_sizing= 0; - param.m_thread_sizing= 0; - param.m_table_sizing= 0; - param.m_file_sizing= 0; - param.m_file_handle_sizing= 0; - param.m_socket_sizing= 0; - param.m_events_waits_history_sizing= 0; - param.m_events_waits_history_long_sizing= 0; - param.m_setup_actor_sizing= 0; - param.m_setup_object_sizing= 0; - param.m_host_sizing= 0; - param.m_user_sizing= 0; - param.m_account_sizing= 0; - param.m_stage_class_sizing= 0; - param.m_events_stages_history_sizing= 0; - param.m_events_stages_history_long_sizing= 0; - param.m_statement_class_sizing= 0; - param.m_events_statements_history_sizing= 0; - param.m_events_statements_history_long_sizing= 0; - param.m_session_connect_attrs_sizing= 0; - - init_event_name_sizing(& param); - rc= init_instruments(& param); - ok(rc == 1, "oom (rwlock)"); + stub_alloc_always_fails= true; + mutex_2= create_mutex(&dummy_mutex_class, NULL); + ok(mutex_2 == NULL, "oom (create mutex)"); + + /* Create rwlock. */ + stub_alloc_always_fails = false; + rc = init_instruments(¶m); + ok(rc == 0, "instances init"); + rwlock_1= create_rwlock(&dummy_rwlock_class, NULL); + ok(rwlock_1 != NULL, "create rwlock"); + destroy_rwlock(rwlock_1); cleanup_instruments(); - param.m_enabled= true; - param.m_mutex_class_sizing= 0; - param.m_rwlock_class_sizing= 0; - param.m_cond_class_sizing= 10; - param.m_thread_class_sizing= 0; - param.m_table_share_sizing= 0; - param.m_file_class_sizing= 0; - param.m_socket_class_sizing= 0; - param.m_mutex_sizing= 0; - param.m_rwlock_sizing= 0; - param.m_cond_sizing= 1000; - param.m_thread_sizing= 0; - param.m_table_sizing= 0; - param.m_file_sizing= 0; - param.m_file_handle_sizing= 0; - param.m_socket_sizing= 0; - param.m_events_waits_history_sizing= 0; - param.m_events_waits_history_long_sizing= 0; - param.m_setup_actor_sizing= 0; - param.m_setup_object_sizing= 0; - param.m_host_sizing= 0; - param.m_user_sizing= 0; - param.m_account_sizing= 0; - param.m_stage_class_sizing= 0; - param.m_events_stages_history_sizing= 0; - param.m_events_stages_history_long_sizing= 0; - param.m_statement_class_sizing= 0; - param.m_events_statements_history_sizing= 0; - param.m_events_statements_history_long_sizing= 0; - param.m_session_connect_attrs_sizing= 0; - - init_event_name_sizing(& param); - rc= init_instruments(& param); - ok(rc == 1, "oom (cond)"); + stub_alloc_always_fails= true; + rwlock_2= create_rwlock(&dummy_rwlock_class, NULL); + ok(rwlock_2 == NULL, "oom (create rwlock)"); + + /* Create cond. */ + stub_alloc_always_fails = false; + rc = init_instruments(¶m); + ok(rc == 0, "instances init"); + cond_1= create_cond(&dummy_cond_class, NULL); + ok(cond_1 != NULL, "create cond"); + destroy_cond(cond_1); cleanup_instruments(); - param.m_enabled= true; - param.m_mutex_class_sizing= 0; - param.m_rwlock_class_sizing= 0; - param.m_cond_class_sizing= 0; - param.m_thread_class_sizing= 0; - param.m_table_share_sizing= 0; - param.m_file_class_sizing= 10; - param.m_socket_class_sizing= 0; - param.m_mutex_sizing= 0; - param.m_rwlock_sizing= 0; - param.m_cond_sizing= 0; - param.m_thread_sizing= 0; - param.m_table_sizing= 0; - param.m_file_sizing= 1000; - param.m_file_handle_sizing= 1000; - param.m_socket_sizing= 0; - param.m_events_waits_history_sizing= 0; - param.m_events_waits_history_long_sizing= 0; - param.m_setup_actor_sizing= 0; - param.m_setup_object_sizing= 0; - param.m_host_sizing= 0; - param.m_user_sizing= 0; - param.m_account_sizing= 0; - param.m_stage_class_sizing= 0; - param.m_events_stages_history_sizing= 0; - param.m_events_stages_history_long_sizing= 0; - param.m_statement_class_sizing= 0; - param.m_events_statements_history_sizing= 0; - param.m_events_statements_history_long_sizing= 0; - param.m_session_connect_attrs_sizing= 0; + stub_alloc_always_fails= true; + cond_2= create_cond(&dummy_cond_class, NULL); + ok(cond_2 == NULL, "oom (create cond)"); - init_event_name_sizing(& param); - rc= init_instruments(& param); - ok(rc == 1, "oom (file)"); - cleanup_instruments(); + /* Create file. */ + PFS_thread fake_thread; + rc = init_instruments(¶m); + fake_thread.m_filename_hash_pins= NULL; + init_file_hash(¶m); - 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; + stub_alloc_always_fails = true; + file_2 = find_or_create_file(&fake_thread, &dummy_file_class, "dummy", 5, true); + ok(file_2 == NULL, "oom (create file)"); - init_event_name_sizing(& param); - rc= init_instruments(& param); - ok(rc == 1, "oom (file handle)"); + stub_alloc_always_fails= false; + file_1= find_or_create_file(&fake_thread, &dummy_file_class, "dummy", 5, true); + ok(file_1 != NULL, "create file"); + release_file(file_1); cleanup_instruments(); - param.m_enabled= true; - param.m_mutex_class_sizing= 0; - param.m_rwlock_class_sizing= 0; - param.m_cond_class_sizing= 0; - param.m_thread_class_sizing= 0; - param.m_table_share_sizing= 10; - param.m_file_class_sizing= 0; - param.m_socket_class_sizing= 0; - param.m_mutex_sizing= 0; - param.m_rwlock_sizing= 0; - param.m_cond_sizing= 0; - param.m_thread_sizing= 0; - param.m_table_sizing= 1000; - param.m_file_sizing= 0; - param.m_file_handle_sizing= 0; - param.m_socket_sizing= 0; - param.m_events_waits_history_sizing= 0; - param.m_events_waits_history_long_sizing= 0; - param.m_setup_actor_sizing= 0; - param.m_setup_object_sizing= 0; - param.m_host_sizing= 0; - param.m_user_sizing= 0; - param.m_account_sizing= 0; - param.m_stage_class_sizing= 0; - param.m_events_stages_history_sizing= 0; - param.m_events_stages_history_long_sizing= 0; - param.m_statement_class_sizing= 0; - param.m_events_statements_history_sizing= 0; - param.m_events_statements_history_long_sizing= 0; - param.m_session_connect_attrs_sizing= 0; - - init_event_name_sizing(& param); - rc= init_instruments(& param); - ok(rc == 1, "oom (table)"); + /* Create socket. */ + stub_alloc_always_fails = false; + rc = init_instruments(¶m); + ok(rc == 0, "instances init"); + socket_1= create_socket(&dummy_socket_class, NULL, NULL, 0); + ok(socket_1 != NULL, "create socket"); + destroy_socket(socket_1); cleanup_instruments(); - param.m_enabled= true; - param.m_mutex_class_sizing= 0; - param.m_rwlock_class_sizing= 0; - param.m_cond_class_sizing= 0; - param.m_thread_class_sizing= 10; - param.m_table_share_sizing= 0; - param.m_file_class_sizing= 0; - param.m_socket_class_sizing= 0; - param.m_mutex_sizing= 0; - param.m_rwlock_sizing= 0; - param.m_cond_sizing= 0; - param.m_thread_sizing= 1000; - param.m_table_sizing= 0; - param.m_file_sizing= 0; - param.m_file_handle_sizing= 0; - param.m_socket_sizing= 0; - param.m_events_waits_history_sizing= 0; - param.m_events_waits_history_long_sizing= 0; - param.m_setup_actor_sizing= 0; - param.m_setup_object_sizing= 0; - param.m_host_sizing= 0; - param.m_user_sizing= 0; - param.m_account_sizing= 0; - param.m_stage_class_sizing= 0; - param.m_events_stages_history_sizing= 0; - param.m_events_stages_history_long_sizing= 0; - param.m_statement_class_sizing= 0; - param.m_events_statements_history_sizing= 0; - param.m_events_statements_history_long_sizing= 0; - param.m_session_connect_attrs_sizing= 0; + stub_alloc_always_fails= true; + socket_2= create_socket(&dummy_socket_class, NULL, NULL, 0); + ok(socket_2 == NULL, "oom (create socket)"); - init_event_name_sizing(& param); - rc= init_instruments(& param); - ok(rc == 1, "oom (thread)"); + /* Create table. */ + stub_alloc_always_fails= false; + rc = init_instruments(¶m); + table_1= create_table(&dummy_table_share, &fake_thread, NULL); + ok(table_1 != NULL, "create table"); + destroy_table(table_1); cleanup_instruments(); + stub_alloc_always_fails= true; + table_2= create_table(&dummy_table_share, &fake_thread, NULL); + ok(table_2 == NULL, "oom (create table)"); + + /* Create thread. */ stub_alloc_always_fails= false; + rc = init_instruments(¶m); + thread_1= create_thread(&dummy_thread_class, NULL, 0); + ok(thread_1 != NULL, "create thread"); + destroy_thread(thread_1); + cleanup_instruments(); - param.m_enabled= true; - param.m_mutex_class_sizing= 0; - param.m_rwlock_class_sizing= 0; - param.m_cond_class_sizing= 0; - param.m_thread_class_sizing= 10; - param.m_table_share_sizing= 0; - param.m_file_class_sizing= 0; - param.m_socket_class_sizing= 0; - param.m_mutex_sizing= 0; - param.m_rwlock_sizing= 0; - param.m_cond_sizing= 0; - param.m_thread_sizing= 1000; - param.m_table_sizing= 0; - param.m_file_sizing= 0; - param.m_file_handle_sizing= 0; - param.m_socket_sizing= 0; - param.m_events_waits_history_sizing= 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_always_fails= true; + thread_2= create_thread(&dummy_thread_class, NULL, 0); + ok(thread_2 == NULL, "oom (create thread)"); - stub_alloc_fails_after_count= 2; - init_event_name_sizing(& param); - rc= init_instruments(& param); - ok(rc == 1, "oom (thread waits history sizing)"); - cleanup_instruments(); + PSI_thread *thread; - param.m_enabled= true; + /* Per thread wait. */ + memset(¶m, 0, sizeof(param)); param.m_mutex_class_sizing= 50; param.m_rwlock_class_sizing= 50; param.m_cond_class_sizing= 50; - param.m_thread_class_sizing= 10; - param.m_table_share_sizing= 0; param.m_file_class_sizing= 50; param.m_socket_class_sizing= 0; - param.m_mutex_sizing= 0; - param.m_rwlock_sizing= 0; - param.m_cond_sizing= 0; - param.m_thread_sizing= 1000; - param.m_table_sizing= 0; - param.m_file_sizing= 0; - param.m_file_handle_sizing= 0; - param.m_socket_sizing= 0; - param.m_events_waits_history_sizing= 0; - param.m_events_waits_history_long_sizing= 0; - param.m_setup_actor_sizing= 0; - param.m_setup_object_sizing= 0; - param.m_stage_class_sizing= 0; - param.m_events_stages_history_sizing= 0; - param.m_events_stages_history_long_sizing= 0; - param.m_statement_class_sizing= 0; - param.m_events_statements_history_sizing= 0; - param.m_events_statements_history_long_sizing= 0; - param.m_session_connect_attrs_sizing= 0; - + psi= initialize_performance_schema_helper(¶m); stub_alloc_fails_after_count= 2; - init_event_name_sizing(& param); - rc= init_instruments(& param); - ok(rc == 1, "oom (per thread wait)"); + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (per thread wait)"); cleanup_sync_class(); cleanup_thread_class(); cleanup_file_class(); cleanup_instruments(); + /* Thread waits history sizing. */ + memset(¶m, 0, sizeof(param)); param.m_enabled= true; - param.m_mutex_class_sizing= 0; - param.m_rwlock_class_sizing= 0; - param.m_cond_class_sizing= 0; - param.m_thread_class_sizing= 0; - param.m_table_share_sizing= 0; - param.m_file_class_sizing= 0; - param.m_socket_class_sizing= 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)"); + param.m_events_waits_history_sizing= 10; + psi= initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (thread waits history sizing)"); + cleanup_thread_class(); 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; + /* Per thread stages. */ + memset(¶m, 0, sizeof(param)); + param.m_stage_class_sizing= 50; + psi= initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (per thread stages)"); - stub_alloc_fails_after_count= 1; - init_event_name_sizing(& param); - rc= init_instruments(& param); - ok(rc == 1, "oom (per thread waits)"); + cleanup_stage_class(); + cleanup_thread_class(); cleanup_instruments(); + cleanup_stage_class(); - 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; + /* Thread stages history sizing. */ + memset(¶m, 0, sizeof(param)); 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; - + psi= initialize_performance_schema_helper(¶m); 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(); + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (thread stages history sizing)"); + cleanup_instruments(); + cleanup_thread_class(); - 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; + /* Per thread statements. */ + memset(¶m, 0, sizeof(param)); 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; + psi= initialize_performance_schema_helper(¶m); + init_statement_class(param.m_statement_class_sizing); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (per thread statements)"); - 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_statement_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; + /* Thread statements history sizing. */ + memset(¶m, 0, sizeof(param)); 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)"); - + psi= initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "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)"); + /* Per thread transactions. */ + memset(¶m, 0, sizeof(param)); + psi= initialize_performance_schema_helper(¶m); + transaction_class_max= 1; // set by register_global_classes(); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (per thread transactions)"); + transaction_class_max= 0; - 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)"); + /* Thread transactions history sizing. */ + memset(¶m, 0, sizeof(param)); + param.m_events_transactions_history_sizing= 10; + psi= initialize_performance_schema_helper(¶m); + stub_alloc_fails_after_count= 3; + thread= psi->new_thread(thread_key_1, NULL, 0); + ok(thread == NULL, "oom (thread transactions history sizing)"); - cleanup_sync_class(); + cleanup_thread_class(); cleanup_instruments(); + /* Global stages. */ + memset(¶m, 0, sizeof(param)); param.m_enabled= true; param.m_mutex_class_sizing= 10; - param.m_rwlock_class_sizing= 0; - param.m_cond_class_sizing= 0; - param.m_thread_class_sizing= 0; - param.m_table_share_sizing= 0; - param.m_file_class_sizing= 0; - param.m_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); + stub_alloc_fails_after_count= 2; + init_event_name_sizing(¶m); 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(); + /* Global statements. */ + memset(¶m, 0, sizeof(param)); param.m_enabled= true; param.m_mutex_class_sizing= 10; - param.m_rwlock_class_sizing= 0; - param.m_cond_class_sizing= 0; - param.m_thread_class_sizing= 0; - param.m_table_share_sizing= 0; - param.m_file_class_sizing= 0; - param.m_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); + stub_alloc_fails_after_count= 2; + init_event_name_sizing(¶m); rc= init_statement_class(param.m_statement_class_sizing); ok(rc == 0, "init statement class"); - rc= init_instruments(& param); + rc= init_instruments(¶m); ok(rc == 1, "oom (global statements)"); - cleanup_sync_class(); cleanup_statement_class(); cleanup_instruments(); + + /* Global memory. */ + memset(¶m, 0, sizeof(param)); + param.m_enabled= true; + param.m_mutex_class_sizing= 10; + param.m_memory_class_sizing= 20; + + stub_alloc_fails_after_count= 2; + init_event_name_sizing(¶m); + rc= init_memory_class(param.m_memory_class_sizing); + ok(rc == 0, "init memory class"); + rc= init_instruments(& param); + ok(rc == 1, "oom (global memory)"); + + cleanup_memory_class(); + cleanup_instruments(); } void do_all_tests() @@ -686,10 +450,10 @@ void do_all_tests() int main(int argc, char **argv) { - plan(20); + plan(32); MY_INIT(argv[0]); do_all_tests(); my_end(0); - return (exit_status()); + return exit_status(); } diff --git a/storage/perfschema/unittest/pfs_instr-t.cc b/storage/perfschema/unittest/pfs_instr-t.cc index c9f4bac1171..d4401ab7ea2 100644 --- a/storage/perfschema/unittest/pfs_instr-t.cc +++ b/storage/perfschema/unittest/pfs_instr-t.cc @@ -21,13 +21,16 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include <my_global.h> -#include <my_pthread.h> +#include <my_thread.h> #include <pfs_instr.h> #include <pfs_stat.h> #include <pfs_global.h> #include <pfs_instr_class.h> +#include <pfs_buffer_container.h> #include <tap.h> +#include "stub_global_status_var.h" + #include <memory.h> PFS_global_param param; @@ -66,9 +69,15 @@ void test_no_instruments() param.m_statement_class_sizing= 0; param.m_events_statements_history_sizing= 0; param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; param.m_digest_sizing= 0; param.m_session_connect_attrs_sizing= 0; - param.m_max_digest_length= 0; + param.m_program_sizing= 0; + param.m_prepared_stmt_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 0; + param.m_metadata_lock_sizing= 0; init_event_name_sizing(& param); rc= init_instruments(& param); @@ -95,6 +104,27 @@ void test_no_instances() PFS_socket *socket; PFS_table *table; + dummy_mutex_class.m_event_name_index = 0; + dummy_mutex_class.m_flags = 0; + dummy_mutex_class.m_enabled = true; + dummy_mutex_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_rwlock_class.m_event_name_index = 1; + dummy_rwlock_class.m_flags = 0; + dummy_rwlock_class.m_enabled = true; + dummy_rwlock_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_cond_class.m_event_name_index = 2; + dummy_cond_class.m_flags = 0; + dummy_cond_class.m_enabled = true; + dummy_cond_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_file_class.m_event_name_index = 3; + dummy_file_class.m_flags = 0; + dummy_file_class.m_enabled = true; + dummy_file_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + dummy_socket_class.m_event_name_index = 4; + dummy_socket_class.m_flags = 0; + dummy_socket_class.m_enabled = true; + dummy_socket_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + memset(& param, 0xFF, sizeof(param)); param.m_enabled= true; param.m_mutex_class_sizing= 1; @@ -125,9 +155,15 @@ void test_no_instances() param.m_statement_class_sizing= 0; param.m_events_statements_history_sizing= 0; param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; param.m_digest_sizing= 0; param.m_session_connect_attrs_sizing= 0; - param.m_max_digest_length= 0; + param.m_program_sizing= 0; + param.m_prepared_stmt_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 1; + param.m_metadata_lock_sizing= 0; init_event_name_sizing(& param); rc= init_instruments(& param); @@ -135,50 +171,50 @@ void test_no_instances() mutex= create_mutex(& dummy_mutex_class, NULL); ok(mutex == NULL, "no mutex"); - ok(mutex_lost == 1, "lost 1"); + ok(global_mutex_container.get_lost_counter() == 1, "lost 1"); mutex= create_mutex(& dummy_mutex_class, NULL); ok(mutex == NULL, "no mutex"); - ok(mutex_lost == 2, "lost 2"); + ok(global_mutex_container.get_lost_counter() == 2, "lost 2"); rwlock= create_rwlock(& dummy_rwlock_class, NULL); ok(rwlock == NULL, "no rwlock"); - ok(rwlock_lost == 1, "lost 1"); + ok(global_rwlock_container.m_lost == 1, "lost 1"); rwlock= create_rwlock(& dummy_rwlock_class, NULL); ok(rwlock == NULL, "no rwlock"); - ok(rwlock_lost == 2, "lost 2"); + ok(global_rwlock_container.m_lost == 2, "lost 2"); cond= create_cond(& dummy_cond_class, NULL); ok(cond == NULL, "no cond"); - ok(cond_lost == 1, "lost 1"); + ok(global_cond_container.m_lost == 1, "lost 1"); cond= create_cond(& dummy_cond_class, NULL); ok(cond == NULL, "no cond"); - ok(cond_lost == 2, "lost 2"); + ok(global_cond_container.m_lost == 2, "lost 2"); thread= create_thread(& dummy_thread_class, NULL, 0); ok(thread == NULL, "no thread"); - ok(thread_lost == 1, "lost 1"); + ok(global_thread_container.m_lost == 1, "lost 1"); thread= create_thread(& dummy_thread_class, NULL, 0); ok(thread == NULL, "no thread"); - ok(thread_lost == 2, "lost 2"); + ok(global_thread_container.m_lost == 2, "lost 2"); PFS_thread fake_thread; fake_thread.m_filename_hash_pins= NULL; file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true); ok(file == NULL, "no file"); - ok(file_lost == 1, "lost 1"); + ok(global_file_container.m_lost == 1, "lost 1"); file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true); ok(file == NULL, "no file"); - ok(file_lost == 2, "lost 2"); + ok(global_file_container.m_lost == 2, "lost 2"); - init_file_hash(); + init_file_hash(& param); file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true); ok(file == NULL, "no file"); - ok(file_lost == 3, "lost 3"); + ok(global_file_container.m_lost == 3, "lost 3"); file= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true); ok(file == NULL, "no file"); - ok(file_lost == 4, "lost 4"); + ok(global_file_container.m_lost == 4, "lost 4"); char long_file_name[10000]; int size= sizeof(long_file_name); @@ -186,21 +222,21 @@ void test_no_instances() 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"); + ok(global_file_container.m_lost == 5, "lost 5"); table= create_table(& dummy_table_share, & fake_thread, NULL); ok(table == NULL, "no table"); - ok(table_lost == 1, "lost 1"); + ok(global_table_container.m_lost == 1, "lost 1"); table= create_table(& dummy_table_share, & fake_thread, NULL); ok(table == NULL, "no table"); - ok(table_lost == 2, "lost 2"); + ok(global_table_container.m_lost == 2, "lost 2"); socket= create_socket(& dummy_socket_class, NULL, NULL, 0); ok(socket == NULL, "no socket"); - ok(socket_lost == 1, "lost 1"); + ok(global_socket_container.m_lost == 1, "lost 1"); socket= create_socket(& dummy_socket_class, NULL, NULL, 0); ok(socket == NULL, "no socket"); - ok(socket_lost == 2, "lost 2"); + ok(global_socket_container.m_lost == 2, "lost 2"); /* No result to test, just make sure it does not crash */ reset_events_waits_by_instance(); @@ -265,139 +301,163 @@ void test_with_instances() param.m_statement_class_sizing= 0; param.m_events_statements_history_sizing= 0; param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; param.m_digest_sizing= 0; param.m_session_connect_attrs_sizing= 0; - param.m_max_digest_length= 0; + param.m_program_sizing= 0; + param.m_prepared_stmt_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 1; + param.m_metadata_lock_sizing= 0; init_event_name_sizing(& param); rc= init_instruments(& param); ok(rc == 0, "instances init"); dummy_mutex_class.m_event_name_index= 0; + dummy_mutex_class.m_flags= 0; + dummy_mutex_class.m_enabled= true; + dummy_mutex_class.m_volatility = PSI_VOLATILITY_UNKNOWN; dummy_rwlock_class.m_event_name_index= 1; + dummy_rwlock_class.m_flags= 0; + dummy_rwlock_class.m_enabled= true; + dummy_rwlock_class.m_volatility = PSI_VOLATILITY_UNKNOWN; dummy_cond_class.m_event_name_index= 2; + dummy_cond_class.m_flags= 0; + dummy_cond_class.m_enabled= true; + dummy_cond_class.m_volatility = PSI_VOLATILITY_UNKNOWN; dummy_file_class.m_event_name_index= 3; + dummy_file_class.m_flags= 0; + dummy_file_class.m_enabled= true; + dummy_file_class.m_volatility = PSI_VOLATILITY_UNKNOWN; dummy_socket_class.m_event_name_index= 4; + dummy_socket_class.m_flags= 0; + dummy_socket_class.m_enabled= true; + dummy_socket_class.m_volatility = PSI_VOLATILITY_UNKNOWN; + + dummy_table_share.m_enabled= true; + dummy_table_share.m_timed= true; mutex_1= create_mutex(& dummy_mutex_class, NULL); ok(mutex_1 != NULL, "mutex"); - ok(mutex_lost == 0, "not lost"); + ok(global_mutex_container.get_lost_counter() == 0, "not lost"); mutex_2= create_mutex(& dummy_mutex_class, NULL); ok(mutex_2 != NULL, "mutex"); - ok(mutex_lost == 0, "not lost"); + ok(global_mutex_container.get_lost_counter() == 0, "not lost"); mutex_2= create_mutex(& dummy_mutex_class, NULL); ok(mutex_2 == NULL, "no mutex"); - ok(mutex_lost == 1, "lost 1"); + ok(global_mutex_container.get_lost_counter() == 1, "lost 1"); destroy_mutex(mutex_1); mutex_2= create_mutex(& dummy_mutex_class, NULL); ok(mutex_2 != NULL, "mutex"); - ok(mutex_lost == 1, "no new loss"); + ok(global_mutex_container.get_lost_counter() == 1, "no new loss"); rwlock_1= create_rwlock(& dummy_rwlock_class, NULL); ok(rwlock_1 != NULL, "rwlock"); - ok(rwlock_lost == 0, "not lost"); + ok(global_rwlock_container.m_lost == 0, "not lost"); rwlock_2= create_rwlock(& dummy_rwlock_class, NULL); ok(rwlock_2 != NULL, "rwlock"); - ok(rwlock_lost == 0, "not lost"); + ok(global_rwlock_container.m_lost == 0, "not lost"); rwlock_2= create_rwlock(& dummy_rwlock_class, NULL); ok(rwlock_2 == NULL, "no rwlock"); - ok(rwlock_lost == 1, "lost 1"); + ok(global_rwlock_container.m_lost == 1, "lost 1"); destroy_rwlock(rwlock_1); rwlock_2= create_rwlock(& dummy_rwlock_class, NULL); ok(rwlock_2 != NULL, "rwlock"); - ok(rwlock_lost == 1, "no new loss"); + ok(global_rwlock_container.m_lost == 1, "no new loss"); cond_1= create_cond(& dummy_cond_class, NULL); ok(cond_1 != NULL, "cond"); - ok(cond_lost == 0, "not lost"); + ok(global_cond_container.m_lost == 0, "not lost"); cond_2= create_cond(& dummy_cond_class, NULL); ok(cond_2 != NULL, "cond"); - ok(cond_lost == 0, "not lost"); + ok(global_cond_container.m_lost == 0, "not lost"); cond_2= create_cond(& dummy_cond_class, NULL); ok(cond_2 == NULL, "no cond"); - ok(cond_lost == 1, "lost 1"); + ok(global_cond_container.m_lost == 1, "lost 1"); destroy_cond(cond_1); cond_2= create_cond(& dummy_cond_class, NULL); ok(cond_2 != NULL, "cond"); - ok(cond_lost == 1, "no new loss"); + ok(global_cond_container.m_lost == 1, "no new loss"); thread_1= create_thread(& dummy_thread_class, NULL, 0); ok(thread_1 != NULL, "thread"); - ok(thread_lost == 0, "not lost"); + ok(global_thread_container.m_lost == 0, "not lost"); thread_2= create_thread(& dummy_thread_class, NULL, 0); ok(thread_2 != NULL, "thread"); - ok(thread_lost == 0, "not lost"); + ok(global_thread_container.m_lost == 0, "not lost"); thread_2= create_thread(& dummy_thread_class, NULL, 0); ok(thread_2 == NULL, "no thread"); - ok(thread_lost == 1, "lost 1"); + ok(global_thread_container.m_lost == 1, "lost 1"); destroy_thread(thread_1); thread_2= create_thread(& dummy_thread_class, NULL, 0); ok(thread_2 != NULL, "thread"); - ok(thread_lost == 1, "no new loss"); + ok(global_thread_container.m_lost == 1, "no new loss"); PFS_thread fake_thread; fake_thread.m_filename_hash_pins= NULL; file_1= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true); ok(file_1 == NULL, "no file"); - ok(file_lost == 1, "lost 1"); + ok(global_file_container.m_lost == 1, "lost 1"); file_1= find_or_create_file(& fake_thread, & dummy_file_class, "dummy", 5, true); ok(file_1 == NULL, "no file"); - ok(file_lost == 2, "lost 2"); + ok(global_file_container.m_lost == 2, "lost 2"); - init_file_hash(); - file_lost= 0; + init_file_hash(& param); + global_file_container.m_lost= 0; file_1= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_A", 7, true); ok(file_1 != NULL, "file"); ok(file_1->m_file_stat.m_open_count == 1, "open count 1"); - ok(file_lost == 0, "not lost"); + ok(global_file_container.m_lost == 0, "not lost"); file_2= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_A", 7, true); ok(file_1 == file_2, "same file"); ok(file_1->m_file_stat.m_open_count == 2, "open count 2"); - ok(file_lost == 0, "not lost"); + ok(global_file_container.m_lost == 0, "not lost"); release_file(file_2); ok(file_1->m_file_stat.m_open_count == 1, "open count 1"); file_2= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_B", 7, true); ok(file_2 != NULL, "file"); - ok(file_lost == 0, "not lost"); + ok(global_file_container.m_lost == 0, "not lost"); file_2= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_C", 7, true); ok(file_2 == NULL, "no file"); - ok(file_lost == 1, "lost"); + ok(global_file_container.m_lost == 1, "lost"); release_file(file_1); /* the file still exists, not destroyed */ ok(file_1->m_file_stat.m_open_count == 0, "open count 0"); file_2= find_or_create_file(& fake_thread, & dummy_file_class, "dummy_D", 7, true); ok(file_2 == NULL, "no file"); - ok(file_lost == 2, "lost"); + ok(global_file_container.m_lost == 2, "lost"); socket_1= create_socket(& dummy_socket_class, NULL, NULL, 0); ok(socket_1 != NULL, "socket"); - ok(socket_lost == 0, "not lost"); + ok(global_socket_container.m_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"); + ok(global_socket_container.m_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"); + ok(global_socket_container.m_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"); + ok(global_socket_container.m_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"); + ok(global_table_container.m_lost == 0, "not lost"); table_2= create_table(& dummy_table_share, & fake_thread, NULL); ok(table_2 != NULL, "table"); - ok(table_lost == 0, "not lost"); + ok(global_table_container.m_lost == 0, "not lost"); table_2= create_table(& dummy_table_share, & fake_thread, NULL); ok(table_2 == NULL, "no table"); - ok(table_lost == 1, "lost 1"); + ok(global_table_container.m_lost == 1, "lost 1"); destroy_table(table_1); table_2= create_table(& dummy_table_share, & fake_thread, NULL); ok(table_2 != NULL, "table"); - ok(table_lost == 1, "no new loss"); + ok(global_table_container.m_lost == 1, "no new loss"); //TODO: test that cleanup works reset_events_waits_by_instance(); @@ -409,6 +469,9 @@ void test_with_instances() void do_all_tests() { + flag_global_instrumentation= true; + flag_thread_instrumentation= true; + test_no_instruments(); test_no_instances(); test_with_instances(); diff --git a/storage/perfschema/unittest/pfs_instr_class-oom-t.cc b/storage/perfschema/unittest/pfs_instr_class-oom-t.cc index 7eb21a33bd7..0f9d6ef07d5 100644 --- a/storage/perfschema/unittest/pfs_instr_class-oom-t.cc +++ b/storage/perfschema/unittest/pfs_instr_class-oom-t.cc @@ -21,16 +21,24 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include <my_global.h> -#include <my_pthread.h> +#include <my_thread.h> #include <pfs_instr_class.h> +#include <pfs_instr.h> #include <pfs_global.h> #include <tap.h> +#include <sql_class.h> +#include <pfs_buffer_container.h> #include "stub_pfs_global.h" +#include "stub_global_status_var.h" void test_oom() { int rc; + PFS_global_param param; + TABLE_SHARE table_share; + PFS_thread pfs_thread; + PFS_table_share *pfs_table_share; rc= init_sync_class(1000, 0, 0); ok(rc == 1, "oom (mutex)"); @@ -42,14 +50,14 @@ void test_oom() ok(rc == 1, "oom (thread)"); rc= init_file_class(1000); ok(rc == 1, "oom (file)"); - rc= init_table_share(1000); - ok(rc == 1, "oom (cond)"); rc= init_socket_class(1000); ok(rc == 1, "oom (socket)"); rc= init_stage_class(1000); ok(rc == 1, "oom (stage)"); rc= init_statement_class(1000); ok(rc == 1, "oom (statement)"); + rc= init_memory_class(1000); + ok(rc == 1, "oom (memory)"); cleanup_sync_class(); cleanup_thread_class(); @@ -58,6 +66,36 @@ void test_oom() cleanup_socket_class(); cleanup_stage_class(); cleanup_statement_class(); + cleanup_memory_class(); + + /* Table share classes. */ + memset(¶m, 0, sizeof(param)); + param.m_enabled= true; + param.m_table_share_sizing= 100; + param.m_setup_object_sizing= 100; + + pfs_thread.m_table_share_hash_pins= NULL; + pfs_thread.m_setup_object_hash_pins= NULL; + + char db_name[]= "schema 1"; + char table_name[]= "table 1"; + table_share.db.str= db_name; + table_share.db.length= strlen(db_name); + table_share.table_name.str= table_name; + table_share.table_name.length= strlen(table_name); + + init_table_share(param.m_table_share_sizing); + init_table_share_hash(¶m); + init_setup_object_hash(¶m); + + stub_alloc_always_fails= false; + pfs_table_share= find_or_create_table_share(&pfs_thread, false, &table_share); + ok(pfs_table_share == NULL, "oom (pfs table share)"); + ok(global_table_share_container.m_lost == 1, "oom (table share)"); + + cleanup_table_share(); + cleanup_table_share_hash(); + cleanup_setup_object_hash(); } void do_all_tests() @@ -67,7 +105,7 @@ void do_all_tests() int main(int argc, char **argv) { - plan(9); + plan(11); MY_INIT(argv[0]); do_all_tests(); my_end(0); diff --git a/storage/perfschema/unittest/pfs_instr_class-t.cc b/storage/perfschema/unittest/pfs_instr_class-t.cc index f1e246dc387..3dfd725cb91 100644 --- a/storage/perfschema/unittest/pfs_instr_class-t.cc +++ b/storage/perfschema/unittest/pfs_instr_class-t.cc @@ -21,13 +21,15 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include <my_global.h> -#include <my_pthread.h> +#include <my_thread.h> #include <string.h> // strncpy #include <pfs_instr_class.h> #include <pfs_instr.h> #include <pfs_global.h> #include <tap.h> +#include "stub_global_status_var.h" + void test_no_registration() { int rc; @@ -35,12 +37,14 @@ void test_no_registration() PFS_thread_key thread_key; PFS_file_key file_key; PFS_socket_key socket_key; + PFS_memory_key memory_key; PFS_mutex_class *mutex; PFS_rwlock_class *rwlock; PFS_cond_class *cond; PFS_thread_class *thread; PFS_file_class *file; PFS_socket_class *socket; + PFS_memory_class *memory; /* PFS_table_share *table; */ rc= init_sync_class(0, 0, 0); @@ -53,6 +57,8 @@ void test_no_registration() ok(rc == 0, "zero init (socket)"); rc= init_table_share(0); ok(rc == 0, "zero init (table)"); + rc= init_memory_class(0); + ok(rc == 0, "zero init (memory)"); key= register_mutex_class("FOO", 3, 0); ok(key == 0, "no mutex registered"); @@ -96,6 +102,13 @@ void test_no_registration() socket_key= register_socket_class("FOO", 3, 0); ok(socket_key == 0, "no socket registered"); + memory_key= register_memory_class("FOO", 3, 0); + ok(memory_key == 0, "no memory registered"); + memory_key= register_memory_class("BAR", 3, 0); + ok(memory_key == 0, "no memory registered"); + memory_key= register_memory_class("FOO", 3, 0); + ok(memory_key == 0, "no memory registered"); + #ifdef LATER PFS_thread fake_thread; fake_thread.m_table_share_hash_pins= NULL; @@ -150,11 +163,19 @@ void test_no_registration() socket= find_socket_class(9999); ok(socket == NULL, "no socket key 9999"); + memory= find_memory_class(0); + ok(memory == NULL, "no memory key 0"); + memory= find_memory_class(1); + ok(memory == NULL, "no memory key 1"); + memory= find_memory_class(9999); + ok(memory == NULL, "no memory key 9999"); + cleanup_sync_class(); cleanup_thread_class(); cleanup_file_class(); cleanup_socket_class(); cleanup_table_share(); + cleanup_memory_class(); } void test_mutex_registration() @@ -480,6 +501,53 @@ void test_table_registration() #endif } +void test_memory_registration() +{ + int rc; + PFS_memory_key key; + PFS_memory_class *memory; + + rc= init_memory_class(5); + ok(rc == 0, "room for 5 memory"); + + key= register_memory_class("FOO", 3, 0); + ok(key == 1, "foo registered"); + key= register_memory_class("BAR", 3, 0); + ok(key == 2, "bar registered"); + key= register_memory_class("FOO", 3, 0); + ok(key == 1, "foo re registered"); + key= register_memory_class("Memory-3", 8, 0); + ok(key == 3, "Memory-3 registered"); + key= register_memory_class("Memory-4", 8, 0); + ok(key == 4, "Memory-4 registered"); + key= register_memory_class("Memory-5", 8, 0); + ok(key == 5, "Memory-5 registered"); + ok(memory_class_lost == 0, "lost nothing"); + key= register_memory_class("Memory-6", 8, 0); + ok(key == 0, "Memory-6 not registered"); + ok(memory_class_lost == 1, "lost 1 memory"); + key= register_memory_class("Memory-7", 8, 0); + ok(key == 0, "Memory-7 not registered"); + ok(memory_class_lost == 2, "lost 2 memory"); + key= register_memory_class("Memory-3", 8, 0); + ok(key == 3, "Memory-3 re registered"); + ok(memory_class_lost == 2, "lost 2 memory"); + key= register_memory_class("Memory-5", 8, 0); + ok(key == 5, "Memory-5 re registered"); + ok(memory_class_lost == 2, "lost 2 memory"); + + memory= find_memory_class(0); + ok(memory == NULL, "no key 0"); + memory= find_memory_class(3); + ok(memory != NULL, "found key 3"); + ok(strncmp(memory->m_name, "Memory-3", 8) == 0, "key 3 is Memory-3"); + ok(memory->m_name_length == 8, "name length 3"); + memory= find_memory_class(9999); + ok(memory == NULL, "no key 9999"); + + cleanup_memory_class(); +} + #ifdef LATER void set_wait_stat(PFS_instr_class *klass) { @@ -668,12 +736,13 @@ void do_all_tests() test_file_registration(); test_socket_registration(); test_table_registration(); + test_memory_registration(); test_instruments_reset(); } int main(int argc, char **argv) { - plan(181); + plan(209); MY_INIT(argv[0]); do_all_tests(); my_end(0); diff --git a/storage/perfschema/unittest/pfs_misc-t.cc b/storage/perfschema/unittest/pfs_misc-t.cc index 7d274c0820d..d82178000c2 100644 --- a/storage/perfschema/unittest/pfs_misc-t.cc +++ b/storage/perfschema/unittest/pfs_misc-t.cc @@ -21,22 +21,26 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include <my_global.h> +#include <my_thread.h> #include <pfs_instr.h> #include <pfs_stat.h> #include <pfs_global.h> #include <pfs_instr_class.h> +#include <pfs_buffer_container.h> #include <tap.h> +#include "stub_global_status_var.h" + #include <memory.h> void test_digest_length_overflow() { if (sizeof(size_t) != 4) { - skip(2, "digest length overflow requires a 32-bit environment"); + skip(3, "digest length overflow requires a 32-bit environment"); return; } - + PFS_global_param param; memset(¶m, 0, sizeof(param)); param.m_enabled= true; @@ -45,19 +49,32 @@ void test_digest_length_overflow() 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); + param.m_max_sql_text_length= 0; pfs_max_digest_length= param.m_max_digest_length; + pfs_max_sqltext= param.m_max_sql_text_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 sql text length, events_statements_history_long. */ + param.m_max_sql_text_length= (1024 * 1024); + param.m_max_digest_length= 0; + pfs_max_digest_length= param.m_max_digest_length; + pfs_max_sqltext= param.m_max_sql_text_length; + + rc = init_events_statements_history_long(param.m_events_statements_history_long_sizing); + ok(rc == 1, "sql text 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; + pfs_max_digest_length= param.m_max_digest_length; + pfs_max_sqltext= param.m_max_sql_text_length; rc = init_digest(¶m); ok(rc == 1, "digest length overflow (init_digest)"); @@ -70,10 +87,9 @@ void do_all_tests() int main(int, char **) { - plan(2); + plan(3); MY_INIT("pfs_misc-t"); do_all_tests(); my_end(0); return (exit_status()); } - diff --git a/storage/perfschema/unittest/pfs_noop-t.cc b/storage/perfschema/unittest/pfs_noop-t.cc new file mode 100644 index 00000000000..8ef11371519 --- /dev/null +++ b/storage/perfschema/unittest/pfs_noop-t.cc @@ -0,0 +1,242 @@ +/* Copyright (c) 2013, 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_thread.h> +#include <pfs_server.h> +#include <pfs_instr_class.h> +#include <pfs_instr.h> +#include <pfs_global.h> +#include <tap.h> + +#include <string.h> +#include <memory.h> + +#include "stub_print_error.h" +#include "stub_pfs_defaults.h" + +void test_noop() +{ + PSI_mutex *mutex; + PSI_rwlock *rwlock; + PSI_cond *cond; + PSI_socket *socket; + PSI_table_share *table_share; + PSI_table *table; + PSI_file *file; + PSI_thread *thread; + PSI_file_locker *file_locker; + PSI_idle_locker *idle_locker; + PSI_mutex_locker *mutex_locker; + PSI_rwlock_locker *rwlock_locker; + PSI_cond_locker *cond_locker; + PSI_table_locker *table_locker; + PSI_statement_locker *statement_locker; + PSI_transaction_locker *transaction_locker; + PSI_socket_locker *socket_locker; + PSI_digest_locker *digest_locker; + PSI_sp_locker *sp_locker; + PSI_sp_share *sp_share; + PSI_memory_key memory_key; + PSI_metadata_lock *metadata_lock; + PSI_metadata_locker *metadata_locker; + PSI_thread *owner; + + diag("test_noop"); + + PSI_server->register_mutex(NULL, NULL, 0); + PSI_server->register_rwlock(NULL, NULL, 0); + PSI_server->register_cond(NULL, NULL, 0); + PSI_server->register_thread(NULL, NULL, 0); + PSI_server->register_file(NULL, NULL, 0); + PSI_server->register_stage(NULL, NULL, 0); + PSI_server->register_statement(NULL, NULL, 0); + PSI_server->register_socket(NULL, NULL, 0); + + ok(true, "register"); + mutex= PSI_server->init_mutex(1, NULL); + ok(mutex == NULL, "no mutex"); + PSI_server->destroy_mutex(NULL); + rwlock= PSI_server->init_rwlock(1, NULL); + ok(rwlock == NULL, "no rwlock"); + PSI_server->destroy_rwlock(NULL); + cond= PSI_server->init_cond(1, NULL); + ok(cond == NULL, "no cond"); + PSI_server->destroy_cond(NULL); + socket= PSI_server->init_socket(1, NULL, NULL, 0); + ok(socket == NULL, "no socket"); + PSI_server->destroy_socket(NULL); + table_share= PSI_server->get_table_share(false, NULL); + ok(table_share == NULL, "no table_share"); + PSI_server->release_table_share(NULL); + PSI_server->drop_table_share(false, NULL, 0, NULL, 0); + table= PSI_server->open_table(NULL, NULL); + ok(table == NULL, "no table"); + PSI_server->unbind_table(NULL); + table= PSI_server->rebind_table(NULL, NULL, NULL); + ok(table == NULL, "no table"); + PSI_server->close_table(NULL, NULL); + PSI_server->create_file(1, NULL, 2); + /* TODO: spawn thread */ + thread= PSI_server->new_thread(1, NULL, 2); + ok(thread == NULL, "no thread"); + PSI_server->set_thread_id(NULL, 1); + thread= PSI_server->get_thread(); + ok(thread == NULL, "no thread"); + PSI_server->set_thread_user(NULL, 0); + PSI_server->set_thread_account(NULL, 0, NULL, 0); + PSI_server->set_thread_db(NULL, 0); + PSI_server->set_thread_command(1); + PSI_server->set_thread_start_time(1); + PSI_server->set_thread_state(NULL); + PSI_server->set_thread_info(NULL, 0); + PSI_server->set_thread(NULL); + PSI_server->delete_current_thread(); + PSI_server->delete_thread(NULL); + file_locker= PSI_server->get_thread_file_name_locker(NULL, 1, PSI_FILE_OPEN, NULL, NULL); + ok(file_locker == NULL, "no file_locker"); + file_locker= PSI_server->get_thread_file_stream_locker(NULL, NULL, PSI_FILE_OPEN); + ok(file_locker == NULL, "no file_locker"); + file_locker= PSI_server->get_thread_file_descriptor_locker(NULL, 0, PSI_FILE_OPEN); + ok(file_locker == NULL, "no file_locker"); + PSI_server->unlock_mutex(NULL); + PSI_server->unlock_rwlock(NULL); + PSI_server->signal_cond(NULL); + PSI_server->broadcast_cond(NULL); + idle_locker= PSI_server->start_idle_wait(NULL, NULL, 0); + ok(idle_locker == NULL, "no idle_locker"); + PSI_server->end_idle_wait(NULL); + mutex_locker= PSI_server->start_mutex_wait(NULL, NULL, PSI_MUTEX_LOCK, NULL, 0); + ok(mutex_locker == NULL, "no mutex_locker"); + PSI_server->end_mutex_wait(NULL, 0); + rwlock_locker= PSI_server->start_rwlock_rdwait(NULL, NULL, PSI_RWLOCK_READLOCK, NULL, 0); + ok(rwlock_locker == NULL, "no rwlock_locker"); + PSI_server->end_rwlock_rdwait(NULL, 0); + rwlock_locker= PSI_server->start_rwlock_wrwait(NULL, NULL, PSI_RWLOCK_WRITELOCK, NULL, 0); + ok(rwlock_locker == NULL, "no rwlock_locker"); + PSI_server->end_rwlock_wrwait(NULL, 0); + cond_locker= PSI_server->start_cond_wait(NULL, NULL, NULL, PSI_COND_WAIT, NULL, 0); + ok(cond_locker == NULL, "no cond_locker"); + PSI_server->end_cond_wait(NULL, 0); + table_locker= PSI_server->start_table_io_wait(NULL, NULL, PSI_TABLE_FETCH_ROW, 0, NULL, 0); + ok(table_locker == NULL, "no table_locker"); + PSI_server->end_table_io_wait(NULL, 0); + table_locker= PSI_server->start_table_lock_wait(NULL, NULL, PSI_TABLE_LOCK, 0, NULL, 0); + ok(table_locker == NULL, "no table_locker"); + PSI_server->end_table_lock_wait(NULL); + PSI_server->start_file_open_wait(NULL, NULL, 0); + file= PSI_server->end_file_open_wait(NULL, NULL); + ok(file == NULL, "no file"); + PSI_server->end_file_open_wait_and_bind_to_descriptor(NULL, 0); + PSI_server->start_file_wait(NULL, 0, NULL, 0); + PSI_server->end_file_wait(NULL, 0); + PSI_server->start_file_close_wait(NULL, NULL, 0); + PSI_server->end_file_close_wait(NULL, 0); + PSI_server->end_file_rename_wait(NULL, NULL, NULL, 0); + PSI_server->start_stage(1, NULL, 0); + + PSI_stage_progress *progress; + progress= PSI_server->get_current_stage_progress(); + ok(progress == NULL, "no progress"); + + PSI_server->end_stage(); + statement_locker= PSI_server->get_thread_statement_locker(NULL, 1, NULL, NULL); + ok(statement_locker == NULL, "no statement_locker"); + statement_locker= PSI_server->refine_statement(NULL, 1); + ok(statement_locker == NULL, "no statement_locker"); + PSI_server->start_statement(NULL, NULL, 0, NULL, 0); + PSI_server->set_statement_text(NULL, NULL, 0); + PSI_server->set_statement_lock_time(NULL, 0); + PSI_server->set_statement_rows_sent(NULL, 0); + PSI_server->set_statement_rows_examined(NULL, 0); + PSI_server->inc_statement_created_tmp_disk_tables(NULL, 0); + PSI_server->inc_statement_created_tmp_tables(NULL, 0); + PSI_server->inc_statement_select_full_join(NULL, 0); + PSI_server->inc_statement_select_full_range_join(NULL, 0); + PSI_server->inc_statement_select_range(NULL, 0); + PSI_server->inc_statement_select_range_check(NULL, 0); + PSI_server->inc_statement_select_scan(NULL, 0); + PSI_server->inc_statement_sort_merge_passes(NULL, 0); + PSI_server->inc_statement_sort_range(NULL, 0); + PSI_server->inc_statement_sort_rows(NULL, 0); + PSI_server->inc_statement_sort_scan(NULL, 0); + PSI_server->set_statement_no_index_used(NULL); + PSI_server->set_statement_no_good_index_used(NULL); + PSI_server->end_statement(NULL, NULL); + socket_locker= PSI_server->start_socket_wait(NULL, NULL, PSI_SOCKET_SEND, 1, NULL, 0); + ok(socket_locker == NULL, "no socket_locker"); + PSI_server->end_socket_wait(NULL, 0); + PSI_server->set_socket_state(NULL, PSI_SOCKET_STATE_IDLE); + PSI_server->set_socket_info(NULL, NULL, NULL, 0); + PSI_server->set_socket_thread_owner(NULL); + digest_locker= PSI_server->digest_start(NULL); + ok(digest_locker == NULL, "no digest_locker"); + PSI_server->digest_end(NULL, NULL); + sp_locker= PSI_server->start_sp(NULL, NULL); + ok(sp_locker == NULL, "no sp_locker"); + PSI_server->end_sp(NULL); + PSI_server->drop_sp(0, NULL, 0, NULL, 0); + sp_share= PSI_server->get_sp_share(0, NULL, 0, NULL, 0); + ok(sp_share == NULL, "no sp_share"); + PSI_server->release_sp_share(NULL); + PSI_server->register_memory(NULL, NULL, 0); + memory_key= PSI_server->memory_alloc(0, 0, & owner); + ok(memory_key == PSI_NOT_INSTRUMENTED, "no memory_key"); + memory_key= PSI_server->memory_realloc(0, 0, 0, & owner); + ok(memory_key == PSI_NOT_INSTRUMENTED, "no memory_key"); + PSI_server->memory_free(0, 0, NULL); + PSI_server->unlock_table(NULL); + metadata_lock= PSI_server->create_metadata_lock(NULL, NULL, 1, 2, 3, NULL, 0); + ok(metadata_lock == NULL, "no metadata_lock"); + PSI_server->set_metadata_lock_status(NULL, 0); + PSI_server->destroy_metadata_lock(NULL); + metadata_locker= PSI_server->start_metadata_wait(NULL, NULL, NULL, 0); + ok(metadata_locker == NULL, "no metadata_locker"); + PSI_server->end_metadata_wait(NULL, 0); + + transaction_locker= PSI_server->get_thread_transaction_locker(NULL, NULL, NULL, 1, false, 1); + ok(transaction_locker == NULL, "no transaction_locker"); + PSI_server->start_transaction(NULL, NULL, 0); + PSI_server->end_transaction(NULL, true); + + PSI_server->set_transaction_gtid(NULL, NULL, NULL); + PSI_server->set_transaction_trxid(NULL, NULL); + PSI_server->set_transaction_xa_state(NULL, 1); + PSI_server->set_transaction_xid(NULL, NULL, 1); + PSI_server->inc_transaction_release_savepoint(NULL, 1); + PSI_server->inc_transaction_rollback_to_savepoint(NULL, 1); + PSI_server->inc_transaction_savepoints(NULL, 1); + + PSI_server->set_thread_THD(NULL, NULL); + + ok(true, "all noop api called"); +} + +int main(int, char **) +{ + plan(34); + + MY_INIT("pfs_noop-t"); + test_noop(); + return (exit_status()); +} + diff --git a/storage/perfschema/unittest/pfs_server_stubs.cc b/storage/perfschema/unittest/pfs_server_stubs.cc index 0cabce37e51..31894223e89 100644 --- a/storage/perfschema/unittest/pfs_server_stubs.cc +++ b/storage/perfschema/unittest/pfs_server_stubs.cc @@ -1,4 +1,5 @@ -/* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 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, version 2.0, @@ -29,6 +30,8 @@ #include "sql_class.h" #include "sql_show.h" +my_bool show_compatibility_56= FALSE; +struct system_status_var global_status_var; struct sql_digest_storage; uint lower_case_table_names= 0; @@ -39,6 +42,15 @@ void compute_digest_md5(const sql_digest_storage *, unsigned char *) { } +void reset_status_vars() +{ +} + +void sql_print_warning(const char *format, ...) +{ + /* Do not pollute the unit test output with annoying messages. */ +} + class sys_var { public: enum where { AUTO }; }; void set_sys_var_value_origin(void *ptr, enum sys_var::where here) { diff --git a/storage/perfschema/unittest/pfs_timer-t.cc b/storage/perfschema/unittest/pfs_timer-t.cc index 139454b8649..6c852242537 100644 --- a/storage/perfschema/unittest/pfs_timer-t.cc +++ b/storage/perfschema/unittest/pfs_timer-t.cc @@ -22,7 +22,6 @@ #include <my_global.h> #include <my_pthread.h> -#include <pfs_atomic.h> #include <pfs_timer.h> #include "my_sys.h" #include <tap.h> diff --git a/storage/perfschema/unittest/pfs_user-oom-t.cc b/storage/perfschema/unittest/pfs_user-oom-t.cc index ca451f3e457..864275b765e 100644 --- a/storage/perfschema/unittest/pfs_user-oom-t.cc +++ b/storage/perfschema/unittest/pfs_user-oom-t.cc @@ -21,21 +21,24 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include <my_global.h> -#include <my_pthread.h> +#include <my_thread.h> #include <pfs_instr.h> #include <pfs_stat.h> #include <pfs_global.h> #include <pfs_user.h> +#include <pfs_buffer_container.h> #include <tap.h> #include "stub_pfs_global.h" +#include "stub_global_status_var.h" #include <string.h> /* memset */ void test_oom() { - int rc; + PSI *psi; PFS_global_param param; + PSI_bootstrap *boot; memset(& param, 0xFF, sizeof(param)); param.m_enabled= true; @@ -45,6 +48,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; @@ -52,6 +56,7 @@ 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; @@ -65,42 +70,64 @@ void test_oom() param.m_statement_class_sizing= 50; param.m_events_statements_history_sizing= 0; param.m_events_statements_history_long_sizing= 0; + param.m_events_transactions_history_sizing= 0; + param.m_events_transactions_history_long_sizing= 0; + param.m_digest_sizing= 0; + param.m_session_connect_attrs_sizing= 0; + param.m_program_sizing= 0; + param.m_statement_stack_sizing= 0; + param.m_memory_class_sizing= 10; + param.m_metadata_lock_sizing= 0; + param.m_max_digest_length= 0; + param.m_max_sql_text_length= 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"); + pre_initialize_performance_schema(); + boot= initialize_performance_schema(¶m); + psi= (PSI *)boot->get_interface(PSI_VERSION_1); + + PSI_thread_key thread_key_1; + PSI_thread_info all_thread[]= + { + {&thread_key_1, "T-1", 0} + }; + psi->register_thread("test", all_thread, 1); + + PSI_thread *thread_1= psi->new_thread(thread_key_1, NULL, 0); + psi->set_thread(thread_1); /* Tests */ - stub_alloc_fails_after_count= 1; - rc= init_user(& param); - ok(rc == 1, "oom (user)"); - cleanup_user(); + int first_fail= 1; + stub_alloc_fails_after_count= first_fail; + psi->set_thread_account("user1", 5, "", 0); + ok(global_user_container.m_lost == 1, "oom (user)"); + + stub_alloc_fails_after_count= first_fail + 1; + psi->set_thread_account("user2", 5, "", 0); + ok(global_user_container.m_lost == 2, "oom (user waits)"); + + stub_alloc_fails_after_count= first_fail + 2; + psi->set_thread_account("user3", 5, "", 0); + ok(global_user_container.m_lost == 3, "oom (user stages)"); - stub_alloc_fails_after_count= 2; - rc= init_user(& param); - ok(rc == 1, "oom (user waits)"); - cleanup_user(); + stub_alloc_fails_after_count= first_fail + 3; + psi->set_thread_account("user4", 5, "", 0); + ok(global_user_container.m_lost == 4, "oom (user statements)"); - stub_alloc_fails_after_count= 3; - rc= init_user(& param); - ok(rc == 1, "oom (user stages)"); - cleanup_user(); + stub_alloc_fails_after_count= first_fail + 4; + psi->set_thread_account("user5", 5, "", 0); + ok(global_user_container.m_lost == 5, "oom (user transactions)"); - stub_alloc_fails_after_count= 4; - rc= init_user(& param); - ok(rc == 1, "oom (user statements)"); - cleanup_user(); + stub_alloc_fails_after_count= first_fail + 5; + psi->set_thread_account("user6", 5, "", 0); + ok(global_user_container.m_lost == 6, "oom (user memory)"); - cleanup_statement_class(); - cleanup_stage_class(); + shutdown_performance_schema(); } void do_all_tests() diff --git a/storage/perfschema/unittest/stub_global_status_var.h b/storage/perfschema/unittest/stub_global_status_var.h new file mode 100644 index 00000000000..bfb06b4e0d5 --- /dev/null +++ b/storage/perfschema/unittest/stub_global_status_var.h @@ -0,0 +1,31 @@ +/* Copyright (c) 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, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_sys.h> +#include <pfs_global.h> +#include <string.h> + + +void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, bool reset_from_var) +{ +} diff --git a/storage/perfschema/unittest/stub_pfs_global.h b/storage/perfschema/unittest/stub_pfs_global.h index 8a1f9216ba2..23b731cb8b2 100644 --- a/storage/perfschema/unittest/stub_pfs_global.h +++ b/storage/perfschema/unittest/stub_pfs_global.h @@ -26,11 +26,13 @@ #include <string.h> bool pfs_initialized= false; +size_t pfs_allocated_memory_size= 0; +size_t pfs_allocated_memory_count= 0; bool stub_alloc_always_fails= true; int stub_alloc_fails_after_count= 0; -void *pfs_malloc(size_t size, myf) +void *pfs_malloc(PFS_builtin_memory_class *klass, size_t size, myf) { /* Catch non initialized sizing parameter in the unit tests. @@ -49,19 +51,27 @@ void *pfs_malloc(size_t size, myf) return ptr; } -void pfs_free(void *ptr) +void pfs_free(PFS_builtin_memory_class *, size_t, void *ptr) { if (ptr != NULL) free(ptr); } -void *pfs_malloc_array(size_t n, size_t size, myf flags) +void *pfs_malloc_array(PFS_builtin_memory_class *klass, 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); + return pfs_malloc(klass, array_size, flags); +} + +void pfs_free_array(PFS_builtin_memory_class *klass, size_t n, size_t size, void *ptr) +{ + if (ptr == NULL) + return; + size_t array_size= n * size; + return pfs_free(klass, array_size, ptr); } bool is_overflow(size_t product, size_t n1, size_t n2) @@ -76,3 +86,4 @@ 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 2cd2ad5b03c..8d87fbe5923 100644 --- a/storage/perfschema/unittest/stub_print_error.h +++ b/storage/perfschema/unittest/stub_print_error.h @@ -26,7 +26,7 @@ bool pfs_initialized= false; -void *pfs_malloc(size_t size, myf flags) +void *pfs_malloc(PFS_builtin_memory_class *klass, size_t size, myf flags) { void *ptr= malloc(size); if (ptr && (flags & MY_ZEROFILL)) @@ -34,19 +34,27 @@ void *pfs_malloc(size_t size, myf flags) return ptr; } -void pfs_free(void *ptr) +void pfs_free(PFS_builtin_memory_class *, size_t, void *ptr) { if (ptr != NULL) free(ptr); } -void *pfs_malloc_array(size_t n, size_t size, myf flags) +void *pfs_malloc_array(PFS_builtin_memory_class *klass, 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); + return pfs_malloc(klass, array_size, flags); +} + +void pfs_free_array(PFS_builtin_memory_class *klass, size_t n, size_t size, void *ptr) +{ + if (ptr == NULL) + return; + size_t array_size= n * size; + return pfs_free(klass, array_size, ptr); } bool is_overflow(size_t product, size_t n1, size_t n2) |