summaryrefslogtreecommitdiff
path: root/storage/myisammrg/ha_myisammrg.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/myisammrg/ha_myisammrg.cc')
-rw-r--r--storage/myisammrg/ha_myisammrg.cc27
1 files changed, 25 insertions, 2 deletions
diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc
index 466c66ec769..26e54d61101 100644
--- a/storage/myisammrg/ha_myisammrg.cc
+++ b/storage/myisammrg/ha_myisammrg.cc
@@ -478,8 +478,31 @@ int ha_myisammrg::add_children_list(void)
/* Set the expected table version, to not cause spurious re-prepare. */
child_l->set_table_ref_id(mrg_child_def->get_child_table_ref_type(),
mrg_child_def->get_child_def_version());
- /* Use the same metadata lock type for children. */
- child_l->mdl_request.set_type(parent_l->mdl_request.type);
+ /*
+ For statements which acquire a SNW metadata lock on a parent table and
+ then later try to upgrade it to an X lock (e.g. ALTER TABLE), SNW
+ locks should be also taken on the children tables.
+
+ Otherwise we end up in a situation where the thread trying to upgrade SNW
+ to X lock on the parent also holds a SR metadata lock and a read
+ thr_lock.c lock on the child. As a result, another thread might be
+ blocked on the thr_lock.c lock for the child after successfully acquiring
+ a SR or SW metadata lock on it. If at the same time this second thread
+ has a shared metadata lock on the parent table or there is some other
+ thread which has a shared metadata lock on the parent and is waiting for
+ this second thread, we get a deadlock. This deadlock cannot be properly
+ detected by the MDL subsystem as part of the waiting happens within
+ thr_lock.c. By taking SNW locks on the child tables we ensure that any
+ thread which waits for a thread doing SNW -> X upgrade, does this within
+ the MDL subsystem and thus potential deadlocks are exposed to the deadlock
+ detector.
+
+ We don't do the same thing for SNRW locks as this would allow
+ DDL on implicitly locked underlying tables of a MERGE table.
+ */
+ if (! thd->locked_tables_mode &&
+ parent_l->mdl_request.type == MDL_SHARED_NO_WRITE)
+ child_l->mdl_request.set_type(MDL_SHARED_NO_WRITE);
/* Link TABLE_LIST object into the children list. */
if (this->children_last_l)
child_l->prev_global= this->children_last_l;