diff options
author | Jon Olav Hauglid <jon.hauglid@sun.com> | 2009-12-16 12:32:11 +0100 |
---|---|---|
committer | Jon Olav Hauglid <jon.hauglid@sun.com> | 2009-12-16 12:32:11 +0100 |
commit | 6d4e09d68e1ea104e84e1f9bafffe43b00a7aec9 (patch) | |
tree | 99bc3c53514e9ebc3d7f1cac2b8c8bb443b1d3d7 /sql/mdl.cc | |
parent | 980e8b413e89175d8fc7f867415712589bead9ff (diff) | |
download | mariadb-git-6d4e09d68e1ea104e84e1f9bafffe43b00a7aec9.tar.gz |
Bug #48541 Deadlock between LOCK_open and LOCK_mdl
The reason for the deadlock was an improper exit from
MDL_context::wait_for_locks() which caused mysys_var->current_mutex to remain
LOCK_mdl even though LOCK_mdl was no longer held by that connection.
This could for example lead to a deadlock in the following way:
1) INSERT DELAYED tries to open a table but fails, and trying to recover it
calls wait_for_locks().
2) Due to a pending exclusive request, wait_for_locks() fails and exits without
resetting mysys_var->current_mutex for the delayed insert handler thread. So it
continues to point to LOCK_mdl.
3) The handler thread manages to open a table.
4) A different connection takes LOCK_open and tries to take LOCK_mdl.
5) FLUSH TABLES from a third connection notices that the handler thread has a
table open, and tries to kill it. This involves locking mysys_var->current_mutex
while having LOCK_open locked. Since current_mutex mistakenly points to LOCK_mdl,
we have a deadlock.
This patch makes sure MDL_EXIT_COND() is called before exiting wait_for_locks().
This clears mysys->current_mutex which resolves the issue.
An assert is added to recover_from_failed_open_table_attempt() after
wait_for_locks() is called, to check that current_mutex is indeed reset.
With this assert in place, existing tests in (e.g.) mdl_sync.test will fail
without this patch.
Diffstat (limited to 'sql/mdl.cc')
-rw-r--r-- | sql/mdl.cc | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/sql/mdl.cc b/sql/mdl.cc index a883b21423e..6187d4515a3 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -1254,7 +1254,8 @@ MDL_context::wait_for_locks(MDL_request_list *mdl_requests) } if (!mdl_request) { - pthread_mutex_unlock(&LOCK_mdl); + /* As a side-effect MDL_EXIT_COND() unlocks LOCK_mdl. */ + MDL_EXIT_COND(m_thd, mysys_var, old_msg); break; } pthread_cond_wait(&COND_mdl, &LOCK_mdl); |