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.
This commit is contained in:
parent
a9dbad1afd
commit
4689cddb23
@ -976,6 +976,7 @@ bool lock_table_names(THD *thd, TABLE_LIST *table_list)
|
||||
goto end;
|
||||
mdl_set_lock_type(mdl_lock_data, MDL_EXCLUSIVE);
|
||||
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))
|
||||
return 1;
|
||||
|
259
sql/mdl.cc
259
sql/mdl.cc
@ -660,91 +660,95 @@ bool mdl_acquire_exclusive_locks(MDL_CONTEXT *context)
|
||||
Used in ALTER TABLE, when a copy of the table with the
|
||||
new definition has been constructed.
|
||||
|
||||
@param context Context to which shared long belongs
|
||||
@param type Id of object type
|
||||
@param db Name of the database
|
||||
@param name Name of the object
|
||||
@param context Context to which shared lock belongs
|
||||
@param lock_data Satisfied request for shared lock to be upgraded
|
||||
|
||||
@note In case of failure to upgrade locks (e.g. because upgrader
|
||||
was killed) leaves locks in their original state (locked
|
||||
in shared mode).
|
||||
@note In case of failure to upgrade lock (e.g. because upgrader
|
||||
was killed) leaves lock in its original state (locked in
|
||||
shared mode).
|
||||
|
||||
@retval FALSE Success
|
||||
@retval TRUE Failure (thread was killed)
|
||||
*/
|
||||
|
||||
bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, int type,
|
||||
const char *db, const char *name)
|
||||
bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context,
|
||||
MDL_LOCK_DATA *lock_data)
|
||||
{
|
||||
char key[MAX_DBKEY_LENGTH];
|
||||
uint key_length;
|
||||
bool signalled= FALSE;
|
||||
MDL_LOCK_DATA *lock_data, *conf_lock_data;
|
||||
MDL_LOCK_DATA *conf_lock_data;
|
||||
MDL_LOCK *lock;
|
||||
I_P_List_iterator<MDL_LOCK_DATA, MDL_LOCK_DATA_context> it(context->locks);
|
||||
const char *old_msg;
|
||||
THD *thd= context->thd;
|
||||
|
||||
DBUG_ENTER("mdl_upgrade_shared_lock_to_exclusive");
|
||||
DBUG_PRINT("enter", ("db=%s name=%s", db, name));
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
old_msg= thd->enter_cond(&COND_mdl, &LOCK_mdl, "Waiting for table");
|
||||
|
||||
while ((lock_data= it++))
|
||||
if (lock_data->key_length == key_length &&
|
||||
!memcmp(lock_data->key, key, key_length) &&
|
||||
lock_data->type == MDL_SHARED)
|
||||
{
|
||||
DBUG_PRINT("info", ("found shared lock for upgrade"));
|
||||
DBUG_ASSERT(lock_data->state == MDL_ACQUIRED);
|
||||
DBUG_ASSERT(lock_data->is_upgradable);
|
||||
lock_data->state= MDL_PENDING_UPGRADE;
|
||||
lock= lock_data->lock;
|
||||
lock->active_shared.remove(lock_data);
|
||||
lock->active_shared_waiting_upgrade.push_front(lock_data);
|
||||
}
|
||||
lock_data->state= MDL_PENDING_UPGRADE;
|
||||
lock->active_shared.remove(lock_data);
|
||||
/*
|
||||
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
|
||||
by obtaining some sort of exclusive table-level lock (e.g. TL_WRITE,
|
||||
TL_WRITE_ALLOW_READ) before performing upgrade of metadata lock.
|
||||
*/
|
||||
DBUG_ASSERT(lock->active_shared_waiting_upgrade.is_empty());
|
||||
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)
|
||||
{
|
||||
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"));
|
||||
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);
|
||||
|
||||
lock= lock_data->lock;
|
||||
|
||||
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;
|
||||
}
|
||||
DBUG_PRINT("info", ("found active shared locks"));
|
||||
found_conflict= TRUE;
|
||||
signalled|= notify_thread_having_shared_lock(thd,
|
||||
conf_lock_data->ctx->thd);
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
if (signalled)
|
||||
pthread_cond_wait(&COND_mdl, &LOCK_mdl);
|
||||
else
|
||||
@ -762,16 +766,9 @@ bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, int type,
|
||||
}
|
||||
if (thd->killed)
|
||||
{
|
||||
it.rewind();
|
||||
while ((lock_data= it++))
|
||||
if (lock_data->state == MDL_PENDING_UPGRADE)
|
||||
{
|
||||
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);
|
||||
}
|
||||
lock_data->state= MDL_ACQUIRED;
|
||||
lock->active_shared_waiting_upgrade.remove(lock_data);
|
||||
lock->active_shared.push_front(lock_data);
|
||||
/* Pending requests for shared locks can be satisfied now. */
|
||||
pthread_cond_broadcast(&COND_mdl);
|
||||
thd->exit_cond(old_msg);
|
||||
@ -779,20 +776,13 @@ bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, int type,
|
||||
}
|
||||
}
|
||||
|
||||
it.rewind();
|
||||
while ((lock_data= it++))
|
||||
if (lock_data->state == MDL_PENDING_UPGRADE)
|
||||
{
|
||||
DBUG_ASSERT(lock_data->type == MDL_SHARED);
|
||||
lock= lock_data->lock;
|
||||
lock->active_shared_waiting_upgrade.remove(lock_data);
|
||||
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;
|
||||
}
|
||||
lock->active_shared_waiting_upgrade.remove(lock_data);
|
||||
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. */
|
||||
thd->exit_cond(old_msg);
|
||||
@ -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.
|
||||
Removes the lock from the context.
|
||||
@ -1161,32 +1108,68 @@ void mdl_release_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data)
|
||||
|
||||
|
||||
/**
|
||||
Downgrade all exclusive locks in the context to
|
||||
shared.
|
||||
Release all locks in the context which correspond to the same name/
|
||||
object as this lock request.
|
||||
|
||||
@param context A context with exclusive locks.
|
||||
@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.
|
||||
|
||||
@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;
|
||||
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);
|
||||
|
||||
DBUG_ASSERT(lock_data->state == MDL_ACQUIRED);
|
||||
|
||||
if (lock_data->type == MDL_SHARED)
|
||||
return;
|
||||
|
||||
lock= lock_data->lock;
|
||||
|
||||
pthread_mutex_lock(&LOCK_mdl);
|
||||
while ((lock_data= it++))
|
||||
if (lock_data->type == MDL_EXCLUSIVE)
|
||||
{
|
||||
DBUG_ASSERT(lock_data->state == MDL_ACQUIRED);
|
||||
if (!lock_data->is_upgradable)
|
||||
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);
|
||||
}
|
||||
if (!lock_data->is_upgradable)
|
||||
global_lock.active_intention_exclusive--;
|
||||
lock->active_exclusive.remove(lock_data);
|
||||
lock_data->type= MDL_SHARED;
|
||||
lock->active_shared.push_front(lock_data);
|
||||
pthread_cond_broadcast(&COND_mdl);
|
||||
pthread_mutex_unlock(&LOCK_mdl);
|
||||
}
|
||||
|
10
sql/mdl.h
10
sql/mdl.h
@ -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_exclusive_locks(MDL_CONTEXT *context);
|
||||
bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, int type,
|
||||
const char *db, const char *name);
|
||||
bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context,
|
||||
MDL_LOCK_DATA *lock_data);
|
||||
bool mdl_try_acquire_exclusive_lock(MDL_CONTEXT *context,
|
||||
MDL_LOCK_DATA *lock_data);
|
||||
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);
|
||||
|
||||
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_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);
|
||||
|
||||
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,
|
||||
{
|
||||
for (TABLE_LIST *table= tables; table; table= table->next_local)
|
||||
{
|
||||
TABLE *tab= find_locked_table(thd->open_tables, table->db,
|
||||
table->table_name);
|
||||
/* This should always succeed thanks to check in caller. */
|
||||
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
|
||||
several instances of the table open and locked.
|
||||
@ -1152,7 +1153,13 @@ err_with_reopen:
|
||||
result|= reopen_tables(thd, 1);
|
||||
thd->in_lock_tables=0;
|
||||
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);
|
||||
}
|
||||
@ -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.
|
||||
*/
|
||||
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;
|
||||
|
||||
@ -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->clear_error(); // Clear error message
|
||||
mdl_release_exclusive_locks(&thd->mdl_context);
|
||||
mdl_release_lock(&thd->mdl_context, table->mdl_lock_data);
|
||||
break;
|
||||
case OT_REPAIR:
|
||||
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,
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
|
||||
result= auto_repair_table(thd, table);
|
||||
mdl_release_exclusive_locks(&thd->mdl_context);
|
||||
mdl_release_lock(&thd->mdl_context, table->mdl_lock_data);
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
@ -8694,8 +8701,8 @@ int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt)
|
||||
/* If MERGE child, forward lock handling to parent. */
|
||||
mysql_lock_abort(lpt->thd, lpt->table->parent ? lpt->table->parent :
|
||||
lpt->table, TRUE);
|
||||
if (mdl_upgrade_shared_lock_to_exclusive(&lpt->thd->mdl_context, 0,
|
||||
lpt->db, lpt->table_name))
|
||||
if (mdl_upgrade_shared_lock_to_exclusive(&lpt->thd->mdl_context,
|
||||
lpt->table->mdl_lock_data))
|
||||
{
|
||||
mysql_lock_downgrade_write(lpt->thd,
|
||||
lpt->table->parent ? lpt->table->parent :
|
||||
|
@ -8114,31 +8114,10 @@ bool parse_sql(THD *thd,
|
||||
|
||||
static void adjust_mdl_locks_upgradability(TABLE_LIST *tables)
|
||||
{
|
||||
TABLE_LIST *tab, *otab;
|
||||
|
||||
for (tab= tables; tab; tab= tab->next_global)
|
||||
for (TABLE_LIST *tab= tables; tab; tab= tab->next_global)
|
||||
{
|
||||
if (tab->lock_type >= TL_WRITE_ALLOW_WRITE)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
102
sql/sql_table.cc
102
sql/sql_table.cc
@ -1904,10 +1904,27 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
else if (thd->locked_tables)
|
||||
{
|
||||
for (table= tables; table; table= table->next_local)
|
||||
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);
|
||||
if (find_temporary_table(thd, table->db, table->table_name))
|
||||
{
|
||||
/*
|
||||
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,
|
||||
error= 0;
|
||||
}
|
||||
|
||||
/* Probably a non-temporary table. */
|
||||
non_temp_tables_count++;
|
||||
|
||||
/*
|
||||
If row-based replication is used and the table is not a
|
||||
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,
|
||||
*/
|
||||
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
|
||||
thd->db is NULL).
|
||||
@ -1985,18 +2004,12 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
{
|
||||
if (thd->locked_tables)
|
||||
{
|
||||
TABLE *tab= find_locked_table(thd->open_tables, db, table->table_name);
|
||||
if (close_cached_table(thd, tab))
|
||||
if (close_cached_table(thd, table->table))
|
||||
{
|
||||
error= -1;
|
||||
goto err_with_placeholders;
|
||||
}
|
||||
/*
|
||||
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);
|
||||
table->table= 0;
|
||||
}
|
||||
|
||||
if (thd->killed)
|
||||
@ -2175,10 +2188,32 @@ err_with_placeholders:
|
||||
doing this. Unfortunately in this case we are likely to get more
|
||||
false positives in lock_table_name_if_not_cached() function. So
|
||||
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);
|
||||
}
|
||||
|
||||
@ -4122,7 +4157,7 @@ bool mysql_create_table(THD *thd, const char *db, const char *table_name,
|
||||
|
||||
unlock:
|
||||
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);
|
||||
if (!--creating_table && creating_database)
|
||||
pthread_cond_signal(&COND_refresh);
|
||||
@ -4292,9 +4327,8 @@ bool wait_while_table_is_used(THD *thd, TABLE *table,
|
||||
old_lock_type= table->reginfo.lock_type;
|
||||
mysql_lock_abort(thd, table, TRUE); /* end threads waiting on lock */
|
||||
|
||||
if (mdl_upgrade_shared_lock_to_exclusive(&thd->mdl_context, 0,
|
||||
table->s->db.str,
|
||||
table->s->table_name.str))
|
||||
if (mdl_upgrade_shared_lock_to_exclusive(&thd->mdl_context,
|
||||
table->mdl_lock_data))
|
||||
{
|
||||
mysql_lock_downgrade_write(thd, table, old_lock_type);
|
||||
DBUG_RETURN(TRUE);
|
||||
@ -4476,6 +4510,10 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
||||
table= &tmp_table;
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
}
|
||||
else
|
||||
{
|
||||
mdl_lock_data= table->mdl_lock_data;
|
||||
}
|
||||
|
||||
/* A MERGE table must not come here. */
|
||||
DBUG_ASSERT(!table->child_l);
|
||||
@ -4574,8 +4612,9 @@ end:
|
||||
closefrm(table, 1); // Free allocated memory
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
}
|
||||
if (error)
|
||||
mdl_release_exclusive_locks(&thd->mdl_context);
|
||||
/* In case of a temporary table there will be no metadata lock. */
|
||||
if (error && mdl_lock_data)
|
||||
mdl_release_lock(&thd->mdl_context, mdl_lock_data);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
@ -5539,7 +5578,7 @@ binlog:
|
||||
|
||||
err:
|
||||
if (target_lock_data)
|
||||
mdl_release_exclusive_locks(&thd->mdl_context);
|
||||
mdl_release_lock(&thd->mdl_context, target_lock_data);
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
@ -6477,7 +6516,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
uint order_num, ORDER *order, bool ignore)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
@ -6649,6 +6688,7 @@ view_err:
|
||||
if (!(table= open_n_lock_single_table(thd, table_list, TL_WRITE_ALLOW_READ)))
|
||||
DBUG_RETURN(TRUE);
|
||||
table->use_all_columns();
|
||||
mdl_lock_data= table->mdl_lock_data;
|
||||
|
||||
/*
|
||||
Prohibit changing of the UNION list of a non-temporary MERGE table
|
||||
@ -6894,9 +6934,12 @@ view_err:
|
||||
lock here...
|
||||
*/
|
||||
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
|
||||
mdl_downgrade_exclusive_locks(&thd->mdl_context);
|
||||
mdl_downgrade_exclusive_lock(&thd->mdl_context, mdl_lock_data);
|
||||
}
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
@ -7575,10 +7618,11 @@ view_err:
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
unlink_open_table(thd, table, FALSE);
|
||||
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
|
||||
mdl_downgrade_exclusive_locks(&thd->mdl_context);
|
||||
mdl_downgrade_exclusive_lock(&thd->mdl_context, mdl_lock_data);
|
||||
}
|
||||
|
||||
end_temporary:
|
||||
@ -7634,7 +7678,7 @@ err:
|
||||
thd->abort_on_warning= save_abort_on_warning;
|
||||
}
|
||||
if (target_lock_data)
|
||||
mdl_release_exclusive_locks(&thd->mdl_context);
|
||||
mdl_release_lock(&thd->mdl_context, target_lock_data);
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
err_with_placeholders:
|
||||
@ -7645,7 +7689,9 @@ err_with_placeholders:
|
||||
*/
|
||||
unlink_open_table(thd, table, FALSE);
|
||||
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);
|
||||
}
|
||||
/* mysql_alter_table */
|
||||
|
@ -527,8 +527,9 @@ end:
|
||||
locks. Otherwise call to close_thread_tables() will take care about both
|
||||
TABLE instance created by reopen_name_locked_table() and meta-data lock.
|
||||
*/
|
||||
if (thd->locked_tables)
|
||||
mdl_downgrade_exclusive_locks(&thd->mdl_context);
|
||||
if (thd->locked_tables && tables && tables->table)
|
||||
mdl_downgrade_exclusive_lock(&thd->mdl_context,
|
||||
tables->table->mdl_lock_data);
|
||||
|
||||
if (need_start_waiting)
|
||||
start_waiting_global_read_lock(thd);
|
||||
|
Loading…
x
Reference in New Issue
Block a user