diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/event_scheduler.cc | 2 | ||||
-rw-r--r-- | sql/slave.cc | 8 | ||||
-rw-r--r-- | sql/sql_class.cc | 43 | ||||
-rw-r--r-- | sql/sql_class.h | 32 | ||||
-rw-r--r-- | sql/sql_insert.cc | 4 | ||||
-rw-r--r-- | sql/sql_parse.cc | 38 | ||||
-rw-r--r-- | sql/sql_plugin_services.ic | 5 | ||||
-rw-r--r-- | sql/sql_repl.cc | 8 | ||||
-rw-r--r-- | sql/sql_show.cc | 45 | ||||
-rw-r--r-- | sql/table.h | 3 | ||||
-rw-r--r-- | sql/threadpool_common.cc | 4 | ||||
-rw-r--r-- | sql/wsrep_dummy.cc | 9 | ||||
-rw-r--r-- | sql/wsrep_thd.cc | 80 |
13 files changed, 226 insertions, 55 deletions
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 2a5399fb94a..41cf8aba324 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -651,13 +651,11 @@ Event_scheduler::stop() 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: " diff --git a/sql/slave.cc b/sql/slave.cc index 1bf83aa9652..f83a733da71 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -346,9 +346,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; @@ -859,7 +857,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: @@ -869,9 +867,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 diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 0a8c136e556..e7934f887dd 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -590,10 +590,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); } @@ -652,7 +650,8 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) wsrep_po_handle(WSREP_PO_INITIALIZER), wsrep_po_cnt(0), wsrep_apply_format(0), - wsrep_ignore_table(false) + wsrep_ignore_table(false), + wsrep_aborter(0) #endif { ulong tmp; @@ -790,6 +789,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier) wsrep_replicate_GTID = false; wsrep_skip_wsrep_GTID = false; wsrep_split_flag = false; + wsrep_aborter = 0; #endif /* Call to init() below requires fully initialized Open_tables_state. */ reset_open_tables_state(this); @@ -1247,7 +1247,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; } @@ -1508,9 +1508,15 @@ 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 + */ + if (WSREP(this)) mysql_mutex_lock(&LOCK_thd_data); + mysql_mutex_lock(&LOCK_thd_kill); + mysql_mutex_unlock(&LOCK_thd_kill); + if (WSREP(this)) mysql_mutex_unlock(&LOCK_thd_data); #ifdef WITH_WSREP delete wsrep_rgi; @@ -1680,17 +1686,18 @@ 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); + if (WSREP(this)) mysql_mutex_assert_owner(&LOCK_thd_data); + mysql_mutex_assert_owner(&LOCK_thd_kill); print_aborted_warning(3, "KILLED"); @@ -1702,7 +1709,6 @@ void THD::awake(killed_state state_to_set) 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) @@ -1789,7 +1795,6 @@ void THD::awake(killed_state state_to_set) } mysql_mutex_unlock(&mysys_var->mutex); } - mysql_mutex_unlock(&LOCK_thd_kill); DBUG_VOID_RETURN; } @@ -1841,7 +1846,7 @@ 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); if (in_use->mysys_var) @@ -1854,7 +1859,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; } @@ -1962,7 +1967,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 @@ -2013,9 +2018,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); @@ -5240,9 +5245,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); } /** diff --git a/sql/sql_class.h b/sql/sql_class.h index 8d8ab779d56..a091f532bb2 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3214,7 +3214,28 @@ 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) + { +/* + bool wsrep_on_local= WSREP(this); +*/ + /* + mutex locking order (LOCK_thd_data - LOCK_thd_kill)) requires + to grab LOCK_thd_data here + */ +/* + if (wsrep_on_local) + mysql_mutex_lock(&LOCK_thd_data); +*/ + mysql_mutex_lock(&LOCK_thd_kill); + awake_no_mutex(state_to_set); + mysql_mutex_unlock(&LOCK_thd_kill); +/* + if (wsrep_on_local) + mysql_mutex_unlock(&LOCK_thd_data); +*/ + } /** Disconnect the associated communication endpoint. */ void disconnect(); @@ -3755,11 +3776,18 @@ public: */ if (killed != NOT_KILLED) { + mysql_mutex_assert_not_owner(&LOCK_thd_kill); mysql_mutex_lock(&LOCK_thd_kill); killed= NOT_KILLED; killed_err= 0; mysql_mutex_unlock(&LOCK_thd_kill); } +#ifdef WITH_WSREP + mysql_mutex_assert_not_owner(&LOCK_thd_data); + mysql_mutex_lock(&LOCK_thd_data); + wsrep_aborter= 0; + mysql_mutex_unlock(&LOCK_thd_data); +#endif /* WITH_WSREP */ } inline void reset_kill_query() { @@ -4470,6 +4498,8 @@ public: registered again, but replication of last chunk of rows is skipped by the innodb engine: */ bool wsrep_split_flag; + /* thread who has started kill for this THD protected by LOCK_thd_data*/ + my_thread_id wsrep_aborter; #endif /* WITH_WSREP */ /* Handling of timeouts for commands */ diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ec784bc6df4..faf40e1b928 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2753,7 +2753,7 @@ 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); if (di->thd.mysys_var) @@ -2773,7 +2773,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; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 543c877b7f1..f34e182942d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2355,11 +2355,11 @@ com_multi_end: DBUG_ASSERT((command != COM_QUIT && command != COM_STMT_CLOSE) || thd->get_stmt_da()->is_disabled()); /* wsrep BF abort in query exec phase */ - mysql_mutex_lock(&thd->LOCK_thd_data); + mysql_mutex_lock(&thd->LOCK_thd_kill); do_end_of_statement= thd->wsrep_conflict_state != REPLAYING && thd->wsrep_conflict_state != RETRY_AUTOCOMMIT && !thd->killed; - mysql_mutex_unlock(&thd->LOCK_thd_data); + mysql_mutex_unlock(&thd->LOCK_thd_kill); } else do_end_of_statement= true; @@ -8820,7 +8820,7 @@ 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 @@ -8840,7 +8840,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; } } @@ -8896,13 +8896,30 @@ 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, false)) { - tmp->awake(kill_signal); - error=0; +#ifdef WITH_WSREP + DEBUG_SYNC(thd, "before_awake_no_mutex"); + if (tmp->wsrep_aborter && tmp->wsrep_aborter != thd->thread_id) + { + /* victim is in hit list already, bail out */ + WSREP_DEBUG("victim has wsrep aborter: %lu, skipping awake()", + tmp->wsrep_aborter); + error= 0; + } + else +#endif /* WITH_WSREP */ + { + 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); + WSREP_DEBUG("victim: %llu taken care of", id); + error= 0; + } } else error= (type == KILL_TYPE_QUERY ? ER_KILL_QUERY_DENIED_ERROR : ER_KILL_DENIED_ERROR); - mysql_mutex_unlock(&tmp->LOCK_thd_data); + if (WSREP(tmp)) mysql_mutex_unlock(&tmp->LOCK_thd_data); + mysql_mutex_unlock(&tmp->LOCK_thd_kill); } DBUG_PRINT("exit", ("%d", error)); DBUG_RETURN(error); @@ -8971,17 +8988,18 @@ 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. */ next_ptr= it2++; - mysql_mutex_unlock(&ptr->LOCK_thd_data); + mysql_mutex_unlock(&ptr->LOCK_thd_kill); + if (WSREP(ptr)) mysql_mutex_unlock(&ptr->LOCK_thd_data); (*rows)++; } while ((ptr= next_ptr)); } diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic index 20113444b64..cc28c38d85b 100644 --- a/sql/sql_plugin_services.ic +++ b/sql/sql_plugin_services.ic @@ -167,6 +167,7 @@ static struct wsrep_service_st wsrep_handler = { wsrep_thd_exec_mode, wsrep_thd_exec_mode_str, wsrep_thd_get_conflict_state, + wsrep_thd_is_aborting, wsrep_thd_is_BF, wsrep_thd_is_wsrep, wsrep_thd_query, @@ -181,10 +182,12 @@ static struct wsrep_service_st wsrep_handler = { wsrep_set_load_multi_commit, wsrep_is_load_multi_commit, wsrep_trx_is_aborting, + wsrep_thd_bf_abort, wsrep_trx_order_before, wsrep_unlock_rollback, wsrep_set_data_home_dir, - wsrep_thd_is_applier + wsrep_thd_is_applier, + wsrep_thd_set_wsrep_aborter }; static struct thd_specifics_service_st thd_specifics_handler= diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 721b6799ed3..e944ea1bc54 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -3375,7 +3375,8 @@ 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 + if (WSREP(tmp)) mysql_mutex_lock(&tmp->LOCK_thd_data); + mysql_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete break; } } @@ -3387,8 +3388,9 @@ 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); + if (WSREP(tmp)) mysql_mutex_unlock(&tmp->LOCK_thd_data); } } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 18b7e92bca5..bbe217c44d3 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2556,6 +2556,28 @@ public: double progress; }; +/** + Try to lock a mutex, but give up after a short while to not cause deadlocks + + The loop is short, as the mutex we are trying to lock are mutex the should + never be locked a long time, just over a few instructions. + + @return 0 ok + @return 1 error +*/ + +static bool trylock_short(mysql_mutex_t *mutex) +{ + uint i; + for (i= 0 ; i < 100 ; i++) + { + if (!mysql_mutex_trylock(mutex)) + return 0; + LF_BACKOFF(); + } + return 1; +} + static const char *thread_state_info(THD *tmp) { #ifndef EMBEDDED_LIBRARY @@ -2574,10 +2596,17 @@ static const char *thread_state_info(THD *tmp) #endif if (tmp->proc_info) return tmp->proc_info; - else if (tmp->mysys_var && tmp->mysys_var->current_cond) - return "Waiting on cond"; - else - return NULL; + + /* 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"; + } + return NULL; } void mysqld_list_processes(THD *thd,const char *user, bool verbose) @@ -2921,13 +2950,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); } @@ -2935,7 +2964,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; @@ -2949,7 +2978,7 @@ int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond) explain_req.request_thd= thd; explain_req.failed_to_produce= FALSE; - /* Ok, we have a lock on target->LOCK_thd_data, can call: */ + /* 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); if (bres || explain_req.failed_to_produce) diff --git a/sql/table.h b/sql/table.h index f3a7f278604..ff8f7d9a692 100644 --- a/sql/table.h +++ b/sql/table.h @@ -17,6 +17,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ +#include "my_cpu.h" #include "sql_plist.h" #include "sql_list.h" /* Sql_alloc */ #include "mdl.h" @@ -610,7 +611,7 @@ class TABLE_STATISTICS_CB return true; if (expected == READY) return false; - (void) LF_BACKOFF; + (void) LF_BACKOFF(); } } diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc index b0438770aae..bf8a1323ef4 100644 --- a/sql/threadpool_common.cc +++ b/sql/threadpool_common.cc @@ -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); } diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc index d8ab86c25f2..9b01dba57a9 100644 --- a/sql/wsrep_dummy.cc +++ b/sql/wsrep_dummy.cc @@ -17,9 +17,15 @@ #include <sql_class.h> #include <mysql/service_wsrep.h> +my_bool wsrep_thd_is_aborting(const THD *) +{ return 0; } + my_bool wsrep_thd_is_BF(THD *, my_bool) { return 0; } +my_bool wsrep_thd_bf_abort(THD *, THD *, my_bool) +{ return 0; } + int wsrep_trx_order_before(THD *, THD *) { return 0; } @@ -154,3 +160,6 @@ void wsrep_log(void (*)(const char *, ...), const char *, ...) my_bool wsrep_thd_is_applier(MYSQL_THD thd) { return false; } + +bool wsrep_thd_set_wsrep_aborter(THD*, THD*) +{ return false; } diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index 1e60088c5f1..37f7ab8cb2e 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -27,6 +27,7 @@ #include "rpl_filter.h" #include "rpl_rli.h" #include "rpl_mi.h" +#include "debug_sync.h" #if (__LP64__) static volatile int64 wsrep_bf_aborts_counter(0); @@ -793,10 +794,13 @@ int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal) THD *bf_thd = (THD *) bf_thd_ptr; DBUG_ENTER("wsrep_abort_thd"); + mysql_mutex_lock(&victim_thd->LOCK_thd_data); + if ( (WSREP(bf_thd) || ( (WSREP_ON || bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU) && bf_thd->wsrep_exec_mode == TOTAL_ORDER) ) && - victim_thd) + victim_thd && + !wsrep_thd_is_aborting(victim_thd)) { if ((victim_thd->wsrep_conflict_state == MUST_ABORT) || (victim_thd->wsrep_conflict_state == ABORTED) || @@ -811,13 +815,16 @@ int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr, my_bool signal) WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu", (bf_thd) ? (long long)bf_thd->real_id : 0, (long long)victim_thd->real_id); + mysql_mutex_unlock(&victim_thd->LOCK_thd_data); ha_abort_transaction(bf_thd, victim_thd, signal); + mysql_mutex_lock(&victim_thd->LOCK_thd_data); } else { WSREP_DEBUG("wsrep_abort_thd not effective: %p %p", bf_thd, victim_thd); } + mysql_mutex_unlock(&victim_thd->LOCK_thd_data); DBUG_RETURN(1); } @@ -876,3 +883,74 @@ bool wsrep_is_load_multi_commit(THD *thd) { return thd->wsrep_split_flag; } + +extern "C" my_bool wsrep_thd_bf_abort(THD *bf_thd, THD *victim_thd, + my_bool signal) +{ + DBUG_EXECUTE_IF("sync.before_wsrep_thd_abort", + { + const char act[]= + "now " + "SIGNAL sync.before_wsrep_thd_abort_reached " + "WAIT_FOR signal.before_wsrep_thd_abort"; + DBUG_ASSERT(!debug_sync_set_action(bf_thd, + STRING_WITH_LEN(act))); + };); + + my_bool ret= true; // wsrep_bf_abort(bf_thd, victim_thd); + /* + Send awake signal if victim was BF aborted or does not + have wsrep on. Note that this should never interrupt RSU + as RSU has paused the provider. + */ + if ((ret || !wsrep_on(victim_thd)) && signal) + { + mysql_mutex_assert_not_owner(&victim_thd->LOCK_thd_data); + mysql_mutex_assert_not_owner(&victim_thd->LOCK_thd_kill); + mysql_mutex_lock(&victim_thd->LOCK_thd_data); + + if (victim_thd->wsrep_aborter && victim_thd->wsrep_aborter != bf_thd->thread_id) + { + WSREP_DEBUG("victim is killed already by %llu, skipping awake", + victim_thd->wsrep_aborter); + mysql_mutex_unlock(&victim_thd->LOCK_thd_data); + return false; + } + + mysql_mutex_lock(&victim_thd->LOCK_thd_kill); + victim_thd->wsrep_aborter= bf_thd->thread_id; + victim_thd->awake_no_mutex(KILL_QUERY); + mysql_mutex_unlock(&victim_thd->LOCK_thd_kill); + mysql_mutex_unlock(&victim_thd->LOCK_thd_data); + } else { + WSREP_DEBUG("wsrep_thd_bf_abort skipped awake"); + } + return ret; +} + +extern "C" bool wsrep_thd_set_wsrep_aborter(THD *bf_thd, THD *victim_thd) +{ + WSREP_DEBUG("wsrep_thd_set_wsrep_aborter called"); + mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data); + if (victim_thd->wsrep_aborter && victim_thd->wsrep_aborter != bf_thd->thread_id) + { + return true; + } + victim_thd->wsrep_aborter = bf_thd->thread_id; + return false; +} + +extern "C" my_bool wsrep_thd_is_aborting(const MYSQL_THD thd) +{ + mysql_mutex_assert_owner(&thd->LOCK_thd_data); + if (thd != 0) + { + if ((thd->wsrep_conflict_state == MUST_ABORT) || + (thd->wsrep_conflict_state == ABORTED) || + (thd->wsrep_conflict_state == ABORTING)) + { + return true; + } + } + return false; +} |