diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2020-09-18 17:35:08 +0200 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2020-09-18 17:35:08 +0200 |
commit | dec45aca77ee23557c59411fa9abf037e5343739 (patch) | |
tree | 1a55e58684ed202d76c24ee59cc86504294a2cbe | |
parent | 46fab5b32a84a1ffd181dd16b5cd63958faf010b (diff) | |
download | mariadb-git-bb-10.6-MDEV-16440-2.tar.gz |
MDEV-23752 SHOW EXPLAIN FOR thd waits for sleepbb-10.6-MDEV-16440-2
my_apc awake thread after request.
-rw-r--r-- | mysql-test/main/processlist_notembedded.result | 13 | ||||
-rw-r--r-- | mysql-test/main/processlist_notembedded.test | 18 | ||||
-rw-r--r-- | sql/event_scheduler.cc | 4 | ||||
-rw-r--r-- | sql/item_func.cc | 2 | ||||
-rw-r--r-- | sql/my_apc.cc | 8 | ||||
-rw-r--r-- | sql/my_apc.h | 3 | ||||
-rw-r--r-- | sql/rpl_parallel.cc | 2 | ||||
-rw-r--r-- | sql/service_wsrep.cc | 4 | ||||
-rw-r--r-- | sql/slave.cc | 7 | ||||
-rw-r--r-- | sql/sql_class.cc | 21 | ||||
-rw-r--r-- | sql/sql_class.h | 13 | ||||
-rw-r--r-- | sql/sql_parse.cc | 7 | ||||
-rw-r--r-- | sql/sql_repl.cc | 2 | ||||
-rw-r--r-- | sql/sql_show.cc | 3 | ||||
-rw-r--r-- | sql/wsrep_mysqld.cc | 7 | ||||
-rw-r--r-- | unittest/sql/my_apc-t.cc | 2 |
16 files changed, 87 insertions, 29 deletions
diff --git a/mysql-test/main/processlist_notembedded.result b/mysql-test/main/processlist_notembedded.result index b622fdf32b9..ab4d3f4d265 100644 --- a/mysql-test/main/processlist_notembedded.result +++ b/mysql-test/main/processlist_notembedded.result @@ -14,3 +14,16 @@ disconnect con1; connection default; SET DEBUG_SYNC = 'RESET'; End of 5.5 tests +# +# MDEV-23752: SHOW EXPLAIN FOR thd waits for sleep +# +connect con1,localhost,root,,; +select sleep(100000);; +connection default; +SHOW EXPLAIN FOR con_id; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used +Warnings: +Note 1003 select sleep(100000) +KILL QUERY con_id; +# End of 10.6 tests diff --git a/mysql-test/main/processlist_notembedded.test b/mysql-test/main/processlist_notembedded.test index 6f269a816fc..8a9ac1bacc5 100644 --- a/mysql-test/main/processlist_notembedded.test +++ b/mysql-test/main/processlist_notembedded.test @@ -40,3 +40,21 @@ SET DEBUG_SYNC = 'RESET'; source include/wait_until_count_sessions.inc; --echo End of 5.5 tests + +--echo # +--echo # MDEV-23752: SHOW EXPLAIN FOR thd waits for sleep +--echo # + +--connect (con1,localhost,root,,) +--let $con_id = `SELECT CONNECTION_ID()` +--send select sleep(100000); + +--connection default + +--replace_result $con_id con_id +eval SHOW EXPLAIN FOR $con_id; + +--replace_result $con_id con_id +eval KILL QUERY $con_id; + +--echo # End of 10.6 tests diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 78802a5e109..86075485865 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -668,7 +668,7 @@ Event_scheduler::stop() sql_print_information("Event Scheduler: Killing the scheduler thread, " "thread id %lu", (ulong) scheduler_thd->thread_id); - scheduler_thd->awake(KILL_CONNECTION); + scheduler_thd->kill_me_pls(KILL_CONNECTION); /* thd could be 0x0, when shutting down */ sql_print_information("Event Scheduler: " @@ -676,7 +676,7 @@ Event_scheduler::stop() /* Wait only 2 seconds, as there is a small chance the thread missed the - above awake() call and we may have to do it again + above kill_me_pls() call and we may have to do it again */ struct timespec top_time; set_timespec(top_time, 2); diff --git a/sql/item_func.cc b/sql/item_func.cc index 8a75d2c9946..e0137d08dfb 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4017,6 +4017,8 @@ int Interruptible_wait::wait(mysql_cond_t *cond, mysql_mutex_t *mutex) timeout= m_abs_timeout; error= mysql_cond_timedwait(cond, mutex, &timeout); + if (m_thd->check_killed(TRUE)) + break; if (error == ETIMEDOUT || error == ETIME) { /* Return error if timed out or connection is broken. */ diff --git a/sql/my_apc.cc b/sql/my_apc.cc index e0feabab8e2..13575c994f4 100644 --- a/sql/my_apc.cc +++ b/sql/my_apc.cc @@ -123,7 +123,7 @@ void init_show_explain_psi_keys(void) timeout occurred) */ -bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call, +bool Apc_target::make_apc_call(THD *thd, THD *caller_thd, Apc_call *call, int timeout_sec, bool *timed_out) { bool res= TRUE; @@ -139,7 +139,11 @@ bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call, NULL); enqueue_request(&apc_request); apc_request.what="enqueued by make_apc_call"; - + +#ifndef MY_APC_STANDALONE + thd->awake_me(); +#endif //MY_APC_STANDALONE + struct timespec abstime; const int timeout= timeout_sec; set_timespec(abstime, timeout); diff --git a/sql/my_apc.h b/sql/my_apc.h index cc98e36bbe4..34f507dcd01 100644 --- a/sql/my_apc.h +++ b/sql/my_apc.h @@ -96,7 +96,8 @@ public: }; /* Make a call in the target thread (see function definition for details) */ - bool make_apc_call(THD *caller_thd, Apc_call *call, int timeout_sec, bool *timed_out); + bool make_apc_call(THD *thd, THD *caller_thd, Apc_call *call, + int timeout_sec, bool *timed_out); #ifndef DBUG_OFF int n_calls_processed; /* Number of calls served by this target */ diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 72347d93ad1..1f10c945d12 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -2203,7 +2203,7 @@ rpl_parallel_entry::choose_thread(rpl_group_info *rgi, bool *did_enter_cond, /* We need to do the debug_sync before ENTER_COND(). Because debug_sync changes the thd->mysys_var->current_mutex, - and this can cause THD::awake to use the wrong mutex. + and this can cause THD::kill_me_pls to use the wrong mutex. */ DBUG_EXECUTE_IF("rpl_parallel_wait_queue_max", { diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc index f61db1e80e8..cce4614c00f 100644 --- a/sql/service_wsrep.cc +++ b/sql/service_wsrep.cc @@ -231,7 +231,7 @@ extern "C" my_bool wsrep_thd_bf_abort(THD *bf_thd, THD *victim_thd, mysql_mutex_lock(&victim_thd->LOCK_thd_kill); victim_thd->wsrep_aborter= bf_thd->thread_id; - victim_thd->awake_no_mutex(KILL_QUERY); + victim_thd->kill_me_pls_no_mutex(KILL_QUERY); mysql_mutex_unlock(&victim_thd->LOCK_thd_kill); mysql_mutex_unlock(&victim_thd->LOCK_thd_data); } else { @@ -372,4 +372,4 @@ extern "C" bool wsrep_thd_set_wsrep_aborter(THD *bf_thd, THD *victim_thd) } victim_thd->wsrep_aborter = bf_thd->thread_id; return false; -}
\ No newline at end of file +} diff --git a/sql/slave.cc b/sql/slave.cc index cc50638ae5b..ed05fee5fba 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -535,7 +535,7 @@ handle_slave_background(void *arg __attribute__((unused))) THD *to_kill= p->to_kill; kill_list= p->next; - to_kill->awake(KILL_CONNECTION); + to_kill->kill_me_pls(KILL_CONNECTION); mysql_mutex_lock(&to_kill->LOCK_wakeup_ready); to_kill->rgi_slave->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED; @@ -1216,7 +1216,7 @@ terminate_slave_thread(THD *thd, DBUG_PRINT("loop", ("killing slave thread")); #ifdef WITH_WSREP - /* awake_no_mutex() requires LOCK_thd_data to be locked if wsrep + /* kill_me_pls_no_mutex() requires LOCK_thd_data to be locked if wsrep is enabled */ if (WSREP(thd)) mysql_mutex_lock(&thd->LOCK_thd_data); #endif /* WITH_WSREP */ @@ -1230,7 +1230,8 @@ terminate_slave_thread(THD *thd, int err __attribute__((unused))= pthread_kill(thd->real_id, thr_client_alarm); DBUG_ASSERT(err != EINVAL); #endif - thd->awake_no_mutex(NOT_KILLED); + thd->kill_me_pls_no_mutex(NOT_KILLED); + mysql_mutex_unlock(&thd->LOCK_thd_kill); #ifdef WITH_WSREP diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ac952fffae8..68159c21f32 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -633,7 +633,7 @@ extern "C" void thd_kill_timeout(THD* thd) { thd->status_var.max_statement_time_exceeded++; /* Kill queries that can't cause data corruptions */ - thd->awake(KILL_TIMEOUT); + thd->kill_me_pls(KILL_TIMEOUT); } THD::THD(my_thread_id id, bool is_wsrep_applier) @@ -1887,9 +1887,9 @@ void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, NOT_KILLED is used to awake a thread for a slave */ -void THD::awake_no_mutex(killed_state state_to_set) +void THD::kill_me_pls_no_mutex(killed_state state_to_set) { - DBUG_ENTER("THD::awake"); + DBUG_ENTER("THD::kill_me_pls_no_mutex"); DBUG_PRINT("enter", ("this: %p current_thd: %p state: %d", this, current_thd, (int) state_to_set)); THD_CHECK_SENTRY(this); @@ -1930,9 +1930,20 @@ void THD::awake_no_mutex(killed_state state_to_set) state_to_set != NOT_KILLED)) ha_kill_query(this, thd_kill_level(this)); + + awake_me(); + DBUG_VOID_RETURN; +} + +void THD::awake_me() +{ + DBUG_ENTER("THD::awake_me"); + mysql_mutex_assert_owner(&LOCK_thd_kill); /* Broadcast a condition to kick the target if it is waiting on it. */ if (mysys_var) { + DBUG_PRINT("enter", ("this: %p current_thd: %p mysys_var", + this, current_thd)); mysql_mutex_lock(&mysys_var->mutex); if (!system_thread) // Don't abort locks mysys_var->abort=1; @@ -2145,7 +2156,7 @@ void THD::reset_killed() { /* Resetting killed has to be done under a mutex to ensure - its not done during an awake() call. + its not done during an kill_me_pls() call. */ DBUG_ENTER("reset_killed"); if (killed != NOT_KILLED) @@ -4973,7 +4984,7 @@ extern "C" size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen) { size_t len= 0; /* InnoDB invokes this function while holding internal mutexes. - THD::awake() will hold LOCK_thd_data while invoking an InnoDB + THD::kill_me_pls() will hold LOCK_thd_data while invoking an InnoDB function that would acquire the internal mutex. Because this function is a non-essential part of information_schema view output, we will break the deadlock by avoiding a mutex wait here diff --git a/sql/sql_class.h b/sql/sql_class.h index b0f68aa8fab..e3e3827e32b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3171,7 +3171,7 @@ public: /* If checking this in conjunction with a wait condition, please include a check after enter_cond() if you want to avoid a race - condition. For details see the implementation of awake(), + condition. For details see the implementation of kill_me_pls(), especially the "broadcast" part. */ killed_state volatile killed; @@ -3436,8 +3436,8 @@ public: } void close_active_vio(); #endif - void awake_no_mutex(killed_state state_to_set); - void awake(killed_state state_to_set) + void kill_me_pls_no_mutex(killed_state state_to_set); + void kill_me_pls(killed_state state_to_set) { bool wsrep_on_local= WSREP_NNULL(this); /* @@ -3447,7 +3447,7 @@ public: if (wsrep_on_local) mysql_mutex_lock(&LOCK_thd_data); mysql_mutex_lock(&LOCK_thd_kill); - awake_no_mutex(state_to_set); + kill_me_pls_no_mutex(state_to_set); mysql_mutex_unlock(&LOCK_thd_kill); if (wsrep_on_local) mysql_mutex_unlock(&LOCK_thd_data); @@ -3507,7 +3507,7 @@ public: Putting the mutex unlock in thd->exit_cond() ensures that mysys_var->current_mutex is always unlocked _before_ mysys_var->mutex is locked (if that would not be the case, you'll get a deadlock if someone - does a THD::awake() on you). + does a THD::kill_me_pls() on you). */ mysql_mutex_unlock(mysys_var->current_mutex); mysql_mutex_lock(&mysys_var->mutex); @@ -4957,6 +4957,9 @@ private: } public: + + void awake_me(); + #ifdef HAVE_REPLICATION /* If we do a purge of binary logs, log index info of the threads diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8c95aa0a760..85b10d8cf88 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7649,7 +7649,7 @@ static bool wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, /* Convert all ER_QUERY_INTERRUPTED errors to ER_LOCK_DEADLOCK if the transaction was BF aborted. This can happen when the - transaction is being BF aborted via thd->awake() while it is + transaction is being BF aborted via thd->kill_me_pls() while it is still executing. Note that this must be done before wsrep_after_statement() call @@ -9047,6 +9047,7 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ #endif /* WITH_WSREP */ { #ifdef WITH_WSREP + // following is historic name, mean kill_me_pls_no_mutex now DEBUG_SYNC(thd, "before_awake_no_mutex"); if (tmp->wsrep_aborter && tmp->wsrep_aborter != thd->thread_id) { @@ -9060,7 +9061,7 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ { WSREP_DEBUG("kill_one_thread %llu, victim: %llu wsrep_aborter %llu by signal %d", thd->thread_id, id, tmp->wsrep_aborter, kill_signal); - tmp->awake_no_mutex(kill_signal); + tmp->kill_me_pls_no_mutex(kill_signal); WSREP_DEBUG("victim: %llu taken care of", id); error= 0; } @@ -9152,7 +9153,7 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user, THD *ptr= it2++; do { - ptr->awake_no_mutex(kill_signal); + ptr->kill_me_pls_no_mutex(kill_signal); /* Careful here: The list nodes are allocated on the memroots of the THDs to be awakened. diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 4a1484df2c2..81f564087c9 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -3495,7 +3495,7 @@ 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. */ - arg.thd->awake_no_mutex(KILL_SLAVE_SAME_ID); + arg.thd->kill_me_pls_no_mutex(KILL_SLAVE_SAME_ID); mysql_mutex_unlock(&arg.thd->LOCK_thd_kill); if (WSREP(arg.thd)) mysql_mutex_unlock(&arg.thd->LOCK_thd_data); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 452690f3237..4ed4f7b270e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3125,7 +3125,8 @@ int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond) explain_req.failed_to_produce= FALSE; /* Ok, we have a lock on target->LOCK_thd_kill, can call: */ - bres= tmp->apc_target.make_apc_call(thd, &explain_req, timeout_sec, &timed_out); + bres= tmp->apc_target.make_apc_call(tmp, thd, &explain_req, + timeout_sec, &timed_out); if (bres || explain_req.failed_to_produce) { diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index d0155f27d6d..deda04575df 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -2574,8 +2574,11 @@ static my_bool kill_all_threads(THD *thd, THD *caller_thd) { /* replicated transactions must be skipped */ WSREP_DEBUG("closing connection %lld", (longlong) thd->thread_id); - /* instead of wsrep_close_thread() we do now soft kill by THD::awake */ - thd->awake(KILL_CONNECTION); + /* + instead of wsrep_close_thread() we do now soft kill by + THD::kill_me_pls + */ + thd->kill_me_pls(KILL_CONNECTION); } } return 0; diff --git a/unittest/sql/my_apc-t.cc b/unittest/sql/my_apc-t.cc index c08e7281c92..9bf26463668 100644 --- a/unittest/sql/my_apc-t.cc +++ b/unittest/sql/my_apc-t.cc @@ -151,7 +151,7 @@ void *test_apc_requestor_thread(void *ptr) bool timed_out; mysql_mutex_lock(&target_mutex); - bool res= apc_target.make_apc_call(&my_thd, &apc_order, 60, &timed_out); + bool res= apc_target.make_apc_call(NULL, &my_thd, &apc_order, 60, &timed_out); if (res) { if (timed_out) |