mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	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.
		
	
			
		
			
				
	
	
		
			266 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			266 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* Copyright (c) 2013, 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, Suite 500, Boston, MA 02110-1335 USA */
 | 
						|
 | 
						|
/**
 | 
						|
  @file storage/perfschema/pfs_events_transactions.cc
 | 
						|
  Events transactions 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_transactions.h"
 | 
						|
#include "pfs_buffer_container.h"
 | 
						|
#include "pfs_builtin_memory.h"
 | 
						|
#include "m_string.h"
 | 
						|
 | 
						|
PFS_ALIGNED ulong events_transactions_history_long_size= 0;
 | 
						|
/** Consumer flag for table EVENTS_TRANSACTIONS_CURRENT. */
 | 
						|
PFS_ALIGNED bool flag_events_transactions_current= false;
 | 
						|
/** Consumer flag for table EVENTS_TRANSACTIONS_HISTORY. */
 | 
						|
PFS_ALIGNED bool flag_events_transactions_history= false;
 | 
						|
/** Consumer flag for table EVENTS_TRANSACTIONS_HISTORY_LONG. */
 | 
						|
PFS_ALIGNED bool flag_events_transactions_history_long= false;
 | 
						|
 | 
						|
/** True if EVENTS_TRANSACTIONS_HISTORY_LONG circular buffer is full. */
 | 
						|
PFS_ALIGNED bool events_transactions_history_long_full= false;
 | 
						|
/** Index in EVENTS_TRANSACTIONS_HISTORY_LONG circular buffer. */
 | 
						|
PFS_ALIGNED PFS_cacheline_uint32 events_transactions_history_long_index;
 | 
						|
/** EVENTS_TRANSACTIONS_HISTORY_LONG circular buffer. */
 | 
						|
PFS_ALIGNED PFS_events_transactions *events_transactions_history_long_array= NULL;
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize table EVENTS_TRANSACTIONS_HISTORY_LONG.
 | 
						|
  @param events_transactions_history_long_sizing       table sizing
 | 
						|
*/
 | 
						|
int init_events_transactions_history_long(uint events_transactions_history_long_sizing)
 | 
						|
{
 | 
						|
  events_transactions_history_long_size= events_transactions_history_long_sizing;
 | 
						|
  events_transactions_history_long_full= false;
 | 
						|
  events_transactions_history_long_index.m_u32.store(0);
 | 
						|
 | 
						|
  if (events_transactions_history_long_size == 0)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  events_transactions_history_long_array=
 | 
						|
    PFS_MALLOC_ARRAY(& builtin_memory_transactions_history_long,
 | 
						|
                     events_transactions_history_long_size,
 | 
						|
                     sizeof(PFS_events_transactions), PFS_events_transactions,
 | 
						|
                     MYF(MY_ZEROFILL));
 | 
						|
 | 
						|
  return (events_transactions_history_long_array ? 0 : 1);
 | 
						|
}
 | 
						|
 | 
						|
/** Cleanup table EVENTS_TRANSACTIONS_HISTORY_LONG. */
 | 
						|
void cleanup_events_transactions_history_long(void)
 | 
						|
{
 | 
						|
  PFS_FREE_ARRAY(& builtin_memory_transactions_history_long,
 | 
						|
                 events_transactions_history_long_size, sizeof(PFS_events_transactions),
 | 
						|
                 events_transactions_history_long_array);
 | 
						|
  events_transactions_history_long_array= NULL;
 | 
						|
}
 | 
						|
 | 
						|
static inline void copy_events_transactions(PFS_events_transactions *dest,
 | 
						|
                                      const PFS_events_transactions *source)
 | 
						|
{
 | 
						|
  memcpy(dest, source, sizeof(PFS_events_transactions));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Insert a transaction record in table EVENTS_TRANSACTIONS_HISTORY.
 | 
						|
  @param thread             thread that executed the wait
 | 
						|
  @param transaction          record to insert
 | 
						|
*/
 | 
						|
void insert_events_transactions_history(PFS_thread *thread, PFS_events_transactions *transaction)
 | 
						|
{
 | 
						|
  if (unlikely(events_transactions_history_per_thread == 0))
 | 
						|
    return;
 | 
						|
 | 
						|
  assert(thread->m_transactions_history != NULL);
 | 
						|
 | 
						|
  uint index= thread->m_transactions_history_index;
 | 
						|
 | 
						|
  /*
 | 
						|
    A concurrent thread executing TRUNCATE TABLE EVENTS_TRANSACTIONS_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_transactions_history will filter this out.
 | 
						|
  */
 | 
						|
  copy_events_transactions(&thread->m_transactions_history[index], transaction);
 | 
						|
 | 
						|
  index++;
 | 
						|
  if (index >= events_transactions_history_per_thread)
 | 
						|
  {
 | 
						|
    index= 0;
 | 
						|
    thread->m_transactions_history_full= true;
 | 
						|
  }
 | 
						|
  thread->m_transactions_history_index= index;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Insert a transaction record in table EVENTS_TRANSACTIONS_HISTORY_LONG.
 | 
						|
  @param transaction              record to insert
 | 
						|
*/
 | 
						|
void insert_events_transactions_history_long(PFS_events_transactions *transaction)
 | 
						|
{
 | 
						|
  if (unlikely(events_transactions_history_long_size == 0))
 | 
						|
    return ;
 | 
						|
 | 
						|
  assert(events_transactions_history_long_array != NULL);
 | 
						|
 | 
						|
  uint index= events_transactions_history_long_index.m_u32.fetch_add(1);
 | 
						|
 | 
						|
  index= index % events_transactions_history_long_size;
 | 
						|
  if (index == 0)
 | 
						|
    events_transactions_history_long_full= true;
 | 
						|
 | 
						|
  /* See related comment in insert_events_transactions_history. */
 | 
						|
  copy_events_transactions(&events_transactions_history_long_array[index], transaction);
 | 
						|
}
 | 
						|
 | 
						|
static void fct_reset_events_transactions_current(PFS_thread *pfs)
 | 
						|
{
 | 
						|
  pfs->m_transaction_current.m_class= NULL;
 | 
						|
}
 | 
						|
 | 
						|
/** Reset table EVENTS_TRANSACTIONS_CURRENT data. */
 | 
						|
void reset_events_transactions_current(void)
 | 
						|
{
 | 
						|
  global_thread_container.apply_all(fct_reset_events_transactions_current);
 | 
						|
}
 | 
						|
 | 
						|
static void fct_reset_events_transactions_history(PFS_thread *pfs_thread)
 | 
						|
{
 | 
						|
  PFS_events_transactions *pfs= pfs_thread->m_transactions_history;
 | 
						|
  PFS_events_transactions *pfs_last= pfs + events_transactions_history_per_thread;
 | 
						|
 | 
						|
  pfs_thread->m_transactions_history_index= 0;
 | 
						|
  pfs_thread->m_transactions_history_full= false;
 | 
						|
  for ( ; pfs < pfs_last; pfs++)
 | 
						|
    pfs->m_class= NULL;
 | 
						|
}
 | 
						|
 | 
						|
/** Reset table EVENTS_TRANSACTIONS_HISTORY data. */
 | 
						|
void reset_events_transactions_history(void)
 | 
						|
{
 | 
						|
  global_thread_container.apply_all(fct_reset_events_transactions_history);
 | 
						|
}
 | 
						|
 | 
						|
/** Reset table EVENTS_TRANSACTIONS_HISTORY_LONG data. */
 | 
						|
void reset_events_transactions_history_long(void)
 | 
						|
{
 | 
						|
  events_transactions_history_long_index.m_u32.store(0);
 | 
						|
  events_transactions_history_long_full= false;
 | 
						|
 | 
						|
  PFS_events_transactions *pfs= events_transactions_history_long_array;
 | 
						|
  PFS_events_transactions *pfs_last= pfs + events_transactions_history_long_size;
 | 
						|
  for ( ; pfs < pfs_last; pfs++)
 | 
						|
    pfs->m_class= NULL;
 | 
						|
}
 | 
						|
 | 
						|
static void fct_reset_events_transactions_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_transactions(thread, account, user, host);
 | 
						|
}
 | 
						|
 | 
						|
/** Reset table EVENTS_TRANSACTIONS_SUMMARY_BY_THREAD_BY_EVENT_NAME data. */
 | 
						|
void reset_events_transactions_by_thread()
 | 
						|
{
 | 
						|
  global_thread_container.apply(fct_reset_events_transactions_by_thread);
 | 
						|
}
 | 
						|
 | 
						|
static void fct_reset_events_transactions_by_account(PFS_account *pfs)
 | 
						|
{
 | 
						|
  PFS_user *user= sanitize_user(pfs->m_user);
 | 
						|
  PFS_host *host= sanitize_host(pfs->m_host);
 | 
						|
  pfs->aggregate_transactions(user, host);
 | 
						|
}
 | 
						|
 | 
						|
/** Reset table EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME data. */
 | 
						|
void reset_events_transactions_by_account()
 | 
						|
{
 | 
						|
  global_account_container.apply(fct_reset_events_transactions_by_account);
 | 
						|
}
 | 
						|
 | 
						|
static void fct_reset_events_transactions_by_user(PFS_user *pfs)
 | 
						|
{
 | 
						|
  pfs->aggregate_transactions();
 | 
						|
}
 | 
						|
 | 
						|
/** Reset table EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME data. */
 | 
						|
void reset_events_transactions_by_user()
 | 
						|
{
 | 
						|
  global_user_container.apply(fct_reset_events_transactions_by_user);
 | 
						|
}
 | 
						|
 | 
						|
static void fct_reset_events_transactions_by_host(PFS_host *pfs)
 | 
						|
{
 | 
						|
  pfs->aggregate_transactions();
 | 
						|
}
 | 
						|
 | 
						|
/** Reset table EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME data. */
 | 
						|
void reset_events_transactions_by_host()
 | 
						|
{
 | 
						|
  global_host_container.apply(fct_reset_events_transactions_by_host);
 | 
						|
}
 | 
						|
 | 
						|
/** Reset table EVENTS_TRANSACTIONS_GLOBAL_BY_EVENT_NAME data. */
 | 
						|
void reset_events_transactions_global()
 | 
						|
{
 | 
						|
  global_transaction_stat.reset();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if the XID consists of printable characters, ASCII 32 - 127.
 | 
						|
  @param xid     XID structure
 | 
						|
  @param offset  offset into XID.data[]
 | 
						|
  @param length  number of bytes to process
 | 
						|
  @return true if all bytes are in printable range
 | 
						|
*/
 | 
						|
bool xid_printable(PSI_xid *xid, size_t offset, size_t length)
 | 
						|
{
 | 
						|
  if (xid->is_null())
 | 
						|
    return false;
 | 
						|
 | 
						|
  assert(offset + length <= MYSQL_XIDDATASIZE);
 | 
						|
 | 
						|
  unsigned char *c= (unsigned char*)&xid->data + offset;
 | 
						|
 | 
						|
  for (size_t i= 0; i < length; i++, c++)
 | 
						|
  {
 | 
						|
    if(*c < 32 || *c > 127)
 | 
						|
      return false;
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 |