diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-05-12 10:13:00 +0300 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2020-06-17 20:38:32 +0200 |
commit | 2dcad36f7085542bca32feef20843a0b01671c52 (patch) | |
tree | 63d40197b2410ebb484a74b750fd13e85496288f | |
parent | f9f968557f9c632a083acabb3578631ce0d1c4f6 (diff) | |
download | mariadb-git-bb-10.2-27snc1.tar.gz |
MDEV-22529 thd_query_safe() isn’t, causing InnoDB to hangbb-10.2-27snc1
The function thd_query_safe() is used in the implementation of the
following INFORMATION_SCHEMA views:
information_schema.innodb_trx
information_schema.innodb_locks
information_schema.innodb_lock_waits
information_schema.rocksdb_trx
The implementation of the InnoDB views is in trx_i_s_common_fill_table().
This function invokes trx_i_s_possibly_fetch_data_into_cache(),
which will acquire lock_sys->mutex and trx_sys->mutex in order to
protect the set of active transactions and explicit locks.
While holding those mutexes, it will traverse the collection of
InnoDB transactions. For each transaction, thd_query_safe() will be
invoked.
When called via trx_i_s_common_fill_table(), thd_query_safe()
is acquiring THD::LOCK_thd_data while holding the InnoDB locks.
This will cause a deadlock with THD::awake() (such as executing
KILL QUERY), because THD::awake() could invoke lock_trx_handle_wait(),
which attempts to acquire lock_sys->mutex while already holding
THD::lock_thd_data.
thd_query_safe(): Invoke mysql_mutex_trylock() instead of
mysql_mutex_lock(). Return the empty string if the mutex
cannot be acquired without waiting.
-rw-r--r-- | sql/sql_class.cc | 18 |
1 files changed, 14 insertions, 4 deletions
diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 20366742084..a67a8b8e143 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4525,6 +4525,7 @@ extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd) @param buflen Length of the buffer @return Length of the query + @retval 0 if LOCK_thd_data cannot be acquired without waiting @note This function is thread safe as the query string is accessed under mutex protection and the string is copied @@ -4533,10 +4534,19 @@ extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd) extern "C" size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen) { - mysql_mutex_lock(&thd->LOCK_thd_data); - size_t len= MY_MIN(buflen - 1, thd->query_length()); - memcpy(buf, thd->query(), len); - mysql_mutex_unlock(&thd->LOCK_thd_data); + size_t len= 0; + /* InnoDB invokes this function while holding internal mutexes. + THD::awake() will hold LOCK_thd_data while invoking an InnoDB + function that would acquire the internal mutex. Because this + function is a non-essential part of information_schema view output, + we will break the deadlock by avoiding a mutex wait here + and returning the empty string if a wait would be needed. */ + if (!mysql_mutex_trylock(&thd->LOCK_thd_data)) + { + len= MY_MIN(buflen - 1, thd->query_length()); + memcpy(buf, thd->query(), len); + mysql_mutex_unlock(&thd->LOCK_thd_data); + } buf[len]= '\0'; return len; } |