1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00

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.
This commit is contained in:
Jon Olav Hauglid
2010-06-26 19:36:00 +02:00
parent 2b2e09086c
commit 9fa66b6440
3 changed files with 102 additions and 0 deletions

View File

@@ -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);