1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Move all kill mutex protection to LOCK_thd_kill

LOCK_thd_data was used to protect both THD data and
ensure that the THD is not deleted while it was in use

This patch moves the THD delete protection to LOCK_thd_kill,
which already protects the THD for kill.

The benefits are:
- More well defined what LOCK_thd_data protects
- LOCK_thd_data usage is now much simpler and easier to verify
- Less chance of deadlocks in SHOW PROCESS LIST as there is less
  chance of interactions between mutexes
- Remove not needed LOCK_thread_count from
  thd_get_error_context_description()
- Fewer mutex taken for thd->awake()

Other things:
- Don't take mysys->var mutex in show processlist to check if thread
  is kill marked
- thd->awake() now automatically takes the LOCK_thd_kill mutex
  (Simplifies code)
- Apc uses LOCK_thd_kill instead of LOCK_thd_data
This commit is contained in:
Monty
2017-12-07 21:28:00 +02:00
parent 3574f9c7bc
commit c2118a08b1
15 changed files with 109 additions and 120 deletions

View File

@ -555,8 +555,6 @@ char *thd_get_error_context_description(THD *thd, char *buffer,
char header[256];
int len;
mysql_mutex_lock(&LOCK_thread_count);
/*
The pointers thd->query and thd->proc_info might change since they are
being modified concurrently. This is acceptable for proc_info since its
@ -612,7 +610,6 @@ char *thd_get_error_context_description(THD *thd, char *buffer,
}
mysql_mutex_unlock(&thd->LOCK_thd_data);
}
mysql_mutex_unlock(&LOCK_thread_count);
if (str.c_ptr_safe() == buffer)
return buffer;
@ -704,10 +701,8 @@ handle_condition(THD *thd,
extern "C" void thd_kill_timeout(THD* thd)
{
thd->status_var.max_statement_time_exceeded++;
mysql_mutex_lock(&thd->LOCK_thd_data);
/* Kill queries that can't cause data corruptions */
thd->awake(KILL_TIMEOUT);
mysql_mutex_unlock(&thd->LOCK_thd_data);
}
@ -1363,7 +1358,7 @@ void THD::init(void)
session_tracker.enable(this);
#endif //EMBEDDED_LIBRARY
apc_target.init(&LOCK_thd_data);
apc_target.init(&LOCK_thd_kill);
DBUG_VOID_RETURN;
}
@ -1627,9 +1622,13 @@ THD::~THD()
if (!status_in_global)
add_status_to_global();
/* Ensure that no one is using THD */
mysql_mutex_lock(&LOCK_thd_data);
mysql_mutex_unlock(&LOCK_thd_data);
/*
Other threads may have a lock on LOCK_thd_kill to ensure that this
THD is not deleted while they access it. The following mutex_lock
ensures that no one else is using this THD and it's now safe to delete
*/
mysql_mutex_lock(&LOCK_thd_kill);
mysql_mutex_unlock(&LOCK_thd_kill);
#ifdef WITH_WSREP
mysql_mutex_lock(&LOCK_wsrep_thd);
@ -1802,17 +1801,17 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
This is normally called from another thread's THD object.
@note Do always call this while holding LOCK_thd_data.
@note Do always call this while holding LOCK_thd_kill.
NOT_KILLED is used to awake a thread for a slave
*/
void THD::awake(killed_state state_to_set)
void THD::awake_no_mutex(killed_state state_to_set)
{
DBUG_ENTER("THD::awake");
DBUG_PRINT("enter", ("this: %p current_thd: %p state: %d",
this, current_thd, (int) state_to_set));
THD_CHECK_SENTRY(this);
mysql_mutex_assert_owner(&LOCK_thd_data);
mysql_mutex_assert_owner(&LOCK_thd_kill);
print_aborted_warning(3, "KILLED");
@ -1823,8 +1822,6 @@ void THD::awake(killed_state state_to_set)
if (killed >= KILL_CONNECTION)
state_to_set= killed;
/* Set the 'killed' flag of 'this', which is the target THD object. */
mysql_mutex_lock(&LOCK_thd_kill);
set_killed_no_mutex(state_to_set);
if (state_to_set >= KILL_CONNECTION || state_to_set == NOT_KILLED)
@ -1911,7 +1908,6 @@ void THD::awake(killed_state state_to_set)
}
mysql_mutex_unlock(&mysys_var->mutex);
}
mysql_mutex_unlock(&LOCK_thd_kill);
DBUG_VOID_RETURN;
}
@ -1927,10 +1923,10 @@ void THD::disconnect()
{
Vio *vio= NULL;
mysql_mutex_lock(&LOCK_thd_data);
set_killed(KILL_CONNECTION);
mysql_mutex_lock(&LOCK_thd_data);
#ifdef SIGNAL_WITH_VIO_CLOSE
/*
Since a active vio might might have not been set yet, in
@ -1963,9 +1959,9 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
{
/* This code is similar to kill_delayed_threads() */
DBUG_PRINT("info", ("kill delayed thread"));
mysql_mutex_lock(&in_use->LOCK_thd_data);
mysql_mutex_lock(&in_use->LOCK_thd_kill);
if (in_use->killed < KILL_CONNECTION)
in_use->set_killed(KILL_CONNECTION);
in_use->set_killed_no_mutex(KILL_CONNECTION);
if (in_use->mysys_var)
{
mysql_mutex_lock(&in_use->mysys_var->mutex);
@ -1976,7 +1972,7 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
in_use->mysys_var->abort= 1;
mysql_mutex_unlock(&in_use->mysys_var->mutex);
}
mysql_mutex_unlock(&in_use->LOCK_thd_data);
mysql_mutex_unlock(&in_use->LOCK_thd_kill);
signalled= TRUE;
}
@ -2084,7 +2080,7 @@ bool THD::store_globals()
return 1;
/*
mysys_var is concurrently readable by a killer thread.
It is protected by LOCK_thd_data, it is not needed to lock while the
It is protected by LOCK_thd_kill, it is not needed to lock while the
pointer is changing from NULL not non-NULL. If the kill thread reads
NULL it doesn't refer to anything, but if it is non-NULL we need to
ensure that the thread doesn't proceed to assign another thread to
@ -2135,9 +2131,9 @@ bool THD::store_globals()
void THD::reset_globals()
{
mysql_mutex_lock(&LOCK_thd_data);
mysql_mutex_lock(&LOCK_thd_kill);
mysys_var= 0;
mysql_mutex_unlock(&LOCK_thd_data);
mysql_mutex_unlock(&LOCK_thd_kill);
/* Undocking the thread specific data. */
set_current_thd(0);
@ -5429,9 +5425,9 @@ void THD::set_query_and_id(char *query_arg, uint32 query_length_arg,
/** Assign a new value to thd->mysys_var. */
void THD::set_mysys_var(struct st_my_thread_var *new_mysys_var)
{
mysql_mutex_lock(&LOCK_thd_data);
mysql_mutex_lock(&LOCK_thd_kill);
mysys_var= new_mysys_var;
mysql_mutex_unlock(&LOCK_thd_data);
mysql_mutex_unlock(&LOCK_thd_kill);
}
/**