mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 21:42:35 +01:00
378cdc58c1
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.
408 lines
17 KiB
Text
408 lines
17 KiB
Text
drop database if exists events_test;
|
||
create database events_test;
|
||
use events_test;
|
||
create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
|
||
select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
|
||
db name body definer convert_tz(execute_at, 'UTC', 'SYSTEM') on_completion
|
||
events_test e_26 set @a = 5 root@localhost 2017-01-01 00:00:00 DROP
|
||
drop event e_26;
|
||
create event e_26 on schedule at NULL disable do set @a = 5;
|
||
ERROR HY000: Incorrect AT value: 'NULL'
|
||
create event e_26 on schedule at 'definitely not a datetime' disable do set @a = 5;
|
||
ERROR HY000: Incorrect AT value: 'definitely not a datetime'
|
||
set names utf8;
|
||
create event задачка on schedule every 123 minute starts now() ends now() + interval 1 month do select 1;
|
||
drop event задачка;
|
||
"DISABLE the scheduler. Testing that it does not work when the variable is 0"
|
||
set global event_scheduler=off;
|
||
select definer, name, db from mysql.event;
|
||
definer name db
|
||
select get_lock("test_lock1", 20);
|
||
get_lock("test_lock1", 20)
|
||
1
|
||
create event закачка on schedule every 10 hour do select get_lock("test_lock1", 20);
|
||
"Should return 1 row"
|
||
select definer, name, db from mysql.event;
|
||
definer name db
|
||
root@localhost закачка events_test
|
||
"Should be only 0 process"
|
||
select /*1*/ user, host, db, command, state, info
|
||
from information_schema.processlist
|
||
where (user='event_scheduler')
|
||
order by info;
|
||
user host db command state info
|
||
select release_lock("test_lock1");
|
||
release_lock("test_lock1")
|
||
1
|
||
drop event закачка;
|
||
"Should have 0 events"
|
||
select count(*) from mysql.event;
|
||
count(*)
|
||
0
|
||
"ENABLE the scheduler and get a lock"
|
||
set global event_scheduler=on;
|
||
select get_lock("test_lock2", 20);
|
||
get_lock("test_lock2", 20)
|
||
1
|
||
"Create an event which tries to acquire a mutex. The event locks on the mutex"
|
||
create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20);
|
||
"Should have only 2 processes: the scheduler and the locked event"
|
||
select /*2*/ user, host, db, command, state, info
|
||
from information_schema.processlist
|
||
where (info like "select get_lock%" OR user='event_scheduler')
|
||
order by info;
|
||
user host db command state info
|
||
event_scheduler localhost NULL Daemon Waiting for next activation NULL
|
||
root localhost events_test Connect User lock select get_lock("test_lock2", 20)
|
||
"Release the mutex, the event worker should finish."
|
||
select release_lock("test_lock2");
|
||
release_lock("test_lock2")
|
||
1
|
||
drop event закачка;
|
||
set global event_scheduler=1;
|
||
select get_lock("test_lock2_1", 20);
|
||
get_lock("test_lock2_1", 20)
|
||
1
|
||
create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20);
|
||
"Should have only 2 processes: the scheduler and the locked event"
|
||
select /*3*/ user, host, db, command, state, info
|
||
from information_schema.processlist
|
||
where (info like "select get_lock%" OR user='event_scheduler')
|
||
order by info;
|
||
user host db command state info
|
||
event_scheduler localhost NULL Daemon Waiting for next activation NULL
|
||
root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
|
||
set global event_scheduler=off;
|
||
"Should have only our process now:"
|
||
select /*4*/ user, host, db, command, state, info
|
||
from information_schema.processlist
|
||
where (info like "select get_lock%" OR user='event_scheduler')
|
||
order by info;
|
||
user host db command state info
|
||
root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
|
||
select release_lock("test_lock2_1");
|
||
release_lock("test_lock2_1")
|
||
1
|
||
drop event закачка21;
|
||
create table t_16 (s1 int);
|
||
create trigger t_16_bi before insert on t_16 for each row create event e_16 on schedule every 1 second do set @a=5;
|
||
ERROR HY000: Recursion of EVENT DDL statements is forbidden when body is present
|
||
drop table t_16;
|
||
create event white_space
|
||
on schedule every 10 hour
|
||
disable
|
||
do
|
||
select 1;
|
||
select event_schema, event_name, definer, event_definition from information_schema.events where event_name='white_space';
|
||
event_schema event_name definer event_definition
|
||
events_test white_space root@localhost select 1
|
||
drop event white_space;
|
||
create event white_space on schedule every 10 hour disable do
|
||
select 2;
|
||
select event_schema, event_name, definer, event_definition from information_schema.events where event_name='white_space';
|
||
event_schema event_name definer event_definition
|
||
events_test white_space root@localhost select 2
|
||
drop event white_space;
|
||
create event white_space on schedule every 10 hour disable do select 3;
|
||
select event_schema, event_name, definer, event_definition from information_schema.events where event_name='white_space';
|
||
event_schema event_name definer event_definition
|
||
events_test white_space root@localhost select 3
|
||
drop event white_space;
|
||
create event e1 on schedule every 1 year do set @a = 5;
|
||
create table t1 (s1 int);
|
||
create trigger t1_ai after insert on t1 for each row show create event e1;
|
||
ERROR 0A000: Not allowed to return a result set from a trigger
|
||
drop table t1;
|
||
drop event e1;
|
||
SHOW EVENTS FROM aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
|
||
ERROR 42000: Incorrect database name 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
|
||
SHOW EVENTS FROM ``;
|
||
ERROR 42000: Incorrect database name ''
|
||
SHOW EVENTS FROM `events\\test`;
|
||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
|
||
|
||
LOCK TABLES mode.
|
||
|
||
create table t1 (a int);
|
||
create event e1 on schedule every 10 hour do select 1;
|
||
lock table t1 read;
|
||
show create event e1;
|
||
Event sql_mode time_zone Create Event character_set_client collation_connection Database Collation
|
||
e1 SYSTEM CREATE DEFINER=`root`@`localhost` EVENT `e1` ON SCHEDULE EVERY 10 HOUR STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1 utf8 utf8_general_ci latin1_swedish_ci
|
||
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 e2;
|
||
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;
|
||
lock table t1 write;
|
||
show create event e1;
|
||
Event sql_mode time_zone Create Event character_set_client collation_connection Database Collation
|
||
e1 SYSTEM CREATE DEFINER=`root`@`localhost` EVENT `e1` ON SCHEDULE EVERY 10 HOUR STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1 utf8 utf8_general_ci latin1_swedish_ci
|
||
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 e2;
|
||
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;
|
||
lock table t1 read, mysql.event read;
|
||
show create event e1;
|
||
Event sql_mode time_zone Create Event character_set_client collation_connection Database Collation
|
||
e1 SYSTEM CREATE DEFINER=`root`@`localhost` EVENT `e1` ON SCHEDULE EVERY 10 HOUR STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1 utf8 utf8_general_ci latin1_swedish_ci
|
||
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 e2;
|
||
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;
|
||
lock table t1 write, mysql.event read;
|
||
show create event e1;
|
||
Event sql_mode time_zone Create Event character_set_client collation_connection Database Collation
|
||
e1 SYSTEM CREATE DEFINER=`root`@`localhost` EVENT `e1` ON SCHEDULE EVERY 10 HOUR STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1 utf8 utf8_general_ci latin1_swedish_ci
|
||
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 e2;
|
||
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;
|
||
lock table t1 read, mysql.event write;
|
||
ERROR HY000: You can't combine write-locking of system tables with other tables or lock types
|
||
lock table t1 write, mysql.event write;
|
||
ERROR HY000: You can't combine write-locking of system tables with other tables or lock types
|
||
lock table mysql.event write;
|
||
show create event e1;
|
||
Event sql_mode time_zone Create Event character_set_client collation_connection Database Collation
|
||
e1 SYSTEM CREATE DEFINER=`root`@`localhost` EVENT `e1` ON SCHEDULE EVERY 10 HOUR STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO select 1 utf8 utf8_general_ci latin1_swedish_ci
|
||
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
|
||
|
||
Events in sub-statements, events and prelocking
|
||
|
||
|
||
create event e1 on schedule every 10 hour do select 1;
|
||
create function f1() returns int
|
||
begin
|
||
show create event e1;
|
||
return 1;
|
||
end|
|
||
ERROR 0A000: Not allowed to return a result set from a function
|
||
create trigger trg before insert on t1 for each row
|
||
begin
|
||
show create event e1;
|
||
end|
|
||
ERROR 0A000: Not allowed to return a result set from a trigger
|
||
create function f1() returns int
|
||
begin
|
||
select event_name from information_schema.events;
|
||
return 1;
|
||
end|
|
||
ERROR 0A000: Not allowed to return a result set from a function
|
||
create trigger trg before insert on t1 for each row
|
||
begin
|
||
select event_name from information_schema.events;
|
||
end|
|
||
ERROR 0A000: Not allowed to return a result set from a trigger
|
||
create function f1() returns int
|
||
begin
|
||
create event e2 on schedule every 10 hour do select 1;
|
||
return 1;
|
||
end|
|
||
ERROR HY000: Recursion of EVENT DDL statements is forbidden when body is present
|
||
create function f1() returns int
|
||
begin
|
||
alter event e1 rename to e2;
|
||
return 1;
|
||
end|
|
||
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
|
||
create function f1() returns int
|
||
begin
|
||
drop event e2;
|
||
return 1;
|
||
end|
|
||
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
|
||
----------------------------------------------------------------------
|
||
create trigger trg before insert on t1 for each row
|
||
begin
|
||
set new.a= f1();
|
||
end|
|
||
create function f1() returns int
|
||
begin
|
||
call p1();
|
||
return 0;
|
||
end|
|
||
create procedure p1()
|
||
begin
|
||
select event_name from information_schema.events;
|
||
end|
|
||
insert into t1 (a) values (1)|
|
||
ERROR 0A000: Not allowed to return a result set from a trigger
|
||
drop procedure p1|
|
||
create procedure p1()
|
||
begin
|
||
show create event e1;
|
||
end|
|
||
insert into t1 (a) values (1)|
|
||
ERROR 0A000: Not allowed to return a result set from a trigger
|
||
drop procedure p1|
|
||
create procedure p1()
|
||
begin
|
||
create temporary table tmp select event_name from information_schema.events;
|
||
end|
|
||
expected to work, since we redirect the output into a tmp table
|
||
insert into t1 (a) values (1)|
|
||
select * from tmp|
|
||
event_name
|
||
e1
|
||
drop temporary table tmp|
|
||
drop procedure p1|
|
||
create procedure p1()
|
||
begin
|
||
alter event e1 rename to e2;
|
||
end|
|
||
insert into t1 (a) values (1)|
|
||
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
|
||
drop procedure p1|
|
||
create procedure p1()
|
||
begin
|
||
drop event e1;
|
||
end|
|
||
insert into t1 (a) values (1)|
|
||
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
|
||
drop table t1|
|
||
drop event e1|
|
||
set names utf8;
|
||
create event имя_события_в_кодировке_утф8_длиной_больше_чем_48 on schedule every 2 year do select 1;
|
||
select EVENT_NAME from information_schema.events
|
||
where event_schema='test';
|
||
EVENT_NAME
|
||
drop event имя_события_в_кодировке_утф8_длиной_больше_чем_48;
|
||
create event
|
||
очень_очень_очень_очень_очень_очень_очень_очень_длинная_строка_66
|
||
on schedule every 2 year do select 1;
|
||
ERROR 42000: Identifier name 'очень_очень_очень_очень_очень_очень_очень_очень_длинна' is too long
|
||
create event event_35981 on schedule every 6 month on completion preserve
|
||
disable
|
||
do
|
||
select 1;
|
||
The following SELECTs should all give 1
|
||
select count(*) from information_schema.events
|
||
where event_schema = database() and event_name = 'event_35981' and
|
||
on_completion = 'PRESERVE';
|
||
count(*)
|
||
1
|
||
alter event event_35981 enable;
|
||
select count(*) from information_schema.events
|
||
where event_schema = database() and event_name = 'event_35981' and
|
||
on_completion = 'PRESERVE';
|
||
count(*)
|
||
1
|
||
alter event event_35981 on completion not preserve;
|
||
select count(*) from information_schema.events
|
||
where event_schema = database() and event_name = 'event_35981' and
|
||
on_completion = 'NOT PRESERVE';
|
||
count(*)
|
||
1
|
||
alter event event_35981 disable;
|
||
select count(*) from information_schema.events
|
||
where event_schema = database() and event_name = 'event_35981' and
|
||
on_completion = 'NOT PRESERVE';
|
||
count(*)
|
||
1
|
||
alter event event_35981 on completion preserve;
|
||
select count(*) from information_schema.events
|
||
where event_schema = database() and event_name = 'event_35981' and
|
||
on_completion = 'PRESERVE';
|
||
count(*)
|
||
1
|
||
drop event event_35981;
|
||
create event event_35981 on schedule every 6 month disable
|
||
do
|
||
select 1;
|
||
select count(*) from information_schema.events
|
||
where event_schema = database() and event_name = 'event_35981' and
|
||
on_completion = 'NOT PRESERVE';
|
||
count(*)
|
||
1
|
||
drop event event_35981;
|
||
create event event_35981 on schedule every 1 hour starts current_timestamp
|
||
on completion not preserve
|
||
do
|
||
select 1;
|
||
alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
|
||
ends '1999-01-02 00:00:00';
|
||
ERROR HY000: Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation.
|
||
drop event event_35981;
|
||
create event event_35981 on schedule every 1 hour starts current_timestamp
|
||
on completion not preserve
|
||
do
|
||
select 1;
|
||
alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
|
||
ends '1999-01-02 00:00:00' on completion preserve;
|
||
Warnings:
|
||
Note 1544 Event execution time is in the past. Event has been disabled
|
||
drop event event_35981;
|
||
create event event_35981 on schedule every 1 hour starts current_timestamp
|
||
on completion preserve
|
||
do
|
||
select 1;
|
||
alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
|
||
ends '1999-01-02 00:00:00';
|
||
Warnings:
|
||
Note 1544 Event execution time is in the past. Event has been disabled
|
||
alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
|
||
ends '1999-01-02 00:00:00' on completion not preserve;
|
||
ERROR HY000: Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation.
|
||
alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
|
||
ends '1999-01-02 00:00:00' on completion preserve;
|
||
Warnings:
|
||
Note 1544 Event execution time is in the past. Event has been disabled
|
||
drop event event_35981;
|
||
drop database events_test;
|