mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +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;
 | 
						|
}
 |