[MDEV-6774] Deadlock between SELECT, DROP TABLE, SHOW STATUS and SET @@global.log_output Created: 2014-09-24  Updated: 2014-10-01  Resolved: 2014-10-01

Status: Closed
Project: MariaDB Server
Component/s: OTHER
Affects Version/s: 5.5.39
Fix Version/s: 5.5.40

Type: Bug Priority: Major
Reporter: Sergey Vojtovich Assignee: Sergey Vojtovich
Resolution: Fixed Votes: 0
Labels: None

Issue Links:
PartOf
is part of MDEV-5089 possible deadlocks between rwlocks an... Closed

 Description   

Deadlock chain:

rdlock(LOCK_logger)                -> lock(LOCK_open)                    SELECT 1
lock(LOCK_open)                    -> lock(LOCK_status)                  DROP TABLE t1
lock(LOCK_status)                  -> lock(LOCK_global_system_variables) SHOW STATUS
lock(LOCK_global_system_variables) -> wrlock(LOCK_logger)                SET @@global.log_output=DEFAULT

MTR test to reproduce this deadlock:

--source include/have_example_plugin.inc
 
SET @@global.log_output='TABLE';
INSTALL SONAME 'ha_example';
CREATE TABLE t1(a int) ENGINE=EXAMPLE;
SELECT * FROM t1;
UNINSTALL SONAME 'ha_example';
 
connect(con1, localhost, root,,);
connect(con2, localhost, root,,);
connect(con3, localhost, root,,);
 
connection con1;
SET debug_sync='fix_log_output SIGNAL ready WAIT_FOR go';
send SET @@global.log_output=DEFAULT;
 
connection con2;
SET debug_sync='now WAIT_FOR ready';
SET debug_sync='fill_status SIGNAL ready';
send SHOW STATUS LIKE 'slave_open_temp_tables';
 
connection con3;
SET debug_sync='now WAIT_FOR ready';
SET debug_sync='remove_status_vars SIGNAL ready';
send DROP TABLE t1;
 
connection default;
SELECT 1;
 
connection con1;
reap;
disconnect con1;
 
connection con2;
reap;
disconnect con2;
 
connection con3;
reap;
disconnect con3;
 
connection default;
SET debug_sync='RESET';

Debug sync points:

=== modified file 'sql/log.cc'
--- sql/log.cc	2014-08-02 19:26:16 +0000
+++ sql/log.cc	2014-09-24 11:02:19 +0000
@@ -600,6 +600,11 @@ void Log_to_csv_event_handler::cleanup()
   ulonglong save_thd_options;
   bool save_time_zone_used;
   DBUG_ENTER("log_general");
+  if (!strncmp(sql_text, "SELECT 1", sql_text_len))
+  {
+    debug_sync_set_action(thd, STRING_WITH_LEN("now WAIT_FOR ready"));
+    debug_sync_set_action(thd, STRING_WITH_LEN("now SIGNAL go"));
+  }
 
   /*
     CSV uses TIME_to_timestamp() internally if table needs to be repaired
 
=== modified file 'sql/sql_show.cc'
--- sql/sql_show.cc	2014-09-12 06:41:35 +0000
+++ sql/sql_show.cc	2014-09-24 09:58:42 +0000
@@ -2543,6 +2543,7 @@ void remove_status_vars(SHOW_VAR *list)
 {
   if (status_vars_inited)
   {
+    DEBUG_SYNC(current_thd, "remove_status_vars");
     mysql_mutex_lock(&LOCK_status);
     SHOW_VAR *all= dynamic_element(&all_status_vars, 0, SHOW_VAR *);
 
@@ -6986,6 +6987,7 @@ int fill_status(THD *thd, TABLE_LIST *ta
     partial_cond->val_int();
 
   mysql_mutex_lock(&LOCK_status);
+  DEBUG_SYNC(thd, "fill_status");
   if (option_type == OPT_GLOBAL)
     calc_sum_of_all_status(&tmp);
   res= show_status_array(thd, wild,
 
=== modified file 'sql/sys_vars.cc'
--- sql/sys_vars.cc	2014-08-02 19:26:16 +0000
+++ sql/sys_vars.cc	2014-09-24 10:48:38 +0000
@@ -3246,6 +3246,7 @@ static bool check_not_empty_set(sys_var
 }
 static bool fix_log_output(sys_var *self, THD *thd, enum_var_type type)
 {
+  DEBUG_SYNC(thd, "fix_log_output");
   logger.lock_exclusive();
   logger.init_slow_log(log_output_options);
   logger.init_general_log(log_output_options);
 



 Comments   
Comment by Sergey Vojtovich [ 2014-09-25 ]

Sergei, please review fix for this bug.

Comment by Sergei Golubchik [ 2014-09-30 ]

ok to push, thanks

Comment by Sergey Vojtovich [ 2014-10-01 ]

Fixed in 5.5.40:

revno: 4297
revision-id: svoj@mariadb.org-20140925064311-lq46fqxnnwyfliu5
parent: svoj@mariadb.org-20140918154506-24bkasfcnmww3w03
committer: Sergey Vojtovich <svoj@mariadb.org>
branch nick: 5.5
timestamp: Thu 2014-09-25 10:43:11 +0400
message:
  MDEV-6774 - Deadlock between SELECT, DROP TABLE, SHOW STATUS and
              SET @@global.log_output
 
  Deadlock chain:
  rdlock(LOCK_logger) -> lock(LOCK_open)     SELECT 1
  lock(LOCK_open)     -> lock(LOCK_status)   DROP TABLE t1
  lock(LOCK_status)   -> lock(LOCK_g_s_v)    SHOW STATUS
  lock(LOCK_g_s_)     -> wrlock(LOCK_logger) SET @@global.log_output=DEFAULT
 
  Fixed by removing relationship between LOCK_status and
  LOCK_global_system_variables during SHOW STATUS: we don't really need
  LOCK_global_system_variables when accessing status vars.

Generated at Thu Feb 08 07:14:29 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.