summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/event_scheduler.cc2
-rw-r--r--sql/slave.cc8
-rw-r--r--sql/sql_class.cc43
-rw-r--r--sql/sql_class.h32
-rw-r--r--sql/sql_insert.cc4
-rw-r--r--sql/sql_parse.cc38
-rw-r--r--sql/sql_plugin_services.ic5
-rw-r--r--sql/sql_repl.cc8
-rw-r--r--sql/sql_show.cc45
-rw-r--r--sql/table.h3
-rw-r--r--sql/threadpool_common.cc4
-rw-r--r--sql/wsrep_dummy.cc9
-rw-r--r--sql/wsrep_thd.cc80
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;
+}