summaryrefslogtreecommitdiff
path: root/sql/sql_db.cc
diff options
context:
space:
mode:
authorJon Olav Hauglid <jon.hauglid@sun.com>2010-06-26 19:36:00 +0200
committerJon Olav Hauglid <jon.hauglid@sun.com>2010-06-26 19:36:00 +0200
commit9fa66b6440a8d0642094600b4f23a12eb3500221 (patch)
treec00b71ca650eb96a0a7ee03e1749a56339817d8f /sql/sql_db.cc
parent2b2e09086cf2b2fcbe32b2555ef51d52481487da (diff)
downloadmariadb-git-9fa66b6440a8d0642094600b4f23a12eb3500221.tar.gz
Bug #54360 Deadlock DROP/ALTER/CREATE DATABASE with open HANDLER
This deadlock happened if DROP DATABASE was blocked due to an open HANDLER table from a different connection. While DROP DATABASE is blocked, it holds the LOCK_mysql_create_db mutex. This results in a deadlock if the connection with the open HANDLER table tries to execute a CREATE/ALTER/DROP DATABASE statement as they all try to acquire LOCK_mysql_create_db. This patch makes this deadlock scenario very unlikely by closing and marking for re-open all HANDLER tables for which there are pending conflicing locks, before LOCK_mysql_create_db is acquired. However, there is still a very slight possibility that a connection could access one of these HANDLER tables between closing/marking for re-open and the acquisition of LOCK_mysql_create_db. This patch is for 5.1 only, a separate and complete fix will be made for 5.5+. Test case added to schema.test.
Diffstat (limited to 'sql/sql_db.cc')
-rw-r--r--sql/sql_db.cc36
1 files changed, 36 insertions, 0 deletions
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 0e65f97e10b..d3435b891b1 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -642,6 +642,18 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
goto exit2;
}
+ /*
+ Close and mark for re-open all HANDLER tables which are marked for flush
+ or which there are pending conflicing locks against. This is needed to
+ prevent deadlocks.
+ */
+ if (thd->handler_tables_hash.records)
+ {
+ pthread_mutex_lock(&LOCK_open);
+ mysql_ha_flush(thd);
+ pthread_mutex_unlock(&LOCK_open);
+ }
+
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
/* Check directory */
@@ -788,6 +800,18 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
if ((error=wait_if_global_read_lock(thd,0,1)))
goto exit2;
+ /*
+ Close and mark for re-open all HANDLER tables which are marked for flush
+ or which there are pending conflicing locks against. This is needed to
+ prevent deadlocks.
+ */
+ if (thd->handler_tables_hash.records)
+ {
+ pthread_mutex_lock(&LOCK_open);
+ mysql_ha_flush(thd);
+ pthread_mutex_unlock(&LOCK_open);
+ }
+
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
/*
@@ -886,6 +910,18 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
goto exit2;
}
+ /*
+ Close and mark for re-open all HANDLER tables which are marked for flush
+ or which there are pending conflicing locks against. This is needed to
+ prevent deadlocks.
+ */
+ if (thd->handler_tables_hash.records)
+ {
+ pthread_mutex_lock(&LOCK_open);
+ mysql_ha_flush(thd);
+ pthread_mutex_unlock(&LOCK_open);
+ }
+
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
length= build_table_filename(path, sizeof(path) - 1, db, "", "", 0);