MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
processlist_val.inc
1 ########### suite/funcs_1/datadict/processlist_val.inc #########################
2 # #
3 # Testing of values within INFORMATION_SCHEMA.PROCESSLIST #
4 # #
5 # Ensure that the values fit to the current state of the connection and #
6 # especially that they change if a connection does nothing or runs some SQL. #
7 # runs some SQL. #
8 # Examples: #
9 # - change the default database #
10 # - send some period of time no SQL command to the server #
11 # - send a long running query #
12 # #
13 # Note(mleich): #
14 # 1. Please inform me if this test fails because of timing problems. #
15 # 2. Storage engine variants of this test do not make sense. #
16 # - I_S tables use the MEMORY storage engine whenever possible. #
17 # - There are some I_S tables which need column data types which are not #
18 # supported by MEMORY. Example: LONGTEXT/BLOB #
19 # MyISAM will be used for such tables. #
20 # The column PROCESSLIST.INFO is of data type LONGTEXT ----> MyISAM #
21 # - There is no impact of the GLOBAL(server) or SESSION default storage #
22 # engine setting on the engine used for I_S tables. #
23 # That means we cannot get NDB or InnoDB instead. #
24 # 3. The SHOW (FULL) PROCESSLIST command are for comparison. #
25 # The main test target is INFORMATION_SCHEMA.PROCESSLIST ! #
26 # 4. Attention: #
27 # The values of the PROCESSLIST columns HOST and TIME tend to cause #
28 # problems and therefore their printing has to be suppressed. #
29 # Examples of the exact values: #
30 # HOST: 'localhost' (UNIX derivates) #
31 # 'localhost:<varying_port>' (WINDOWS) #
32 # TIME: In many cases within this test 0 seconds but if the testing box is #
33 # overloaded we might get up to 2 seconds. #
34 # Solution: #
35 # --replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME> #
36 # 5. How to debug the script? #
37 # <graphical diff tool> \ #
38 # suite/funcs_1/datadict/processlist_val.inc \ #
39 # <Result|Reject|Log file> #
40 # I tweaked a lot of the script lines around "echo" so that you will get a #
41 # lot of useful synchronisation. #
42 # #
43 # Creation: #
44 # 2007-08-09 mleich Implement this test as part of #
45 # WL#3982 Test information_schema.processlist #
46 # #
47 # Last Modification: #
48 # 2008-07-04 mleich Fix for #
49 # Bug#37853 Test "funcs_1.processlist_val_ps" fails in #
50 # various ways #
51 # - issues with printing of port (Win only) #
52 # - too optimistic assumptions about timing #
53 # + corrections of logic in poll routines #
54 # + minor improvements #
55 ################################################################################
56 
57 # Basic preparations
58 --error 0, ER_CANNOT_USER
59 DROP USER test_user@'localhost';
60 CREATE USER test_user@'localhost';
61 GRANT ALL ON *.* TO test_user@'localhost';
62 REVOKE PROCESS ON *.* FROM test_user@'localhost';
63 SET PASSWORD FOR test_user@'localhost' = PASSWORD('ddictpass');
64 --disable_warnings
65 DROP TABLE IF EXISTS test.t1;
66 --enable_warnings
67 CREATE TABLE test.t1 (f1 BIGINT);
68 USE test;
69 
70 
71 echo
72 # Show the definition of the PROCESSLIST table
73 #--------------------------------------------------------------------------
74 ;
75 SHOW CREATE TABLE INFORMATION_SCHEMA.PROCESSLIST;
76 
77 echo
78 # Ensure that the information about the own connection is correct.
79 #--------------------------------------------------------------------------
80 ;
81 # Expected values
82 # - USER = 'root'
83 # - HOST (printed value is unified), the exact values are often like
84 # UNIX: 'localhost'
85 # WIN: 'localhost:<some port>'
86 # - DB = 'test'
87 # - Command IN (no protocol -> 'Query', ps-protocol -> 'Execute')
88 # - TIME (printed value will be unified), the exact values are like
89 # "normal" load: 0 (seconds)
90 # "heavy" load: 1 or more (seconds)
91 # - State 'executing'
92 # - INFO must contain the corresponding SHOW/SELECT PROCESSLIST
93 #
94 # 1. Just dump what we get
95 --replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME>
96 --sorted_result
97 SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
98 --replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME>
99 --sorted_result
100 SHOW FULL PROCESSLIST;
101 #
102 # Determine the connection id of the current connection (default)
103 SET @default_id = CONNECTION_ID();
104 #
105 # 2. There must be exact one connection with @default_id;
106 SELECT COUNT(*) = 1 AS "Expect exact one connection with this id"
107 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @default_id;
108 #
109 # 3. Check the remaining stuff
110 SELECT COUNT(*) = 1 AS "Expect 1"
111 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @default_id
112  AND USER = 'root' AND DB = 'test' AND Command IN('Query','Execute')
113  AND State = 'executing';
114 #
115 # 4. Change the DB
116 USE information_schema;
117 SELECT COUNT(*) = 1 AS "Is the DB correct?"
118 FROM INFORMATION_SCHEMA.PROCESSLIST
119 WHERE ID = @default_id AND DB = 'information_schema';
120 #
121 # 5. Change the statement
122 let $my_statement =
123 SELECT @my_info := INFO FROM INFORMATION_SCHEMA.PROCESSLIST
124 WHERE ID = @default_id;
125 eval $my_statement;
126 eval
127 SELECT @my_info = '$my_statement'
128  AS 'Is the content of PROCESSLIST.INFO correct?';
129 #
130 # 6. TIME must have a reasonable value
131 SELECT COUNT(*) = 1 AS "Has TIME a reasonable value?"
132 FROM INFORMATION_SCHEMA.PROCESSLIST
133 WHERE ID = @default_id AND 0 <= TIME < 10;
134 
135 
136 echo
137 # Ensure that the information about an inactive connection is correct.
138 #--------------------------------------------------------------------------
139 ;
140 echo
141 # ----- establish connection con1 (user = test_user) -----
142 ;
143 connect (con1,localhost,test_user,ddictpass,information_schema);
144 #
145 echo
146 # ----- switch to connection default (user = root) -----
147 ;
148 connection default;
149 # We have now a second connection.
150 # First working phase for the new connection is with Command = 'Connect'.
151 # This is a very short phase and the likelihood to meet it is
152 # - nearly zero on average boxes with low parallel load
153 # - around some percent on weak or overloaded boxes
154 # (Bug#32153 Status output differs - scheduling ?)
155 # Therefore we do not try to catch this state.
156 # We poll till we reach the long lasting phase with Command = 'Sleep'.
157 # - USER = 'test_user'
158 # - DB = 'information_schema'
159 # - Command = 'Sleep'
160 # - State is empty
161 # - INFO IS NULL
162 echo
163 # Poll till the connection con1 is in state COMMAND = 'Sleep'.
164 ;
165 let $wait_timeout= 10;
166 let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST
167  WHERE COMMAND = 'Sleep' AND USER = 'test_user';
168 --source include/wait_condition.inc
169 # 1. Just dump what we get
170 --replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME>
171 --sorted_result
172 SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
173 --replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME>
174 --sorted_result
175 SHOW FULL PROCESSLIST;
176 #
177 # Pull ID and TIME of the second connection
178 SELECT ID,TIME INTO @test_user_con1_id,@time FROM INFORMATION_SCHEMA.PROCESSLIST
179 WHERE COMMAND = 'Sleep' AND USER = 'test_user';
180 #
181 # 2. The second connection must (behaviour at least since 2007) have an
182 # ID = ID_of_previous_connection + 1
183 SELECT @test_user_con1_id = @default_id + 1
184  AS "Did we got the next higher PROCESSLIST ID?";
185 #
186 # 3. TIME must have a reasonable value
187 SELECT 0 <= @time < 10 AS "Has TIME a reasonable value?";
188 #
189 # 4. HOST must be for both connections similar (varying port on Win)
190 SELECT COUNT(*) = 2 AS "Is HOST LIKE 'localhost%'?"
191 FROM INFORMATION_SCHEMA.PROCESSLIST
192 WHERE HOST LIKE 'localhost%';
193 #
194 # 5. Check the remaining stuff
195 SELECT COUNT(*) = 1 AS "Expect 1"
196 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = @test_user_con1_id
197  AND USER = 'test_user' AND DB = 'information_schema'
198  AND Command = 'Sleep' AND State = '' AND INFO IS NULL;
199 #
200 # 6. Check that TIME increases
201 let $wait_timeout= 10;
202 let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST
203  WHERE COMMAND = 'Sleep' AND USER = 'test_user'
204  AND TIME > @time;
205 --source include/wait_condition.inc
206 
207 
208 echo
209 # Ensure that the user test_user sees only connections with his username
210 # because he has not the PROCESS privilege.
211 #----------------------------------------------------------------------------
212 ;
213 echo
214 # ----- switch to connection con1 (user = test_user) -----
215 ;
216 connection con1;
217 --replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME>
218 --sorted_result
219 SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
220 --replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME>
221 --sorted_result
222 SHOW FULL PROCESSLIST;
223 
224 
225 echo
226 # Ensure that the user test_user sees all connections with his username.
227 #----------------------------------------------------------------------------
228 ;
229 echo
230 ----- establish connection con2 (user = test_user) ------
231 ;
232 connect (con2,localhost,test_user,ddictpass,information_schema);
233 echo
234 # ----- switch to connection default (user = root) -----
235 ;
236 connection default;
237 # If the testing box is under heavy load we might see within some of the
238 # next queries connection
239 # con2 with Command = 'Connect'
240 # con1 with INFO = 'SHOW FULL PROCESSLIST' and STATE = 'Writing to net'
241 # Both phases are too short to be checked.
242 echo
243 # Poll till all connections of 'test_user' are in a state with COMMAND = 'Sleep'
244 ;
245 let $wait_condition= SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST
246  WHERE USER = 'test_user' AND COMMAND = 'Sleep';
247 --source include/wait_condition.inc
248 echo
249 # ----- switch to connection con2 (user = test_user) -----
250 ;
251 connection con2;
252 # Just dump what we get
253 --replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME>
254 --sorted_result
255 SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
256 --replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME>
257 --sorted_result
258 SHOW FULL PROCESSLIST;
259 #
260 echo
261 # ----- switch to connection default (user = root) -----
262 ;
263 connection default;
264 # Pull the ID of con2, we will need it later
265 SELECT ID INTO @test_user_con2_id FROM INFORMATION_SCHEMA.PROCESSLIST
266 WHERE ID <> @test_user_con1_id
267  AND USER = 'test_user' AND DB = 'information_schema';
268 
269 
270 echo
271 # Ensure we get correct information about a connection during work
272 #----------------------------------------------------------------------------
273 ;
274 echo
275 # ----- switch to connection con2 (user = test_user) -----
276 ;
277 connection con2;
278 # "Organise" a long running command to be observed by the root user.
279 echo
280 # Send a long enough running statement to the server, but do not
281 # wait till the result comes back.
282 ;
283 # Worst case scenario (=high I/O load on testing box):
284 # - My experience:
285 # Up to 2 seconds runtime per SELECT ... FROM INFORMATION_SCHEMA.PROCESSLIST
286 # in rare cases.
287 # - The following sequence contains ~ 4 of such SELECTs
288 # Therefore we sleep 10 seconds.
289 let $sleep_command =
290 SELECT sleep(10), 17;
291 send;
292 eval $sleep_command;
293 #
294 echo
295 # ----- switch to connection default (user = root) -----
296 ;
297 connection default;
298 echo
299 # Poll till connection con2 is in state 'User sleep'.
300 ;
301 # Expect to see within the processlist the other connection just during
302 # statement execution.
303 # - USER = 'test_user'
304 # - DB = 'information_schema'
305 # - Command = 'Query'(run without --ps-protocol)/'Execute' (run --ps-protocol)
306 # - TIME >= 0
307 # - State = 'User sleep'
308 # - INFO = $sleep_command
309 let $wait_condition=
310 SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST
311 WHERE ID = @test_user_con2_id AND Command IN('Query','Execute')
312  AND State = 'User sleep' AND INFO IS NOT NULL ;
313 --source include/wait_condition.inc
314 # 1. Just dump what we get
315 --replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME>
316 --sorted_result
317 SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
318 --replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME>
319 --sorted_result
320 SHOW FULL PROCESSLIST;
321 #
322 # Pull some information about the connection con2
323 SELECT STATE, TIME, INFO INTO @state, @time, @info
324 FROM INFORMATION_SCHEMA.PROCESSLIST
325 WHERE ID = @test_user_con2_id;
326 # 2. TIME must have a reasonable value
327 SELECT 0 <= @time < 10 AS "Has TIME a reasonable value?";
328 # 3. STATE must be 'User sleep'
329 SELECT @state = 'User sleep' AS "Has STATE the expected value?";
330 # 4. INFO must fit
331 eval SELECT @info = '$sleep_command' AS "Has INFO the expected value?";
332 # 5. Check that TIME increases
333 let $wait_timeout= 10;
334 let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST
335  WHERE ID = @test_user_con2_id AND INFO IS NOT NULL AND TIME > @time;
336 --source include/wait_condition.inc
337 echo
338 # ----- switch to connection con2 (user = testuser) -----
339 ;
340 connection con2;
341 echo
342 # Pull("reap") the result set from the statement executed with "send".
343 ;
344 reap;
345 echo
346 # ----- switch to connection default (user = root) -----
347 ;
348 connection default;
349 echo
350 # Poll till all connections of 'test_user' are in a state with COMMAND = 'Sleep'
351 ;
352 let $wait_timeout= 10;
353 let $wait_condition= SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.PROCESSLIST
354  WHERE COMMAND = 'Sleep' AND USER = 'test_user';
355 --source include/wait_condition.inc
356 
357 
358 echo
359 # Ensure that we see that a connection "hangs" when colliding with a
360 # WRITE TABLE LOCK
361 #----------------------------------------------------------------------------
362 ;
363 LOCK TABLE test.t1 WRITE;
364 #
365 echo
366 # ----- switch to connection con2 (user = test_user) -----
367 ;
368 connection con2;
369 echo
370 # Send a statement to the server, but do not wait till the result
371 # comes back. We will pull this later.
372 ;
373 send
374 SELECT COUNT(*) FROM test.t1;
375 echo
376 # ----- switch to connection default (user = root) -----
377 ;
378 connection default;
379 echo
380 # Poll till INFO is no more NULL and State = 'Waiting for table metadata lock'.
381 ;
382 let $wait_condition= SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST
383  WHERE INFO IS NOT NULL AND STATE = 'Waiting for table metadata lock';
384 --source include/wait_condition.inc
385 #
386 # Expect to see the state 'Waiting for table metadata lock' for the third
387 # connection because the SELECT collides with the WRITE TABLE LOCK.
388 --replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME>
389 --sorted_result
390 SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
391 UNLOCK TABLES;
392 #
393 echo
394 # ----- switch to connection con2 (user = test_user) -----
395 ;
396 connection con2;
397 echo
398 # Pull("reap") the result set from the statement executed with "send".
399 ;
400 reap;
401 
402 
403 echo
404 # Ensure that SHOW/SELECT processlist can handle extreme long commands
405 #----------------------------------------------------------------------------
406 ;
407 # We do not want to waste runtime, therefore we run the following test based
408 # on "Lock collision" and not with some "sleep(10)".
409 echo
410 # ----- switch to connection default (user = root) -----
411 ;
412 connection default;
413 LOCK TABLE test.t1 WRITE;
414 #
415 echo
416 # ----- switch to connection con2 (user = test_user) -----
417 ;
418 connection con2;
419 echo
420 # Send a long (~20 KB code) statement to the server, but do not wait
421 # till the result comes back. We will pull this later.
422 ;
423 let $string=
424 `SELECT CONCAT('BEGIN-',
425  REPEAT('This is the representative of a very long statement.',400),
426  '-END')`;
427 let $my_statement =
428 SELECT count(*),'$string' AS "Long string" FROM test.t1;
429 send;
430 eval $my_statement;
431 echo
432 # ----- switch to connection default (user = root) -----
433 ;
434 connection default;
435 echo
436 # Poll till INFO is no more NULL and State = 'Waiting for table metadata lock'.
437 ;
438 let $wait_condition= SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST
439  WHERE INFO IS NOT NULL AND STATE = 'Waiting for table metadata lock';
440 --source include/wait_condition.inc
441 echo
442 # Expect result:
443 # Statement Content of INFO
444 # SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST Complete statement
445 # SHOW FULL PROCESSLIST Complete statement
446 # SHOW PROCESSLIST statement truncated after 100 char
447 ;
448 --replace_column 1 <ID> 3 <HOST_NAME> 5 <COMMAND> 6 <TIME> 7 <STATE>
449 --sorted_result
450 SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
451 --replace_column 1 <ID> 3 <HOST_NAME> 5 <COMMAND> 6 <TIME> 7 <STATE>
452 --sorted_result
453 SHOW FULL PROCESSLIST;
454 --replace_column 1 <ID> 3 <HOST_NAME> 5 <COMMAND> 6 <TIME> 7 <STATE>
455 --sorted_result
456 SHOW PROCESSLIST;
457 UNLOCK TABLES;
458 echo
459 # ----- switch to connection con2 (user = test_user) -----
460 ;
461 connection con2;
462 echo
463 # Pull("reap") the result set from the monster statement executed with "send".
464 ;
465 reap;
466 
467 
468 # Cleanup
469 echo
470 # ----- switch to connection default (user = root) -----
471 ;
472 connection default;
473 echo
474 ----- disconnect con1 and con2 -----
475 ;
476 disconnect con1;
477 disconnect con2;
478 DROP USER test_user@'localhost';
479 DROP TABLE test.t1;