summaryrefslogtreecommitdiff
path: root/sql/wsrep_thd.cc
diff options
context:
space:
mode:
authorsjaakola <seppo.jaakola@iki.fi>2021-09-15 09:16:44 +0300
committerJan Lindström <jan.lindstrom@mariadb.com>2021-09-23 15:26:19 +0300
commitda9a37bf4181d92699af40fdd82ab5b7ae1bf307 (patch)
treea732bc90cef6e3e439254c440bcd46fdbd2dd93a /sql/wsrep_thd.cc
parentc8126d173c57a3b2419cd39d8ed546f8fc8a01f7 (diff)
downloadmariadb-git-bb-10.5-MDEV-25114.tar.gz
MDEV-25114 Crash: WSREP: invalid state ROLLED_BACK (FATAL)bb-10.5-MDEV-25114
This patch is the plan D variant for fixing potetial mutex locking order exercised by BF aborting and KILL command execution. In this approach, KILL command is replicated as TOI operation. This guarantees total isolation for the KILL command execution in the first node: there is no concurrent replication applying and no concurrent DDL executing. Therefore there is no risk of BF aborting to happen in parallel with KILL command execution either. Potential mutex deadlocks between the different mutex access paths with KILL command execution and BF aborting cannot therefore happen. TOI replication is used, in this approach, purely as means to provide isolated KILL command execution in the first node. KILL command should not (and must not) be applied in secondary nodes. In this patch, we make this sure by skipping KILL execution in secondary nodes, in applying phase, where we bail out if applier thread is trying to execute KILL command. This is effective, but skipping the applying of KILL command could happen much earlier as well. This patch also fixes mutex locking order and unprotected THD member accesses on bf aborting case. We try to hold THD::LOCK_thd_data during bf aborting. Only case where it is not possible is at wsrep_abort_transaction before call wsrep_innobase_kill_one_trx where we take InnoDB mutexes first and then THD::LOCK_thd_data. This will also fix possible race condition during close_connection and while wsrep is disconnecting connections. Added wsrep_bf_kill_debug test case Reviewed-by: Jan Lindström <jan.lindstrom@mariadb.com>
Diffstat (limited to 'sql/wsrep_thd.cc')
-rw-r--r--sql/wsrep_thd.cc34
1 files changed, 26 insertions, 8 deletions
diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc
index dc6bb21dbd9..e60a2a693d1 100644
--- a/sql/wsrep_thd.cc
+++ b/sql/wsrep_thd.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2013 Codership Oy <info@codership.com>
+/* Copyright (C) 2013-2021 Codership Oy <info@codership.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -64,7 +64,7 @@ static void wsrep_replication_process(THD *thd,
delete thd->wsrep_rgi->rli->mi;
delete thd->wsrep_rgi->rli;
-
+
thd->wsrep_rgi->cleanup_after_session();
delete thd->wsrep_rgi;
thd->wsrep_rgi= NULL;
@@ -314,8 +314,8 @@ int wsrep_abort_thd(THD *bf_thd_ptr, THD *victim_thd_ptr, my_bool signal)
THD *victim_thd= (THD *) victim_thd_ptr;
THD *bf_thd= (THD *) bf_thd_ptr;
- mysql_mutex_lock(&victim_thd->LOCK_thd_data);
-
+ mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
+ mysql_mutex_assert_owner(&victim_thd->LOCK_thd_kill);
/* Note that when you use RSU node is desynced from cluster, thus WSREP(thd)
might not be true.
*/
@@ -327,16 +327,13 @@ int wsrep_abort_thd(THD *bf_thd_ptr, THD *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);
}
@@ -345,6 +342,9 @@ bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
WSREP_LOG_THD(bf_thd, "BF aborter before");
WSREP_LOG_THD(victim_thd, "victim before");
+ mysql_mutex_assert_owner(&victim_thd->LOCK_thd_kill);
+ mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
+
DBUG_EXECUTE_IF("sync.wsrep_bf_abort",
{
const char act[]=
@@ -358,7 +358,7 @@ bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
if (WSREP(victim_thd) && !victim_thd->wsrep_trx().active())
{
WSREP_DEBUG("wsrep_bf_abort, BF abort for non active transaction");
- switch (victim_thd->wsrep_trx().state())
+ switch (victim_thd->wsrep_trx().state())
{
case wsrep::transaction::s_aborting: /* fall through */
case wsrep::transaction::s_aborted:
@@ -367,7 +367,13 @@ bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
default:
break;
}
+
+ /* Test: galera_create_table_as_select. Here we enter wsrep-lib
+ were LOCK_thd_data will be acquired, thus we need to release it.
+ */
+ mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
wsrep_start_transaction(victim_thd, victim_thd->wsrep_next_trx_id());
+ mysql_mutex_lock(&victim_thd->LOCK_thd_data);
}
bool ret;
@@ -375,12 +381,24 @@ bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
if (wsrep_thd_is_toi(bf_thd))
{
+ /* Here we enter wsrep-lib were LOCK_thd_data will be acquired,
+ thus we need to release it. */
+ mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
ret= victim_thd->wsrep_cs().total_order_bf_abort(bf_seqno);
+ mysql_mutex_lock(&victim_thd->LOCK_thd_data);
}
else
{
+ /* Test: mysql-wsrep-features#165. Here we enter wsrep-lib
+ were LOCK_thd_data will be acquired and later LOCK_thd_kill
+ thus we need to release them. */
+ mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
+ mysql_mutex_unlock(&victim_thd->LOCK_thd_kill);
ret= victim_thd->wsrep_cs().bf_abort(bf_seqno);
+ mysql_mutex_lock(&victim_thd->LOCK_thd_kill);
+ mysql_mutex_lock(&victim_thd->LOCK_thd_data);
}
+
if (ret)
{
wsrep_bf_aborts_counter++;