Commit 4064f11a authored by monty@mysql.com's avatar monty@mysql.com

Merge bk-internal.mysql.com:/home/bk/mysql-5.0

into  mysql.com:/home/my/mysql-5.0
parents 99b1d746 7cb3df01
...@@ -48,3 +48,10 @@ lock table t1 read, t2 read, t3 read; ...@@ -48,3 +48,10 @@ lock table t1 read, t2 read, t3 read;
flush tables with read lock; flush tables with read lock;
unlock tables; unlock tables;
drop table t1, t2, t3; 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;
...@@ -43,3 +43,19 @@ Field Type Null Key Default Extra ...@@ -43,3 +43,19 @@ Field Type Null Key Default Extra
a int(11) YES NULL a int(11) YES NULL
unlock tables; unlock tables;
drop table t1; 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;
...@@ -102,3 +102,43 @@ unlock tables; ...@@ -102,3 +102,43 @@ unlock tables;
drop table t1, t2, t3; drop table t1, t2, t3;
# End of 4.1 tests # 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
...@@ -107,3 +107,35 @@ show columns from t1; ...@@ -107,3 +107,35 @@ show columns from t1;
connection locker; connection locker;
unlock tables; unlock tables;
drop table t1; 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
...@@ -1138,8 +1138,9 @@ bool lock_global_read_lock(THD *thd) ...@@ -1138,8 +1138,9 @@ bool lock_global_read_lock(THD *thd)
if (!thd->global_read_lock) if (!thd->global_read_lock)
{ {
const char *old_message;
(void) pthread_mutex_lock(&LOCK_global_read_lock); (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"); "Waiting to get readlock");
DBUG_PRINT("info", DBUG_PRINT("info",
("waiting_for: %d protect_against: %d", ("waiting_for: %d protect_against: %d",
...@@ -1147,7 +1148,7 @@ bool lock_global_read_lock(THD *thd) ...@@ -1147,7 +1148,7 @@ bool lock_global_read_lock(THD *thd)
waiting_for_read_lock++; waiting_for_read_lock++;
while (protect_against_global_read_lock && !thd->killed) 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--; waiting_for_read_lock--;
if (thd->killed) if (thd->killed)
{ {
...@@ -1169,9 +1170,15 @@ bool lock_global_read_lock(THD *thd) ...@@ -1169,9 +1170,15 @@ bool lock_global_read_lock(THD *thd)
DBUG_RETURN(0); DBUG_RETURN(0);
} }
void unlock_global_read_lock(THD *thd) void unlock_global_read_lock(THD *thd)
{ {
uint tmp; 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); pthread_mutex_lock(&LOCK_global_read_lock);
tmp= --global_read_lock; tmp= --global_read_lock;
if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT) if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT)
...@@ -1179,8 +1186,13 @@ void unlock_global_read_lock(THD *thd) ...@@ -1179,8 +1186,13 @@ void unlock_global_read_lock(THD *thd)
pthread_mutex_unlock(&LOCK_global_read_lock); pthread_mutex_unlock(&LOCK_global_read_lock);
/* Send the signal outside the mutex to avoid a context switch */ /* Send the signal outside the mutex to avoid a context switch */
if (!tmp) 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; thd->global_read_lock= 0;
DBUG_VOID_RETURN;
} }
#define must_wait (global_read_lock && \ #define must_wait (global_read_lock && \
...@@ -1218,11 +1230,15 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, ...@@ -1218,11 +1230,15 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
*/ */
DBUG_RETURN(is_not_commit); 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"); "Waiting for release of readlock");
while (must_wait && ! thd->killed && while (must_wait && ! thd->killed &&
(!abort_on_refresh || thd->version == refresh_version)) (!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) if (thd->killed)
result=1; result=1;
} }
...@@ -1251,7 +1267,7 @@ void start_waiting_global_read_lock(THD *thd) ...@@ -1251,7 +1267,7 @@ void start_waiting_global_read_lock(THD *thd)
(waiting_for_read_lock || global_read_lock_blocks_commit)); (waiting_for_read_lock || global_read_lock_blocks_commit));
(void) pthread_mutex_unlock(&LOCK_global_read_lock); (void) pthread_mutex_unlock(&LOCK_global_read_lock);
if (tmp) if (tmp)
pthread_cond_broadcast(&COND_refresh); pthread_cond_broadcast(&COND_global_read_lock);
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1273,10 +1289,10 @@ bool make_global_read_lock_block_commit(THD *thd) ...@@ -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 */ /* For testing we set up some blocking, to see if we can be killed */
DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop", DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
protect_against_global_read_lock++;); 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"); "Waiting for all running commits to finish");
while (protect_against_global_read_lock && !thd->killed) 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", DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop",
protect_against_global_read_lock--;); protect_against_global_read_lock--;);
if ((error= test(thd->killed))) if ((error= test(thd->killed)))
......
...@@ -1220,6 +1220,7 @@ extern pthread_mutex_t LOCK_des_key_file; ...@@ -1220,6 +1220,7 @@ extern pthread_mutex_t LOCK_des_key_file;
#endif #endif
extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
extern pthread_cond_t COND_global_read_lock;
extern pthread_attr_t connection_attrib; extern pthread_attr_t connection_attrib;
extern I_List<THD> threads; extern I_List<THD> threads;
extern I_List<NAMED_LIST> key_caches; extern I_List<NAMED_LIST> key_caches;
......
...@@ -516,7 +516,7 @@ pthread_mutex_t LOCK_prepared_stmt_count; ...@@ -516,7 +516,7 @@ pthread_mutex_t LOCK_prepared_stmt_count;
pthread_mutex_t LOCK_des_key_file; pthread_mutex_t LOCK_des_key_file;
#endif #endif
rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
pthread_cond_t COND_refresh,COND_thread_count; pthread_cond_t COND_refresh,COND_thread_count, COND_global_read_lock;
pthread_t signal_thread; pthread_t signal_thread;
pthread_attr_t connection_attrib; pthread_attr_t connection_attrib;
...@@ -1248,6 +1248,7 @@ static void clean_up_mutexes() ...@@ -1248,6 +1248,7 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_prepared_stmt_count); (void) pthread_mutex_destroy(&LOCK_prepared_stmt_count);
(void) pthread_cond_destroy(&COND_thread_count); (void) pthread_cond_destroy(&COND_thread_count);
(void) pthread_cond_destroy(&COND_refresh); (void) pthread_cond_destroy(&COND_refresh);
(void) pthread_cond_destroy(&COND_global_read_lock);
(void) pthread_cond_destroy(&COND_thread_cache); (void) pthread_cond_destroy(&COND_thread_cache);
(void) pthread_cond_destroy(&COND_flush_thread_cache); (void) pthread_cond_destroy(&COND_flush_thread_cache);
(void) pthread_cond_destroy(&COND_manager); (void) pthread_cond_destroy(&COND_manager);
...@@ -1670,13 +1671,11 @@ void end_thread(THD *thd, bool put_in_cache) ...@@ -1670,13 +1671,11 @@ void end_thread(THD *thd, bool put_in_cache)
} }
} }
DBUG_PRINT("info", ("sending a broadcast"))
/* Tell main we are ready */ /* Tell main we are ready */
(void) pthread_mutex_unlock(&LOCK_thread_count); (void) pthread_mutex_unlock(&LOCK_thread_count);
/* It's safe to broadcast outside a lock (COND... is not deleted here) */ /* It's safe to broadcast outside a lock (COND... is not deleted here) */
DBUG_PRINT("signal", ("Broadcasting COND_thread_count"));
(void) pthread_cond_broadcast(&COND_thread_count); (void) pthread_cond_broadcast(&COND_thread_count);
DBUG_PRINT("info", ("unlocked thread_count mutex"))
#ifdef ONE_THREAD #ifdef ONE_THREAD
if (!(test_flags & TEST_NO_THREADS)) // For debugging under Linux if (!(test_flags & TEST_NO_THREADS)) // For debugging under Linux
#endif #endif
...@@ -2824,6 +2823,7 @@ static int init_thread_environment() ...@@ -2824,6 +2823,7 @@ static int init_thread_environment()
(void) my_rwlock_init(&LOCK_grant, NULL); (void) my_rwlock_init(&LOCK_grant, NULL);
(void) pthread_cond_init(&COND_thread_count,NULL); (void) pthread_cond_init(&COND_thread_count,NULL);
(void) pthread_cond_init(&COND_refresh,NULL); (void) pthread_cond_init(&COND_refresh,NULL);
(void) pthread_cond_init(&COND_global_read_lock,NULL);
(void) pthread_cond_init(&COND_thread_cache,NULL); (void) pthread_cond_init(&COND_thread_cache,NULL);
(void) pthread_cond_init(&COND_flush_thread_cache,NULL); (void) pthread_cond_init(&COND_flush_thread_cache,NULL);
(void) pthread_cond_init(&COND_manager,NULL); (void) pthread_cond_init(&COND_manager,NULL);
......
...@@ -316,7 +316,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, ...@@ -316,7 +316,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
bool found=1; bool found=1;
/* Wait until all threads has closed all the tables we had locked */ /* Wait until all threads has closed all the tables we had locked */
DBUG_PRINT("info", DBUG_PRINT("info",
("Waiting for others threads to close their open tables")); ("Waiting for other threads to close their open tables"));
while (found && ! thd->killed) while (found && ! thd->killed)
{ {
found=0; found=0;
...@@ -326,6 +326,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, ...@@ -326,6 +326,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
if ((table->s->version) < refresh_version && table->db_stat) if ((table->s->version) < refresh_version && table->db_stat)
{ {
found=1; found=1;
DBUG_PRINT("signal", ("Waiting for COND_refresh"));
pthread_cond_wait(&COND_refresh,&LOCK_open); pthread_cond_wait(&COND_refresh,&LOCK_open);
break; break;
} }
...@@ -1046,6 +1047,7 @@ TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find) ...@@ -1046,6 +1047,7 @@ TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find)
void wait_for_refresh(THD *thd) void wait_for_refresh(THD *thd)
{ {
DBUG_ENTER("wait_for_refresh");
safe_mutex_assert_owner(&LOCK_open); safe_mutex_assert_owner(&LOCK_open);
/* Wait until the current table is up to date */ /* Wait until the current table is up to date */
...@@ -1063,6 +1065,7 @@ void wait_for_refresh(THD *thd) ...@@ -1063,6 +1065,7 @@ void wait_for_refresh(THD *thd)
thd->mysys_var->current_cond= 0; thd->mysys_var->current_cond= 0;
thd->proc_info= proc_info; thd->proc_info= proc_info;
pthread_mutex_unlock(&thd->mysys_var->mutex); pthread_mutex_unlock(&thd->mysys_var->mutex);
DBUG_VOID_RETURN;
} }
...@@ -1346,6 +1349,9 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, ...@@ -1346,6 +1349,9 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
{ {
if (table->s->version != refresh_version) if (table->s->version != refresh_version)
{ {
DBUG_PRINT("note",
("Found table '%s.%s' with different refresh version",
table_list->db, table_list->table_name));
if (flags & MYSQL_LOCK_IGNORE_FLUSH) if (flags & MYSQL_LOCK_IGNORE_FLUSH)
{ {
/* Force close at once after usage */ /* Force close at once after usage */
...@@ -5123,6 +5129,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, ...@@ -5123,6 +5129,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
TABLE *table; TABLE *table;
bool result=0, signalled= 0; bool result=0, signalled= 0;
DBUG_ENTER("remove_table_from_cache"); DBUG_ENTER("remove_table_from_cache");
DBUG_PRINT("enter", ("Table: '%s.%s' flags: %u", db, table_name, flags));
key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1; key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
for (;;) for (;;)
...@@ -5147,7 +5154,10 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, ...@@ -5147,7 +5154,10 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
{ {
in_use->some_tables_deleted=1; in_use->some_tables_deleted=1;
if (table->db_stat) if (table->db_stat)
{
DBUG_PRINT("info", ("Found another active instance of the table"));
result=1; result=1;
}
/* Kill delayed insert threads */ /* Kill delayed insert threads */
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) && if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
! in_use->killed) ! in_use->killed)
...@@ -5182,6 +5192,12 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, ...@@ -5182,6 +5192,12 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
VOID(hash_delete(&open_cache,(byte*) unused_tables)); VOID(hash_delete(&open_cache,(byte*) unused_tables));
if (result && (flags & RTFC_WAIT_OTHER_THREAD_FLAG)) if (result && (flags & RTFC_WAIT_OTHER_THREAD_FLAG))
{ {
/*
Signal any thread waiting for tables to be freed to
reopen their tables
*/
(void) pthread_cond_broadcast(&COND_refresh);
DBUG_PRINT("info", ("Waiting for refresh signal"));
if (!(flags & RTFC_CHECK_KILLED_FLAG) || !thd->killed) if (!(flags & RTFC_CHECK_KILLED_FLAG) || !thd->killed)
{ {
dropping_tables++; dropping_tables++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment