summaryrefslogtreecommitdiff
path: root/sql/wsrep_mysqld.h
diff options
context:
space:
mode:
authorJan Lindström <jan.lindstrom@mariadb.com>2020-03-12 15:34:50 +0200
committerJan Lindström <jan.lindstrom@mariadb.com>2020-09-03 15:19:28 +0300
commit1b6bd701b30f8297db38e605692aa91aff92a06d (patch)
treefa977c8546b930b6f0a7df259abfdc725586dc29 /sql/wsrep_mysqld.h
parent97db6c15ea3e83a21df137c222dbd5a40fbe7c82 (diff)
downloadmariadb-git-bb-10.2-MDEV-21910.tar.gz
MDEV-21910 : KIlling thread on Galera could cause mutex deadlockbb-10.2-MDEV-21910
Whenever Galera BF (brute force) transaction decides to abort conflicting transaction it will kill that thread using thd::awake() User KILL [QUERY|CONNECTION] ... for a thread it will also call thd::awake() Whenever one of these actions is executed we will hold number of InnoDB internal mutexes and thd mutexes. Sometimes these mutexes are taken in different order causing mutex deadlock. Lets call BF kill as bf_thread and user KILL-query as kill_thread. bf_thread takes mutexes in order: (1) lock_sys->mutex (lock0lock.cc lock_rec_other_has_conflicting) (2) victim_trx->mutex (lock0lock.cc lock_rec_other_has_conflicting) (3) victim_thread->LOCK_thd_data (handler.cc wsrep_innobase_kill_one_trx) kill_thread takes mutexes in order: (1) victim_thread->LOCK_thd_data (sql_parse.cc find_thread_by_id) (2) lock_sys->mutex (ha_innodb.cc innobase_kill_query) (3) victim_trx->mutex (ha_innodb.cc innobase_kill_query) Mutex deadlock is result of taking victim_thread->LOCK_thd_data in different order. In this patch we will fix Galera BF victim thread kill so that it will not try to lock victim_thread->LOCK_thd_data mutex while we hold InnoDB mutexes. Instead victim is inserted a list for later kill processing. A new background thread will pick victim thread from this new list and uses thd::awake() with no InnoDB mutexes. Idea is similar to replication background kill. This fix enforces that we take mutexes in same order: (1) victim_thread->LOCK_thd_data (2) lock_sys->mutex -> (3) victim_trx->mutex wsrep_mysqld.cc Here we introduce a list where victim threads are stored, condition variable to be used to wake up background thread and mutex to protect list. wsrep_thd.cc Create a new background thread to handle victim thread abort. We may take victim_thread->LOCK_thd_data mutex here but not any InnoDB mutexes. wsrep_innobase_kill_one_trx Remove all the wsrep code that was moved to wsrep_thd.cc We just enqueue required information to background kill list and cancel victim trx lock wait if there is such. Here we have InnoDB lock_sys->mutex and victim_trx->mutex so here we can't take victim_thread->LOCK_thd_data mutex. wsrep_abort_transaction Cleanup only.
Diffstat (limited to 'sql/wsrep_mysqld.h')
-rw-r--r--sql/wsrep_mysqld.h24
1 files changed, 21 insertions, 3 deletions
diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h
index e28b90885b4..61aa0fcd860 100644
--- a/sql/wsrep_mysqld.h
+++ b/sql/wsrep_mysqld.h
@@ -18,9 +18,20 @@
#ifndef WSREP_MYSQLD_H
#define WSREP_MYSQLD_H
+#include <my_config.h>
+#include <stdint.h>
#include <mysql/plugin.h>
#include <mysql/service_wsrep.h>
+typedef struct wsrep_kill {
+ unsigned long victim_thd_id;
+ unsigned long bf_thd_id;
+ uint64_t victim_trx_id;
+ uint64_t bf_trx_id;
+ bool signal;
+ bool wait_lock;
+} wsrep_kill_t;
+
#ifdef WITH_WSREP
typedef struct st_mysql_show_var SHOW_VAR;
@@ -92,6 +103,7 @@ extern my_bool wsrep_slave_UK_checks;
extern ulong wsrep_running_threads;
extern ulong wsrep_running_applier_threads;
extern ulong wsrep_running_rollbacker_threads;
+extern ulong wsrep_running_killer_threads;
extern bool wsrep_new_cluster;
extern bool wsrep_gtid_mode;
extern uint32 wsrep_gtid_domain_id;
@@ -223,8 +235,6 @@ void wsrep_log(void (*fun)(const char *, ...), const char *format, ...);
#define WSREP_PROVIDER_EXISTS \
(wsrep_provider && strncasecmp(wsrep_provider, WSREP_NONE, FN_REFLEN))
-#define WSREP_QUERY(thd) (thd->query())
-
extern my_bool wsrep_ready_get();
extern void wsrep_ready_wait();
@@ -254,6 +264,8 @@ extern mysql_cond_t COND_wsrep_replaying;
extern mysql_mutex_t LOCK_wsrep_slave_threads;
extern mysql_mutex_t LOCK_wsrep_desync;
extern mysql_mutex_t LOCK_wsrep_config_state;
+extern mysql_mutex_t LOCK_wsrep_kill;
+extern mysql_cond_t COND_wsrep_kill;
extern wsrep_aborting_thd_t wsrep_aborting_thd;
extern my_bool wsrep_emulate_bin_log;
extern int wsrep_to_isolation;
@@ -278,6 +290,8 @@ extern PSI_mutex_key key_LOCK_wsrep_replaying;
extern PSI_cond_key key_COND_wsrep_replaying;
extern PSI_mutex_key key_LOCK_wsrep_slave_threads;
extern PSI_mutex_key key_LOCK_wsrep_desync;
+extern PSI_mutex_key key_LOCK_wsrep_kill;
+extern PSI_cond_key key_COND_wsrep_kill;
extern PSI_file_key key_file_wsrep_gra_log;
@@ -285,6 +299,7 @@ extern PSI_thread_key key_wsrep_sst_joiner;
extern PSI_thread_key key_wsrep_sst_donor;
extern PSI_thread_key key_wsrep_rollbacker;
extern PSI_thread_key key_wsrep_applier;
+extern PSI_thread_key key_wsrep_killer;
#endif /* HAVE_PSI_INTERFACE */
@@ -311,7 +326,8 @@ void thd_binlog_trx_reset(THD * thd);
enum wsrep_thread_type {
WSREP_APPLIER_THREAD=1,
- WSREP_ROLLBACKER_THREAD=2
+ WSREP_ROLLBACKER_THREAD=2,
+ WSREP_KILLER_THREAD=3
};
typedef void (*wsrep_thd_processor_fun)(THD *);
@@ -358,6 +374,8 @@ void wsrep_keys_free(wsrep_key_arr_t* key_arr);
((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \
wsrep_forced_binlog_format : my_format)
+bool wsrep_thd_set_wsrep_aborter(THD *victim_thd, THD *bf_thd);
+
#else /* WITH_WSREP */
#define WSREP(T) (0)