summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <monty@narttu.mysql.fi>2003-03-03 20:42:49 +0200
committerunknown <monty@narttu.mysql.fi>2003-03-03 20:42:49 +0200
commit374ea106f5098e4a6ee79f217bf799d181d20a25 (patch)
treebb5b30b61dc86c58f8550645b5e1dd2dd91770ed /sql
parent391bc11a2121919a29a2579639bc476b6c25fa6a (diff)
downloadmariadb-git-374ea106f5098e4a6ee79f217bf799d181d20a25.tar.gz
Fixed a deadlock problem when using LOCK TABLE in one thread and DROP TABLE in another
sql/lock.cc: Added functions to handle list of table name locks sql/mysql_priv.h: Added functions to handle list of named locks sql/sql_rename.cc: Use new general table name lock functions sql/sql_table.cc: Require table name locks when doing drop table. This fixed a deadlock problem when using LOCK TABLE in one thread and DROP TABLE in another
Diffstat (limited to 'sql')
-rw-r--r--sql/lock.cc76
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/sql_rename.cc32
-rw-r--r--sql/sql_table.cc11
4 files changed, 94 insertions, 28 deletions
diff --git a/sql/lock.cc b/sql/lock.cc
index 84d10d61366..e46e2aac7bc 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -416,10 +416,11 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
char key[MAX_DBKEY_LENGTH];
+ char *db= table_list->db ? table_list->db : (thd->db ? thd->db : (char*) "");
uint key_length;
DBUG_ENTER("lock_table_name");
- key_length=(uint) (strmov(strmov(key,table_list->db)+1,table_list->real_name)
+ key_length=(uint) (strmov(strmov(key,db)+1,table_list->real_name)
-key)+ 1;
/* Only insert the table if we haven't insert it already */
@@ -447,7 +448,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
my_free((gptr) table,MYF(0));
DBUG_RETURN(-1);
}
- if (remove_table_from_cache(thd, table_list->db, table_list->real_name))
+ if (remove_table_from_cache(thd, db, table_list->real_name))
DBUG_RETURN(1); // Table is in use
DBUG_RETURN(0);
}
@@ -490,6 +491,77 @@ bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list)
DBUG_RETURN(result);
}
+
+/*
+ Lock all tables in list with a name lock
+
+ SYNOPSIS
+ lock_table_names()
+ thd Thread handle
+ table_list Names of tables to lock
+
+ NOTES
+ One must have a lock on LOCK_open when calling this
+
+ RETURN
+ 0 ok
+ 1 Fatal error (end of memory ?)
+*/
+
+bool lock_table_names(THD *thd, TABLE_LIST *table_list)
+{
+ bool got_all_locks=1;
+ TABLE_LIST *lock_table;
+
+ for (lock_table=table_list ; lock_table ; lock_table=lock_table->next)
+ {
+ int got_lock;
+ if ((got_lock=lock_table_name(thd,lock_table)) < 0)
+ goto end; // Fatal error
+ if (got_lock)
+ got_all_locks=0; // Someone is using table
+ }
+
+ /* If some table was in use, wait until we got the lock */
+ if (!got_all_locks && wait_for_locked_table_names(thd, table_list))
+ goto end;
+ return 0;
+
+end:
+ unlock_table_names(thd, table_list, lock_table);
+ return 1;
+}
+
+
+/*
+ Unlock all tables in list with a name lock
+
+ SYNOPSIS
+ unlock_table_names()
+ thd Thread handle
+ table_list Names of tables to unlock
+ last_table Don't unlock any tables after this one.
+ (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
+
+ RETURN
+ 0 ok
+ 1 Fatal error (end of memory ?)
+*/
+
+void unlock_table_names(THD *thd, TABLE_LIST *table_list,
+ TABLE_LIST *last_table)
+{
+ for (TABLE_LIST *table=table_list ; table != last_table ; table=table->next)
+ unlock_table_name(thd,table);
+ pthread_cond_broadcast(&COND_refresh);
+}
+
+
static void print_lock_error(int error)
{
int textno;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 49f1713bbc9..237a8a79acd 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -594,6 +594,9 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b);
int lock_table_name(THD *thd, TABLE_LIST *table_list);
void unlock_table_name(THD *thd, TABLE_LIST *table_list);
bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list);
+bool lock_table_names(THD *thd, TABLE_LIST *table_list);
+void unlock_table_names(THD *thd, TABLE_LIST *table_list,
+ TABLE_LIST *last_table= 0);
/* old unireg functions */
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index a6614f3f3f6..9eee8ccf7ac 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -31,8 +31,8 @@ static TABLE_LIST *rename_tables(THD *thd, TABLE_LIST *table_list,
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
{
- bool error=1,cerror,got_all_locks=1;
- TABLE_LIST *lock_table,*ren_table=0;
+ bool error=1, cerror;
+ TABLE_LIST *ren_table= 0;
DBUG_ENTER("mysql_rename_tables");
/* Avoid problems with a rename on a table that we have locked or
@@ -45,23 +45,11 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
}
VOID(pthread_mutex_lock(&LOCK_open));
- for (lock_table=table_list ; lock_table ; lock_table=lock_table->next)
- {
- int got_lock;
- if ((got_lock=lock_table_name(thd,lock_table)) < 0)
- goto end;
- if (got_lock)
- got_all_locks=0;
- }
-
- if (!got_all_locks && wait_for_locked_table_names(thd,table_list))
- goto end;
+ if (lock_table_names(thd, table_list))
+ goto err;
- if (!(ren_table=rename_tables(thd,table_list,0)))
- error=0;
-
-end:
- if (ren_table)
+ error= 0;
+ if ((ren_table=rename_tables(thd,table_list,0)))
{
/* Rename didn't succeed; rename back the tables in reverse order */
TABLE_LIST *prev=0,*table;
@@ -83,7 +71,7 @@ end:
table=table->next->next; // Skipp error table
/* Revert to old names */
rename_tables(thd, table, 1);
- /* Note that lock_table == 0 here, so the unlock loop will work */
+ error= 1;
}
/* Lets hope this doesn't fail as the result will be messy */
@@ -103,9 +91,9 @@ end:
send_ok(&thd->net);
}
- for (TABLE_LIST *table=table_list ; table != lock_table ; table=table->next)
- unlock_table_name(thd,table);
- pthread_cond_broadcast(&COND_refresh);
+ unlock_table_names(thd,table_list);
+
+err:
pthread_mutex_unlock(&LOCK_open);
DBUG_RETURN(error);
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 4691c2fd494..2ff7c9c1a75 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -49,7 +49,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
char path[FN_REFLEN];
String wrong_tables;
bool some_tables_deleted=0;
- uint error;
+ uint error= 1;
db_type table_type;
TABLE_LIST *table;
DBUG_ENTER("mysql_rm_table");
@@ -66,7 +66,6 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
{
my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,MYF(0),
tables->real_name);
- error = 1;
goto err;
}
while (global_read_lock && ! thd->killed)
@@ -76,9 +75,12 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
}
+ if (lock_table_names(thd, tables))
+ goto err;
+
for (table=tables ; table ; table=table->next)
{
- char *db=table->db ? table->db : thd->db;
+ char *db=table->db ? table->db : (thd->db ? thd->db : (char*) "");
if (!close_temporary_table(thd, db, table->real_name))
{
some_tables_deleted=1; // Log query
@@ -149,9 +151,10 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
}
error = 0;
+ unlock_table_names(thd, tables);
+
err:
pthread_mutex_unlock(&LOCK_open);
- VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh
pthread_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex= 0;