Loading mysql-test/r/lock_multi.result +15 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,21 @@ Select_priv N use test; use test; CREATE TABLE t1 (c1 int); LOCK TABLE t1 WRITE; FLUSH TABLES WITH READ LOCK; CREATE TABLE t2 (c1 int); UNLOCK TABLES; UNLOCK TABLES; DROP TABLE t1, t2; CREATE TABLE t1 (c1 int); LOCK TABLE t1 WRITE; FLUSH TABLES WITH READ LOCK; CREATE TABLE t2 AS SELECT * FROM t1; ERROR HY000: Table 't2' was not locked with LOCK TABLES UNLOCK TABLES; UNLOCK TABLES; DROP TABLE t1; create table t1 (f1 int(12) unsigned not null auto_increment, primary key(f1)) engine=innodb; lock tables t1 write; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; // Loading mysql-test/t/lock_multi.test +50 −0 Original line number Diff line number Diff line Loading @@ -142,6 +142,7 @@ disconnect con2; --error ER_DB_DROP_EXISTS DROP DATABASE mysqltest_1; # # Bug#16986 - Deadlock condition with MyISAM tables # connection locker; Loading Loading @@ -170,6 +171,55 @@ connection locker; use test; # connection default; # # Test if CREATE TABLE with LOCK TABLE deadlocks. # connection writer; CREATE TABLE t1 (c1 int); LOCK TABLE t1 WRITE; # # This waits until t1 is unlocked. connection locker; send FLUSH TABLES WITH READ LOCK; --sleep 1 # # This must not block. connection writer; CREATE TABLE t2 (c1 int); UNLOCK TABLES; # # This awakes now. connection locker; reap; UNLOCK TABLES; # connection default; DROP TABLE t1, t2; # # Test if CREATE TABLE SELECT with LOCK TABLE deadlocks. # connection writer; CREATE TABLE t1 (c1 int); LOCK TABLE t1 WRITE; # # This waits until t1 is unlocked. connection locker; send FLUSH TABLES WITH READ LOCK; --sleep 1 # # This must not block. connection writer; --error 1100 CREATE TABLE t2 AS SELECT * FROM t1; UNLOCK TABLES; # # This awakes now. connection locker; reap; UNLOCK TABLES; # connection default; DROP TABLE t1; # # Bug #17264: MySQL Server freeze Loading mysys/thr_lock.c +2 −0 Original line number Diff line number Diff line Loading @@ -204,6 +204,8 @@ static void check_locks(THR_LOCK *lock, const char *where, { if ((int) data->type == (int) TL_READ_NO_INSERT) count++; /* Protect against infinite loop. */ DBUG_ASSERT(count <= lock->read_no_write_count); } if (count != lock->read_no_write_count) { Loading sql/lock.cc +39 −5 Original line number Diff line number Diff line Loading @@ -905,7 +905,7 @@ void unlock_table_name(THD *thd, TABLE_LIST *table_list) if (table_list->table) { hash_delete(&open_cache, (byte*) table_list->table); (void) pthread_cond_broadcast(&COND_refresh); broadcast_refresh(); } } Loading Loading @@ -997,9 +997,9 @@ bool lock_table_names(THD *thd, TABLE_LIST *table_list) (default 0, which will unlock all tables) NOTES One must have a lock on LOCK_open when calling this This function will send a COND_refresh signal to inform other threads that the name locks are removed One must have a lock on LOCK_open when calling this. This function will broadcast refresh signals to inform other threads that the name locks are removed. RETURN 0 ok Loading @@ -1013,7 +1013,7 @@ void unlock_table_names(THD *thd, TABLE_LIST *table_list, table != last_table; table= table->next_local) unlock_table_name(thd,table); pthread_cond_broadcast(&COND_refresh); broadcast_refresh(); } Loading Loading @@ -1304,3 +1304,37 @@ bool make_global_read_lock_block_commit(THD *thd) } /* Broadcast COND_refresh and COND_global_read_lock. SYNOPSIS broadcast_refresh() void No parameters. DESCRIPTION Due to a bug in a threading library it could happen that a signal did not reach its target. A condition for this was that the same condition variable was used with different mutexes in pthread_cond_wait(). Some time ago we changed LOCK_open to LOCK_global_read_lock in global read lock handling. So COND_refresh was used with LOCK_open and LOCK_global_read_lock. We did now also change from COND_refresh to COND_global_read_lock in global read lock handling. But now it is necessary to signal both conditions at the same time. NOTE When signalling COND_global_read_lock within the global read lock handling, it is not necessary to also signal COND_refresh. RETURN void */ void broadcast_refresh(void) { VOID(pthread_cond_broadcast(&COND_refresh)); VOID(pthread_cond_broadcast(&COND_global_read_lock)); } sql/mysql_priv.h +1 −0 Original line number Diff line number Diff line Loading @@ -1344,6 +1344,7 @@ void start_waiting_global_read_lock(THD *thd); bool make_global_read_lock_block_commit(THD *thd); bool set_protect_against_global_read_lock(void); void unset_protect_against_global_read_lock(void); void broadcast_refresh(void); /* Lock based on name */ int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list); Loading Loading
mysql-test/r/lock_multi.result +15 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,21 @@ Select_priv N use test; use test; CREATE TABLE t1 (c1 int); LOCK TABLE t1 WRITE; FLUSH TABLES WITH READ LOCK; CREATE TABLE t2 (c1 int); UNLOCK TABLES; UNLOCK TABLES; DROP TABLE t1, t2; CREATE TABLE t1 (c1 int); LOCK TABLE t1 WRITE; FLUSH TABLES WITH READ LOCK; CREATE TABLE t2 AS SELECT * FROM t1; ERROR HY000: Table 't2' was not locked with LOCK TABLES UNLOCK TABLES; UNLOCK TABLES; DROP TABLE t1; create table t1 (f1 int(12) unsigned not null auto_increment, primary key(f1)) engine=innodb; lock tables t1 write; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; // Loading
mysql-test/t/lock_multi.test +50 −0 Original line number Diff line number Diff line Loading @@ -142,6 +142,7 @@ disconnect con2; --error ER_DB_DROP_EXISTS DROP DATABASE mysqltest_1; # # Bug#16986 - Deadlock condition with MyISAM tables # connection locker; Loading Loading @@ -170,6 +171,55 @@ connection locker; use test; # connection default; # # Test if CREATE TABLE with LOCK TABLE deadlocks. # connection writer; CREATE TABLE t1 (c1 int); LOCK TABLE t1 WRITE; # # This waits until t1 is unlocked. connection locker; send FLUSH TABLES WITH READ LOCK; --sleep 1 # # This must not block. connection writer; CREATE TABLE t2 (c1 int); UNLOCK TABLES; # # This awakes now. connection locker; reap; UNLOCK TABLES; # connection default; DROP TABLE t1, t2; # # Test if CREATE TABLE SELECT with LOCK TABLE deadlocks. # connection writer; CREATE TABLE t1 (c1 int); LOCK TABLE t1 WRITE; # # This waits until t1 is unlocked. connection locker; send FLUSH TABLES WITH READ LOCK; --sleep 1 # # This must not block. connection writer; --error 1100 CREATE TABLE t2 AS SELECT * FROM t1; UNLOCK TABLES; # # This awakes now. connection locker; reap; UNLOCK TABLES; # connection default; DROP TABLE t1; # # Bug #17264: MySQL Server freeze Loading
mysys/thr_lock.c +2 −0 Original line number Diff line number Diff line Loading @@ -204,6 +204,8 @@ static void check_locks(THR_LOCK *lock, const char *where, { if ((int) data->type == (int) TL_READ_NO_INSERT) count++; /* Protect against infinite loop. */ DBUG_ASSERT(count <= lock->read_no_write_count); } if (count != lock->read_no_write_count) { Loading
sql/lock.cc +39 −5 Original line number Diff line number Diff line Loading @@ -905,7 +905,7 @@ void unlock_table_name(THD *thd, TABLE_LIST *table_list) if (table_list->table) { hash_delete(&open_cache, (byte*) table_list->table); (void) pthread_cond_broadcast(&COND_refresh); broadcast_refresh(); } } Loading Loading @@ -997,9 +997,9 @@ bool lock_table_names(THD *thd, TABLE_LIST *table_list) (default 0, which will unlock all tables) NOTES One must have a lock on LOCK_open when calling this This function will send a COND_refresh signal to inform other threads that the name locks are removed One must have a lock on LOCK_open when calling this. This function will broadcast refresh signals to inform other threads that the name locks are removed. RETURN 0 ok Loading @@ -1013,7 +1013,7 @@ void unlock_table_names(THD *thd, TABLE_LIST *table_list, table != last_table; table= table->next_local) unlock_table_name(thd,table); pthread_cond_broadcast(&COND_refresh); broadcast_refresh(); } Loading Loading @@ -1304,3 +1304,37 @@ bool make_global_read_lock_block_commit(THD *thd) } /* Broadcast COND_refresh and COND_global_read_lock. SYNOPSIS broadcast_refresh() void No parameters. DESCRIPTION Due to a bug in a threading library it could happen that a signal did not reach its target. A condition for this was that the same condition variable was used with different mutexes in pthread_cond_wait(). Some time ago we changed LOCK_open to LOCK_global_read_lock in global read lock handling. So COND_refresh was used with LOCK_open and LOCK_global_read_lock. We did now also change from COND_refresh to COND_global_read_lock in global read lock handling. But now it is necessary to signal both conditions at the same time. NOTE When signalling COND_global_read_lock within the global read lock handling, it is not necessary to also signal COND_refresh. RETURN void */ void broadcast_refresh(void) { VOID(pthread_cond_broadcast(&COND_refresh)); VOID(pthread_cond_broadcast(&COND_global_read_lock)); }
sql/mysql_priv.h +1 −0 Original line number Diff line number Diff line Loading @@ -1344,6 +1344,7 @@ void start_waiting_global_read_lock(THD *thd); bool make_global_read_lock_block_commit(THD *thd); bool set_protect_against_global_read_lock(void); void unset_protect_against_global_read_lock(void); void broadcast_refresh(void); /* Lock based on name */ int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list); Loading