From d95e57a328bee96c9a7069aa6c9302771c341322 Mon Sep 17 00:00:00 2001 From: prabakaran thirumalai Date: Tue, 30 Jul 2013 09:44:11 +0530 Subject: [PATCH] Bug#17083851 BACKPORT BUG#11765744 TO 5.1, 5.5 AND 5.6 Description: Original fix Bug#11765744 changed mutex to read write lock to avoid multiple recursive lock acquire operation on LOCK_status mutex. On Windows, locking read-write lock recursively is not safe. Slim read-write locks, which MySQL uses if they are supported by Windows version, do not support recursion according to their documentation. For our own implementation of read-write lock, which is used in cases when Windows version doesn't support SRW, recursive locking of read-write lock can easily lead to deadlock if there are concurrent lock requests. Fix: This patch reverts the previous fix for bug#11765744 that used read-write locks. Instead problem of recursive locking for LOCK_status mutex is solved by tracking recursion level using counter in THD object and acquiring lock only once when we enter fill_status() function first time. --- sql/sql_class.cc | 1 + sql/sql_class.h | 11 +++++++++++ sql/sql_show.cc | 10 ++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 80bd4eff457..d71da6403ae 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -605,6 +605,7 @@ THD::THD() Open_tables_state(refresh_version), rli_fake(NULL), rli_slave(NULL), lock_id(&main_lock_id), user_time(0), in_sub_stmt(0), + fill_status_recursion_level(0), sql_log_bin_toplevel(false), binlog_table_maps(0), binlog_flags(0UL), table_map_for_update(0), diff --git a/sql/sql_class.h b/sql/sql_class.h index 4543f9ef7a2..0942e9274b1 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1443,6 +1443,17 @@ public: /* <> 0 if we are inside of trigger or stored function. */ uint in_sub_stmt; + + /** + Used by fill_status() to avoid acquiring LOCK_status mutex twice + when this function is called recursively (e.g. queries + that contains SELECT on I_S.GLOBAL_STATUS with subquery on the + same I_S table). + Incremented each time fill_status() function is entered and + decremented each time before it returns from the function. + */ + uint fill_status_recursion_level; + /* TRUE when the current top has SQL_LOG_BIN ON */ bool sql_log_bin_toplevel; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 7859d7f61e3..a72ca4d1bfc 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5569,14 +5569,20 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond) tmp1= &thd->status_var; } - pthread_mutex_lock(&LOCK_status); + /* + Avoid recursive acquisition of LOCK_status in cases when WHERE clause + represented by "cond" contains subquery on I_S.SESSION/GLOBAL_STATUS. + */ + if (thd->fill_status_recursion_level++ == 0) + pthread_mutex_lock(&LOCK_status); if (option_type == OPT_GLOBAL) calc_sum_of_all_status(&tmp); res= show_status_array(thd, wild, (SHOW_VAR *)all_status_vars.buffer, option_type, tmp1, "", tables->table, upper_case_names, cond); - pthread_mutex_unlock(&LOCK_status); + if (thd->fill_status_recursion_level-- == 1) + pthread_mutex_unlock(&LOCK_status); DBUG_RETURN(res); }