diff options
author | Konstantin Osipov <kostja@sun.com> | 2009-12-01 01:39:13 +0300 |
---|---|---|
committer | Konstantin Osipov <kostja@sun.com> | 2009-12-01 01:39:13 +0300 |
commit | b05303c132995ed78f38d725ffae198dcaaba364 (patch) | |
tree | 52b964eba5b9ce63717368ccff69c2934a6e8472 /sql/mdl.cc | |
parent | e23046d1bcaf54838167dd6bd3d8c6900e24b2ef (diff) | |
download | mariadb-git-b05303c132995ed78f38d725ffae198dcaaba364.tar.gz |
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.
sql/lock.cc:
lock_table_names():
Set TABLE_LIST::mdl_lock_data when allocating new metadata
lock request object for table list element.
sql/mdl.cc:
Now during upgrading/downgrading metadata locks we deal with
individual metadata lock requests rather than with all
requests for this object in the context. Adjusted upgrade/
downgrade functions accordingly.
We also got rid of mdl_release_exclusive_locks() and
now release locks individually. To simplify this process
mdl_release_all_locks_for_name() was introduced.
sql/mdl.h:
Now during upgrading/downgrading metadata locks we deal with
individual metadata lock requests rather than with all
requests for this object in the context. Adjusted upgrade/
downgrade functions accordingly.
We also got rid of mdl_release_exclusive_locks() and
now release locks individually. To simplify this process
mdl_release_all_locks_for_name() was introduced.
sql/sql_base.cc:
Now during upgrading/downgrading metadata locks we deal with
individual metadata lock requests rather than with all
requests for this object in the context.
We also got rid of mdl_release_exclusive_locks() and
now release locks individually.
sql/sql_parse.cc:
adjust_mdl_locks_upgradability() is much simplier now due to the
fact that now during upgrading/downgrading metadata locks we
deal with individual metadata lock requests rather than with
all requests for this object in the context.
sql/sql_table.cc:
Now during upgrading/downgrading metadata locks we deal with
individual metadata lock requests rather than with all
requests for this object in the context. Adjusted upgrade/
downgrade functions accordingly.
We also got rid of mdl_release_exclusive_locks() and
now release locks individually. To simplify this process
mdl_release_all_locks_for_name() was introduced.
sql/sql_trigger.cc:
ow during upgrading/downgrading metadata locks we deal with
individual metadata lock requests rather than with all
requests for this object in the context.
Diffstat (limited to 'sql/mdl.cc')
-rw-r--r-- | sql/mdl.cc | 259 |
1 files changed, 121 insertions, 138 deletions
diff --git a/sql/mdl.cc b/sql/mdl.cc index 64c011d34bf..7ed2f6e8bdf 100644 --- a/sql/mdl.cc +++ b/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); @@ -1086,49 +1076,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 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; 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); } |