~tsarev/percona-server/test55_716210

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# name       : innodb_kill_idle_transaction.patch
# introduced : 5.5.14
# maintainer : Yasufumi
#
#!!! notice !!!
# Any small change to this file in the main branch
# should be done or reviewed by the maintainer!
diff -ruN a/include/mysql/plugin.h b/include/mysql/plugin.h
--- a/include/mysql/plugin.h	2011-06-22 01:42:39.000000000 +0900
+++ b/include/mysql/plugin.h	2011-07-12 22:19:58.000000000 +0900
@@ -625,6 +625,12 @@
 */
 void thd_set_ha_data(MYSQL_THD thd, const struct handlerton *hton,
                      const void *ha_data);
+
+int thd_command(const MYSQL_THD thd);
+long long thd_start_time(const MYSQL_THD thd);
+void thd_kill(MYSQL_THD thd);
+#define EXTENDED_FOR_KILLIDLE
+
 #ifdef __cplusplus
 }
 #endif
diff -ruN a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp
--- a/include/mysql/plugin_audit.h.pp	2011-06-22 01:42:39.000000000 +0900
+++ b/include/mysql/plugin_audit.h.pp	2011-07-13 00:53:06.000000000 +0900
@@ -195,6 +195,9 @@
 void *thd_get_ha_data(const void* thd, const struct handlerton *hton);
 void thd_set_ha_data(void* thd, const struct handlerton *hton,
                      const void *ha_data);
+int thd_command(const void* thd);
+long long thd_start_time(const void* thd);
+void thd_kill(void* thd);
 struct mysql_event_general
 {
   unsigned int event_subclass;
diff -ruN a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp
--- a/include/mysql/plugin_auth.h.pp	2011-06-22 01:42:39.000000000 +0900
+++ b/include/mysql/plugin_auth.h.pp	2011-07-13 00:53:06.000000000 +0900
@@ -195,6 +195,9 @@
 void *thd_get_ha_data(const void* thd, const struct handlerton *hton);
 void thd_set_ha_data(void* thd, const struct handlerton *hton,
                      const void *ha_data);
+int thd_command(const void* thd);
+long long thd_start_time(const void* thd);
+void thd_kill(void* thd);
 #include <mysql/plugin_auth_common.h>
 typedef struct st_plugin_vio_info
 {
diff -ruN a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp
--- a/include/mysql/plugin_ftparser.h.pp	2011-06-22 01:42:39.000000000 +0900
+++ b/include/mysql/plugin_ftparser.h.pp	2011-07-13 00:53:06.000000000 +0900
@@ -148,6 +148,9 @@
 void *thd_get_ha_data(const void* thd, const struct handlerton *hton);
 void thd_set_ha_data(void* thd, const struct handlerton *hton,
                      const void *ha_data);
+int thd_command(const void* thd);
+long long thd_start_time(const void* thd);
+void thd_kill(void* thd);
 enum enum_ftparser_mode
 {
   MYSQL_FTPARSER_SIMPLE_MODE= 0,
diff -ruN a/sql/sql_class.cc b/sql/sql_class.cc
--- a/sql/sql_class.cc	2011-06-22 01:42:40.000000000 +0900
+++ b/sql/sql_class.cc	2011-07-12 22:23:35.000000000 +0900
@@ -711,6 +711,26 @@
   return buffer;
 }
 
+/* extend for kill session of idle transaction from engine */
+extern "C"
+int thd_command(const THD* thd)
+{
+  return (int) thd->command;
+}
+
+extern "C"
+long long thd_start_time(const THD* thd)
+{
+  return (long long) thd->start_time;
+}
+
+extern "C"
+void thd_kill(THD* thd)
+{
+  mysql_mutex_lock(&thd->LOCK_thd_data);
+  thd->awake(THD::KILL_CONNECTION);
+  mysql_mutex_unlock(&thd->LOCK_thd_data);
+}
 
 /**
   Implementation of Drop_table_error_handler::handle_condition().
diff -ruN a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
--- a/storage/innobase/handler/ha_innodb.cc	2011-07-12 17:10:37.000000000 +0900
+++ b/storage/innobase/handler/ha_innodb.cc	2011-07-12 22:33:06.000000000 +0900
@@ -2828,6 +2828,10 @@
 
 	innobase_commit_concurrency_init_default();
 
+#ifndef EXTENDED_FOR_KILLIDLE
+	srv_kill_idle_transaction = 0;
+#endif
+
 #ifdef HAVE_PSI_INTERFACE
 	/* Register keys with MySQL performance schema */
 	if (PSI_server) {
@@ -11586,6 +11590,48 @@
 	return(false);
 }
 
+/***********************************************************************
+functions for kill session of idle transaction */
+extern "C"
+ibool
+innobase_thd_is_idle(
+/*=================*/
+	const void*	thd)	/*!< in: thread handle (THD*) */
+{
+#ifdef EXTENDED_FOR_KILLIDLE
+	return(thd_command((const THD*) thd) == COM_SLEEP);
+#else
+	return(FALSE);
+#endif
+}
+
+extern "C"
+ib_int64_t
+innobase_thd_get_start_time(
+/*========================*/
+	const void*	thd)	/*!< in: thread handle (THD*) */
+{
+#ifdef EXTENDED_FOR_KILLIDLE
+	return((ib_int64_t)thd_start_time((const THD*) thd));
+#else
+	return(0); /*dummy value*/
+#endif
+}
+
+extern "C"
+void
+innobase_thd_kill(
+/*==============*/
+	void*	thd)
+{
+#ifdef EXTENDED_FOR_KILLIDLE
+	thd_kill((THD*) thd);
+#else
+	return;
+#endif
+}
+
+
 static SHOW_VAR innodb_status_variables_export[]= {
   {"Innodb",                   (char*) &show_innodb_vars, SHOW_FUNC},
   {NullS, NullS, SHOW_LONG}
@@ -11872,6 +11918,15 @@
   "Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket",
   NULL, NULL, 500L, 1L, ~0L, 0);
 
+static MYSQL_SYSVAR_LONG(kill_idle_transaction, srv_kill_idle_transaction,
+  PLUGIN_VAR_RQCMDARG,
+#ifdef EXTENDED_FOR_KILLIDLE
+  "If non-zero value, the idle session with transaction which is idle over the value in seconds is killed by InnoDB.",
+#else
+  "No effect for this build.",
+#endif
+  NULL, NULL, 0, 0, LONG_MAX, 0);
+
 static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads,
   PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY | PLUGIN_VAR_NOSYSVAR,
   "Number of file I/O threads in InnoDB.",
@@ -12162,6 +12217,7 @@
   MYSQL_SYSVAR(fast_checksum),
   MYSQL_SYSVAR(commit_concurrency),
   MYSQL_SYSVAR(concurrency_tickets),
+  MYSQL_SYSVAR(kill_idle_transaction),
   MYSQL_SYSVAR(data_file_path),
   MYSQL_SYSVAR(doublewrite_file),
   MYSQL_SYSVAR(data_home_dir),
diff -ruN a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
--- a/storage/innobase/include/srv0srv.h	2011-07-12 17:10:37.000000000 +0900
+++ b/storage/innobase/include/srv0srv.h	2011-07-12 22:33:57.000000000 +0900
@@ -291,6 +291,7 @@
 extern ulint	srv_activity_count;
 extern ulint	srv_fatal_semaphore_wait_threshold;
 extern ulint	srv_dml_needed_delay;
+extern lint	srv_kill_idle_transaction;
 
 extern mutex_t*	kernel_mutex_temp;/* mutex protecting the server, trx structs,
 				query threads, and lock table: we allocate
diff -ruN a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
--- a/storage/innobase/include/trx0trx.h	2011-07-12 16:47:24.000000000 +0900
+++ b/storage/innobase/include/trx0trx.h	2011-07-12 22:35:39.000000000 +0900
@@ -594,6 +594,8 @@
 					replication has processed */
 	const char*	mysql_relay_log_file_name;
 	ib_int64_t	mysql_relay_log_pos;
+	time_t		idle_start;
+	ib_int64_t	last_stmt_start;
 	/*------------------------------*/
 	ulint		n_mysql_tables_in_use; /* number of Innobase tables
 					used in the processing of the current
diff -ruN a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
--- a/storage/innobase/srv/srv0srv.c	2011-07-12 17:10:37.000000000 +0900
+++ b/storage/innobase/srv/srv0srv.c	2011-07-12 22:43:22.000000000 +0900
@@ -87,6 +87,11 @@
 #include "mysql/plugin.h"
 #include "mysql/service_thd_wait.h"
 
+/* prototypes of new functions added to ha_innodb.cc for kill_idle_transaction */
+ibool		innobase_thd_is_idle(const void* thd);
+ib_int64_t	innobase_thd_get_start_time(const void* thd);
+void		innobase_thd_kill(void* thd);
+
 /* prototypes for new functions added to ha_innodb.cc */
 ibool	innobase_get_slow_log();
 
@@ -97,6 +102,9 @@
 /* The following is the maximum allowed duration of a lock wait. */
 UNIV_INTERN ulint	srv_fatal_semaphore_wait_threshold = 600;
 
+/**/
+UNIV_INTERN lint	srv_kill_idle_transaction = 0;
+
 /* How much data manipulation language (DML) statements need to be delayed,
 in microseconds, in order to reduce the lagging of the purge thread. */
 UNIV_INTERN ulint	srv_dml_needed_delay = 0;
@@ -2826,6 +2834,36 @@
 		old_sema = sema;
 	}
 
+	if (srv_kill_idle_transaction && trx_sys) {
+		trx_t*	trx;
+		time_t	now;
+rescan_idle:
+		now = time(NULL);
+		mutex_enter(&kernel_mutex);
+		trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list);
+		while (trx) {
+			if (trx->conc_state == TRX_ACTIVE
+			    && trx->mysql_thd
+			    && innobase_thd_is_idle(trx->mysql_thd)) {
+				ib_int64_t	start_time; /* as stmt ID */
+
+				start_time = innobase_thd_get_start_time(trx->mysql_thd);
+				if (trx->last_stmt_start != start_time) {
+					trx->idle_start = now;
+					trx->last_stmt_start = start_time;
+				} else if (difftime(now, trx->idle_start)
+					   > srv_kill_idle_transaction) {
+					/* kill the session */
+					mutex_exit(&kernel_mutex);
+					innobase_thd_kill(trx->mysql_thd);
+					goto rescan_idle;
+				}
+			}
+			trx = UT_LIST_GET_NEXT(mysql_trx_list, trx);
+		}
+		mutex_exit(&kernel_mutex);
+	}
+
 	/* Flush stderr so that a database user gets the output
 	to possible MySQL error file */
 
diff -ruN a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c
--- a/storage/innobase/trx/trx0trx.c	2011-07-12 17:05:25.000000000 +0900
+++ b/storage/innobase/trx/trx0trx.c	2011-07-12 22:44:08.000000000 +0900
@@ -143,6 +143,9 @@
 	trx->mysql_relay_log_file_name = "";
 	trx->mysql_relay_log_pos = 0;
 
+	trx->idle_start = 0;
+	trx->last_stmt_start = 0;
+
 	mutex_create(trx_undo_mutex_key, &trx->undo_mutex, SYNC_TRX_UNDO);
 
 	trx->rseg = NULL;