1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-27 13:04:36 +03:00
Files
mariadb/mysql-test/r/mdl_sync.result
Dmitry Lenev a63f8480db Patch that changes metadata locking subsystem to use mutex per lock and
condition variable per context instead of one mutex and one conditional
variable for the whole subsystem.

This should increase concurrency in this subsystem.

It also opens the way for further changes which are necessary to solve
such bugs as bug #46272 "MySQL 5.4.4, new MDL: unnecessary deadlock"
and bug #37346 "innodb does not detect deadlock between update and alter
table".

Two other notable changes done by this patch:

- MDL subsystem no longer implicitly acquires global intention exclusive
  metadata lock when per-object metadata lock is acquired. Now this has
  to be done by explicit calls outside of MDL subsystem.
- Instead of using separate MDL_context for opening system tables/tables
  for purposes of I_S we now create MDL savepoint in the main context
  before opening tables and rollback to this savepoint after closing
  them. This means that it is now possible to get ER_LOCK_DEADLOCK error
  even not inside a transaction. This might happen in unlikely case when
  one runs DDL on one of system tables while also running DDL on some
  other tables. Cases when this ER_LOCK_DEADLOCK error is not justified
  will be addressed by advanced deadlock detector for MDL subsystem which
  we plan to implement.
2010-01-21 23:43:03 +03:00

545 lines
17 KiB
Plaintext

SET DEBUG_SYNC= 'RESET';
drop table if exists t1,t2,t3;
create table t1 (i int);
create table t2 (i int);
connection: default
lock tables t2 read;
connection: con1
set debug_sync='mdl_upgrade_shared_lock_to_exclusive SIGNAL parked WAIT_FOR go';
alter table t1 rename t3;
connection: default
set debug_sync= 'now WAIT_FOR parked';
connection: con2
set debug_sync='mdl_acquire_exclusive_locks_wait SIGNAL go';
drop table t1,t2;
connection: con1
connection: default
unlock tables;
connection: con2
ERROR 42S02: Unknown table 't1'
drop table t3;
SET DEBUG_SYNC= 'RESET';
#
# Test coverage for basic deadlock detection in metadata
# locking subsystem.
#
drop tables if exists t0, t1, t2, t3, t4, t5;
create table t1 (i int);
create table t2 (j int);
create table t3 (k int);
create table t4 (k int);
#
# Test for the case in which no deadlock occurs.
#
#
# Switching to connection 'deadlock_con1'.
begin;
insert into t1 values (1);
#
# Switching to connection 'deadlock_con2'.
begin;
insert into t2 values (1);
#
# Switching to connection 'default'.
# Send:
rename table t2 to t0, t3 to t2, t0 to t3;;
#
# Switching to connection 'deadlock_con1'.
# Wait until the above RENAME TABLE is blocked because it has to wait
# for 'deadlock_con2' which holds shared metadata lock on 't2'.
# The below statement should wait for exclusive metadata lock
# on 't2' to go away and should not produce ER_LOCK_DEADLOCK
# as no deadlock is possible in this situation.
# Send:
select * from t2;;
#
# Switching to connection 'deadlock_con2'.
# Wait until the above SELECT * FROM t2 is starts waiting
# for an exclusive metadata lock to go away.
#
# Unblock RENAME TABLE by releasing shared metadata lock on t2.
commit;
#
# Switching to connection 'default'.
# Reap RENAME TABLE.
#
# Switching to connection 'deadlock_con1'.
# Reap SELECT.
k
#
# Switching to connection 'default'.
#
# Let us check that in the process of waiting for conflicting lock
# on table 't2' to go away transaction in connection 'deadlock_con1'
# has not released metadata lock on table 't1'.
# Send:
rename table t1 to t0, t3 to t1, t0 to t3;;
#
# Switching to connection 'deadlock_con1'.
# Wait until the above RENAME TABLE is blocked because it has to wait
# for 'deadlock_con1' which should still hold shared metadata lock on
# table 't1'.
# Commit transaction to unblock RENAME TABLE.
commit;
#
# Switching to connection 'default'.
# Reap RENAME TABLE.
#
# Test for case when deadlock occurs and should be detected immediately.
#
#
# Switching to connection 'deadlock_con1'.
begin;
insert into t2 values (2);
#
# Switching to connection 'default'.
# Send:
rename table t2 to t0, t1 to t2, t0 to t1;;
#
# Switching to connection 'deadlock_con1'.
# Wait until the above RENAME TABLE is blocked because it has to wait
# for 'deadlock_con1' which holds shared metadata lock on 't2'.
#
# The below statement should not wait as doing so will cause deadlock.
# Instead it should fail and emit ER_LOCK_DEADLOCK statement.
select * from t1;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
#
# Let us check that failure of the above statement has not released
# metadata lock on table 't1', i.e. that RENAME TABLE is still blocked.
# Commit transaction to unblock RENAME TABLE.
commit;
#
# Switching to connection 'default'.
# Reap RENAME TABLE.
#
# Test for the case in which deadlock also occurs but not immediately.
#
#
# Switching to connection 'deadlock_con1'.
begin;
insert into t1 values (1);
#
# Switching to connection 'deadlock_con2'.
begin;
insert into t3 values (1);
#
# Switching to connection 'default'.
# Send:
rename table t2 to t0, t3 to t2, t0 to t3;;
#
# Switching to connection 'deadlock_con1'.
# Wait until the above RENAME TABLE is blocked because it has to wait
# for 'deadlock_con2' which holds shared metadata lock on 't3'.
# The below SELECT statement should wait for metadata lock
# on table 't2' and should not produce ER_LOCK_DEADLOCK
# immediately as no deadlock is possible at the moment.
select * from t2;;
#
# Switching to connection 'deadlock_con3'.
# Wait until the above SELECT * FROM t2 is starts waiting
# for an exclusive metadata lock to go away.
# Send RENAME TABLE statement that will deadlock with the
# SELECT statement and thus should abort the latter.
rename table t1 to t5, t2 to t1, t5 to t2;;
#
# Switching to connection 'deadlock_con1'.
# Since the latest RENAME TABLE entered in deadlock with SELECT
# statement the latter should be aborted and emit ER_LOCK_DEADLOCK
# error.
# Reap SELECT * FROM t2.
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
#
# Again let us check that failure of the SELECT statement has not
# released metadata lock on table 't1', i.e. that the latest RENAME
# is blocked.
# Commit transaction to unblock this RENAME TABLE.
commit;
#
# Switching to connection 'deadlock_con2'.
# Commit transaction to unblock the first RENAME TABLE.
commit;
#
# Switching to connection 'default'.
# Reap RENAME TABLE t2 TO t0 ... .
#
# Switching to connection 'deadlock_con3'.
# Reap RENAME TABLE t1 TO t5 ... .
#
# Switching to connection 'default'.
drop tables t1, t2, t3, t4;
#
# Now, test case which shows that deadlock detection empiric
# also takes into account requests for metadata lock upgrade.
#
create table t1 (i int);
#
# Switching to connection 'deadlock_con1'.
begin;
insert into t1 values (1);
#
# Switching to connection 'default'.
# Send:
alter table t1 add column j int, rename to t2;;
#
# Switching to connection 'deadlock_con1'.
# Wait until the above ALTER TABLE ... RENAME acquires exclusive
# metadata lock on 't2' and starts waiting for connection
# 'deadlock_con1' which holds shared lock on 't1'.
# The below statement should not wait as it will cause deadlock.
# An appropriate error should be reported instead.
select * from t2;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
# Again let us check that failure of the above statement has not
# released all metadata locks in connection 'deadlock_con1' and
# so ALTER TABLE ... RENAME is still blocked.
# Commit transaction to unblock ALTER TABLE ... RENAME.
commit;
#
# Switching to connection 'default'.
# Reap ALTER TABLE ... RENAME.
drop table t2;
#
# Finally, test case in which deadlock (or potentially livelock) occurs
# between metadata locking subsystem and table definition cache/table
# locks, but which should still be detected by our empiric.
#
create table t1 (i int);
#
# Switching to connection 'deadlock_con1'.
begin;
insert into t1 values (1);
#
# Switching to connection 'default'.
lock tables t1 write;
#
# Switching to connection 'deadlock_con1'.
# Send:
insert into t1 values (2);;
#
# Switching to connection 'default'.
# Wait until INSERT in connection 'deadlock_con1' is blocked on
# table-level lock.
# Send:
alter table t1 add column j int;;
#
# Switching to connection 'deadlock_con1'.
# The above ALTER TABLE statement should cause INSERT statement in
# this connection to be aborted and emit ER_LOCK_DEADLOCK error.
# Reap INSERT
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
# Commit transaction to unblock ALTER TABLE.
commit;
#
# Switching to connection 'default'.
# Reap ALTER TABLE.
unlock tables;
drop table t1;
#
# Test for bug #46748 "Assertion in MDL_context::wait_for_locks()
# on INSERT + CREATE TRIGGER".
#
drop tables if exists t1, t2, t3, t4, t5;
# Let us simulate scenario in which we open some tables from extended
# part of prelocking set but then encounter conflicting metadata lock,
# so have to back-off and wait for it to go away.
create table t1 (i int);
create table t2 (j int);
create table t3 (k int);
create table t4 (l int);
create trigger t1_bi before insert on t1 for each row
insert into t2 values (new.i);
create trigger t2_bi before insert on t2 for each row
insert into t3 values (new.j);
#
# Switching to connection 'con1root'.
lock tables t4 read;
#
# Switching to connection 'con2root'.
# Send :
rename table t3 to t5, t4 to t3;;
#
# Switching to connection 'default'.
# Wait until the above RENAME TABLE adds pending requests for exclusive
# metadata lock on its tables and blocks due to 't4' being used by LOCK
# TABLES.
# Send :
insert into t1 values (1);;
#
# Switching to connection 'con1root'.
# Wait until INSERT statement waits due to encountering pending
# exclusive metadata lock on 't3'.
unlock tables;
#
# Switching to connection 'con2root'.
# Reap RENAME TABLE.
#
# Switching to connection 'default'.
# Reap INSERT.
# Clean-up.
drop tables t1, t2, t3, t5;
#
# Bug#42546 - Backup: RESTORE fails, thinking it finds an existing table
#
DROP TABLE IF EXISTS t1;
set @save_log_output=@@global.log_output;
set global log_output=file;
#
# Test 1: CREATE TABLE
#
# Connection 2
# Start insert on the not-yet existing table
# Wait after taking the MDL lock
SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL locked WAIT_FOR finish';
INSERT INTO t1 VALUES(1,"def");
# Connection 1
SET DEBUG_SYNC= 'now WAIT_FOR locked';
# Now INSERT has a MDL on the non-existent table t1.
#
# Continue the INSERT once CREATE waits for exclusive lock
SET DEBUG_SYNC= 'mdl_acquire_exclusive_locks_wait SIGNAL finish';
# Try to create that table.
CREATE TABLE t1 (c1 INT, c2 VARCHAR(100), KEY(c1));
# Connection 2
# Insert fails
ERROR 42S02: Table 'test.t1' doesn't exist
# Connection 1
SET DEBUG_SYNC= 'RESET';
SHOW TABLES;
Tables_in_test
t1
DROP TABLE IF EXISTS t1;
#
# Test 2: CREATE TABLE LIKE
#
CREATE TABLE t2 (c1 INT, c2 VARCHAR(100), KEY(c1));
# Connection 2
# Start insert on the not-yet existing table
# Wait after taking the MDL
SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL locked WAIT_FOR finish';
INSERT INTO t1 VALUES(1,"def");
# Connection 1
SET DEBUG_SYNC= 'now WAIT_FOR locked';
# Now INSERT has a MDL on the non-existent table t1.
#
# Continue the INSERT once CREATE waits for exclusive lock
SET DEBUG_SYNC= 'mdl_acquire_exclusive_locks_wait SIGNAL finish';
# Try to create that table.
CREATE TABLE t1 LIKE t2;
# Connection 2
# Insert fails
ERROR 42S02: Table 'test.t1' doesn't exist
# Connection 1
SET DEBUG_SYNC= 'RESET';
SHOW TABLES;
Tables_in_test
t1
t2
DROP TABLE t2;
DROP TABLE IF EXISTS t1;
set global log_output=@save_log_output;
#
# Bug #46044 "MDL deadlock on LOCK TABLE + CREATE TABLE HIGH_PRIORITY
# FOR UPDATE"
#
drop tables if exists t1, t2;
create table t1 (i int);
# Let us check that we won't deadlock if during filling
# of I_S table we encounter conflicting metadata lock
# which owner is in its turn waiting for our connection.
lock tables t1 write;
# Switching to connection 'con46044'.
# Sending:
create table t2 select * from t1;;
# Switching to connection 'default'.
# Waiting until CREATE TABLE ... SELECT ... is blocked.
# First let us check that SHOW FIELDS/DESCRIBE doesn't
# gets blocked and emits and error.
show fields from t2;
ERROR HY000: Table 'test'.'t2' was skipped since its definition is being modified by concurrent DDL statement
# Now test for I_S query which reads only .FRMs.
#
# Query below should only emit a warning.
select column_name from information_schema.columns
where table_schema='test' and table_name='t2';
column_name
Warnings:
Warning 1652 Table 'test'.'t2' was skipped since its definition is being modified by concurrent DDL statement
# Finally, test for I_S query which does full-blown table open.
#
# Query below should not be blocked. Warning message should be
# stored in the 'table_comment' column.
select table_name, table_type, auto_increment, table_comment
from information_schema.tables where table_schema='test' and table_name='t2';
table_name table_type auto_increment table_comment
t2 BASE TABLE NULL Table 'test'.'t2' was skipped since its definition is being modified by concurre
# Switching to connection 'default'.
unlock tables;
# Switching to connection 'con46044'.
# Reaping CREATE TABLE ... SELECT ... .
drop table t2;
#
# Let us also check that queries to I_S wait for conflicting metadata
# locks to go away instead of skipping table with a warning in cases
# when deadlock is not possible. This is a nice thing from compatibility
# and ease of use points of view.
#
# We check same three queries to I_S in this new situation.
# Switching to connection 'con46044_2'.
lock tables t1 write;
# Switching to connection 'con46044'.
# Sending:
create table t2 select * from t1;;
# Switching to connection 'default'.
# Waiting until CREATE TABLE ... SELECT ... is blocked.
# Let us check that SHOW FIELDS/DESCRIBE gets blocked.
# Sending:
show fields from t2;;
# Switching to connection 'con46044_2'.
# Wait until SHOW FIELDS gets blocked.
unlock tables;
# Switching to connection 'con46044'.
# Reaping CREATE TABLE ... SELECT ... .
# Switching to connection 'default'.
# Reaping SHOW FIELDS ...
Field Type Null Key Default Extra
i int(11) YES NULL
drop table t2;
# Switching to connection 'con46044_2'.
lock tables t1 write;
# Switching to connection 'con46044'.
# Sending:
create table t2 select * from t1;;
# Switching to connection 'default'.
# Waiting until CREATE TABLE ... SELECT ... is blocked.
# Check that I_S query which reads only .FRMs gets blocked.
# Sending:
select column_name from information_schema.columns where table_schema='test' and table_name='t2';;
# Switching to connection 'con46044_2'.
# Wait until SELECT COLUMN_NAME FROM I_S.COLUMNS gets blocked.
unlock tables;
# Switching to connection 'con46044'.
# Reaping CREATE TABLE ... SELECT ... .
# Switching to connection 'default'.
# Reaping SELECT COLUMN_NAME FROM I_S.COLUMNS
column_name
i
drop table t2;
# Switching to connection 'con46044_2'.
lock tables t1 write;
# Switching to connection 'con46044'.
# Sending:
create table t2 select * from t1;;
# Switching to connection 'default'.
# Waiting until CREATE TABLE ... SELECT ... is blocked.
# Finally, check that I_S query which does full-blown table open
# also gets blocked.
# Sending:
select table_name, table_type, auto_increment, table_comment from information_schema.tables where table_schema='test' and table_name='t2';;
# Switching to connection 'con46044_2'.
# Wait until SELECT ... FROM I_S.TABLES gets blocked.
unlock tables;
# Switching to connection 'con46044'.
# Reaping CREATE TABLE ... SELECT ... .
# Switching to connection 'default'.
# Reaping SELECT ... FROM I_S.TABLES
table_name table_type auto_increment table_comment
t2 BASE TABLE NULL
drop table t2;
# Switching to connection 'default'.
# Clean-up.
drop table t1;
#
# Test for bug #46273 "MySQL 5.4.4 new MDL: Bug#989 is not fully fixed
# in case of ALTER".
#
drop table if exists t1;
set debug_sync= 'RESET';
create table t1 (c1 int primary key, c2 int, c3 int);
insert into t1 values (1,1,0),(2,2,0),(3,3,0),(4,4,0),(5,5,0);
begin;
update t1 set c3=c3+1 where c2=3;
#
# Switching to connection 'con46273'.
set debug_sync='after_lock_tables_takes_lock SIGNAL alter_table_locked WAIT_FOR alter_go';
alter table t1 add column e int, rename to t2;;
#
# Switching to connection 'default'.
set debug_sync='now WAIT_FOR alter_table_locked';
set debug_sync='wait_for_lock SIGNAL alter_go';
# The below statement should get ER_LOCK_DEADLOCK error
# (i.e. it should not allow ALTER to proceed, and then
# fail due to 't1' changing its name to 't2').
update t1 set c3=c3+1 where c2=4;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
#
# Let us check that failure of the above statement has not released
# metadata lock on table 't1', i.e. that ALTER TABLE is still blocked.
# Unblock ALTER TABLE by commiting transaction and thus releasing
# metadata lock on 't1'.
commit;
#
# Switching to connection 'con46273'.
# Reap ALTER TABLE.
#
# Switching to connection 'default'.
# Clean-up.
set debug_sync= 'RESET';
drop table t2;
#
# Test for bug #46673 "Deadlock between FLUSH TABLES WITH READ LOCK
# and DML".
#
drop tables if exists t1;
create table t1 (i int);
# Switching to connection 'con46673'.
begin;
insert into t1 values (1);
# Switching to connection 'default'.
# Statement below should not get blocked. And if after some
# changes to code it is there should not be a deadlock between
# it and transaction from connection 'con46673'.
flush tables with read lock;
unlock tables;
# Switching to connection 'con46673'.
delete from t1 where i = 1;
commit;
# Switching to connection 'default'.
# Clean-up
drop table t1;
#
# Bug#48210 FLUSH TABLES WITH READ LOCK deadlocks
# against concurrent CREATE PROCEDURE
#
# Test 1: CREATE PROCEDURE
# Connection 1
# Start CREATE PROCEDURE and open mysql.proc
SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL table_opened WAIT_FOR grlwait';
CREATE PROCEDURE p1() SELECT 1;
# Connection 2
SET DEBUG_SYNC= 'now WAIT_FOR table_opened';
# Check that FLUSH must wait to get the GRL
# and let CREATE PROCEDURE continue
SET DEBUG_SYNC= 'wait_lock_global_read_lock SIGNAL grlwait';
FLUSH TABLES WITH READ LOCK;
# Connection 1
# Connection 2
UNLOCK TABLES;
# Connection 1
SET DEBUG_SYNC= 'RESET';
# Test 2: DROP PROCEDURE
# Start DROP PROCEDURE and open tables
SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL table_opened WAIT_FOR grlwait';
DROP PROCEDURE p1;
# Connection 2
SET DEBUG_SYNC= 'now WAIT_FOR table_opened';
# Check that FLUSH must wait to get the GRL
# and let DROP PROCEDURE continue
SET DEBUG_SYNC= 'wait_lock_global_read_lock SIGNAL grlwait';
FLUSH TABLES WITH READ LOCK;
# Connection 1
# Connection 2
UNLOCK TABLES;
# Connection 1
SET DEBUG_SYNC= 'RESET';