diff options
-rw-r--r-- | sql/ha_ndbcluster_binlog.cc | 2 | ||||
-rw-r--r-- | sql/log_event.cc | 2 | ||||
-rw-r--r-- | sql/mdl.cc | 136 | ||||
-rw-r--r-- | sql/mdl.h | 19 | ||||
-rw-r--r-- | sql/mysql_priv.h | 2 | ||||
-rw-r--r-- | sql/sql_base.cc | 8 | ||||
-rw-r--r-- | sql/sql_handler.cc | 2 | ||||
-rw-r--r-- | sql/sql_show.cc | 4 |
8 files changed, 120 insertions, 55 deletions
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 6f0e4498d75..b9ea87aec52 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -141,7 +141,7 @@ static Uint64 *p_latest_trans_gci= 0; static TABLE *ndb_binlog_index= 0; static TABLE_LIST binlog_tables; static MDL_LOCK_DATA binlog_mdl_lock_data; -static char binlog_mdlkey[MAX_DBKEY_LENGTH]; +static char binlog_mdlkey[MAX_MDLKEY_LENGTH]; /* Helper functions diff --git a/sql/log_event.cc b/sql/log_event.cc index 92de9933181..b3f6fd58f1a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -8074,7 +8074,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) &db_mem, (uint) NAME_LEN + 1, &tname_mem, (uint) NAME_LEN + 1, &mdl_lock_data, sizeof(MDL_LOCK_DATA), - &mdlkey, MAX_DBKEY_LENGTH, + &mdlkey, MAX_MDLKEY_LENGTH, NullS))) DBUG_RETURN(HA_ERR_OUT_OF_MEM); diff --git a/sql/mdl.cc b/sql/mdl.cc index afe3f0eaa7b..0a663ad2e11 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -15,13 +15,9 @@ -/* - TODO: Remove this dependency on mysql_priv.h. It's not - trivial step at the moment since currently we access to - some of THD members and use some of its methods here. -*/ -#include "mysql_priv.h" #include "mdl.h" +#include <hash.h> +#include <mysqld_error.h> /** @@ -308,7 +304,7 @@ MDL_LOCK_DATA *mdl_alloc_lock(int type, const char *db, const char *name, char *key; if (!multi_alloc_root(root, &lock_data, sizeof(MDL_LOCK_DATA), &key, - MAX_DBKEY_LENGTH, NULL)) + MAX_MDLKEY_LENGTH, NULL)) return NULL; mdl_init_lock(lock_data, key, type, db, name); @@ -442,6 +438,58 @@ static bool is_shared(MDL_LOCK_DATA *lock_data) /** + Helper functions and macros to be used for killable waiting in metadata + locking subsystem. + + @sa THD::enter_cond()/exit_cond()/killed. + + @note We can't use THD::enter_cond()/exit_cond()/killed directly here + since this will make metadata subsystem dependant on THD class + and thus prevent us from writing unit tests for it. And usage of + wrapper functions to access THD::killed/enter_cond()/exit_cond() + will probably introduce too much overhead. +*/ + +#define MDL_ENTER_COND(A, B) mdl_enter_cond(A, B, __func__, __FILE__, __LINE__) + +static inline const char* mdl_enter_cond(MDL_CONTEXT *context, + st_my_thread_var *mysys_var, + const char *calling_func, + const char *calling_file, + const unsigned int calling_line) +{ + safe_mutex_assert_owner(&LOCK_mdl); + + mysys_var->current_mutex= &LOCK_mdl; + mysys_var->current_cond= &COND_mdl; + + return set_thd_proc_info(context->thd, "Waiting for table", + calling_func, calling_file, calling_line); +} + +#define MDL_EXIT_COND(A, B, C) mdl_exit_cond(A, B, C, __func__, __FILE__, __LINE__) + +static inline void mdl_exit_cond(MDL_CONTEXT *context, + st_my_thread_var *mysys_var, + const char* old_msg, + const char *calling_func, + const char *calling_file, + const unsigned int calling_line) +{ + DBUG_ASSERT(&LOCK_mdl == mysys_var->current_mutex); + + pthread_mutex_unlock(&LOCK_mdl); + pthread_mutex_lock(&mysys_var->mutex); + mysys_var->current_mutex= 0; + mysys_var->current_cond= 0; + pthread_mutex_unlock(&mysys_var->mutex); + + (void) set_thd_proc_info(context->thd, old_msg, calling_func, + calling_file, calling_line); +} + + +/** Check if request for the lock on particular object can be satisfied given current state of the global metadata lock. @@ -752,9 +800,7 @@ bool mdl_acquire_exclusive_locks(MDL_CONTEXT *context) bool signalled= FALSE; const char *old_msg; I_P_List_iterator<MDL_LOCK_DATA, MDL_LOCK_DATA_context> it(context->locks); - THD *thd= context->thd; - - DBUG_ASSERT(thd == current_thd); + st_my_thread_var *mysys_var= my_thread_var; safe_mutex_assert_not_owner(&LOCK_open); @@ -766,7 +812,7 @@ bool mdl_acquire_exclusive_locks(MDL_CONTEXT *context) pthread_mutex_lock(&LOCK_mdl); - old_msg= thd->enter_cond(&COND_mdl, &LOCK_mdl, "Waiting for table"); + old_msg= MDL_ENTER_COND(context, mysys_var); while ((lock_data= it++)) { @@ -826,8 +872,11 @@ bool mdl_acquire_exclusive_locks(MDL_CONTEXT *context) !lock->active_shared_waiting_upgrade.is_empty(); while ((conf_lock_data= it++)) + { signalled|= - notify_thread_having_shared_lock(thd, conf_lock_data->ctx->thd); + mysql_notify_thread_having_shared_lock(context->thd, + conf_lock_data->ctx->thd); + } break; } @@ -848,7 +897,7 @@ bool mdl_acquire_exclusive_locks(MDL_CONTEXT *context) set_timespec(abstime, 10); pthread_cond_timedwait(&COND_mdl, &LOCK_mdl, &abstime); } - if (thd->killed) + if (mysys_var->abort) goto err; } it.rewind(); @@ -863,8 +912,8 @@ bool mdl_acquire_exclusive_locks(MDL_CONTEXT *context) (*lock->cached_object_release_hook)(lock->cached_object); lock->cached_object= NULL; } - /* As a side-effect THD::exit_cond() unlocks LOCK_mdl. */ - thd->exit_cond(old_msg); + /* As a side-effect MDL_EXIT_COND() unlocks LOCK_mdl. */ + MDL_EXIT_COND(context, mysys_var, old_msg); return FALSE; err: @@ -880,7 +929,7 @@ err: } /* May be some pending requests for shared locks can be satisfied now. */ pthread_cond_broadcast(&COND_mdl); - thd->exit_cond(old_msg); + MDL_EXIT_COND(context, mysys_var, old_msg); return TRUE; } @@ -907,12 +956,10 @@ bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, { MDL_LOCK *lock; const char *old_msg; - THD *thd= context->thd; + st_my_thread_var *mysys_var= my_thread_var; DBUG_ENTER("mdl_upgrade_shared_lock_to_exclusive"); - DBUG_ASSERT(thd == current_thd); - safe_mutex_assert_not_owner(&LOCK_open); DBUG_ASSERT(lock_data->state == MDL_ACQUIRED); @@ -927,7 +974,7 @@ bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, pthread_mutex_lock(&LOCK_mdl); - old_msg= thd->enter_cond(&COND_mdl, &LOCK_mdl, "Waiting for table"); + old_msg= MDL_ENTER_COND(context, mysys_var); lock_data->state= MDL_PENDING_UPGRADE; /* Set type of lock request to the type at which we are aiming. */ @@ -960,8 +1007,11 @@ bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, while ((conf_lock_data= it++)) { if (conf_lock_data->ctx != context) - signalled|= notify_thread_having_shared_lock(thd, - conf_lock_data->ctx->thd); + { + signalled|= + mysql_notify_thread_having_shared_lock(context->thd, + conf_lock_data->ctx->thd); + } } if (signalled) @@ -979,7 +1029,7 @@ bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, DBUG_PRINT("info", ("Failed to wake-up from table-level lock ... sleeping")); pthread_cond_timedwait(&COND_mdl, &LOCK_mdl, &abstime); } - if (thd->killed) + if (mysys_var->abort) { lock_data->state= MDL_ACQUIRED; lock_data->type= MDL_SHARED_UPGRADABLE; @@ -987,7 +1037,7 @@ bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, 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); + MDL_EXIT_COND(context, mysys_var, old_msg); DBUG_RETURN(TRUE); } } @@ -999,8 +1049,8 @@ bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context, (*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); + /* As a side-effect MDL_EXIT_COND() unlocks LOCK_mdl. */ + MDL_EXIT_COND(context, mysys_var, old_msg); DBUG_RETURN(FALSE); } @@ -1086,32 +1136,31 @@ err: bool mdl_acquire_global_shared_lock(MDL_CONTEXT *context) { - THD *thd= context->thd; + st_my_thread_var *mysys_var= my_thread_var; const char *old_msg; safe_mutex_assert_not_owner(&LOCK_open); - DBUG_ASSERT(thd == current_thd); DBUG_ASSERT(!context->has_global_shared_lock); pthread_mutex_lock(&LOCK_mdl); global_lock.waiting_shared++; - old_msg= thd->enter_cond(&COND_mdl, &LOCK_mdl, "Waiting for table"); + old_msg= MDL_ENTER_COND(context, mysys_var); - while (!thd->killed && global_lock.active_intention_exclusive) + while (!mysys_var->abort && global_lock.active_intention_exclusive) pthread_cond_wait(&COND_mdl, &LOCK_mdl); global_lock.waiting_shared--; - if (thd->killed) + if (mysys_var->abort) { - /* As a side-effect THD::exit_cond() unlocks LOCK_mdl. */ - thd->exit_cond(old_msg); + /* As a side-effect MDL_EXIT_COND() unlocks LOCK_mdl. */ + MDL_EXIT_COND(context, mysys_var, old_msg); return TRUE; } global_lock.active_shared++; context->has_global_shared_lock= TRUE; - /* As a side-effect THD::exit_cond() unlocks LOCK_mdl. */ - thd->exit_cond(old_msg); + /* As a side-effect MDL_EXIT_COND() unlocks LOCK_mdl. */ + MDL_EXIT_COND(context, mysys_var, old_msg); return FALSE; } @@ -1137,12 +1186,11 @@ bool mdl_wait_for_locks(MDL_CONTEXT *context) 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; + st_my_thread_var *mysys_var= my_thread_var; safe_mutex_assert_not_owner(&LOCK_open); - DBUG_ASSERT(thd == current_thd); - while (!thd->killed) + while (!mysys_var->abort) { /* We have to check if there are some HANDLERs open by this thread @@ -1156,7 +1204,7 @@ bool mdl_wait_for_locks(MDL_CONTEXT *context) */ mysql_ha_flush(context->thd); pthread_mutex_lock(&LOCK_mdl); - old_msg= thd->enter_cond(&COND_mdl, &LOCK_mdl, "Waiting for table"); + old_msg= MDL_ENTER_COND(context, mysys_var); it.rewind(); while ((lock_data= it++)) { @@ -1179,10 +1227,10 @@ bool mdl_wait_for_locks(MDL_CONTEXT *context) break; } pthread_cond_wait(&COND_mdl, &LOCK_mdl); - /* As a side-effect THD::exit_cond() unlocks LOCK_mdl. */ - thd->exit_cond(old_msg); + /* As a side-effect MDL_EXIT_COND() unlocks LOCK_mdl. */ + MDL_EXIT_COND(context, mysys_var, old_msg); } - return thd->killed; + return mysys_var->abort; } @@ -1422,7 +1470,7 @@ void mdl_release_global_shared_lock(MDL_CONTEXT *context) bool mdl_is_exclusive_lock_owner(MDL_CONTEXT *context, int type, const char *db, const char *name) { - char key[MAX_DBKEY_LENGTH]; + char key[MAX_MDLKEY_LENGTH]; uint key_length; MDL_LOCK_DATA *lock_data; I_P_List_iterator<MDL_LOCK_DATA, MDL_LOCK_DATA_context> it(context->locks); @@ -1456,7 +1504,7 @@ bool mdl_is_exclusive_lock_owner(MDL_CONTEXT *context, int type, bool mdl_is_lock_owner(MDL_CONTEXT *context, int type, const char *db, const char *name) { - char key[MAX_DBKEY_LENGTH]; + char key[MAX_MDLKEY_LENGTH]; uint key_length; MDL_LOCK_DATA *lock_data; I_P_List_iterator<MDL_LOCK_DATA, MDL_LOCK_DATA_context> it(context->locks); diff --git a/sql/mdl.h b/sql/mdl.h index 92bd83038e5..b4b84a9ab24 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -19,6 +19,7 @@ #include "sql_plist.h" #include <my_sys.h> #include <m_string.h> +#include <mysql_com.h> class THD; @@ -148,6 +149,9 @@ void mdl_context_backup_and_reset(MDL_CONTEXT *ctx, MDL_CONTEXT *backup); void mdl_context_restore(MDL_CONTEXT *ctx, MDL_CONTEXT *backup); void mdl_context_merge(MDL_CONTEXT *target, MDL_CONTEXT *source); +/** Maximal length of key for metadata locking subsystem. */ +#define MAX_MDLKEY_LENGTH (4 + NAME_LEN + 1 + NAME_LEN + 1) + void mdl_init_lock(MDL_LOCK_DATA *lock_data, char *key, int type, const char *db, const char *name); MDL_LOCK_DATA *mdl_alloc_lock(int type, const char *db, const char *name, @@ -237,4 +241,19 @@ void* mdl_get_cached_object(MDL_LOCK_DATA *lock_data); void mdl_set_cached_object(MDL_LOCK_DATA *lock_data, void *cached_object, mdl_cached_object_release_hook release_hook); + +/* + Functions in the server's kernel used by metadata locking subsystem. +*/ + +extern bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use); +extern void mysql_ha_flush(THD *thd); +extern "C" const char *set_thd_proc_info(THD *thd, const char *info, + const char *calling_function, + const char *calling_file, + const unsigned int calling_line); +#ifndef DBUG_OFF +extern pthread_mutex_t LOCK_open; +#endif + #endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 12d7e46e821..2f15ecb2b71 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1534,8 +1534,6 @@ char *generate_partition_syntax(partition_info *part_info, Alter_info *alter_info); #endif -bool notify_thread_having_shared_lock(THD *thd, THD *in_use); - enum enum_tdc_remove_table_type {TDC_RT_REMOVE_ALL, TDC_RT_REMOVE_NOT_OWN, TDC_RT_REMOVE_UNUSED}; void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6c344ad1d4e..7803bd0ba11 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1275,7 +1275,7 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share, /* We need to hold LOCK_open while changing the open_tables list, since another thread may work on it. - @sa notify_thread_having_shared_lock() + @sa mysql_notify_thread_having_shared_lock() */ pthread_mutex_lock(&LOCK_open); @@ -1455,7 +1455,7 @@ void close_thread_tables(THD *thd, /* Note that we need to hold LOCK_open while changing the open_tables list. Another thread may work on it. - (See: notify_thread_having_shared_lock()) + (See: mysql_notify_thread_having_shared_lock()) Closing a MERGE child before the parent would be fatal if the other thread tries to abort the MERGE lock in between. */ @@ -7956,7 +7956,7 @@ void flush_tables() rest of the server is broken. */ -bool notify_thread_having_shared_lock(THD *thd, THD *in_use) +bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use) { bool signalled= FALSE; if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) && @@ -8501,7 +8501,7 @@ void close_performance_schema_table(THD *thd, Open_tables_state *backup) /* Note that we need to hold LOCK_open while changing the open_tables list. Another thread may work on it. - (See: notify_thread_having_shared_lock()) + (See: mysql_notify_thread_having_shared_lock()) Closing a MERGE child before the parent would be fatal if the other thread tries to abort the MERGE lock in between. */ diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 9b30d8cec12..49d6cbaa447 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -247,7 +247,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) &name, (uint) namelen, &alias, (uint) aliaslen, &mdl_lock_data, sizeof(MDL_LOCK_DATA), - &mdlkey, MAX_DBKEY_LENGTH, + &mdlkey, MAX_MDLKEY_LENGTH, NullS))) { DBUG_PRINT("exit",("ERROR")); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index c50d74412bf..a77ba6264a3 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3084,7 +3084,7 @@ uint get_table_open_method(TABLE_LIST *tables, @param mdlkey Pointer to the buffer for key for the lock request (should be at least strlen(db) + strlen(name) + 2 bytes, or, if the lengths are not known, - MAX_DBNAME_LENGTH) + MAX_MDLKEY_LENGTH) @param table Table list element for the table @note This is an auxiliary function to be used in cases when we want to @@ -3157,7 +3157,7 @@ static int fill_schema_table_from_frm(THD *thd,TABLE *table, uint key_length; char db_name_buff[NAME_LEN + 1], table_name_buff[NAME_LEN + 1]; MDL_LOCK_DATA mdl_lock_data; - char mdlkey[MAX_DBKEY_LENGTH]; + char mdlkey[MAX_MDLKEY_LENGTH]; bzero((char*) &table_list, sizeof(TABLE_LIST)); bzero((char*) &tbl, sizeof(TABLE)); |