summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Lindström <jan.lindstrom@mariadb.com>2019-02-05 15:41:53 +0200
committerJan Lindström <jan.lindstrom@mariadb.com>2019-03-28 08:43:44 +0200
commit81d71ee6b21870772c336bff15b71904914f146a (patch)
tree72bb4aeb8a81ad04047a48102d3756a010b43eb5
parent21b2fada7ab7f35c898c02d2f918461409cc9c8e (diff)
downloadmariadb-git-81d71ee6b21870772c336bff15b71904914f146a.tar.gz
MDEV-12009: Allow to force kill user threads/query which are flagged as high priority by Galera
As noted on kill_one_thread SUPER should be able to kill even system threads i.e. threads/query flagged as high priority or wsrep applier thread. Normal user, should not able to kill threads/query flagged as high priority (BF) or wsrep applier thread.
-rw-r--r--include/mysql/service_wsrep.h3
-rw-r--r--mysql-test/suite/galera/r/galera_kill_applier.result4
-rw-r--r--mysql-test/suite/galera/t/galera_kill_applier.cnf10
-rw-r--r--mysql-test/suite/galera/t/galera_kill_applier.test54
-rw-r--r--sql/sql_parse.cc14
-rw-r--r--sql/sql_plugin_services.ic3
-rw-r--r--sql/wsrep_dummy.cc3
-rw-r--r--sql/wsrep_mysqld.cc1
-rw-r--r--sql/wsrep_thd.cc9
-rw-r--r--sql/wsrep_thd.h2
10 files changed, 95 insertions, 8 deletions
diff --git a/include/mysql/service_wsrep.h b/include/mysql/service_wsrep.h
index 267c8cb4e90..59df7a8b561 100644
--- a/include/mysql/service_wsrep.h
+++ b/include/mysql/service_wsrep.h
@@ -112,6 +112,7 @@ extern struct wsrep_service_st {
int (*wsrep_trx_order_before_func)(MYSQL_THD, MYSQL_THD);
void (*wsrep_unlock_rollback_func)();
void (*wsrep_set_data_home_dir_func)(const char *data_dir);
+ my_bool (*wsrep_thd_is_applier_func)(THD *thd);
} *wsrep_service;
#ifdef MYSQL_DYNAMIC_PLUGIN
@@ -155,6 +156,7 @@ extern struct wsrep_service_st {
#define wsrep_trx_order_before(T1,T2) wsrep_service->wsrep_trx_order_before_func(T1,T2)
#define wsrep_unlock_rollback() wsrep_service->wsrep_unlock_rollback_func()
#define wsrep_set_data_home_dir(A) wsrep_service->wsrep_set_data_home_dir_func(A)
+#define wsrep_thd_is_applier(T) wsrep_service->wsrep_thd_is_applier_func(T)
#define wsrep_debug get_wsrep_debug()
#define wsrep_log_conflicts get_wsrep_log_conflicts()
@@ -214,6 +216,7 @@ void wsrep_thd_set_conflict_state(THD *thd, enum wsrep_conflict_state state);
bool wsrep_thd_ignore_table(THD *thd);
void wsrep_unlock_rollback();
void wsrep_set_data_home_dir(const char *data_dir);
+my_bool wsrep_thd_is_applier(THD *thd);
#endif
diff --git a/mysql-test/suite/galera/r/galera_kill_applier.result b/mysql-test/suite/galera/r/galera_kill_applier.result
index fe4911639ed..89f8ead0b65 100644
--- a/mysql-test/suite/galera/r/galera_kill_applier.result
+++ b/mysql-test/suite/galera/r/galera_kill_applier.result
@@ -1,4 +1,8 @@
+CREATE USER foo@localhost;
+GRANT SELECT on test.* TO foo@localhost;
+# Open connection to the 1st node using 'test_user1' user.
Got one of the listed errors
Got one of the listed errors
Got one of the listed errors
Got one of the listed errors
+DROP USER foo@localhost;
diff --git a/mysql-test/suite/galera/t/galera_kill_applier.cnf b/mysql-test/suite/galera/t/galera_kill_applier.cnf
new file mode 100644
index 00000000000..f2563e66f2e
--- /dev/null
+++ b/mysql-test/suite/galera/t/galera_kill_applier.cnf
@@ -0,0 +1,10 @@
+!include ../galera_2nodes.cnf
+
+[mysqld.1]
+wsrep_provider_options='base_port=@mysqld.1.#galera_port;pc.ignore_sb=true'
+auto_increment_offset=1
+
+[mysqld.2]
+wsrep_provider_options='base_port=@mysqld.2.#galera_port;pc.ignore_sb=true'
+auto_increment_offset=2
+
diff --git a/mysql-test/suite/galera/t/galera_kill_applier.test b/mysql-test/suite/galera/t/galera_kill_applier.test
index e14a8b9af23..5e4a587fe57 100644
--- a/mysql-test/suite/galera/t/galera_kill_applier.test
+++ b/mysql-test/suite/galera/t/galera_kill_applier.test
@@ -1,14 +1,25 @@
#
# This test checks that applier threads are immune to KILL QUERY and KILL STATEMENT
+# when USER is not SUPER
#
--source include/galera_cluster.inc
---source include/have_innodb.inc
--connection node_1
+CREATE USER foo@localhost;
+GRANT SELECT on test.* TO foo@localhost;
+
--let $applier_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE != 'wsrep aborter idle' OR STATE IS NULL LIMIT 1`
+--let $aborter_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'wsrep aborter idle' LIMIT 1`
+
+--echo # Open connection to the 1st node using 'test_user1' user.
+--let $port_1= \$NODE_MYPORT_1
+--connect(foo_node_1,localhost,foo,,test,$port_1,)
+
+--connection foo_node_1
+
--disable_query_log
--error ER_KILL_DENIED_ERROR,ER_KILL_DENIED_ERROR
--eval KILL $applier_thread
@@ -16,11 +27,48 @@
--error ER_KILL_DENIED_ERROR,ER_KILL_DENIED_ERROR
--eval KILL QUERY $applier_thread
---let $aborter_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'wsrep aborter idle' LIMIT 1`
-
--error ER_KILL_DENIED_ERROR,ER_KILL_DENIED_ERROR
--eval KILL $aborter_thread
--error ER_KILL_DENIED_ERROR,ER_KILL_DENIED_ERROR
--eval KILL QUERY $aborter_thread
--enable_query_log
+
+#
+# SUPER can kill applier threads
+#
+--connection node_2
+
+--let $applier_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE != 'wsrep aborter idle' OR STATE IS NULL LIMIT 1`
+
+--disable_query_log
+--eval KILL $applier_thread
+--enable_query_log
+
+--let $aborter_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'wsrep aborter idle' LIMIT 1`
+
+--disable_query_log
+--eval KILL $aborter_thread
+--enable_query_log
+
+--source include/restart_mysqld.inc
+
+--connection node_2
+--let $applier_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE != 'wsrep aborter idle' OR STATE IS NULL LIMIT 1`
+
+--disable_query_log
+--eval KILL QUERY $applier_thread
+--enable_query_log
+
+--let $aborter_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'system user' AND STATE = 'wsrep aborter idle' LIMIT 1`
+
+--disable_query_log
+--eval KILL QUERY $aborter_thread
+--enable_query_log
+
+--source include/restart_mysqld.inc
+
+--connection node_1
+--disconnect foo_node_1
+DROP USER foo@localhost;
+
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 1f060305d4f..920f7ac0329 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -8292,11 +8292,19 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ
It's ok to also kill DELAYED threads with KILL_CONNECTION instead of
KILL_SYSTEM_THREAD; The difference is that KILL_CONNECTION may be
faster and do a harder kill than KILL_SYSTEM_THREAD;
+
+ Note that if thread is wsrep Brute Force or applier thread we
+ allow killing it only when we're SUPER.
*/
- if (((thd->security_ctx->master_access & SUPER_ACL) ||
- thd->security_ctx->user_matches(tmp->security_ctx)) &&
- !wsrep_thd_is_BF(tmp, false))
+ if ((thd->security_ctx->master_access & SUPER_ACL) ||
+ (thd->security_ctx->user_matches(tmp->security_ctx)
+#ifdef WITH_WSREP
+ &&
+ !tmp->wsrep_applier &&
+ !wsrep_thd_is_BF(tmp, false)
+#endif
+ ))
{
tmp->awake(kill_signal);
error=0;
diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic
index 427d8937c57..d70c76701fd 100644
--- a/sql/sql_plugin_services.ic
+++ b/sql/sql_plugin_services.ic
@@ -181,7 +181,8 @@ static struct wsrep_service_st wsrep_handler = {
wsrep_trx_is_aborting,
wsrep_trx_order_before,
wsrep_unlock_rollback,
- wsrep_set_data_home_dir
+ wsrep_set_data_home_dir,
+ wsrep_thd_is_applier,
};
static struct thd_specifics_service_st thd_specifics_handler=
diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc
index 795e2d19252..e2a4dcf3bad 100644
--- a/sql/wsrep_dummy.cc
+++ b/sql/wsrep_dummy.cc
@@ -20,6 +20,9 @@
my_bool wsrep_thd_is_BF(THD *, my_bool)
{ return 0; }
+my_bool wsrep_thd_is_applier(THD *)
+{ return 0; }
+
int wsrep_trx_order_before(THD *, THD *)
{ return 0; }
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index ee8509e3fa2..82415691b3f 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -2470,7 +2470,6 @@ extern "C" void wsrep_thd_set_exec_mode(THD *thd, enum wsrep_exec_mode mode)
thd->wsrep_exec_mode= mode;
}
-
extern "C" void wsrep_thd_set_query_state(
THD *thd, enum wsrep_query_state state)
{
diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc
index 551e710cfeb..91f0e1e8d8a 100644
--- a/sql/wsrep_thd.cc
+++ b/sql/wsrep_thd.cc
@@ -596,6 +596,15 @@ my_bool wsrep_thd_is_BF(THD *thd, my_bool sync)
return status;
}
+my_bool wsrep_thd_is_applier(THD *thd)
+{
+ my_bool ret = FALSE;
+ if (thd) {
+ ret = thd->wsrep_applier;
+ }
+ return ret;
+}
+
extern "C"
my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync)
{
diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h
index 5900668f3fb..f5fcb50280c 100644
--- a/sql/wsrep_thd.h
+++ b/sql/wsrep_thd.h
@@ -37,6 +37,7 @@ int wsrep_abort_thd(void *bf_thd_ptr, void *victim_thd_ptr,
*/
extern void wsrep_thd_set_PA_safe(void *thd_ptr, my_bool safe);
extern my_bool wsrep_thd_is_BF(THD *thd, my_bool sync);
+extern my_bool wsrep_thd_is_applier(THD *thd);
extern my_bool wsrep_thd_is_wsrep(void *thd_ptr);
enum wsrep_conflict_state wsrep_thd_conflict_state(void *thd_ptr, my_bool sync);
@@ -47,6 +48,7 @@ extern "C" int wsrep_thd_in_locking_session(void *thd_ptr);
#else /* WITH_WSREP */
#define wsrep_thd_is_BF(T, S) (0)
+#define wsrep_thd_is_applier(T) (0)
#define wsrep_abort_thd(X,Y,Z) do { } while(0)
#define wsrep_create_appliers(T) do { } while(0)