Commit 4689cddb authored by Konstantin Osipov's avatar Konstantin Osipov

Backport of:

------------------------------------------------------------
revno: 2630.4.18
committer: Dmitry Lenev <dlenev@mysql.com>
branch nick: mysql-6.0-3726-w2
timestamp: Tue 2008-06-03 21:07:58 +0400
message:
  WL#3726 "DDL locking for all metadata objects".

  After review fixes in progress.

  Now during upgrading/downgrading metadata locks we deal with
  individual metadata lock requests rather than with all requests
  for this object in the context. This makes API a bit more clear
  and makes adjust_mdl_locks_upgradability() much nicer.
parent a9dbad1a
...@@ -976,6 +976,7 @@ bool lock_table_names(THD *thd, TABLE_LIST *table_list) ...@@ -976,6 +976,7 @@ bool lock_table_names(THD *thd, TABLE_LIST *table_list)
goto end; goto end;
mdl_set_lock_type(mdl_lock_data, MDL_EXCLUSIVE); mdl_set_lock_type(mdl_lock_data, MDL_EXCLUSIVE);
mdl_add_lock(&thd->mdl_context, mdl_lock_data); mdl_add_lock(&thd->mdl_context, mdl_lock_data);
lock_table->mdl_lock_data= mdl_lock_data;
} }
if (mdl_acquire_exclusive_locks(&thd->mdl_context)) if (mdl_acquire_exclusive_locks(&thd->mdl_context))
return 1; return 1;
......
...@@ -660,91 +660,95 @@ bool mdl_acquire_exclusive_locks(MDL_CONTEXT *context) ...@@ -660,91 +660,95 @@ bool mdl_acquire_exclusive_locks(MDL_CONTEXT *context)
Used in ALTER TABLE, when a copy of the table with the Used in ALTER TABLE, when a copy of the table with the
new definition has been constructed. new definition has been constructed.
@param context Context to which shared long belongs @param context Context to which shared lock belongs
@param type Id of object type @param lock_data Satisfied request for shared lock to be upgraded
@param db Name of the database
@param name Name of the object
@note In case of failure to upgrade locks (e.g. because upgrader @note In case of failure to upgrade lock (e.g. because upgrader
was killed) leaves locks in their original state (locked was killed) leaves lock in its original state (locked in
in shared mode). shared mode).
@retval FALSE Success @retval FALSE Success
@retval TRUE Failure (thread was killed) @retval TRUE Failure (thread was killed)
*/ */
bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, int type, bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context,
const char *db, const char *name) MDL_LOCK_DATA *lock_data)
{ {
char key[MAX_DBKEY_LENGTH]; MDL_LOCK_DATA *conf_lock_data;
uint key_length;
bool signalled= FALSE;
MDL_LOCK_DATA *lock_data, *conf_lock_data;
MDL_LOCK *lock; MDL_LOCK *lock;
I_P_List_iterator<MDL_LOCK_DATA, MDL_LOCK_DATA_context> it(context->locks);
const char *old_msg; const char *old_msg;
THD *thd= context->thd; THD *thd= context->thd;
DBUG_ENTER("mdl_upgrade_shared_lock_to_exclusive"); DBUG_ENTER("mdl_upgrade_shared_lock_to_exclusive");
DBUG_PRINT("enter", ("db=%s name=%s", db, name));
DBUG_ASSERT(thd == current_thd); DBUG_ASSERT(thd == current_thd);
int4store(key, type);
key_length= (uint) (strmov(strmov(key+4, db)+1, name)-key)+1;
safe_mutex_assert_not_owner(&LOCK_open); safe_mutex_assert_not_owner(&LOCK_open);
DBUG_ASSERT(lock_data->state == MDL_ACQUIRED);
/* Allow this function to be called twice for the same lock request. */
if (lock_data->type == MDL_EXCLUSIVE)
DBUG_RETURN(FALSE);
DBUG_ASSERT(lock_data->is_upgradable);
lock= lock_data->lock;
pthread_mutex_lock(&LOCK_mdl); pthread_mutex_lock(&LOCK_mdl);
old_msg= thd->enter_cond(&COND_mdl, &LOCK_mdl, "Waiting for table"); old_msg= thd->enter_cond(&COND_mdl, &LOCK_mdl, "Waiting for table");
while ((lock_data= it++)) lock_data->state= MDL_PENDING_UPGRADE;
if (lock_data->key_length == key_length && lock->active_shared.remove(lock_data);
!memcmp(lock_data->key, key, key_length) && /*
lock_data->type == MDL_SHARED) There can be only one upgrader for this lock or we will have deadlock.
{ This invariant is ensured by code outside of metadata subsystem usually
DBUG_PRINT("info", ("found shared lock for upgrade")); by obtaining some sort of exclusive table-level lock (e.g. TL_WRITE,
DBUG_ASSERT(lock_data->state == MDL_ACQUIRED); TL_WRITE_ALLOW_READ) before performing upgrade of metadata lock.
DBUG_ASSERT(lock_data->is_upgradable); */
lock_data->state= MDL_PENDING_UPGRADE; DBUG_ASSERT(lock->active_shared_waiting_upgrade.is_empty());
lock= lock_data->lock; lock->active_shared_waiting_upgrade.push_front(lock_data);
lock->active_shared.remove(lock_data);
lock->active_shared_waiting_upgrade.push_front(lock_data); /*
} There should be no conflicting global locks since for each upgradable
shared lock we obtain intention exclusive global lock first.
*/
DBUG_ASSERT(global_lock.active_shared == 0 &&
global_lock.active_intention_exclusive);
while (1) while (1)
{ {
bool signalled= FALSE;
bool found_conflict= FALSE;
I_P_List_iterator<MDL_LOCK_DATA, MDL_LOCK_DATA_lock> it(lock->active_shared);
DBUG_PRINT("info", ("looking at conflicting locks")); DBUG_PRINT("info", ("looking at conflicting locks"));
it.rewind();
while ((lock_data= it++)) while ((conf_lock_data= it++))
{ {
if (lock_data->state == MDL_PENDING_UPGRADE) /*
We can have other shared locks for the same object in the same context,
e.g. in case when several instances of TABLE are open.
*/
if (conf_lock_data->ctx != context)
{ {
DBUG_ASSERT(lock_data->type == MDL_SHARED); DBUG_PRINT("info", ("found active shared locks"));
found_conflict= TRUE;
lock= lock_data->lock; signalled|= notify_thread_having_shared_lock(thd,
conf_lock_data->ctx->thd);
DBUG_ASSERT(global_lock.active_shared == 0 &&
global_lock.active_intention_exclusive);
if ((conf_lock_data= lock->active_shared.head()))
{
DBUG_PRINT("info", ("found active shared locks"));
signalled= notify_thread_having_shared_lock(thd,
conf_lock_data->ctx->thd);
break;
}
else if (!lock->active_exclusive.is_empty())
{
DBUG_PRINT("info", ("found active exclusive locks"));
signalled= TRUE;
break;
}
} }
} }
if (!lock_data)
/*
There should be no active exclusive locks since we own shared lock
on the object.
*/
DBUG_ASSERT(lock->active_exclusive.is_empty());
if (!found_conflict)
break; break;
if (signalled) if (signalled)
pthread_cond_wait(&COND_mdl, &LOCK_mdl); pthread_cond_wait(&COND_mdl, &LOCK_mdl);
else else
...@@ -762,16 +766,9 @@ bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, int type, ...@@ -762,16 +766,9 @@ bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, int type,
} }
if (thd->killed) if (thd->killed)
{ {
it.rewind(); lock_data->state= MDL_ACQUIRED;
while ((lock_data= it++)) lock->active_shared_waiting_upgrade.remove(lock_data);
if (lock_data->state == MDL_PENDING_UPGRADE) lock->active_shared.push_front(lock_data);
{
DBUG_ASSERT(lock_data->type == MDL_SHARED);
lock_data->state= MDL_ACQUIRED;
lock= lock_data->lock;
lock->active_shared_waiting_upgrade.remove(lock_data);
lock->active_shared.push_front(lock_data);
}
/* Pending requests for shared locks can be satisfied now. */ /* Pending requests for shared locks can be satisfied now. */
pthread_cond_broadcast(&COND_mdl); pthread_cond_broadcast(&COND_mdl);
thd->exit_cond(old_msg); thd->exit_cond(old_msg);
...@@ -779,20 +776,13 @@ bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, int type, ...@@ -779,20 +776,13 @@ bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, int type,
} }
} }
it.rewind(); lock->active_shared_waiting_upgrade.remove(lock_data);
while ((lock_data= it++)) lock->active_exclusive.push_front(lock_data);
if (lock_data->state == MDL_PENDING_UPGRADE) lock_data->type= MDL_EXCLUSIVE;
{ lock_data->state= MDL_ACQUIRED;
DBUG_ASSERT(lock_data->type == MDL_SHARED); if (lock->cached_object)
lock= lock_data->lock; (*lock->cached_object_release_hook)(lock->cached_object);
lock->active_shared_waiting_upgrade.remove(lock_data); lock->cached_object= 0;
lock->active_exclusive.push_front(lock_data);
lock_data->type= MDL_EXCLUSIVE;
lock_data->state= MDL_ACQUIRED;
if (lock->cached_object)
(*lock->cached_object_release_hook)(lock->cached_object);
lock->cached_object= 0;
}
/* As a side-effect THD::exit_cond() unlocks LOCK_mdl. */ /* As a side-effect THD::exit_cond() unlocks LOCK_mdl. */
thd->exit_cond(old_msg); thd->exit_cond(old_msg);
...@@ -1085,49 +1075,6 @@ void mdl_release_locks(MDL_CONTEXT *context) ...@@ -1085,49 +1075,6 @@ void mdl_release_locks(MDL_CONTEXT *context)
} }
/**
Release all exclusive locks associated with context.
Removes the locks from the context.
@param context Context with exclusive locks.
@note Shared locks are left intact.
@note Resets lock requests for locks released back to their
initial state (i.e.sets type and priority to MDL_SHARED
and MDL_NORMAL_PRIO).
*/
void mdl_release_exclusive_locks(MDL_CONTEXT *context)
{
MDL_LOCK_DATA *lock_data;
I_P_List_iterator<MDL_LOCK_DATA, MDL_LOCK_DATA_context> it(context->locks);
safe_mutex_assert_not_owner(&LOCK_open);
pthread_mutex_lock(&LOCK_mdl);
while ((lock_data= it++))
{
if (lock_data->type == MDL_EXCLUSIVE)
{
DBUG_ASSERT(lock_data->state == MDL_ACQUIRED);
release_lock(lock_data);
#ifndef DBUG_OFF
lock_data->ctx= 0;
lock_data->lock= 0;
#endif
lock_data->state= MDL_PENDING;
/* Return lock request to its initial state. */
lock_data->type= MDL_SHARED;
lock_data->prio= MDL_NORMAL_PRIO;
lock_data->is_upgradable= FALSE;
context->locks.remove(lock_data);
}
}
pthread_cond_broadcast(&COND_mdl);
pthread_mutex_unlock(&LOCK_mdl);
}
/** /**
Release a lock. Release a lock.
Removes the lock from the context. Removes the lock from the context.
...@@ -1161,32 +1108,68 @@ void mdl_release_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data) ...@@ -1161,32 +1108,68 @@ void mdl_release_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data)
/** /**
Downgrade all exclusive locks in the context to Release all locks in the context which correspond to the same name/
shared. object as this lock request.
@param context Context containing locks in question
@param lock_data One of the locks for the name/object for which all
locks should be released.
@param context A context with exclusive locks. @see mdl_release_lock()
*/ */
void mdl_downgrade_exclusive_locks(MDL_CONTEXT *context) void mdl_release_all_locks_for_name(MDL_CONTEXT *context,
MDL_LOCK_DATA *lock_data)
{ {
MDL_LOCK_DATA *lock_data;
MDL_LOCK *lock; MDL_LOCK *lock;
I_P_List_iterator<MDL_LOCK_DATA, MDL_LOCK_DATA_context> it(context->locks); I_P_List_iterator<MDL_LOCK_DATA, MDL_LOCK_DATA_context> it(context->locks);
DBUG_ASSERT(lock_data->state == MDL_ACQUIRED);
/*
We can use MDL_LOCK_DATA::lock here to identify other locks for the same
object since even altough MDL_LOCK object might be reused for different
lock after the first lock for this object have been released we can't
have references to this other MDL_LOCK object in this context.
*/
lock= lock_data->lock;
while ((lock_data= it++))
{
DBUG_ASSERT(lock_data->state == MDL_ACQUIRED);
if (lock_data->lock == lock)
mdl_release_lock(context, lock_data);
}
}
/**
Downgrade an exclusive lock to shared metadata lock.
@param context A context to which exclusive lock belongs
@param lock_data Satisfied request for exclusive lock to be downgraded
*/
void mdl_downgrade_exclusive_lock(MDL_CONTEXT *context,
MDL_LOCK_DATA *lock_data)
{
MDL_LOCK *lock;
safe_mutex_assert_not_owner(&LOCK_open); safe_mutex_assert_not_owner(&LOCK_open);
DBUG_ASSERT(lock_data->state == MDL_ACQUIRED);
if (lock_data->type == MDL_SHARED)
return;
lock= lock_data->lock;
pthread_mutex_lock(&LOCK_mdl); pthread_mutex_lock(&LOCK_mdl);
while ((lock_data= it++)) if (!lock_data->is_upgradable)
if (lock_data->type == MDL_EXCLUSIVE) global_lock.active_intention_exclusive--;
{ lock->active_exclusive.remove(lock_data);
DBUG_ASSERT(lock_data->state == MDL_ACQUIRED); lock_data->type= MDL_SHARED;
if (!lock_data->is_upgradable) lock->active_shared.push_front(lock_data);
global_lock.active_intention_exclusive--;
lock= lock_data->lock;
lock->active_exclusive.remove(lock_data);
lock_data->type= MDL_SHARED;
lock->active_shared.push_front(lock_data);
}
pthread_cond_broadcast(&COND_mdl); pthread_cond_broadcast(&COND_mdl);
pthread_mutex_unlock(&LOCK_mdl); pthread_mutex_unlock(&LOCK_mdl);
} }
......
...@@ -194,8 +194,8 @@ inline void mdl_set_upgradable(MDL_LOCK_DATA *lock_data) ...@@ -194,8 +194,8 @@ inline void mdl_set_upgradable(MDL_LOCK_DATA *lock_data)
bool mdl_acquire_shared_lock(MDL_LOCK_DATA *lock_data, bool *retry); bool mdl_acquire_shared_lock(MDL_LOCK_DATA *lock_data, bool *retry);
bool mdl_acquire_exclusive_locks(MDL_CONTEXT *context); bool mdl_acquire_exclusive_locks(MDL_CONTEXT *context);
bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, int type, bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context,
const char *db, const char *name); MDL_LOCK_DATA *lock_data);
bool mdl_try_acquire_exclusive_lock(MDL_CONTEXT *context, bool mdl_try_acquire_exclusive_lock(MDL_CONTEXT *context,
MDL_LOCK_DATA *lock_data); MDL_LOCK_DATA *lock_data);
bool mdl_acquire_global_shared_lock(MDL_CONTEXT *context); bool mdl_acquire_global_shared_lock(MDL_CONTEXT *context);
...@@ -203,9 +203,11 @@ bool mdl_acquire_global_shared_lock(MDL_CONTEXT *context); ...@@ -203,9 +203,11 @@ bool mdl_acquire_global_shared_lock(MDL_CONTEXT *context);
bool mdl_wait_for_locks(MDL_CONTEXT *context); bool mdl_wait_for_locks(MDL_CONTEXT *context);
void mdl_release_locks(MDL_CONTEXT *context); void mdl_release_locks(MDL_CONTEXT *context);
void mdl_release_exclusive_locks(MDL_CONTEXT *context); void mdl_release_all_locks_for_name(MDL_CONTEXT *context,
MDL_LOCK_DATA *lock_data);
void mdl_release_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data); void mdl_release_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data);
void mdl_downgrade_exclusive_locks(MDL_CONTEXT *context); void mdl_downgrade_exclusive_lock(MDL_CONTEXT *context,
MDL_LOCK_DATA *lock_data);
void mdl_release_global_shared_lock(MDL_CONTEXT *context); void mdl_release_global_shared_lock(MDL_CONTEXT *context);
bool mdl_is_exclusive_lock_owner(MDL_CONTEXT *context, int type, const char *db, bool mdl_is_exclusive_lock_owner(MDL_CONTEXT *context, int type, const char *db,
......
...@@ -1066,8 +1066,9 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock, ...@@ -1066,8 +1066,9 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables, bool have_lock,
{ {
for (TABLE_LIST *table= tables; table; table= table->next_local) for (TABLE_LIST *table= tables; table; table= table->next_local)
{ {
TABLE *tab= find_locked_table(thd->open_tables, table->db, /* This should always succeed thanks to check in caller. */
table->table_name); TABLE *tab= find_write_locked_table(thd->open_tables, table->db,
table->table_name);
/* /*
Checking TABLE::db_stat is essential in case when we have Checking TABLE::db_stat is essential in case when we have
several instances of the table open and locked. several instances of the table open and locked.
...@@ -1152,7 +1153,13 @@ err_with_reopen: ...@@ -1152,7 +1153,13 @@ err_with_reopen:
result|= reopen_tables(thd, 1); result|= reopen_tables(thd, 1);
thd->in_lock_tables=0; thd->in_lock_tables=0;
pthread_mutex_unlock(&LOCK_open); pthread_mutex_unlock(&LOCK_open);
mdl_downgrade_exclusive_locks(&thd->mdl_context); /*
Since mdl_downgrade_exclusive_lock() won't do anything with shared
metadata lock it is much simplier to go through all open tables rather
than picking only those tables that were flushed.
*/
for (TABLE *tab= thd->open_tables; tab; tab= tab->next)
mdl_downgrade_exclusive_lock(&thd->mdl_context, tab->mdl_lock_data);
} }
DBUG_RETURN(result); DBUG_RETURN(result);
} }
...@@ -2976,7 +2983,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, ...@@ -2976,7 +2983,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
lock on this table to shared metadata lock. lock on this table to shared metadata lock.
*/ */
if (table_list->open_type == TABLE_LIST::OPEN_OR_CREATE) if (table_list->open_type == TABLE_LIST::OPEN_OR_CREATE)
mdl_downgrade_exclusive_locks(&thd->mdl_context); mdl_downgrade_exclusive_lock(&thd->mdl_context, table_list->mdl_lock_data);
table->mdl_lock_data= mdl_lock_data; table->mdl_lock_data= mdl_lock_data;
...@@ -3992,7 +3999,7 @@ static bool handle_failed_open_table_attempt(THD *thd, TABLE_LIST *table, ...@@ -3992,7 +3999,7 @@ static bool handle_failed_open_table_attempt(THD *thd, TABLE_LIST *table,
thd->warning_info->clear_warning_info(thd->query_id); thd->warning_info->clear_warning_info(thd->query_id);
thd->clear_error(); // Clear error message thd->clear_error(); // Clear error message
mdl_release_exclusive_locks(&thd->mdl_context); mdl_release_lock(&thd->mdl_context, table->mdl_lock_data);
break; break;
case OT_REPAIR: case OT_REPAIR:
mdl_set_lock_type(table->mdl_lock_data, MDL_EXCLUSIVE); mdl_set_lock_type(table->mdl_lock_data, MDL_EXCLUSIVE);
...@@ -4004,7 +4011,7 @@ static bool handle_failed_open_table_attempt(THD *thd, TABLE_LIST *table, ...@@ -4004,7 +4011,7 @@ static bool handle_failed_open_table_attempt(THD *thd, TABLE_LIST *table,
pthread_mutex_unlock(&LOCK_open); pthread_mutex_unlock(&LOCK_open);
result= auto_repair_table(thd, table); result= auto_repair_table(thd, table);
mdl_release_exclusive_locks(&thd->mdl_context); mdl_release_lock(&thd->mdl_context, table->mdl_lock_data);
break; break;
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
...@@ -8694,8 +8701,8 @@ int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt) ...@@ -8694,8 +8701,8 @@ int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt)
/* If MERGE child, forward lock handling to parent. */ /* If MERGE child, forward lock handling to parent. */
mysql_lock_abort(lpt->thd, lpt->table->parent ? lpt->table->parent : mysql_lock_abort(lpt->thd, lpt->table->parent ? lpt->table->parent :
lpt->table, TRUE); lpt->table, TRUE);
if (mdl_upgrade_shared_lock_to_exclusive(&lpt->thd->mdl_context, 0, if (mdl_upgrade_shared_lock_to_exclusive(&lpt->thd->mdl_context,
lpt->db, lpt->table_name)) lpt->table->mdl_lock_data))
{ {
mysql_lock_downgrade_write(lpt->thd, mysql_lock_downgrade_write(lpt->thd,
lpt->table->parent ? lpt->table->parent : lpt->table->parent ? lpt->table->parent :
......
...@@ -8114,31 +8114,10 @@ bool parse_sql(THD *thd, ...@@ -8114,31 +8114,10 @@ bool parse_sql(THD *thd,
static void adjust_mdl_locks_upgradability(TABLE_LIST *tables) static void adjust_mdl_locks_upgradability(TABLE_LIST *tables)
{ {
TABLE_LIST *tab, *otab; for (TABLE_LIST *tab= tables; tab; tab= tab->next_global)
for (tab= tables; tab; tab= tab->next_global)
{ {
if (tab->lock_type >= TL_WRITE_ALLOW_WRITE) if (tab->lock_type >= TL_WRITE_ALLOW_WRITE)
tab->mdl_upgradable= TRUE; tab->mdl_upgradable= TRUE;
else
{
/*
TODO: To get rid of this loop we need to change our code to do
metadata lock upgrade only for those instances of tables
which are write locked instead of doing such upgrade for
all instances of tables.
*/
for (otab= tables; otab; otab= otab->next_global)
if (otab->lock_type >= TL_WRITE_ALLOW_WRITE &&
otab->db_length == tab->db_length &&
otab->table_name_length == tab->table_name_length &&
!strcmp(otab->db, tab->db) &&
!strcmp(otab->table_name, tab->table_name))
{
tab->mdl_upgradable= TRUE;
break;
}
}
} }
} }
......
...@@ -1904,10 +1904,27 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1904,10 +1904,27 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
else if (thd->locked_tables) else if (thd->locked_tables)
{ {
for (table= tables; table; table= table->next_local) for (table= tables; table; table= table->next_local)
if (!find_temporary_table(thd, table->db, table->table_name) && if (find_temporary_table(thd, table->db, table->table_name))
!find_write_locked_table(thd->open_tables, table->db, {
table->table_name)) /*
DBUG_RETURN(1); Since we don't acquire metadata lock if we have found temporary
table, we should do something to avoid releasing it at the end.
*/
table->mdl_lock_data= 0;
}
else
{
/*
Since 'tables' list can't contain duplicates (this is ensured
by parser) it is safe to cache pointer to the TABLE instances
in its elements.
*/
table->table= find_write_locked_table(thd->open_tables, table->db,
table->table_name);
if (!table->table)
DBUG_RETURN(1);
table->mdl_lock_data= table->table->mdl_lock_data;
}
} }
} }
...@@ -1956,6 +1973,9 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1956,6 +1973,9 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
error= 0; error= 0;
} }
/* Probably a non-temporary table. */
non_temp_tables_count++;
/* /*
If row-based replication is used and the table is not a If row-based replication is used and the table is not a
temporary table, we add the table name to the drop statement temporary table, we add the table name to the drop statement
...@@ -1964,7 +1984,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1964,7 +1984,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
*/ */
if (!drop_temporary && thd->current_stmt_binlog_row_based && !dont_log_query) if (!drop_temporary && thd->current_stmt_binlog_row_based && !dont_log_query)
{ {
non_temp_tables_count++;
/* /*
Don't write the database name if it is the current one (or if Don't write the database name if it is the current one (or if
thd->db is NULL). thd->db is NULL).
...@@ -1985,18 +2004,12 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, ...@@ -1985,18 +2004,12 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
{ {
if (thd->locked_tables) if (thd->locked_tables)
{ {
TABLE *tab= find_locked_table(thd->open_tables, db, table->table_name); if (close_cached_table(thd, table->table))
if (close_cached_table(thd, tab))
{ {
error= -1; error= -1;
goto err_with_placeholders; goto err_with_placeholders;
} }
/* table->table= 0;
Leave LOCK TABLES mode if we managed to drop all tables
which were locked.
*/
if (thd->locked_tables->table_count == 0)
unlock_locked_tables(thd);
} }
if (thd->killed) if (thd->killed)
...@@ -2175,10 +2188,32 @@ err_with_placeholders: ...@@ -2175,10 +2188,32 @@ err_with_placeholders:
doing this. Unfortunately in this case we are likely to get more doing this. Unfortunately in this case we are likely to get more
false positives in lock_table_name_if_not_cached() function. So false positives in lock_table_name_if_not_cached() function. So
it makes sense to remove exclusive meta-data locks in all cases. it makes sense to remove exclusive meta-data locks in all cases.
Leave LOCK TABLES mode if we managed to drop all tables which were
locked. Additional check for 'non_temp_tables_count' is to avoid
leaving LOCK TABLES mode if we have dropped only temporary tables.
*/ */
mdl_release_exclusive_locks(&thd->mdl_context); if (thd->locked_tables && thd->locked_tables->table_count == 0 &&
non_temp_tables_count > 0)
{
unlock_locked_tables(thd);
goto end;
}
for (table= tables; table; table= table->next_local)
{
if (table->mdl_lock_data)
{
/*
Under LOCK TABLES we may have several instances of table open
and locked and therefore have to remove several metadata lock
requests associated with them.
*/
mdl_release_all_locks_for_name(&thd->mdl_context, table->mdl_lock_data);
}
}
} }
end:
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -4122,7 +4157,7 @@ bool mysql_create_table(THD *thd, const char *db, const char *table_name, ...@@ -4122,7 +4157,7 @@ bool mysql_create_table(THD *thd, const char *db, const char *table_name,
unlock: unlock:
if (target_lock_data) if (target_lock_data)
mdl_release_exclusive_locks(&thd->mdl_context); mdl_release_lock(&thd->mdl_context, target_lock_data);
pthread_mutex_lock(&LOCK_lock_db); pthread_mutex_lock(&LOCK_lock_db);
if (!--creating_table && creating_database) if (!--creating_table && creating_database)
pthread_cond_signal(&COND_refresh); pthread_cond_signal(&COND_refresh);
...@@ -4292,9 +4327,8 @@ bool wait_while_table_is_used(THD *thd, TABLE *table, ...@@ -4292,9 +4327,8 @@ bool wait_while_table_is_used(THD *thd, TABLE *table,
old_lock_type= table->reginfo.lock_type; old_lock_type= table->reginfo.lock_type;
mysql_lock_abort(thd, table, TRUE); /* end threads waiting on lock */ mysql_lock_abort(thd, table, TRUE); /* end threads waiting on lock */
if (mdl_upgrade_shared_lock_to_exclusive(&thd->mdl_context, 0, if (mdl_upgrade_shared_lock_to_exclusive(&thd->mdl_context,
table->s->db.str, table->mdl_lock_data))
table->s->table_name.str))
{ {
mysql_lock_downgrade_write(thd, table, old_lock_type); mysql_lock_downgrade_write(thd, table, old_lock_type);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
...@@ -4476,6 +4510,10 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, ...@@ -4476,6 +4510,10 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
table= &tmp_table; table= &tmp_table;
pthread_mutex_unlock(&LOCK_open); pthread_mutex_unlock(&LOCK_open);
} }
else
{
mdl_lock_data= table->mdl_lock_data;
}
/* A MERGE table must not come here. */ /* A MERGE table must not come here. */
DBUG_ASSERT(!table->child_l); DBUG_ASSERT(!table->child_l);
...@@ -4574,8 +4612,9 @@ end: ...@@ -4574,8 +4612,9 @@ end:
closefrm(table, 1); // Free allocated memory closefrm(table, 1); // Free allocated memory
pthread_mutex_unlock(&LOCK_open); pthread_mutex_unlock(&LOCK_open);
} }
if (error) /* In case of a temporary table there will be no metadata lock. */
mdl_release_exclusive_locks(&thd->mdl_context); if (error && mdl_lock_data)
mdl_release_lock(&thd->mdl_context, mdl_lock_data);
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -5539,7 +5578,7 @@ binlog: ...@@ -5539,7 +5578,7 @@ binlog:
err: err:
if (target_lock_data) if (target_lock_data)
mdl_release_exclusive_locks(&thd->mdl_context); mdl_release_lock(&thd->mdl_context, target_lock_data);
DBUG_RETURN(res); DBUG_RETURN(res);
} }
...@@ -6477,7 +6516,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, ...@@ -6477,7 +6516,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
uint order_num, ORDER *order, bool ignore) uint order_num, ORDER *order, bool ignore)
{ {
TABLE *table, *new_table= 0; TABLE *table, *new_table= 0;
MDL_LOCK_DATA *target_lock_data= 0; MDL_LOCK_DATA *mdl_lock_data, *target_lock_data= 0;
int error= 0; int error= 0;
char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN + 1]; char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN + 1];
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias; char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
...@@ -6649,6 +6688,7 @@ view_err: ...@@ -6649,6 +6688,7 @@ view_err:
if (!(table= open_n_lock_single_table(thd, table_list, TL_WRITE_ALLOW_READ))) if (!(table= open_n_lock_single_table(thd, table_list, TL_WRITE_ALLOW_READ)))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
table->use_all_columns(); table->use_all_columns();
mdl_lock_data= table->mdl_lock_data;
/* /*
Prohibit changing of the UNION list of a non-temporary MERGE table Prohibit changing of the UNION list of a non-temporary MERGE table
...@@ -6894,9 +6934,12 @@ view_err: ...@@ -6894,9 +6934,12 @@ view_err:
lock here... lock here...
*/ */
if (new_name != table_name || new_db != db) if (new_name != table_name || new_db != db)
mdl_release_exclusive_locks(&thd->mdl_context); {
mdl_release_lock(&thd->mdl_context, target_lock_data);
mdl_release_all_locks_for_name(&thd->mdl_context, mdl_lock_data);
}
else else
mdl_downgrade_exclusive_locks(&thd->mdl_context); mdl_downgrade_exclusive_lock(&thd->mdl_context, mdl_lock_data);
} }
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -7575,10 +7618,11 @@ view_err: ...@@ -7575,10 +7618,11 @@ view_err:
pthread_mutex_lock(&LOCK_open); pthread_mutex_lock(&LOCK_open);
unlink_open_table(thd, table, FALSE); unlink_open_table(thd, table, FALSE);
pthread_mutex_unlock(&LOCK_open); pthread_mutex_unlock(&LOCK_open);
mdl_release_exclusive_locks(&thd->mdl_context); mdl_release_lock(&thd->mdl_context, target_lock_data);
mdl_release_all_locks_for_name(&thd->mdl_context, mdl_lock_data);
} }
else else
mdl_downgrade_exclusive_locks(&thd->mdl_context); mdl_downgrade_exclusive_lock(&thd->mdl_context, mdl_lock_data);
} }
end_temporary: end_temporary:
...@@ -7634,7 +7678,7 @@ err: ...@@ -7634,7 +7678,7 @@ err:
thd->abort_on_warning= save_abort_on_warning; thd->abort_on_warning= save_abort_on_warning;
} }
if (target_lock_data) if (target_lock_data)
mdl_release_exclusive_locks(&thd->mdl_context); mdl_release_lock(&thd->mdl_context, target_lock_data);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
err_with_placeholders: err_with_placeholders:
...@@ -7645,7 +7689,9 @@ err_with_placeholders: ...@@ -7645,7 +7689,9 @@ err_with_placeholders:
*/ */
unlink_open_table(thd, table, FALSE); unlink_open_table(thd, table, FALSE);
pthread_mutex_unlock(&LOCK_open); pthread_mutex_unlock(&LOCK_open);
mdl_release_exclusive_locks(&thd->mdl_context); if (target_lock_data)
mdl_release_lock(&thd->mdl_context, target_lock_data);
mdl_release_all_locks_for_name(&thd->mdl_context, mdl_lock_data);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
/* mysql_alter_table */ /* mysql_alter_table */
......
...@@ -527,8 +527,9 @@ end: ...@@ -527,8 +527,9 @@ end:
locks. Otherwise call to close_thread_tables() will take care about both locks. Otherwise call to close_thread_tables() will take care about both
TABLE instance created by reopen_name_locked_table() and meta-data lock. TABLE instance created by reopen_name_locked_table() and meta-data lock.
*/ */
if (thd->locked_tables) if (thd->locked_tables && tables && tables->table)
mdl_downgrade_exclusive_locks(&thd->mdl_context); mdl_downgrade_exclusive_lock(&thd->mdl_context,
tables->table->mdl_lock_data);
if (need_start_waiting) if (need_start_waiting)
start_waiting_global_read_lock(thd); start_waiting_global_read_lock(thd);
......
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