summaryrefslogtreecommitdiffstats
path: root/storage/perfschema/pfs_variable.h
diff options
context:
space:
mode:
Diffstat (limited to 'storage/perfschema/pfs_variable.h')
-rw-r--r--storage/perfschema/pfs_variable.h716
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
+