mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-30 18:36:12 +01:00 
			
		
		
		
	 55db59f16d
			
		
	
	
	55db59f16d
	
	
	
		
			
			PFS_atomic class contains wrappers around my_atomic_* operations, which
are macros to GNU atomic operations (__atomic_*). Due to different
implementations of compilers, clang may encounter errors when compiling
on x86_32 architecture.
The following functions are replaced with C++ std::atomic type in
performance schema code base:
  - PFS_atomic::store_*()
      -> my_atomic_store*
        -> __atomic_store_n()
    => std::atomic<T>::store()
  - PFS_atomic::load_*()
      -> my_atomic_load*
        -> __atomic_load_n()
    => std::atomic<T>::load()
  - PFS_atomic::add_*()
      -> my_atomic_add*
        -> __atomic_fetch_add()
    => std::atomic<T>::fetch_add()
  - PFS_atomic::cas_*()
    -> my_atomic_cas*
      -> __atomic_compare_exchange_n()
    => std::atomic<T>::compare_exchange_strong()
and PFS_atomic class could be dropped completely.
Note that in the wrapper memory order passed to original GNU atomic
extensions are hard-coded as `__ATOMIC_SEQ_CST`, which is equivalent to
`std::memory_order_seq_cst` in C++, and is the default parameter for
std::atomic_* functions.
All new code of the whole pull request, including one or several files
that are either new files or modified ones, are contributed under the
BSD-new license. I am contributing on behalf of my employer Amazon Web
Services.
		
	
			
		
			
				
	
	
		
			327 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			327 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (c) 2010, 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_events_statements.cc
 | |
|   Events statements data structures (implementation).
 | |
| */
 | |
| 
 | |
| #include "my_global.h"
 | |
| #include "my_sys.h"
 | |
| #include "pfs_global.h"
 | |
| #include "pfs_instr_class.h"
 | |
| #include "pfs_instr.h"
 | |
| #include "pfs_account.h"
 | |
| #include "pfs_host.h"
 | |
| #include "pfs_user.h"
 | |
| #include "pfs_events_statements.h"
 | |
| #include "pfs_buffer_container.h"
 | |
| #include "pfs_builtin_memory.h"
 | |
| #include "m_string.h"
 | |
| 
 | |
| PFS_ALIGNED size_t events_statements_history_long_size= 0;
 | |
| /** Consumer flag for table EVENTS_STATEMENTS_CURRENT. */
 | |
| PFS_ALIGNED bool flag_events_statements_current= false;
 | |
| /** Consumer flag for table EVENTS_STATEMENTS_HISTORY. */
 | |
| PFS_ALIGNED bool flag_events_statements_history= false;
 | |
| /** Consumer flag for table EVENTS_STATEMENTS_HISTORY_LONG. */
 | |
| PFS_ALIGNED bool flag_events_statements_history_long= false;
 | |
| 
 | |
| /** True if EVENTS_STATEMENTS_HISTORY_LONG circular buffer is full. */
 | |
| PFS_ALIGNED bool events_statements_history_long_full= false;
 | |
| /** Index in EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */
 | |
| PFS_ALIGNED PFS_cacheline_uint32 events_statements_history_long_index;
 | |
| /** EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */
 | |
| PFS_ALIGNED PFS_events_statements *events_statements_history_long_array= NULL;
 | |
| static unsigned char *h_long_stmts_digest_token_array= NULL;
 | |
| static char *h_long_stmts_text_array= NULL;
 | |
| 
 | |
| /**
 | |
|   Initialize table EVENTS_STATEMENTS_HISTORY_LONG.
 | |
|   @param events_statements_history_long_sizing       table sizing
 | |
| */
 | |
| int init_events_statements_history_long(size_t events_statements_history_long_sizing)
 | |
| {
 | |
|   events_statements_history_long_size= events_statements_history_long_sizing;
 | |
|   events_statements_history_long_full= false;
 | |
|   events_statements_history_long_index.m_u32.store(0);
 | |
| 
 | |
|   if (events_statements_history_long_size == 0)
 | |
|     return 0;
 | |
| 
 | |
|   events_statements_history_long_array=
 | |
|     PFS_MALLOC_ARRAY(& builtin_memory_statements_history_long,
 | |
|                      events_statements_history_long_size, sizeof(PFS_events_statements),
 | |
|                      PFS_events_statements, MYF(MY_ZEROFILL));
 | |
| 
 | |
|   if (events_statements_history_long_array == NULL)
 | |
|    {
 | |
|      cleanup_events_statements_history_long();
 | |
|      return 1;
 | |
|    }
 | |
| 
 | |
|   if (pfs_max_digest_length > 0)
 | |
|   {
 | |
|     /* Size of each digest text array. */
 | |
|     size_t digest_text_size= pfs_max_digest_length * sizeof(unsigned char);
 | |
| 
 | |
|     h_long_stmts_digest_token_array=
 | |
|       PFS_MALLOC_ARRAY(& builtin_memory_statements_history_long_tokens,
 | |
|                        events_statements_history_long_size, digest_text_size,
 | |
|                        unsigned char, MYF(MY_ZEROFILL));
 | |
| 
 | |
|     if (h_long_stmts_digest_token_array == NULL)
 | |
|     {
 | |
|       cleanup_events_statements_history_long();
 | |
|       return 1;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (pfs_max_sqltext > 0)
 | |
|   {
 | |
|     /* Size of each sql text array. */
 | |
|     size_t sqltext_size= pfs_max_sqltext * sizeof(char);
 | |
| 
 | |
|     h_long_stmts_text_array=
 | |
|       PFS_MALLOC_ARRAY(& builtin_memory_statements_history_long_sqltext,
 | |
|                        events_statements_history_long_size, sqltext_size,
 | |
|                        char, MYF(MY_ZEROFILL));
 | |
| 
 | |
|     if (h_long_stmts_text_array == NULL)
 | |
|     {
 | |
|       cleanup_events_statements_history_long();
 | |
|       return 1;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (size_t index= 0; index < events_statements_history_long_size; index++)
 | |
|   {
 | |
|     events_statements_history_long_array[index].m_digest_storage.reset(h_long_stmts_digest_token_array
 | |
|                                                                        + index * pfs_max_digest_length, pfs_max_digest_length);
 | |
|     events_statements_history_long_array[index].m_sqltext= h_long_stmts_text_array + index * pfs_max_sqltext;
 | |
|   }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /** Cleanup table EVENTS_STATEMENTS_HISTORY_LONG. */
 | |
| void cleanup_events_statements_history_long(void)
 | |
| {
 | |
|   PFS_FREE_ARRAY(& builtin_memory_statements_history_long,
 | |
|                  events_statements_history_long_size,
 | |
|                  sizeof(PFS_events_statements),
 | |
|                  events_statements_history_long_array);
 | |
| 
 | |
|   PFS_FREE_ARRAY(& builtin_memory_statements_history_long_tokens,
 | |
|                  events_statements_history_long_size,
 | |
|                  (pfs_max_digest_length * sizeof(unsigned char)),
 | |
|                  h_long_stmts_digest_token_array);
 | |
| 
 | |
|   PFS_FREE_ARRAY(& builtin_memory_statements_history_long_sqltext,
 | |
|                  events_statements_history_long_size,
 | |
|                  (pfs_max_sqltext * sizeof(char)),
 | |
|                  h_long_stmts_text_array);
 | |
| 
 | |
|   events_statements_history_long_array= NULL;
 | |
|   h_long_stmts_digest_token_array= NULL;
 | |
|   h_long_stmts_text_array= NULL;
 | |
| }
 | |
| 
 | |
| inline void PFS_events_statements::copy(const PFS_events_statements &source)
 | |
| {
 | |
|   /* Copy all attributes except SQL TEXT and DIGEST */
 | |
|   memcpy((void*) this, &source, offsetof(PFS_events_statements, m_sqltext));
 | |
| 
 | |
|   /* Copy SQL TEXT */
 | |
|   int sqltext_length= source.m_sqltext_length;
 | |
| 
 | |
|   if (sqltext_length > 0)
 | |
|   {
 | |
|     memcpy(m_sqltext, source.m_sqltext, sqltext_length);
 | |
|     m_sqltext_length= sqltext_length;
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     m_sqltext_length= 0;
 | |
|   }
 | |
| 
 | |
|   /* Copy DIGEST */
 | |
|   m_digest_storage.copy(&source.m_digest_storage);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Insert a statement record in table EVENTS_STATEMENTS_HISTORY.
 | |
|   @param thread             thread that executed the wait
 | |
|   @param statement          record to insert
 | |
| */
 | |
| void insert_events_statements_history(PFS_thread *thread, PFS_events_statements *statement)
 | |
| {
 | |
|   if (unlikely(events_statements_history_per_thread == 0))
 | |
|     return;
 | |
| 
 | |
|   assert(thread->m_statements_history != NULL);
 | |
| 
 | |
|   uint index= thread->m_statements_history_index;
 | |
| 
 | |
|   /*
 | |
|     A concurrent thread executing TRUNCATE TABLE EVENTS_STATEMENTS_CURRENT
 | |
|     could alter the data that this thread is inserting,
 | |
|     causing a potential race condition.
 | |
|     We are not testing for this and insert a possibly empty record,
 | |
|     to make this thread (the writer) faster.
 | |
|     This is ok, the readers of m_statements_history will filter this out.
 | |
|   */
 | |
|   thread->m_statements_history[index].copy(*statement);
 | |
| 
 | |
|   index++;
 | |
|   if (index >= events_statements_history_per_thread)
 | |
|   {
 | |
|     index= 0;
 | |
|     thread->m_statements_history_full= true;
 | |
|   }
 | |
|   thread->m_statements_history_index= index;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Insert a statement record in table EVENTS_STATEMENTS_HISTORY_LONG.
 | |
|   @param statement              record to insert
 | |
| */
 | |
| void insert_events_statements_history_long(PFS_events_statements *statement)
 | |
| {
 | |
|   if (unlikely(events_statements_history_long_size == 0))
 | |
|     return ;
 | |
| 
 | |
|   assert(events_statements_history_long_array != NULL);
 | |
| 
 | |
|   uint index= events_statements_history_long_index.m_u32.fetch_add(1);
 | |
| 
 | |
|   index= index % events_statements_history_long_size;
 | |
|   if (index == 0)
 | |
|     events_statements_history_long_full= true;
 | |
| 
 | |
|   /* See related comment in insert_events_statements_history. */
 | |
|   events_statements_history_long_array[index].copy(*statement);
 | |
| }
 | |
| 
 | |
| static void fct_reset_events_statements_current(PFS_thread *pfs_thread)
 | |
| {
 | |
|   PFS_events_statements *pfs_stmt= & pfs_thread->m_statement_stack[0];
 | |
|   PFS_events_statements *pfs_stmt_last= pfs_stmt + statement_stack_max;
 | |
| 
 | |
|   for ( ; pfs_stmt < pfs_stmt_last; pfs_stmt++)
 | |
|     pfs_stmt->m_event.m_class= nullptr;
 | |
| }
 | |
| 
 | |
| /** Reset table EVENTS_STATEMENTS_CURRENT data. */
 | |
| void reset_events_statements_current(void)
 | |
| {
 | |
|   global_thread_container.apply_all(fct_reset_events_statements_current);
 | |
| }
 | |
| 
 | |
| static void fct_reset_events_statements_history(PFS_thread *pfs_thread)
 | |
| {
 | |
|   PFS_events_statements *pfs= pfs_thread->m_statements_history;
 | |
|   PFS_events_statements *pfs_last= pfs + events_statements_history_per_thread;
 | |
| 
 | |
|   pfs_thread->m_statements_history_index= 0;
 | |
|   pfs_thread->m_statements_history_full= false;
 | |
|   for ( ; pfs < pfs_last; pfs++)
 | |
|     pfs->m_event.m_class= nullptr;
 | |
| }
 | |
| 
 | |
| /** Reset table EVENTS_STATEMENTS_HISTORY data. */
 | |
| void reset_events_statements_history(void)
 | |
| {
 | |
|   global_thread_container.apply_all(fct_reset_events_statements_history);
 | |
| }
 | |
| 
 | |
| /** Reset table EVENTS_STATEMENTS_HISTORY_LONG data. */
 | |
| void reset_events_statements_history_long(void)
 | |
| {
 | |
|   events_statements_history_long_index.m_u32.store(0);
 | |
|   events_statements_history_long_full= false;
 | |
| 
 | |
|   PFS_events_statements *pfs= events_statements_history_long_array;
 | |
|   PFS_events_statements *pfs_last= pfs + events_statements_history_long_size;
 | |
|   for ( ; pfs < pfs_last; pfs++)
 | |
|     pfs->m_event.m_class= nullptr;
 | |
| }
 | |
| 
 | |
| static void fct_reset_events_statements_by_thread(PFS_thread *thread)
 | |
| {
 | |
|   PFS_account *account= sanitize_account(thread->m_account);
 | |
|   PFS_user *user= sanitize_user(thread->m_user);
 | |
|   PFS_host *host= sanitize_host(thread->m_host);
 | |
|   aggregate_thread_statements(thread, account, user, host);
 | |
| }
 | |
| 
 | |
| /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */
 | |
| void reset_events_statements_by_thread()
 | |
| {
 | |
|   global_thread_container.apply(fct_reset_events_statements_by_thread);
 | |
| }
 | |
| 
 | |
| static void fct_reset_events_statements_by_account(PFS_account *pfs)
 | |
| {
 | |
|   PFS_user *user= sanitize_user(pfs->m_user);
 | |
|   PFS_host *host= sanitize_host(pfs->m_host);
 | |
|   pfs->aggregate_statements(user, host);
 | |
| }
 | |
| 
 | |
| /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */
 | |
| void reset_events_statements_by_account()
 | |
| {
 | |
|   global_account_container.apply(fct_reset_events_statements_by_account);
 | |
| }
 | |
| 
 | |
| static void fct_reset_events_statements_by_user(PFS_user *pfs)
 | |
| {
 | |
|   pfs->aggregate_statements();
 | |
| }
 | |
| 
 | |
| /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME data. */
 | |
| void reset_events_statements_by_user()
 | |
| {
 | |
|   global_user_container.apply(fct_reset_events_statements_by_user);
 | |
| }
 | |
| 
 | |
| static void fct_reset_events_statements_by_host(PFS_host *pfs)
 | |
| {
 | |
|   pfs->aggregate_statements();
 | |
| }
 | |
| 
 | |
| /** Reset table EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME data. */
 | |
| void reset_events_statements_by_host()
 | |
| {
 | |
|   global_host_container.apply(fct_reset_events_statements_by_host);
 | |
| }
 | |
| 
 | |
| /** Reset table EVENTS_STATEMENTS_GLOBAL_BY_EVENT_NAME data. */
 | |
| void reset_events_statements_global()
 | |
| {
 | |
|   PFS_statement_stat *stat= global_instr_class_statements_array;
 | |
|   PFS_statement_stat *stat_last= global_instr_class_statements_array + statement_class_max;
 | |
| 
 | |
|   for ( ; stat < stat_last; stat++)
 | |
|     stat->reset();
 | |
| }
 | |
| 
 |