1
0
mirror of https://github.com/MariaDB/server.git synced 2025-12-24 11:21:21 +03:00

Fix for bug #56251 "Deadlock with INSERT DELAYED and MERGE

tables".

Attempting to issue an INSERT DELAYED statement for a MERGE
table might have caused a deadlock if it happened as part of
a transaction or under LOCK TABLES, and there was a concurrent
DDL or LOCK TABLES ... WRITE statement which tried to lock one
of its underlying tables.

The problem occurred when a delayed insert handler thread tried
to open a MERGE table and discovered that to do this it had also
to open all underlying tables and hence acquire metadata
locks on them. Since metadata locks on the underlying tables were
not pre-acquired by the connection thread executing INSERT DELAYED,
attempts to do so might lead to waiting. In this case the
connection thread had to wait for the delayed insert thread.
If the thread which was preventing the lock on the underlying table
from being acquired had to wait for the connection thread (due to
this or other metadata locks), a deadlock occurred. 
This deadlock was not detected by the MDL deadlock detector since 
waiting for the handler thread by the connection thread is not
represented in the wait-for graph.

This patch solves the problem by ensuring that the delayed
insert handler thread never tries to open underlying tables 
of a MERGE table. Instead open_tables() is aborted right after
the parent table is opened and a ER_DELAYED_NOT_SUPPORTED 
error is emitted (which is passed to the connection thread and
ultimately to the user).

mysql-test/r/merge.result:
  Added test for bug #56251 "Deadlock with INSERT DELAYED and
  MERGE tables".
mysql-test/t/merge.test:
  Added test for bug #56251 "Deadlock with INSERT DELAYED and
  MERGE tables".
sql/sql_base.cc:
  Changed open_n_lock_single_table() to take prelocking strategy
  as an argument instead of always using DML_prelocking_strategy.
sql/sql_base.h:
  Changed open_n_lock_single_table() to take prelocking strategy
  as an argument instead of always using DML_prelocking_strategy.
  Added a version of this function which is compatible with old
  signature.
sql/sql_insert.cc:
  When opening MERGE table in delayed insert thread stop and emit
  ER_DELAYED_NOT_SUPPORTED right after opening main table and
  before opening underlying tables. This ensures that we won't
  try to acquire metadata lock on underlying tables which might
  lead to a deadlock.
  This is achieved by using special prelocking strategy which
  abort open_tables() process as soon as we discover that we
  have opened table with engine which doesn't support delayed
  inserts.
This commit is contained in:
Dmitry Lenev
2010-09-15 18:15:31 +04:00
parent 5f352c2887
commit e86bbbda55
5 changed files with 170 additions and 12 deletions

View File

@@ -3575,4 +3575,32 @@ ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 'm1
drop view v1;
drop temporary table tmp;
drop table t1, t2, t3, m1, m2;
#
# Test for bug #56251 "Deadlock with INSERT DELAYED and MERGE tables".
#
drop table if exists t1, t2, tm;
create table t1(a int);
create table t2(a int);
create table tm(a int) engine=merge union=(t1, t2);
begin;
select * from t1;
a
# Connection 'con1'.
# Sending:
alter table t1 comment 'test';
# Connection 'default'.
# Wait until ALTER TABLE blocks and starts waiting
# for connection 'default'. It should wait with a
# pending SNW lock on 't1'.
# Attempt to perform delayed insert into 'tm' should not lead
# to a deadlock. Instead error ER_DELAYED_NOT_SUPPORTED should
# be emitted.
insert delayed into tm values (1);
ERROR HY000: DELAYED option not supported for table 'tm'
# Unblock ALTER TABLE.
commit;
# Connection 'con1'.
# Reaping ALTER TABLE:
# Connection 'default'.
drop tables tm, t1, t2;
End of 6.0 tests