Commit 554ac6f3 authored by Sergey Vojtovich's avatar Sergey Vojtovich

Allocate Session_sysvars_tracker statically

One less new/delete per connection.

Removed m_mem_flag since most allocs are thread specific. The only
exception are allocs performed during initialization.

Removed State_tracker and Session_tracker constructors as they don't make
sense anymore.

No reason to access session_sysvars_tracker via get_tracker(), so access
it directly instead.

Part of MDEV-14984 - regression in connect performance
parent a7adc2ce
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
#include "sql_plugin.h" #include "sql_plugin.h"
#include "session_tracker.h"
#include "hash.h" #include "hash.h"
#include "table.h" #include "table.h"
#include "rpl_gtid.h" #include "rpl_gtid.h"
...@@ -34,145 +32,6 @@ void State_tracker::mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name) ...@@ -34,145 +32,6 @@ void State_tracker::mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name)
} }
/**
Session_sysvars_tracker
This is a tracker class that enables & manages the tracking of session
system variables. It internally maintains a hash of user supplied variable
references and a boolean field to store if the variable was changed by the
last statement.
*/
class Session_sysvars_tracker : public State_tracker
{
struct sysvar_node_st {
sys_var *m_svar;
bool *test_load;
bool m_changed;
};
class vars_list
{
/**
Registered system variables. (@@session_track_system_variables)
A hash to store the name of all the system variables specified by the
user.
*/
HASH m_registered_sysvars;
/** Size of buffer for string representation */
size_t buffer_length;
myf m_mem_flag;
/**
If TRUE then we want to check all session variable.
*/
bool track_all;
void init()
{
my_hash_init(&m_registered_sysvars,
&my_charset_bin,
4, 0, 0, (my_hash_get_key) sysvars_get_key,
my_free, MYF(HASH_UNIQUE |
((m_mem_flag & MY_THREAD_SPECIFIC) ?
HASH_THREAD_SPECIFIC : 0)));
}
void free_hash()
{
if (my_hash_inited(&m_registered_sysvars))
{
my_hash_free(&m_registered_sysvars);
}
}
sysvar_node_st *search(const sys_var *svar)
{
return reinterpret_cast<sysvar_node_st*>(
my_hash_search(&m_registered_sysvars,
reinterpret_cast<const uchar*>(&svar),
sizeof(sys_var*)));
}
sysvar_node_st *at(ulong i)
{
DBUG_ASSERT(i < m_registered_sysvars.records);
return reinterpret_cast<sysvar_node_st*>(
my_hash_element(&m_registered_sysvars, i));
}
public:
vars_list(): buffer_length(0), track_all(false)
{
m_mem_flag= current_thd ? MY_THREAD_SPECIFIC : 0;
init();
}
size_t get_buffer_length()
{
DBUG_ASSERT(buffer_length != 0); // asked earlier then should
return buffer_length;
}
~vars_list()
{
/* free the allocated hash. */
if (my_hash_inited(&m_registered_sysvars))
{
my_hash_free(&m_registered_sysvars);
}
}
sysvar_node_st *insert_or_search(const sys_var *svar)
{
sysvar_node_st *res= search(svar);
if (!res)
{
if (track_all)
{
insert(svar);
return search(svar);
}
}
return res;
}
bool insert(const sys_var *svar);
void reinit();
void reset();
inline bool is_enabled()
{
return track_all || m_registered_sysvars.records;
}
void copy(vars_list* from, THD *thd);
bool parse_var_list(THD *thd, LEX_STRING var_list, bool throw_error,
CHARSET_INFO *char_set, bool take_mutex);
bool construct_var_list(char *buf, size_t buf_len);
bool store(THD *thd, String *buf);
};
/**
Two objects of vars_list type are maintained to manage
various operations.
*/
vars_list orig_list;
public:
size_t get_buffer_length()
{
return orig_list.get_buffer_length();
}
bool construct_var_list(char *buf, size_t buf_len)
{
return orig_list.construct_var_list(buf, buf_len);
}
bool enable(THD *thd);
bool update(THD *thd, set_var *var);
bool store(THD *thd, String *buf);
void mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name);
/* callback */
static uchar *sysvars_get_key(const char *entry, size_t *length,
my_bool not_used __attribute__((unused)));
friend bool sysvartrack_global_update(THD *thd, char *str, size_t len);
};
/* To be used in expanding the buffer. */ /* To be used in expanding the buffer. */
static const unsigned int EXTRA_ALLOC= 1024; static const unsigned int EXTRA_ALLOC= 1024;
...@@ -217,7 +76,9 @@ bool Session_sysvars_tracker::vars_list::insert(const sys_var *svar) ...@@ -217,7 +76,9 @@ bool Session_sysvars_tracker::vars_list::insert(const sys_var *svar)
{ {
sysvar_node_st *node; sysvar_node_st *node;
if (!(node= (sysvar_node_st *) my_malloc(sizeof(sysvar_node_st), if (!(node= (sysvar_node_st *) my_malloc(sizeof(sysvar_node_st),
MYF(MY_WME | m_mem_flag)))) MYF(MY_WME |
(mysqld_server_initialized ?
MY_THREAD_SPECIFIC : 0)))))
return true; return true;
node->m_svar= (sys_var *)svar; node->m_svar= (sys_var *)svar;
...@@ -511,6 +372,7 @@ bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf, ...@@ -511,6 +372,7 @@ bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf,
bool Session_sysvars_tracker::enable(THD *thd) bool Session_sysvars_tracker::enable(THD *thd)
{ {
orig_list.reinit();
mysql_mutex_lock(&LOCK_plugin); mysql_mutex_lock(&LOCK_plugin);
LEX_STRING tmp; LEX_STRING tmp;
tmp.str= global_system_variables.session_track_system_variables; tmp.str= global_system_variables.session_track_system_variables;
...@@ -519,6 +381,7 @@ bool Session_sysvars_tracker::enable(THD *thd) ...@@ -519,6 +381,7 @@ bool Session_sysvars_tracker::enable(THD *thd)
{ {
mysql_mutex_unlock(&LOCK_plugin); mysql_mutex_unlock(&LOCK_plugin);
orig_list.reinit(); orig_list.reinit();
m_enabled= false;
return true; return true;
} }
mysql_mutex_unlock(&LOCK_plugin); mysql_mutex_unlock(&LOCK_plugin);
...@@ -1330,49 +1193,6 @@ bool Session_state_change_tracker::store(THD *thd, String *buf) ...@@ -1330,49 +1193,6 @@ bool Session_state_change_tracker::store(THD *thd, String *buf)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/**
@brief Initialize session tracker objects.
*/
Session_tracker::Session_tracker()
{
/* track data ID fit into one byte in net coding */
compile_time_assert(SESSION_TRACK_always_at_the_end < 251);
/* one tracker could serv several tracking data */
compile_time_assert((uint)SESSION_TRACK_always_at_the_end >=
(uint)SESSION_TRACKER_END);
m_trackers[SESSION_SYSVARS_TRACKER]= 0;
m_trackers[CURRENT_SCHEMA_TRACKER]= &current_schema;
m_trackers[SESSION_STATE_CHANGE_TRACKER]= &state_change;
m_trackers[TRANSACTION_INFO_TRACKER]= &transaction_info;
}
/**
@brief Enables the tracker objects.
@param thd [IN] The thread handle.
@return void
*/
void Session_tracker::enable(THD *thd)
{
/*
Originally and correctly this allocation was in the constructor and
deallocation in the destructor, but in this case memory counting
system works incorrectly (for example in INSERT DELAYED thread)
*/
deinit();
m_trackers[SESSION_SYSVARS_TRACKER]=
new (std::nothrow) Session_sysvars_tracker();
for (int i= 0; i < SESSION_TRACKER_END; i++)
m_trackers[i]->enable(thd);
}
/** /**
@brief Store all change information in the specified buffer. @brief Store all change information in the specified buffer.
...@@ -1385,6 +1205,12 @@ void Session_tracker::store(THD *thd, String *buf) ...@@ -1385,6 +1205,12 @@ void Session_tracker::store(THD *thd, String *buf)
{ {
size_t start; size_t start;
/* track data ID fit into one byte in net coding */
compile_time_assert(SESSION_TRACK_always_at_the_end < 251);
/* one tracker could serv several tracking data */
compile_time_assert((uint) SESSION_TRACK_always_at_the_end >=
(uint) SESSION_TRACKER_END);
/* /*
Probably most track result will fit in 251 byte so lets made it at Probably most track result will fit in 251 byte so lets made it at
least efficient. We allocate 1 byte for length and then will move least efficient. We allocate 1 byte for length and then will move
......
...@@ -71,13 +71,7 @@ class State_tracker ...@@ -71,13 +71,7 @@ class State_tracker
bool m_changed; bool m_changed;
public: public:
/** Constructor */ virtual ~State_tracker() {}
State_tracker() : m_enabled(false), m_changed(false)
{}
/** Destructor */
virtual ~State_tracker()
{}
/** Getters */ /** Getters */
bool is_enabled() const bool is_enabled() const
...@@ -112,6 +106,130 @@ class State_tracker ...@@ -112,6 +106,130 @@ class State_tracker
}; };
/**
Session_sysvars_tracker
This is a tracker class that enables & manages the tracking of session
system variables. It internally maintains a hash of user supplied variable
references and a boolean field to store if the variable was changed by the
last statement.
*/
class Session_sysvars_tracker: public State_tracker
{
struct sysvar_node_st {
sys_var *m_svar;
bool *test_load;
bool m_changed;
};
class vars_list
{
/**
Registered system variables. (@@session_track_system_variables)
A hash to store the name of all the system variables specified by the
user.
*/
HASH m_registered_sysvars;
/** Size of buffer for string representation */
size_t buffer_length;
/**
If TRUE then we want to check all session variable.
*/
bool track_all;
void init()
{
my_hash_init(&m_registered_sysvars, &my_charset_bin, 0, 0, 0,
(my_hash_get_key) sysvars_get_key, my_free,
HASH_UNIQUE | (mysqld_server_initialized ?
HASH_THREAD_SPECIFIC : 0));
}
void free_hash()
{
DBUG_ASSERT(my_hash_inited(&m_registered_sysvars));
my_hash_free(&m_registered_sysvars);
}
sysvar_node_st *search(const sys_var *svar)
{
return reinterpret_cast<sysvar_node_st*>(
my_hash_search(&m_registered_sysvars,
reinterpret_cast<const uchar*>(&svar),
sizeof(sys_var*)));
}
sysvar_node_st *at(ulong i)
{
DBUG_ASSERT(i < m_registered_sysvars.records);
return reinterpret_cast<sysvar_node_st*>(
my_hash_element(&m_registered_sysvars, i));
}
public:
vars_list(): buffer_length(0), track_all(false) { init(); }
void deinit() { free_hash(); }
size_t get_buffer_length()
{
DBUG_ASSERT(buffer_length != 0); // asked earlier then should
return buffer_length;
}
sysvar_node_st *insert_or_search(const sys_var *svar)
{
sysvar_node_st *res= search(svar);
if (!res)
{
if (track_all)
{
insert(svar);
return search(svar);
}
}
return res;
}
bool insert(const sys_var *svar);
void reinit();
void reset();
inline bool is_enabled()
{
return track_all || m_registered_sysvars.records;
}
void copy(vars_list* from, THD *thd);
bool parse_var_list(THD *thd, LEX_STRING var_list, bool throw_error,
CHARSET_INFO *char_set, bool take_mutex);
bool construct_var_list(char *buf, size_t buf_len);
bool store(THD *thd, String *buf);
};
/**
Two objects of vars_list type are maintained to manage
various operations.
*/
vars_list orig_list;
public:
size_t get_buffer_length()
{
return orig_list.get_buffer_length();
}
bool construct_var_list(char *buf, size_t buf_len)
{
return orig_list.construct_var_list(buf, buf_len);
}
bool enable(THD *thd);
bool update(THD *thd, set_var *var);
bool store(THD *thd, String *buf);
void mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name);
void deinit() { orig_list.deinit(); }
/* callback */
static uchar *sysvars_get_key(const char *entry, size_t *length,
my_bool not_used __attribute__((unused)));
friend bool sysvartrack_global_update(THD *thd, char *str, size_t len);
};
bool sysvartrack_validate_value(THD *thd, const char *str, size_t len); bool sysvartrack_validate_value(THD *thd, const char *str, size_t len);
bool sysvartrack_global_update(THD *thd, char *str, size_t len); bool sysvartrack_global_update(THD *thd, char *str, size_t len);
uchar *sysvartrack_session_value_ptr(THD *thd, const LEX_CSTRING *base); uchar *sysvartrack_session_value_ptr(THD *thd, const LEX_CSTRING *base);
...@@ -310,18 +428,21 @@ class Session_tracker ...@@ -310,18 +428,21 @@ class Session_tracker
Current_schema_tracker current_schema; Current_schema_tracker current_schema;
Session_state_change_tracker state_change; Session_state_change_tracker state_change;
Transaction_state_tracker transaction_info; Transaction_state_tracker transaction_info;
Session_sysvars_tracker sysvars;
Session_tracker(); Session_tracker()
~Session_tracker() { deinit(); }
/* trick to make happy memory accounting system */
void deinit()
{ {
delete m_trackers[SESSION_SYSVARS_TRACKER]; m_trackers[SESSION_SYSVARS_TRACKER]= &sysvars;
m_trackers[SESSION_SYSVARS_TRACKER]= 0; m_trackers[CURRENT_SCHEMA_TRACKER]= &current_schema;
m_trackers[SESSION_STATE_CHANGE_TRACKER]= &state_change;
m_trackers[TRANSACTION_INFO_TRACKER]= &transaction_info;
} }
void enable(THD *thd); void enable(THD *thd)
{
for (int i= 0; i < SESSION_TRACKER_END; i++)
m_trackers[i]->enable(thd);
}
/** Returns the pointer to the tracker object for the specified tracker. */ /** Returns the pointer to the tracker object for the specified tracker. */
inline State_tracker *get_tracker(enum_session_tracker tracker) const inline State_tracker *get_tracker(enum_session_tracker tracker) const
......
...@@ -1016,13 +1016,13 @@ int set_var_collation_client::update(THD *thd) ...@@ -1016,13 +1016,13 @@ int set_var_collation_client::update(THD *thd)
/* Mark client collation variables as changed */ /* Mark client collation variables as changed */
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
if (thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->is_enabled()) if (thd->session_tracker.sysvars.is_enabled())
{ {
thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)-> thd->session_tracker.sysvars.
mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_client_ptr); mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_client_ptr);
thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)-> thd->session_tracker.sysvars.
mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_results_ptr); mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_results_ptr);
thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)-> thd->session_tracker.sysvars.
mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_connection_ptr); mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_connection_ptr);
} }
thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER, NULL); thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER, NULL);
......
...@@ -1661,7 +1661,7 @@ THD::~THD() ...@@ -1661,7 +1661,7 @@ THD::~THD()
/* trick to make happy memory accounting system */ /* trick to make happy memory accounting system */
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
session_tracker.deinit(); session_tracker.sysvars.deinit();
#endif //EMBEDDED_LIBRARY #endif //EMBEDDED_LIBRARY
if (status_var.local_memory_used != 0) if (status_var.local_memory_used != 0)
...@@ -7302,10 +7302,9 @@ void THD::set_last_commit_gtid(rpl_gtid &gtid) ...@@ -7302,10 +7302,9 @@ void THD::set_last_commit_gtid(rpl_gtid &gtid)
#endif #endif
m_last_commit_gtid= gtid; m_last_commit_gtid= gtid;
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
if (changed_gtid && if (changed_gtid && session_tracker.sysvars.is_enabled())
session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->is_enabled())
{ {
session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)-> session_tracker.sysvars.
mark_as_changed(this, (LEX_CSTRING*)Sys_last_gtid_ptr); mark_as_changed(this, (LEX_CSTRING*)Sys_last_gtid_ptr);
} }
#endif #endif
......
...@@ -623,10 +623,7 @@ public: ...@@ -623,10 +623,7 @@ public:
return (new_val == 0 && var->save_result.string_value.str != 0); return (new_val == 0 && var->save_result.string_value.str != 0);
} }
bool session_update(THD *thd, set_var *var) bool session_update(THD *thd, set_var *var)
{ { return thd->session_tracker.sysvars.update(thd, var); }
return thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->
update(thd, var);
}
void session_save_default(THD *thd, set_var *var) void session_save_default(THD *thd, set_var *var)
{ {
var->save_result.string_value.str= global_var(char*); var->save_result.string_value.str= global_var(char*);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment