mirror of
https://github.com/MariaDB/server.git
synced 2025-07-18 23:03:28 +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:
@ -125,7 +125,7 @@ relative_event_id relative_end_event_id event_name comment nesting_event_type re
|
||||
15 15 stage/sql/Starting cleanup (stage) STATEMENT 0
|
||||
16 16 stage/sql/Freeing items (stage) STATEMENT 0
|
||||
17 17 wait/io/socket/sql/client_connection send STATEMENT 0
|
||||
18 18 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 0
|
||||
18 18 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 0
|
||||
19 20 stage/sql/Reset for next command (stage) STATEMENT 0
|
||||
20 20 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 19
|
||||
21 21 idle idle NULL NULL
|
||||
@ -147,7 +147,7 @@ relative_event_id relative_end_event_id event_name comment nesting_event_type re
|
||||
37 37 stage/sql/Starting cleanup (stage) STATEMENT 22
|
||||
38 38 stage/sql/Freeing items (stage) STATEMENT 22
|
||||
39 39 wait/io/socket/sql/client_connection send STATEMENT 22
|
||||
40 40 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 22
|
||||
40 40 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 22
|
||||
41 42 stage/sql/Reset for next command (stage) STATEMENT 22
|
||||
42 42 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 41
|
||||
43 43 idle idle NULL NULL
|
||||
@ -169,7 +169,7 @@ relative_event_id relative_end_event_id event_name comment nesting_event_type re
|
||||
59 59 stage/sql/Starting cleanup (stage) STATEMENT 44
|
||||
60 60 stage/sql/Freeing items (stage) STATEMENT 44
|
||||
61 61 wait/io/socket/sql/client_connection send STATEMENT 44
|
||||
62 62 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 44
|
||||
62 62 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 44
|
||||
63 64 stage/sql/Reset for next command (stage) STATEMENT 44
|
||||
64 64 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 63
|
||||
65 65 idle idle NULL NULL
|
||||
@ -194,7 +194,7 @@ select "With a third part to make things complete" as payload NULL NULL
|
||||
82 82 stage/sql/Starting cleanup (stage) STATEMENT 66
|
||||
83 85 stage/sql/Freeing items (stage) STATEMENT 66
|
||||
84 84 wait/io/socket/sql/client_connection send STAGE 83
|
||||
85 85 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 83
|
||||
85 85 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 83
|
||||
86 103 statement/sql/select select "And this is the second part of a multi query" as payload;
|
||||
select "With a third part to make things complete" as payload NULL NULL
|
||||
87 89 stage/sql/Init (stage) STATEMENT 86
|
||||
@ -213,7 +213,7 @@ select "With a third part to make things complete" as payload NULL NULL
|
||||
100 100 stage/sql/Starting cleanup (stage) STATEMENT 86
|
||||
101 103 stage/sql/Freeing items (stage) STATEMENT 86
|
||||
102 102 wait/io/socket/sql/client_connection send STAGE 101
|
||||
103 103 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 101
|
||||
103 103 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 101
|
||||
104 122 statement/sql/select select "With a third part to make things complete" as payload NULL NULL
|
||||
105 106 stage/sql/Init (stage) STATEMENT 104
|
||||
106 106 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 105
|
||||
@ -230,7 +230,7 @@ select "With a third part to make things complete" as payload NULL NULL
|
||||
117 117 stage/sql/Starting cleanup (stage) STATEMENT 104
|
||||
118 118 stage/sql/Freeing items (stage) STATEMENT 104
|
||||
119 119 wait/io/socket/sql/client_connection send STATEMENT 104
|
||||
120 120 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 104
|
||||
120 120 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 104
|
||||
121 122 stage/sql/Reset for next command (stage) STATEMENT 104
|
||||
122 122 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 121
|
||||
123 123 idle idle NULL NULL
|
||||
@ -252,7 +252,7 @@ select "With a third part to make things complete" as payload NULL NULL
|
||||
139 139 stage/sql/Starting cleanup (stage) STATEMENT 124
|
||||
140 140 stage/sql/Freeing items (stage) STATEMENT 124
|
||||
141 141 wait/io/socket/sql/client_connection send STATEMENT 124
|
||||
142 142 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 124
|
||||
142 142 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STATEMENT 124
|
||||
143 144 stage/sql/Reset for next command (stage) STATEMENT 124
|
||||
144 144 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 143
|
||||
disconnect con1;
|
||||
|
@ -39,6 +39,7 @@ update performance_schema.setup_instruments set enabled='YES', timed='YES'
|
||||
'wait/io/socket/sql/client_connection',
|
||||
'wait/synch/rwlock/sql/LOCK_grant',
|
||||
'wait/synch/mutex/sql/THD::LOCK_thd_data',
|
||||
'wait/synch/mutex/sql/THD::LOCK_thd_kill',
|
||||
'wait/io/file/sql/query_log');
|
||||
|
||||
update performance_schema.setup_instruments set enabled='YES', timed='YES'
|
||||
|
@ -648,14 +648,11 @@ Event_scheduler::stop()
|
||||
state= STOPPING;
|
||||
DBUG_PRINT("info", ("Scheduler thread has id %lu",
|
||||
(ulong) scheduler_thd->thread_id));
|
||||
/* Lock from delete */
|
||||
mysql_mutex_lock(&scheduler_thd->LOCK_thd_data);
|
||||
/* This will wake up the thread if it waits on Queue's conditional */
|
||||
sql_print_information("Event Scheduler: Killing the scheduler thread, "
|
||||
"thread id %lu",
|
||||
(ulong) scheduler_thd->thread_id);
|
||||
scheduler_thd->awake(KILL_CONNECTION);
|
||||
mysql_mutex_unlock(&scheduler_thd->LOCK_thd_data);
|
||||
|
||||
/* thd could be 0x0, when shutting down */
|
||||
sql_print_information("Event Scheduler: "
|
||||
|
@ -34,7 +34,7 @@
|
||||
void Apc_target::init(mysql_mutex_t *target_mutex)
|
||||
{
|
||||
DBUG_ASSERT(!enabled);
|
||||
LOCK_thd_data_ptr= target_mutex;
|
||||
LOCK_thd_kill_ptr= target_mutex;
|
||||
#ifndef DBUG_OFF
|
||||
n_calls_processed= 0;
|
||||
#endif
|
||||
@ -45,7 +45,7 @@ void Apc_target::init(mysql_mutex_t *target_mutex)
|
||||
|
||||
void Apc_target::enqueue_request(Call_request *qe)
|
||||
{
|
||||
mysql_mutex_assert_owner(LOCK_thd_data_ptr);
|
||||
mysql_mutex_assert_owner(LOCK_thd_kill_ptr);
|
||||
if (apc_calls)
|
||||
{
|
||||
Call_request *after= apc_calls->prev;
|
||||
@ -71,7 +71,7 @@ void Apc_target::enqueue_request(Call_request *qe)
|
||||
|
||||
void Apc_target::dequeue_request(Call_request *qe)
|
||||
{
|
||||
mysql_mutex_assert_owner(LOCK_thd_data_ptr);
|
||||
mysql_mutex_assert_owner(LOCK_thd_kill_ptr);
|
||||
if (apc_calls == qe)
|
||||
{
|
||||
if ((apc_calls= apc_calls->next) == qe)
|
||||
@ -145,14 +145,14 @@ bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call,
|
||||
|
||||
int wait_res= 0;
|
||||
PSI_stage_info old_stage;
|
||||
caller_thd->ENTER_COND(&apc_request.COND_request, LOCK_thd_data_ptr,
|
||||
caller_thd->ENTER_COND(&apc_request.COND_request, LOCK_thd_kill_ptr,
|
||||
&stage_show_explain, &old_stage);
|
||||
/* todo: how about processing other errors here? */
|
||||
while (!apc_request.processed && (wait_res != ETIMEDOUT))
|
||||
{
|
||||
/* We own LOCK_thd_data_ptr */
|
||||
/* We own LOCK_thd_kill_ptr */
|
||||
wait_res= mysql_cond_timedwait(&apc_request.COND_request,
|
||||
LOCK_thd_data_ptr, &abstime);
|
||||
LOCK_thd_kill_ptr, &abstime);
|
||||
// &apc_request.LOCK_request, &abstime);
|
||||
if (caller_thd->killed)
|
||||
break;
|
||||
@ -163,7 +163,7 @@ bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call,
|
||||
/*
|
||||
The wait has timed out, or this thread was KILLed.
|
||||
Remove the request from the queue (ok to do because we own
|
||||
LOCK_thd_data_ptr)
|
||||
LOCK_thd_kill_ptr)
|
||||
*/
|
||||
apc_request.processed= TRUE;
|
||||
dequeue_request(&apc_request);
|
||||
@ -176,7 +176,7 @@ bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call,
|
||||
res= FALSE;
|
||||
}
|
||||
/*
|
||||
exit_cond() will call mysql_mutex_unlock(LOCK_thd_data_ptr) for us:
|
||||
exit_cond() will call mysql_mutex_unlock(LOCK_thd_kill_ptr) for us:
|
||||
*/
|
||||
caller_thd->EXIT_COND(&old_stage);
|
||||
|
||||
@ -185,7 +185,7 @@ bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call,
|
||||
}
|
||||
else
|
||||
{
|
||||
mysql_mutex_unlock(LOCK_thd_data_ptr);
|
||||
mysql_mutex_unlock(LOCK_thd_kill_ptr);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -202,11 +202,11 @@ void Apc_target::process_apc_requests()
|
||||
{
|
||||
Call_request *request;
|
||||
|
||||
mysql_mutex_lock(LOCK_thd_data_ptr);
|
||||
mysql_mutex_lock(LOCK_thd_kill_ptr);
|
||||
if (!(request= get_first_in_queue()))
|
||||
{
|
||||
/* No requests in the queue */
|
||||
mysql_mutex_unlock(LOCK_thd_data_ptr);
|
||||
mysql_mutex_unlock(LOCK_thd_kill_ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -225,7 +225,7 @@ void Apc_target::process_apc_requests()
|
||||
n_calls_processed++;
|
||||
#endif
|
||||
mysql_cond_signal(&request->COND_request);
|
||||
mysql_mutex_unlock(LOCK_thd_data_ptr);
|
||||
mysql_mutex_unlock(LOCK_thd_kill_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ class THD;
|
||||
*/
|
||||
class Apc_target
|
||||
{
|
||||
mysql_mutex_t *LOCK_thd_data_ptr;
|
||||
mysql_mutex_t *LOCK_thd_kill_ptr;
|
||||
public:
|
||||
Apc_target() : enabled(0), apc_calls(NULL) {}
|
||||
~Apc_target() { DBUG_ASSERT(!enabled && !apc_calls);}
|
||||
@ -66,9 +66,9 @@ public:
|
||||
void disable()
|
||||
{
|
||||
DBUG_ASSERT(enabled);
|
||||
mysql_mutex_lock(LOCK_thd_data_ptr);
|
||||
mysql_mutex_lock(LOCK_thd_kill_ptr);
|
||||
bool process= !--enabled && have_apc_requests();
|
||||
mysql_mutex_unlock(LOCK_thd_data_ptr);
|
||||
mysql_mutex_unlock(LOCK_thd_kill_ptr);
|
||||
if (unlikely(process))
|
||||
process_apc_requests();
|
||||
}
|
||||
|
@ -1704,7 +1704,7 @@ static void close_connections(void)
|
||||
#endif
|
||||
tmp->set_killed(KILL_SERVER_HARD);
|
||||
MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (tmp));
|
||||
mysql_mutex_lock(&tmp->LOCK_thd_data);
|
||||
mysql_mutex_lock(&tmp->LOCK_thd_kill);
|
||||
if (tmp->mysys_var)
|
||||
{
|
||||
tmp->mysys_var->abort=1;
|
||||
@ -1727,7 +1727,7 @@ static void close_connections(void)
|
||||
}
|
||||
mysql_mutex_unlock(&tmp->mysys_var->mutex);
|
||||
}
|
||||
mysql_mutex_unlock(&tmp->LOCK_thd_data);
|
||||
mysql_mutex_unlock(&tmp->LOCK_thd_kill);
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_thread_count); // For unlink from list
|
||||
|
||||
|
@ -343,9 +343,7 @@ handle_slave_background(void *arg __attribute__((unused)))
|
||||
THD *to_kill= p->to_kill;
|
||||
kill_list= p->next;
|
||||
|
||||
mysql_mutex_lock(&to_kill->LOCK_thd_data);
|
||||
to_kill->awake(KILL_CONNECTION);
|
||||
mysql_mutex_unlock(&to_kill->LOCK_thd_data);
|
||||
mysql_mutex_lock(&to_kill->LOCK_wakeup_ready);
|
||||
to_kill->rgi_slave->killed_for_retry=
|
||||
rpl_group_info::RETRY_KILL_KILLED;
|
||||
@ -856,7 +854,7 @@ terminate_slave_thread(THD *thd,
|
||||
int error __attribute__((unused));
|
||||
DBUG_PRINT("loop", ("killing slave thread"));
|
||||
|
||||
mysql_mutex_lock(&thd->LOCK_thd_data);
|
||||
mysql_mutex_lock(&thd->LOCK_thd_kill);
|
||||
#ifndef DONT_USE_THR_ALARM
|
||||
/*
|
||||
Error codes from pthread_kill are:
|
||||
@ -866,9 +864,9 @@ terminate_slave_thread(THD *thd,
|
||||
int err __attribute__((unused))= pthread_kill(thd->real_id, thr_client_alarm);
|
||||
DBUG_ASSERT(err != EINVAL);
|
||||
#endif
|
||||
thd->awake(NOT_KILLED);
|
||||
thd->awake_no_mutex(NOT_KILLED);
|
||||
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_kill);
|
||||
|
||||
/*
|
||||
There is a small chance that slave thread might miss the first
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2127,11 +2127,15 @@ public:
|
||||
- thd->query and thd->query_length (used by SHOW ENGINE
|
||||
INNODB STATUS and SHOW PROCESSLIST
|
||||
- thd->db and thd->db_length (used in SHOW PROCESSLIST)
|
||||
- thd->mysys_var (used by KILL statement and shutdown).
|
||||
Is locked when THD is deleted.
|
||||
*/
|
||||
mysql_mutex_t LOCK_thd_data;
|
||||
/* Protect kill information */
|
||||
/*
|
||||
Protects:
|
||||
- kill information
|
||||
- mysys_var (used by KILL statement and shutdown).
|
||||
- Also ensures that THD is not deleted while mutex is hold
|
||||
*/
|
||||
mysql_mutex_t LOCK_thd_kill;
|
||||
|
||||
/* all prepared statements and cursors of this connection */
|
||||
@ -3131,7 +3135,13 @@ public:
|
||||
}
|
||||
void close_active_vio();
|
||||
#endif
|
||||
void awake(killed_state state_to_set);
|
||||
void awake_no_mutex(killed_state state_to_set);
|
||||
void awake(killed_state state_to_set)
|
||||
{
|
||||
mysql_mutex_lock(&LOCK_thd_kill);
|
||||
awake_no_mutex(state_to_set);
|
||||
mysql_mutex_unlock(&LOCK_thd_kill);
|
||||
}
|
||||
|
||||
/** Disconnect the associated communication endpoint. */
|
||||
void disconnect();
|
||||
|
@ -2702,9 +2702,9 @@ void kill_delayed_threads(void)
|
||||
Delayed_insert *di;
|
||||
while ((di= it++))
|
||||
{
|
||||
mysql_mutex_lock(&di->thd.LOCK_thd_data);
|
||||
mysql_mutex_lock(&di->thd.LOCK_thd_kill);
|
||||
if (di->thd.killed < KILL_CONNECTION)
|
||||
di->thd.set_killed(KILL_CONNECTION);
|
||||
di->thd.set_killed_no_mutex(KILL_CONNECTION);
|
||||
if (di->thd.mysys_var)
|
||||
{
|
||||
mysql_mutex_lock(&di->thd.mysys_var->mutex);
|
||||
@ -2722,7 +2722,7 @@ void kill_delayed_threads(void)
|
||||
}
|
||||
mysql_mutex_unlock(&di->thd.mysys_var->mutex);
|
||||
}
|
||||
mysql_mutex_unlock(&di->thd.LOCK_thd_data);
|
||||
mysql_mutex_unlock(&di->thd.LOCK_thd_kill);
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_delayed_insert); // For unlink from list
|
||||
DBUG_VOID_RETURN;
|
||||
@ -3076,9 +3076,9 @@ pthread_handler_t handle_delayed_insert(void *arg)
|
||||
this.
|
||||
*/
|
||||
mysql_mutex_lock(&thd->LOCK_thd_data);
|
||||
thd->set_killed(KILL_CONNECTION_HARD); // If error
|
||||
thd->mdl_context.set_needs_thr_lock_abort(0);
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||
thd->set_killed(KILL_CONNECTION_HARD); // If error
|
||||
|
||||
close_thread_tables(thd); // Free the table
|
||||
thd->mdl_context.release_transactional_locks();
|
||||
|
@ -8758,13 +8758,13 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields,
|
||||
|
||||
|
||||
/**
|
||||
Find a thread by id and return it, locking it LOCK_thd_data
|
||||
Find a thread by id and return it, locking it LOCK_thd_kill
|
||||
|
||||
@param id Identifier of the thread we're looking for
|
||||
@param query_id If true, search by query_id instead of thread_id
|
||||
|
||||
@return NULL - not found
|
||||
pointer - thread found, and its LOCK_thd_data is locked.
|
||||
pointer - thread found, and its LOCK_thd_kill is locked.
|
||||
*/
|
||||
|
||||
THD *find_thread_by_id(longlong id, bool query_id)
|
||||
@ -8778,7 +8778,7 @@ THD *find_thread_by_id(longlong id, bool query_id)
|
||||
continue;
|
||||
if (id == (query_id ? tmp->query_id : (longlong) tmp->thread_id))
|
||||
{
|
||||
mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
|
||||
mysql_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -8834,13 +8834,13 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ
|
||||
thd->security_ctx->user_matches(tmp->security_ctx)) &&
|
||||
!wsrep_thd_is_BF(tmp, true))
|
||||
{
|
||||
tmp->awake(kill_signal);
|
||||
tmp->awake_no_mutex(kill_signal);
|
||||
error=0;
|
||||
}
|
||||
else
|
||||
error= (type == KILL_TYPE_QUERY ? ER_KILL_QUERY_DENIED_ERROR :
|
||||
ER_KILL_DENIED_ERROR);
|
||||
mysql_mutex_unlock(&tmp->LOCK_thd_data);
|
||||
mysql_mutex_unlock(&tmp->LOCK_thd_kill);
|
||||
}
|
||||
DBUG_PRINT("exit", ("%d", error));
|
||||
DBUG_RETURN(error);
|
||||
@ -8898,7 +8898,7 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user,
|
||||
DBUG_RETURN(ER_KILL_DENIED_ERROR);
|
||||
}
|
||||
if (!threads_to_kill.push_back(tmp, thd->mem_root))
|
||||
mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
|
||||
mysql_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete
|
||||
}
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_thread_count);
|
||||
@ -8909,17 +8909,17 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user,
|
||||
THD *ptr= it2++;
|
||||
do
|
||||
{
|
||||
ptr->awake(kill_signal);
|
||||
ptr->awake_no_mutex(kill_signal);
|
||||
/*
|
||||
Careful here: The list nodes are allocated on the memroots of the
|
||||
THDs to be awakened.
|
||||
But those THDs may be terminated and deleted as soon as we release
|
||||
LOCK_thd_data, which will make the list nodes invalid.
|
||||
LOCK_thd_kill, which will make the list nodes invalid.
|
||||
Since the operation "it++" dereferences the "next" pointer of the
|
||||
previous list node, we need to do this while holding LOCK_thd_data.
|
||||
previous list node, we need to do this while holding LOCK_thd_kill.
|
||||
*/
|
||||
next_ptr= it2++;
|
||||
mysql_mutex_unlock(&ptr->LOCK_thd_data);
|
||||
mysql_mutex_unlock(&ptr->LOCK_thd_kill);
|
||||
(*rows)++;
|
||||
} while ((ptr= next_ptr));
|
||||
}
|
||||
|
@ -3344,7 +3344,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id)
|
||||
if (tmp->get_command() == COM_BINLOG_DUMP &&
|
||||
tmp->variables.server_id == slave_server_id)
|
||||
{
|
||||
mysql_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
|
||||
mysql_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3356,8 +3356,8 @@ void kill_zombie_dump_threads(uint32 slave_server_id)
|
||||
it will be slow because it will iterate through the list
|
||||
again. We just to do kill the thread ourselves.
|
||||
*/
|
||||
tmp->awake(KILL_SLAVE_SAME_ID);
|
||||
mysql_mutex_unlock(&tmp->LOCK_thd_data);
|
||||
tmp->awake_no_mutex(KILL_SLAVE_SAME_ID);
|
||||
mysql_mutex_unlock(&tmp->LOCK_thd_kill);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2578,22 +2578,27 @@ static const char *thread_state_info(THD *tmp)
|
||||
{
|
||||
if (tmp->net.reading_or_writing == 2)
|
||||
return "Writing to net";
|
||||
else if (tmp->get_command() == COM_SLEEP)
|
||||
if (tmp->get_command() == COM_SLEEP)
|
||||
return "";
|
||||
else
|
||||
return "Reading from net";
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
|
||||
if (tmp->proc_info)
|
||||
return tmp->proc_info;
|
||||
else if (tmp->mysys_var && tmp->mysys_var->current_cond)
|
||||
|
||||
/* Check if we are waiting on a condition */
|
||||
if (!trylock_short(&tmp->LOCK_thd_kill))
|
||||
{
|
||||
/* mysys_var is protected by above mutex */
|
||||
bool cond= tmp->mysys_var && tmp->mysys_var->current_cond;
|
||||
mysql_mutex_unlock(&tmp->LOCK_thd_kill);
|
||||
if (cond)
|
||||
return "Waiting on cond";
|
||||
else
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mysqld_list_processes(THD *thd,const char *user, bool verbose)
|
||||
{
|
||||
@ -2657,8 +2662,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
|
||||
while ((tmp=it++))
|
||||
{
|
||||
Security_context *tmp_sctx= tmp->security_ctx;
|
||||
struct st_my_thread_var *mysys_var= 0;
|
||||
bool got_thd_data, got_mysys_lock= 0;
|
||||
bool got_thd_data;
|
||||
if ((tmp->vio_ok() || tmp->system_thread) &&
|
||||
(!user || (!tmp->system_thread &&
|
||||
tmp_sctx->user && !strcmp(tmp_sctx->user, user))))
|
||||
@ -2684,17 +2688,10 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
|
||||
thd_info->command=(int) tmp->get_command();
|
||||
|
||||
if ((got_thd_data= !trylock_short(&tmp->LOCK_thd_data)))
|
||||
if ((mysys_var= tmp->mysys_var))
|
||||
got_mysys_lock= !trylock_short(&mysys_var->mutex);
|
||||
|
||||
if (got_thd_data)
|
||||
{
|
||||
/* This is correct under mysys_lock, otherwise an approximation */
|
||||
/* This is an approximation */
|
||||
thd_info->proc_info= (char*) (tmp->killed >= KILL_QUERY ?
|
||||
"Killed" : 0);
|
||||
if (got_mysys_lock)
|
||||
mysql_mutex_unlock(&mysys_var->mutex);
|
||||
|
||||
/*
|
||||
The following variables are only safe to access under a lock
|
||||
*/
|
||||
@ -2952,13 +2949,13 @@ int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond)
|
||||
tmp_sctx->user)))
|
||||
{
|
||||
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "PROCESS");
|
||||
mysql_mutex_unlock(&tmp->LOCK_thd_data);
|
||||
mysql_mutex_unlock(&tmp->LOCK_thd_kill);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
if (tmp == thd)
|
||||
{
|
||||
mysql_mutex_unlock(&tmp->LOCK_thd_data);
|
||||
mysql_mutex_unlock(&tmp->LOCK_thd_kill);
|
||||
my_error(ER_TARGET_NOT_EXPLAINABLE, MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
@ -2966,7 +2963,7 @@ int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond)
|
||||
bool bres;
|
||||
/*
|
||||
Ok we've found the thread of interest and it won't go away because
|
||||
we're holding its LOCK_thd data. Post it a SHOW EXPLAIN request.
|
||||
we're holding its LOCK_thd_kill. Post it a SHOW EXPLAIN request.
|
||||
*/
|
||||
bool timed_out;
|
||||
int timeout_sec= 30;
|
||||
@ -3059,10 +3056,9 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
|
||||
while ((tmp= it++))
|
||||
{
|
||||
Security_context *tmp_sctx= tmp->security_ctx;
|
||||
struct st_my_thread_var *mysys_var= 0;
|
||||
const char *val, *db;
|
||||
ulonglong max_counter;
|
||||
bool got_thd_data, got_mysys_lock= 0;
|
||||
bool got_thd_data;
|
||||
|
||||
if ((!tmp->vio_ok() && !tmp->system_thread) ||
|
||||
(user && (tmp->system_thread || !tmp_sctx->user ||
|
||||
@ -3090,10 +3086,6 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
|
||||
strlen(tmp_sctx->host_or_ip), cs);
|
||||
|
||||
if ((got_thd_data= !trylock_short(&tmp->LOCK_thd_data)))
|
||||
if ((mysys_var= tmp->mysys_var))
|
||||
got_mysys_lock= !trylock_short(&mysys_var->mutex);
|
||||
|
||||
if (got_thd_data)
|
||||
{
|
||||
/* DB */
|
||||
if ((db= tmp->db))
|
||||
@ -3112,9 +3104,6 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
|
||||
table->field[4]->store(command_name[tmp->get_command()].str,
|
||||
command_name[tmp->get_command()].length, cs);
|
||||
|
||||
if (got_mysys_lock)
|
||||
mysql_mutex_unlock(&mysys_var->mutex);
|
||||
|
||||
/* MYSQL_TIME */
|
||||
ulonglong utime= tmp->start_utime;
|
||||
ulonglong utime_after_query_snapshot= tmp->utime_after_query;
|
||||
@ -3124,13 +3113,6 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
|
||||
|
||||
table->field[5]->store(utime / HRTIME_RESOLUTION, TRUE);
|
||||
|
||||
/* STATE */
|
||||
if ((val= thread_state_info(tmp)))
|
||||
{
|
||||
table->field[6]->store(val, strlen(val), cs);
|
||||
table->field[6]->set_notnull();
|
||||
}
|
||||
|
||||
if (got_thd_data)
|
||||
{
|
||||
if (tmp->query())
|
||||
@ -3162,6 +3144,13 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
|
||||
mysql_mutex_unlock(&tmp->LOCK_thd_data);
|
||||
}
|
||||
|
||||
/* STATE */
|
||||
if ((val= thread_state_info(tmp)))
|
||||
{
|
||||
table->field[6]->store(val, strlen(val), cs);
|
||||
table->field[6]->set_notnull();
|
||||
}
|
||||
|
||||
/* TIME_MS */
|
||||
table->field[8]->store((double)(utime / (HRTIME_RESOLUTION / 1000.0)));
|
||||
|
||||
|
@ -250,7 +250,7 @@ static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data)
|
||||
}
|
||||
delete connect;
|
||||
add_to_active_threads(thd);
|
||||
thd->mysys_var= mysys_var;
|
||||
thd->set_mysys_var(mysys_var);
|
||||
thd->event_scheduler.data= scheduler_data;
|
||||
|
||||
/* Create new PSI thread for use with the THD. */
|
||||
@ -477,11 +477,11 @@ void tp_timeout_handler(TP_connection *c)
|
||||
if (c->state != TP_STATE_IDLE)
|
||||
return;
|
||||
THD *thd=c->thd;
|
||||
mysql_mutex_lock(&thd->LOCK_thd_data);
|
||||
mysql_mutex_lock(&thd->LOCK_thd_kill);
|
||||
thd->set_killed(KILL_WAIT_TIMEOUT);
|
||||
c->priority= TP_PRIORITY_HIGH;
|
||||
post_kill_notification(thd);
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_kill);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2492,9 +2492,7 @@ extern "C" void wsrep_thd_awake(THD *thd, my_bool signal)
|
||||
{
|
||||
if (signal)
|
||||
{
|
||||
mysql_mutex_lock(&thd->LOCK_thd_data);
|
||||
thd->awake(KILL_QUERY);
|
||||
mysql_mutex_unlock(&thd->LOCK_thd_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Reference in New Issue
Block a user