mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
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:
@ -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;
|
||||||
|
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
|
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,
|
|||||||
}
|
}
|
||||||
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
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)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
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 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;
|
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);
|
||||||
}
|
}
|
||||||
|
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_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);
|
|||||||
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,
|
|||||||
{
|
{
|
||||||
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:
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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)
|
|||||||
/* 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,
|
|||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
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,
|
|||||||
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,
|
|||||||
*/
|
*/
|
||||||
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,
|
|||||||
{
|
{
|
||||||
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:
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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:
|
|||||||
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:
|
|||||||
|
|
||||||
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,
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
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:
|
|||||||
*/
|
*/
|
||||||
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:
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user