From 4689cddb23749b161f5822dddbe3ea25e3ca5a5a Mon Sep 17 00:00:00 2001 From: Konstantin Osipov Date: Tue, 1 Dec 2009 01:39:13 +0300 Subject: [PATCH] Backport of: ------------------------------------------------------------ revno: 2630.4.18 committer: Dmitry Lenev 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 | 1 + sql/mdl.cc | 259 +++++++++++++++++++++------------------------ sql/mdl.h | 10 +- sql/sql_base.cc | 23 ++-- sql/sql_parse.cc | 23 +--- sql/sql_table.cc | 102 +++++++++++++----- sql/sql_trigger.cc | 5 +- 7 files changed, 221 insertions(+), 202 deletions(-) diff --git a/sql/lock.cc b/sql/lock.cc index b5eaaa05fff..f391b323a59 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -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; 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 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 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 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 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); } diff --git a/sql/mdl.h b/sql/mdl.h index 74c90c01730..12ce2bb9820 100644 --- a/sql/mdl.h +++ b/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, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 44db7938caf..6dc9c67f348 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -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 : diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 24939f1cd21..52a4a4e0144 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -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; - } - } } } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2a41fe2008c..9a55b386628 100644 --- a/sql/sql_table.cc +++ b/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 */ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 4e2b77292d8..caf5c84e1f9 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -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);