diff options
author | Jon Olav Hauglid <jon.hauglid@sun.com> | 2010-02-24 18:04:00 +0100 |
---|---|---|
committer | Jon Olav Hauglid <jon.hauglid@sun.com> | 2010-02-24 18:04:00 +0100 |
commit | dd42aab8406e70caec4f58435c0281cddc8ea2c0 (patch) | |
tree | 9d2e97b85337c7ffc2bf1d2a6643b34baf1acda8 | |
parent | b6e0f92f052a37568b984330b8cca8331c979a8d (diff) | |
download | mariadb-git-dd42aab8406e70caec4f58435c0281cddc8ea2c0.tar.gz |
Followup to Bug#45225 Locking: hang if drop table with no timeout
This patch prevents system threads and system table accesses from
using user-specified values for "lock_wait_timeout". Instead all
such accesses are done using the default value (1 year).
This prevents background tasks (such as replication, events,
accessing stored function definitions, logging, reading time-zone
information, etc.) from failing in cases where the global value
of "lock_wait_timeout" is set very low.
The patch also simplifies the open tables API. Rather than adding
another convenience function for opening and locking system tables,
this patch removes most of the existing convenience functions for
open_and_lock_tables_derived(). Before, open_and_lock_tables() was
a convenience function that enforced derived tables handling, while
open_and_lock_tables_derived() was the main function where derived
tables handling was optional. Now, this convencience function is
gone and the main function is renamed to open_and_lock_tables().
No test case added as it would have required the use of --sleep to
check that system threads and system tables have a different timeout
value from the user-specified "lock_wait_timeout" system variable.
-rw-r--r-- | sql/event_db_repository.cc | 9 | ||||
-rwxr-xr-x | sql/event_scheduler.cc | 3 | ||||
-rw-r--r-- | sql/ha_ndbcluster.cc | 2 | ||||
-rw-r--r-- | sql/ha_ndbcluster_binlog.cc | 4 | ||||
-rw-r--r-- | sql/lock.cc | 7 | ||||
-rw-r--r-- | sql/log_event.cc | 2 | ||||
-rw-r--r-- | sql/log_event_old.cc | 2 | ||||
-rw-r--r-- | sql/mysql_priv.h | 30 | ||||
-rw-r--r-- | sql/slave.cc | 2 | ||||
-rw-r--r-- | sql/sp_head.cc | 2 | ||||
-rw-r--r-- | sql/sql_acl.cc | 18 | ||||
-rw-r--r-- | sql/sql_base.cc | 65 | ||||
-rw-r--r-- | sql/sql_class.h | 12 | ||||
-rw-r--r-- | sql/sql_delete.cc | 2 | ||||
-rw-r--r-- | sql/sql_insert.cc | 10 | ||||
-rw-r--r-- | sql/sql_load.cc | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 20 | ||||
-rw-r--r-- | sql/sql_plugin.cc | 7 | ||||
-rw-r--r-- | sql/sql_servers.cc | 8 | ||||
-rw-r--r-- | sql/sql_table.cc | 21 | ||||
-rw-r--r-- | sql/sql_udf.cc | 6 | ||||
-rw-r--r-- | sql/sql_view.cc | 2 | ||||
-rw-r--r-- | sql/tztime.cc | 4 | ||||
-rw-r--r-- | storage/perfschema/pfs_engine_table.cc | 2 |
24 files changed, 128 insertions, 114 deletions
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index e9bcecc459d..0696652deb1 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -574,7 +574,7 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type, tables.init_one_table("mysql", 5, "event", 5, "event", lock_type); - if (simple_open_n_lock_tables(thd, &tables)) + if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { close_thread_tables(thd); DBUG_RETURN(TRUE); @@ -1129,11 +1129,10 @@ Event_db_repository::check_system_tables(THD *thd) DBUG_ENTER("Event_db_repository::check_system_tables"); DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd)); - /* Check mysql.db */ tables.init_one_table("mysql", 5, "db", 2, "db", TL_READ); - if (simple_open_n_lock_tables(thd, &tables)) + if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { ret= 1; sql_print_error("Cannot open mysql.db"); @@ -1148,7 +1147,7 @@ Event_db_repository::check_system_tables(THD *thd) /* Check mysql.user */ tables.init_one_table("mysql", 5, "user", 4, "user", TL_READ); - if (simple_open_n_lock_tables(thd, &tables)) + if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { ret= 1; sql_print_error("Cannot open mysql.user"); @@ -1168,7 +1167,7 @@ Event_db_repository::check_system_tables(THD *thd) /* Check mysql.event */ tables.init_one_table("mysql", 5, "event", 5, "event", TL_READ); - if (simple_open_n_lock_tables(thd, &tables)) + if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { ret= 1; sql_print_error("Cannot open mysql.event"); diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 733f2a7167f..3ceb1597a41 100755 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -203,6 +203,9 @@ pre_init_event_thread(THD* thd) thd->version= refresh_version; thd->set_time(); + /* Do not use user-supplied timeout value for system threads. */ + thd->variables.lock_wait_timeout= LONG_TIMEOUT; + DBUG_VOID_RETURN; } diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index b0276e14ebf..05a42220caf 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -9504,6 +9504,8 @@ pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused))) my_net_init(&thd->net, 0); thd->main_security_ctx.master_access= ~0; thd->main_security_ctx.priv_user = 0; + /* Do not use user-supplied timeout value for system threads. */ + thd->variables.lock_wait_timeout= LONG_TIMEOUT; CHARSET_INFO *charset_connection; charset_connection= get_charset_by_csname("utf8", diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index ed2bdfbbe71..279d5b4c242 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -2348,7 +2348,7 @@ static int open_ndb_binlog_index(THD *thd, TABLE **ndb_binlog_index) tables->required_type= FRMTYPE_TABLE; uint counter; thd->clear_error(); - if (simple_open_n_lock_tables(thd, tables)) + if (open_and_lock_tables(thd, tables, FALSE, 0)) { if (thd->killed) sql_print_error("NDB Binlog: Opening ndb_binlog_index: killed"); @@ -3675,6 +3675,8 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) my_net_init(&thd->net, 0); thd->main_security_ctx.master_access= ~0; thd->main_security_ctx.priv_user= 0; + /* Do not use user-supplied timeout value for system threads. */ + thd->variables.lock_wait_timeout= LONG_TIMEOUT; /* Set up ndb binlog diff --git a/sql/lock.cc b/sql/lock.cc index fa58e43f6bb..3ff131bb828 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -251,6 +251,7 @@ static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock) MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY MYSQL_LOCK_IGNORE_FLUSH Ignore a flush tables. + MYSQL_LOCK_IGNORE_TIMEOUT Use maximum timeout value. @param need_reopen Out parameter, TRUE if some tables were altered or deleted and should be reopened by caller. @@ -277,6 +278,9 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, if (mysql_lock_tables_check(thd, tables, count, flags)) DBUG_RETURN (NULL); + ulong timeout= (flags & MYSQL_LOCK_IGNORE_TIMEOUT) ? + LONG_TIMEOUT : thd->variables.lock_wait_timeout; + for (;;) { if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS, @@ -336,8 +340,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks + sql_lock->lock_count, sql_lock->lock_count, - thd->lock_id, - thd->variables.lock_wait_timeout)]; + thd->lock_id, timeout)]; if (rc > 1) /* a timeout or a deadlock */ { if (sql_lock->table_count) diff --git a/sql/log_event.cc b/sql/log_event.cc index b0deee62fd7..b0437b7c2e5 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -7480,7 +7480,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) /* A small test to verify that objects have consistent types */ DBUG_ASSERT(sizeof(thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS)); - if (simple_open_n_lock_tables(thd, rli->tables_to_lock)) + if (open_and_lock_tables(thd, rli->tables_to_lock, FALSE, 0)) { uint actual_error= thd->stmt_da->sql_errno(); if (thd->is_slave_error || thd->is_fatal_error) diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index caa69269e28..2d559804534 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -73,7 +73,7 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info */ thd->lex->set_stmt_row_injection(); - if (simple_open_n_lock_tables(thd, rli->tables_to_lock)) + if (open_and_lock_tables(thd, rli->tables_to_lock, FALSE, 0)) { uint actual_error= thd->stmt_da->sql_errno(); if (thd->is_slave_error || thd->is_fatal_error) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a006d2a07ff..20720d50194 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1562,26 +1562,16 @@ open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags) return open_tables(thd, tables, counter, flags, &prelocking_strategy); } /* open_and_lock_tables with optional derived handling */ -bool open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, - bool derived, uint flags, - Prelocking_strategy *prelocking_strategy); -inline bool open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, - bool derived, uint flags) +bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, + bool derived, uint flags, + Prelocking_strategy *prelocking_strategy); +inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, + bool derived, uint flags) { DML_prelocking_strategy prelocking_strategy; - return open_and_lock_tables_derived(thd, tables, derived, flags, - &prelocking_strategy); -} -/* simple open_and_lock_tables without derived handling */ -inline bool simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) -{ - return open_and_lock_tables_derived(thd, tables, FALSE, 0); -} -/* open_and_lock_tables with derived handling */ -inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) -{ - return open_and_lock_tables_derived(thd, tables, TRUE, 0); + return open_and_lock_tables(thd, tables, derived, flags, + &prelocking_strategy); } /* simple open_and_lock_tables without derived handling for single table */ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l, @@ -2171,11 +2161,17 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, in parser. */ #define MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL 0x0800 +/** + When opening or locking the table, use the maximum timeout + (LONG_TIMEOUT = 1 year) rather than the user-supplied timeout value. +*/ +#define MYSQL_LOCK_IGNORE_TIMEOUT 0x1000 /** Please refer to the internals manual. */ #define MYSQL_OPEN_REOPEN (MYSQL_LOCK_IGNORE_FLUSH |\ MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |\ MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |\ + MYSQL_LOCK_IGNORE_TIMEOUT |\ MYSQL_OPEN_GET_NEW_TABLE |\ MYSQL_OPEN_SKIP_TEMPORARY |\ MYSQL_OPEN_HAS_MDL_LOCK) diff --git a/sql/slave.cc b/sql/slave.cc index 45c73a3e190..2f06d468d64 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2030,6 +2030,8 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) thd_proc_info(thd, "Waiting for master update"); thd->version=refresh_version; thd->set_time(); + /* Do not use user-supplied timeout value for system threads. */ + thd->variables.lock_wait_timeout= LONG_TIMEOUT; DBUG_RETURN(0); } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index e50aa208798..d2ac5d638d7 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2825,7 +2825,7 @@ int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables) and open and lock them before executing instructions core function. */ if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE) - || open_and_lock_tables(thd, tables)) + || open_and_lock_tables(thd, tables, TRUE, 0)) result= -1; else result= 0; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index fb257a6e5ec..86f62d9bf72 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -675,7 +675,7 @@ my_bool acl_reload(THD *thd) tables[0].open_type= tables[1].open_type= tables[2].open_type= OT_BASE_ONLY; init_mdl_requests(tables); - if (simple_open_n_lock_tables(thd, tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { /* Execution might have been interrupted; only print the error message @@ -1602,7 +1602,7 @@ bool change_password(THD *thd, const char *host, const char *user, } #endif - if (!(table= open_ltable(thd, &tables, TL_WRITE, 0))) + if (!(table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) DBUG_RETURN(1); mysql_mutex_lock(&acl_cache->lock); @@ -3040,7 +3040,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, class LEX_COLUMN *column; List_iterator <LEX_COLUMN> column_iter(columns); - if (open_and_lock_tables(thd, table_list)) + if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); while ((column = column_iter++)) @@ -3146,7 +3146,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, */ Query_tables_list backup; thd->lex->reset_n_backup_query_tables_list(&backup); - if (simple_open_n_lock_tables(thd,tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // Should never happen close_thread_tables(thd); /* purecov: deadcode */ /* Restore the state of binlog format */ @@ -3374,7 +3374,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, } #endif - if (simple_open_n_lock_tables(thd,tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // Should never happen close_thread_tables(thd); /* Restore the state of binlog format */ @@ -3531,7 +3531,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, } #endif - if (simple_open_n_lock_tables(thd,tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // This should never happen close_thread_tables(thd); /* purecov: deadcode */ /* Restore the state of binlog format */ @@ -3853,7 +3853,7 @@ static my_bool grant_reload_procs_priv(THD *thd) TL_READ); table.open_type= OT_BASE_ONLY; - if (simple_open_n_lock_tables(thd, &table)) + if (open_and_lock_tables(thd, &table, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { close_thread_tables(thd); DBUG_RETURN(TRUE); @@ -3924,7 +3924,7 @@ my_bool grant_reload(THD *thd) To avoid deadlocks we should obtain table locks before obtaining LOCK_grant rwlock. */ - if (simple_open_n_lock_tables(thd, tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) goto end; mysql_rwlock_wrlock(&LOCK_grant); @@ -5227,7 +5227,7 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables) } #endif - if (simple_open_n_lock_tables(thd, tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // This should never happen close_thread_tables(thd); DBUG_RETURN(-1); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d5a664df0d0..0f572350647 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -122,7 +122,8 @@ static bool open_table_entry_fini(THD *thd, TABLE_SHARE *share, TABLE *entry); static bool auto_repair_table(THD *thd, TABLE_LIST *table_list); static void free_cache_entry(TABLE *entry); static bool tdc_wait_for_old_versions(THD *thd, - MDL_request_list *mdl_requests); + MDL_request_list *mdl_requests, + ulong timeout); static bool has_write_table_with_auto_increment(TABLE_LIST *tables); @@ -2363,8 +2364,7 @@ open_table_get_mdl_lock(THD *thd, TABLE_LIST *table_list, mdl_requests.push_front(mdl_request); mdl_requests.push_front(global_request); - if (thd->mdl_context.acquire_locks(&mdl_requests, - thd->variables.lock_wait_timeout)) + if (thd->mdl_context.acquire_locks(&mdl_requests, ot_ctx->get_timeout())) return 1; } else @@ -3308,7 +3308,7 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count) bool Locked_tables_list::reopen_tables(THD *thd) { - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); bool lt_refresh_unused; size_t reopen_count= 0; MYSQL_LOCK *lock; @@ -3744,13 +3744,14 @@ end_with_lock_open: /** Open_table_context */ -Open_table_context::Open_table_context(THD *thd) +Open_table_context::Open_table_context(THD *thd, ulong timeout) :m_action(OT_NO_ACTION), m_start_of_statement_svp(thd->mdl_context.mdl_savepoint()), m_has_locks((thd->in_multi_stmt_transaction() && thd->mdl_context.has_locks()) || thd->mdl_context.trans_sentinel()), - m_global_mdl_request(NULL) + m_global_mdl_request(NULL), + m_timeout(timeout) {} @@ -3845,11 +3846,10 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request, switch (m_action) { case OT_WAIT_MDL_LOCK: - result= thd->mdl_context.wait_for_lock(mdl_request, - thd->variables.lock_wait_timeout); + result= thd->mdl_context.wait_for_lock(mdl_request, get_timeout()); break; case OT_WAIT_TDC: - result= tdc_wait_for_old_versions(thd, &m_mdl_requests); + result= tdc_wait_for_old_versions(thd, &m_mdl_requests, get_timeout()); DBUG_ASSERT(thd->mysys_var->current_mutex == NULL); break; case OT_DISCOVER: @@ -3866,8 +3866,7 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request, mdl_requests.push_front(&mdl_global_request); if ((result= - thd->mdl_context.acquire_locks(&mdl_requests, - thd->variables.lock_wait_timeout))) + thd->mdl_context.acquire_locks(&mdl_requests, get_timeout()))) break; DBUG_ASSERT(mdl_request->key.mdl_namespace() == MDL_key::TABLE); @@ -3899,8 +3898,7 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request, mdl_requests.push_front(&mdl_global_request); if ((result= - thd->mdl_context.acquire_locks(&mdl_requests, - thd->variables.lock_wait_timeout))) + thd->mdl_context.acquire_locks(&mdl_requests, get_timeout()))) break; DBUG_ASSERT(mdl_request->key.mdl_namespace() == MDL_key::TABLE); @@ -4397,8 +4395,7 @@ open_tables_acquire_upgradable_mdl(THD *thd, TABLE_LIST *tables_start, mdl_requests.push_front(global_request); } - if (thd->mdl_context.acquire_locks(&mdl_requests, - thd->variables.lock_wait_timeout)) + if (thd->mdl_context.acquire_locks(&mdl_requests, ot_ctx->get_timeout())) return TRUE; for (table= tables_start; table && table != tables_end; @@ -4457,7 +4454,8 @@ bool open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags, TABLE_LIST **table_to_open; Sroutine_hash_entry **sroutine_to_open; TABLE_LIST *tables; - Open_table_context ot_ctx(thd); + Open_table_context ot_ctx(thd, (flags & MYSQL_LOCK_IGNORE_TIMEOUT) ? + LONG_TIMEOUT : thd->variables.lock_wait_timeout); bool error= FALSE; MEM_ROOT new_frm_mem; bool has_prelocking_list; @@ -4961,7 +4959,7 @@ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l, table_l->required_type= FRMTYPE_TABLE; /* Open the table. */ - if (open_and_lock_tables_derived(thd, table_l, FALSE, flags)) + if (open_and_lock_tables(thd, table_l, FALSE, flags)) table_l->table= NULL; /* Just to be sure. */ /* Restore list. */ @@ -4999,7 +4997,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type, uint lock_flags) { TABLE *table; - Open_table_context ot_ctx(thd); + Open_table_context ot_ctx(thd, (lock_flags & MYSQL_LOCK_IGNORE_TIMEOUT) ? + LONG_TIMEOUT : thd->variables.lock_wait_timeout); bool refresh; bool error; DBUG_ENTER("open_ltable"); @@ -5098,20 +5097,13 @@ end: @note The lock will automaticaly be freed by close_thread_tables() - @note - There are several convenience functions, e.g. : - - simple_open_n_lock_tables(thd, tables) without derived handling - - open_and_lock_tables(thd, tables) with derived handling - Both inline functions call open_and_lock_tables_derived() with - the third argument set appropriately. - @retval FALSE OK. @retval TRUE Error */ -bool open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, - bool derived, uint flags, - Prelocking_strategy *prelocking_strategy) +bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, + bool derived, uint flags, + Prelocking_strategy *prelocking_strategy) { uint counter; bool need_reopen; @@ -5125,7 +5117,7 @@ bool open_and_lock_tables_derived(THD *thd, TABLE_LIST *tables, statement. */ MDL_ticket *start_of_statement_svp= thd->mdl_context.mdl_savepoint(); - DBUG_ENTER("open_and_lock_tables_derived"); + DBUG_ENTER("open_and_lock_tables"); DBUG_PRINT("enter", ("derived handling: %d", derived)); for ( ; ; ) @@ -8536,16 +8528,18 @@ void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type, @param thd Thread context @param context Metadata locking context with locks. + @param timeout Seconds to wait before reporting ER_LOCK_WAIT_TIMEOUT. */ static bool -tdc_wait_for_old_versions(THD *thd, MDL_request_list *mdl_requests) +tdc_wait_for_old_versions(THD *thd, MDL_request_list *mdl_requests, + ulong timeout) { TABLE_SHARE *share; const char *old_msg; MDL_request *mdl_request; struct timespec abstime; - set_timespec(abstime, thd->variables.lock_wait_timeout); + set_timespec(abstime, timeout); int wait_result= 0; while (!thd->killed) @@ -8812,8 +8806,9 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, lex->reset_n_backup_query_tables_list(&query_tables_list_backup); thd->reset_n_backup_open_tables_state(backup); - if (open_and_lock_tables_derived(thd, table_list, FALSE, - MYSQL_LOCK_IGNORE_FLUSH)) + if (open_and_lock_tables(thd, table_list, FALSE, + MYSQL_LOCK_IGNORE_FLUSH | + MYSQL_LOCK_IGNORE_TIMEOUT)) { lex->restore_backup_query_tables_list(&query_tables_list_backup); goto error; @@ -8875,7 +8870,8 @@ open_system_table_for_update(THD *thd, TABLE_LIST *one_table) { DBUG_ENTER("open_system_table_for_update"); - TABLE *table= open_ltable(thd, one_table, one_table->lock_type, 0); + TABLE *table= open_ltable(thd, one_table, one_table->lock_type, + MYSQL_LOCK_IGNORE_TIMEOUT); if (table) { DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_SYSTEM); @@ -8902,6 +8898,7 @@ open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup) uint flags= ( MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK | MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY | MYSQL_LOCK_IGNORE_FLUSH | + MYSQL_LOCK_IGNORE_TIMEOUT | MYSQL_LOCK_PERF_SCHEMA); TABLE *table; /* Save value that is changed in mysql_lock_tables() */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 2efff63354a..617c13a0a08 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1280,7 +1280,7 @@ public: OT_DISCOVER, OT_REPAIR }; - Open_table_context(THD *thd); + Open_table_context(THD *thd, ulong timeout); bool recover_from_failed_open(THD *thd, MDL_request *mdl_request, TABLE_LIST *table); @@ -1305,6 +1305,11 @@ public: MDL_request *get_global_mdl_request(THD *thd); + inline ulong get_timeout() const + { + return m_timeout; + } + private: /** List of requests for all locks taken so far. Used for waiting on locks. */ MDL_request_list m_mdl_requests; @@ -1322,6 +1327,11 @@ private: opening tables for statements which take upgradable shared metadata locks. */ MDL_request *m_global_mdl_request; + /** + Lock timeout in seconds. Initialized to LONG_TIMEOUT when opening system + tables or to the "lock_wait_timeout" system variable for regular tables. + */ + uint m_timeout; }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index ea466da8ea1..2c3242c10cd 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -57,7 +57,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, THD::STMT_QUERY_TYPE : THD::ROW_QUERY_TYPE; - if (open_and_lock_tables(thd, table_list)) + if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); if (!(table= table_list->table)) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 45c9c0363dd..ddf7dcb22d0 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -545,7 +545,7 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list) Open tables used for sub-selects or in stored functions, will also cache these functions. */ - if (open_and_lock_tables(thd, table_list->next_global)) + if (open_and_lock_tables(thd, table_list->next_global, TRUE, 0)) { end_delayed_insert(thd); DBUG_RETURN(TRUE); @@ -569,7 +569,7 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list) Use a normal insert. */ table_list->lock_type= TL_WRITE; - DBUG_RETURN(open_and_lock_tables(thd, table_list)); + DBUG_RETURN(open_and_lock_tables(thd, table_list, TRUE, 0)); } @@ -646,7 +646,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, } else { - if (open_and_lock_tables(thd, table_list)) + if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); } lock_type= table_list->lock_type; @@ -3619,7 +3619,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); /* Here we open the destination table, on which we already have an exclusive metadata lock. @@ -3638,7 +3638,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, } else { - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); if (open_table(thd, create_table, thd->mem_root, &ot_ctx_unused, MYSQL_OPEN_TEMPORARY_ONLY)) { diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 1eabce0b474..3f49543c69d 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -195,7 +195,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ER(WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED)); } - if (open_and_lock_tables(thd, table_list)) + if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, &thd->lex->select_lex.top_join_list, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c7e1be2237b..b3c60fbd429 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2077,7 +2077,7 @@ case SQLCOM_PREPARE: } case SQLCOM_DO: if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) - || open_and_lock_tables(thd, all_tables)) + || open_and_lock_tables(thd, all_tables, TRUE, 0)) goto error; res= mysql_do(thd, *lex->insert_list); @@ -2414,7 +2414,7 @@ case SQLCOM_PREPARE: create_table->open_type= OT_BASE_ONLY; } - if (!(res= open_and_lock_tables_derived(thd, lex->query_tables, TRUE, 0))) + if (!(res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0))) { /* Is table which we are changing used somewhere in other parts @@ -3007,7 +3007,7 @@ end_with_restore_list: unit->set_limit(select_lex); - if (!(res= open_and_lock_tables(thd, all_tables))) + if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0))) { MYSQL_INSERT_SELECT_START(thd->query()); /* Skip first table, which is the table we are inserting in */ @@ -3109,7 +3109,7 @@ end_with_restore_list: goto error; thd_proc_info(thd, "init"); - if ((res= open_and_lock_tables(thd, all_tables))) + if ((res= open_and_lock_tables(thd, all_tables, TRUE, 0))) break; MYSQL_MULTI_DELETE_START(thd->query()); @@ -3237,7 +3237,7 @@ end_with_restore_list: List<set_var_base> *lex_var_list= &lex->var_list; if ((check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) - || open_and_lock_tables(thd, all_tables))) + || open_and_lock_tables(thd, all_tables, TRUE, 0))) goto error; if (!(res= sql_set_variables(thd, lex_var_list))) { @@ -3303,9 +3303,9 @@ end_with_restore_list: { Lock_tables_prelocking_strategy lock_tables_prelocking_strategy; - res= (open_and_lock_tables_derived(thd, all_tables, FALSE, - MYSQL_OPEN_TAKE_UPGRADABLE_MDL, - &lock_tables_prelocking_strategy) || + res= (open_and_lock_tables(thd, all_tables, FALSE, + MYSQL_OPEN_TAKE_UPGRADABLE_MDL, + &lock_tables_prelocking_strategy) || thd->locked_tables_list.init_locked_tables(thd)); } @@ -4008,7 +4008,7 @@ create_sp_error: */ if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) || - open_and_lock_tables(thd, all_tables)) + open_and_lock_tables(thd, all_tables, TRUE, 0)) goto error; /* @@ -4510,7 +4510,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) param->select_limit= new Item_int((ulonglong) thd->variables.select_limit); } - if (!(res= open_and_lock_tables(thd, all_tables))) + if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0))) { if (lex->describe) { diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index f0d9560dff4..3d1380d46f3 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1469,7 +1469,7 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv) goto end; #endif /* EMBEDDED_LIBRARY */ - if (simple_open_n_lock_tables(new_thd, &tables)) + if (open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { DBUG_PRINT("error",("Can't open plugin table")); sql_print_error("Can't open the mysql.plugin table. Please " @@ -1746,7 +1746,8 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl DBUG_RETURN(TRUE); /* need to open before acquiring LOCK_plugin or it will deadlock */ - if (! (table = open_ltable(thd, &tables, TL_WRITE, 0))) + if (! (table = open_ltable(thd, &tables, TL_WRITE, + MYSQL_LOCK_IGNORE_TIMEOUT))) DBUG_RETURN(TRUE); mysql_mutex_lock(&LOCK_plugin); @@ -1817,7 +1818,7 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE); /* need to open before acquiring LOCK_plugin or it will deadlock */ - if (! (table= open_ltable(thd, &tables, TL_WRITE, 0))) + if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) DBUG_RETURN(TRUE); mysql_mutex_lock(&LOCK_plugin); diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 0af076d6102..0bf38639ff7 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -253,7 +253,7 @@ bool servers_reload(THD *thd) tables[0].init_one_table("mysql", 5, "servers", 7, "servers", TL_READ); - if (simple_open_n_lock_tables(thd, tables)) + if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { /* Execution might have been interrupted; only print the error message @@ -390,7 +390,7 @@ insert_server(THD *thd, FOREIGN_SERVER *server) tables.init_one_table("mysql", 5, "servers", 7, "servers", TL_WRITE); /* need to open before acquiring THR_LOCK_plugin or it will deadlock */ - if (! (table= open_ltable(thd, &tables, TL_WRITE, 0))) + if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) goto end; /* insert the server into the table */ @@ -611,7 +611,7 @@ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options) if ((error= delete_server_record_in_cache(server_options))) goto end; - if (! (table= open_ltable(thd, &tables, TL_WRITE, 0))) + if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) { error= my_errno; goto end; @@ -728,7 +728,7 @@ int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered) tables.init_one_table("mysql", 5, "servers", 7, "servers", TL_WRITE); - if (!(table= open_ltable(thd, &tables, TL_WRITE, 0))) + if (!(table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) { error= my_errno; goto end; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9acbc37fd9a..4bf56c7f8c8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4227,8 +4227,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, /* Open or obtain an exclusive metadata lock on table being created. */ - if (open_and_lock_tables_derived(thd, thd->lex->query_tables, FALSE, - 0)) + if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0)) { result= TRUE; goto unlock; @@ -4427,7 +4426,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, char from[FN_REFLEN],tmp[FN_REFLEN+32]; const char **ext; MY_STAT stat_info; - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); DBUG_ENTER("prepare_for_repair"); uint reopen_for_repair_flags= (MYSQL_LOCK_IGNORE_FLUSH | MYSQL_OPEN_HAS_MDL_LOCK); @@ -4679,8 +4678,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (view_operator_func == NULL) table->required_type=FRMTYPE_TABLE; - open_error= open_and_lock_tables_derived(thd, table, TRUE, - MYSQL_OPEN_TAKE_UPGRADABLE_MDL); + open_error= open_and_lock_tables(thd, table, TRUE, + MYSQL_OPEN_TAKE_UPGRADABLE_MDL); thd->no_warnings_for_error= 0; table->next_global= save_next_global; table->next_local= save_next_local; @@ -5349,7 +5348,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, char buf[2048]; String query(buf, sizeof(buf), system_charset_info); query.length(0); // Have to zero it since constructor doesn't - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); /* The condition avoids a crash as described in BUG#48506. Other @@ -6558,9 +6557,9 @@ view_err: Alter_table_prelocking_strategy alter_prelocking_strategy(alter_info); - error= open_and_lock_tables_derived(thd, table_list, FALSE, - MYSQL_OPEN_TAKE_UPGRADABLE_MDL, - &alter_prelocking_strategy); + error= open_and_lock_tables(thd, table_list, FALSE, + MYSQL_OPEN_TAKE_UPGRADABLE_MDL, + &alter_prelocking_strategy); if (error) { @@ -7148,7 +7147,7 @@ view_err: { if (table->s->tmp_table) { - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); TABLE_LIST tbl; bzero((void*) &tbl, sizeof(tbl)); tbl.db= new_db; @@ -7433,7 +7432,7 @@ view_err: To do this we need to obtain a handler object for it. NO need to tamper with MERGE tables. The real open is done later. */ - Open_table_context ot_ctx_unused(thd); + Open_table_context ot_ctx_unused(thd, LONG_TIMEOUT); TABLE *t_table; if (new_name != table_name || new_db != db) { diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 3bead5217f0..7dfcf9f6b2e 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -163,7 +163,7 @@ void udf_init() tables.init_one_table(db, sizeof(db)-1, "func", 4, "func", TL_READ); - if (simple_open_n_lock_tables(new_thd, &tables)) + if (open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { DBUG_PRINT("error",("Can't open udf table")); sql_print_error("Can't open the mysql.func table. Please " @@ -505,7 +505,7 @@ int mysql_create_function(THD *thd,udf_func *udf) tables.init_one_table("mysql", 5, "func", 4, "func", TL_WRITE); /* Allow creation of functions even if we can't open func table */ - if (!(table = open_ltable(thd, &tables, TL_WRITE, 0))) + if (!(table = open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) goto err; table->use_all_columns(); restore_record(table, s->default_values); // Default values for fields @@ -596,7 +596,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) tables.init_one_table("mysql", 5, "func", 4, "func", TL_WRITE); - if (!(table = open_ltable(thd, &tables, TL_WRITE, 0))) + if (!(table = open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) goto err; table->use_all_columns(); table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index b9eb6a63552..5f61adb392d 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -396,7 +396,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, view->lock_strategy= TABLE_LIST::EXCLUSIVE_MDL; view->open_type= OT_BASE_ONLY; - if (open_and_lock_tables(thd, lex->query_tables)) + if (open_and_lock_tables(thd, lex->query_tables, TRUE, 0)) { view= lex->unlink_first_table(&link_to_local); res= TRUE; diff --git a/sql/tztime.cc b/sql/tztime.cc index 01450c9bae3..632dca1ce44 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -1667,8 +1667,8 @@ my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap) We need to open only mysql.time_zone_leap_second, but we try to open all time zone tables to see if they exist. */ - if (open_and_lock_tables_derived(thd, tz_tables, FALSE, - MYSQL_LOCK_IGNORE_FLUSH)) + if (open_and_lock_tables(thd, tz_tables, FALSE, + MYSQL_LOCK_IGNORE_FLUSH | MYSQL_LOCK_IGNORE_TIMEOUT)) { sql_print_warning("Can't open and lock time zone table: %s " "trying to live without them", thd->stmt_da->message()); diff --git a/storage/perfschema/pfs_engine_table.cc b/storage/perfschema/pfs_engine_table.cc index c824b93093e..d0f5315ff36 100644 --- a/storage/perfschema/pfs_engine_table.cc +++ b/storage/perfschema/pfs_engine_table.cc @@ -128,7 +128,7 @@ void PFS_engine_table_share::check_one_table(THD *thd) thd->lex= &dummy_lex; lex_start(thd); - if (! simple_open_n_lock_tables(thd, &tables)) + if (! open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { PFS_check_intact checker; |