Merge lp:~percona-toolkit-dev/percona-toolkit/pt-kill-reconnect-bug-941469 into lp:percona-toolkit/2.1
- pt-kill-reconnect-bug-941469
- Merge into 2.1
Proposed by
Daniel Nichter
Status: | Merged |
---|---|
Approved by: | Daniel Nichter |
Approved revision: | 313 |
Merged at revision: | 311 |
Proposed branch: | lp:~percona-toolkit-dev/percona-toolkit/pt-kill-reconnect-bug-941469 |
Merge into: | lp:percona-toolkit/2.1 |
Diff against target: |
612 lines (+402/-33) 7 files modified
bin/pt-kill (+317/-23) lib/Cxn.pm (+5/-1) t/pt-kill/basics.t (+30/-4) t/pt-kill/execute_command.t (+4/-3) t/pt-kill/kill.t (+1/-1) t/pt-kill/standard_options.t (+1/-1) util/kill-mysql-process (+44/-0) |
To merge this branch: | bzr merge lp:~percona-toolkit-dev/percona-toolkit/pt-kill-reconnect-bug-941469 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Daniel Nichter | Approve | ||
Review via email: mp+114748@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
- 312. By Daniel Nichter
-
Retry for an hour to get proclist; retry KILL once.
- 313. By Daniel Nichter
-
Stabilize some pt-kill tests.
Revision history for this message
Daniel Nichter (daniel-nichter) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bin/pt-kill' |
2 | --- bin/pt-kill 2012-07-12 16:55:54 +0000 |
3 | +++ bin/pt-kill 2012-07-12 23:28:21 +0000 |
4 | @@ -3686,6 +3686,232 @@ |
5 | # ########################################################################### |
6 | |
7 | # ########################################################################### |
8 | +# Retry package |
9 | +# This package is a copy without comments from the original. The original |
10 | +# with comments and its test file can be found in the Bazaar repository at, |
11 | +# lib/Retry.pm |
12 | +# t/lib/Retry.t |
13 | +# See https://launchpad.net/percona-toolkit for more information. |
14 | +# ########################################################################### |
15 | +{ |
16 | +package Retry; |
17 | + |
18 | +use strict; |
19 | +use warnings FATAL => 'all'; |
20 | +use English qw(-no_match_vars); |
21 | +use constant PTDEBUG => $ENV{PTDEBUG} || 0; |
22 | + |
23 | +sub new { |
24 | + my ( $class, %args ) = @_; |
25 | + my $self = { |
26 | + %args, |
27 | + }; |
28 | + return bless $self, $class; |
29 | +} |
30 | + |
31 | +sub retry { |
32 | + my ( $self, %args ) = @_; |
33 | + my @required_args = qw(try fail final_fail); |
34 | + foreach my $arg ( @required_args ) { |
35 | + die "I need a $arg argument" unless $args{$arg}; |
36 | + }; |
37 | + my ($try, $fail, $final_fail) = @args{@required_args}; |
38 | + my $wait = $args{wait} || sub { sleep 1; }; |
39 | + my $tries = $args{tries} || 3; |
40 | + |
41 | + my $last_error; |
42 | + my $tryno = 0; |
43 | + TRY: |
44 | + while ( ++$tryno <= $tries ) { |
45 | + PTDEBUG && _d("Try", $tryno, "of", $tries); |
46 | + my $result; |
47 | + eval { |
48 | + $result = $try->(tryno=>$tryno); |
49 | + }; |
50 | + if ( $EVAL_ERROR ) { |
51 | + PTDEBUG && _d("Try code failed:", $EVAL_ERROR); |
52 | + $last_error = $EVAL_ERROR; |
53 | + |
54 | + if ( $tryno < $tries ) { # more retries |
55 | + my $retry = $fail->(tryno=>$tryno, error=>$last_error); |
56 | + last TRY unless $retry; |
57 | + PTDEBUG && _d("Calling wait code"); |
58 | + $wait->(tryno=>$tryno); |
59 | + } |
60 | + } |
61 | + else { |
62 | + PTDEBUG && _d("Try code succeeded"); |
63 | + return $result; |
64 | + } |
65 | + } |
66 | + |
67 | + PTDEBUG && _d('Try code did not succeed'); |
68 | + return $final_fail->(error=>$last_error); |
69 | +} |
70 | + |
71 | +sub _d { |
72 | + my ($package, undef, $line) = caller 0; |
73 | + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } |
74 | + map { defined $_ ? $_ : 'undef' } |
75 | + @_; |
76 | + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; |
77 | +} |
78 | + |
79 | +1; |
80 | +} |
81 | +# ########################################################################### |
82 | +# End Retry package |
83 | +# ########################################################################### |
84 | + |
85 | +# ########################################################################### |
86 | +# Cxn package |
87 | +# This package is a copy without comments from the original. The original |
88 | +# with comments and its test file can be found in the Bazaar repository at, |
89 | +# lib/Cxn.pm |
90 | +# t/lib/Cxn.t |
91 | +# See https://launchpad.net/percona-toolkit for more information. |
92 | +# ########################################################################### |
93 | +{ |
94 | +package Cxn; |
95 | + |
96 | +use strict; |
97 | +use warnings FATAL => 'all'; |
98 | +use English qw(-no_match_vars); |
99 | +use Scalar::Util qw(blessed); |
100 | +use constant { |
101 | + PTDEBUG => $ENV{PTDEBUG} || 0, |
102 | + PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0, |
103 | +}; |
104 | + |
105 | +sub new { |
106 | + my ( $class, %args ) = @_; |
107 | + my @required_args = qw(DSNParser OptionParser); |
108 | + foreach my $arg ( @required_args ) { |
109 | + die "I need a $arg argument" unless $args{$arg}; |
110 | + }; |
111 | + my ($dp, $o) = @args{@required_args}; |
112 | + |
113 | + my $dsn_defaults = $dp->parse_options($o); |
114 | + my $prev_dsn = $args{prev_dsn}; |
115 | + my $dsn = $args{dsn}; |
116 | + if ( !$dsn ) { |
117 | + $args{dsn_string} ||= 'h=' . ($dsn_defaults->{h} || 'localhost'); |
118 | + |
119 | + $dsn = $dp->parse( |
120 | + $args{dsn_string}, $prev_dsn, $dsn_defaults); |
121 | + } |
122 | + elsif ( $prev_dsn ) { |
123 | + $dsn = $dp->copy($prev_dsn, $dsn); |
124 | + } |
125 | + |
126 | + my $self = { |
127 | + dsn => $dsn, |
128 | + dbh => $args{dbh}, |
129 | + dsn_name => $dp->as_string($dsn, [qw(h P S)]), |
130 | + hostname => '', |
131 | + set => $args{set}, |
132 | + NAME_lc => $args{NAME_lc}, |
133 | + dbh_set => 0, |
134 | + OptionParser => $o, |
135 | + DSNParser => $dp, |
136 | + }; |
137 | + |
138 | + return bless $self, $class; |
139 | +} |
140 | + |
141 | +sub connect { |
142 | + my ( $self ) = @_; |
143 | + my $dsn = $self->{dsn}; |
144 | + my $dp = $self->{DSNParser}; |
145 | + my $o = $self->{OptionParser}; |
146 | + |
147 | + my $dbh = $self->{dbh}; |
148 | + if ( !$dbh || !$dbh->ping() ) { |
149 | + if ( $o->get('ask-pass') && !$self->{asked_for_pass} ) { |
150 | + $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); |
151 | + $self->{asked_for_pass} = 1; |
152 | + } |
153 | + $dbh = $dp->get_dbh($dp->get_cxn_params($dsn), { AutoCommit => 1 }); |
154 | + } |
155 | + PTDEBUG && _d($dbh, 'Connected dbh to', $self->{name}); |
156 | + |
157 | + return $self->set_dbh($dbh); |
158 | +} |
159 | + |
160 | +sub set_dbh { |
161 | + my ($self, $dbh) = @_; |
162 | + |
163 | + if ( $self->{dbh} && $self->{dbh} == $dbh && $self->{dbh_set} ) { |
164 | + PTDEBUG && _d($dbh, 'Already set dbh'); |
165 | + return $dbh; |
166 | + } |
167 | + |
168 | + PTDEBUG && _d($dbh, 'Setting dbh'); |
169 | + |
170 | + if ( !exists $self->{NAME_lc} |
171 | + || (defined $self->{NAME_lc} && $self->{NAME_lc}) ) { |
172 | + $dbh->{FetchHashKeyName} = 'NAME_lc'; |
173 | + } |
174 | + |
175 | + my $sql = 'SELECT @@hostname, @@server_id'; |
176 | + PTDEBUG && _d($dbh, $sql); |
177 | + my ($hostname, $server_id) = $dbh->selectrow_array($sql); |
178 | + PTDEBUG && _d($dbh, 'hostname:', $hostname, $server_id); |
179 | + if ( $hostname ) { |
180 | + $self->{hostname} = $hostname; |
181 | + } |
182 | + |
183 | + if ( my $set = $self->{set}) { |
184 | + $set->($dbh); |
185 | + } |
186 | + |
187 | + $self->{dbh} = $dbh; |
188 | + $self->{dbh_set} = 1; |
189 | + return $dbh; |
190 | +} |
191 | + |
192 | +sub dbh { |
193 | + my ($self) = @_; |
194 | + return $self->{dbh}; |
195 | +} |
196 | + |
197 | +sub dsn { |
198 | + my ($self) = @_; |
199 | + return $self->{dsn}; |
200 | +} |
201 | + |
202 | +sub name { |
203 | + my ($self) = @_; |
204 | + return $self->{dsn_name} if PERCONA_TOOLKIT_TEST_USE_DSN_NAMES; |
205 | + return $self->{hostname} || $self->{dsn_name} || 'unknown host'; |
206 | +} |
207 | + |
208 | +sub DESTROY { |
209 | + my ($self) = @_; |
210 | + if ( $self->{dbh} |
211 | + && blessed($self->{dbh}) |
212 | + && $self->{dbh}->can("disconnect") ) { |
213 | + PTDEBUG && _d('Disconnecting dbh', $self->{dbh}, $self->{name}); |
214 | + $self->{dbh}->disconnect(); |
215 | + } |
216 | + return; |
217 | +} |
218 | + |
219 | +sub _d { |
220 | + my ($package, undef, $line) = caller 0; |
221 | + @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } |
222 | + map { defined $_ ? $_ : 'undef' } |
223 | + @_; |
224 | + print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; |
225 | +} |
226 | + |
227 | +1; |
228 | +} |
229 | +# ########################################################################### |
230 | +# End Cxn package |
231 | +# ########################################################################### |
232 | + |
233 | +# ########################################################################### |
234 | # This is a combination of modules and programs in one -- a runnable module. |
235 | # http://www.perl.com/pub/a/2006/07/13/lightning-articles.html?page=last |
236 | # Or, look it up in the Camel book on pages 642 and 643 in the 3rd edition. |
237 | @@ -3798,10 +4024,10 @@ |
238 | # ######################################################################## |
239 | # Make input sub that will either get processlist from MySQL or a file. |
240 | # ######################################################################## |
241 | - my $dsn; |
242 | - my $dbh; |
243 | - my $kill_sth; |
244 | - my $get_proclist; |
245 | + my $cxn; |
246 | + my $dbh; # $cxn->dbh |
247 | + my $get_proclist; # callback to SHOW PROCESSLIST |
248 | + my $kill; # callback to KILL |
249 | my $files; |
250 | if ( $files = $o->get('test-matching') ) { |
251 | PTDEBUG && _d('Getting processlist from files:', @$files); |
252 | @@ -3840,14 +4066,83 @@ |
253 | } |
254 | else { |
255 | PTDEBUG && _d('Getting processlist from MySQL'); |
256 | - $dsn = $dp->parse_options($o); |
257 | - $dbh = get_cxn($dp, $dsn, 1); |
258 | - $kill_sth = $o->get('kill-query') ? $dbh->prepare('KILL QUERY ?') |
259 | - : $dbh->prepare('KILL ?'); |
260 | + $cxn = Cxn->new( |
261 | + dsn_string => shift @ARGV, |
262 | + NAME_lc => 0, |
263 | + DSNParser => $dp, |
264 | + OptionParser => $o, |
265 | + ); |
266 | + $dbh = $cxn->connect(); |
267 | + |
268 | + # Make the get_proclist and kill callbacks. Use Retry in case |
269 | + # the connection to MySQL is lost, then the dbh and the sths |
270 | + # will need to be re-initialized. |
271 | + my $retry = Retry->new(); |
272 | + |
273 | my $proc_sth = $dbh->prepare('SHOW FULL PROCESSLIST'); |
274 | $get_proclist = sub { |
275 | - $proc_sth->execute(); |
276 | - return $proc_sth->fetchall_arrayref({}); |
277 | + return $retry->retry( |
278 | + # Retry for an hour: 1,200 tries x 3 seconds = 3600s/1hr |
279 | + tries => 1200, |
280 | + wait => sub { sleep 3; }, |
281 | + try => sub { |
282 | + $proc_sth->execute(); |
283 | + return $proc_sth->fetchall_arrayref({}); |
284 | + }, |
285 | + fail => sub { |
286 | + my (%args) = @_; |
287 | + my $error = $args{error}; |
288 | + # The 1st pattern means that MySQL itself died or was stopped. |
289 | + # The 2nd pattern means that our cxn was killed (KILL <id>). |
290 | + if ( $error =~ m/MySQL server has gone away/ |
291 | + || $error =~ m/Lost connection to MySQL server/ ) { |
292 | + eval { |
293 | + $dbh = $cxn->connect(); |
294 | + $proc_sth = $dbh->prepare('SHOW FULL PROCESSLIST'); |
295 | + msg('Reconnected to ' . $cxn->name()); |
296 | + }; |
297 | + return 1 unless $EVAL_ERROR; # try again |
298 | + } |
299 | + return 0; # call final_fail |
300 | + }, |
301 | + final_fail => sub { |
302 | + my (%args) = @_; |
303 | + die $args{error}; |
304 | + }, |
305 | + ); |
306 | + }; |
307 | + |
308 | + my $kill_sql = $o->get('kill-query') ? 'KILL QUERY ?' : 'KILL ?'; |
309 | + my $kill_sth = $dbh->prepare($kill_sql); |
310 | + $kill = sub { |
311 | + my ($id) = @_; |
312 | + PTDEBUG && _d('Killing process', $id); |
313 | + return $retry->retry( |
314 | + tries => 2, |
315 | + try => sub { |
316 | + return $kill_sth->execute($id); |
317 | + }, |
318 | + fail => sub { |
319 | + my (%args) = @_; |
320 | + my $error = $args{error}; |
321 | + # The 1st pattern means that MySQL itself died or was stopped. |
322 | + # The 2nd pattern means that our cxn was killed (KILL <id>). |
323 | + if ( $error =~ m/MySQL server has gone away/ |
324 | + || $error =~ m/Lost connection to MySQL server/ ) { |
325 | + eval { |
326 | + $dbh = $cxn->connect(); |
327 | + $kill_sth = $dbh->prepare($kill_sql); |
328 | + msg('Reconnected to ' . $cxn->name()); |
329 | + }; |
330 | + return 1 unless $EVAL_ERROR; # try again |
331 | + } |
332 | + return 0; # call final_fail |
333 | + }, |
334 | + final_fail => sub { |
335 | + my (%args) = @_; |
336 | + die $args{error}; |
337 | + }, |
338 | + ); |
339 | }; |
340 | } |
341 | |
342 | @@ -3870,7 +4165,7 @@ |
343 | # Start working. |
344 | # ######################################################################## |
345 | msg("$PROGRAM_NAME starting"); |
346 | - msg($dbh ? "Connected to host " . $dp->as_string($dsn) |
347 | + msg($dbh ? "Connected to host " . $cxn->name() |
348 | : "Test matching files @$files"); |
349 | |
350 | # Class-based match criteria. |
351 | @@ -4054,7 +4349,7 @@ |
352 | . " seconds before kill"); |
353 | sleep $o->get('wait-before-kill'); |
354 | } |
355 | - eval { $kill_sth->execute($query->{Id}); }; |
356 | + eval { $kill->($query->{Id}) }; |
357 | if ( $EVAL_ERROR ) { |
358 | msg("Error killing $query->{Id}: $EVAL_ERROR"); |
359 | } |
360 | @@ -4093,16 +4388,6 @@ |
361 | # Subroutines. |
362 | # ############################################################################ |
363 | |
364 | -sub get_cxn { |
365 | - my ( $dp, $dsn, $ac ) = @_; |
366 | - if ( $o->get('ask-pass') ) { |
367 | - $dsn->{p} = OptionParser::prompt_noecho("Enter password: "); |
368 | - } |
369 | - my $dbh = $dp->get_dbh($dp->get_cxn_params($dsn), {AutoCommit => $ac}); |
370 | - $dbh->{InactiveDestroy} = 1; # Because of forking. |
371 | - return $dbh; |
372 | -} |
373 | - |
374 | # Forks and detaches from parent to execute the given command; |
375 | # does not block parent. |
376 | sub exec_cmd { |
377 | @@ -4187,7 +4472,7 @@ |
378 | |
379 | =head1 SYNOPSIS |
380 | |
381 | -Usage: pt-kill [OPTIONS] |
382 | +Usage: pt-kill [OPTIONS] [DSN] |
383 | |
384 | pt-kill kills MySQL connections. pt-kill connects to MySQL and gets queries |
385 | from SHOW PROCESSLIST if no FILE is given. Else, it reads queries from one |
386 | @@ -4326,6 +4611,9 @@ |
387 | |
388 | L<"--daemonize"> and L<"--test-matching"> are mutually exclusive. |
389 | |
390 | +This tool accepts additional command-line arguments. Refer to the |
391 | +L<"SYNOPSIS"> and usage information for details. |
392 | + |
393 | =over |
394 | |
395 | =item --ask-pass |
396 | @@ -4348,6 +4636,12 @@ |
397 | Read this comma-separated list of config files; if specified, this must be the |
398 | first option on the command line. |
399 | |
400 | +=item --database |
401 | + |
402 | +short form: -D; type: string |
403 | + |
404 | +The database to use for the connection. |
405 | + |
406 | =item --daemonize |
407 | |
408 | Fork to the background and detach from the shell. POSIX operating systems |
409 | |
410 | === modified file 'lib/Cxn.pm' |
411 | --- lib/Cxn.pm 2012-06-05 19:24:32 +0000 |
412 | +++ lib/Cxn.pm 2012-07-12 23:28:21 +0000 |
413 | @@ -103,6 +103,7 @@ |
414 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), |
415 | hostname => '', |
416 | set => $args{set}, |
417 | + NAME_lc => $args{NAME_lc}, |
418 | dbh_set => 0, |
419 | OptionParser => $o, |
420 | DSNParser => $dp, |
421 | @@ -149,7 +150,10 @@ |
422 | PTDEBUG && _d($dbh, 'Setting dbh'); |
423 | |
424 | # Set stuff for this dbh (i.e. initialize it). |
425 | - $dbh->{FetchHashKeyName} = 'NAME_lc'; |
426 | + if ( !exists $self->{NAME_lc} |
427 | + || (defined $self->{NAME_lc} && $self->{NAME_lc}) ) { |
428 | + $dbh->{FetchHashKeyName} = 'NAME_lc'; |
429 | + } |
430 | |
431 | # Update the cxn's name. Until we connect, the DSN parts |
432 | # h and P are used. Once connected, use @@hostname. |
433 | |
434 | === modified file 't/pt-kill/basics.t' |
435 | --- t/pt-kill/basics.t 2012-06-03 19:14:30 +0000 |
436 | +++ t/pt-kill/basics.t 2012-07-12 23:28:21 +0000 |
437 | @@ -4,6 +4,7 @@ |
438 | die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n" |
439 | unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH}; |
440 | unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib"; |
441 | + $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} = 1; |
442 | }; |
443 | |
444 | use strict; |
445 | @@ -25,7 +26,7 @@ |
446 | plan skip_all => 'Cannot connect to sandbox master'; |
447 | } |
448 | else { |
449 | - plan tests => 4; |
450 | + plan tests => 6; |
451 | } |
452 | |
453 | my $output; |
454 | @@ -52,7 +53,7 @@ |
455 | ok( |
456 | @times > 2 && @times < 7, |
457 | "There were 2 to 5 captures" |
458 | -) or print STDERR Dumper($output); |
459 | +) or diag($output); |
460 | |
461 | # This is to catch a bad bug where there wasn't any sleep time when |
462 | # --iterations was 0, and another bug when --run-time was not respected. |
463 | @@ -64,8 +65,7 @@ |
464 | ok( |
465 | @times > 7 && @times < 12, |
466 | 'Approximately 9 or 10 captures with --iterations 0' |
467 | -) or print STDERR Dumper($output); |
468 | - |
469 | +) or diag($output); |
470 | |
471 | # ############################################################################ |
472 | # --verbose |
473 | @@ -81,6 +81,32 @@ |
474 | ); |
475 | |
476 | # ############################################################################# |
477 | +# Reconnect if cxn lost. |
478 | +# ############################################################################# |
479 | +$master_dbh->do("CREATE DATABASE IF NOT EXISTS pt_kill_test"); |
480 | + |
481 | +system(qq($trunk/util/kill-mysql-process db=pt_kill_test wait=2 &)); |
482 | + |
483 | +$output = output( |
484 | + sub { pt_kill::main('-F', $cnf, qw(-D pt_kill_test), |
485 | + qw(--run-time 4 --interval 1 --print --verbose)) }, |
486 | + stderr => 1, |
487 | +); |
488 | + |
489 | +like( |
490 | + $output, |
491 | + qr/Reconnected/, |
492 | + "kill-mysql-process says it reconnected" |
493 | +); |
494 | + |
495 | +my $n_checks =()= $output =~ m/Checking processlist/g; |
496 | +is( |
497 | + $n_checks, |
498 | + 4, |
499 | + "pt-kill still checked the processlist 4 times" |
500 | +) or diag($output); |
501 | + |
502 | +# ############################################################################# |
503 | # Done. |
504 | # ############################################################################# |
505 | $sb->wipe_clean($master_dbh); |
506 | |
507 | === modified file 't/pt-kill/execute_command.t' |
508 | --- t/pt-kill/execute_command.t 2012-06-03 19:14:30 +0000 |
509 | +++ t/pt-kill/execute_command.t 2012-07-12 23:28:21 +0000 |
510 | @@ -47,6 +47,7 @@ |
511 | |
512 | SKIP: { |
513 | skip 'Cannot connect to sandbox master', 2 unless $master_dbh; |
514 | + $master_dbh->do("CREATE DATABASE IF NOT EXISTS pt_kill_zombie_test"); |
515 | |
516 | system "/tmp/12345/use -e 'select sleep(2)' >/dev/null 2>&1 &"; |
517 | |
518 | @@ -70,7 +71,7 @@ |
519 | diag(`rm $out`); |
520 | |
521 | # Don't make zombies (https://bugs.launchpad.net/percona-toolkit/+bug/919819) |
522 | - system "/tmp/12345/use -e 'select sleep(2)' >/dev/null 2>&1 &"; |
523 | + $master_dbh->do("USE pt_kill_zombie_test"); |
524 | |
525 | my $sentinel = "/tmp/pt-kill-test.$PID.stop"; |
526 | my $pid_file = "/tmp/pt-kill-test.$PID.pid"; |
527 | @@ -79,8 +80,8 @@ |
528 | diag(`rm $pid_file 2>/dev/null`); |
529 | diag(`rm $log_file 2>/dev/null`); |
530 | |
531 | - `$cmd --daemonize --match-info 'select sleep' --interval 1 --print --execute-command 'echo zombie > $out' --verbose --pid $pid_file --log $log_file --sentinel $sentinel`; |
532 | - sleep 1; |
533 | + `$cmd --daemonize --match-db pt_kill_zombie_test --interval 1 --print --execute-command 'echo zombie > $out' --verbose --pid $pid_file --log $log_file --sentinel $sentinel`; |
534 | + PerconaTest::wait_for_files($pid_file, $log_file, $out); |
535 | $output = `grep Executed $log_file`; |
536 | like( |
537 | $output, |
538 | |
539 | === modified file 't/pt-kill/kill.t' |
540 | --- t/pt-kill/kill.t 2012-06-03 19:14:30 +0000 |
541 | +++ t/pt-kill/kill.t 2012-07-12 23:28:21 +0000 |
542 | @@ -41,7 +41,7 @@ |
543 | |
544 | # Shell out to a sleep(10) query and try to capture the query. |
545 | # Backticks don't work here. |
546 | -system("/tmp/12345/use -h127.1 -P12345 -umsandbox -pmsandbox -e 'select sleep(4)' >/dev/null&"); |
547 | +system("/tmp/12345/use -h127.1 -P12345 -umsandbox -pmsandbox -e 'select sleep(4)' >/dev/null 2>&1 &"); |
548 | sleep 0.5; |
549 | my $rows = $dbh->selectall_hashref('show processlist', 'id'); |
550 | my $pid; |
551 | |
552 | === modified file 't/pt-kill/standard_options.t' |
553 | --- t/pt-kill/standard_options.t 2012-06-05 15:56:56 +0000 |
554 | +++ t/pt-kill/standard_options.t 2012-07-12 23:28:21 +0000 |
555 | @@ -48,7 +48,7 @@ |
556 | 'Log file created' |
557 | ); |
558 | |
559 | - sleep 3; # --run-time=2; if we sleep 2 we'll get intermittent failures. |
560 | + wait_until(sub { return !-f '/tmp/pt-kill.pid' }); |
561 | ok( |
562 | !-f '/tmp/pt-kill.pid', |
563 | 'PID file removed' |
564 | |
565 | === added file 'util/kill-mysql-process' |
566 | --- util/kill-mysql-process 1970-01-01 00:00:00 +0000 |
567 | +++ util/kill-mysql-process 2012-07-12 23:28:21 +0000 |
568 | @@ -0,0 +1,44 @@ |
569 | +#!/usr/bin/env perl |
570 | + |
571 | +# This script helps test that tools reconnect to MySQL. Its meant to be ran |
572 | +# in the background like system(qq($trunk/util/kill-mysql-process DB)) where |
573 | +# DB is the name of special "tracer" database used to isolate the test in |
574 | +# the process list. So, do something like CREATE DATABASE pt_kill_test, then |
575 | +# run the test with D=pt_kill_test (presuming pt_kill_test is unique to |
576 | +# the test). This script will then kill any and all processes that are using |
577 | +# the pt_kill_test db. |
578 | +# |
579 | +# Exits 0 if the tracer db is observed and procs are killed, else exits 1. |
580 | + |
581 | +use strict; |
582 | +use warnings FATAL => 'all'; |
583 | +use Time::HiRes qw(sleep time); |
584 | + |
585 | +if ( !@ARGV || @ARGV < 1 || @ARGV > 3 ) { |
586 | + print STDERR "Usage: kill-mysql-process OPTION=VALUE\n"; |
587 | + print STDERR "Options: db, wait, runtime, interval\n"; |
588 | + exit 1; |
589 | +} |
590 | + |
591 | +my %opt = map { my ($op, $val) = split '=', $_; $op => $val; } @ARGV; |
592 | + |
593 | +$opt{db} ||= 'tracer_db'; |
594 | +$opt{runtime} ||= 5.0; |
595 | +$opt{interval} ||= 0.2; |
596 | + |
597 | +sleep $opt{wait} if $opt{wait}; |
598 | + |
599 | +my $t_start = time; |
600 | +while ( time - $t_start < $opt{runtime} ) { |
601 | + my $procs = `/tmp/12345/use -ss -e "show processlist" | grep $opt{db} | cut -f1`; |
602 | + if ( $procs && $procs =~ /\d/ ) { |
603 | + foreach my $proc ( split "\n", $procs ) { |
604 | + chomp $proc; |
605 | + `/tmp/12345/use -e "KILL $proc"`; |
606 | + } |
607 | + exit 0; |
608 | + } |
609 | + sleep $opt{interval}; |
610 | +} |
611 | + |
612 | +exit 1; |