mariadb/mysql-test/t/mdl_sync.test
Jon Olav Hauglid d7f9583a9b Backport of revno: 3690
Postfix for Bug#48210 FLUSH TABLES WITH READ LOCK deadlocks
                      against concurrent CREATE PROCEDURE

Rewrote the second test to use DROP PROCEDURE instead of 
CREATE USER as CREATE USER does not work with embedded server.
2009-12-10 15:09:56 +01:00

547 lines
15 KiB
Text

#
# We need the Debug Sync Facility.
#
--source include/have_debug_sync.inc
# Save the initial number of concurrent sessions.
--source include/count_sessions.inc
# Clean up resources used in this test case.
--disable_warnings
SET DEBUG_SYNC= 'RESET';
--enable_warnings
#
# Test the case of when a exclusive lock request waits for a
# shared lock being upgraded to a exclusive lock.
#
connect (con1,localhost,root,,test,,);
connect (con2,localhost,root,,test,,);
connect (con3,localhost,root,,test,,);
connection default;
--disable_warnings
drop table if exists t1,t2,t3;
--enable_warnings
create table t1 (i int);
create table t2 (i int);
--echo connection: default
lock tables t2 read;
connection con1;
--echo connection: con1
set debug_sync='mdl_upgrade_shared_lock_to_exclusive SIGNAL parked WAIT_FOR go';
--send alter table t1 rename t3
connection default;
--echo connection: default
set debug_sync= 'now WAIT_FOR parked';
connection con2;
--echo connection: con2
set debug_sync='mdl_acquire_exclusive_locks_wait SIGNAL go';
--send drop table t1,t2
connection con1;
--echo connection: con1
--reap
connection default;
--echo connection: default
unlock tables;
connection con2;
--echo connection: con2
--error ER_BAD_TABLE_ERROR
--reap
connection default;
drop table t3;
disconnect con1;
disconnect con2;
disconnect con3;
# Clean up resources used in this test case.
--disable_warnings
SET DEBUG_SYNC= 'RESET';
--enable_warnings
--echo #
--echo # Test for bug #46748 "Assertion in MDL_context::wait_for_locks()
--echo # on INSERT + CREATE TRIGGER".
--echo #
--disable_warnings
drop tables if exists t1, t2, t3, t4, t5;
--enable_warnings
--echo # Let us simulate scenario in which we open some tables from extended
--echo # part of prelocking set but then encounter conflicting metadata lock,
--echo # so have to back-off and wait for it to go away.
connect (con1root,localhost,root,,test,,);
connect (con2root,localhost,root,,test,,);
connection default;
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);
--echo #
--echo # Switching to connection 'con1root'.
connection con1root;
lock tables t4 read;
--echo #
--echo # Switching to connection 'con2root'.
connection con2root;
--echo # Send :
--send rename table t3 to t5, t4 to t3;
--echo #
--echo # Switching to connection 'default'.
connection default;
--echo # Wait until the above RENAME TABLE adds pending requests for exclusive
--echo # metadata lock on its tables and blocks due to 't4' being used by LOCK
--echo # TABLES.
let $wait_condition= select count(*)= 1 from information_schema.processlist
where state= 'Waiting for table' and
info='rename table t3 to t5, t4 to t3';
--source include/wait_condition.inc
--echo # Send :
--send insert into t1 values (1);
--echo #
--echo # Switching to connection 'con1root'.
connection con1root;
--echo # Wait until INSERT statement waits due to encountering pending
--echo # exclusive metadata lock on 't3'.
let $wait_condition= select count(*)= 1 from information_schema.processlist
where state= 'Waiting for table' and
info='insert into t1 values (1)';
--source include/wait_condition.inc
unlock tables;
--echo #
--echo # Switching to connection 'con2root'.
connection con2root;
--echo # Reap RENAME TABLE.
--reap
--echo #
--echo # Switching to connection 'default'.
connection default;
--echo # Reap INSERT.
--reap
--echo # Clean-up.
disconnect con1root;
disconnect con2root;
drop tables t1, t2, t3, t5;
--echo #
--echo # Bug#42546 - Backup: RESTORE fails, thinking it finds an existing table
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
set @save_log_output=@@global.log_output;
set global log_output=file;
connect(con2, localhost, root,,);
--echo #
--echo # Test 1: CREATE TABLE
--echo #
--echo # Connection 2
connection con2;
--echo # Start insert on the not-yet existing table
--echo # Wait after taking the MDL lock
SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL locked WAIT_FOR finish';
--send INSERT INTO t1 VALUES(1,"def")
--echo # Connection 1
connection default;
SET DEBUG_SYNC= 'now WAIT_FOR locked';
--echo # Now INSERT has a MDL on the non-existent table t1.
--echo #
--echo # Continue the INSERT once CREATE waits for exclusive lock
SET DEBUG_SYNC= 'mdl_acquire_exclusive_locks_wait SIGNAL finish';
--echo # Try to create that table.
--send CREATE TABLE t1 (c1 INT, c2 VARCHAR(100), KEY(c1))
--echo # Connection 2
--echo # Insert fails
connection con2;
--error ER_NO_SUCH_TABLE
--reap
--echo # Connection 1
connection default;
--reap;
SET DEBUG_SYNC= 'RESET';
SHOW TABLES;
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
--echo #
--echo # Test 2: CREATE TABLE LIKE
--echo #
CREATE TABLE t2 (c1 INT, c2 VARCHAR(100), KEY(c1));
--echo # Connection 2
connection con2;
--echo # Start insert on the not-yet existing table
--echo # Wait after taking the MDL
SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL locked WAIT_FOR finish';
--send INSERT INTO t1 VALUES(1,"def")
--echo # Connection 1
connection default;
SET DEBUG_SYNC= 'now WAIT_FOR locked';
--echo # Now INSERT has a MDL on the non-existent table t1.
--echo #
--echo # Continue the INSERT once CREATE waits for exclusive lock
SET DEBUG_SYNC= 'mdl_acquire_exclusive_locks_wait SIGNAL finish';
--echo # Try to create that table.
--send CREATE TABLE t1 LIKE t2
--echo # Connection 2
--echo # Insert fails
connection con2;
--error ER_NO_SUCH_TABLE
--reap
--echo # Connection 1
connection default;
--reap
SET DEBUG_SYNC= 'RESET';
SHOW TABLES;
DROP TABLE t2;
disconnect con2;
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
set global log_output=@save_log_output;
--echo #
--echo # Bug #46044 "MDL deadlock on LOCK TABLE + CREATE TABLE HIGH_PRIORITY
--echo # FOR UPDATE"
--echo #
--disable_warnings
drop tables if exists t1, t2;
--enable_warnings
connect (con46044, localhost, root,,);
connect (con46044_2, localhost, root,,);
connection default;
create table t1 (i int);
--echo # Let us check that we won't deadlock if during filling
--echo # of I_S table we encounter conflicting metadata lock
--echo # which owner is in its turn waiting for our connection.
lock tables t1 write;
--echo # Switching to connection 'con46044'.
connection con46044;
--echo # Sending:
--send create table t2 select * from t1;
--echo # Switching to connection 'default'.
connection default;
--echo # Waiting until CREATE TABLE ... SELECT ... is blocked.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and info = "create table t2 select * from t1";
--source include/wait_condition.inc
--echo # First let us check that SHOW FIELDS/DESCRIBE doesn't
--echo # gets blocked and emits and error.
--error ER_WARN_I_S_SKIPPED_TABLE
show fields from t2;
--echo # Now test for I_S query which reads only .FRMs.
--echo #
--echo # Query below should only emit a warning.
select column_name from information_schema.columns
where table_schema='test' and table_name='t2';
--echo # Finally, test for I_S query which does full-blown table open.
--echo #
--echo # Query below should not be blocked. Warning message should be
--echo # 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';
--echo # Switching to connection 'default'.
connection default;
unlock tables;
--echo # Switching to connection 'con46044'.
connection con46044;
--echo # Reaping CREATE TABLE ... SELECT ... .
--reap
drop table t2;
--echo #
--echo # Let us also check that queries to I_S wait for conflicting metadata
--echo # locks to go away instead of skipping table with a warning in cases
--echo # when deadlock is not possible. This is a nice thing from compatibility
--echo # and ease of use points of view.
--echo #
--echo # We check same three queries to I_S in this new situation.
--echo # Switching to connection 'con46044_2'.
connection con46044_2;
lock tables t1 write;
--echo # Switching to connection 'con46044'.
connection con46044;
--echo # Sending:
--send create table t2 select * from t1;
--echo # Switching to connection 'default'.
connection default;
--echo # Waiting until CREATE TABLE ... SELECT ... is blocked.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and info = "create table t2 select * from t1";
--source include/wait_condition.inc
--echo # Let us check that SHOW FIELDS/DESCRIBE gets blocked.
--echo # Sending:
--send show fields from t2;
--echo # Switching to connection 'con46044_2'.
connection con46044_2;
--echo # Wait until SHOW FIELDS gets blocked.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and info = "show fields from t2";
--source include/wait_condition.inc
unlock tables;
--echo # Switching to connection 'con46044'.
connection con46044;
--echo # Reaping CREATE TABLE ... SELECT ... .
--reap
--echo # Switching to connection 'default'.
connection default;
--echo # Reaping SHOW FIELDS ...
--reap
drop table t2;
--echo # Switching to connection 'con46044_2'.
connection con46044_2;
lock tables t1 write;
--echo # Switching to connection 'con46044'.
connection con46044;
--echo # Sending:
--send create table t2 select * from t1;
--echo # Switching to connection 'default'.
connection default;
--echo # Waiting until CREATE TABLE ... SELECT ... is blocked.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and info = "create table t2 select * from t1";
--source include/wait_condition.inc
--echo # Check that I_S query which reads only .FRMs gets blocked.
--echo # Sending:
--send select column_name from information_schema.columns where table_schema='test' and table_name='t2';
--echo # Switching to connection 'con46044_2'.
connection con46044_2;
--echo # Wait until SELECT COLUMN_NAME FROM I_S.COLUMNS gets blocked.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
info like "select column_name from information_schema.columns%";
--source include/wait_condition.inc
unlock tables;
--echo # Switching to connection 'con46044'.
connection con46044;
--echo # Reaping CREATE TABLE ... SELECT ... .
--reap
--echo # Switching to connection 'default'.
connection default;
--echo # Reaping SELECT COLUMN_NAME FROM I_S.COLUMNS
--reap
drop table t2;
--echo # Switching to connection 'con46044_2'.
connection con46044_2;
lock tables t1 write;
--echo # Switching to connection 'con46044'.
connection con46044;
--echo # Sending:
--send create table t2 select * from t1;
--echo # Switching to connection 'default'.
connection default;
--echo # Waiting until CREATE TABLE ... SELECT ... is blocked.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Table lock" and info = "create table t2 select * from t1";
--source include/wait_condition.inc
--echo # Finally, check that I_S query which does full-blown table open
--echo # also gets blocked.
--echo # Sending:
--send select table_name, table_type, auto_increment, table_comment from information_schema.tables where table_schema='test' and table_name='t2';
--echo # Switching to connection 'con46044_2'.
connection con46044_2;
--echo # Wait until SELECT ... FROM I_S.TABLES gets blocked.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table" and
info like "select table_name, table_type, auto_increment, table_comment from information_schema.tables%";
--source include/wait_condition.inc
unlock tables;
--echo # Switching to connection 'con46044'.
connection con46044;
--echo # Reaping CREATE TABLE ... SELECT ... .
--reap
--echo # Switching to connection 'default'.
connection default;
--echo # Reaping SELECT ... FROM I_S.TABLES
--reap
drop table t2;
--echo # Switching to connection 'default'.
connection default;
--echo # Clean-up.
disconnect con46044;
disconnect con46044_2;
drop table t1;
--echo #
--echo # Test for bug #46673 "Deadlock between FLUSH TABLES WITH READ LOCK
--echo # and DML".
--echo #
--disable_warnings
drop tables if exists t1;
--enable_warnings
connect (con46673, localhost, root,,);
connection default;
create table t1 (i int);
--echo # Switching to connection 'con46673'.
connection con46673;
begin;
insert into t1 values (1);
--echo # Switching to connection 'default'.
connection default;
--echo # Statement below should not get blocked. And if after some
--echo # changes to code it is there should not be a deadlock between
--echo # it and transaction from connection 'con46673'.
flush tables with read lock;
unlock tables;
--echo # Switching to connection 'con46673'.
connection con46673;
delete from t1 where i = 1;
commit;
--echo # Switching to connection 'default'.
connection default;
--echo # Clean-up
disconnect con46673;
drop table t1;
--echo #
--echo # Bug#48210 FLUSH TABLES WITH READ LOCK deadlocks
--echo # against concurrent CREATE PROCEDURE
--echo #
connect (con2, localhost, root);
--echo # Test 1: CREATE PROCEDURE
--echo # Connection 1
connection default;
--echo # Start CREATE PROCEDURE and open mysql.proc
SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL table_opened WAIT_FOR grlwait';
--send CREATE PROCEDURE p1() SELECT 1
--echo # Connection 2
connection con2;
SET DEBUG_SYNC= 'now WAIT_FOR table_opened';
--echo # Check that FLUSH must wait to get the GRL
--echo # and let CREATE PROCEDURE continue
SET DEBUG_SYNC= 'wait_lock_global_read_lock SIGNAL grlwait';
--send FLUSH TABLES WITH READ LOCK
--echo # Connection 1
connection default;
--reap
--echo # Connection 2
connection con2;
--reap
UNLOCK TABLES;
--echo # Connection 1
connection default;
SET DEBUG_SYNC= 'RESET';
--echo # Test 2: DROP PROCEDURE
connection default;
--echo # Start DROP PROCEDURE and open tables
SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL table_opened WAIT_FOR grlwait';
--send DROP PROCEDURE p1
--echo # Connection 2
connection con2;
SET DEBUG_SYNC= 'now WAIT_FOR table_opened';
--echo # Check that FLUSH must wait to get the GRL
--echo # and let DROP PROCEDURE continue
SET DEBUG_SYNC= 'wait_lock_global_read_lock SIGNAL grlwait';
--send FLUSH TABLES WITH READ LOCK
--echo # Connection 1
connection default;
--reap
--echo # Connection 2
connection con2;
--reap
UNLOCK TABLES;
--echo # Connection 1
connection default;
SET DEBUG_SYNC= 'RESET';
disconnect con2;
# Check that all connections opened by test cases in this file are really
# gone so execution of other tests won't be affected by their presence.
--source include/wait_until_count_sessions.inc