summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorJon Olav Hauglid <jon.hauglid@sun.com>2010-02-11 11:23:39 +0100
committerJon Olav Hauglid <jon.hauglid@sun.com>2010-02-11 11:23:39 +0100
commit3d6a89e7929292a8ca4c369d03e7d723045626b6 (patch)
tree61c2376a790a37e251fcfa30ba118b660e25e60d /sql
parentd7f203c79fdb25bef8756016efc63628187520cd (diff)
downloadmariadb-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')
-rw-r--r--sql/lock.cc12
-rw-r--r--sql/mdl.cc114
-rw-r--r--sql/mdl.h14
-rw-r--r--sql/sql_base.cc43
-rw-r--r--sql/sql_class.h1
-rw-r--r--sql/sql_delete.cc3
-rw-r--r--sql/sql_insert.cc12
-rw-r--r--sql/sql_show.cc4
-rw-r--r--sql/sql_table.cc3
-rw-r--r--sql/sys_vars.cc6
10 files changed, 144 insertions, 68 deletions
diff --git a/sql/lock.cc b/sql/lock.cc
index 97756893e2b..fa58e43f6bb 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -336,7 +336,8 @@ 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->lock_id,
+ thd->variables.lock_wait_timeout)];
if (rc > 1) /* a timeout or a deadlock */
{
if (sql_lock->table_count)
@@ -983,7 +984,8 @@ bool lock_table_names(THD *thd, TABLE_LIST *table_list)
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;
return 0;
@@ -1055,7 +1057,8 @@ bool lock_routine_name(THD *thd, bool is_function,
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 TRUE;
DEBUG_SYNC(thd, "after_wait_locked_pname");
@@ -1258,7 +1261,8 @@ bool Global_read_lock::lock_global_read_lock(THD *thd)
MDL_SHARED));
mdl_request.init(MDL_key::GLOBAL, "", "", MDL_SHARED);
- if (thd->mdl_context.acquire_lock(&mdl_request))
+ if (thd->mdl_context.acquire_lock(&mdl_request,
+ thd->variables.lock_wait_timeout))
{
/* Our thread was killed -- return back to initial state. */
mysql_mutex_lock(&LOCK_global_read_lock);
diff --git a/sql/mdl.cc b/sql/mdl.cc
index e48ae8a3f59..245d6d8a018 100644
--- a/sql/mdl.cc
+++ b/sql/mdl.cc
@@ -772,45 +772,25 @@ static inline void mdl_exit_cond(THD *thd,
}
-MDL_context::mdl_signal_type MDL_context::wait()
+MDL_context::mdl_signal_type MDL_context::timed_wait(struct timespec
+ *abs_timeout)
{
const char *old_msg;
- st_my_thread_var *mysys_var= my_thread_var;
- mdl_signal_type result;
-
- mysql_mutex_lock(&m_signal_lock);
-
- old_msg= MDL_ENTER_COND(m_thd, mysys_var, &m_signal_cond, &m_signal_lock);
-
- while (! m_signal && !mysys_var->abort)
- mysql_cond_wait(&m_signal_cond, &m_signal_lock);
-
- result= m_signal;
-
- MDL_EXIT_COND(m_thd, mysys_var, &m_signal_lock, old_msg);
-
- return result;
-}
-
-
-MDL_context::mdl_signal_type MDL_context::timed_wait(ulong timeout)
-{
- struct timespec abstime;
- const char *old_msg;
mdl_signal_type result;
st_my_thread_var *mysys_var= my_thread_var;
+ int wait_result= 0;
mysql_mutex_lock(&m_signal_lock);
old_msg= MDL_ENTER_COND(m_thd, mysys_var, &m_signal_cond, &m_signal_lock);
- if (! m_signal)
- {
- set_timespec(abstime, timeout);
- mysql_cond_timedwait(&m_signal_cond, &m_signal_lock, &abstime);
- }
+ while (!m_signal && !mysys_var->abort &&
+ wait_result != ETIMEDOUT && wait_result != ETIME)
+ wait_result= mysql_cond_timedwait(&m_signal_cond, &m_signal_lock,
+ abs_timeout);
- result= (m_signal != NO_WAKE_UP) ? m_signal : TIMEOUT_WAKE_UP;
+ result= (m_signal != NO_WAKE_UP || mysys_var->abort) ?
+ m_signal : TIMEOUT_WAKE_UP;
MDL_EXIT_COND(m_thd, mysys_var, &m_signal_lock, old_msg);
@@ -1197,15 +1177,17 @@ MDL_context::find_ticket(MDL_request *mdl_request,
@param mdl_request [in/out] Lock request object for lock to be acquired
+ @param lock_wait_timeout [in] Seconds to wait before timeout.
+
@retval FALSE Success. MDL_request::ticket points to the ticket
for the lock.
@retval TRUE Failure (Out of resources or waiting is aborted),
*/
bool
-MDL_context::acquire_lock(MDL_request *mdl_request)
+MDL_context::acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout)
{
- return acquire_lock_impl(mdl_request);
+ return acquire_lock_impl(mdl_request, lock_wait_timeout);
}
@@ -1397,6 +1379,8 @@ void notify_shared_lock(THD *thd, MDL_ticket *conflicting_ticket)
@param mdl_request Request for the lock to be acqured.
+ @param lock_wait_timeout Seconds to wait before timeout.
+
@note Should not be used outside of MDL subsystem. Instead one
should call acquire_lock() or acquire_locks()
methods which ensure that conditions for deadlock-free
@@ -1406,13 +1390,17 @@ void notify_shared_lock(THD *thd, MDL_ticket *conflicting_ticket)
@retval TRUE Failure
*/
-bool MDL_context::acquire_lock_impl(MDL_request *mdl_request)
+bool MDL_context::acquire_lock_impl(MDL_request *mdl_request,
+ ulong lock_wait_timeout)
{
MDL_lock *lock;
MDL_ticket *ticket;
bool not_used;
st_my_thread_var *mysys_var= my_thread_var;
MDL_key *key= &mdl_request->key;
+ struct timespec abs_timeout;
+ struct timespec abs_shortwait;
+ set_timespec(abs_timeout, lock_wait_timeout);
mysql_mutex_assert_not_owner(&LOCK_open);
@@ -1464,16 +1452,31 @@ bool MDL_context::acquire_lock_impl(MDL_request *mdl_request)
/* There is a shared or exclusive lock on the object. */
DEBUG_SYNC(m_thd, "mdl_acquire_lock_wait");
- bool is_deadlock= (find_deadlock() || timed_wait(1) == VICTIM_WAKE_UP);
+ bool is_deadlock= find_deadlock();
+ bool is_timeout= FALSE;
+ if (!is_deadlock)
+ {
+ set_timespec(abs_shortwait, 1);
+ bool timeout_is_near= cmp_timespec(abs_shortwait, abs_timeout) > 0;
+ mdl_signal_type wait_result=
+ timed_wait(timeout_is_near ? &abs_timeout : &abs_shortwait);
+
+ if (timeout_is_near && wait_result == TIMEOUT_WAKE_UP)
+ is_timeout= TRUE;
+ else if (wait_result == VICTIM_WAKE_UP)
+ is_deadlock= TRUE;
+ }
stop_waiting();
- if (is_deadlock || mysys_var->abort)
+ if (mysys_var->abort || is_deadlock || is_timeout)
{
lock->remove_ticket(&MDL_lock::m_waiting, ticket);
MDL_ticket::destroy(ticket);
if (is_deadlock)
my_error(ER_LOCK_DEADLOCK, MYF(0));
+ else if (is_timeout)
+ my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
return TRUE;
}
rw_wrlock(&lock->m_rwlock);
@@ -1513,6 +1516,8 @@ extern "C" int mdl_request_ptr_cmp(const void* ptr1, const void* ptr2)
@param mdl_requests List of requests for locks to be acquired.
+ @param lock_wait_timeout Seconds to wait before timeout.
+
@note The list of requests should not contain non-exclusive lock requests.
There should not be any acquired locks in the context.
@@ -1522,7 +1527,8 @@ extern "C" int mdl_request_ptr_cmp(const void* ptr1, const void* ptr2)
@retval TRUE Failure
*/
-bool MDL_context::acquire_locks(MDL_request_list *mdl_requests)
+bool MDL_context::acquire_locks(MDL_request_list *mdl_requests,
+ ulong lock_wait_timeout)
{
MDL_request_list::Iterator it(*mdl_requests);
MDL_request **sort_buf, **p_req;
@@ -1552,7 +1558,7 @@ bool MDL_context::acquire_locks(MDL_request_list *mdl_requests)
for (p_req= sort_buf; p_req < sort_buf + req_count; p_req++)
{
- if (acquire_lock_impl(*p_req))
+ if (acquire_lock_impl(*p_req, lock_wait_timeout))
goto err;
}
my_free(sort_buf, MYF(0));
@@ -1578,6 +1584,8 @@ err:
Used in ALTER TABLE, when a copy of the table with the
new definition has been constructed.
+ @param lock_wait_timeout Seconds to wait before timeout.
+
@note In case of failure to upgrade lock (e.g. because upgrader
was killed) leaves lock in its original state (locked in
shared mode).
@@ -1592,7 +1600,8 @@ err:
*/
bool
-MDL_context::upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket)
+MDL_context::upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket,
+ ulong lock_wait_timeout)
{
MDL_request mdl_xlock_request;
MDL_ticket *mdl_svp= mdl_savepoint();
@@ -1614,7 +1623,7 @@ MDL_context::upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket)
mdl_xlock_request.init(&mdl_ticket->m_lock->key, MDL_EXCLUSIVE);
- if (acquire_lock_impl(&mdl_xlock_request))
+ if (acquire_lock_impl(&mdl_xlock_request, lock_wait_timeout))
DBUG_RETURN(TRUE);
is_new_ticket= ! has_lock(mdl_svp, mdl_xlock_request.ticket);
@@ -1803,21 +1812,25 @@ bool MDL_context::find_deadlock()
Does not acquire the locks!
+ @param lock_wait_timeout Seconds to wait before timeout.
+
@retval FALSE Success. One can try to obtain metadata locks.
@retval TRUE Failure (thread was killed or deadlock is possible).
*/
bool
-MDL_context::wait_for_lock(MDL_request *mdl_request)
+MDL_context::wait_for_lock(MDL_request *mdl_request, ulong lock_wait_timeout)
{
MDL_lock *lock;
st_my_thread_var *mysys_var= my_thread_var;
+ struct timespec abs_timeout;
+ set_timespec(abs_timeout, lock_wait_timeout);
mysql_mutex_assert_not_owner(&LOCK_open);
DBUG_ASSERT(mdl_request->ticket == NULL);
- while (!mysys_var->abort)
+ while (TRUE)
{
/*
We have to check if there are some HANDLERs open by this thread
@@ -1860,19 +1873,32 @@ MDL_context::wait_for_lock(MDL_request *mdl_request)
set_deadlock_weight(MDL_DEADLOCK_WEIGHT_DML);
will_wait_for(pending_ticket);
- bool is_deadlock= (find_deadlock() || wait() == VICTIM_WAKE_UP);
+ bool is_deadlock= find_deadlock();
+ bool is_timeout= FALSE;
+ if (!is_deadlock)
+ {
+ mdl_signal_type wait_result= timed_wait(&abs_timeout);
+ if (wait_result == TIMEOUT_WAKE_UP)
+ is_timeout= TRUE;
+ else if (wait_result == VICTIM_WAKE_UP)
+ is_deadlock= TRUE;
+ }
stop_waiting();
lock->remove_ticket(&MDL_lock::m_waiting, pending_ticket);
MDL_ticket::destroy(pending_ticket);
- if (is_deadlock)
+
+ if (mysys_var->abort || is_deadlock || is_timeout)
{
- my_error(ER_LOCK_DEADLOCK, MYF(0));
+ if (is_deadlock)
+ my_error(ER_LOCK_DEADLOCK, MYF(0));
+ else if (is_timeout)
+ my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0));
return TRUE;
}
}
- return mysys_var->abort;
+ return TRUE;
}
diff --git a/sql/mdl.h b/sql/mdl.h
index 05a0b44dc9b..d43548fb65f 100644
--- a/sql/mdl.h
+++ b/sql/mdl.h
@@ -466,13 +466,14 @@ public:
void destroy();
bool try_acquire_lock(MDL_request *mdl_request);
- bool acquire_lock(MDL_request *mdl_request);
- bool acquire_locks(MDL_request_list *requests);
- bool upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket);
+ bool acquire_lock(MDL_request *mdl_request, ulong lock_wait_timeout);
+ bool acquire_locks(MDL_request_list *requests, ulong lock_wait_timeout);
+ bool upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket,
+ ulong lock_wait_timeout);
bool clone_ticket(MDL_request *mdl_request);
- bool wait_for_lock(MDL_request *mdl_request);
+ bool wait_for_lock(MDL_request *mdl_request, ulong lock_wait_timeout);
void release_all_locks_for_name(MDL_ticket *ticket);
void release_lock(MDL_ticket *ticket);
@@ -644,7 +645,7 @@ private:
MDL_ticket *find_ticket(MDL_request *mdl_req,
bool *is_transactional);
void release_locks_stored_before(MDL_ticket *sentinel);
- bool acquire_lock_impl(MDL_request *mdl_request);
+ bool acquire_lock_impl(MDL_request *mdl_request, ulong lock_wait_timeout);
bool find_deadlock();
@@ -680,8 +681,7 @@ private:
mysql_mutex_unlock(&m_signal_lock);
}
- mdl_signal_type wait();
- mdl_signal_type timed_wait(ulong timeout);
+ mdl_signal_type timed_wait(struct timespec *abs_timeout);
mdl_signal_type peek_signal()
{
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;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 9e33bea25c0..7c935d376f9 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -342,6 +342,7 @@ typedef struct system_variables
ulong auto_increment_increment, auto_increment_offset;
ulong bulk_insert_buff_size;
ulong join_buff_size;
+ ulong lock_wait_timeout;
ulong max_allowed_packet;
ulong max_error_count;
ulong max_length_for_sort_data;
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 0f5d51f924d..ea466da8ea1 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -1210,7 +1210,8 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
mdl_requests.push_front(&mdl_request);
mdl_requests.push_front(&mdl_global_request);
- if (thd->mdl_context.acquire_locks(&mdl_requests))
+ if (thd->mdl_context.acquire_locks(&mdl_requests,
+ thd->variables.lock_wait_timeout))
DBUG_RETURN(TRUE);
has_mdl_lock= TRUE;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 7587a447445..45c9c0363dd 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1823,6 +1823,12 @@ public:
*/
thd.lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_DELAYED);
thd.set_current_stmt_binlog_format_row_if_mixed();
+ /*
+ Prevent changes to global.lock_wait_timeout from affecting
+ delayed insert threads as any timeouts in delayed inserts
+ are not communicated to the client.
+ */
+ thd.variables.lock_wait_timeout= LONG_TIMEOUT;
bzero((char*) &thd.net, sizeof(thd.net)); // Safety
bzero((char*) &table_list, sizeof(table_list)); // Safety
@@ -2708,7 +2714,8 @@ bool Delayed_insert::handle_inserts(void)
table->use_all_columns();
thd_proc_info(&thd, "upgrading lock");
- if (thr_upgrade_write_delay_lock(*thd.lock->locks, delayed_lock))
+ if (thr_upgrade_write_delay_lock(*thd.lock->locks, delayed_lock,
+ thd.variables.lock_wait_timeout))
{
/*
This can happen if thread is killed either by a shutdown
@@ -2893,7 +2900,8 @@ bool Delayed_insert::handle_inserts(void)
goto err;
}
query_cache_invalidate3(&thd, table, 1);
- if (thr_reschedule_write_lock(*thd.lock->locks))
+ if (thr_reschedule_write_lock(*thd.lock->locks,
+ thd.variables.lock_wait_timeout))
{
/* This is not known to happen. */
my_error(ER_DELAYED_CANT_CHANGE_LOCK,MYF(ME_FATALERROR),
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 2a05cbc561d..2e1827f9a35 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -3103,7 +3103,9 @@ try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table,
thd->mdl_context.try_acquire_lock(&table->mdl_request)) &&
!table->mdl_request.ticket && !can_deadlock)
{
- if ((error= thd->mdl_context.wait_for_lock(&table->mdl_request)))
+ if ((error=
+ thd->mdl_context.wait_for_lock(&table->mdl_request,
+ thd->variables.lock_wait_timeout)))
break;
}
return error;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 30725d2035c..d6c656080b4 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4403,7 +4403,8 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
mdl_requests.push_front(&table_list->mdl_request);
mdl_requests.push_front(&mdl_global_request);
- if (thd->mdl_context.acquire_locks(&mdl_requests))
+ if (thd->mdl_context.acquire_locks(&mdl_requests,
+ thd->variables.lock_wait_timeout))
DBUG_RETURN(0);
has_mdl_lock= TRUE;
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 73d01f5341d..085e8b8ee1e 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -853,6 +853,12 @@ static Sys_var_mybool Sys_local_infile(
"local_infile", "Enable LOAD DATA LOCAL INFILE",
GLOBAL_VAR(opt_local_infile), CMD_LINE(OPT_ARG), DEFAULT(TRUE));
+static Sys_var_ulong Sys_lock_wait_timeout(
+ "lock_wait_timeout",
+ "Timeout in seconds to wait for a lock before returning an error.",
+ SESSION_VAR(lock_wait_timeout), CMD_LINE(REQUIRED_ARG),
+ VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(LONG_TIMEOUT), BLOCK_SIZE(1));
+
#ifdef HAVE_MLOCKALL
static Sys_var_mybool Sys_locked_in_memory(
"locked_in_memory",