diff options
Diffstat (limited to 'storage/perfschema/pfs_variable.h')
-rw-r--r-- | storage/perfschema/pfs_variable.h | 716 |
1 files changed, 716 insertions, 0 deletions
diff --git a/storage/perfschema/pfs_variable.h b/storage/perfschema/pfs_variable.h new file mode 100644 index 00000000..d3ad4c7f --- /dev/null +++ b/storage/perfschema/pfs_variable.h @@ -0,0 +1,716 @@ +/* Copyright (c) 2015, 2023, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, 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" + +/* 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), + m_initialized(false), + m_external_init(external_init), + m_materialized(false), + m_show_var_array(PSI_INSTRUMENT_MEM), + 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; + +}; + +/** + 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) +{ + 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); +} + +/** + 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 + |