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.cc47
1 files changed, 44 insertions, 3 deletions
diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc
index ef7cd5712e8..22b4794dbde 100644
--- a/storage/myisammrg/ha_myisammrg.cc
+++ b/storage/myisammrg/ha_myisammrg.cc
@@ -480,6 +480,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());
+ /*
+ 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;
@@ -657,7 +682,7 @@ CPP_UNNAMED_NS_END
@return A cloned handler instance.
*/
-handler *ha_myisammrg::clone(MEM_ROOT *mem_root)
+handler *ha_myisammrg::clone(const char *name, MEM_ROOT *mem_root)
{
MYRG_TABLE *u_table,*newu_table;
ha_myisammrg *new_handler=
@@ -678,8 +703,8 @@ handler *ha_myisammrg::clone(MEM_ROOT *mem_root)
return NULL;
}
- if (new_handler->ha_open(table, table->s->normalized_path.str, table->db_stat,
- HA_OPEN_IGNORE_IF_LOCKED))
+ if (new_handler->ha_open(table, name, table->db_stat,
+ HA_OPEN_IGNORE_IF_LOCKED))
{
delete new_handler;
return NULL;
@@ -1202,6 +1227,22 @@ ha_rows ha_myisammrg::records_in_range(uint inx, key_range *min_key,
}
+int ha_myisammrg::truncate()
+{
+ int err= 0;
+ MYRG_TABLE *table;
+ DBUG_ENTER("ha_myisammrg::truncate");
+
+ for (table= file->open_tables; table != file->end_table; table++)
+ {
+ if ((err= mi_delete_all_rows(table->table)))
+ break;
+ }
+
+ DBUG_RETURN(err);
+}
+
+
int ha_myisammrg::info(uint flag)
{
MYMERGE_INFO mrg_info;