Skip to content

Commit cc8aed3

Browse files
committed
MDEV 4427: query timeouts
Added MAX_STATEMENT_TIME user variable to automaticly kill queries after a given time limit has expired. - Added timer functions based on pthread_cond_timedwait - Added kill_handlerton() to signal storage engines about kill/timeout - Added support for GRANT ... MAX_STATEMENT_TIME=# - Copy max_statement_time to current user, if stored in mysql.user - Added status variable max_statement_time_exceeded - Added KILL_TIMEOUT - Removed digest hash from performance schema tests as they change all the time. - Updated test results that changed because of the new user variables or new fields in mysql.user This functionallity is inspired by work done by Davi Arnaut at twitter. Test case is copied from Davi's work. Documentation can be found at https://kb.askmonty.org/en/how-to-limittimeout-queries/ mysql-test/r/mysqld--help.result: Updated for new help message mysql-test/suite/perfschema/r/all_instances.result: Added new mutex mysql-test/suite/sys_vars/r/max_statement_time_basic.result: Added testing of max_statement_time mysql-test/suite/sys_vars/t/max_statement_time_basic.test: Added testing of max_statement_time mysql-test/t/max_statement_time.test: Added testing of max_statement_time mysys/CMakeLists.txt: Added thr_timer mysys/my_init.c: mysys/mysys_priv.h: Added new mutex and condition variables Added new mutex and condition variables mysys/thr_timer.c: Added timer functions based on pthread_cond_timedwait() This can be compiled with HAVE_TIMER_CREATE to benchmark agains timer_create()/timer_settime() sql/lex.h: Added MAX_STATEMENT_TIME sql/log_event.cc: Safety fix (timeout should be threated as an interrupted query) sql/mysqld.cc: Added support for timers Added status variable max_statement_time_exceeded sql/share/errmsg-utf8.txt: Added ER_QUERY_TIMEOUT sql/signal_handler.cc: Added support for KILL_TIMEOUT sql/sql_acl.cc: Added support for GRANT ... MAX_STATEMENT_TIME=# Copy max_statement_time to current user sql/sql_class.cc: Added timer functionality to THD. Added thd_kill_timeout() sql/sql_class.h: Added timer functionality to THD. Added KILL_TIMEOUT Added max_statement_time variable in similar manner as long_query_time was done. sql/sql_connect.cc: Added handling of max_statement_time_exceeded sql/sql_parse.cc: Added starting and stopping timers for queries. sql/sql_show.cc: Added max_statement_time_exceeded for user/connects status in MariaDB 10.0 sql/sql_yacc.yy: Added support for GRANT ... MAX_STATEMENT_TIME=# syntax, to be enabled in 10.0 sql/structs.h: Added max_statement_time user resource sql/sys_vars.cc: Added max_statement_time variables mysql-test/suite/roles/create_and_drop_role_invalid_user_table.test Removed test as we require all fields in mysql.user table. scripts/mysql_system_tables.sql scripts/mysql_system_tables_data.sql scripts/mysql_system_tables_fix.sql Updated mysql.user with new max_statement_time field
1 parent 1a7d173 commit cc8aed3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1780
-255
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ mysql-test/mtr
7575
mysql-test/mysql-test-run
7676
mysql-test/var/
7777
mysys/thr_lock
78+
mysys/thr_timer
7879
packaging/rpm-oel/mysql.spec
7980
packaging/rpm-uln/mysql.10.0.11.spec
8081
packaging/solaris/postinstall-solaris

include/thr_timer.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/* Copyright (c) 2012 Monty Program Ab
2+
3+
This program is free software; you can redistribute it and/or modify
4+
it under the terms of the GNU General Public License as published by
5+
the Free Software Foundation; version 2 or later of the License.
6+
7+
This program is distributed in the hope that it will be useful,
8+
but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
GNU General Public License for more details.
11+
12+
You should have received a copy of the GNU General Public License
13+
along with this program; if not, write to the Free Software
14+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15+
16+
/* Prototypes when using thr_timer functions */
17+
18+
#ifndef _thr_timer_h
19+
#define _thr_timer_h
20+
#ifdef __cplusplus
21+
extern "C" {
22+
#endif
23+
24+
typedef struct st_timer {
25+
struct timespec expire_time;
26+
my_bool expired;
27+
uint index_in_queue;
28+
void (*func)(void*);
29+
void *func_arg;
30+
} thr_timer_t;
31+
32+
/* Main functions for library */
33+
my_bool init_thr_timer(uint init_size_for_timer_queue);
34+
void end_thr_timer();
35+
36+
/* Functions for handling one timer */
37+
void thr_timer_init(thr_timer_t *timer_data, void(*function)(void*),
38+
void *arg);
39+
my_bool thr_timer_settime(thr_timer_t *timer_data, ulonglong microseconds);
40+
void thr_timer_end(thr_timer_t *timer_data);
41+
42+
#ifdef __cplusplus
43+
}
44+
#endif /* __cplusplus */
45+
#endif /* _thr_timer_h */

mysql-test/r/grant.result

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ authentication_string
5858
password_expired N
5959
is_role N
6060
default_role
61+
max_statement_time 0.000000
6162
show grants for mysqltest_1@localhost;
6263
Grants for mysqltest_1@localhost
6364
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA'
@@ -85,7 +86,7 @@ delete from mysql.user where user='mysqltest_1';
8586
flush privileges;
8687
delete from mysql.user where user='mysqltest_1';
8788
flush privileges;
88-
grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 10;
89+
grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 10 max_statement_time 60;
8990
select * from mysql.user where user="mysqltest_1";
9091
Host localhost
9192
User mysqltest_1
@@ -132,10 +133,11 @@ authentication_string
132133
password_expired N
133134
is_role N
134135
default_role
136+
max_statement_time 60.000000
135137
show grants for mysqltest_1@localhost;
136138
Grants for mysqltest_1@localhost
137-
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10
138-
grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 20 max_connections_per_hour 30;
139+
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_STATEMENT_TIME 60.000000
140+
grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 20 max_connections_per_hour 30 max_statement_time 0;
139141
select * from mysql.user where user="mysqltest_1";
140142
Host localhost
141143
User mysqltest_1
@@ -182,6 +184,7 @@ authentication_string
182184
password_expired N
183185
is_role N
184186
default_role
187+
max_statement_time 0.000000
185188
show grants for mysqltest_1@localhost;
186189
Grants for mysqltest_1@localhost
187190
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
2+
# Test the MAX_STATEMENT_TIME option.
3+
4+
SET @@MAX_STATEMENT_TIME=2;
5+
select @@max_statement_time;
6+
@@max_statement_time
7+
2.000000
8+
SELECT SLEEP(1);
9+
SLEEP(1)
10+
0
11+
SELECT SLEEP(3);
12+
SLEEP(3)
13+
1
14+
SET @@MAX_STATEMENT_TIME=0;
15+
SELECT SLEEP(1);
16+
SLEEP(1)
17+
0
18+
SHOW STATUS LIKE "max_statement_time_exceeded";
19+
Variable_name Value
20+
Max_statement_time_exceeded 1
21+
CREATE TABLE t1 (a INT, b VARCHAR(300)) engine=myisam;
22+
INSERT INTO t1 VALUES (1, 'string');
23+
SELECT 0;
24+
0
25+
0
26+
27+
# Test the MAX_STATEMENT_TIME option with SF (should have no effect).
28+
29+
CREATE PROCEDURE p1()
30+
BEGIN
31+
declare tmp int;
32+
SET @@MAX_STATEMENT_TIME=0.0001;
33+
SELECT COUNT(*) INTO tmp FROM t1 WHERE b LIKE '%z%';
34+
SET @@MAX_STATEMENT_TIME=0;
35+
END|
36+
CREATE PROCEDURE p2()
37+
BEGIN
38+
SET @@MAX_STATEMENT_TIME=5;
39+
END|
40+
SELECT @@MAX_STATEMENT_TIME;
41+
@@MAX_STATEMENT_TIME
42+
0.000000
43+
CALL p1();
44+
CALL p2();
45+
SELECT @@MAX_STATEMENT_TIME;
46+
@@MAX_STATEMENT_TIME
47+
5.000000
48+
SET @@MAX_STATEMENT_TIME=0;
49+
DROP PROCEDURE p1;
50+
DROP PROCEDURE p2;
51+
DROP TABLE t1;
52+
53+
# MAX_STATEMENT_TIME account resource
54+
55+
GRANT USAGE ON *.* TO user1@localhost WITH MAX_STATEMENT_TIME 1.005;
56+
# con1
57+
SELECT @@max_statement_time;
58+
@@max_statement_time
59+
1.005000
60+
# restart and reconnect
61+
set @global.userstat=1;
62+
SELECT @@global.max_statement_time,@@session.max_statement_time;
63+
@@global.max_statement_time @@session.max_statement_time
64+
0.000000 1.005000
65+
select sleep(100);
66+
sleep(100)
67+
1
68+
SHOW STATUS LIKE "max_statement_time_exceeded";
69+
Variable_name Value
70+
Max_statement_time_exceeded 1
71+
show grants for user1@localhost;
72+
Grants for user1@localhost
73+
GRANT USAGE ON *.* TO 'user1'@'localhost' WITH MAX_STATEMENT_TIME 1.005000
74+
set @global.userstat=0;
75+
DROP USER user1@localhost;
76+
77+
# MAX_STATEMENT_TIME status variables.
78+
79+
flush status;
80+
SET @@max_statement_time=0;
81+
SELECT CONVERT(VARIABLE_VALUE, UNSIGNED) INTO @time_exceeded
82+
FROM INFORMATION_SCHEMA.GLOBAL_STATUS
83+
WHERE VARIABLE_NAME = 'max_statement_time_exceeded';
84+
SET @@max_statement_time=0.5;
85+
SELECT SLEEP(2);
86+
SLEEP(2)
87+
1
88+
SHOW STATUS LIKE '%timeout%';
89+
Variable_name Value
90+
Ssl_default_timeout 0
91+
Ssl_session_cache_timeouts 0
92+
SET @@max_statement_time=0;
93+
# Ensure that the counters for:
94+
# - statements that exceeded their maximum execution time
95+
# are incremented.
96+
SELECT 1 AS STATUS FROM INFORMATION_SCHEMA.GLOBAL_STATUS
97+
WHERE VARIABLE_NAME = 'max_statement_time_exceeded'
98+
AND CONVERT(VARIABLE_VALUE, UNSIGNED) > @time_exceeded;
99+
STATUS
100+
1
101+
102+
# Check that the appropriate error status is set.
103+
104+
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
105+
INSERT INTO t1 VALUES (1);
106+
START TRANSACTION;
107+
SELECT * FROM t1 FOR UPDATE;
108+
a
109+
1
110+
SET @@SESSION.max_statement_time = 0.5;
111+
UPDATE t1 SET a = 2;
112+
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
113+
SHOW WARNINGS;
114+
Level Code Message
115+
Error 1967 Query execution was interrupted (max_statement_time exceeded)
116+
ROLLBACK;
117+
DROP TABLE t1;
118+
119+
# Test interaction with lock waits.
120+
121+
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
122+
INSERT INTO t1 VALUES (1);
123+
SET @@SESSION.max_statement_time= 0.5;
124+
LOCK TABLES t1 WRITE;
125+
SELECT @@SESSION.max_statement_time;
126+
@@SESSION.max_statement_time
127+
0.500000
128+
LOCK TABLES t1 READ;
129+
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
130+
UNLOCK TABLES;
131+
BEGIN;
132+
SELECT * FROM t1;
133+
a
134+
1
135+
ALTER TABLE t1 ADD COLUMN b INT;
136+
ERROR 70100: Query execution was interrupted (max_statement_time exceeded)
137+
ROLLBACK;
138+
SELECT GET_LOCK('lock', 1);
139+
GET_LOCK('lock', 1)
140+
1
141+
SELECT GET_LOCK('lock', 1);
142+
GET_LOCK('lock', 1)
143+
NULL
144+
SELECT RELEASE_LOCK('lock');
145+
RELEASE_LOCK('lock')
146+
1
147+
DROP TABLE t1;

mysql-test/r/mysqld--help.result

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,11 @@ The following options may be given as the first argument:
422422
value are used; the rest are ignored)
423423
--max-sp-recursion-depth[=#]
424424
Maximum stored procedure recursion depth
425+
--max-statement-time=#
426+
A SELECT query that have taken more than
427+
max_statement_time seconds will be aborted. The argument
428+
will be treated as a decimal value with microsecond
429+
precision. A value of 0 (default) means no timeout
425430
--max-tmp-tables=# Maximum number of temporary tables a client can keep open
426431
at a time
427432
--max-user-connections=#
@@ -1196,6 +1201,7 @@ max-relay-log-size 1073741824
11961201
max-seeks-for-key 18446744073709551615
11971202
max-sort-length 1024
11981203
max-sp-recursion-depth 0
1204+
max-statement-time 0
11991205
max-tmp-tables 32
12001206
max-user-connections 0
12011207
max-write-lock-count 18446744073709551615

mysql-test/r/ps.result

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,13 +1202,13 @@ SET @aux= "SELECT COUNT(*)
12021202
prepare my_stmt from @aux;
12031203
execute my_stmt;
12041204
COUNT(*)
1205-
45
1205+
46
12061206
execute my_stmt;
12071207
COUNT(*)
1208-
45
1208+
46
12091209
execute my_stmt;
12101210
COUNT(*)
1211-
45
1211+
46
12121212
deallocate prepare my_stmt;
12131213
drop procedure if exists p1|
12141214
drop table if exists t1|

mysql-test/r/status_user.result

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ DENIED_CONNECTIONS bigint(21) NO 0
2525
LOST_CONNECTIONS bigint(21) NO 0
2626
ACCESS_DENIED bigint(21) NO 0
2727
EMPTY_QUERIES bigint(21) NO 0
28+
MAX_STATEMENT_TIME_EXCEEDED bigint(21) NO 0
2829
show columns from information_schema.user_statistics;
2930
Field Type Null Key Default Extra
3031
USER varchar(128) NO
@@ -50,6 +51,7 @@ DENIED_CONNECTIONS bigint(21) NO 0
5051
LOST_CONNECTIONS bigint(21) NO 0
5152
ACCESS_DENIED bigint(21) NO 0
5253
EMPTY_QUERIES bigint(21) NO 0
54+
MAX_STATEMENT_TIME_EXCEEDED bigint(21) NO 0
5355
show columns from information_schema.index_statistics;
5456
Field Type Null Key Default Extra
5557
TABLE_SCHEMA varchar(192) NO

mysql-test/r/system_mysql_db.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ user CREATE TABLE `user` (
131131
`password_expired` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
132132
`is_role` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
133133
`default_role` char(80) COLLATE utf8_bin NOT NULL DEFAULT '',
134+
`max_statement_time` decimal(12,6) NOT NULL DEFAULT '0.000000',
134135
PRIMARY KEY (`Host`,`User`)
135136
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges'
136137
show create table func;

mysql-test/r/system_mysql_db_fix40123.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ user CREATE TABLE `user` (
131131
`password_expired` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
132132
`is_role` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
133133
`default_role` char(80) COLLATE utf8_bin NOT NULL DEFAULT '',
134+
`max_statement_time` decimal(12,6) NOT NULL DEFAULT '0.000000',
134135
PRIMARY KEY (`Host`,`User`)
135136
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges'
136137
show create table func;

mysql-test/r/system_mysql_db_fix50030.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ user CREATE TABLE `user` (
131131
`password_expired` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
132132
`is_role` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
133133
`default_role` char(80) COLLATE utf8_bin NOT NULL DEFAULT '',
134+
`max_statement_time` decimal(12,6) NOT NULL DEFAULT '0.000000',
134135
PRIMARY KEY (`Host`,`User`)
135136
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges'
136137
show create table func;

0 commit comments

Comments
 (0)