Loading mysql-test/r/flush.result +7 −0 Original line number Diff line number Diff line Loading @@ -48,3 +48,10 @@ lock table t1 read, t2 read, t3 read; flush tables with read lock; unlock tables; drop table t1, t2, t3; create table t1 (c1 int); create table t2 (c1 int); lock table t1 write; flush tables with read lock; insert into t2 values(1); unlock tables; drop table t1, t2; mysql-test/r/lock_multi.result +16 −0 Original line number Diff line number Diff line Loading @@ -43,3 +43,19 @@ Field Type Null Key Default Extra a int(11) YES NULL unlock tables; drop table t1; use mysql; LOCK TABLES columns_priv WRITE, db WRITE, host WRITE, user WRITE; FLUSH TABLES; use mysql; SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1; OPTIMIZE TABLES columns_priv, db, host, user; Table Op Msg_type Msg_text mysql.columns_priv optimize status OK mysql.db optimize status OK mysql.host optimize status OK mysql.user optimize status OK UNLOCK TABLES; Select_priv N use test; use test; mysql-test/t/flush.test +40 −0 Original line number Diff line number Diff line Loading @@ -102,3 +102,43 @@ unlock tables; drop table t1, t2, t3; # End of 4.1 tests # # Test of deadlock problem when doing FLUSH TABLE with read lock # (Bug was in NTPL threads in Linux when using different mutex while # waiting for a condtion variable) create table t1 (c1 int); create table t2 (c1 int); connect (con1,localhost,root,,); connect (con3,localhost,root,,); connection con1; lock table t1 write; connection con2; send flush tables with read lock; --sleep 1 connection con3; send insert into t2 values(1); --sleep 1 connection con1; unlock tables; disconnect con1; connection con2; reap; disconnect con2; connection con3; # It hangs here (insert into t2 does not end). reap; disconnect con3; connection default; drop table t1, t2; # End of 5.0 tests mysql-test/t/lock_multi.test +32 −0 Original line number Diff line number Diff line Loading @@ -107,3 +107,35 @@ show columns from t1; connection locker; unlock tables; drop table t1; # # Bug#16986 - Deadlock condition with MyISAM tables # connection locker; use mysql; LOCK TABLES columns_priv WRITE, db WRITE, host WRITE, user WRITE; FLUSH TABLES; --sleep 1 # connection reader; use mysql; #NOTE: This must be a multi-table select, otherwise the deadlock will not occur send SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1; --sleep 1 # connection locker; # Make test case independent from earlier grants. --replace_result "Table is already up to date" "OK" OPTIMIZE TABLES columns_priv, db, host, user; UNLOCK TABLES; # connection reader; reap; use test; # connection locker; use test; # connection default; # End of 5.0 tests sql/lock.cc +25 −9 Original line number Diff line number Diff line Loading @@ -1138,8 +1138,9 @@ bool lock_global_read_lock(THD *thd) if (!thd->global_read_lock) { const char *old_message; (void) pthread_mutex_lock(&LOCK_global_read_lock); const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock, old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock, "Waiting to get readlock"); DBUG_PRINT("info", ("waiting_for: %d protect_against: %d", Loading @@ -1147,7 +1148,7 @@ bool lock_global_read_lock(THD *thd) waiting_for_read_lock++; while (protect_against_global_read_lock && !thd->killed) pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock); pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock); waiting_for_read_lock--; if (thd->killed) { Loading @@ -1169,9 +1170,15 @@ bool lock_global_read_lock(THD *thd) DBUG_RETURN(0); } void unlock_global_read_lock(THD *thd) { uint tmp; DBUG_ENTER("unlock_global_read_lock"); DBUG_PRINT("info", ("global_read_lock: %u global_read_lock_blocks_commit: %u", global_read_lock, global_read_lock_blocks_commit)); pthread_mutex_lock(&LOCK_global_read_lock); tmp= --global_read_lock; if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT) Loading @@ -1179,8 +1186,13 @@ void unlock_global_read_lock(THD *thd) pthread_mutex_unlock(&LOCK_global_read_lock); /* Send the signal outside the mutex to avoid a context switch */ if (!tmp) pthread_cond_broadcast(&COND_refresh); { DBUG_PRINT("signal", ("Broadcasting COND_global_read_lock")); pthread_cond_broadcast(&COND_global_read_lock); } thd->global_read_lock= 0; DBUG_VOID_RETURN; } #define must_wait (global_read_lock && \ Loading Loading @@ -1218,11 +1230,15 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, */ DBUG_RETURN(is_not_commit); } old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock, old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock, "Waiting for release of readlock"); while (must_wait && ! thd->killed && (!abort_on_refresh || thd->version == refresh_version)) (void) pthread_cond_wait(&COND_refresh,&LOCK_global_read_lock); { DBUG_PRINT("signal", ("Waiting for COND_global_read_lock")); (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock); DBUG_PRINT("signal", ("Got COND_global_read_lock")); } if (thd->killed) result=1; } Loading Loading @@ -1251,7 +1267,7 @@ void start_waiting_global_read_lock(THD *thd) (waiting_for_read_lock || global_read_lock_blocks_commit)); (void) pthread_mutex_unlock(&LOCK_global_read_lock); if (tmp) pthread_cond_broadcast(&COND_refresh); pthread_cond_broadcast(&COND_global_read_lock); DBUG_VOID_RETURN; } Loading @@ -1273,10 +1289,10 @@ bool make_global_read_lock_block_commit(THD *thd) /* For testing we set up some blocking, to see if we can be killed */ DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop", protect_against_global_read_lock++;); old_message= thd->enter_cond(&COND_refresh, &LOCK_global_read_lock, old_message= thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock, "Waiting for all running commits to finish"); while (protect_against_global_read_lock && !thd->killed) pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock); pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock); DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop", protect_against_global_read_lock--;); if ((error= test(thd->killed))) Loading Loading
mysql-test/r/flush.result +7 −0 Original line number Diff line number Diff line Loading @@ -48,3 +48,10 @@ lock table t1 read, t2 read, t3 read; flush tables with read lock; unlock tables; drop table t1, t2, t3; create table t1 (c1 int); create table t2 (c1 int); lock table t1 write; flush tables with read lock; insert into t2 values(1); unlock tables; drop table t1, t2;
mysql-test/r/lock_multi.result +16 −0 Original line number Diff line number Diff line Loading @@ -43,3 +43,19 @@ Field Type Null Key Default Extra a int(11) YES NULL unlock tables; drop table t1; use mysql; LOCK TABLES columns_priv WRITE, db WRITE, host WRITE, user WRITE; FLUSH TABLES; use mysql; SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1; OPTIMIZE TABLES columns_priv, db, host, user; Table Op Msg_type Msg_text mysql.columns_priv optimize status OK mysql.db optimize status OK mysql.host optimize status OK mysql.user optimize status OK UNLOCK TABLES; Select_priv N use test; use test;
mysql-test/t/flush.test +40 −0 Original line number Diff line number Diff line Loading @@ -102,3 +102,43 @@ unlock tables; drop table t1, t2, t3; # End of 4.1 tests # # Test of deadlock problem when doing FLUSH TABLE with read lock # (Bug was in NTPL threads in Linux when using different mutex while # waiting for a condtion variable) create table t1 (c1 int); create table t2 (c1 int); connect (con1,localhost,root,,); connect (con3,localhost,root,,); connection con1; lock table t1 write; connection con2; send flush tables with read lock; --sleep 1 connection con3; send insert into t2 values(1); --sleep 1 connection con1; unlock tables; disconnect con1; connection con2; reap; disconnect con2; connection con3; # It hangs here (insert into t2 does not end). reap; disconnect con3; connection default; drop table t1, t2; # End of 5.0 tests
mysql-test/t/lock_multi.test +32 −0 Original line number Diff line number Diff line Loading @@ -107,3 +107,35 @@ show columns from t1; connection locker; unlock tables; drop table t1; # # Bug#16986 - Deadlock condition with MyISAM tables # connection locker; use mysql; LOCK TABLES columns_priv WRITE, db WRITE, host WRITE, user WRITE; FLUSH TABLES; --sleep 1 # connection reader; use mysql; #NOTE: This must be a multi-table select, otherwise the deadlock will not occur send SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1; --sleep 1 # connection locker; # Make test case independent from earlier grants. --replace_result "Table is already up to date" "OK" OPTIMIZE TABLES columns_priv, db, host, user; UNLOCK TABLES; # connection reader; reap; use test; # connection locker; use test; # connection default; # End of 5.0 tests
sql/lock.cc +25 −9 Original line number Diff line number Diff line Loading @@ -1138,8 +1138,9 @@ bool lock_global_read_lock(THD *thd) if (!thd->global_read_lock) { const char *old_message; (void) pthread_mutex_lock(&LOCK_global_read_lock); const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock, old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock, "Waiting to get readlock"); DBUG_PRINT("info", ("waiting_for: %d protect_against: %d", Loading @@ -1147,7 +1148,7 @@ bool lock_global_read_lock(THD *thd) waiting_for_read_lock++; while (protect_against_global_read_lock && !thd->killed) pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock); pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock); waiting_for_read_lock--; if (thd->killed) { Loading @@ -1169,9 +1170,15 @@ bool lock_global_read_lock(THD *thd) DBUG_RETURN(0); } void unlock_global_read_lock(THD *thd) { uint tmp; DBUG_ENTER("unlock_global_read_lock"); DBUG_PRINT("info", ("global_read_lock: %u global_read_lock_blocks_commit: %u", global_read_lock, global_read_lock_blocks_commit)); pthread_mutex_lock(&LOCK_global_read_lock); tmp= --global_read_lock; if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT) Loading @@ -1179,8 +1186,13 @@ void unlock_global_read_lock(THD *thd) pthread_mutex_unlock(&LOCK_global_read_lock); /* Send the signal outside the mutex to avoid a context switch */ if (!tmp) pthread_cond_broadcast(&COND_refresh); { DBUG_PRINT("signal", ("Broadcasting COND_global_read_lock")); pthread_cond_broadcast(&COND_global_read_lock); } thd->global_read_lock= 0; DBUG_VOID_RETURN; } #define must_wait (global_read_lock && \ Loading Loading @@ -1218,11 +1230,15 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, */ DBUG_RETURN(is_not_commit); } old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock, old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock, "Waiting for release of readlock"); while (must_wait && ! thd->killed && (!abort_on_refresh || thd->version == refresh_version)) (void) pthread_cond_wait(&COND_refresh,&LOCK_global_read_lock); { DBUG_PRINT("signal", ("Waiting for COND_global_read_lock")); (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock); DBUG_PRINT("signal", ("Got COND_global_read_lock")); } if (thd->killed) result=1; } Loading Loading @@ -1251,7 +1267,7 @@ void start_waiting_global_read_lock(THD *thd) (waiting_for_read_lock || global_read_lock_blocks_commit)); (void) pthread_mutex_unlock(&LOCK_global_read_lock); if (tmp) pthread_cond_broadcast(&COND_refresh); pthread_cond_broadcast(&COND_global_read_lock); DBUG_VOID_RETURN; } Loading @@ -1273,10 +1289,10 @@ bool make_global_read_lock_block_commit(THD *thd) /* For testing we set up some blocking, to see if we can be killed */ DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop", protect_against_global_read_lock++;); old_message= thd->enter_cond(&COND_refresh, &LOCK_global_read_lock, old_message= thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock, "Waiting for all running commits to finish"); while (protect_against_global_read_lock && !thd->killed) pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock); pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock); DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop", protect_against_global_read_lock--;); if ((error= test(thd->killed))) Loading