mirror of
https://github.com/MariaDB/server.git
synced 2025-01-21 22:34:18 +01:00
b6f0c3a157
This was a deadlock between CREATE/ALTER/DROP EVENT and a query accessing both the mysql.event table and I_S.GLOBAL_VARIABLES. The root of the problem was that the LOCK_event_metadata mutex was used to both protect the "event_scheduler" global system variable and the internal event data structures used by CREATE/ALTER/DROP EVENT. The deadlock would occur if CREATE/ALTER/DROP EVENT held LOCK_event_metadata while trying to open the mysql.event table, at the same time as the query had mysql.event open, trying to lock LOCK_event_metadata to access "event_scheduler". This bug was fixed in the scope of Bug#51160 by using only LOCK_global_system_variables to protect "event_scheduler". This makes it so that the query above won't lock LOCK_event_metadata, thereby preventing this deadlock from occuring. This patch contains no code changes. Test case added to lock_sync.test.
114 lines
4 KiB
Text
114 lines
4 KiB
Text
#
|
|
# Test for bug #45143 "All connections hang on concurrent ALTER TABLE".
|
|
#
|
|
# Concurrent execution of statements which required weak write lock
|
|
# (TL_WRITE_ALLOW_WRITE) on several instances of the same table and
|
|
# statements which tried to acquire stronger write lock (TL_WRITE,
|
|
# TL_WRITE_ALLOW_READ) on this table might have led to deadlock.
|
|
drop table if exists t1;
|
|
drop view if exists v1;
|
|
# Create auxiliary connections used through the test.
|
|
# Reset DEBUG_SYNC facility before using it.
|
|
set debug_sync= 'RESET';
|
|
# Turn off logging so calls to locking subsystem performed
|
|
# for general_log table won't interfere with our test.
|
|
set @old_general_log = @@global.general_log;
|
|
set @@global.general_log= OFF;
|
|
create table t1 (i int) engine=InnoDB;
|
|
# We have to use view in order to make LOCK TABLES avoid
|
|
# acquiring SNRW metadata lock on table.
|
|
create view v1 as select * from t1;
|
|
insert into t1 values (1);
|
|
# Prepare user lock which will be used for resuming execution of
|
|
# the first statement after it acquires TL_WRITE_ALLOW_WRITE lock.
|
|
select get_lock("lock_bug45143_wait", 0);
|
|
get_lock("lock_bug45143_wait", 0)
|
|
1
|
|
# Switch to connection 'con_bug45143_1'.
|
|
# Sending:
|
|
insert into t1 values (get_lock("lock_bug45143_wait", 100));;
|
|
# Switch to connection 'con_bug45143_2'.
|
|
# Wait until the above INSERT takes TL_WRITE_ALLOW_WRITE lock on 't1'
|
|
# and then gets blocked on user lock 'lock_bug45143_wait'.
|
|
# Ensure that upcoming SELECT waits after acquiring TL_WRITE_ALLOW_WRITE
|
|
# lock for the first instance of 't1'.
|
|
set debug_sync='thr_multi_lock_after_thr_lock SIGNAL parked WAIT_FOR go';
|
|
# Sending:
|
|
select count(*) > 0 from t1 as a, t1 as b for update;;
|
|
# Switch to connection 'con_bug45143_3'.
|
|
# Wait until the above SELECT ... FOR UPDATE is blocked after
|
|
# acquiring lock for the the first instance of 't1'.
|
|
set debug_sync= 'now WAIT_FOR parked';
|
|
# Send LOCK TABLE statement which will try to get TL_WRITE lock on 't1':
|
|
lock table v1 write;;
|
|
# Switch to connection 'default'.
|
|
# Wait until this LOCK TABLES statement starts waiting for table lock.
|
|
# Allow SELECT ... FOR UPDATE to resume.
|
|
# Since it already has TL_WRITE_ALLOW_WRITE lock on the first instance
|
|
# of 't1' it should be able to get lock on the second instance without
|
|
# waiting, even although there is another thread which has such lock
|
|
# on this table and also there is a thread waiting for a TL_WRITE on it.
|
|
set debug_sync= 'now SIGNAL go';
|
|
# Switch to connection 'con_bug45143_2'.
|
|
# Reap SELECT ... FOR UPDATE
|
|
count(*) > 0
|
|
1
|
|
# Switch to connection 'default'.
|
|
# Resume execution of the INSERT statement.
|
|
select release_lock("lock_bug45143_wait");
|
|
release_lock("lock_bug45143_wait")
|
|
1
|
|
# Switch to connection 'con_bug45143_1'.
|
|
# Reap INSERT statement.
|
|
# In Statement and Mixed replication mode we get here "Unsafe
|
|
# for binlog" warnings. In row mode there are no warnings.
|
|
# Hide the discrepancy.
|
|
# Switch to connection 'con_bug45143_3'.
|
|
# Reap LOCK TABLES statement.
|
|
unlock tables;
|
|
# Switch to connection 'default'.
|
|
# Do clean-up.
|
|
set debug_sync= 'RESET';
|
|
set @@global.general_log= @old_general_log;
|
|
drop view v1;
|
|
drop table t1;
|
|
#
|
|
# Bug#50821 Deadlock between LOCK TABLES and ALTER TABLE
|
|
#
|
|
DROP TABLE IF EXISTS t1, t2;
|
|
CREATE TABLE t1(id INT);
|
|
CREATE TABLE t2(id INT);
|
|
# Connection con2
|
|
START TRANSACTION;
|
|
SELECT * FROM t1;
|
|
id
|
|
# Connection default
|
|
# Sending:
|
|
ALTER TABLE t1 ADD COLUMN j INT;
|
|
# Connection con2
|
|
# This used to cause a deadlock.
|
|
INSERT INTO t2 SELECT * FROM t1;
|
|
COMMIT;
|
|
# Connection default
|
|
# Reaping ALTER TABLE t1 ADD COLUMN j INT
|
|
DROP TABLE t1, t2;
|
|
#
|
|
# Bug#51391 Deadlock involving events during rqg_info_schema test
|
|
#
|
|
CREATE EVENT e1 ON SCHEDULE EVERY 5 HOUR DO SELECT 1;
|
|
CREATE EVENT e2 ON SCHEDULE EVERY 5 HOUR DO SELECT 2;
|
|
# Connection con1
|
|
SET DEBUG_SYNC="before_lock_tables_takes_lock SIGNAL drop WAIT_FOR query";
|
|
# Sending:
|
|
DROP EVENT e1;;
|
|
# Connection default
|
|
SET DEBUG_SYNC="now WAIT_FOR drop";
|
|
SELECT name FROM mysql.event, INFORMATION_SCHEMA.GLOBAL_VARIABLES
|
|
WHERE definer = VARIABLE_VALUE;
|
|
name
|
|
SET DEBUG_SYNC="now SIGNAL query";
|
|
# Connection con1
|
|
# Reaping: DROP EVENT t1
|
|
# Connection default
|
|
DROP EVENT e2;
|
|
SET DEBUG_SYNC="RESET";
|