Commit 378cdc58 authored by Dmitry Lenev's avatar Dmitry Lenev

Patch that refactors global read lock implementation and fixes

bug #57006 "Deadlock between HANDLER and FLUSH TABLES WITH READ
LOCK" and bug #54673 "It takes too long to get readlock for
'FLUSH TABLES WITH READ LOCK'".

The first bug manifested itself as a deadlock which occurred
when a connection, which had some table open through HANDLER
statement, tried to update some data through DML statement
while another connection tried to execute FLUSH TABLES WITH
READ LOCK concurrently.

What happened was that FTWRL in the second connection managed
to perform first step of GRL acquisition and thus blocked all
upcoming DML. After that it started to wait for table open
through HANDLER statement to be flushed. When the first connection
tried to execute DML it has started to wait for GRL/the second
connection creating deadlock.

The second bug manifested itself as starvation of FLUSH TABLES
WITH READ LOCK statements in cases when there was a constant
stream of concurrent DML statements (in two or more
connections).

This has happened because requests for protection against GRL
which were acquired by DML statements were ignoring presence of
pending GRL and thus the latter was starved.

This patch solves both these problems by re-implementing GRL
using metadata locks.

Similar to the old implementation acquisition of GRL in new
implementation is two-step. During the first step we block
all concurrent DML and DDL statements by acquiring global S
metadata lock (each DML and DDL statement acquires global IX
lock for its duration). During the second step we block commits
by acquiring global S lock in COMMIT namespace (commit code
acquires global IX lock in this namespace).

Note that unlike in old implementation acquisition of
protection against GRL in DML and DDL is semi-automatic.
We assume that any statement which should be blocked by GRL
will either open and acquires write-lock on tables or acquires
metadata locks on objects it is going to modify. For any such
statement global IX metadata lock is automatically acquired
for its duration.

The first problem is solved because waits for GRL become
visible to deadlock detector in metadata locking subsystem
and thus deadlocks like one in the first bug become impossible.

The second problem is solved because global S locks which
are used for GRL implementation are given preference over
IX locks which are acquired by concurrent DML (and we can
switch to fair scheduling in future if needed).

Important change:
FTWRL/GRL no longer blocks DML and DDL on temporary tables.
Before this patch behavior was not consistent in this respect:
in some cases DML/DDL statements on temporary tables were
blocked while in others they were not. Since the main use cases
for FTWRL are various forms of backups and temporary tables are
not preserved during backups we have opted for consistently
allowing DML/DDL on temporary tables during FTWRL/GRL.

Important change:
This patch changes thread state names which are used when
DML/DDL of FTWRL is waiting for global read lock. It is now
either "Waiting for global read lock" or "Waiting for commit
lock" depending on the stage on which FTWRL is.

Incompatible change:
To solve deadlock in events code which was exposed by this
patch we have to replace LOCK_event_metadata mutex with
metadata locks on events. As result we have to prohibit
DDL on events under LOCK TABLES.

This patch also adds extensive test coverage for interaction
of DML/DDL and FTWRL.

Performance of new and old global read lock implementations
in sysbench tests were compared. There were no significant
difference between new and old implementations.
parent aee8fce2
#
# SUMMARY
# Check that a statement is compatible with FLUSH TABLES WITH READ LOCK.
#
# PARAMETERS
# $con_aux1 Name of the 1st aux connection to be used by this script.
# $con_aux2 Name of the 2nd aux connection to be used by this script.
# $statement The statement to be checked.
# $cleanup_stmt The statement to be run in order to revert effects of
# the statement to be checked.
# $skip_3rd_chk Skip the 3rd stage of checking. The purpose of the third
# stage is to check that metadata locks taken by this
# statement are compatible with metadata locks taken
# by FTWRL.
#
# EXAMPLE
# flush_read_lock.test
#
--disable_result_log
--disable_query_log
# Reset DEBUG_SYNC facility for safety.
set debug_sync= "RESET";
#
# First, check that the statement can be run under FTWRL.
#
flush tables with read lock;
--disable_abort_on_error
--eval $statement
--enable_abort_on_error
let $err= $mysql_errno;
if (!$err)
{
--echo Success: Was able to run '$statement' under FTWRL.
unlock tables;
if (`SELECT "$cleanup_stmt" <> ""`)
{
--eval $cleanup_stmt;
}
}
if ($err)
{
--echo Error: Wasn't able to run '$statement' under FTWRL!
unlock tables;
}
#
# Then check that this statement won't be blocked by FTWRL
# that is active in another connection.
#
connection $con_aux1;
flush tables with read lock;
connection default;
--send_eval $statement;
connection $con_aux1;
--enable_result_log
--enable_query_log
let $wait_condition=
select count(*) = 0 from information_schema.processlist
where info = "$statement";
--source include/wait_condition.inc
--disable_result_log
--disable_query_log
if ($success)
{
--echo Success: Was able to run '$statement' with FTWRL active in another connection.
connection default;
# Apparently statement was successfully executed and so
# was not blocked by FTWRL.
# To be safe against wait_condition.inc succeeding due to
# races let us first reap the statement being checked to
# ensure that it has been successfully executed.
--reap
connection $con_aux1;
unlock tables;
connection default;
}
if (!$success)
{
--echo Error: Wasn't able to run '$statement' with FTWRL active in another connection!
unlock tables;
connection default;
--reap
}
if (`SELECT "$cleanup_stmt" <> ""`)
{
--eval $cleanup_stmt;
}
if (`SELECT "$skip_3rd_check" = ""`)
{
#
# Finally, let us check that FTWRL will succeed if this statement
# is active but has already closed its tables.
#
connection default;
set debug_sync='execute_command_after_close_tables SIGNAL parked WAIT_FOR go';
--send_eval $statement;
connection $con_aux1;
set debug_sync="now WAIT_FOR parked";
--send flush tables with read lock
connection $con_aux2;
--enable_result_log
--enable_query_log
let $wait_condition=
select count(*) = 0 from information_schema.processlist
where info = "flush tables with read lock";
--source include/wait_condition.inc
--disable_result_log
--disable_query_log
if ($success)
{
--echo Success: Was able to run FTWRL while '$statement' was active in another connection.
connection $con_aux1;
# Apparently FTWRL was successfully executed and so was not blocked by
# the statement being checked. To be safe against wait_condition.inc
# succeeding due to races let us first reap the FTWRL to ensure that it
# has been successfully executed.
--reap
unlock tables;
set debug_sync="now SIGNAL go";
connection default;
--reap
}
if (!$success)
{
--echo Error: Wasn't able to run FTWRL while '$statement' was active in another connection!
set debug_sync="now SIGNAL go";
connection default;
--reap
connection $con_aux1;
--reap
unlock tables;
connection default;
}
set debug_sync= "RESET";
if (`SELECT "$cleanup_stmt" <> ""`)
{
--eval $cleanup_stmt;
}
}
--enable_result_log
--enable_query_log
#
# SUMMARY
# Check that a statement is incompatible with FLUSH TABLES WITH READ LOCK.
#
# PARAMETERS
# $con_aux1 Name of the 1st aux connection to be used by this script.
# $con_aux2 Name of the 2nd aux connection to be used by this script.
# $statement The statement to be checked.
# $cleanup_stmt1 The 1st statement to be run in order to revert effects
# of statement to be checked.
# $cleanup_stmt2 The 2nd statement to be run in order to revert effects
# of statement to be checked.
# $skip_3rd_chk Skip the 3rd stage of checking. The purpose of the third
# stage is to check that metadata locks taken by this
# statement are incompatible with metadata locks taken
# by FTWRL.
#
# EXAMPLE
# flush_read_lock.test
#
--disable_result_log
--disable_query_log
# Reset DEBUG_SYNC facility for safety.
set debug_sync= "RESET";
#
# First, check that the statement cannot be run under FTWRL.
#
flush tables with read lock;
--disable_abort_on_error
--eval $statement
--enable_abort_on_error
let $err= $mysql_errno;
if ($err)
{
--echo Success: Was not able to run '$statement' under FTWRL.
unlock tables;
}
if (!$err)
{
--echo Error: Was able to run '$statement' under FTWRL!
unlock tables;
if (`SELECT "$cleanup_stmt1" <> ""`)
{
--eval $cleanup_stmt1;
}
if (`SELECT "$cleanup_stmt2" <> ""`)
{
--eval $cleanup_stmt2;
}
}
#
# Then check that this statement is blocked by FTWRL
# that is active in another connection.
#
connection $con_aux1;
flush tables with read lock;
connection default;
--send_eval $statement;
connection $con_aux1;
--enable_result_log
--enable_query_log
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where (state = "Waiting for global read lock" or
state = "Waiting for commit lock") and
info = "$statement";
--source include/wait_condition.inc
--disable_result_log
--disable_query_log
if ($success)
{
--echo Success: '$statement' is blocked by FTWRL active in another connection.
}
if (!$success)
{
--echo Error: '$statement' wasn't blocked by FTWRL active in another connection!
}
unlock tables;
connection default;
--reap
if (`SELECT "$cleanup_stmt1" <> ""`)
{
--eval $cleanup_stmt1;
}
if (`SELECT "$cleanup_stmt2" <> ""`)
{
--eval $cleanup_stmt2;
}
if (`SELECT "$skip_3rd_check" = ""`)
{
#
# Finally, let us check that FTWRL will not succeed if this
# statement is active but has already closed its tables.
#
connection default;
--eval set debug_sync='execute_command_after_close_tables SIGNAL parked WAIT_FOR go';
--send_eval $statement;
connection $con_aux1;
set debug_sync="now WAIT_FOR parked";
--send flush tables with read lock
connection $con_aux2;
--enable_result_log
--enable_query_log
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where (state = "Waiting for global read lock" or
state = "Waiting for commit lock") and
info = "flush tables with read lock";
--source include/wait_condition.inc
--disable_result_log
--disable_query_log
if ($success)
{
--echo Success: FTWRL is blocked when '$statement' is active in another connection.
}
if (!$success)
{
--echo Error: FTWRL isn't blocked when '$statement' is active in another connection!
}
set debug_sync="now SIGNAL go";
connection default;
--reap
connection $con_aux1;
--reap
unlock tables;
connection default;
set debug_sync= "RESET";
if (`SELECT "$cleanup_stmt1" <> ""`)
{
--eval $cleanup_stmt1;
}
if (`SELECT "$cleanup_stmt2" <> ""`)
{
--eval $cleanup_stmt2;
}
}
--enable_result_log
--enable_query_log
......@@ -1545,8 +1545,6 @@ lock table not_exists_write read;
--echo # We still have the read lock.
--error ER_CANT_UPDATE_WITH_READLOCK
drop table t1;
handler t1 read next;
handler t1 close;
handler t1 open;
select a from t2;
handler t1 read next;
......
......@@ -101,7 +101,7 @@ if (`SELECT '$wait_for_all' = '1'`)
if (!$found)
{
echo # Timeout in include/wait_show_condition.inc for $wait_condition;
echo # Timeout in include/wait_show_condition.inc for $condition;
echo # show_statement : $show_statement;
echo # field : $field;
echo # condition : $condition;
......
......@@ -418,6 +418,18 @@ COMMIT;
UNLOCK TABLES;
# Connection con1
# Reaping: INSERT DELAYED INTO t1 VALUES (5)
# Connection default
# Test 5: LOCK TABLES + INSERT DELAYED in one connection.
# This test has triggered some asserts in metadata locking
# subsystem at some point in time..
LOCK TABLE t1 WRITE;
INSERT DELAYED INTO t2 VALUES (7);
UNLOCK TABLES;
SET AUTOCOMMIT= 0;
LOCK TABLE t1 WRITE;
INSERT DELAYED INTO t2 VALUES (8);
UNLOCK TABLES;
SET AUTOCOMMIT= 1;
# Connection con2
# Connection con1
# Connection default
......
......@@ -133,15 +133,15 @@ select event_name from information_schema.events;
event_name
e1
create event e2 on schedule every 10 hour do select 1;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
alter event e2 disable;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
alter event e2 rename to e3;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
drop event e2;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
drop event e1;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
unlock tables;
lock table t1 write;
show create event e1;
......@@ -151,15 +151,15 @@ select event_name from information_schema.events;
event_name
e1
create event e2 on schedule every 10 hour do select 1;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
alter event e2 disable;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
alter event e2 rename to e3;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
drop event e2;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
drop event e1;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
unlock tables;
lock table t1 read, mysql.event read;
show create event e1;
......@@ -169,15 +169,15 @@ select event_name from information_schema.events;
event_name
e1
create event e2 on schedule every 10 hour do select 1;
ERROR HY000: Table 'event' was locked with a READ lock and can't be updated
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
alter event e2 disable;
ERROR HY000: Table 'event' was locked with a READ lock and can't be updated
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
alter event e2 rename to e3;
ERROR HY000: Table 'event' was locked with a READ lock and can't be updated
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
drop event e2;
ERROR HY000: Table 'event' was locked with a READ lock and can't be updated
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
drop event e1;
ERROR HY000: Table 'event' was locked with a READ lock and can't be updated
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
unlock tables;
lock table t1 write, mysql.event read;
show create event e1;
......@@ -187,15 +187,15 @@ select event_name from information_schema.events;
event_name
e1
create event e2 on schedule every 10 hour do select 1;
ERROR HY000: Table 'event' was locked with a READ lock and can't be updated
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
alter event e2 disable;
ERROR HY000: Table 'event' was locked with a READ lock and can't be updated
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
alter event e2 rename to e3;
ERROR HY000: Table 'event' was locked with a READ lock and can't be updated
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
drop event e2;
ERROR HY000: Table 'event' was locked with a READ lock and can't be updated
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
drop event e1;
ERROR HY000: Table 'event' was locked with a READ lock and can't be updated
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
unlock tables;
lock table t1 read, mysql.event write;
ERROR HY000: You can't combine write-locking of system tables with other tables or lock types
......@@ -209,11 +209,17 @@ select event_name from information_schema.events;
event_name
e1
create event e2 on schedule every 10 hour do select 1;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
alter event e2 disable;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
alter event e2 rename to e3;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
drop event e3;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
drop event e1;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
unlock tables;
drop event e1;
Make sure we have left no events
select event_name from information_schema.events;
event_name
......
......@@ -423,3 +423,31 @@ i
4
unlock tables;
drop tables tm, t1, t2;
#
# Test for bug #57006 "Deadlock between HANDLER and
# FLUSH TABLES WITH READ LOCK".
#
drop table if exists t1, t2;
create table t1 (i int);
create table t2 (i int);
handler t1 open;
# Switching to connection 'con1'.
# Sending:
flush tables with read lock;
# Switching to connection 'con2'.
# Wait until FTWRL starts waiting for 't1' to be closed.
# Switching to connection 'default'.
# The below statement should not cause deadlock.
# Sending:
insert into t2 values (1);
# Switching to connection 'con2'.
# Wait until INSERT starts to wait for FTWRL to go away.
# Switching to connection 'con1'.
# FTWRL should be able to continue now.
# Reap FTWRL.
unlock tables;
# Switching to connection 'default'.
# Reap INSERT.
handler t1 close;
# Cleanup.
drop tables t1, t2;
This diff is collapsed.
SET @old_concurrent_insert= @@global.concurrent_insert;
SET @@global.concurrent_insert= 0;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (kill_id INT);
SET DEBUG_SYNC= 'RESET';
CREATE TABLE t1 (kill_id INT) engine = InnoDB;
INSERT INTO t1 VALUES(connection_id());
# Switching to connection 'default'.
# Start transaction.
BEGIN;
INSERT INTO t1 VALUES(connection_id());
# Ensure that COMMIT will pause once it acquires protection
# against its global read lock.
SET DEBUG_SYNC='ha_commit_trans_after_acquire_commit_lock SIGNAL acquired WAIT_FOR go';
# Sending:
COMMIT;
# Switching to 'con1'.
# Wait till COMMIT acquires protection against global read
# lock and pauses.
SET DEBUG_SYNC='now WAIT_FOR acquired';
# Sending:
FLUSH TABLES WITH READ LOCK;
SELECT ((@id := kill_id) - kill_id) FROM t1;
# Switching to 'con2'.
SELECT ((@id := kill_id) - kill_id) FROM t1 LIMIT 1;
((@id := kill_id) - kill_id)
0
# Wait till FLUSH TABLES WITH READ LOCK blocks due
# to active COMMIT
# Kill connection 'con1'.
KILL CONNECTION @id;
# Switching to 'con1'.
# Try to reap FLUSH TABLES WITH READ LOCK,
# it fail due to killed statement and connection.
Got one of the listed errors
# Switching to 'con2'.
# Resume COMMIT.
SET DEBUG_SYNC='now SIGNAL go';
# Switching to 'default'.
# Reaping COMMIT.
DROP TABLE t1;
SET @@global.concurrent_insert= @old_concurrent_insert;
SET DEBUG_SYNC= 'RESET';
......@@ -1485,10 +1485,6 @@ ERROR 42S02: Table 'test.not_exists_write' doesn't exist
# We still have the read lock.
drop table t1;
ERROR HY000: Can't execute the query because you have a conflicting read lock
handler t1 read next;
a b
1 1
handler t1 close;
handler t1 open;
select a from t2;
a
......
......@@ -1481,10 +1481,6 @@ ERROR 42S02: Table 'test.not_exists_write' doesn't exist
# We still have the read lock.
drop table t1;
ERROR HY000: Can't execute the query because you have a conflicting read lock
handler t1 read next;
a b
1 1
handler t1 close;
handler t1 open;
select a from t2;
a
......
......@@ -2471,7 +2471,7 @@ CREATE PROCEDURE p1() SELECT 1;
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';
SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL grlwait';
FLUSH TABLES WITH READ LOCK;
# Connection 1
# Connection 2
......@@ -2486,10 +2486,17 @@ DROP PROCEDURE p1;
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';
SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL grlwait';
FLUSH TABLES WITH READ LOCK;
# Connection 1
# Once FLUSH TABLES WITH READ LOCK starts waiting
# DROP PROCEDURE will be waked up and will drop
# procedure. Global read lock will be granted after
# this statement ends.
#
# Reaping DROP PROCEDURE.
# Connection 2
# Reaping FTWRL.
UNLOCK TABLES;
# Connection 1
SET DEBUG_SYNC= 'RESET';
......
......@@ -37,7 +37,6 @@ where name like 'Wait/Synch/Cond/sql/%'
order by name limit 10;
NAME ENABLED TIMED
wait/synch/cond/sql/COND_flush_thread_cache YES YES
wait/synch/cond/sql/COND_global_read_lock YES YES
wait/synch/cond/sql/COND_manager YES YES
wait/synch/cond/sql/COND_queue_state YES YES
wait/synch/cond/sql/COND_rpl_status YES YES
......@@ -46,6 +45,7 @@ wait/synch/cond/sql/COND_thread_cache YES YES
wait/synch/cond/sql/COND_thread_count YES YES
wait/synch/cond/sql/Delayed_insert::cond YES YES
wait/synch/cond/sql/Delayed_insert::cond_client YES YES
wait/synch/cond/sql/Event_scheduler::COND_state YES YES
select * from performance_schema.SETUP_INSTRUMENTS
where name='Wait';
select * from performance_schema.SETUP_INSTRUMENTS
......
......@@ -100,3 +100,4 @@ INNER JOIN performance_schema.THREADS p USING (THREAD_ID)
WHERE p.PROCESSLIST_ID = 1
GROUP BY h.EVENT_NAME
HAVING TOTAL_WAIT > 0;
UPDATE performance_schema.SETUP_INSTRUMENTS SET enabled = 'YES';
......@@ -110,4 +110,5 @@ WHERE (EVENT_NAME = 'wait/synch/rwlock/sql/LOCK_grant'));
SELECT IF((COALESCE(@after_count, 0) - COALESCE(@before_count, 0)) = 0, 'Success', 'Failure') test_fm2_rw_timed;
test_fm2_rw_timed
Success
UPDATE performance_schema.SETUP_INSTRUMENTS SET enabled = 'YES';
DROP TABLE t1;
use performance_schema;
update performance_schema.SETUP_INSTRUMENTS set enabled='YES';
grant SELECT, UPDATE, LOCK TABLES on performance_schema.* to pfsuser@localhost;
flush privileges;
connect (con1, localhost, pfsuser, , test);
......@@ -21,9 +22,9 @@ select event_name,
left(source, locate(":", source)) as short_source,
timer_end, timer_wait, operation
from performance_schema.EVENTS_WAITS_CURRENT
where event_name like "wait/synch/cond/sql/COND_global_read_lock";
where event_name like "wait/synch/cond/sql/MDL_context::COND_wait_status";
event_name short_source timer_end timer_wait operation
wait/synch/cond/sql/COND_global_read_lock lock.cc: NULL NULL wait
wait/synch/cond/sql/MDL_context::COND_wait_status mdl.cc: NULL NULL timed_wait
unlock tables;
update performance_schema.SETUP_INSTRUMENTS set enabled='NO';
update performance_schema.SETUP_INSTRUMENTS set enabled='YES';
......
......@@ -88,10 +88,6 @@ where name like "wait/synch/mutex/sql/LOCK_manager";
count(name)
1
select count(name) from MUTEX_INSTANCES
where name like "wait/synch/mutex/sql/LOCK_global_read_lock";
count(name)
1
select count(name) from MUTEX_INSTANCES
where name like "wait/synch/mutex/sql/LOCK_global_system_variables";
count(name)
1
......@@ -120,10 +116,6 @@ where name like "wait/synch/mutex/sql/Query_cache::structure_guard_mutex";
count(name)
1
select count(name) from MUTEX_INSTANCES
where name like "wait/synch/mutex/sql/LOCK_event_metadata";
count(name)
1
select count(name) from MUTEX_INSTANCES
where name like "wait/synch/mutex/sql/LOCK_event_queue";
count(name)
1
......@@ -184,10 +176,6 @@ where name like "wait/synch/cond/sql/COND_manager";
count(name)
1
select count(name) from COND_INSTANCES
where name like "wait/synch/cond/sql/COND_global_read_lock";
count(name)
1
select count(name) from COND_INSTANCES
where name like "wait/synch/cond/sql/COND_thread_cache";
count(name)
1
......
......@@ -190,3 +190,6 @@ HAVING TOTAL_WAIT > 0;
## HAVING BYTES > 0
## ORDER BY i.user, h.operation;
## --enable_result_log
# Clean-up.
UPDATE performance_schema.SETUP_INSTRUMENTS SET enabled = 'YES';
......@@ -128,4 +128,6 @@ SET @after_count = (SELECT SUM(TIMER_WAIT)
SELECT IF((COALESCE(@after_count, 0) - COALESCE(@before_count, 0)) = 0, 'Success', 'Failure') test_fm2_rw_timed;
# Clean-up.
UPDATE performance_schema.SETUP_INSTRUMENTS SET enabled = 'YES';
DROP TABLE t1;
......@@ -22,6 +22,10 @@
use performance_schema;
# Make test robust against errors in other tests.
# Ensure that instrumentation is turned on when we create new connection.
update performance_schema.SETUP_INSTRUMENTS set enabled='YES';
grant SELECT, UPDATE, LOCK TABLES on performance_schema.* to pfsuser@localhost;
flush privileges;
......@@ -60,7 +64,7 @@ lock tables performance_schema.SETUP_INSTRUMENTS write;
--echo connection default;
connection default;
let $wait_condition= select 1 from performance_schema.EVENTS_WAITS_CURRENT where event_name like "wait/synch/cond/sql/COND_global_read_lock";
let $wait_condition= select 1 from performance_schema.EVENTS_WAITS_CURRENT where event_name like "wait/synch/cond/sql/MDL_context::COND_wait_status";
--source include/wait_condition.inc
......@@ -69,7 +73,7 @@ select event_name,
left(source, locate(":", source)) as short_source,
timer_end, timer_wait, operation
from performance_schema.EVENTS_WAITS_CURRENT
where event_name like "wait/synch/cond/sql/COND_global_read_lock";
where event_name like "wait/synch/cond/sql/MDL_context::COND_wait_status";
unlock tables;
......
......@@ -100,9 +100,6 @@ select count(name) from MUTEX_INSTANCES
select count(name) from MUTEX_INSTANCES
where name like "wait/synch/mutex/sql/LOCK_manager";
select count(name) from MUTEX_INSTANCES
where name like "wait/synch/mutex/sql/LOCK_global_read_lock";
select count(name) from MUTEX_INSTANCES
where name like "wait/synch/mutex/sql/LOCK_global_system_variables";
......@@ -132,9 +129,6 @@ select count(name) from MUTEX_INSTANCES
# select count(name) from MUTEX_INSTANCES
# where name like "wait/synch/mutex/sql/Event_scheduler::LOCK_scheduler_state";
select count(name) from MUTEX_INSTANCES
where name like "wait/synch/mutex/sql/LOCK_event_metadata";
select count(name) from MUTEX_INSTANCES
where name like "wait/synch/mutex/sql/LOCK_event_queue";
......@@ -188,9 +182,6 @@ select count(name) from COND_INSTANCES
select count(name) from COND_INSTANCES
where name like "wait/synch/cond/sql/COND_manager";
select count(name) from COND_INSTANCES
where name like "wait/synch/cond/sql/COND_global_read_lock";
select count(name) from COND_INSTANCES
where name like "wait/synch/cond/sql/COND_thread_cache";
......
......@@ -123,16 +123,16 @@ DROP PROCEDURE p2;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
INSERT INTO t2 VALUES ("DROP PROCEDURE p2 with table locked");
CREATE EVENT e1 ON SCHEDULE EVERY 10 HOUR DO SELECT 1;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
INSERT INTO t2 VALUES ("CREATE EVENT e1 with table locked");
UNLOCK TABLE;
CREATE EVENT e2 ON SCHEDULE EVERY 10 HOUR DO SELECT 1;
LOCK TABLE t1 WRITE;
ALTER EVENT e2 ON SCHEDULE EVERY 20 HOUR DO SELECT 1;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
INSERT INTO t2 VALUES ("ALTER EVENT e2 with table locked");
DROP EVENT e2;
ERROR HY000: Table 'event' was not locked with LOCK TABLES
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
INSERT INTO t2 VALUES ("DROP EVENT e2 with table locked");
CREATE DATABASE mysqltest1;
ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
......
......@@ -539,6 +539,21 @@ connection con1;
--echo # Reaping: INSERT DELAYED INTO t1 VALUES (5)
--reap
--echo # Connection default
connection default;
--echo # Test 5: LOCK TABLES + INSERT DELAYED in one connection.
--echo # This test has triggered some asserts in metadata locking
--echo # subsystem at some point in time..
LOCK TABLE t1 WRITE;
INSERT DELAYED INTO t2 VALUES (7);
UNLOCK TABLES;
SET AUTOCOMMIT= 0;
LOCK TABLE t1 WRITE;
INSERT DELAYED INTO t2 VALUES (8);
UNLOCK TABLES;
SET AUTOCOMMIT= 1;
--echo # Connection con2
connection con2;
disconnect con2;
......
......@@ -212,15 +212,15 @@ lock table t1 read;
--replace_regex /STARTS '[^']+'/STARTS '#'/
show create event e1;
select event_name from information_schema.events;
--error ER_TABLE_NOT_LOCKED
--error ER_LOCK_OR_ACTIVE_TRANSACTION
create event e2 on schedule every 10 hour do select 1;
--error ER_TABLE_NOT_LOCKED
--error ER_LOCK_OR_ACTIVE_TRANSACTION
alter event e2 disable;
--error ER_TABLE_NOT_LOCKED
--error ER_LOCK_OR_ACTIVE_TRANSACTION
alter event e2 rename to e3;
--error ER_TABLE_NOT_LOCKED
--error ER_LOCK_OR_ACTIVE_TRANSACTION
drop event e2;
--error ER_TABLE_NOT_LOCKED
--error ER_LOCK_OR_ACTIVE_TRANSACTION
drop event e1;
unlock tables;
#
......@@ -229,15 +229,15 @@ lock table t1 write;
--replace_regex /STARTS '[^']+'/STARTS '#'/
show create event e1;
select event_name from information_schema.events;
--error ER_TABLE_NOT_LOCKED
--error ER_LOCK_OR_ACTIVE_TRANSACTION
create event e2 on schedule every 10 hour do select 1;
--error ER_TABLE_NOT_LOCKED
--error ER_LOCK_OR_ACTIVE_TRANSACTION
alter event e2 disable;
--error ER_TABLE_NOT_LOCKED
--error ER_LOCK_OR_ACTIVE_TRANSACTION
alter event e2 rename to e3;
--error ER_TABLE_NOT_LOCKED
--error ER_LOCK_OR_ACTIVE_TRANSACTION
drop event e2;
--error ER_TABLE_NOT_LOCKED
--error ER_LOCK_OR_ACTIVE_TRANSACTION
drop event e1;
unlock tables;
#
......@@ -246,15 +246,15 @@ lock table t1 read, mysql.event read;
--replace_regex /STARTS '[^']+'/STARTS '#'/
show create event e1;
select event_name from information_schema.events;
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
--error ER_LOCK_OR_ACTIVE_TRANSACTION
create event e2 on schedule every 10 hour do select 1;
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
--error ER_LOCK_OR_ACTIVE_TRANSACTION
alter event e2 disable;
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
--error ER_LOCK_OR_ACTIVE_TRANSACTION
alter event e2 rename to e3;
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
--error ER_LOCK_OR_ACTIVE_TRANSACTION
drop event e2;
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
--error ER_LOCK_OR_ACTIVE_TRANSACTION
drop event e1;
unlock tables;
#
......@@ -263,15 +263,15 @@ lock table t1 write, mysql.event read;
--replace_regex /STARTS '[^']+'/STARTS '#'/
show create event e1;
select event_name from information_schema.events;
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
--error ER_LOCK_OR_ACTIVE_TRANSACTION
create event e2 on schedule every 10 hour do select 1;
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
--error ER_LOCK_OR_ACTIVE_TRANSACTION
alter event e2 disable;
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
--error ER_LOCK_OR_ACTIVE_TRANSACTION
alter event e2 rename to e3;
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
--error ER_LOCK_OR_ACTIVE_TRANSACTION
drop event e2;
--error ER_TABLE_NOT_LOCKED_FOR_WRITE
--error ER_LOCK_OR_ACTIVE_TRANSACTION
drop event e1;
unlock tables;
#
......@@ -285,12 +285,18 @@ lock table mysql.event write;
--replace_regex /STARTS '[^']+'/STARTS '#'/
show create event e1;
select event_name from information_schema.events;
--error ER_LOCK_OR_ACTIVE_TRANSACTION
create event e2 on schedule every 10 hour do select 1;
--error ER_LOCK_OR_ACTIVE_TRANSACTION
alter event e2 disable;
--error ER_LOCK_OR_ACTIVE_TRANSACTION
alter event e2 rename to e3;
--error ER_LOCK_OR_ACTIVE_TRANSACTION
drop event e3;
--error ER_LOCK_OR_ACTIVE_TRANSACTION
drop event e1;
unlock tables;
drop event e1;
--echo Make sure we have left no events
select event_name from information_schema.events;
--echo
......
......@@ -577,3 +577,70 @@ select * from t1;
select * from t2;
unlock tables;
drop tables tm, t1, t2;
--echo #
--echo # Test for bug #57006 "Deadlock between HANDLER and
--echo # FLUSH TABLES WITH READ LOCK".
--echo #
--disable_warnings
drop table if exists t1, t2;
--enable_warnings
connect (con1,localhost,root,,);
connect (con2,localhost,root,,);
connection default;
create table t1 (i int);
create table t2 (i int);
handler t1 open;
--echo # Switching to connection 'con1'.
connection con1;
--echo # Sending:
--send flush tables with read lock
--echo # Switching to connection 'con2'.
connection con2;
--echo # Wait until FTWRL starts waiting for 't1' to be closed.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for table flush"
and info = "flush tables with read lock";
--source include/wait_condition.inc
--echo # Switching to connection 'default'.
connection default;
--echo # The below statement should not cause deadlock.
--echo # Sending:
--send insert into t2 values (1)
--echo # Switching to connection 'con2'.
connection con2;
--echo # Wait until INSERT starts to wait for FTWRL to go away.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for global read lock"
and info = "insert into t2 values (1)";
--source include/wait_condition.inc
--echo # Switching to connection 'con1'.
connection con1;
--echo # FTWRL should be able to continue now.
--echo # Reap FTWRL.
--reap
unlock tables;
--echo # Switching to connection 'default'.
connection default;
--echo # Reap INSERT.
--reap
handler t1 close;
--echo # Cleanup.
connection con1;
disconnect con1;
--source include/wait_until_disconnected.inc
connection con2;
disconnect con2;
--source include/wait_until_disconnected.inc
connection default;
drop tables t1, t2;
......@@ -39,7 +39,7 @@ connection con2;
--echo # Wait until COMMIT gets blocked.
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for release of readlock" and info = "COMMIT";
where state = "Waiting for commit lock" and info = "COMMIT";
--source include/wait_condition.inc
--echo # Verify that 'con1' was blocked and data did not move.
SELECT * FROM t1;
......
......@@ -53,7 +53,7 @@ begin;
connection con1;
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for release of readlock" and
where state = "Waiting for global read lock" and
info = "insert into t1 values (1)";
--source include/wait_condition.inc
unlock tables;
......
This diff is collapsed.
--loose-debug=+d,make_global_read_lock_block_commit_loop
......@@ -2,24 +2,19 @@
# for running commits to finish (in the past it could not)
# This will not be a meaningful test on non-debug servers so will be
# skipped.
# If running mysql-test-run --debug, the --debug added by
# mysql-test-run to the mysqld command line will override the one of
# -master.opt. But this test is designed to still pass then (though it
# won't test anything interesting).
# This also won't work with the embedded server test
--source include/not_embedded.inc
--source include/have_debug.inc
# This test needs transactional engine as otherwise COMMIT
# won't block FLUSH TABLES WITH GLOBAL READ LOCK.
--source include/have_innodb.inc
# Save the initial number of concurrent sessions
--source include/count_sessions.inc
# Disable concurrent inserts to avoid test failures when reading the
# connection id which was inserted into a table by another thread.
SET @old_concurrent_insert= @@global.concurrent_insert;
SET @@global.concurrent_insert= 0;
connect (con1,localhost,root,,);
connect (con2,localhost,root,,);
connection con1;
......@@ -27,47 +22,64 @@ connection con1;
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1 (kill_id INT);
SET DEBUG_SYNC= 'RESET';
CREATE TABLE t1 (kill_id INT) engine = InnoDB;
INSERT INTO t1 VALUES(connection_id());
--echo # Switching to connection 'default'.
connection default;
--echo # Start transaction.
BEGIN;
INSERT INTO t1 VALUES(connection_id());
--echo # Ensure that COMMIT will pause once it acquires protection
--echo # against its global read lock.
SET DEBUG_SYNC='ha_commit_trans_after_acquire_commit_lock SIGNAL acquired WAIT_FOR go';
# Thanks to the parameter we passed to --debug, this FLUSH will
# block on a debug build running with our --debug=make_global... It
# will block until killed. In other cases (non-debug build or other
# --debug) it will succeed immediately
--echo # Sending:
--send COMMIT
--echo # Switching to 'con1'.
connection con1;
--echo # Wait till COMMIT acquires protection against global read
--echo # lock and pauses.
SET DEBUG_SYNC='now WAIT_FOR acquired';
--echo # Sending:
send FLUSH TABLES WITH READ LOCK;
# kill con1
--echo # Switching to 'con2'.
connection con2;
SELECT ((@id := kill_id) - kill_id) FROM t1;
SELECT ((@id := kill_id) - kill_id) FROM t1 LIMIT 1;
# Wait for the debug sync point, test won't run on non-debug
# builds anyway.
--echo # Wait till FLUSH TABLES WITH READ LOCK blocks due
--echo # to active COMMIT
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for all running commits to finish"
where state = "Waiting for commit lock"
and info = "flush tables with read lock";
--source include/wait_condition.inc
--echo # Kill connection 'con1'.
KILL CONNECTION @id;
--echo # Switching to 'con1'.
connection con1;
# On debug builds it will be error 1053 (killed); on non-debug, or
# debug build running without our --debug=make_global..., will be
# error 0 (no error). The only important thing to test is that on
# debug builds with our --debug=make_global... we don't hang forever.
--error 0,1317,2013
--echo # Try to reap FLUSH TABLES WITH READ LOCK,
--echo # it fail due to killed statement and connection.
--error 1317,2013
reap;
--echo # Switching to 'con2'.
connection con2;
DROP TABLE t1;
--echo # Resume COMMIT.
SET DEBUG_SYNC='now SIGNAL go';
--echo # Switching to 'default'.
connection default;
--echo # Reaping COMMIT.
--reap
disconnect con2;
# Restore global concurrent_insert value
SET @@global.concurrent_insert= @old_concurrent_insert;
DROP TABLE t1;
SET DEBUG_SYNC= 'RESET';
# Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc
......
This diff is collapsed.
......@@ -3661,7 +3661,7 @@ 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';
SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL grlwait';
--send FLUSH TABLES WITH READ LOCK
--echo # Connection 1
......@@ -3689,15 +3689,22 @@ 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';
SET DEBUG_SYNC= 'mdl_acquire_lock_wait SIGNAL grlwait';
--send FLUSH TABLES WITH READ LOCK
--echo # Connection 1
connection default;
--echo # Once FLUSH TABLES WITH READ LOCK starts waiting
--echo # DROP PROCEDURE will be waked up and will drop
--echo # procedure. Global read lock will be granted after
--echo # this statement ends.
--echo #
--echo # Reaping DROP PROCEDURE.
--reap
--echo # Connection 2
connection con2;
--echo # Reaping FTWRL.
--reap
UNLOCK TABLES;
......@@ -4485,7 +4492,7 @@ connection con2;
--echo # Connection default
connection default;
let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist
WHERE state='Waiting for release of readlock'
WHERE state='Waiting for global read lock'
AND info='CREATE TABLE db1.t2(a INT)';
--source include/wait_condition.inc
UNLOCK TABLES;
......@@ -4507,7 +4514,7 @@ connection con2;
--echo # Connection default
connection default;
let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist
WHERE state='Waiting for release of readlock'
WHERE state='Waiting for global read lock'
AND info='ALTER DATABASE db1 DEFAULT CHARACTER SET utf8';
--source include/wait_condition.inc
UNLOCK TABLES;
......
......@@ -896,7 +896,7 @@ connection default;
--echo connection: default
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where state = "Waiting for global metadata lock";
where state = "Waiting for global read lock";
--source include/wait_condition.inc
create trigger t1_bi before insert on t1 for each row begin end;
unlock tables;
......
This diff is collapsed.
......@@ -82,10 +82,6 @@ class Event_basic
class Event_queue_element : public Event_basic
{
protected:
bool status_changed;
bool last_executed_changed;
public:
int on_completion;
int status;
......@@ -117,9 +113,6 @@ class Event_queue_element : public Event_basic
void
mark_last_executed(THD *thd);
bool
update_timing_fields(THD *thd);
};
......
This diff is collapsed.
......@@ -101,9 +101,7 @@ class Event_db_repository
update_timing_fields_for_event(THD *thd,
LEX_STRING event_db_name,
LEX_STRING event_name,
bool update_last_executed,
my_time_t last_executed,
bool update_status,
ulonglong status);
public:
static bool
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -4961,6 +4961,8 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
*/
if (! thd->in_multi_stmt_transaction_mode())
thd->mdl_context.release_transactional_locks();
else
thd->mdl_context.release_statement_locks();
DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error",
thd->is_slave_error= 0; thd->is_fatal_error= 1;);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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