MDEV-33748 get rid of pthread_(get_/set_)specific, use thread_local

Apart from better performance when accessing thread local variables,
we'll get rid of things that depend on initialization/cleanup of
pthread_key_t variables.

Where appropriate, use compiler-dependent pre-C++11 thread-local
equivalents, where it makes sense, to avoid initialization check overhead
that non-static thread_local can suffer from.
This commit is contained in:
Vladislav Vaintroub 2024-06-07 16:20:10 +02:00
commit 7c5fdc9b6a
26 changed files with 95 additions and 236 deletions

View file

@ -18,7 +18,6 @@
#include <cstdint>
#endif
typedef pthread_key_t thread_local_key_t;
typedef pthread_t my_thread_handle;
typedef pthread_attr_t my_thread_attr_t;
#if defined(HAVE_PTHREAD_THREADID_NP) || defined(HAVE_GETTID) || defined(HAVE_SYS_GETTID) || defined(HAVE_GETTHRID)
@ -34,19 +33,6 @@ typedef unsigned long long my_thread_os_id_t;
#endif
#define LOCK_plugin_delete LOCK_plugin
static inline int my_create_thread_local_key(thread_local_key_t *key, void (*destructor)(void*))
{ return pthread_key_create(key, destructor); }
static inline int my_delete_thread_local_key(thread_local_key_t key)
{ return pthread_key_delete(key); }
static inline void *my_get_thread_local(thread_local_key_t key)
{ return pthread_getspecific(key); }
static inline int my_set_thread_local(thread_local_key_t key, const void *ptr)
{ return pthread_setspecific(key, ptr); }
static inline int my_thread_create(my_thread_handle *thread,
const my_thread_attr_t *attr, void *(*start_routine)(void *), void *arg)
{ return pthread_create(thread, attr, start_routine, arg); }

View file

@ -1351,24 +1351,22 @@ static inline int mysql_mutex_lock(...)
@ingroup Performance_schema_implementation
*/
thread_local_key_t THR_PFS;
thread_local_key_t THR_PFS_VG; // global_variables
thread_local_key_t THR_PFS_SV; // session_variables
thread_local_key_t THR_PFS_VBT; // variables_by_thread
thread_local_key_t THR_PFS_SG; // global_status
thread_local_key_t THR_PFS_SS; // session_status
thread_local_key_t THR_PFS_SBT; // status_by_thread
thread_local_key_t THR_PFS_SBU; // status_by_user
thread_local_key_t THR_PFS_SBH; // status_by_host
thread_local_key_t THR_PFS_SBA; // status_by_account
MY_THREAD_LOCAL void* THR_PFS_VG; // global_variables
MY_THREAD_LOCAL void* THR_PFS_SV; // session_variables
MY_THREAD_LOCAL void* THR_PFS_VBT; // variables_by_thread
MY_THREAD_LOCAL void* THR_PFS_SG; // global_status
MY_THREAD_LOCAL void* THR_PFS_SS; // session_status
MY_THREAD_LOCAL void* THR_PFS_SBT; // status_by_thread
MY_THREAD_LOCAL void* THR_PFS_SBU; // status_by_user
MY_THREAD_LOCAL void* THR_PFS_SBH; // status_by_host
MY_THREAD_LOCAL void* THR_PFS_SBA; // status_by_account
bool THR_PFS_initialized= false;
MY_THREAD_LOCAL PFS_thread* THR_PFS;
static inline PFS_thread*
my_thread_get_THR_PFS()
{
assert(THR_PFS_initialized);
PFS_thread *thread= static_cast<PFS_thread*>(my_get_thread_local(THR_PFS));
PFS_thread *thread= THR_PFS;
assert(thread == NULL || sanitize_thread(thread) != NULL);
return thread;
}
@ -1376,8 +1374,7 @@ my_thread_get_THR_PFS()
static inline void
my_thread_set_THR_PFS(PFS_thread *pfs)
{
assert(THR_PFS_initialized);
my_set_thread_local(THR_PFS, pfs);
THR_PFS= pfs;
}
/**

View file

@ -40,19 +40,18 @@
*/
extern struct PSI_bootstrap PFS_bootstrap;
/** Performance schema Thread Local Storage key. */
extern pthread_key_t THR_PFS;
extern pthread_key_t THR_PFS_VG; // global_variables
extern pthread_key_t THR_PFS_SV; // session_variables
extern pthread_key_t THR_PFS_VBT; // variables_by_thread
extern pthread_key_t THR_PFS_SG; // global_status
extern pthread_key_t THR_PFS_SS; // session_status
extern pthread_key_t THR_PFS_SBT; // status_by_thread
extern pthread_key_t THR_PFS_SBU; // status_by_user
extern pthread_key_t THR_PFS_SBA; // status_by_host
extern pthread_key_t THR_PFS_SBH; // status_by_account
struct PFS_thread;
/** True when @c THR_PFS and all other Performance Schema TLS keys are initialized. */
extern bool THR_PFS_initialized;
extern MY_THREAD_LOCAL PFS_thread* THR_PFS;
extern MY_THREAD_LOCAL void* THR_PFS_VG; // global_variables
extern MY_THREAD_LOCAL void* THR_PFS_SV; // session_variables
extern MY_THREAD_LOCAL void* THR_PFS_VBT; // variables_by_thread
extern MY_THREAD_LOCAL void* THR_PFS_SG; // global_status
extern MY_THREAD_LOCAL void* THR_PFS_SS; // session_status
extern MY_THREAD_LOCAL void* THR_PFS_SBT; // status_by_thread
extern MY_THREAD_LOCAL void* THR_PFS_SBU; // status_by_user
extern MY_THREAD_LOCAL void* THR_PFS_SBA; // status_by_host
extern MY_THREAD_LOCAL void* THR_PFS_SBH; // status_by_account
#define PSI_VOLATILITY_UNKNOWN 0
#define PSI_VOLATILITY_SESSION 1

View file

@ -146,7 +146,7 @@ bool PFS_table_context::initialize(void)
if (m_restore)
{
/* Restore context from TLS. */
PFS_table_context *context= static_cast<PFS_table_context *>(my_get_thread_local(m_thr_key));
PFS_table_context *context= static_cast<PFS_table_context *>(*m_thr_varptr);
assert(context != NULL);
if(context)
@ -160,7 +160,7 @@ bool PFS_table_context::initialize(void)
else
{
/* Check that TLS is not in use. */
PFS_table_context *context= static_cast<PFS_table_context *>(my_get_thread_local(m_thr_key));
PFS_table_context *context= static_cast<PFS_table_context *>(*m_thr_varptr);
//assert(context == NULL);
context= this;
@ -178,7 +178,7 @@ bool PFS_table_context::initialize(void)
}
/* Write to TLS. */
my_set_thread_local(m_thr_key, static_cast<void *>(context));
*m_thr_varptr=static_cast<void *>(context);
}
m_initialized= (m_map_size > 0) ? (m_map != NULL) : true;
@ -187,8 +187,8 @@ bool PFS_table_context::initialize(void)
}
/* Constructor for global or single thread tables, map size = 0. */
PFS_table_context::PFS_table_context(ulonglong current_version, bool restore, thread_local_key_t key) :
m_thr_key(key), m_current_version(current_version), m_last_version(0),
PFS_table_context::PFS_table_context(ulonglong current_version, bool restore, void** thr_var_ptr) :
m_thr_varptr(thr_var_ptr), m_current_version(current_version), m_last_version(0),
m_map(NULL), m_map_size(0),
m_restore(restore), m_initialized(false), m_last_item(0)
{
@ -196,8 +196,8 @@ PFS_table_context::PFS_table_context(ulonglong current_version, bool restore, th
}
/* Constructor for by-thread or aggregate tables, map size = max thread/user/host/account. */
PFS_table_context::PFS_table_context(ulonglong current_version, ulong map_size, bool restore, thread_local_key_t key) :
m_thr_key(key), m_current_version(current_version), m_last_version(0),
PFS_table_context::PFS_table_context(ulonglong current_version, ulong map_size, bool restore, void** thr_var_ptr) :
m_thr_varptr(thr_var_ptr), m_current_version(current_version), m_last_version(0),
m_map(NULL), m_map_size(map_size),
m_restore(restore), m_initialized(false), m_last_item(0)
{

View file

@ -47,15 +47,7 @@ using PFS_ident_table = Lex_ident_i_s_table;
*/
#include "pfs_instr_class.h"
extern pthread_key_t THR_PFS_VG; // global_variables
extern pthread_key_t THR_PFS_SV; // session_variables
extern pthread_key_t THR_PFS_VBT; // variables_by_thread
extern pthread_key_t THR_PFS_SG; // global_status
extern pthread_key_t THR_PFS_SS; // session_status
extern pthread_key_t THR_PFS_SBT; // status_by_thread
extern pthread_key_t THR_PFS_SBU; // status_by_user
extern pthread_key_t THR_PFS_SBH; // status_by_host
extern pthread_key_t THR_PFS_SBA; // status_by_account
#include "pfs.h"
class Field;
struct PFS_engine_table_share;
@ -72,8 +64,8 @@ struct time_normalizer;
class PFS_table_context
{
public:
PFS_table_context(ulonglong current_version, bool restore, pthread_key_t key);
PFS_table_context(ulonglong current_version, ulong map_size, bool restore, pthread_key_t key);
PFS_table_context(ulonglong current_version, bool restore, void** thr_var_ptr);
PFS_table_context(ulonglong current_version, ulong map_size, bool restore, void** thr_var_ptr);
~PFS_table_context(void);
bool initialize(void);
@ -83,7 +75,7 @@ public:
bool versions_match(void) { return m_last_version == m_current_version; }
void set_item(ulong n);
bool is_item_set(ulong n);
pthread_key_t m_thr_key;
void** m_thr_varptr;
private:
ulonglong m_current_version;

View file

@ -434,7 +434,7 @@ void destroy_cond(PFS_cond *pfs)
PFS_thread* PFS_thread::get_current_thread()
{
return static_cast<PFS_thread*>(my_get_thread_local(THR_PFS));
return THR_PFS;
}
void PFS_thread::reset_session_connect_attrs()

View file

@ -54,10 +54,6 @@ 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);
@ -71,40 +67,11 @@ void pre_initialize_performance_schema()
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);
@ -208,24 +175,6 @@ initialize_performance_schema(PFS_global_param *param)
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)
{
@ -324,36 +273,16 @@ void shutdown_performance_schema(void)
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;
}
THR_PFS= NULL;
THR_PFS_VG= NULL; // global_variables
THR_PFS_SV= NULL; // session_variables
THR_PFS_VBT= NULL; // variables_by_thread
THR_PFS_SG= NULL; // global_status
THR_PFS_SS= NULL; // session_status
THR_PFS_SBT= NULL; // status_by_thread
THR_PFS_SBU= NULL; // status_by_user
THR_PFS_SBH= NULL; // status_by_host
THR_PFS_SBA= NULL; // status_by_account
}
/**

View file

@ -59,7 +59,7 @@ class table_global_status_context : public PFS_table_context
{
public:
table_global_status_context(ulonglong current_version, bool restore) :
PFS_table_context(current_version, restore, THR_PFS_SG) { }
PFS_table_context(current_version, restore, &THR_PFS_SG) { }
};
/** Table PERFORMANCE_SCHEMA.GLOBAL_STATUS. */

View file

@ -47,7 +47,7 @@ class table_global_variables_context : public PFS_table_context
{
public:
table_global_variables_context(ulonglong hash_version, bool restore) :
PFS_table_context(hash_version, restore, THR_PFS_VG) {}
PFS_table_context(hash_version, restore, &THR_PFS_VG) {}
};
/**

View file

@ -61,7 +61,7 @@ class table_session_status_context : public PFS_table_context
{
public:
table_session_status_context(ulonglong current_version, bool restore) :
PFS_table_context(current_version, restore, THR_PFS_SS) { }
PFS_table_context(current_version, restore, &THR_PFS_SS) { }
};
/** Table PERFORMANCE_SCHEMA.SESSION_STATUS. */

View file

@ -47,7 +47,7 @@ class table_session_variables_context : public PFS_table_context
{
public:
table_session_variables_context(ulonglong hash_version, bool restore) :
PFS_table_context(hash_version, restore, THR_PFS_SV) {}
PFS_table_context(hash_version, restore, &THR_PFS_SV) {}
};
/**

View file

@ -95,7 +95,7 @@ class table_status_by_account_context : public PFS_table_context
{
public:
table_status_by_account_context(ulonglong current_version, bool restore) :
PFS_table_context(current_version, global_account_container.get_row_count(), restore, THR_PFS_SBH) { }
PFS_table_context(current_version, global_account_container.get_row_count(), restore, &THR_PFS_SBH) { }
};
/** Table PERFORMANCE_SCHEMA.STATUS_BY_ACCOUNT. */

View file

@ -93,7 +93,7 @@ class table_status_by_host_context : public PFS_table_context
{
public:
table_status_by_host_context(ulonglong current_version, bool restore) :
PFS_table_context(current_version, global_host_container.get_row_count(), restore, THR_PFS_SBH) { }
PFS_table_context(current_version, global_host_container.get_row_count(), restore, &THR_PFS_SBH) { }
};
/** Table PERFORMANCE_SCHEMA.STATUS_BY_HOST. */

View file

@ -91,7 +91,7 @@ class table_status_by_thread_context : public PFS_table_context
{
public:
table_status_by_thread_context(ulonglong current_version, bool restore) :
PFS_table_context(current_version, global_thread_container.get_row_count(), restore, THR_PFS_SBT) { }
PFS_table_context(current_version, global_thread_container.get_row_count(), restore, &THR_PFS_SBT) { }
};
/** Table PERFORMANCE_SCHEMA.STATUS_BY_THREAD. */

View file

@ -93,7 +93,7 @@ class table_status_by_user_context : public PFS_table_context
{
public:
table_status_by_user_context(ulonglong current_version, bool restore) :
PFS_table_context(current_version, global_user_container.get_row_count(), restore, THR_PFS_SBU) { }
PFS_table_context(current_version, global_user_container.get_row_count(), restore, &THR_PFS_SBU) { }
};
/** Table PERFORMANCE_SCHEMA.STATUS_BY_USER. */

View file

@ -92,7 +92,7 @@ class table_variables_by_thread_context : public PFS_table_context
{
public:
table_variables_by_thread_context(ulonglong hash_version, bool restore) :
PFS_table_context(hash_version, global_thread_container.get_row_count(), restore, THR_PFS_VBT) { }
PFS_table_context(hash_version, global_thread_container.get_row_count(), restore, &THR_PFS_VBT) { }
};
/** Table PERFORMANCE_SCHEMA.VARIABLES_BY_THREAD. */