mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge mysql.com:/home/mydev/mysql-5.0-bug19815
into mysql.com:/home/mydev/mysql-5.1-bug19815
This commit is contained in:
@ -50,3 +50,11 @@ Field Type Null Key Default Extra
|
||||
a int(11) YES NULL
|
||||
unlock tables;
|
||||
drop table t1;
|
||||
CREATE DATABASE mysqltest_1;
|
||||
FLUSH TABLES WITH READ LOCK;
|
||||
DROP DATABASE mysqltest_1;
|
||||
DROP DATABASE mysqltest_1;
|
||||
ERROR HY000: Can't execute the query because you have a conflicting read lock
|
||||
UNLOCK TABLES;
|
||||
DROP DATABASE mysqltest_1;
|
||||
ERROR HY000: Can't drop database 'mysqltest_1'; database doesn't exist
|
||||
|
@ -126,3 +126,38 @@ show columns from t1;
|
||||
connection locker;
|
||||
unlock tables;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Bug#19815 - CREATE/RENAME/DROP DATABASE can deadlock on a global read lock
|
||||
#
|
||||
connect (con1,localhost,root,,);
|
||||
connect (con2,localhost,root,,);
|
||||
#
|
||||
connection con1;
|
||||
CREATE DATABASE mysqltest_1;
|
||||
FLUSH TABLES WITH READ LOCK;
|
||||
#
|
||||
# With bug in place: acquire LOCK_mysql_create_table and
|
||||
# wait in wait_if_global_read_lock().
|
||||
connection con2;
|
||||
send DROP DATABASE mysqltest_1;
|
||||
--sleep 1
|
||||
#
|
||||
# With bug in place: try to acquire LOCK_mysql_create_table...
|
||||
# When fixed: Reject dropping db because of the read lock.
|
||||
connection con1;
|
||||
--error ER_CANT_UPDATE_WITH_READLOCK
|
||||
DROP DATABASE mysqltest_1;
|
||||
UNLOCK TABLES;
|
||||
#
|
||||
connection con2;
|
||||
reap;
|
||||
#
|
||||
connection default;
|
||||
disconnect con1;
|
||||
disconnect con2;
|
||||
# This must have been dropped by connection 2 already,
|
||||
# which waited until the global read lock was released.
|
||||
--error ER_DB_DROP_EXISTS
|
||||
DROP DATABASE mysqltest_1;
|
||||
|
||||
|
@ -538,16 +538,27 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
|
||||
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
|
||||
|
||||
/* do not create database if another thread is holding read lock */
|
||||
/*
|
||||
Do not create database if another thread is holding read lock.
|
||||
Wait for global read lock before acquiring LOCK_mysql_create_db.
|
||||
After wait_if_global_read_lock() we have protection against another
|
||||
global read lock. If we would acquire LOCK_mysql_create_db first,
|
||||
another thread could step in and get the global read lock before we
|
||||
reach wait_if_global_read_lock(). If this thread tries the same as we
|
||||
(admin a db), it would then go and wait on LOCK_mysql_create_db...
|
||||
Furthermore wait_if_global_read_lock() checks if the current thread
|
||||
has the global read lock and refuses the operation with
|
||||
ER_CANT_UPDATE_WITH_READLOCK if applicable.
|
||||
*/
|
||||
if (wait_if_global_read_lock(thd, 0, 1))
|
||||
{
|
||||
error= -1;
|
||||
goto exit2;
|
||||
}
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
|
||||
|
||||
/* Check directory */
|
||||
path_len= build_table_filename(path, sizeof(path), db, "", "");
|
||||
path[path_len-1]= 0; // Remove last '/' from path
|
||||
@ -655,9 +666,9 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
|
||||
}
|
||||
|
||||
exit:
|
||||
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
|
||||
start_waiting_global_read_lock(thd);
|
||||
exit2:
|
||||
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
@ -671,12 +682,23 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
|
||||
int error= 0;
|
||||
DBUG_ENTER("mysql_alter_db");
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
|
||||
|
||||
/* do not alter database if another thread is holding read lock */
|
||||
/*
|
||||
Do not alter database if another thread is holding read lock.
|
||||
Wait for global read lock before acquiring LOCK_mysql_create_db.
|
||||
After wait_if_global_read_lock() we have protection against another
|
||||
global read lock. If we would acquire LOCK_mysql_create_db first,
|
||||
another thread could step in and get the global read lock before we
|
||||
reach wait_if_global_read_lock(). If this thread tries the same as we
|
||||
(admin a db), it would then go and wait on LOCK_mysql_create_db...
|
||||
Furthermore wait_if_global_read_lock() checks if the current thread
|
||||
has the global read lock and refuses the operation with
|
||||
ER_CANT_UPDATE_WITH_READLOCK if applicable.
|
||||
*/
|
||||
if ((error=wait_if_global_read_lock(thd,0,1)))
|
||||
goto exit2;
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
|
||||
|
||||
/*
|
||||
Recreate db options file: /dbpath/.db.opt
|
||||
We pass MY_DB_OPT_FILE as "extension" to avoid
|
||||
@ -721,9 +743,9 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
|
||||
send_ok(thd, result);
|
||||
|
||||
exit:
|
||||
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
|
||||
start_waiting_global_read_lock(thd);
|
||||
exit2:
|
||||
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
@ -755,15 +777,26 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
|
||||
TABLE_LIST* dropped_tables= 0;
|
||||
DBUG_ENTER("mysql_rm_db");
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
|
||||
|
||||
/* do not drop database if another thread is holding read lock */
|
||||
/*
|
||||
Do not drop database if another thread is holding read lock.
|
||||
Wait for global read lock before acquiring LOCK_mysql_create_db.
|
||||
After wait_if_global_read_lock() we have protection against another
|
||||
global read lock. If we would acquire LOCK_mysql_create_db first,
|
||||
another thread could step in and get the global read lock before we
|
||||
reach wait_if_global_read_lock(). If this thread tries the same as we
|
||||
(admin a db), it would then go and wait on LOCK_mysql_create_db...
|
||||
Furthermore wait_if_global_read_lock() checks if the current thread
|
||||
has the global read lock and refuses the operation with
|
||||
ER_CANT_UPDATE_WITH_READLOCK if applicable.
|
||||
*/
|
||||
if (wait_if_global_read_lock(thd, 0, 1))
|
||||
{
|
||||
error= -1;
|
||||
goto exit2;
|
||||
}
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
|
||||
|
||||
length= build_table_filename(path, sizeof(path), db, "", "");
|
||||
strmov(path+length, MY_DB_OPT_FILE); // Append db option file name
|
||||
del_dbopt(path); // Remove dboption hash entry
|
||||
@ -872,7 +905,6 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
|
||||
exit:
|
||||
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
|
||||
(void)evex_drop_db_events(thd, db); /* QQ Ignore errors for now */
|
||||
start_waiting_global_read_lock(thd);
|
||||
/*
|
||||
If this database was the client's selected database, we silently change the
|
||||
client's selected database to nothing (to have an empty SELECT DATABASE()
|
||||
@ -901,9 +933,9 @@ exit:
|
||||
thd->db= 0;
|
||||
thd->db_length= 0;
|
||||
}
|
||||
exit2:
|
||||
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
|
||||
|
||||
start_waiting_global_read_lock(thd);
|
||||
exit2:
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user