WL#9856: MySQL GCS: Instrument locking structures in GCS/XCom
Affects: Server-8.0
—
Status: Complete
Executive Summary ================= This worklog will instrument mutex and condition synchronization objects on GCS and will expose them automatically in P_S tables metrics, using the Server's Performance Schema Interface to instrument the aforementioned synchronization objects as well as declaring and registering the keys of the instrumented mutex and condition objects. Since XCom is currently single threaded, this worklog will not affect it. User Stories ============ -As a MySQL DBA, I want to monitor the mutex and condition synchronization objects of GCS, so that I am able to determine if there are any concurrency related issues. -As a MySQL dev, I want to have mutex and condition synchronization objects instrumentation in GCS, so I can determine if there are any abnormal wait events like bottlenecks or deadlocks.
------------------------ Functional requirements: ------------------------ FR1. GCS must be able to be built with or without instrumentation. FR2. If instrumentation is enabled, each instrumented condition or mutex must correspond to an entry in the setup_instruments table, stating its name and if its instrumentation is timed and enabled. FR3. If instrumentation is enabled while the node is in a group or trying to join one, the cond_instances table must contain one entry per instrumented GCS condition, stating its name and memory address. FR4. If instrumentation is enabled while the node is in a group or trying to join one, the mutex_instances table must contain 6 entries, current value of the XCOM_MAX_HANDLERS macro in the gcs_xcom_utils.cc file, with the name wait/synch/mutex/group_rpl/GCS_Xcom_handler::m_lock, which refer to the 6 instances of the m_lock mutex, present in the Xcom_handler class. FR5. If instrumentation is enabled while the node is in a group or trying to join one, the mutex_instances table must contain one entry for each of the remaining instrumented GCS mutexes, stating its name, memory address and the id of the thread that locked it, or NULL if it is unlocked. FR6. If instrumentation is enabled, the events_waits_current, events_waits_history and events_waits_history_long tables must contain entries regarding current and past mutex locks by threads. FR7. If instrumentation is disabled globally, no instrumentation information should be displayed. ---------------------------- Non-Functional requirements: ---------------------------- NFR1. The code modifications resulting from this WL must not degrade the performance of GCS and XCom. NFR2. Each instrumented code element must be univocally identified so that we can monitor and understand the behavior of each individual element as a separate entity.
Since the build process of GCS was already modified in WL#10622 to enable instrumentation, it is only necessary to modify its source code in order to leverage it for synchronization objects, such as mutexes and conditions. The source code of GCS is then modified with the declaration and registration of the instrumentation keys, and with the addition of the corresponding instrumentation keys as parameters for the invoked synchronization objects init functions. These are wrapped in the Xplatform, which is modified by replacing the existing platform-specific code with invocations to the corresponding instrumented Server's mysql_mutex_* and mysql_cond_* functions for mutexes and conditions, respectively. Interface changes ================= This WL introduces minor interface changes to GCS, namely by modifying the signatures of the init methods of My_xp_mutex and My_xp_cond to include the additional instrumentation key parameter. -For instance, in the Gcs_suspicions_manager constructor, defined in the gcs_xcom_control_interface.cc file, there's the following invocation to the init method of m_suspicions_mutex: m_suspicions_mutex.init(NULL); This will be replaced by the following code: m_suspicions_mutex.init( key_GCS_MUTEX_Gcs_suspicions_manager_m_suspicions_mutex, NULL); -We have the following invocation to initialize a cond in the Gcs_xcom_engine constructor, implemented in the gcs_xcom_notification.cc file, we have the following invocation to initialize a cond: m_wait_for_notification_cond.init(); This invocation will be replaced by: m_wait_for_notification_cond.init( key_GCS_COND_Gcs_xcom_engine_m_wait_for_notification_cond);
To enable the instrumentation of the synchronization objects used in GCS (mutexes, conditions), we resort to the corresponding instrumented functions provided by the Server's mysys library. Besides allowing us to remove the platform-specific code contained in XPlatform, this also leverages the Server's existing mechanism for enabling or disabling instrumentation, not only in build time, but also in runtime. ======================================== 1. Changes to the build process of GCS ======================================== In this WL, the building process of GCS does not need any modification, since the required changes were performed in WL#10622. The existing XCOM_STANDALONE macro will be used on GCS to distinguish if it is to be used separately from the Server. When this macro is disabled, GCS will be built using the Server's instrumented mutex and cond functions. The implementation to use when XCOM_STANDALONE is enabled is out of the scope of this WL. ====================================== 2. Changes to the source code of GCS ====================================== 2.1.Instrumentation keys ======================== Mutex and Cond instrumentation keys must be declared with the PSI_mutex_key and PSI_cond_key types, respectively, in the gcs_psi.cc file. The keys should also be declared as extern in the corresponding header, gcs_psi.h, to allow their usage throughout the code. Hence, the following mutex and cond instrumentation keys will be declared: gcs_psi.h --------- extern PSI_mutex_key key_GCS_MUTEX_Gcs_async_buffer_m_wait_for_events_mutex, key_GCS_MUTEX_Gcs_async_buffer_m_free_buffer_mutex, key_GCS_MUTEX_Gcs_suspicions_manager_m_suspicions_mutex, key_GCS_MUTEX_Gcs_xcom_group_management_m_nodes_mutex, key_GCS_MUTEX_Gcs_xcom_interface_m_wait_for_ssl_init_mutex, key_GCS_MUTEX_Gcs_xcom_engine_m_wait_for_notification_mutex, key_GCS_MUTEX_Gcs_xcom_view_change_control_m_wait_for_view_mutex, key_GCS_MUTEX_Gcs_xcom_view_change_control_m_current_view_mutex, key_GCS_MUTEX_Gcs_xcom_view_change_control_m_joining_leaving_mutex, key_GCS_MUTEX_Gcs_xcom_proxy_impl_m_lock_xcom_cursor, key_GCS_MUTEX_Gcs_xcom_proxy_impl_m_lock_xcom_ready, key_GCS_MUTEX_Gcs_xcom_proxy_impl_m_lock_xcom_comms_status, key_GCS_MUTEX_Gcs_xcom_proxy_impl_m_lock_xcom_exit, key_GCS_MUTEX_Xcom_handler_m_lock; extern PSI_cond_key key_GCS_COND_Gcs_async_buffer_m_wait_for_events_cond, key_GCS_COND_Gcs_async_buffer_m_free_buffer_cond, key_GCS_COND_Gcs_xcom_interface_m_wait_for_ssl_init_cond, key_GCS_COND_Gcs_xcom_engine_m_wait_for_notification_cond, key_GCS_COND_Gcs_xcom_view_change_control_m_wait_for_view_cond, key_GCS_COND_Gcs_xcom_proxy_impl_m_cond_xcom_ready, key_GCS_COND_Gcs_xcom_proxy_impl_m_cond_xcom_comms_status, key_GCS_COND_Gcs_xcom_proxy_impl_m_cond_xcom_exit; --------- gcs_psi.cc ---------- PSI_mutex_key key_GCS_MUTEX_Gcs_async_buffer_m_wait_for_events_mutex, key_GCS_MUTEX_Gcs_async_buffer_m_free_buffer_mutex, key_GCS_MUTEX_Gcs_suspicions_manager_m_suspicions_mutex, key_GCS_MUTEX_Gcs_xcom_group_management_m_nodes_mutex, key_GCS_MUTEX_Gcs_xcom_interface_m_wait_for_ssl_init_mutex, key_GCS_MUTEX_Gcs_xcom_engine_m_wait_for_notification_mutex, key_GCS_MUTEX_Gcs_xcom_view_change_control_m_wait_for_view_mutex, key_GCS_MUTEX_Gcs_xcom_view_change_control_m_current_view_mutex, key_GCS_MUTEX_Gcs_xcom_view_change_control_m_joining_leaving_mutex, key_GCS_MUTEX_Gcs_xcom_proxy_impl_m_lock_xcom_cursor, key_GCS_MUTEX_Gcs_xcom_proxy_impl_m_lock_xcom_ready, key_GCS_MUTEX_Gcs_xcom_proxy_impl_m_lock_xcom_comms_status, key_GCS_MUTEX_Gcs_xcom_proxy_impl_m_lock_xcom_exit, key_GCS_MUTEX_Xcom_handler_m_lock; PSI_cond_key key_GCS_COND_Gcs_async_buffer_m_wait_for_events_cond, key_GCS_COND_Gcs_async_buffer_m_free_buffer_cond, key_GCS_COND_Gcs_xcom_interface_m_wait_for_ssl_init_cond, key_GCS_COND_Gcs_xcom_engine_m_wait_for_notification_cond, key_GCS_COND_Gcs_xcom_view_change_control_m_wait_for_view_cond, key_GCS_COND_Gcs_xcom_proxy_impl_m_cond_xcom_ready, key_GCS_COND_Gcs_xcom_proxy_impl_m_cond_xcom_comms_status, key_GCS_COND_Gcs_xcom_proxy_impl_m_cond_xcom_exit; ---------- Two static arrays, one with PSI_mutex_info elements and another with PSI_cond_info elements, are declared, where each tuple contains the following data regarding a mutex or a cond: -the instrumentation key's memory address; -the instrument name; -PSI flags, which are defined in psi_base.h and could be, for instance, PSI_FLAG_SINGLETON, to indicate that the element is a singleton; -the volatility index of the instrument; -the documentation for the instrument. Concerning the registration of mutex instrumentation keys, the PSI_mutex_info element has an additional field to be filled, which concerns the volatility of the mutex. Since there are no special requirements to the volatility of mutexes, we will define it as 0, since it is the same value used in instrumented mutexes in the plugin_psi.cc file of the Group Replication plugin. gcs_psi.cc ---------- static PSI_mutex_info all_gcs_psi_mutex_keys_info[]= { {&key_GCS_MUTEX_Gcs_async_buffer_m_free_buffer_mutex, "GCS_Gcs_async_buffer::m_free_buffer_mutex", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_MUTEX_Gcs_suspicions_manager_m_suspicions_mutex, "GCS_Gcs_suspicions_manager::m_suspicions_mutex", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_MUTEX_Gcs_xcom_group_management_m_nodes_mutex, "GCS_Gcs_xcom_group_management::m_nodes_mutex", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_MUTEX_Gcs_xcom_interface_m_wait_for_ssl_init_mutex, "GCS_Gcs_xcom_interface::m_wait_for_ssl_init_mutex", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_MUTEX_Gcs_xcom_engine_m_wait_for_notification_mutex, "GCS_Gcs_xcom_engine::m_wait_for_notification_mutex", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_MUTEX_Gcs_xcom_view_change_control_m_wait_for_view_mutex, "GCS_Gcs_xcom_view_change_control::m_wait_for_view_mutex", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_MUTEX_Gcs_xcom_view_change_control_m_current_view_mutex, "GCS_Gcs_xcom_view_change_control::m_current_view_mutex", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_MUTEX_Gcs_xcom_view_change_control_m_joining_leaving_mutex, "GCS_Gcs_xcom_view_change_control::m_joining_leaving_mutex", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_MUTEX_Gcs_xcom_proxy_impl_m_lock_xcom_cursor, "GCS_Gcs_xcom_proxy_impl::m_lock_xcom_cursor", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_MUTEX_Gcs_xcom_proxy_impl_m_lock_xcom_ready, "GCS_Gcs_xcom_proxy_impl::m_lock_xcom_ready", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_MUTEX_Gcs_xcom_proxy_impl_m_lock_xcom_comms_status, "GCS_Gcs_xcom_proxy_impl::m_lock_xcom_comms_status", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_MUTEX_Gcs_xcom_proxy_impl_m_lock_xcom_exit, "GCS_Gcs_xcom_proxy_impl::m_lock_xcom_exit", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_MUTEX_Xcom_handler_m_lock, "GCS_Xcom_handler::m_lock", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME} }; static PSI_cond_info all_gcs_psi_cond_keys_info[]= { {&key_GCS_COND_Gcs_async_buffer_m_wait_for_events_cond, "GCS_Gcs_async_buffer::m_wait_for_events_cond", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_COND_Gcs_async_buffer_m_free_buffer_cond, "GCS_Gcs_async_buffer::m_free_buffer_cond", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_COND_Gcs_xcom_interface_m_wait_for_ssl_init_cond, "GCS_Gcs_xcom_interface::m_wait_for_ssl_init_cond", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_COND_Gcs_xcom_engine_m_wait_for_notification_cond, "GCS_Gcs_xcom_engine::m_wait_for_notification_cond", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_COND_Gcs_xcom_view_change_control_m_wait_for_view_cond, "GCS_Gcs_xcom_view_change_control::m_wait_for_view_cond", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_COND_Gcs_xcom_proxy_impl_m_cond_xcom_ready, "GCS_Gcs_xcom_proxy_impl::m_cond_xcom_ready", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_COND_Gcs_xcom_proxy_impl_m_cond_xcom_comms_status, "GCS_Gcs_xcom_proxy_impl::m_cond_xcom_comms_status", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, {&key_GCS_COND_Gcs_xcom_proxy_impl_m_cond_xcom_exit, "GCS_Gcs_xcom_proxy_impl::m_cond_xcom_exit", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME} }; ---------- 2.1.1 Key registration ====================== All the keys used for instrumenting mutexes and conditions must be registered during the initialization of GCS, by invoking the mysql_mutex_register and mysql_cond_register functions with a static array of PSI_mutex_info and PSI_cond_info elements, respectively. Both invocations will be performed inside the register_gcs_mutex_cond_psi_keys function, implemented in the gcs_psi.cc file. This function is executed in the initialize method of the Gcs_xcom_interface class, during the startup of GCS. All the keys are registered under the "group_rpl" category, as it refers to Group Replication, which is the Server's plugin that includes GCS. gcs_psi.h --------- /** Registers the psi keys for the mutexes and conds that will be instrumented. */ void register_gcs_mutex_cond_psi_keys(); --------- gcs_psi.cc ---------- void register_gcs_mutex_cond_psi_keys() { const char *category = "group_rpl"; int count= static_cast(array_elements(all_gcs_psi_cond_keys_info)); mysql_cond_register(category, all_gcs_psi_cond_keys_info, count); count= static_cast (array_elements(all_gcs_psi_mutex_keys_info)); mysql_mutex_register(category, all_gcs_psi_mutex_keys_info, count); } ---------- 2.2 XPlatform ============= Some of the classes in the XPlatform of GCS have code that is inspired by Server's mysys. This code will be replaced by invocations to the corresponding functions on mysys, reducing our codebase by removing duplicate code from the my_xp_cond.cc and my_xp_mutex.cc files. It will be possible to remove the large majority of the code dealing with multiple platforms, such as the following classes: My_xp_cond_pthread, My_xp_cond_win, My_xp_mutex_pthread, My_xp_mutex_win. The My_xp_cond_server and My_xp_mutex_server classes will then extend the corresponding abstract class and implement the declared methods directly. The init method of each of these code elements will have to be modified in order to receive the instrumentation key as parameter. Then, My_xp_cond_impl and My_xp_mutex_impl will extend the My_xp_cond_server and My_xp_mutex_server classes. These changes to the code can be seen in the following excerpts. my_xp_cond.h: ------------- #include "plugin/group_replication/libmysqlgcs/include/mysql/gcs/xplatform/my_xp_mutex.h" #include "plugin/group_replication/libmysqlgcs/include/mysql/gcs/xplatform/my_xp_util.h" #include "mysql/psi/mysql_cond.h" /** @class My_xp_cond Abstract class used to wrap condition for various implementations. A typical use case of cond is: @code{.cpp} My_xp_cond *cond= new My_xp_cond_impl(); cond->init(cond_PSI_key); cond->signal(); @endcode */ class My_xp_cond { public: /** Initialize cond. @param key cond instrumentation key @return success status */ virtual int init(PSI_cond_key key)= 0; /** Destroy cond. @return success status */ virtual int destroy()= 0; /** Wait for cond to be signaled during some time before unlocking mutex. @param mutex mutex to unlock @param abstime time to wait @return success status */ virtual int timed_wait(mysql_mutex_t *mutex, const struct timespec *abstime)= 0; /** Wait for cond to be signaled to unlock mutex. @param mutex mutex to unlock @return success status */ virtual int wait(mysql_mutex_t *mutex)= 0; /** Signal cond. @return success status */ virtual int signal()= 0; /** Broadcast cond. @return success status */ virtual int broadcast()= 0; /** Get reference to native cond. @return native cond */ virtual mysql_cond_t *get_native_cond()= 0; virtual ~My_xp_cond() {} }; #ifndef XCOM_STANDALONE class My_xp_cond_server : public My_xp_cond { public: explicit My_xp_cond_server(); virtual ~My_xp_cond_server(); int init(PSI_cond_key key); int destroy(); int timed_wait(mysql_mutex_t *mutex, const struct timespec *abstime); int wait(mysql_mutex_t *mutex); int signal(); int broadcast(); mysql_cond_t *get_native_cond(); protected: mysql_cond_t *m_cond; }; #endif #ifndef XCOM_STANDALONE class My_xp_cond_impl : public My_xp_cond_server #endif { public: explicit My_xp_cond_impl() {} ~My_xp_cond_impl() {} }; ------------- my_xp_cond.cc: -------------- #include "plugin/group_replication/libmysqlgcs/include/mysql/gcs/xplatform/my_xp_cond.h" #ifndef XCOM_STANDALONE My_xp_cond_server::My_xp_cond_server() :m_cond(static_cast (malloc(sizeof(*m_cond)))) {} My_xp_cond_server::~My_xp_cond_server() { free(m_cond); } int My_xp_cond_server::init(PSI_cond_key key) { return mysql_cond_init(key, m_cond); } int My_xp_cond_server::destroy() { return mysql_cond_destroy(m_cond); } int My_xp_cond_server::timed_wait(mysql_mutex_t *mutex, const struct timespec *abstime) { return mysql_cond_timedwait(m_cond, mutex, abstime); } int My_xp_cond_server::wait(mysql_mutex_t *mutex) { return mysql_cond_wait(m_cond, mutex); } int My_xp_cond_server::signal() { return mysql_cond_signal(m_cond); } int My_xp_cond_server::broadcast() { return mysql_cond_broadcast(m_cond); } mysql_cond_t *My_xp_cond_server::get_native_cond() { return m_cond; } #endif -------------- my_xp_mutex.h: -------------- #include "mysql/psi/mysql_mutex.h" /** @class My_xp_mutex Abstract class used to wrap mutex for various implementations. A typical use case is: @code{.cpp} My_xp_mutex *mutex= new My_xp_mutex_impl(); mutex->init(mutex_PSI_key, NULL); mutex->lock(); ... mutex->unlock(); @endcode */ class My_xp_mutex { public: /** Initialize mutex. @param key mutex instrumentation key @param attr mutex attributes reference @return success status */ virtual int init(PSI_mutex_key key, const native_mutexattr_t *attr)= 0; /** Destroy mutex. @return success status */ virtual int destroy()= 0; /** Lock mutex. @return success status */ virtual int lock()= 0; /** Trylock mutex. @return success status */ virtual int trylock()= 0; /** Unlock mutex. @return success status */ virtual int unlock()= 0; /** To get native mutex reference. @return native mutex pointer */ virtual mysql_mutex_t *get_native_mutex()= 0; virtual ~My_xp_mutex() {} }; #ifndef XCOM_STANDALONE class My_xp_mutex_server : public My_xp_mutex { public: explicit My_xp_mutex_server(); virtual ~My_xp_mutex_server(); int init(PSI_mutex_key key, const native_mutexattr_t *attr); int destroy(); int lock(); int trylock(); int unlock(); mysql_mutex_t *get_native_mutex(); protected: mysql_mutex_t *m_mutex; }; #endif #ifndef XCOM_STANDALONE class My_xp_mutex_impl : public My_xp_mutex_server #endif { public: explicit My_xp_mutex_impl() {} ~My_xp_mutex_impl() {} }; class My_xp_mutex_util { public: /** Initialize mutex attributes object @param attr mutex attributes reference @return success status */ static int attr_init(native_mutexattr_t *attr); /** Destroy mutex attributes object @param attr mutex attributes reference @return success status */ static int attr_destroy(native_mutexattr_t *attr); }; -------------- my_xp_mutex.cc: --------------- #include "plugin/group_replication/libmysqlgcs/include/mysql/gcs/xplatform/my_xp_mutex.h" #ifndef XCOM_STANDALONE My_xp_mutex_server::My_xp_mutex_server() :m_mutex(static_cast (malloc(sizeof(*m_mutex)))) {} My_xp_mutex_server::~My_xp_mutex_server() { free(m_mutex); } mysql_mutex_t *My_xp_mutex_server::get_native_mutex() { return m_mutex; } int My_xp_mutex_server::init(PSI_mutex_key key, const native_mutexattr_t *attr) { if (m_mutex == NULL) return -1; return mysql_mutex_init(key, m_mutex, attr); } int My_xp_mutex_server::destroy() { return mysql_mutex_destroy(m_mutex); } int My_xp_mutex_server::lock() { return mysql_mutex_lock(m_mutex); } int My_xp_mutex_server::trylock() { return mysql_mutex_trylock(m_mutex); } int My_xp_mutex_server::unlock() { return mysql_mutex_unlock(m_mutex); } #endif int My_xp_mutex_util::attr_init(native_mutexattr_t *attr) { /* On Windows there is no initialization of mutex attributes. Therefore, we simply return 0. */ #ifdef _WIN32 return 0; #else return pthread_mutexattr_init(attr); #endif } int My_xp_mutex_util::attr_destroy(native_mutexattr_t *attr) { /* On Windows there is no destruction of mutex attributes. Therefore, we simply return 0. */ #ifdef _WIN32 return 0; #else return pthread_mutexattr_destroy(attr); #endif } --------------- 2.3 Usage example ================= This WL introduces minor interface changes to GCS, namely by modifying the signatures of the init methods of My_xp_mutex and My_xp_cond to include the additional instrumentation key parameter. -Here is an example of the usage of the modified My_xp_mutex init method, since it is the only method that requires changes to enable mutex instrumentation. Until now, to initialize m_suspicions_mutex, inside the Gcs_suspicions_manager constructor, defined in the gcs_xcom_control_interface.cc file, we would use: m_suspicions_mutex.init(NULL); This will be replaced by the following code: m_suspicions_mutex.init( key_GCS_MUTEX_Gcs_suspicions_manager_m_suspicions_mutex, NULL); -To exemplify the new way of initializing a cond, we can see the current way of initializing m_wait_for_notification_cond in the Gcs_xcom_engine constructor, which is implemented in the gcs_xcom_notification.cc file: m_wait_for_notification_cond.init(); This invocation will be modified to accommodate the cond instrumentation key conveyed as parameter to the init method: m_wait_for_notification_cond.init( key_GCS_COND_Gcs_xcom_engine_m_wait_for_notification_cond); 2.4 Tests ========= The existing invocations to the init methods of My_xp_mutex and My_xp_cond, in the unit and smoke tests, must be modified through the addition of the instrumentation key parameter. Since instrumentation is not available in these cases and it is also not required, the parameter will be defined as PSI_NOT_INSTRUMENTED. To verify the correct implementation of the formal requirements of this WL, a new MTR test will be defined, where: -the registration of the instrumentation keys for mutexes and conditions will be verified in the tables setup_instruments, namely by the correspondence of a new entry per key; -the existence of 19 instances of mutexes in the mutex_instances tables, which correspond to 6 instances of the m_lock mutex of the Xcom_handler class, and one instance for each of the other 13 instrumented mutexes. -the existence of 8 instances of conds in the cond_instances table which correspond to the 8 distinct instrumented cond elements. ========================= 3. Instrumentation data ========================= When code instrumentation is enabled, the instrumentation data is inserted and, or updated in the appropriate performance schema tables in runtime. 3.1 Instances Tables ==================== The performance schema *_instances tables contain entries regarding the currently alive instances of the instrumented code elements. In the scope of this WL, we'll look more closely into the cond_instances and mutex_instances tables. -The cond_instances table lists all the instrumented conditions during the server execution. Its columns, NAME and OBJECT_INSTANCE_BEGIN, contain the instrument name associated with each instrumented condition and its memory address, respectively. -The mutex_instances table lists all the instrumented mutexes during the server execution, and it has two columns that are identical in name and content to those in the cond_instances table. It also has an additional column named LOCKED_BY_THREAD_ID, which contains the THREAD_ID of the locking thread, or NULL in case it is unlocked. 3.2 Wait Events Tables ====================== Since the instrumented mutex elements deal with waits, we'll look more closely into the performance schema wait event tables: -events_waits_current, which contains the current wait events; -events_waits_history, containing the 10 most recent wait events per thread; -events_waits_history_long, which contains the most recent 10,000 global wait events, i.e. across all threads. These three tables share the same structure, having the following columns: -THREAD_ID: ID of the thread associated with the event. -EVENT_ID: Number of the thread's current event when it starts. The THREAD_ID and EVENT_ID values combined uniquely identify the entry. -END_EVENT_ID: Set to NULL when the event starts and updated to the thread current event number when the event ends. -EVENT_NAME: The name of the instrument that produced the event, corresponding to the NAME value from the setup_instruments table. -SOURCE: Name of the source file that contains the instrumented code that produced the event, followed by file's the line number. -TIMER_START, TIMER_END, TIMER_WAIT: These columns provide timing information for the event in picoseconds. If the value of the TIMED column of the event in setup_instruments is NO, these columns will all be NULL. If the event hasn't finished, TIMER_END is the current timer value and TIMER_WAIT is the time elapsed so far (TIMER_END − TIMER_START). -SPINS: The number of spin rounds for a mutex. If the value is NULL, the code does not use spin rounds or spinning is not instrumented. -OBJECT_SCHEMA, OBJECT_NAME, OBJECT_TYPE: All are NULL for synchronization objects. -OBJECT_INSTANCE_BEGIN: Memory address of the synchronization object. -INDEX_NAME: The name of the index used, PRIMARY or NULL, in case no index was used. -NESTING_EVENT_ID: The EVENT_ID value of the event within which this event is nested. -NESTING_EVENT_TYPE: The nesting event type that can be TRANSACTION, STATEMENT, STAGE, WAIT or NULL. -OPERATION: The type of operation performed, which should contain lock for mutexes. -NUMBER_OF_BYTES: The number of bytes read or written by the operation. Not relevant for mutexes. -FLAGS: Reserved for future use. The size of the history tables can be modified in performance_schema_events_waits_history_size and performance_schema_events_waits_history_long_size. These three wait events tables can be disabled in the setup_consumers table, by switching the value of the ENABLED column to NO. 3.3 Workflow ============ When a thread tries to lock a mutex, a new entry is added in the events_waits_current table, showing that it is waiting on a mutex, in the EVENT_NAME column, and identifying the mutex in the OBJECT_INSTANCE_BEGIN column. When the thread successfully locks the mutex, the TIMER_END and TIMER_WAIT columns of that same entry are updated and the event is added to the events_waits_history and events_waits_history_long tables. The mutex_instances table is also modified, since mutex entry now shows it is owned by the thread. When the mutex is unlocked, the value of the THREAD_ID column of this entry is NULL again, showing it has no owner. When the mutex is destroyed, the corresponding row is removed from mutex_instances. The same occurs with a cond. When it is destroyed, its entry is removed from the cond_instances table. To detect bottlenecks or deadlocks between threads that involve mutexes, the following tables can be queried: -events_waits_current, where we can see what mutex a thread is waiting for; -mutex_instances, where we can find which thread currently owns a mutex. For instance, to identify events that have not yet completed and have taken longer than N picoseconds thus far, the following expression can be used in queries: SELECT * FROM performance_schema.events_waits_current WHERE END_EVENT_ID IS NULL AND TIMER_WAIT > N; For more details on these tables see: https://dev.mysql.com/doc/refman/8.0/en/performance-schema-instance-tables.html https://dev.mysql.com/doc/refman/8.0/en/cond-instances-table.html https://dev.mysql.com/doc/refman/8.0/en/mutex-instances-table.html https://dev.mysql.com/doc/refman/8.0/en/performance-schema-wait-tables.html https://dev.mysql.com/doc/refman/8.0/en/events-waits-current-table.html https://dev.mysql.com/doc/refman/8.0/en/events-waits-history-table.html https://dev.mysql.com/doc/refman/8.0/en/events-waits-history-long-table.html
Copyright (c) 2000, 2024, Oracle Corporation and/or its affiliates. All rights reserved.