Bug #35395 Object services for enumerating view dependencies make server deadlock.
Submitted: 18 Mar 2008 13:14 Modified: 18 Sep 2008 5:56
Reporter: Rafal Somla Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Locking Severity:S3 (Non-critical)
Version:6.0 source OS:Any
Assigned to: Alexander Nozdrin CPU Architecture:Any

[18 Mar 2008 13:14] Rafal Somla
Description:
There is function obs::get_view_base_views() in si_objects.{h,cc}. When I use this function some tables get locked which makes following SQL statements hang, waiting for the locks to be removed.

How to repeat:
Modify the main 6.0 tree using the patch below. It calls the object services function before proceeding with database drop.

Then compile the tree and run simple test which creates database, creates a view in it and then drops it. Like this:

CREATE DATABASE db1;
USE db1;
CREATE table t1(a int);
CREATE VIEW v1 AS SELECT * FROM t1;
DROP DATABASE db1;

Test will hang on DROP DATABASE. When run under gdb, one can interrupt execution and see that the thread executing DROP DATABASE hangs waiting on lock condition. Here is stack trace:

#0  0x40029c01 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib/tls/libpthread.so.0
#1  0x086e6dd8 in safe_cond_wait (cond=0x8a24000, mp=0x8a23ac0, file=0x882dbc9 "sql_base.cc", line=2222) at thr_mutex.c:237
#2  0x082e5c03 in wait_for_condition (thd=0x8bd95e0, mutex=0x8a23ac0, cond=0x8a24000) at sql_base.cc:2222
#3  0x0828d7c6 in wait_for_locked_table_names (thd=0x8bd95e0, table_list=0x8c1dc40) at lock.cc:1115
#4  0x0828dcbd in lock_table_names (thd=0x8bd95e0, table_list=0x8c1dc40) at lock.cc:1156
#5  0x0828dd1c in lock_table_names_exclusively (thd=0x8bd95e0, table_list=0x8c1dc40) at lock.cc:1187
#6  0x083e86ec in mysql_rm_table_part2 (thd=0x8bd95e0, tables=0x8c1dc40, if_exists=true, drop_temporary=false, drop_view=true, dont_log_query=true) at sql_table.cc:1585
#7  0x083d425b in mysql_rm_known_files (thd=0x8bd95e0, dirp=0x8bfdd00, db=0x8bfaca8 "db1", org_path=0x41023258 "./db1/", level=0, dropped_tables=0x410234fc) at sql_db.cc:1137
#8  0x083d5cf4 in mysql_rm_db (thd=0x8bd95e0, db=0x8bfaca8 "db1", if_exists=false, silent=false) at sql_db.cc:919
#9  0x082ac927 in mysql_execute_command (thd=0x8bd95e0) at sql_parse.cc:3355

Looking at the code one can see that mysql_rm_db removes all objects from database and while doing that, waits if any of them are locked. Apparently, the service function leaves some table/view locked and hence the deadlock.

Here is the patch modifying mysql_rm_db() function to call object services.

===== sql/sql_db.cc 1.170 vs edited =====
--- 1.170/sql/sql_db.cc 2008-03-18 14:06:36 +01:00
+++ edited/sql/sql_db.cc        2008-03-18 13:46:49 +01:00
@@ -836,6 +836,8 @@ exit2:
 }
 
 
+#include "si_objects.h"
+
 /*
   Drop all tables in a database and the database itself
 
@@ -862,6 +864,28 @@ bool mysql_rm_db(THD *thd,char *db,bool 
   uint length;
   TABLE_LIST* dropped_tables= 0;
   DBUG_ENTER("mysql_rm_db");
+
+#if TRUE
+  {
+    String db_name(db, system_charset_info);
+    obs::ObjIterator *it1= obs::get_db_views(thd, &db_name);
+    obs::Obj         *obj= it1->next();
+    
+    if (obj)
+    {
+      obs::ObjIterator *it2= obs::get_view_base_views(current_thd, 
+                                                      obj->get_db_name(), 
+                                                      obj->get_name());
+      obs::Obj *bv;
+      while ((bv= it2->next()))
+        delete bv;
+      delete it2;
+    }
+  
+    delete obj;
+    delete it1;
+  }
+#endif
 
   /*
     Do not drop database if another thread is holding read lock.
[29 Apr 2008 14:17] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/46186

ChangeSet@1.2613, 2008-04-29 18:22:41+04:00, anozdrin@quad.opbmk +1 -0
  A fix for Bug#35395: Object services for enumerating view
  dependencies make server deadlock.
  
  The problem was that ViewBaseObjectsIterator::create() method opened
  a view and its underlying tables in order to get a list of all
  the tables on which view depends without closing them afterwards.
  This happened due to false assumption that THD::~THD() closes all
  the tables which were open for THD object being destroyed.
  
  The fix is to call close_thread_tables() explicitly. Also, since
  we're interested only in meta-data, there is no need to lock tables.
  So, open_tables() can be used instead of open_and_lock_tables().
  
  A test case is not provided because there is no easy way to test
  this without changing the source code.
[29 Apr 2008 14:20] Alexander Nozdrin
Pushed into 6.0-backup.
[14 Sep 2008 2:29] Bugs System
Pushed into 6.0.6-alpha  (revid:sp1r-anozdrin/alik@quad.opbmk-20080429142241-05042) (version source revid:hakan@mysql.com-20080716160135-l7310heud233kagu) (pib:3)
[18 Sep 2008 5:56] Paul DuBois
Noted in 6.0.6 changelog.

The method for enumerating view dependencies could cause the server
to deadlock.