Commit 744a5380 authored by Monty's avatar Monty Committed by Sergei Golubchik

Fixed hang in concurrent DROP TABLE and BACKUP LOCK BLOCK_DDL

The problem was that tdc_remove_referenced_share() did not take into
account that someone could push things into share->free_tables() even
if there is a MDL_EXCLUSIVE lock on the table.
This can happen if flush_tables() uses the table cache to flush a
a non transactional table to disk.
parent 0b59320d
create or replace table t1 (a int primary key, b int, c int, key(b),key(c)) engine=myisam;
insert into t1 (a) values(1);
set debug_sync='RESET';
connect con1, localhost, root,,;
connect con2, localhost, root,,;
connection default;
backup stage start;
backup stage flush;
select * from t1;
a b c
1 NULL NULL
set debug_sync='after_purge_tables SIGNAL parked WAIT_FOR go';
set debug_sync='before_tc_release_table SIGNAL parked2 WAIT_FOR go2';
backup stage BLOCK_DDL;
connection con1;
set debug_sync='now WAIT_FOR parked';
select * from t1;
a b c
1 NULL NULL
set debug_sync='now SIGNAL go';
set debug_sync='now WAIT_FOR parked2';
set debug_sync='before_wait_for_refs SIGNAL waiting WAIT_FOR go3';
drop table t1;;
connection con2;
set debug_sync='now WAIT_FOR waiting';
set debug_sync='now SIGNAL go2';
set debug_sync='now SIGNAL go3';
connection default;
connection con1;
connection default;
disconnect con1;
disconnect con2;
set debug_sync='RESET';
--source include/have_debug.inc
create or replace table t1 (a int primary key, b int, c int, key(b),key(c)) engine=myisam;
insert into t1 (a) values(1);
set debug_sync='RESET';
connect (con1, localhost, root,,);
connect (con2, localhost, root,,);
connection default;
backup stage start;
backup stage flush;
select * from t1;
set debug_sync='after_purge_tables SIGNAL parked WAIT_FOR go';
set debug_sync='before_tc_release_table SIGNAL parked2 WAIT_FOR go2';
--send backup stage BLOCK_DDL
--connection con1
set debug_sync='now WAIT_FOR parked';
select * from t1;
set debug_sync='now SIGNAL go';
set debug_sync='now WAIT_FOR parked2';
set debug_sync='before_wait_for_refs SIGNAL waiting WAIT_FOR go3';
--send drop table t1;
--connection con2
set debug_sync='now WAIT_FOR waiting';
set debug_sync='now SIGNAL go2';
set debug_sync='now SIGNAL go3';
--connection default
--reap
--connection con1
--reap
connection default;
disconnect con1;
disconnect con2;
set debug_sync='RESET';
......@@ -554,6 +554,7 @@ bool flush_tables(THD *thd, flush_tables_type flag)
DBUG_ENTER("flush_tables");
purge_tables(); /* Flush unused tables and shares */
DEBUG_SYNC(thd, "after_purge_tables");
/*
Loop over all shares and collect shares that have open tables
......@@ -593,6 +594,7 @@ bool flush_tables(THD *thd, flush_tables_type flag)
if (table)
{
(void) table->file->extra(HA_EXTRA_FLUSH);
DEBUG_SYNC(table->in_use, "before_tc_release_table");
tc_release_table(table);
}
else
......
......@@ -1001,8 +1001,9 @@ void tdc_remove_referenced_share(THD *thd, TABLE_SHARE *share)
DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, share->db.str,
share->table_name.str,
MDL_EXCLUSIVE));
share->tdc->flush_unused(false);
share->tdc->flush_unused(true);
mysql_mutex_lock(&share->tdc->LOCK_table_share);
DEBUG_SYNC(thd, "before_wait_for_refs");
share->tdc->wait_for_refs(1);
DBUG_ASSERT(share->tdc->all_tables.is_empty());
share->tdc->ref_count--;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment