diff options
author | sjaakola <seppo.jaakola@iki.fi> | 2021-09-15 09:16:44 +0300 |
---|---|---|
committer | Jan Lindström <jan.lindstrom@mariadb.com> | 2021-09-23 15:26:19 +0300 |
commit | da9a37bf4181d92699af40fdd82ab5b7ae1bf307 (patch) | |
tree | a732bc90cef6e3e439254c440bcd46fdbd2dd93a /sql/sql_parse.cc | |
parent | c8126d173c57a3b2419cd39d8ed546f8fc8a01f7 (diff) | |
download | mariadb-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/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 42 |
1 files changed, 38 insertions, 4 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index af30aa6fde9..0a0aef66507 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -9216,7 +9216,8 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields, @param query_id If true, search by query_id instead of thread_id @return NULL - not found - pointer - thread found, and its LOCK_thd_kill is locked. + pointer - thread found, and its LOCK_thd_data and + LOCK_thd_kill is locked. */ struct find_thread_callback_arg @@ -9234,6 +9235,7 @@ static my_bool find_thread_callback(THD *thd, find_thread_callback_arg *arg) if (arg->id == (arg->query_id ? thd->query_id : (longlong) thd->thread_id)) { mysql_mutex_lock(&thd->LOCK_thd_kill); // Lock from delete + mysql_mutex_lock(&thd->LOCK_thd_data); // Lock from concurrent usage arg->thd= thd; return 1; } @@ -9248,7 +9250,6 @@ THD *find_thread_by_id(longlong id, bool query_id) return arg.thd; } - mysql_mutex_lock(&thd->LOCK_thd_data); /** kill one thread. @@ -9292,7 +9293,6 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ faster and do a harder kill than KILL_SYSTEM_THREAD; */ - mysql_mutex_lock(&tmp->LOCK_thd_data); // for various wsrep* checks below #ifdef WITH_WSREP if (((thd->security_ctx->master_access & PRIV_KILL_OTHER_USER_PROCESS) || thd->security_ctx->user_matches(tmp->security_ctx)) && @@ -9324,8 +9324,8 @@ kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type typ else error= (type == KILL_TYPE_QUERY ? ER_KILL_QUERY_DENIED_ERROR : ER_KILL_DENIED_ERROR); - mysql_mutex_unlock(&tmp->LOCK_thd_data); } + mysql_mutex_unlock(&tmp->LOCK_thd_data); mysql_mutex_unlock(&tmp->LOCK_thd_kill); DBUG_PRINT("exit", ("%d", error)); DBUG_RETURN(error); @@ -9438,6 +9438,18 @@ static void sql_kill(THD *thd, longlong id, killed_state state, killed_type type) { uint error; +#ifdef WITH_WSREP + if (WSREP(thd)) + { + WSREP_DEBUG("sql_kill called"); + if (thd->wsrep_applier) + { + WSREP_DEBUG("KILL in applying, bailing out here"); + return; + } + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + } +#endif /* WITH_WSREP */ if (likely(!(error= kill_one_thread(thd, id, state, type)))) { if (!thd->killed) @@ -9447,6 +9459,11 @@ void sql_kill(THD *thd, longlong id, killed_state state, killed_type type) } else my_error(error, MYF(0), id); +#ifdef WITH_WSREP + return; + wsrep_error_label: + my_error(ER_CANNOT_USER, MYF(0), wsrep_thd_query(thd)); +#endif /* WITH_WSREP */ } @@ -9455,6 +9472,18 @@ sql_kill_user(THD *thd, LEX_USER *user, killed_state state) { uint error; ha_rows rows; +#ifdef WITH_WSREP + if (WSREP(thd)) + { + WSREP_DEBUG("sql_kill_user called"); + if (thd->wsrep_applier) + { + WSREP_DEBUG("KILL in applying, bailing out here"); + return; + } + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) + } +#endif /* WITH_WSREP */ if (likely(!(error= kill_threads_for_user(thd, user, state, &rows)))) my_ok(thd, rows); else @@ -9465,6 +9494,11 @@ sql_kill_user(THD *thd, LEX_USER *user, killed_state state) */ my_error(error, MYF(0), user->host.str, user->user.str); } +#ifdef WITH_WSREP + return; + wsrep_error_label: + my_error(ER_CANNOT_USER, MYF(0), user->user.str); +#endif /* WITH_WSREP */ } |