diff options
author | Jon Olav Hauglid <jon.hauglid@sun.com> | 2010-02-11 11:23:39 +0100 |
---|---|---|
committer | Jon Olav Hauglid <jon.hauglid@sun.com> | 2010-02-11 11:23:39 +0100 |
commit | 3d6a89e7929292a8ca4c369d03e7d723045626b6 (patch) | |
tree | 61c2376a790a37e251fcfa30ba118b660e25e60d /sql/sql_base.cc | |
parent | d7f203c79fdb25bef8756016efc63628187520cd (diff) | |
download | mariadb-git-3d6a89e7929292a8ca4c369d03e7d723045626b6.tar.gz |
Bug #45225 Locking: hang if drop table with no timeout
This patch introduces timeouts for metadata locks.
The timeout is specified in seconds using the new dynamic system
variable "lock_wait_timeout" which has both GLOBAL and SESSION
scopes. Allowed values range from 1 to 31536000 seconds (= 1 year).
The default value is 1 year.
The new server parameter "lock-wait-timeout" can be used to set
the default value parameter upon server startup.
"lock_wait_timeout" applies to all statements that use metadata locks.
These include DML and DDL operations on tables, views, stored procedures
and stored functions. They also include LOCK TABLES, FLUSH TABLES WITH
READ LOCK and HANDLER statements.
The patch also changes thr_lock.c code (table data locks used by MyISAM
and other simplistic engines) to use the same system variable.
InnoDB row locks are unaffected.
One exception to the handling of the "lock_wait_timeout" variable
is delayed inserts. All delayed inserts are executed with a timeout
of 1 year regardless of the setting for the global variable. As the
connection issuing the delayed insert gets no notification of
delayed insert timeouts, we want to avoid unnecessary timeouts.
It's important to note that the timeout value is used for each lock
acquired and that one statement can take more than one lock.
A statement can therefore block for longer than the lock_wait_timeout
value before reporting a timeout error. When lock timeout occurs,
ER_LOCK_WAIT_TIMEOUT is reported.
Test case added to lock_multi.test.
include/my_pthread.h:
Added macros for comparing two timespec structs.
include/thr_lock.h:
Introduced timeouts for thr_lock.c locks.
mysql-test/r/mysqld--help-notwin.result:
Updated result file with the new server variable.
mysql-test/r/mysqld--help-win.result:
Updated result file with the new server variable.
mysql-test/suite/sys_vars/r/lock_wait_timeout_basic.result:
Added basic test for the new server variable.
mysql-test/suite/sys_vars/t/lock_wait_timeout_basic.test:
Added basic test for the new server variable.
mysys/thr_lock.c:
Introduced timeouts for thr_lock.c locks.
sql/mdl.cc:
Introduced timeouts for metadata locks.
sql/mdl.h:
Introduced timeouts for metadata locks.
sql/sql_base.cc:
Introduced timeouts in tdc_wait_for_old_versions().
sql/sql_class.h:
Added new server variable lock_wait_timeout.
sql/sys_vars.cc:
Added new server variable lock_wait_timeout.
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1564838548f..ae5c5803545 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2148,7 +2148,8 @@ bool wait_while_table_is_used(THD *thd, TABLE *table, table->s->table_name.str, (ulong) table->s, table->db_stat, table->s->version)); - if (thd->mdl_context.upgrade_shared_lock_to_exclusive(table->mdl_ticket)) + if (thd->mdl_context.upgrade_shared_lock_to_exclusive( + table->mdl_ticket, thd->variables.lock_wait_timeout)) DBUG_RETURN(TRUE); mysql_mutex_lock(&LOCK_open); @@ -2362,7 +2363,8 @@ 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)) + if (thd->mdl_context.acquire_locks(&mdl_requests, + thd->variables.lock_wait_timeout)) return 1; } else @@ -3843,7 +3845,8 @@ 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); + result= thd->mdl_context.wait_for_lock(mdl_request, + thd->variables.lock_wait_timeout); break; case OT_WAIT_TDC: result= tdc_wait_for_old_versions(thd, &m_mdl_requests); @@ -3862,7 +3865,9 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request, mdl_requests.push_front(&mdl_xlock_request); mdl_requests.push_front(&mdl_global_request); - if ((result= thd->mdl_context.acquire_locks(&mdl_requests))) + if ((result= + thd->mdl_context.acquire_locks(&mdl_requests, + thd->variables.lock_wait_timeout))) break; DBUG_ASSERT(mdl_request->key.mdl_namespace() == MDL_key::TABLE); @@ -3893,7 +3898,9 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request, mdl_requests.push_front(&mdl_xlock_request); mdl_requests.push_front(&mdl_global_request); - if ((result= thd->mdl_context.acquire_locks(&mdl_requests))) + if ((result= + thd->mdl_context.acquire_locks(&mdl_requests, + thd->variables.lock_wait_timeout))) break; DBUG_ASSERT(mdl_request->key.mdl_namespace() == MDL_key::TABLE); @@ -4381,7 +4388,8 @@ 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)) + if (thd->mdl_context.acquire_locks(&mdl_requests, + thd->variables.lock_wait_timeout)) return TRUE; for (table= tables_start; table && table != tables_end; @@ -8530,6 +8538,9 @@ tdc_wait_for_old_versions(THD *thd, MDL_request_list *mdl_requests) TABLE_SHARE *share; const char *old_msg; MDL_request *mdl_request; + struct timespec abstime; + set_timespec(abstime, thd->variables.lock_wait_timeout); + int wait_result= 0; while (!thd->killed) { @@ -8557,15 +8568,31 @@ tdc_wait_for_old_versions(THD *thd, MDL_request_list *mdl_requests) } if (!mdl_request) { + /* + Reset wait_result here in case this was the final check + after getting a timeout from mysql_cond_timedwait(). + */ + wait_result= 0; + mysql_mutex_unlock(&LOCK_open); + break; + } + if (wait_result == ETIMEDOUT || wait_result == ETIME) + { + /* + Test for timeout here instead of right after mysql_cond_timedwait(). + This allows for a final iteration and a final check before reporting + ER_LOCK_WAIT_TIMEOUT. + */ mysql_mutex_unlock(&LOCK_open); + my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0)); break; } old_msg= thd->enter_cond(&COND_refresh, &LOCK_open, "Waiting for table"); - mysql_cond_wait(&COND_refresh, &LOCK_open); + wait_result= mysql_cond_timedwait(&COND_refresh, &LOCK_open, &abstime); /* LOCK_open mutex is unlocked by THD::exit_cond() as side-effect. */ thd->exit_cond(old_msg); } - return thd->killed; + return thd->killed || wait_result == ETIMEDOUT || wait_result == ETIME; } |