mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 19:06:14 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			448 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			448 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (c) 2008, 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,
 | |
|   51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
 | |
| 
 | |
| /**
 | |
|   @file storage/perfschema/pfs_server.cc
 | |
|   Private interface for the server (implementation).
 | |
| */
 | |
| 
 | |
| #include "my_global.h"
 | |
| #include "my_sys.h"
 | |
| #include "mysys_err.h"
 | |
| #include "pfs_server.h"
 | |
| #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"
 | |
| #include "pfs_host.h"
 | |
| #include "pfs_user.h"
 | |
| #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;
 | |
| 
 | |
| PFS_table_stat PFS_table_stat::g_reset_template;
 | |
| 
 | |
| C_MODE_START
 | |
| static void destroy_pfs_thread(void *key);
 | |
| C_MODE_END
 | |
| 
 | |
| static void cleanup_performance_schema(void);
 | |
| void cleanup_instrument_config(void);
 | |
| 
 | |
| 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();
 | |
| 
 | |
|   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;
 | |
| }
 | |
| 
 | |
| struct PSI_bootstrap*
 | |
| initialize_performance_schema(PFS_global_param *param)
 | |
| {
 | |
|   if (!THR_PFS_initialized)
 | |
|   {
 | |
|     /* Pre-initialization failed. */
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   pfs_enabled= param->m_enabled;
 | |
| 
 | |
|   pfs_automated_sizing(param);
 | |
|   init_timers();
 | |
|   init_event_name_sizing(param);
 | |
|   register_global_classes();
 | |
| 
 | |
|   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) ||
 | |
|       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))
 | |
|   {
 | |
|     /*
 | |
|       The performance schema initialization failed.
 | |
|       Free the memory used, and disable the instrumentation.
 | |
|     */
 | |
|     cleanup_performance_schema();
 | |
|     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;
 | |
| 
 | |
|   if (param->m_enabled)
 | |
|   {
 | |
|     install_default_setup(&PFS_bootstrap);
 | |
|     return &PFS_bootstrap;
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static void destroy_pfs_thread(void *key)
 | |
| {
 | |
|   PFS_thread* pfs= reinterpret_cast<PFS_thread*> (key);
 | |
|   assert(pfs);
 | |
|   /*
 | |
|     This automatic cleanup is a last resort and best effort to avoid leaks,
 | |
|     and may not work on windows due to the implementation of pthread_key_create().
 | |
|     Please either use:
 | |
|     - my_thread_end()
 | |
|     - or PSI_server->delete_current_thread()
 | |
|     in the instrumented code, to explicitly cleanup the instrumentation.
 | |
| 
 | |
|     Avoid invalid writes when the main() thread completes after shutdown:
 | |
|     the memory pointed by pfs is already released.
 | |
|   */
 | |
|   if (pfs_initialized)
 | |
|     destroy_thread(pfs);
 | |
| }
 | |
| 
 | |
| static void cleanup_performance_schema(void)
 | |
| {
 | |
|   /*
 | |
|     my.cnf options
 | |
|   */
 | |
| 
 | |
|   cleanup_instrument_config();
 | |
| 
 | |
|   /*
 | |
|     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_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();
 | |
|   /*
 | |
|     Be careful to not delete un-initialized keys,
 | |
|     this would affect key 0, which is THR_KEY_mysys,
 | |
|   */
 | |
|   if (THR_PFS_initialized)
 | |
|   {
 | |
|     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;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize the dynamic array used to hold PFS_INSTRUMENT configuration
 | |
|   options.
 | |
| */
 | |
| void init_pfs_instrument_array()
 | |
| {
 | |
|   pfs_instr_config_array= new Pfs_instr_config_array((PSI_memory_key)PSI_NOT_INSTRUMENTED);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Deallocate the PFS_INSTRUMENT array.
 | |
| */
 | |
| void cleanup_instrument_config()
 | |
| {
 | |
|   if (pfs_instr_config_array != NULL)
 | |
|   {
 | |
|     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;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Process one performance_schema_instrument configuration string. Isolate the
 | |
|   instrument name, evaluate the option value, and store them in a dynamic array.
 | |
|   Return 'false' for success, 'true' for error.
 | |
| 
 | |
|   @param name    Instrument name
 | |
|   @param value   Configuration option: 'on', 'off', etc.
 | |
|   @return 0 for success, non zero for errors
 | |
| */
 | |
| 
 | |
| int add_pfs_instr_to_array(const char* name, const char* value)
 | |
| {
 | |
|   size_t name_length= strlen(name);
 | |
|   size_t value_length= strlen(value);
 | |
| 
 | |
|   /* Allocate structure plus string buffers plus null terminators */
 | |
|   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"))
 | |
|   {
 | |
|     e->m_enabled= true;
 | |
|     e->m_timed= false;
 | |
|   }
 | |
|   else
 | |
|   if (!my_strcasecmp(&my_charset_latin1, value, "true") ||
 | |
|       !my_strcasecmp(&my_charset_latin1, value, "on") ||
 | |
|       !my_strcasecmp(&my_charset_latin1, value, "1") ||
 | |
|       !my_strcasecmp(&my_charset_latin1, value, "yes"))
 | |
|   {
 | |
|     e->m_enabled= true;
 | |
|     e->m_timed= true;
 | |
|   }
 | |
|   else
 | |
|   if (!my_strcasecmp(&my_charset_latin1, value, "false") ||
 | |
|       !my_strcasecmp(&my_charset_latin1, value, "off") ||
 | |
|       !my_strcasecmp(&my_charset_latin1, value, "0") ||
 | |
|       !my_strcasecmp(&my_charset_latin1, value, "no"))
 | |
|   {
 | |
|     e->m_enabled= false;
 | |
|     e->m_timed= false;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     my_free(e);
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   /* Add to the array of default startup options */
 | |
|   if (pfs_instr_config_array->push(e))
 | |
|   {
 | |
|     my_free(e);
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   return 0;
 | |
| }
 | 
