Merge lp:~vlad-lesin/percona-server/5.6-sql_timeout_twitter into lp:percona-server/5.6

Proposed by Vlad Lesin on 2013-02-06
Status: Merged
Approved by: Alexey Kopytov on 2013-09-21
Approved revision: 426
Merged at revision: 428
Proposed branch: lp:~vlad-lesin/percona-server/5.6-sql_timeout_twitter
Merge into: lp:percona-server/5.6
Diff against target: 2612 lines (+1997/-29)
40 files modified
Percona-Server/config.h.cmake (+4/-0)
Percona-Server/configure.cmake (+19/-1)
Percona-Server/include/my_global.h (+13/-0)
Percona-Server/include/my_timer.h (+69/-0)
Percona-Server/include/mysql/plugin.h (+7/-0)
Percona-Server/include/mysql/plugin_audit.h.pp (+1/-0)
Percona-Server/include/mysql/plugin_auth.h.pp (+1/-0)
Percona-Server/include/mysql/plugin_ftparser.h.pp (+1/-0)
Percona-Server/include/mysql/thread_pool_priv.h (+6/-0)
Percona-Server/libmysqld/CMakeLists.txt (+3/-0)
Percona-Server/mysql-test/include/have_statement_timeout.inc (+4/-0)
Percona-Server/mysql-test/r/have_statement_timeout.require (+2/-0)
Percona-Server/mysql-test/r/max_statement_time_func.result (+116/-0)
Percona-Server/mysql-test/r/mysqld--help-notwin.result (+4/-0)
Percona-Server/mysql-test/r/mysqld--help-win.result (+4/-0)
Percona-Server/mysql-test/suite/sys_vars/r/have_statement_timeout_basic.result (+53/-0)
Percona-Server/mysql-test/suite/sys_vars/r/max_statement_time_basic.result (+89/-0)
Percona-Server/mysql-test/suite/sys_vars/t/have_statement_timeout_basic.test (+55/-0)
Percona-Server/mysql-test/suite/sys_vars/t/max_statement_time_basic.test (+78/-0)
Percona-Server/mysql-test/t/max_statement_time_func.test (+154/-0)
Percona-Server/mysys/CMakeLists.txt (+8/-0)
Percona-Server/mysys/kqueue_timers.c (+219/-0)
Percona-Server/mysys/posix_timers.c (+256/-0)
Percona-Server/sql/CMakeLists.txt (+4/-0)
Percona-Server/sql/handler.cc (+18/-0)
Percona-Server/sql/handler.h (+4/-0)
Percona-Server/sql/mysqld.cc (+22/-0)
Percona-Server/sql/set_var.h (+1/-0)
Percona-Server/sql/share/errmsg-utf8.txt (+3/-0)
Percona-Server/sql/signal_handler.cc (+3/-0)
Percona-Server/sql/sql_class.cc (+39/-15)
Percona-Server/sql/sql_class.h (+13/-0)
Percona-Server/sql/sql_parse.cc (+89/-1)
Percona-Server/sql/sql_timer.cc (+253/-0)
Percona-Server/sql/sql_timer.h (+50/-0)
Percona-Server/sql/sys_vars.cc (+10/-0)
Percona-Server/storage/innobase/handler/ha_innodb.cc (+49/-3)
Percona-Server/storage/innobase/include/lock0lock.h (+10/-0)
Percona-Server/storage/innobase/include/lock0priv.h (+0/-9)
Percona-Server/unittest/mysys/my_timer-t.c (+263/-0)
To merge this branch: bzr merge lp:~vlad-lesin/percona-server/5.6-sql_timeout_twitter
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve on 2013-09-21
Sergei Glushchenko (community) g2 2013-02-06 Needs Fixing on 2013-02-11
Review via email: mp+146919@code.launchpad.net
To post a comment you must log in.

Vlad,

I see you encountered same issue as I did also. performance_schema *digest* tables are rely heavily on sql_yacc.yy grammar. So if someone just add new token (or even rule?) many of statement's digests will change.

I very dislike it as
1. There is a need to almost completely rewrite several *.result in perfscehma suite
2. There is no way to merge for example this branch and lp:~sergei.glushchenko/percona-server/ps56-univ-log-archive as both touch sql_yacc.yy. As resulting MD5 hashes will depend on changes made in both branches. The only possible way is once one of the branges been merged, update another one and recalculate digests in test cases.

Do you have any thoughts on how to workaround this?

Thanks,
Sergei

Vlad,
Some minor comments:

lines 2279-2280 redundant change
likewise 2585
likewise 3023

in have_statement_timeout_basic.test
it has been said that error 'Readonly variable' is expected but what really
is expected is the 'Unknown column 'have_statement_timeout' in 'field list''
error and it is raised as well.

review: Needs Fixing (g2)
Vlad Lesin (vlad-lesin) wrote :

> I see you encountered same issue as I did also. performance_schema *digest*
> tables are rely heavily on sql_yacc.yy grammar. So if someone just add new
> token (or even rule?) many of statement's digests will change.
...
> Do you have any thoughts on how to workaround this?

Digest calculation is based on token IDs. So every time we add new token in the middle of tokens list we just shift token IDs that are after just inserted token. So I see two variants how to avoid that. The first is add new tokens at the end of the list. The second - calculate digest using text representation of query instead of set of tokens.

First option obviously wouldn't work because there are additional PFS-specific tokens which are generated automatically (in gen_pfs_lex_token.cc) with IDs starting from max last token seen.

Maybe it isn't that bad to update test cases with new digests. I just wondering why that method of digest calculation has been chosen. Probably nobody should refer to digests in their scripts/applications/etc, and they are needed only for internal purposes.

Vlad Lesin (vlad-lesin) wrote :

> Vlad,
> Some minor comments:
>
> lines 2279-2280 redundant change
> likewise 2585
> likewise 3023
>
> in have_statement_timeout_basic.test
> it has been said that error 'Readonly variable' is expected but what really
> is expected is the 'Unknown column 'have_statement_timeout' in 'field list''
> error and it is raised as well.

Fixed.

Vlad Lesin (vlad-lesin) wrote :

> Maybe it isn't that bad to update test cases with new digests. I just
> wondering why that method of digest calculation has been chosen. Probably
> nobody should refer to digests in their scripts/applications/etc, and they are
> needed only for internal purposes.

It can lead to issues during merging. If several people make MP with updated tests merge captain should update that test results manually. But I think we can do nothing with it. We can't make rules for test scripts as we work with upstream code.

Alexey Kopytov (akopytov) wrote :

Vlad,

  - do we really need the following change?

-#if !defined(__cplusplus) && !defined(bool)
-#define bool In_C_you_should_use_my_bool_instead()
-#endif
+#include <stdbool.h>

    The intention was to allow using C99 'bool' in C code (and break
    Windows compatibility), but I don't see any occurrences of such
    usage?

  - my_os_timer_* to avoid name clash with existing my_timer_init()

  - I'm having second thoughts on per-user MAX_STATEMENT_TIME limit
    after reviewing the code. It feels like it's going to be a pain to
    support and maintain. Let's remove it? It's a "nice to have" thing, but
    it was not a requirement for us originally, and would also
    unproportionally complicate migrations to/from upstream MySQL.

  - was there any specific reason to implement your own set of
    regression tests instead of porting them from the Twitter tree? Most
    of their tests use the SELECT hint that we chose not to implement,
    but those could be converted to SET ...; SELECT ... form.

  - include my_global.h and use DBUG_ASSERT() instead of assert()? Also
    don't include assert.h, errno.h and string.h?

  - unnecessary change:

@@ -4254,6 +4284,7 @@ static int replace_column_table(GRANT_TA
         goto end;
       }
     }
+
   }

   /*

  - remnant from SELECT hints implementation that is also unnecessary:

--- Percona-Server/sql/sql_lex.h 2013-06-27 15:15:35 +0000
+++ Percona-Server/sql/sql_lex.h 2013-08-06 11:40:36 +0000
@@ -2533,6 +2533,9 @@ struct LEX: public Query_tables_list

   class Explain_format *explain_format;

+ /** Maximum execution time for a statement. */
+ ulong max_statement_time;
+
   LEX();

   virtual ~LEX()

  - I would restructure get_max_statement_time() / set_statement_timer()
    a bit for performance reasons. We should first check if we do have
    some timeout defined (i.e. thd->variables.max_statement_time > 0)
    and then check other conditions. So that we do as less work as
    possible when timeouts are not used. likely()/unlikely() and
    explicit "inline" hints can also make a big difference.

  - can you explain changed in ha_innodb.cc? It looks like fixing a
    problem in the wrong place, i.e. implementing a workaround of
    thread_pool_priv.h defining MYSQL_SERVER unconditionally.

  - innobase_kill_connection() needs comments

review: Needs Fixing
Vlad Lesin (vlad-lesin) wrote :
Download full text (3.2 KiB)

> Vlad,
>
> - do we really need the following change?
>
> -#if !defined(__cplusplus) && !defined(bool)
> -#define bool In_C_you_should_use_my_bool_instead()
> -#endif
> +#include <stdbool.h>
>
> The intention was to allow using C99 'bool' in C code (and break
> Windows compatibility), but I don't see any occurrences of such
> usage?
>
Removed.

> - my_os_timer_* to avoid name clash with existing my_timer_init()
>
Done.

> - I'm having second thoughts on per-user MAX_STATEMENT_TIME limit
> after reviewing the code. It feels like it's going to be a pain to
> support and maintain. Let's remove it? It's a "nice to have" thing, but
> it was not a requirement for us originally, and would also
> unproportionally complicate migrations to/from upstream MySQL.
>
Removed.

> - was there any specific reason to implement your own set of
> regression tests instead of porting them from the Twitter tree? Most
> of their tests use the SELECT hint that we chose not to implement,
> but those could be converted to SET ...; SELECT ... form.
All tests are ported from Twitter tree except these two:
mysql-test/suite/randgen/t/max_statement_time.test
mysql-test/t/max_statement_time.test

The first one is not ported because I did not find randgen grammar files for the test
in the tree. The second one repeats the mysql-test/t/max_statement_time_func.test test
but uses statement timeout set instead of set with variable.

>
> - include my_global.h and use DBUG_ASSERT() instead of assert()? Also
> don't include assert.h, errno.h and string.h?
As we do not support BSD-based platforms and do not test code for such platforms with our
regression tests system the BSD-based platform specific files are kept as is.

> - unnecessary change:
>
> @@ -4254,6 +4284,7 @@ static int replace_column_table(GRANT_TA
> goto end;
> }
> }
> +
> }
>
> /*
>
> - remnant from SELECT hints implementation that is also unnecessary:
>
> --- Percona-Server/sql/sql_lex.h 2013-06-27 15:15:35 +0000
> +++ Percona-Server/sql/sql_lex.h 2013-08-06 11:40:36 +0000
> @@ -2533,6 +2533,9 @@ struct LEX: public Query_tables_list
>
> class Explain_format *explain_format;
>
> + /** Maximum execution time for a statement. */
> + ulong max_statement_time;
> +
> LEX();
>
> virtual ~LEX()
>
As per-user MAX_STATEMENT_TIME limit code is removed the above changes are removed too.

> - I would restructure get_max_statement_time() / set_statement_timer()
> a bit for performance reasons. We should first check if we do have
> some timeout defined (i.e. thd->variables.max_statement_time > 0)
> and then check other conditions. So that we do as less work as
> possible when timeouts are not used. likely()/unlikely() and
> explicit "inline" hints can also make a big difference.
>
Done.

> - can you explain changed in ha_innodb.cc? It looks like fixing a
> problem in the wrong place, i.e. implementing a workaround of
> thread_pool_priv.h defining MYSQL_SERVER unconditionally.
Made conditional #define in thread_pool_priv.h

> - innobase_kill_connection() needs comments
Done.

h...

Read more...

Alexey Kopytov (akopytov) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Percona-Server/config.h.cmake'
2--- Percona-Server/config.h.cmake 2013-06-20 15:16:00 +0000
3+++ Percona-Server/config.h.cmake 2013-09-09 15:30:42 +0000
4@@ -306,6 +306,10 @@
5 #cmakedefine STRUCT_DIRENT_HAS_D_NAMLEN 1
6 #cmakedefine SPRINTF_RETURNS_INT 1
7
8+#cmakedefine HAVE_POSIX_TIMERS 1
9+#cmakedefine HAVE_KQUEUE_TIMERS 1
10+#cmakedefine HAVE_MY_TIMER 1
11+
12 #cmakedefine DNS_USE_CPU_CLOCK_FOR_ID 1
13 #cmakedefine HAVE_EPOLL 1
14 #cmakedefine HAVE_EPOLL_CTL 1
15
16=== modified file 'Percona-Server/configure.cmake'
17--- Percona-Server/configure.cmake 2013-08-14 03:57:21 +0000
18+++ Percona-Server/configure.cmake 2013-09-09 15:30:42 +0000
19@@ -197,6 +197,7 @@
20 IF(NOT LIBRT)
21 MY_SEARCH_LIBS(clock_gettime rt LIBRT)
22 ENDIF()
23+ MY_SEARCH_LIBS(timer_create rt LIBRT)
24 FIND_PACKAGE(Threads)
25
26 SET(CMAKE_REQUIRED_LIBRARIES
27@@ -523,6 +524,10 @@
28 CHECK_FUNCTION_EXISTS (nl_langinfo HAVE_NL_LANGINFO)
29 CHECK_FUNCTION_EXISTS (ntohll HAVE_HTONLL)
30
31+CHECK_FUNCTION_EXISTS (timer_create HAVE_TIMER_CREATE)
32+CHECK_FUNCTION_EXISTS (timer_settime HAVE_TIMER_SETTIME)
33+CHECK_FUNCTION_EXISTS (kqueue HAVE_KQUEUE)
34+
35 CHECK_FUNCTION_EXISTS (clock_gettime DNS_USE_CPU_CLOCK_FOR_ID)
36 CHECK_FUNCTION_EXISTS (epoll_create HAVE_EPOLL)
37 CHECK_FUNCTION_EXISTS (epoll_ctl HAVE_EPOLL_CTL)
38@@ -579,6 +584,8 @@
39 CHECK_SYMBOL_EXISTS(TIOCSTAT "sys/ioctl.h" TIOCSTAT_IN_SYS_IOCTL)
40 CHECK_SYMBOL_EXISTS(FIONREAD "sys/filio.h" FIONREAD_IN_SYS_FILIO)
41 CHECK_SYMBOL_EXISTS(gettimeofday "sys/time.h" HAVE_GETTIMEOFDAY)
42+CHECK_SYMBOL_EXISTS(SIGEV_THREAD_ID "signal.h;time.h" HAVE_SIGEV_THREAD_ID)
43+CHECK_SYMBOL_EXISTS(EVFILT_TIMER "sys/types.h;sys/event.h;sys/time.h" HAVE_EVFILT_TIMER)
44
45 CHECK_SYMBOL_EXISTS(finite "math.h" HAVE_FINITE_IN_MATH_H)
46 IF(HAVE_FINITE_IN_MATH_H)
47@@ -607,7 +614,18 @@
48 return 0;
49 }" HAVE_FESETROUND)
50
51-
52+# Check for the Linux-specific POSIX timers API.
53+IF(HAVE_TIMER_CREATE AND HAVE_TIMER_SETTIME AND HAVE_SIGEV_THREAD_ID)
54+ SET(HAVE_POSIX_TIMERS 1 CACHE INTERNAL "Have POSIX timer-related functions")
55+ENDIF()
56+
57+IF(HAVE_KQUEUE AND HAVE_EVFILT_TIMER)
58+ SET(HAVE_KQUEUE_TIMERS 1 CACHE INTERNAL "Have kqueue timer-related filter")
59+ENDIF()
60+
61+IF(HAVE_POSIX_TIMERS OR HAVE_KQUEUE_TIMERS)
62+ SET(HAVE_MY_TIMER 1 CACHE INTERNAL "Have mysys timer-related functions")
63+ENDIF()
64
65 #
66 # Test for endianess
67
68=== modified file 'Percona-Server/include/my_global.h'
69--- Percona-Server/include/my_global.h 2013-06-26 14:15:01 +0000
70+++ Percona-Server/include/my_global.h 2013-09-09 15:30:42 +0000
71@@ -363,6 +363,19 @@
72 #include <crypt.h>
73 #endif
74
75+/**
76+ Cast a member of a structure to the structure that contains it.
77+
78+ @param ptr Pointer to the member.
79+ @param type Type of the structure that contains the member.
80+ @param member Name of the member within the structure.
81+*/
82+#define my_container_of(ptr, type, member) \
83+ ({ \
84+ const typeof(((type *)0)->member) *__mptr= (ptr); \
85+ (type *)((char *)__mptr - offsetof(type, member)); \
86+ })
87+
88 /*
89 A lot of our programs uses asserts, so better to always include it
90 This also fixes a problem when people uses DBUG_ASSERT without including
91
92=== added file 'Percona-Server/include/my_timer.h'
93--- Percona-Server/include/my_timer.h 1970-01-01 00:00:00 +0000
94+++ Percona-Server/include/my_timer.h 2013-09-09 15:30:42 +0000
95@@ -0,0 +1,69 @@
96+/* Copyright (c) 2012, Twitter, Inc. All rights reserved.
97+
98+ This program is free software; you can redistribute it and/or modify
99+ it under the terms of the GNU General Public License as published by
100+ the Free Software Foundation; version 2 of the License.
101+
102+ This program is distributed in the hope that it will be useful,
103+ but WITHOUT ANY WARRANTY; without even the implied warranty of
104+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
105+ GNU General Public License for more details.
106+
107+ You should have received a copy of the GNU General Public License along
108+ with this program; if not, write to the Free Software Foundation, Inc.,
109+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
110+
111+#ifndef MY_TIMER_H
112+#define MY_TIMER_H
113+
114+#include "my_global.h" /* C_MODE_START, C_MODE_END */
115+#include "my_config.h" /* HAVE_*_TIMERS */
116+
117+/* POSIX timers API. */
118+#ifdef HAVE_POSIX_TIMERS
119+# include <time.h> /* timer_t */
120+ typedef timer_t os_timer_t;
121+#elif HAVE_KQUEUE_TIMERS
122+# include <sys/types.h> /* uintptr_t */
123+ typedef uintptr_t os_timer_t;
124+#endif
125+
126+/* Whether timer API is implemented. */
127+#ifdef HAVE_MY_TIMER
128+
129+C_MODE_START
130+
131+typedef struct st_my_timer my_timer_t;
132+
133+/** Non-copyable timer object. */
134+struct st_my_timer
135+{
136+ /** Timer ID used to identify the timer in timer requests. */
137+ os_timer_t id;
138+
139+ /** Timer expiration notification function. */
140+ void (*notify_function)(my_timer_t *);
141+};
142+
143+/* Initialize internal components. */
144+int my_os_timer_init_ext(void);
145+
146+/* Release any resources acquired. */
147+void my_os_timer_deinit(void);
148+
149+/* Create a timer object. */
150+int my_os_timer_create(my_timer_t *timer);
151+
152+/* Set the time (in milliseconds) until the next expiration of the timer. */
153+int my_os_timer_set(my_timer_t *timer, unsigned long time);
154+
155+/* Reset the time until the next expiration of the timer. */
156+int my_os_timer_reset(my_timer_t *timer, int *state);
157+
158+/* Delete a timer object. */
159+void my_os_timer_delete(my_timer_t *timer);
160+
161+C_MODE_END
162+
163+#endif /* HAVE_MY_TIMER */
164+#endif /* MY_TIMER_H */
165
166=== modified file 'Percona-Server/include/mysql/plugin.h'
167--- Percona-Server/include/mysql/plugin.h 2013-08-06 15:16:34 +0000
168+++ Percona-Server/include/mysql/plugin.h 2013-09-09 15:30:42 +0000
169@@ -627,6 +627,13 @@
170 unsigned long long *pos_var);
171
172 /**
173+ Set the killed status of the current statement.
174+
175+ @param thd user thread connection handle
176+*/
177+void thd_set_kill_status(const MYSQL_THD thd);
178+
179+/**
180 Return the thread id of a user thread
181
182 @param thd user thread connection handle
183
184=== modified file 'Percona-Server/include/mysql/plugin_audit.h.pp'
185--- Percona-Server/include/mysql/plugin_audit.h.pp 2013-05-12 06:24:46 +0000
186+++ Percona-Server/include/mysql/plugin_audit.h.pp 2013-09-09 15:30:42 +0000
187@@ -249,6 +249,7 @@
188 void thd_binlog_pos(const void* thd,
189 const char **file_var,
190 unsigned long long *pos_var);
191+void thd_set_kill_status(const void* thd);
192 unsigned long thd_get_thread_id(const void* thd);
193 void thd_get_xid(const void* thd, MYSQL_XID *xid);
194 void mysql_query_cache_invalidate4(void* thd,
195
196=== modified file 'Percona-Server/include/mysql/plugin_auth.h.pp'
197--- Percona-Server/include/mysql/plugin_auth.h.pp 2013-05-12 06:24:46 +0000
198+++ Percona-Server/include/mysql/plugin_auth.h.pp 2013-09-09 15:30:42 +0000
199@@ -249,6 +249,7 @@
200 void thd_binlog_pos(const void* thd,
201 const char **file_var,
202 unsigned long long *pos_var);
203+void thd_set_kill_status(const void* thd);
204 unsigned long thd_get_thread_id(const void* thd);
205 void thd_get_xid(const void* thd, MYSQL_XID *xid);
206 void mysql_query_cache_invalidate4(void* thd,
207
208=== modified file 'Percona-Server/include/mysql/plugin_ftparser.h.pp'
209--- Percona-Server/include/mysql/plugin_ftparser.h.pp 2013-05-12 06:24:46 +0000
210+++ Percona-Server/include/mysql/plugin_ftparser.h.pp 2013-09-09 15:30:42 +0000
211@@ -202,6 +202,7 @@
212 void thd_binlog_pos(const void* thd,
213 const char **file_var,
214 unsigned long long *pos_var);
215+void thd_set_kill_status(const void* thd);
216 unsigned long thd_get_thread_id(const void* thd);
217 void thd_get_xid(const void* thd, MYSQL_XID *xid);
218 void mysql_query_cache_invalidate4(void* thd,
219
220=== modified file 'Percona-Server/include/mysql/thread_pool_priv.h'
221--- Percona-Server/include/mysql/thread_pool_priv.h 2013-05-12 06:24:46 +0000
222+++ Percona-Server/include/mysql/thread_pool_priv.h 2013-09-09 15:30:42 +0000
223@@ -30,7 +30,13 @@
224 to include sql_profile.h and table.h.
225 */
226 #include <mysqld_error.h> /* To get ER_ERROR_ON_READ */
227+/*
228+ MYSQL_SERVER can be defined before including this header, check it to avoid
229+ compilation error.
230+*/
231+#ifndef MYSQL_SERVER
232 #define MYSQL_SERVER 1
233+#endif //MYSQL_SERVER
234 #include <scheduler.h>
235 #include <debug_sync.h>
236 #include <sql_profile.h>
237
238=== modified file 'Percona-Server/libmysqld/CMakeLists.txt'
239--- Percona-Server/libmysqld/CMakeLists.txt 2012-10-16 06:21:51 +0000
240+++ Percona-Server/libmysqld/CMakeLists.txt 2013-09-09 15:30:42 +0000
241@@ -78,6 +78,9 @@
242 ${IMPORTED_SOURCES}
243 )
244
245+IF(HAVE_MY_TIMER)
246+ SET(SQL_EMBEDDED_SOURCES ${SQL_EMBEDDED_SOURCES} ../sql/sql_timer.cc)
247+ENDIF()
248
249 ADD_CONVENIENCE_LIBRARY(sql_embedded ${SQL_EMBEDDED_SOURCES})
250 DTRACE_INSTRUMENT(sql_embedded)
251
252=== added file 'Percona-Server/mysql-test/include/have_statement_timeout.inc'
253--- Percona-Server/mysql-test/include/have_statement_timeout.inc 1970-01-01 00:00:00 +0000
254+++ Percona-Server/mysql-test/include/have_statement_timeout.inc 2013-09-09 15:30:42 +0000
255@@ -0,0 +1,4 @@
256+-- require r/have_statement_timeout.require
257+disable_query_log;
258+show variables like 'have_statement_timeout';
259+enable_query_log;
260
261=== added file 'Percona-Server/mysql-test/r/have_statement_timeout.require'
262--- Percona-Server/mysql-test/r/have_statement_timeout.require 1970-01-01 00:00:00 +0000
263+++ Percona-Server/mysql-test/r/have_statement_timeout.require 2013-09-09 15:30:42 +0000
264@@ -0,0 +1,2 @@
265+Variable_name Value
266+have_statement_timeout YES
267
268=== added file 'Percona-Server/mysql-test/r/max_statement_time_func.result'
269--- Percona-Server/mysql-test/r/max_statement_time_func.result 1970-01-01 00:00:00 +0000
270+++ Percona-Server/mysql-test/r/max_statement_time_func.result 2013-09-09 15:30:42 +0000
271@@ -0,0 +1,116 @@
272+SET @old_session_max_statement_time = @@SESSION.max_statement_time;
273+#
274+# Test max statement time interruption.
275+# Note that if SLEEP() is interrupted, it returns 1.
276+#
277+SET @@SESSION.max_statement_time = 10;
278+SELECT SLEEP(1000);
279+SLEEP(1000)
280+1
281+SET @@SESSION.max_statement_time = 0;
282+#
283+# Apply timeout to the top-level statement.
284+#
285+CREATE PROCEDURE p1()
286+BEGIN
287+SELECT SLEEP(1000);
288+END|
289+SET @@SESSION.max_statement_time = 10;
290+CALL p1();
291+SLEEP(1000)
292+1
293+SET @@SESSION.max_statement_time = 0;
294+# Apply timeout to prepared statements.
295+PREPARE prep_1 FROM 'call p1()';
296+SET @@SESSION.max_statement_time = 10;
297+EXECUTE prep_1;
298+SLEEP(1000)
299+1
300+SET @@SESSION.max_statement_time = 0;
301+DROP PREPARE prep_1;
302+DROP PROCEDURE p1;
303+#
304+# Interrupt a statement that changes data.
305+#
306+CREATE TABLE t1 (a INT);
307+CREATE FUNCTION f1() RETURNS INT
308+BEGIN
309+WHILE true DO
310+INSERT INTO t1 VALUES (1);
311+END WHILE;
312+RETURN 1;
313+END|
314+SET @@SESSION.max_statement_time = 500;
315+SELECT f1();
316+ERROR 70101: Query execution was interrupted, max_statement_time exceeded
317+SET @@SESSION.max_statement_time = 0;
318+DROP FUNCTION f1;
319+DROP TABLE t1;
320+SELECT CONVERT(VARIABLE_VALUE, UNSIGNED) INTO @time_set
321+FROM INFORMATION_SCHEMA.GLOBAL_STATUS
322+WHERE VARIABLE_NAME = 'MAX_STATEMENT_TIME_SET';
323+SELECT CONVERT(VARIABLE_VALUE, UNSIGNED) INTO @time_exceeded
324+FROM INFORMATION_SCHEMA.GLOBAL_STATUS
325+WHERE VARIABLE_NAME = 'MAX_STATEMENT_TIME_EXCEEDED';
326+SET @@SESSION.max_statement_time = 100;
327+SELECT SLEEP(1000);
328+SLEEP(1000)
329+1
330+# Ensure that the counters for:
331+# - statements that are time limited; and
332+# - statements that exceeded their maximum execution time
333+# are incremented.
334+SELECT 1 AS STATUS FROM INFORMATION_SCHEMA.GLOBAL_STATUS
335+WHERE VARIABLE_NAME = 'MAX_STATEMENT_TIME_SET'
336+ AND CONVERT(VARIABLE_VALUE, UNSIGNED) > @time_set;
337+STATUS
338+SELECT 1 AS STATUS FROM INFORMATION_SCHEMA.GLOBAL_STATUS
339+WHERE VARIABLE_NAME = 'MAX_STATEMENT_TIME_EXCEEDED'
340+ AND CONVERT(VARIABLE_VALUE, UNSIGNED) > @time_exceeded;
341+STATUS
342+SET @@SESSION.max_statement_time = default;
343+
344+# Check that the appropriate error status is set.
345+
346+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
347+INSERT INTO t1 VALUES (1);
348+START TRANSACTION;
349+SELECT * FROM t1 FOR UPDATE;
350+a
351+1
352+SET @@SESSION.max_statement_time = 100;
353+UPDATE t1 SET a = 2;
354+ERROR 70101: Query execution was interrupted, max_statement_time exceeded
355+SHOW WARNINGS;
356+Level Code Message
357+Error 1877 Query execution was interrupted, max_statement_time exceeded
358+ROLLBACK;
359+DROP TABLE t1;
360+#
361+# Test interaction with lock waits.
362+#
363+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
364+INSERT INTO t1 VALUES (1);
365+SET @@SESSION.max_statement_time = 500;
366+LOCK TABLES t1 WRITE;
367+LOCK TABLES t1 READ;
368+ERROR 70101: Query execution was interrupted, max_statement_time exceeded
369+UNLOCK TABLES;
370+BEGIN;
371+SELECT * FROM t1;
372+a
373+1
374+ALTER TABLE t1 ADD COLUMN b INT;
375+ERROR 70101: Query execution was interrupted, max_statement_time exceeded
376+ROLLBACK;
377+SELECT GET_LOCK('lock', 1);
378+GET_LOCK('lock', 1)
379+1
380+SELECT GET_LOCK('lock', 1);
381+GET_LOCK('lock', 1)
382+NULL
383+SELECT RELEASE_LOCK('lock');
384+RELEASE_LOCK('lock')
385+1
386+DROP TABLE t1;
387+SET @@SESSION.max_statement_time = @old_session_max_statement_time;
388
389=== modified file 'Percona-Server/mysql-test/r/mysqld--help-notwin.result'
390--- Percona-Server/mysql-test/r/mysqld--help-notwin.result 2013-09-09 07:01:33 +0000
391+++ Percona-Server/mysql-test/r/mysqld--help-notwin.result 2013-09-09 15:30:42 +0000
392@@ -448,6 +448,9 @@
393 value are used; the rest are ignored)
394 --max-sp-recursion-depth[=#]
395 Maximum stored procedure recursion depth
396+ --max-statement-time=#
397+ Kill any statement that takes over the specified number
398+ of milliseconds
399 --max-tmp-tables=# Maximum number of temporary tables a client can keep open
400 at a time
401 --max-user-connections=#
402@@ -1209,6 +1212,7 @@
403 max-seeks-for-key 18446744073709551615
404 max-sort-length 1024
405 max-sp-recursion-depth 0
406+max-statement-time 0
407 max-tmp-tables 32
408 max-user-connections 0
409 max-write-lock-count 18446744073709551615
410
411=== modified file 'Percona-Server/mysql-test/r/mysqld--help-win.result'
412--- Percona-Server/mysql-test/r/mysqld--help-win.result 2013-09-09 07:01:33 +0000
413+++ Percona-Server/mysql-test/r/mysqld--help-win.result 2013-09-09 15:30:42 +0000
414@@ -424,6 +424,9 @@
415 value are used; the rest are ignored)
416 --max-sp-recursion-depth[=#]
417 Maximum stored procedure recursion depth
418+ --max-statement-time=#
419+ Kill any statement that takes over the specified number
420+ of milliseconds
421 --max-tmp-tables=# Maximum number of temporary tables a client can keep open
422 at a time
423 --max-user-connections=#
424@@ -1155,6 +1158,7 @@
425 max-seeks-for-key 18446744073709551615
426 max-sort-length 1024
427 max-sp-recursion-depth 0
428+max-statement-time 0
429 max-tmp-tables 32
430 max-user-connections 0
431 max-write-lock-count 18446744073709551615
432
433=== added file 'Percona-Server/mysql-test/suite/sys_vars/r/have_statement_timeout_basic.result'
434--- Percona-Server/mysql-test/suite/sys_vars/r/have_statement_timeout_basic.result 1970-01-01 00:00:00 +0000
435+++ Percona-Server/mysql-test/suite/sys_vars/r/have_statement_timeout_basic.result 2013-09-09 15:30:42 +0000
436@@ -0,0 +1,53 @@
437+# Displaying default value
438+SELECT COUNT(@@GLOBAL.have_statement_timeout);
439+COUNT(@@GLOBAL.have_statement_timeout)
440+1
441+1 Expected
442+# Check if Value can set
443+SET @@GLOBAL.have_statement_timeout=1;
444+ERROR HY000: Variable 'have_statement_timeout' is a read only variable
445+Expected error 'Read only variable'
446+SELECT COUNT(@@GLOBAL.have_statement_timeout);
447+COUNT(@@GLOBAL.have_statement_timeout)
448+1
449+1 Expected
450+# Check if the value in GLOBAL Table matches value in variable
451+SELECT @@GLOBAL.have_statement_timeout = VARIABLE_VALUE
452+FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
453+WHERE VARIABLE_NAME='have_statement_timeout';
454+@@GLOBAL.have_statement_timeout = VARIABLE_VALUE
455+1
456+1 Expected
457+SELECT COUNT(@@GLOBAL.have_statement_timeout);
458+COUNT(@@GLOBAL.have_statement_timeout)
459+1
460+1 Expected
461+SELECT COUNT(VARIABLE_VALUE)
462+FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
463+WHERE VARIABLE_NAME='have_statement_timeout';
464+COUNT(VARIABLE_VALUE)
465+1
466+1 Expected
467+# Check if accessing variable with and without GLOBAL point to same variable
468+SELECT @@have_statement_timeout = @@GLOBAL.have_statement_timeout;
469+@@have_statement_timeout = @@GLOBAL.have_statement_timeout
470+1
471+1 Expected
472+# Check if have_statement_timeout can be accessed with and without @@ sign
473+SELECT COUNT(@@have_statement_timeout);
474+COUNT(@@have_statement_timeout)
475+1
476+1 Expected
477+SELECT COUNT(@@local.have_statement_timeout);
478+ERROR HY000: Variable 'have_statement_timeout' is a GLOBAL variable
479+Expected error 'Variable is a GLOBAL variable'
480+SELECT COUNT(@@SESSION.have_statement_timeout);
481+ERROR HY000: Variable 'have_statement_timeout' is a GLOBAL variable
482+Expected error 'Variable is a GLOBAL variable'
483+SELECT COUNT(@@GLOBAL.have_statement_timeout);
484+COUNT(@@GLOBAL.have_statement_timeout)
485+1
486+1 Expected
487+SELECT have_statement_timeout = @@SESSION.have_statement_timeout;
488+ERROR 42S22: Unknown column 'have_statement_timeout' in 'field list'
489+Expected error 'Unknown column 'have_statement_timeout' in 'field list''
490
491=== added file 'Percona-Server/mysql-test/suite/sys_vars/r/max_statement_time_basic.result'
492--- Percona-Server/mysql-test/suite/sys_vars/r/max_statement_time_basic.result 1970-01-01 00:00:00 +0000
493+++ Percona-Server/mysql-test/suite/sys_vars/r/max_statement_time_basic.result 2013-09-09 15:30:42 +0000
494@@ -0,0 +1,89 @@
495+# Save initial value
496+SET @start_session_value = @@session.max_statement_time;
497+SELECT @start_session_value;
498+@start_session_value
499+0
500+# Display the DEFAULT value of max_statement_time
501+SET @@session.max_statement_time = 20000;
502+SET @@session.max_statement_time = DEFAULT;
503+SELECT @@session.max_statement_time;
504+@@session.max_statement_time
505+0
506+# Check the DEFAULT value of max_statement_time
507+SET @@session.max_statement_time = DEFAULT;
508+SELECT @@session.max_statement_time = 28800;
509+@@session.max_statement_time = 28800
510+0
511+# Change the value of max_statement_time to a valid value for SESSION scope
512+SET @@session.max_statement_time = 10000;
513+SELECT @@session.max_statement_time;
514+@@session.max_statement_time
515+10000
516+SET @@session.max_statement_time = 50050;
517+SELECT @@session.max_statement_time;
518+@@session.max_statement_time
519+50050
520+SET @@session.max_statement_time = 65535;
521+SELECT @@session.max_statement_time;
522+@@session.max_statement_time
523+65535
524+# Change the value of max_statement_time to an invalid value #
525+SET @@session.max_statement_time = 0;
526+SELECT @@session.max_statement_time;
527+@@session.max_statement_time
528+0
529+SET @@session.max_statement_time = -2;
530+Warnings:
531+Warning 1292 Truncated incorrect max_statement_time value: '-2'
532+SELECT @@session.max_statement_time;
533+@@session.max_statement_time
534+0
535+SET @@session.max_statement_time = 65530.34;
536+ERROR 42000: Incorrect argument type to variable 'max_statement_time'
537+SET @@session.max_statement_time = 100000000;
538+SELECT @@session.max_statement_time;
539+@@session.max_statement_time
540+100000000
541+SET @@session.max_statement_time = test;
542+ERROR 42000: Incorrect argument type to variable 'max_statement_time'
543+SELECT @@session.max_statement_time;
544+@@session.max_statement_time
545+100000000
546+# Check if the value in SESSION Table matches value in variable
547+SELECT @@session.max_statement_time = VARIABLE_VALUE
548+FROM INFORMATION_SCHEMA.SESSION_VARIABLES
549+WHERE VARIABLE_NAME='max_statement_time';
550+@@session.max_statement_time = VARIABLE_VALUE
551+1
552+# Check if TRUE and FALSE values can be used on variable
553+SET @@session.max_statement_time = TRUE;
554+SELECT @@session.max_statement_time;
555+@@session.max_statement_time
556+1
557+SET @@session.max_statement_time = FALSE;
558+SELECT @@session.max_statement_time;
559+@@session.max_statement_time
560+0
561+# Check if accessing variable with SESSION,LOCAL and without SCOPE points to same session variable
562+SET @@max_statement_time = 10000;
563+SELECT @@max_statement_time = @@local.max_statement_time;
564+@@max_statement_time = @@local.max_statement_time
565+1
566+SELECT @@local.max_statement_time = @@session.max_statement_time;
567+@@local.max_statement_time = @@session.max_statement_time
568+1
569+# Check if max_statement_time can be accessed with and without @@ sign
570+SET max_statement_time = 10000;
571+SELECT @@max_statement_time;
572+@@max_statement_time
573+10000
574+SELECT local.max_statement_time;
575+ERROR 42S02: Unknown table 'local' in field list
576+SELECT session.max_statement_time;
577+ERROR 42S02: Unknown table 'session' in field list
578+SET @@global.max_statement_time = 0;
579+# Restore initial value
580+SET @@session.max_statement_time = @start_session_value;
581+SELECT @@session.max_statement_time;
582+@@session.max_statement_time
583+0
584
585=== added file 'Percona-Server/mysql-test/suite/sys_vars/t/have_statement_timeout_basic.test'
586--- Percona-Server/mysql-test/suite/sys_vars/t/have_statement_timeout_basic.test 1970-01-01 00:00:00 +0000
587+++ Percona-Server/mysql-test/suite/sys_vars/t/have_statement_timeout_basic.test 2013-09-09 15:30:42 +0000
588@@ -0,0 +1,55 @@
589+--source include/have_statement_timeout.inc
590+
591+--echo # Displaying default value
592+
593+SELECT COUNT(@@GLOBAL.have_statement_timeout);
594+--echo 1 Expected
595+
596+--echo # Check if Value can set
597+
598+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
599+SET @@GLOBAL.have_statement_timeout=1;
600+--echo Expected error 'Read only variable'
601+
602+SELECT COUNT(@@GLOBAL.have_statement_timeout);
603+--echo 1 Expected
604+
605+--echo # Check if the value in GLOBAL Table matches value in variable
606+
607+SELECT @@GLOBAL.have_statement_timeout = VARIABLE_VALUE
608+FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
609+WHERE VARIABLE_NAME='have_statement_timeout';
610+--echo 1 Expected
611+
612+SELECT COUNT(@@GLOBAL.have_statement_timeout);
613+--echo 1 Expected
614+
615+SELECT COUNT(VARIABLE_VALUE)
616+FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
617+WHERE VARIABLE_NAME='have_statement_timeout';
618+--echo 1 Expected
619+
620+--echo # Check if accessing variable with and without GLOBAL point to same variable
621+
622+SELECT @@have_statement_timeout = @@GLOBAL.have_statement_timeout;
623+--echo 1 Expected
624+
625+--echo # Check if have_statement_timeout can be accessed with and without @@ sign
626+
627+SELECT COUNT(@@have_statement_timeout);
628+--echo 1 Expected
629+
630+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
631+SELECT COUNT(@@local.have_statement_timeout);
632+--echo Expected error 'Variable is a GLOBAL variable'
633+
634+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
635+SELECT COUNT(@@SESSION.have_statement_timeout);
636+--echo Expected error 'Variable is a GLOBAL variable'
637+
638+SELECT COUNT(@@GLOBAL.have_statement_timeout);
639+--echo 1 Expected
640+
641+--error ER_BAD_FIELD_ERROR
642+SELECT have_statement_timeout = @@SESSION.have_statement_timeout;
643+--echo Expected error 'Unknown column 'have_statement_timeout' in 'field list''
644
645=== added file 'Percona-Server/mysql-test/suite/sys_vars/t/max_statement_time_basic.test'
646--- Percona-Server/mysql-test/suite/sys_vars/t/max_statement_time_basic.test 1970-01-01 00:00:00 +0000
647+++ Percona-Server/mysql-test/suite/sys_vars/t/max_statement_time_basic.test 2013-09-09 15:30:42 +0000
648@@ -0,0 +1,78 @@
649+--source include/have_statement_timeout.inc
650+
651+--echo # Save initial value
652+
653+SET @start_session_value = @@session.max_statement_time;
654+SELECT @start_session_value;
655+
656+--echo # Display the DEFAULT value of max_statement_time
657+
658+SET @@session.max_statement_time = 20000;
659+SET @@session.max_statement_time = DEFAULT;
660+SELECT @@session.max_statement_time;
661+
662+--echo # Check the DEFAULT value of max_statement_time
663+
664+SET @@session.max_statement_time = DEFAULT;
665+SELECT @@session.max_statement_time = 28800;
666+
667+--echo # Change the value of max_statement_time to a valid value for SESSION scope
668+
669+SET @@session.max_statement_time = 10000;
670+SELECT @@session.max_statement_time;
671+SET @@session.max_statement_time = 50050;
672+SELECT @@session.max_statement_time;
673+SET @@session.max_statement_time = 65535;
674+SELECT @@session.max_statement_time;
675+
676+--echo # Change the value of max_statement_time to an invalid value #
677+
678+SET @@session.max_statement_time = 0;
679+SELECT @@session.max_statement_time;
680+SET @@session.max_statement_time = -2;
681+SELECT @@session.max_statement_time;
682+--error ER_WRONG_TYPE_FOR_VAR
683+SET @@session.max_statement_time = 65530.34;
684+SET @@session.max_statement_time = 100000000;
685+SELECT @@session.max_statement_time;
686+
687+--error ER_WRONG_TYPE_FOR_VAR
688+SET @@session.max_statement_time = test;
689+SELECT @@session.max_statement_time;
690+
691+--echo # Check if the value in SESSION Table matches value in variable
692+
693+SELECT @@session.max_statement_time = VARIABLE_VALUE
694+FROM INFORMATION_SCHEMA.SESSION_VARIABLES
695+WHERE VARIABLE_NAME='max_statement_time';
696+
697+--echo # Check if TRUE and FALSE values can be used on variable
698+
699+SET @@session.max_statement_time = TRUE;
700+SELECT @@session.max_statement_time;
701+SET @@session.max_statement_time = FALSE;
702+SELECT @@session.max_statement_time;
703+
704+--echo # Check if accessing variable with SESSION,LOCAL and without SCOPE points to same session variable
705+
706+SET @@max_statement_time = 10000;
707+SELECT @@max_statement_time = @@local.max_statement_time;
708+SELECT @@local.max_statement_time = @@session.max_statement_time;
709+
710+--echo # Check if max_statement_time can be accessed with and without @@ sign
711+
712+SET max_statement_time = 10000;
713+SELECT @@max_statement_time;
714+--error ER_UNKNOWN_TABLE
715+SELECT local.max_statement_time;
716+--error ER_UNKNOWN_TABLE
717+SELECT session.max_statement_time;
718+
719+#--echo # Check that the variable is a SESSION-only variable
720+#--error ER_LOCAL_VARIABLE
721+SET @@global.max_statement_time = 0;
722+
723+--echo # Restore initial value
724+
725+SET @@session.max_statement_time = @start_session_value;
726+SELECT @@session.max_statement_time;
727
728=== added file 'Percona-Server/mysql-test/t/max_statement_time_func.test'
729--- Percona-Server/mysql-test/t/max_statement_time_func.test 1970-01-01 00:00:00 +0000
730+++ Percona-Server/mysql-test/t/max_statement_time_func.test 2013-09-09 15:30:42 +0000
731@@ -0,0 +1,154 @@
732+--source include/have_statement_timeout.inc
733+--source include/not_embedded.inc
734+--source include/have_innodb.inc
735+
736+SET @old_session_max_statement_time = @@SESSION.max_statement_time;
737+
738+--echo #
739+--echo # Test max statement time interruption.
740+--echo # Note that if SLEEP() is interrupted, it returns 1.
741+--echo #
742+
743+SET @@SESSION.max_statement_time = 10;
744+SELECT SLEEP(1000);
745+SET @@SESSION.max_statement_time = 0;
746+
747+--echo #
748+--echo # Apply timeout to the top-level statement.
749+--echo #
750+
751+DELIMITER |;
752+
753+CREATE PROCEDURE p1()
754+BEGIN
755+ SELECT SLEEP(1000);
756+END|
757+
758+DELIMITER ;|
759+
760+SET @@SESSION.max_statement_time = 10;
761+CALL p1();
762+SET @@SESSION.max_statement_time = 0;
763+
764+--echo # Apply timeout to prepared statements.
765+PREPARE prep_1 FROM 'call p1()';
766+SET @@SESSION.max_statement_time = 10;
767+EXECUTE prep_1;
768+SET @@SESSION.max_statement_time = 0;
769+
770+DROP PREPARE prep_1;
771+DROP PROCEDURE p1;
772+
773+--echo #
774+--echo # Interrupt a statement that changes data.
775+--echo #
776+
777+CREATE TABLE t1 (a INT);
778+
779+DELIMITER |;
780+
781+CREATE FUNCTION f1() RETURNS INT
782+BEGIN
783+ WHILE true DO
784+ INSERT INTO t1 VALUES (1);
785+ END WHILE;
786+ RETURN 1;
787+END|
788+
789+DELIMITER ;|
790+
791+SET @@SESSION.max_statement_time = 500;
792+--error ER_QUERY_TIMEOUT
793+SELECT f1();
794+SET @@SESSION.max_statement_time = 0;
795+
796+DROP FUNCTION f1;
797+DROP TABLE t1;
798+
799+SELECT CONVERT(VARIABLE_VALUE, UNSIGNED) INTO @time_set
800+ FROM INFORMATION_SCHEMA.GLOBAL_STATUS
801+ WHERE VARIABLE_NAME = 'MAX_STATEMENT_TIME_SET';
802+
803+SELECT CONVERT(VARIABLE_VALUE, UNSIGNED) INTO @time_exceeded
804+ FROM INFORMATION_SCHEMA.GLOBAL_STATUS
805+ WHERE VARIABLE_NAME = 'MAX_STATEMENT_TIME_EXCEEDED';
806+
807+SET @@SESSION.max_statement_time = 100;
808+SELECT SLEEP(1000);
809+
810+--echo # Ensure that the counters for:
811+--echo # - statements that are time limited; and
812+--echo # - statements that exceeded their maximum execution time
813+--echo # are incremented.
814+
815+SELECT 1 AS STATUS FROM INFORMATION_SCHEMA.GLOBAL_STATUS
816+ WHERE VARIABLE_NAME = 'MAX_STATEMENT_TIME_SET'
817+ AND CONVERT(VARIABLE_VALUE, UNSIGNED) > @time_set;
818+
819+SELECT 1 AS STATUS FROM INFORMATION_SCHEMA.GLOBAL_STATUS
820+ WHERE VARIABLE_NAME = 'MAX_STATEMENT_TIME_EXCEEDED'
821+ AND CONVERT(VARIABLE_VALUE, UNSIGNED) > @time_exceeded;
822+
823+SET @@SESSION.max_statement_time = default;
824+
825+--echo
826+--echo # Check that the appropriate error status is set.
827+--echo
828+
829+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
830+INSERT INTO t1 VALUES (1);
831+
832+START TRANSACTION;
833+SELECT * FROM t1 FOR UPDATE;
834+
835+connect (con1,localhost,root,,test,,);
836+SET @@SESSION.max_statement_time = 100;
837+--error ER_QUERY_TIMEOUT
838+UPDATE t1 SET a = 2;
839+SHOW WARNINGS;
840+disconnect con1;
841+
842+connection default;
843+ROLLBACK;
844+
845+DROP TABLE t1;
846+
847+
848+--echo #
849+--echo # Test interaction with lock waits.
850+--echo #
851+
852+CREATE TABLE t1 (a INT) ENGINE=InnoDB;
853+INSERT INTO t1 VALUES (1);
854+
855+connect (con1,localhost,root,,test,,);
856+SET @@SESSION.max_statement_time = 500;
857+
858+connection default;
859+LOCK TABLES t1 WRITE;
860+
861+connection con1;
862+--error ER_QUERY_TIMEOUT
863+LOCK TABLES t1 READ;
864+
865+connection default;
866+UNLOCK TABLES;
867+BEGIN;
868+SELECT * FROM t1;
869+
870+connection con1;
871+--error ER_QUERY_TIMEOUT
872+ALTER TABLE t1 ADD COLUMN b INT;
873+
874+connection default;
875+ROLLBACK;
876+SELECT GET_LOCK('lock', 1);
877+
878+connection con1;
879+SELECT GET_LOCK('lock', 1);
880+
881+disconnect con1;
882+connection default;
883+SELECT RELEASE_LOCK('lock');
884+DROP TABLE t1;
885+SET @@SESSION.max_statement_time = @old_session_max_statement_time;
886
887=== modified file 'Percona-Server/mysys/CMakeLists.txt'
888--- Percona-Server/mysys/CMakeLists.txt 2013-08-06 15:16:34 +0000
889+++ Percona-Server/mysys/CMakeLists.txt 2013-09-09 15:30:42 +0000
890@@ -45,6 +45,14 @@
891 SET(MYSYS_SOURCES ${MYSYS_SOURCES} my_alarm.c)
892 ENDIF()
893
894+IF(HAVE_POSIX_TIMERS)
895+ SET(MYSYS_SOURCES ${MYSYS_SOURCES} posix_timers.c)
896+ENDIF()
897+
898+IF(HAVE_KQUEUE_TIMERS)
899+ SET(MYSYS_SOURCES ${MYSYS_SOURCES} kqueue_timers.c)
900+ENDIF()
901+
902 IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_C_COMPILER_ID MATCHES "SunPro")
903 # Inline assembly template for rdtsc
904 SET_SOURCE_FILES_PROPERTIES(my_rdtsc.c
905
906=== added file 'Percona-Server/mysys/kqueue_timers.c'
907--- Percona-Server/mysys/kqueue_timers.c 1970-01-01 00:00:00 +0000
908+++ Percona-Server/mysys/kqueue_timers.c 2013-09-09 15:30:42 +0000
909@@ -0,0 +1,219 @@
910+/* Copyright (c) 2012, Twitter, Inc. All rights reserved.
911+
912+ This program is free software; you can redistribute it and/or modify
913+ it under the terms of the GNU General Public License as published by
914+ the Free Software Foundation; version 2 of the License.
915+
916+ This program is distributed in the hope that it will be useful,
917+ but WITHOUT ANY WARRANTY; without even the implied warranty of
918+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
919+ GNU General Public License for more details.
920+
921+ You should have received a copy of the GNU General Public License along
922+ with this program; if not, write to the Free Software Foundation, Inc.,
923+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
924+
925+#include "my_timer.h" /* my_timer_t */
926+#include "my_pthread.h" /* my_thread_init, my_thread_end */
927+
928+#include <sys/types.h>
929+#include <sys/event.h>
930+#include <sys/time.h>
931+#include <assert.h>
932+#include <errno.h>
933+
934+static int kq_fd= -1;
935+static pthread_t thread;
936+
937+/**
938+ Timer expiration notification thread.
939+
940+ @param arg Unused.
941+*/
942+
943+static void *
944+timer_notify_thread(void *arg __attribute__((unused)))
945+{
946+ my_timer_t *timer;
947+ struct kevent kev;
948+
949+ my_thread_init();
950+
951+ while (1)
952+ {
953+ if (kevent(kq_fd, NULL, 0, &kev, 1, NULL) < 0)
954+ continue;
955+
956+ if (kev.filter == EVFILT_TIMER)
957+ {
958+ timer= kev.udata;
959+ assert(timer->id == kev.ident);
960+ timer->notify_function(timer);
961+ }
962+ else if (kev.filter == EVFILT_USER)
963+ break;
964+ }
965+
966+ my_thread_end();
967+
968+ return NULL;
969+}
970+
971+
972+/**
973+ Create a helper thread to dispatch timer expiration notifications.
974+
975+ @return On success, 0. On error, -1 is returned.
976+*/
977+
978+static int
979+start_helper_thread(void)
980+{
981+ struct kevent kev;
982+
983+ EV_SET(&kev, 0, EVFILT_USER, EV_ADD, 0, 0, 0);
984+
985+ if (kevent(kq_fd, &kev, 1, NULL, 0, NULL) < 0)
986+ return -1;
987+
988+ return pthread_create(&thread, NULL, timer_notify_thread, NULL);
989+}
990+
991+
992+/**
993+ Initialize internal components.
994+
995+ @return On success, 0.
996+ On error, -1 is returned, and errno is set to indicate the error.
997+*/
998+
999+int
1000+my_os_timer_init_ext(void)
1001+{
1002+ int rc;
1003+
1004+ /* Create a file descriptor for event notification. */
1005+ if ((kq_fd= kqueue()) < 0)
1006+ return -1;
1007+
1008+ /* Create a helper thread. */
1009+ if ((rc= start_helper_thread()))
1010+ close(kq_fd);
1011+
1012+ return rc;
1013+}
1014+
1015+
1016+/**
1017+ Release any resources that were allocated as part of initialization.
1018+*/
1019+
1020+void
1021+my_os_timer_deinit(void)
1022+{
1023+ struct kevent kev;
1024+
1025+ EV_SET(&kev, 0, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0);
1026+
1027+ /* There's not much to do if triggering the event fails. */
1028+ if (kevent(kq_fd, &kev, 1, NULL, 0, NULL) > -1)
1029+ pthread_join(thread, NULL);
1030+
1031+ close(kq_fd);
1032+}
1033+
1034+
1035+/**
1036+ Create a timer object.
1037+
1038+ @param timer Timer object.
1039+
1040+ @return On success, 0.
1041+ On error, -1 is returned, and errno is set to indicate the error.
1042+*/
1043+
1044+int
1045+my_os_timer_create(my_timer_t *timer)
1046+{
1047+ assert(kq_fd >= 0);
1048+
1049+ timer->id= (uintptr_t) timer;
1050+
1051+ return 0;
1052+}
1053+
1054+
1055+/**
1056+ Set the time until the next expiration of the timer.
1057+
1058+ @param timer Timer object.
1059+ @param time Amount of time (in milliseconds) before the timer expires.
1060+
1061+ @return On success, 0.
1062+ On error, -1 is returned, and errno is set to indicate the error.
1063+*/
1064+
1065+int
1066+my_os_timer_set(my_timer_t *timer, unsigned long time)
1067+{
1068+ struct kevent kev;
1069+
1070+ EV_SET(&kev, timer->id, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, time, timer);
1071+
1072+ return kevent(kq_fd, &kev, 1, NULL, 0, NULL);
1073+}
1074+
1075+
1076+/**
1077+ Reset the time until the next expiration of the timer.
1078+
1079+ @param timer Timer object.
1080+ @param state The state of the timer at the time of cancellation, either
1081+ signaled (false) or nonsignaled (true).
1082+
1083+ @return On success, 0.
1084+ On error, -1 is returned, and errno is set to indicate the error.
1085+*/
1086+
1087+int
1088+my_os_timer_reset(my_timer_t *timer, int *state)
1089+{
1090+ int status;
1091+ struct kevent kev;
1092+
1093+ EV_SET(&kev, timer->id, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
1094+
1095+ status= kevent(kq_fd, &kev, 1, NULL, 0, NULL);
1096+
1097+ /*
1098+ If the event was retrieved from the kqueue (at which point we
1099+ consider it to be signaled), the timer was automatically deleted.
1100+ */
1101+ if (!status)
1102+ *state= 1;
1103+ else if (errno == ENOENT)
1104+ {
1105+ *state= 0;
1106+ status= 0;
1107+ }
1108+
1109+ return status;
1110+}
1111+
1112+
1113+/**
1114+ Delete a timer object.
1115+
1116+ @param timer Timer object.
1117+*/
1118+
1119+void
1120+my_os_timer_delete(my_timer_t *timer)
1121+{
1122+ struct kevent kev;
1123+
1124+ EV_SET(&kev, timer->id, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
1125+
1126+ kevent(kq_fd, &kev, 1, NULL, 0, NULL);
1127+}
1128+
1129
1130=== added file 'Percona-Server/mysys/posix_timers.c'
1131--- Percona-Server/mysys/posix_timers.c 1970-01-01 00:00:00 +0000
1132+++ Percona-Server/mysys/posix_timers.c 2013-09-09 15:30:42 +0000
1133@@ -0,0 +1,256 @@
1134+/* Copyright (c) 2012, Twitter, Inc. All rights reserved.
1135+
1136+ This program is free software; you can redistribute it and/or modify
1137+ it under the terms of the GNU General Public License as published by
1138+ the Free Software Foundation; version 2 of the License.
1139+
1140+ This program is distributed in the hope that it will be useful,
1141+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1142+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1143+ GNU General Public License for more details.
1144+
1145+ You should have received a copy of the GNU General Public License along
1146+ with this program; if not, write to the Free Software Foundation, Inc.,
1147+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
1148+
1149+#include "my_timer.h" /* my_timer_t */
1150+#include "my_pthread.h" /* my_thread_init, my_thread_end */
1151+#include "m_string.h" /* memset */
1152+#include <sys/syscall.h> /* SYS_gettid */
1153+
1154+#ifndef sigev_notify_thread_id
1155+#define sigev_notify_thread_id _sigev_un._tid
1156+#endif
1157+
1158+#define MY_TIMER_EVENT_SIGNO (SIGRTMIN)
1159+#define MY_TIMER_KILL_SIGNO (SIGRTMIN+1)
1160+
1161+/* Timer thread object. */
1162+static pthread_t thread;
1163+
1164+/* Timer thread ID (TID). */
1165+static pid_t thread_id;
1166+
1167+/**
1168+ Timer expiration notification function.
1169+
1170+ @param sigev_value Signal (notification) value.
1171+
1172+ @remark The notification function is usually run in a helper thread
1173+ and is called each time the timer expires.
1174+*/
1175+
1176+static void
1177+timer_notify_function(sigval_t sigev_value)
1178+{
1179+ my_timer_t *timer= sigev_value.sival_ptr;
1180+ timer->notify_function(timer);
1181+}
1182+
1183+
1184+/**
1185+ Timer expiration notification thread.
1186+
1187+ @param arg Barrier object.
1188+*/
1189+
1190+static void *
1191+timer_notify_thread(void *arg)
1192+{
1193+ sigset_t set;
1194+ siginfo_t info;
1195+ pthread_barrier_t *barrier= arg;
1196+
1197+ my_thread_init();
1198+
1199+ sigemptyset(&set);
1200+ sigaddset(&set, MY_TIMER_EVENT_SIGNO);
1201+ sigaddset(&set, MY_TIMER_KILL_SIGNO);
1202+
1203+ /* Get the thread ID of the current thread. */
1204+ thread_id= (pid_t) syscall(SYS_gettid);
1205+
1206+ /* Wake up parent thread, thread_id is available. */
1207+ pthread_barrier_wait(barrier);
1208+
1209+ while (1)
1210+ {
1211+ if (sigwaitinfo(&set, &info) < 0)
1212+ continue;
1213+
1214+ if (info.si_signo == MY_TIMER_EVENT_SIGNO)
1215+ timer_notify_function(info.si_value);
1216+ else if (info.si_signo == MY_TIMER_KILL_SIGNO)
1217+ break;
1218+ }
1219+
1220+ my_thread_end();
1221+
1222+ return NULL;
1223+}
1224+
1225+
1226+/**
1227+ Create a helper thread to dispatch timer expiration notifications.
1228+
1229+ @return On success, 0. On error, -1 is returned.
1230+*/
1231+
1232+static int
1233+start_helper_thread(void)
1234+{
1235+ pthread_barrier_t barrier;
1236+
1237+ if (pthread_barrier_init(&barrier, NULL, 2))
1238+ return -1;
1239+
1240+ if (pthread_create(&thread, NULL, timer_notify_thread, &barrier))
1241+ return -1;
1242+
1243+ pthread_barrier_wait(&barrier);
1244+ pthread_barrier_destroy(&barrier);
1245+
1246+ return 0;
1247+}
1248+
1249+
1250+/**
1251+ Initialize internal components.
1252+
1253+ @return On success, 0.
1254+ On error, -1 is returned, and errno is set to indicate the error.
1255+*/
1256+
1257+int
1258+my_os_timer_init_ext(void)
1259+{
1260+ int rc;
1261+ sigset_t set, old_set;
1262+
1263+ if (sigfillset(&set))
1264+ return -1;
1265+
1266+ /*
1267+ Temporarily block all signals. New thread will inherit signal
1268+ mask of the current thread.
1269+ */
1270+ if (pthread_sigmask(SIG_BLOCK, &set, &old_set))
1271+ return -1;
1272+
1273+ /* Create a helper thread. */
1274+ rc= start_helper_thread();
1275+
1276+ /* Restore the signal mask. */
1277+ pthread_sigmask(SIG_SETMASK, &old_set, NULL);
1278+
1279+ return rc;
1280+}
1281+
1282+
1283+/**
1284+ Release any resources that were allocated as part of initialization.
1285+*/
1286+
1287+void
1288+my_os_timer_deinit(void)
1289+{
1290+ /* Kill helper thread. */
1291+ pthread_kill(thread, MY_TIMER_KILL_SIGNO);
1292+
1293+ /* Wait for helper thread termination. */
1294+ pthread_join(thread, NULL);
1295+}
1296+
1297+
1298+/**
1299+ Create a timer object.
1300+
1301+ @param timer Location where the timer ID is returned.
1302+
1303+ @return On success, 0.
1304+ On error, -1 is returned, and errno is set to indicate the error.
1305+*/
1306+
1307+int
1308+my_os_timer_create(my_timer_t *timer)
1309+{
1310+ struct sigevent sigev;
1311+
1312+ memset(&sigev, 0, sizeof(sigev));
1313+
1314+ sigev.sigev_value.sival_ptr= timer;
1315+ sigev.sigev_signo= MY_TIMER_EVENT_SIGNO;
1316+ sigev.sigev_notify= SIGEV_SIGNAL | SIGEV_THREAD_ID;
1317+ sigev.sigev_notify_thread_id= thread_id;
1318+
1319+ return timer_create(CLOCK_MONOTONIC, &sigev, &timer->id);
1320+}
1321+
1322+
1323+/**
1324+ Set the time until the next expiration of the timer.
1325+
1326+ @param timer Timer object.
1327+ @param time Amount of time (in milliseconds) before the timer expires.
1328+
1329+ @return On success, 0.
1330+ On error, -1 is returned, and errno is set to indicate the error.
1331+*/
1332+
1333+int
1334+my_os_timer_set(my_timer_t *timer, unsigned long time)
1335+{
1336+ const struct itimerspec spec= {
1337+ .it_interval= {.tv_sec= 0, .tv_nsec= 0},
1338+ .it_value= {.tv_sec= time / 1000,
1339+ .tv_nsec= (time % 1000) * 1000000}
1340+ };
1341+
1342+ return timer_settime(timer->id, 0, &spec, NULL);
1343+}
1344+
1345+
1346+/**
1347+ Reset the time until the next expiration of the timer.
1348+
1349+ @param timer Timer object.
1350+ @param state The state of the timer at the time of cancellation, either
1351+ signaled (false) or nonsignaled (true).
1352+
1353+ @return On success, 0.
1354+ On error, -1 is returned, and errno is set to indicate the error.
1355+*/
1356+
1357+int
1358+my_os_timer_reset(my_timer_t *timer, int *state)
1359+{
1360+ int status;
1361+ struct itimerspec old_spec;
1362+
1363+ /* A zeroed initial expiration value disarms the timer. */
1364+ const struct timespec zero_time= { .tv_sec= 0, .tv_nsec= 0 };
1365+ const struct itimerspec zero_spec= { .it_value= zero_time };
1366+
1367+ /*
1368+ timer_settime returns the amount of time before the timer
1369+ would have expired or zero if the timer was disarmed.
1370+ */
1371+ if (! (status= timer_settime(timer->id, 0, &zero_spec, &old_spec)))
1372+ *state= (old_spec.it_value.tv_sec || old_spec.it_value.tv_nsec);
1373+
1374+ return status;
1375+}
1376+
1377+
1378+/**
1379+ Delete a timer object.
1380+
1381+ @param timer Timer object.
1382+*/
1383+
1384+void
1385+my_os_timer_delete(my_timer_t *timer)
1386+{
1387+ timer_delete(timer->id);
1388+}
1389+
1390
1391=== modified file 'Percona-Server/sql/CMakeLists.txt'
1392--- Percona-Server/sql/CMakeLists.txt 2013-06-25 13:13:06 +0000
1393+++ Percona-Server/sql/CMakeLists.txt 2013-09-09 15:30:42 +0000
1394@@ -206,6 +206,10 @@
1395 )
1396 ENDIF()
1397
1398+IF(HAVE_MY_TIMER)
1399+ SET(SQL_SOURCE ${SQL_SOURCE} sql_timer.cc)
1400+ENDIF()
1401+
1402 MYSQL_ADD_PLUGIN(partition ha_partition.cc STORAGE_ENGINE DEFAULT STATIC_ONLY
1403 RECOMPILE_FOR_EMBEDDED)
1404
1405
1406=== modified file 'Percona-Server/sql/handler.cc'
1407--- Percona-Server/sql/handler.cc 2013-08-22 13:38:28 +0000
1408+++ Percona-Server/sql/handler.cc 2013-09-09 15:30:42 +0000
1409@@ -887,6 +887,24 @@
1410 plugin_foreach(thd, closecon_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, 0);
1411 }
1412
1413+static my_bool kill_handlerton(THD *thd, plugin_ref plugin, void *)
1414+{
1415+ handlerton *hton= plugin_data(plugin, handlerton *);
1416+
1417+ if (hton->state == SHOW_OPTION_YES && hton->kill_connection)
1418+ {
1419+ if (thd_get_ha_data(thd, hton))
1420+ hton->kill_connection(hton, thd);
1421+ }
1422+
1423+ return FALSE;
1424+}
1425+
1426+void ha_kill_connection(THD *thd)
1427+{
1428+ plugin_foreach(thd, kill_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, 0);
1429+}
1430+
1431 /* ========================================================================
1432 ======================= TRANSACTIONS ===================================*/
1433
1434
1435=== modified file 'Percona-Server/sql/handler.h'
1436--- Percona-Server/sql/handler.h 2013-08-22 13:38:28 +0000
1437+++ Percona-Server/sql/handler.h 2013-09-09 15:30:42 +0000
1438@@ -908,6 +908,9 @@
1439 const char *db, const char *table_name);
1440 int (*release_temporary_latches)(handlerton *hton, THD *thd);
1441
1442+ /* Terminate connection/statement notification. */
1443+ void (*kill_connection)(handlerton *hton, THD *thd);
1444+
1445 /*
1446 Get log status.
1447 If log_status is null then the handler do not support transaction
1448@@ -3399,6 +3402,7 @@
1449 TYPELIB* ha_known_exts();
1450 int ha_panic(enum ha_panic_function flag);
1451 void ha_close_connection(THD* thd);
1452+void ha_kill_connection(THD *thd);
1453 bool ha_flush_logs(handlerton *db_type);
1454 void ha_drop_database(char* path);
1455 int ha_create_table(THD *thd, const char *path,
1456
1457=== modified file 'Percona-Server/sql/mysqld.cc'
1458--- Percona-Server/sql/mysqld.cc 2013-09-09 07:01:33 +0000
1459+++ Percona-Server/sql/mysqld.cc 2013-09-09 15:30:42 +0000
1460@@ -108,6 +108,8 @@
1461 #include "sp_cache.h"
1462 #include "sql_reload.h" // reload_acl_and_cache
1463
1464+#include "my_timer.h" // my_os_timer_init_ext, my_os_timer_deinit
1465+
1466 #ifdef HAVE_POLL_H
1467 #include <poll.h>
1468 #endif
1469@@ -720,6 +722,8 @@
1470 extern TYPELIB utility_user_privileges_typelib;
1471 ulonglong utility_user_privileges= 0;
1472
1473+SHOW_COMP_OPTION have_statement_timeout= SHOW_OPTION_DISABLED;
1474+
1475 /* Thread specific variables */
1476
1477 pthread_key(MEM_ROOT**,THR_MALLOC);
1478@@ -1789,6 +1793,12 @@
1479
1480 memcached_shutdown();
1481
1482+#ifdef HAVE_MY_TIMER
1483+ if (have_statement_timeout == SHOW_OPTION_YES)
1484+ my_os_timer_deinit();
1485+#endif
1486+
1487+ have_statement_timeout= SHOW_OPTION_DISABLED;
1488 /*
1489 make sure that handlers finish up
1490 what they have that is dependent on the binlog
1491@@ -4584,6 +4594,15 @@
1492 if (table_def_init() | hostname_cache_init())
1493 unireg_abort(1);
1494
1495+#ifdef HAVE_MY_TIMER
1496+ if (my_os_timer_init_ext())
1497+ sql_print_error("Failed to initialize timer component (errno %d).", errno);
1498+ else
1499+ have_statement_timeout= SHOW_OPTION_YES;
1500+#else
1501+ have_statement_timeout= SHOW_OPTION_NO;
1502+#endif
1503+
1504 query_cache_set_min_res_unit(query_cache_min_res_unit);
1505 query_cache_init();
1506 query_cache_resize(query_cache_size);
1507@@ -7991,6 +8010,9 @@
1508 {"Last_query_cost", (char*) offsetof(STATUS_VAR, last_query_cost), SHOW_DOUBLE_STATUS},
1509 {"Last_query_partial_plans", (char*) offsetof(STATUS_VAR, last_query_partial_plans), SHOW_LONGLONG_STATUS},
1510 {"Max_used_connections", (char*) &max_used_connections, SHOW_LONG},
1511+ {"Max_statement_time_exceeded", (char*) offsetof(STATUS_VAR, max_statement_time_exceeded), SHOW_LONG_STATUS},
1512+ {"Max_statement_time_set", (char*) offsetof(STATUS_VAR, max_statement_time_set), SHOW_LONG_STATUS},
1513+ {"Max_statement_time_set_failed", (char*) offsetof(STATUS_VAR, max_statement_time_set_failed), SHOW_LONG_STATUS},
1514 {"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use, SHOW_LONG_NOFLUSH},
1515 {"Open_files", (char*) &my_file_opened, SHOW_LONG_NOFLUSH},
1516 {"Open_streams", (char*) &my_stream_opened, SHOW_LONG_NOFLUSH},
1517
1518=== modified file 'Percona-Server/sql/set_var.h'
1519--- Percona-Server/sql/set_var.h 2013-08-14 03:57:21 +0000
1520+++ Percona-Server/sql/set_var.h 2013-09-09 15:30:42 +0000
1521@@ -340,6 +340,7 @@
1522 extern SHOW_COMP_OPTION have_geometry, have_rtree_keys;
1523 extern SHOW_COMP_OPTION have_crypt;
1524 extern SHOW_COMP_OPTION have_compress;
1525+extern SHOW_COMP_OPTION have_statement_timeout;
1526
1527 /*
1528 Prototypes for helper functions
1529
1530=== modified file 'Percona-Server/sql/share/errmsg-utf8.txt'
1531--- Percona-Server/sql/share/errmsg-utf8.txt 2013-08-06 15:16:34 +0000
1532+++ Percona-Server/sql/share/errmsg-utf8.txt 2013-09-09 15:30:42 +0000
1533@@ -7082,6 +7082,9 @@
1534 ER_STOP_SLAVE_IO_THREAD_TIMEOUT
1535 eng "STOP SLAVE command execution is incomplete: Slave IO thread got the stop signal, thread is busy, IO thread will stop once the current task is complete."
1536
1537+ER_QUERY_TIMEOUT 70101
1538+ eng "Query execution was interrupted, max_statement_time exceeded"
1539+
1540 #
1541 # End of 5.6 error messages.
1542 #
1543
1544=== modified file 'Percona-Server/sql/signal_handler.cc'
1545--- Percona-Server/sql/signal_handler.cc 2013-08-14 03:57:21 +0000
1546+++ Percona-Server/sql/signal_handler.cc 2013-09-09 15:30:42 +0000
1547@@ -181,6 +181,9 @@
1548 case THD::KILL_QUERY:
1549 kreason= "KILL_QUERY";
1550 break;
1551+ case THD::KILL_TIMEOUT:
1552+ kreason= "KILL_TIMEOUT";
1553+ break;
1554 case THD::KILLED_NO_VALUE:
1555 kreason= "KILLED_NO_VALUE";
1556 break;
1557
1558=== modified file 'Percona-Server/sql/sql_class.cc'
1559--- Percona-Server/sql/sql_class.cc 2013-08-14 03:57:21 +0000
1560+++ Percona-Server/sql/sql_class.cc 2013-09-09 15:30:42 +0000
1561@@ -66,6 +66,8 @@
1562 using std::min;
1563 using std::max;
1564
1565+#include "sql_timer.h" // thd_timer_end
1566+
1567 /*
1568 The following is used to initialise Table_ident with a internal
1569 table name
1570@@ -764,8 +766,11 @@
1571
1572 @note LOCK_thread_count mutex is not necessary when the function is invoked on
1573 the currently running thread (current_thd) or if the caller in some other
1574- way guarantees that access to thd->query is serialized.
1575-
1576+ way guarantees that the thread won't be going away.
1577+
1578+ @note The query string is only printed if the session (thd) to be
1579+ described belongs to the calling thread.
1580+
1581 @return Pointer to string
1582 */
1583
1584@@ -778,13 +783,11 @@
1585 char header[256];
1586 int len;
1587 /*
1588- The pointers thd->query and thd->proc_info might change since they are
1589- being modified concurrently. This is acceptable for proc_info since its
1590- values doesn't have to very accurate and the memory it points to is static,
1591- but we need to attempt a snapshot on the pointer values to avoid using NULL
1592- values. The pointer to thd->query however, doesn't point to static memory
1593- and has to be protected by LOCK_thread_count or risk pointing to
1594- uninitialized memory.
1595+ The thd->proc_info pointer might change since it is being modified
1596+ concurrently. This is acceptable for proc_info since its value
1597+ doesn't have to be accurate and the memory it points to is static,
1598+ but we need to attempt a snapshot on the pointer values to avoid
1599+ using NULL values.
1600 */
1601 const char *proc_info= thd->proc_info;
1602
1603@@ -818,9 +821,7 @@
1604 str.append(proc_info);
1605 }
1606
1607- mysql_mutex_lock(&thd->LOCK_thd_data);
1608-
1609- if (thd->query())
1610+ if (thd == current_thd && thd->query())
1611 {
1612 if (max_query_len < 1)
1613 len= thd->query_length();
1614@@ -830,8 +831,6 @@
1615 str.append(thd->query(), len);
1616 }
1617
1618- mysql_mutex_unlock(&thd->LOCK_thd_data);
1619-
1620 if (str.c_ptr_safe() == buffer)
1621 return buffer;
1622
1623@@ -1129,6 +1128,8 @@
1624 #ifndef DBUG_OFF
1625 gis_debug= 0;
1626 #endif
1627+
1628+ timer= timer_cache= NULL;
1629 }
1630
1631
1632@@ -1766,6 +1767,11 @@
1633 mysql_mutex_lock(&LOCK_thd_data);
1634 mysql_mutex_unlock(&LOCK_thd_data);
1635
1636+ DBUG_ASSERT(timer == NULL);
1637+
1638+ if (timer_cache)
1639+ thd_timer_end(timer_cache);
1640+
1641 DBUG_PRINT("info", ("freeing security context"));
1642 main_security_ctx.destroy();
1643 my_free(db);
1644@@ -1890,7 +1896,8 @@
1645 /* Set the 'killed' flag of 'this', which is the target THD object. */
1646 killed= state_to_set;
1647
1648- if (state_to_set != THD::KILL_QUERY)
1649+ if (state_to_set != THD::KILL_QUERY &&
1650+ state_to_set != THD::KILL_TIMEOUT)
1651 {
1652 #ifdef SIGNAL_WITH_VIO_SHUTDOWN
1653 if (this != current_thd)
1654@@ -1933,6 +1940,13 @@
1655 MYSQL_CALLBACK(scheduler, post_kill_notification, (this));
1656 }
1657
1658+ /* Interrupt target waiting inside a storage engine. */
1659+ if (state_to_set != THD::NOT_KILLED)
1660+ ha_kill_connection(this);
1661+
1662+ if (state_to_set == THD::KILL_TIMEOUT)
1663+ status_var_increment(status_var.max_statement_time_exceeded);
1664+
1665 /* Broadcast a condition to kick the target if it is waiting on it. */
1666 if (mysys_var)
1667 {
1668@@ -4251,6 +4265,16 @@
1669 }
1670
1671 /**
1672+ Set the killed status of the current statement.
1673+
1674+ @param thd user thread connection handle
1675+*/
1676+extern "C" void thd_set_kill_status(const MYSQL_THD thd)
1677+{
1678+ thd->send_kill_message();
1679+}
1680+
1681+/**
1682 Return the thread id of a user thread
1683 @param thd user thread
1684 @return thread id
1685
1686=== modified file 'Percona-Server/sql/sql_class.h'
1687--- Percona-Server/sql/sql_class.h 2013-08-14 03:57:21 +0000
1688+++ Percona-Server/sql/sql_class.h 2013-09-09 15:30:42 +0000
1689@@ -86,6 +86,8 @@
1690 class User_level_lock;
1691 class user_var_entry;
1692
1693+struct st_thd_timer;
1694+
1695 enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME };
1696
1697 enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON,
1698@@ -600,6 +602,8 @@
1699
1700 my_bool pseudo_slave_mode;
1701
1702+ ulong max_statement_time;
1703+
1704 Gtid_specification gtid_next;
1705 Gtid_set_or_null gtid_next_list;
1706
1707@@ -682,6 +686,11 @@
1708 */
1709 double last_query_cost;
1710 ulonglong last_query_partial_plans;
1711+
1712+ ulong max_statement_time_exceeded;
1713+ ulong max_statement_time_set;
1714+ ulong max_statement_time_set_failed;
1715+
1716 } STATUS_VAR;
1717
1718 /*
1719@@ -2387,6 +2396,9 @@
1720 return m_binlog_filter_state;
1721 }
1722
1723+ /** Timer object. */
1724+ struct st_thd_timer *timer, *timer_cache;
1725+
1726 private:
1727 /**
1728 Indicate if the current statement should be discarded
1729@@ -3029,6 +3041,7 @@
1730 KILL_BAD_DATA=1,
1731 KILL_CONNECTION=ER_SERVER_SHUTDOWN,
1732 KILL_QUERY=ER_QUERY_INTERRUPTED,
1733+ KILL_TIMEOUT=ER_QUERY_TIMEOUT,
1734 KILLED_NO_VALUE /* means neither of the states */
1735 };
1736 killed_state volatile killed;
1737
1738=== modified file 'Percona-Server/sql/sql_parse.cc'
1739--- Percona-Server/sql/sql_parse.cc 2013-09-09 07:01:33 +0000
1740+++ Percona-Server/sql/sql_parse.cc 2013-09-09 15:30:42 +0000
1741@@ -105,6 +105,8 @@
1742 using std::max;
1743 using std::min;
1744
1745+#include "sql_timer.h" // thd_timer_set, thd_timer_reset
1746+
1747 #define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
1748
1749 /**
1750@@ -1123,6 +1125,85 @@
1751 DBUG_RETURN(FALSE);
1752 }
1753
1754+
1755+/**
1756+ Get the maximum execution time for a statement.
1757+
1758+ @return Length of time in milliseconds.
1759+
1760+ @remark A zero timeout means that no timeout should be
1761+ applied to this particular statement.
1762+*/
1763+
1764+static ulong inline get_max_statement_time(THD *thd)
1765+{
1766+
1767+ /* Assume query execution timeout feature is not used in the most cases */
1768+ if (likely(!thd->variables.max_statement_time))
1769+ return 0;
1770+
1771+ /* Check if timer support is implemented and was initialized. */
1772+ if (unlikely(have_statement_timeout != SHOW_OPTION_YES))
1773+ return 0;
1774+
1775+ /* The maximum execution time only applies to top-level statements. */
1776+ if (unlikely(thd->sp_runtime_ctx || thd->in_sub_stmt))
1777+ return 0;
1778+
1779+ /* Also does not apply to statements made by the slave thread. */
1780+ if (unlikely(thd->slave_thread))
1781+ return 0;
1782+
1783+ return thd->variables.max_statement_time;
1784+}
1785+
1786+
1787+/**
1788+ Set the time until the currently running statement is aborted.
1789+
1790+ @param thd Thread (session) context.
1791+
1792+ @return TRUE if the timer was armed.
1793+*/
1794+
1795+static inline bool set_statement_timer(THD *thd)
1796+{
1797+ ulong max_statement_time= get_max_statement_time(thd);
1798+
1799+ /* Assume query execution timeout feature is not used in the most cases */
1800+ if (likely(max_statement_time == 0))
1801+ return false;
1802+
1803+ if (unlikely(thd->timer != NULL))
1804+ return false;
1805+
1806+ thd->timer= thd_timer_set(thd, thd->timer_cache, max_statement_time);
1807+ thd->timer_cache= NULL;
1808+
1809+ if (thd->timer)
1810+ status_var_increment(thd->status_var.max_statement_time_set);
1811+ else
1812+ status_var_increment(thd->status_var.max_statement_time_set_failed);
1813+
1814+ return thd->timer;
1815+}
1816+
1817+
1818+/**
1819+ Deactivate the timer associated with the statement that was executed.
1820+
1821+ @param thd Thread (session) context.
1822+*/
1823+
1824+static void reset_statement_timer(THD *thd)
1825+{
1826+ DBUG_ASSERT(thd->timer);
1827+ /* Cache the timer object if it can be reused. */
1828+ thd->timer_cache= thd_timer_reset(thd->timer);
1829+ thd->timer= NULL;
1830+}
1831+
1832+
1833 /**
1834 Perform one connection-level (COM_XXXX) command.
1835
1836@@ -2613,6 +2694,8 @@
1837 } /* endif unlikely slave */
1838 #endif
1839
1840+ bool reset_timer= set_statement_timer(thd);
1841+
1842 status_var_increment(thd->status_var.com_stat[lex->sql_command]);
1843
1844 Opt_trace_start ots(thd, all_tables, lex->sql_command, &lex->var_list,
1845@@ -5201,12 +5284,17 @@
1846 DBUG_ASSERT(!thd->in_active_multi_stmt_transaction() ||
1847 thd->in_multi_stmt_transaction_mode());
1848
1849+ if (reset_timer)
1850+ reset_statement_timer(thd);
1851+
1852 if (! thd->in_sub_stmt)
1853 {
1854 /* report error issued during command execution */
1855 if (thd->killed_errno())
1856 thd->send_kill_message();
1857- if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
1858+ if (thd->killed == THD::KILL_QUERY ||
1859+ thd->killed == THD::KILL_TIMEOUT ||
1860+ thd->killed == THD::KILL_BAD_DATA)
1861 {
1862 thd->killed= THD::NOT_KILLED;
1863 thd->mysys_var->abort= 0;
1864
1865=== added file 'Percona-Server/sql/sql_timer.cc'
1866--- Percona-Server/sql/sql_timer.cc 1970-01-01 00:00:00 +0000
1867+++ Percona-Server/sql/sql_timer.cc 2013-09-09 15:30:42 +0000
1868@@ -0,0 +1,253 @@
1869+/* Copyright (c) 2012, Twitter, Inc. All rights reserved.
1870+
1871+ This program is free software; you can redistribute it and/or modify
1872+ it under the terms of the GNU General Public License as published by
1873+ the Free Software Foundation; version 2 of the License.
1874+
1875+ This program is distributed in the hope that it will be useful,
1876+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1877+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1878+ GNU General Public License for more details.
1879+
1880+ You should have received a copy of the GNU General Public License along
1881+ with this program; if not, write to the Free Software Foundation, Inc.,
1882+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
1883+
1884+#include "sql_class.h" /* THD */
1885+#include "sql_timer.h" /* thd_timer_set, etc. */
1886+#include "my_timer.h" /* my_timer_t */
1887+
1888+struct st_thd_timer
1889+{
1890+ THD *thd;
1891+ my_timer_t timer;
1892+ pthread_mutex_t mutex;
1893+ bool destroy;
1894+};
1895+
1896+C_MODE_START
1897+static void timer_callback(my_timer_t *);
1898+C_MODE_END
1899+
1900+/**
1901+ Allocate and initialize a thread timer object.
1902+
1903+ @return NULL on failure.
1904+*/
1905+
1906+static thd_timer_t *
1907+thd_timer_create(void)
1908+{
1909+ thd_timer_t *ttp;
1910+ DBUG_ENTER("thd_timer_create");
1911+
1912+ ttp= (thd_timer_t *) my_malloc(sizeof(*ttp), MYF(MY_WME | MY_ZEROFILL));
1913+
1914+ if (ttp == NULL)
1915+ DBUG_RETURN(NULL);
1916+
1917+ ttp->timer.notify_function= timer_callback;
1918+ pthread_mutex_init(&ttp->mutex, MY_MUTEX_INIT_FAST);
1919+
1920+ if (! my_os_timer_create(&ttp->timer))
1921+ DBUG_RETURN(ttp);
1922+
1923+ pthread_mutex_destroy(&ttp->mutex);
1924+ my_free(ttp);
1925+
1926+ DBUG_RETURN(NULL);
1927+}
1928+
1929+
1930+/**
1931+ Release resources allocated for a thread timer.
1932+
1933+ @param ttp Thread timer object.
1934+*/
1935+
1936+static void
1937+thd_timer_destroy(thd_timer_t *ttp)
1938+{
1939+ DBUG_ENTER("thd_timer_destroy");
1940+
1941+ my_os_timer_delete(&ttp->timer);
1942+ pthread_mutex_destroy(&ttp->mutex);
1943+ my_free(ttp);
1944+
1945+ DBUG_VOID_RETURN;
1946+}
1947+
1948+
1949+/**
1950+ Notify a thread (session) that its timer has expired.
1951+
1952+ @param ttp Thread timer object.
1953+
1954+ @return true if the object should be destroyed.
1955+*/
1956+
1957+static bool
1958+timer_notify(thd_timer_t *ttp)
1959+{
1960+ THD *thd= ttp->thd;
1961+
1962+ DBUG_ASSERT(!ttp->destroy || !thd);
1963+
1964+ /*
1965+ Statement might have finished while the timer notification
1966+ was being delivered. If this is the case, the timer object
1967+ was detached (orphaned) and has no associated session (thd).
1968+ */
1969+ if (thd)
1970+ {
1971+ mysql_mutex_lock(&thd->LOCK_thd_data);
1972+ thd->awake(THD::KILL_TIMEOUT);
1973+ mysql_mutex_unlock(&thd->LOCK_thd_data);
1974+ }
1975+
1976+ /* Mark the object as unreachable. */
1977+ ttp->thd= NULL;
1978+
1979+ return ttp->destroy;
1980+}
1981+
1982+
1983+/**
1984+ Timer expiration notification callback.
1985+
1986+ @param timer Timer (mysys) object.
1987+
1988+ @note Invoked in a separate thread of control.
1989+*/
1990+
1991+static void
1992+timer_callback(my_timer_t *timer)
1993+{
1994+ bool destroy;
1995+ thd_timer_t *ttp;
1996+
1997+ ttp= my_container_of(timer, thd_timer_t, timer);
1998+
1999+ pthread_mutex_lock(&ttp->mutex);
2000+ destroy= timer_notify(ttp);
2001+ pthread_mutex_unlock(&ttp->mutex);
2002+
2003+ if (destroy)
2004+ thd_timer_destroy(ttp);
2005+}
2006+
2007+
2008+/**
2009+ Set the time until the currently running statement is aborted.
2010+
2011+ @param thd Thread (session) context.
2012+ @param ttp Thread timer object.
2013+ @param time Length of time, in milliseconds, until the currently
2014+ running statement is aborted.
2015+
2016+ @return NULL on failure.
2017+*/
2018+
2019+thd_timer_t *
2020+thd_timer_set(THD *thd, thd_timer_t *ttp, unsigned long time)
2021+{
2022+ DBUG_ENTER("thd_timer_set");
2023+
2024+ /* Create a new thread timer object if one was not provided. */
2025+ if (ttp == NULL && (ttp= thd_timer_create()) == NULL)
2026+ DBUG_RETURN(NULL);
2027+
2028+ DBUG_ASSERT(!ttp->destroy && !ttp->thd);
2029+
2030+ /* Mark the notification as pending. */
2031+ ttp->thd= thd;
2032+
2033+ /* Arm the timer. */
2034+ if (! my_os_timer_set(&ttp->timer, time))
2035+ DBUG_RETURN(ttp);
2036+
2037+ /* Dispose of the (cached) timer object. */
2038+ thd_timer_destroy(ttp);
2039+
2040+ DBUG_RETURN(NULL);
2041+}
2042+
2043+
2044+/**
2045+ Reap a (possibly) pending timer object.
2046+
2047+ @param ttp Thread timer object.
2048+
2049+ @return true if the timer object is unreachable.
2050+*/
2051+
2052+static bool
2053+reap_timer(thd_timer_t *ttp, bool pending)
2054+{
2055+ bool unreachable;
2056+
2057+ /* Cannot be tagged for destruction. */
2058+ DBUG_ASSERT(!ttp->destroy);
2059+
2060+ /* If not pending, timer hasn't fired. */
2061+ DBUG_ASSERT(pending || ttp->thd);
2062+
2063+ /*
2064+ The timer object can be reused if the timer was stopped before
2065+ expiring. Otherwise, the timer notification function might be
2066+ executing asynchronously in the context of a separate thread.
2067+ */
2068+ unreachable= pending ? ttp->thd == NULL : true;
2069+
2070+ ttp->thd= NULL;
2071+
2072+ return unreachable;
2073+}
2074+
2075+/**
2076+ Deactivate the given timer.
2077+
2078+ @param ttp Thread timer object.
2079+
2080+ @return NULL if the timer object was orphaned.
2081+ Otherwise, the given timer object is returned.
2082+*/
2083+
2084+thd_timer_t *
2085+thd_timer_reset(thd_timer_t *ttp)
2086+{
2087+ bool unreachable;
2088+ int status, state;
2089+ DBUG_ENTER("thd_timer_reset");
2090+
2091+ status= my_os_timer_reset(&ttp->timer, &state);
2092+
2093+ /*
2094+ If the notification function cannot possibly run anymore, cache
2095+ the timer object as there are no outstanding references to it.
2096+ */
2097+ pthread_mutex_lock(&ttp->mutex);
2098+ unreachable= reap_timer(ttp, status ? true : !state);
2099+ ttp->destroy= unreachable ? false : true;
2100+ pthread_mutex_unlock(&ttp->mutex);
2101+
2102+ DBUG_RETURN(unreachable ? ttp : NULL);
2103+}
2104+
2105+
2106+/**
2107+ Release resources allocated for a given thread timer.
2108+
2109+ @param ttp Thread timer object.
2110+*/
2111+
2112+void
2113+thd_timer_end(thd_timer_t *ttp)
2114+{
2115+ DBUG_ENTER("thd_timer_end");
2116+
2117+ thd_timer_destroy(ttp);
2118+
2119+ DBUG_VOID_RETURN;
2120+}
2121+
2122
2123=== added file 'Percona-Server/sql/sql_timer.h'
2124--- Percona-Server/sql/sql_timer.h 1970-01-01 00:00:00 +0000
2125+++ Percona-Server/sql/sql_timer.h 2013-09-09 15:30:42 +0000
2126@@ -0,0 +1,50 @@
2127+/* Copyright (c) 2012, Twitter, Inc. All rights reserved.
2128+
2129+ This program is free software; you can redistribute it and/or modify
2130+ it under the terms of the GNU General Public License as published by
2131+ the Free Software Foundation; version 2 of the License.
2132+
2133+ This program is distributed in the hope that it will be useful,
2134+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2135+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2136+ GNU General Public License for more details.
2137+
2138+ You should have received a copy of the GNU General Public License along
2139+ with this program; if not, write to the Free Software Foundation, Inc.,
2140+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
2141+
2142+#ifndef SQL_TIMER_INCLUDED
2143+#define SQL_TIMER_INCLUDED
2144+
2145+class THD;
2146+struct st_thd_timer;
2147+typedef struct st_thd_timer thd_timer_t;
2148+
2149+#ifdef HAVE_MY_TIMER
2150+
2151+thd_timer_t *thd_timer_set(THD *, thd_timer_t *, unsigned long);
2152+thd_timer_t *thd_timer_reset(thd_timer_t *);
2153+void thd_timer_end(thd_timer_t *);
2154+
2155+#else
2156+
2157+static inline thd_timer_t *
2158+thd_timer_set(THD *, thd_timer_t *, unsigned long)
2159+{
2160+ return NULL;
2161+}
2162+
2163+static inline thd_timer_t *
2164+thd_timer_reset(thd_timer_t *)
2165+{
2166+ return NULL;
2167+}
2168+
2169+static inline void
2170+thd_timer_end(thd_timer_t *)
2171+{
2172+}
2173+
2174+#endif
2175+
2176+#endif /* SQL_TIMER_INCLUDED */
2177
2178=== modified file 'Percona-Server/sql/sys_vars.cc'
2179--- Percona-Server/sql/sys_vars.cc 2013-09-09 07:01:33 +0000
2180+++ Percona-Server/sql/sys_vars.cc 2013-09-09 15:30:42 +0000
2181@@ -2928,6 +2928,12 @@
2182 sql_mode_names, DEFAULT(MODE_NO_ENGINE_SUBSTITUTION), NO_MUTEX_GUARD,
2183 NOT_IN_BINLOG, ON_CHECK(check_sql_mode), ON_UPDATE(fix_sql_mode));
2184
2185+static Sys_var_ulong Sys_max_statement_time(
2186+ "max_statement_time",
2187+ "Kill any statement that takes over the specified number of milliseconds",
2188+ SESSION_VAR(max_statement_time), CMD_LINE(REQUIRED_ARG),
2189+ VALID_RANGE(0, ULONG_MAX), DEFAULT(0), BLOCK_SIZE(1));
2190+
2191 #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
2192 #define SSL_OPT(X) CMD_LINE(REQUIRED_ARG,X)
2193 #else
2194@@ -3966,6 +3972,10 @@
2195 "have_symlink", "have_symlink",
2196 READ_ONLY GLOBAL_VAR(have_symlink), NO_CMD_LINE);
2197
2198+static Sys_var_have Sys_have_statement_timeout(
2199+ "have_statement_timeout", "have_statement_timeout",
2200+ READ_ONLY GLOBAL_VAR(have_statement_timeout), NO_CMD_LINE);
2201+
2202 static bool fix_log_state(sys_var *self, THD *thd, enum_var_type type);
2203 static Sys_var_mybool Sys_general_log(
2204 "general_log", "Log connections and queries to a table or log file. "
2205
2206=== modified file 'Percona-Server/storage/innobase/handler/ha_innodb.cc'
2207--- Percona-Server/storage/innobase/handler/ha_innodb.cc 2013-08-30 13:23:53 +0000
2208+++ Percona-Server/storage/innobase/handler/ha_innodb.cc 2013-09-09 15:30:42 +0000
2209@@ -42,6 +42,7 @@
2210 #include <my_base.h> // HA_OPTION_*
2211 #include <mysys_err.h>
2212 #include <mysql/innodb_priv.h>
2213+#include <mysql/thread_pool_priv.h>
2214
2215 /** @file ha_innodb.cc */
2216
2217@@ -809,6 +810,15 @@
2218 which to close the connection */
2219
2220 /*****************************************************************//**
2221+Cancel any pending lock request associated with the current THD. */
2222+static
2223+void
2224+innobase_kill_connection(
2225+/*======================*/
2226+ handlerton* hton, /*!< in: innobase handlerton */
2227+ THD* thd); /*!< in: handle to the MySQL thread being killed */
2228+
2229+/*****************************************************************//**
2230 Commits a transaction in an InnoDB database or marks an SQL statement
2231 ended.
2232 @return 0 */
2233@@ -1540,8 +1550,8 @@
2234 return(0);
2235
2236 case DB_INTERRUPTED:
2237- my_error(ER_QUERY_INTERRUPTED, MYF(0));
2238- /* fall through */
2239+ thd_set_kill_status(thd ? thd : thd_get_current_thd());
2240+ return(-1);
2241
2242 case DB_FOREIGN_EXCEED_MAX_CASCADE:
2243 ut_ad(thd);
2244@@ -3017,6 +3027,8 @@
2245 = innobase_purge_changed_page_bitmaps;
2246 innobase_hton->is_fake_change = innobase_is_fake_change;
2247
2248+ innobase_hton->kill_connection = innobase_kill_connection;
2249+
2250 ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
2251
2252 #ifndef DBUG_OFF
2253@@ -4199,6 +4211,40 @@
2254 return(ROW_TYPE_NOT_USED);
2255 }
2256
2257+/*****************************************************************//**
2258+Cancel any pending lock request associated with the current THD. */
2259+static
2260+void
2261+innobase_kill_connection(
2262+/*======================*/
2263+ handlerton* hton, /*!< in: innobase handlerton */
2264+ THD* thd) /*!< in: handle to the MySQL thread being killed */
2265+{
2266+ trx_t* trx;
2267+
2268+ DBUG_ENTER("innobase_kill_connection");
2269+ DBUG_ASSERT(hton == innodb_hton_ptr);
2270+
2271+ lock_mutex_enter();
2272+
2273+ trx = thd_to_trx(thd);
2274+
2275+ if (trx)
2276+ {
2277+ trx_mutex_enter(trx);
2278+
2279+ /* Cancel a pending lock request. */
2280+ if (trx->lock.wait_lock)
2281+ lock_cancel_waiting_and_release(trx->lock.wait_lock);
2282+
2283+ trx_mutex_exit(trx);
2284+ }
2285+
2286+ lock_mutex_exit();
2287+
2288+ DBUG_VOID_RETURN;
2289+}
2290+
2291
2292
2293 /****************************************************************//**
2294@@ -11874,7 +11920,7 @@
2295
2296 prebuilt->trx->op_info = "";
2297 if (thd_killed(user_thd)) {
2298- my_error(ER_QUERY_INTERRUPTED, MYF(0));
2299+ thd_set_kill_status(user_thd);
2300 }
2301
2302 if (UNIV_UNLIKELY(share->ib_table->is_corrupt)) {
2303
2304=== modified file 'Percona-Server/storage/innobase/include/lock0lock.h'
2305--- Percona-Server/storage/innobase/include/lock0lock.h 2013-08-06 15:16:34 +0000
2306+++ Percona-Server/storage/innobase/include/lock0lock.h 2013-09-09 15:30:42 +0000
2307@@ -498,6 +498,16 @@
2308 lock_trx_release_locks(
2309 /*===================*/
2310 trx_t* trx); /*!< in/out: transaction */
2311+
2312+/*********************************************************************//**
2313+Cancels a waiting lock request and releases possible other transactions
2314+waiting behind it. */
2315+UNIV_INTERN
2316+void
2317+lock_cancel_waiting_and_release(
2318+/*============================*/
2319+ lock_t* lock); /*!< in/out: waiting lock request */
2320+
2321 /*********************************************************************//**
2322 Removes locks on a table to be dropped or truncated.
2323 If remove_also_table_sx_locks is TRUE then table-level S and X locks are
2324
2325=== modified file 'Percona-Server/storage/innobase/include/lock0priv.h'
2326--- Percona-Server/storage/innobase/include/lock0priv.h 2013-06-10 20:44:22 +0000
2327+++ Percona-Server/storage/innobase/include/lock0priv.h 2013-09-09 15:30:42 +0000
2328@@ -98,15 +98,6 @@
2329 ulint heap_no);/*!< in: heap number of the record */
2330
2331 /*********************************************************************//**
2332-Cancels a waiting lock request and releases possible other transactions
2333-waiting behind it. */
2334-UNIV_INTERN
2335-void
2336-lock_cancel_waiting_and_release(
2337-/*============================*/
2338- lock_t* lock); /*!< in/out: waiting lock request */
2339-
2340-/*********************************************************************//**
2341 Checks if some transaction has an implicit x-lock on a record in a clustered
2342 index.
2343 @return transaction id of the transaction which has the x-lock, or 0 */
2344
2345=== added directory 'Percona-Server/unittest/mysys'
2346=== added file 'Percona-Server/unittest/mysys/my_timer-t.c'
2347--- Percona-Server/unittest/mysys/my_timer-t.c 1970-01-01 00:00:00 +0000
2348+++ Percona-Server/unittest/mysys/my_timer-t.c 2013-09-09 15:30:42 +0000
2349@@ -0,0 +1,263 @@
2350+/* Copyright (c) 2012, Twitter, Inc. All rights reserved.
2351+
2352+ This program is free software; you can redistribute it and/or modify
2353+ it under the terms of the GNU General Public License as published by
2354+ the Free Software Foundation; version 2 of the License.
2355+
2356+ This program is distributed in the hope that it will be useful,
2357+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2358+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2359+ GNU General Public License for more details.
2360+
2361+ You should have received a copy of the GNU General Public License along
2362+ with this program; if not, write to the Free Software Foundation, Inc.,
2363+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
2364+
2365+#include "m_string.h"
2366+#include "my_timer.h"
2367+#include "thr_template.c"
2368+
2369+typedef struct
2370+{
2371+ my_timer_t timer;
2372+ unsigned int fired;
2373+ pthread_mutex_t mutex;
2374+ pthread_cond_t cond;
2375+} test_timer_t;
2376+
2377+static void timer_notify_function(my_timer_t *timer)
2378+{
2379+ test_timer_t *test= my_container_of(timer, test_timer_t, timer);
2380+
2381+ pthread_mutex_lock(&test->mutex);
2382+ test->fired++;
2383+ pthread_cond_signal(&test->cond);
2384+ pthread_mutex_unlock(&test->mutex);
2385+}
2386+
2387+static void test_timer_create(test_timer_t *test)
2388+{
2389+ memset(test, 0, sizeof(test_timer_t));
2390+ pthread_mutex_init(&test->mutex, NULL);
2391+ pthread_cond_init(&test->cond, NULL);
2392+ ok(my_os_timer_create(&test->timer) == 0, "my_os_timer_create");
2393+ test->timer.notify_function= timer_notify_function;
2394+}
2395+
2396+static void test_timer_destroy(test_timer_t *test)
2397+{
2398+ pthread_mutex_destroy(&test->mutex);
2399+ pthread_cond_destroy(&test->cond);
2400+ my_os_timer_delete(&test->timer);
2401+}
2402+
2403+static void test_create_and_delete(void)
2404+{
2405+ int rc;
2406+ my_timer_t timer;
2407+
2408+ diag("test_create_and_delete");
2409+
2410+ memset(&timer, 0, sizeof(timer));
2411+
2412+ rc= my_os_timer_create(&timer);
2413+ ok(rc == 0, "my_os_timer_create");
2414+
2415+ my_os_timer_delete(&timer);
2416+}
2417+
2418+static void test_reset(void)
2419+{
2420+ int rc, state;
2421+ test_timer_t test;
2422+
2423+ diag("test_reset");
2424+
2425+ test_timer_create(&test);
2426+
2427+ rc= my_os_timer_set(&test.timer, 3600000U);
2428+ ok(rc == 0, "my_os_timer_set");
2429+
2430+ rc= my_os_timer_reset(&test.timer, &state);
2431+ ok(rc == 0, "my_os_timer_reset");
2432+
2433+ ok(state == 1, "timer state is nonsignaled");
2434+ ok(test.fired == 0, "timer has not fired");
2435+
2436+ test_timer_destroy(&test);
2437+}
2438+
2439+static void test_timer(void)
2440+{
2441+ int rc, state;
2442+ test_timer_t test;
2443+
2444+ diag("test_timer");
2445+
2446+ test_timer_create(&test);
2447+
2448+ pthread_mutex_lock(&test.mutex);
2449+
2450+ rc= my_os_timer_set(&test.timer, 5);
2451+ ok(rc == 0, "my_os_timer_set");
2452+
2453+ ok(test.fired == 0, "not fired yet");
2454+
2455+ while (!test.fired)
2456+ pthread_cond_wait(&test.cond, &test.mutex);
2457+
2458+ ok(test.fired == 1, "timer fired once");
2459+
2460+ rc= my_os_timer_reset(&test.timer, &state);
2461+ ok(rc == 0, "my_os_timer_reset");
2462+
2463+ ok(state == 0, "timer state was signaled");
2464+
2465+ pthread_mutex_unlock(&test.mutex);
2466+
2467+ test_timer_destroy(&test);
2468+}
2469+
2470+static void timer_set_and_wait(test_timer_t *test, unsigned int fired_count)
2471+{
2472+ int rc, state;
2473+
2474+ rc= my_os_timer_set(&test->timer, 5);
2475+ ok(rc == 0, "my_os_timer_set");
2476+
2477+ ok(test->fired != fired_count, "not fired yet");
2478+
2479+ while (test->fired != fired_count)
2480+ pthread_cond_wait(&test->cond, &test->mutex);
2481+
2482+ ok(test->fired == fired_count, "timer fired");
2483+
2484+ rc= my_os_timer_reset(&test->timer, &state);
2485+ ok(rc == 0, "my_os_timer_reset");
2486+
2487+ ok(state == 0, "timer state was signaled");
2488+}
2489+
2490+static void test_timer_reuse(void)
2491+{
2492+ test_timer_t test;
2493+
2494+ diag("test_timer_reuse");
2495+
2496+ test_timer_create(&test);
2497+
2498+ pthread_mutex_lock(&test.mutex);
2499+
2500+ timer_set_and_wait(&test, 1);
2501+ timer_set_and_wait(&test, 2);
2502+ timer_set_and_wait(&test, 3);
2503+
2504+ pthread_mutex_unlock(&test.mutex);
2505+
2506+ test_timer_destroy(&test);
2507+}
2508+
2509+static void test_independent_timers(void)
2510+{
2511+ int rc, state;
2512+ test_timer_t test;
2513+
2514+ diag("test_independent_timers");
2515+
2516+ test_timer_create(&test);
2517+
2518+ rc= my_os_timer_set(&test.timer, 3600000U);
2519+ ok(rc == 0, "my_os_timer_set");
2520+
2521+ test_timer();
2522+
2523+ rc= my_os_timer_reset(&test.timer, &state);
2524+ ok(rc == 0, "my_os_timer_reset");
2525+
2526+ ok(state == 1, "timer state is nonsignaled");
2527+ ok(test.fired == 0, "timer has not fired");
2528+
2529+ test_timer_destroy(&test);
2530+}
2531+
2532+static void test_timer_no_tap(void)
2533+{
2534+ int rc, state;
2535+ test_timer_t test;
2536+
2537+ memset(&test, 0, sizeof(test_timer_t));
2538+
2539+ pthread_mutex_init(&test.mutex, NULL);
2540+ pthread_cond_init(&test.cond, NULL);
2541+
2542+ test.timer.notify_function= timer_notify_function;
2543+
2544+ rc= my_os_timer_create(&test.timer);
2545+ assert(rc == 0);
2546+
2547+ pthread_mutex_lock(&test.mutex);
2548+
2549+ rc= my_os_timer_set(&test.timer, 5);
2550+ assert(rc == 0);
2551+
2552+ assert(test.fired == 0); /* not fired yet */
2553+
2554+ while (!test.fired)
2555+ pthread_cond_wait(&test.cond, &test.mutex);
2556+
2557+ assert(test.fired == 1); /* timer fired once */
2558+
2559+ rc= my_os_timer_reset(&test.timer, &state);
2560+ assert(rc == 0);
2561+
2562+ assert(state == 0); /* timer state was signaled */
2563+
2564+ pthread_mutex_unlock(&test.mutex);
2565+
2566+ pthread_mutex_destroy(&test.mutex);
2567+ pthread_cond_destroy(&test.cond);
2568+ my_os_timer_delete(&test.timer);
2569+}
2570+
2571+static pthread_handler_t test_timer_per_thread(void *arg)
2572+{
2573+ int iter= *(int *) arg;
2574+
2575+ while (iter--)
2576+ test_timer_no_tap();
2577+
2578+ pthread_mutex_lock(&mutex);
2579+ if (!--running_threads)
2580+ pthread_cond_signal(&cond);
2581+ pthread_mutex_unlock(&mutex);
2582+
2583+ return NULL;
2584+}
2585+
2586+static void test_reinitialization(void)
2587+{
2588+ diag("test_reinitialization");
2589+
2590+ my_os_timer_deinit();
2591+ ok(my_os_timer_init_ext() == 0, "my_os_timer_init_ext");
2592+ test_timer();
2593+ my_os_timer_deinit();
2594+ ok(my_os_timer_init_ext() == 0, "my_os_timer_init_ext");
2595+}
2596+
2597+void do_tests()
2598+{
2599+ plan(49);
2600+
2601+ ok(my_os_timer_init_ext() == 0, "my_os_timer_init_ext");
2602+
2603+ test_create_and_delete();
2604+ test_reset();
2605+ test_timer();
2606+ test_timer_reuse();
2607+ test_independent_timers();
2608+ test_concurrently("per-thread", test_timer_per_thread, THREADS, 5);
2609+ test_reinitialization();
2610+
2611+ my_os_timer_deinit();
2612+}

Subscribers

People subscribed via source and target branches