Merge lp:~percona-toolkit-dev/percona-toolkit/validate-load-options-bug-996915 into lp:percona-toolkit/2.1

Proposed by Daniel Nichter
Status: Merged
Merged at revision: 268
Proposed branch: lp:~percona-toolkit-dev/percona-toolkit/validate-load-options-bug-996915
Merge into: lp:percona-toolkit/2.1
Diff against target: 612 lines (+315/-89)
6 files modified
bin/pt-online-schema-change (+91/-31)
bin/pt-table-checksum (+88/-30)
lib/MySQLStatusWaiter.pm (+60/-24)
t/lib/MySQLStatusWaiter.t (+49/-2)
t/pt-online-schema-change/option_sanity.t (+15/-1)
t/pt-table-checksum/option_sanity.t (+12/-1)
To merge this branch: bzr merge lp:~percona-toolkit-dev/percona-toolkit/validate-load-options-bug-996915
Reviewer Review Type Date Requested Status
Daniel Nichter Approve
Review via email: mp+107480@code.launchpad.net
To post a comment you must log in.
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-online-schema-change'
2--- bin/pt-online-schema-change 2012-05-25 16:24:32 +0000
3+++ bin/pt-online-schema-change 2012-05-25 21:39:18 +0000
4@@ -3701,18 +3701,24 @@
5 }
6
7 PTDEBUG && _d('Parsing spec for max thresholds');
8- my $max_val_for = _parse_spec(
9- spec => $args{max_spec},
10- get_status => $args{get_status},
11- threshold_factor => 0.2, # +20%
12- );
13+ my $max_val_for = _parse_spec($args{max_spec});
14+ if ( $max_val_for ) {
15+ _check_and_set_vals(
16+ vars => $max_val_for,
17+ get_status => $args{get_status},
18+ threshold_factor => 0.2, # +20%
19+ );
20+ }
21
22 PTDEBUG && _d('Parsing spec for critical thresholds');
23- my $critical_val_for = _parse_spec(
24- spec => $args{critical_spec} || [],
25- get_status => $args{get_status},
26- threshold_factor => 1.0, # double (x2; +100%)
27- );
28+ my $critical_val_for = _parse_spec($args{critical_spec} || []);
29+ if ( $critical_val_for ) {
30+ _check_and_set_vals(
31+ vars => $critical_val_for,
32+ get_status => $args{get_status},
33+ threshold_factor => 1.0, # double (x2; +100%)
34+ );
35+ }
36
37 my $self = {
38 get_status => $args{get_status},
39@@ -3726,27 +3732,29 @@
40 }
41
42 sub _parse_spec {
43- my ( %args ) = @_;
44- my @required_args = qw(spec get_status);
45- foreach my $arg ( @required_args ) {
46- die "I need a $arg argument" unless defined $args{$arg};
47- }
48- my ($spec, $get_status) = @args{@required_args};
49+ my ($spec) = @_;
50
51 return unless $spec && scalar @$spec;
52- my $threshold_factor = $args{threshold_factor} || 0.20;
53
54 my %max_val_for;
55 foreach my $var_val ( @$spec ) {
56+ die "Empty or undefined spec\n" unless $var_val;
57+ $var_val =~ s/^\s+//;
58+ $var_val =~ s/\s+$//g;
59+
60 my ($var, $val) = split /[:=]/, $var_val;
61- die "Invalid spec: $var_val" unless $var;
62+ die "$var_val does not contain a variable\n" unless $var;
63+ die "$var is not a variable name\n" unless $var =~ m/^[a-zA-Z_]+$/;
64+
65 if ( !$val ) {
66- my $init_val = $get_status->($var);
67- PTDEBUG && _d('Initial', $var, 'value:', $init_val);
68- $val = int(($init_val * $threshold_factor) + $init_val);
69- }
70- PTDEBUG && _d('Wait if', $var, '>=', $val);
71- $max_val_for{$var} = $val;
72+ PTDEBUG && _d('Will get intial value for', $var, 'later');
73+ $max_val_for{$var} = undef;
74+ }
75+ else {
76+ die "The value for $var must be a number\n"
77+ unless $val =~ m/^[\d\.]+$/;
78+ $max_val_for{$var} = $val;
79+ }
80 }
81
82 return \%max_val_for;
83@@ -3826,6 +3834,34 @@
84 return;
85 }
86
87+sub _check_and_set_vals {
88+ my (%args) = @_;
89+ my @required_args = qw(vars get_status threshold_factor);
90+ foreach my $arg ( @required_args ) {
91+ die "I need a $arg argument" unless defined $args{$arg};
92+ }
93+ my ($vars, $get_status, $threshold_factor) = @args{@required_args};
94+
95+ PTDEBUG && _d('Checking and setting values');
96+ return unless $vars && scalar %$vars;
97+
98+ foreach my $var ( keys %$vars ) {
99+ my $init_val = $get_status->($var);
100+ die "Variable $var does not exist or its value is undefined\n"
101+ unless defined $init_val;
102+ my $val;
103+ if ( defined $vars->{$var} ) {
104+ $val = $vars->{$var};
105+ }
106+ else {
107+ PTDEBUG && _d('Initial', $var, 'value:', $init_val);
108+ $val = int(($init_val * $threshold_factor) + $init_val);
109+ $vars->{$var} = $val;
110+ }
111+ PTDEBUG && _d('Wait if', $var, '>=', $val);
112+ }
113+}
114+
115 sub _d {
116 my ($package, undef, $line) = caller 0;
117 @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
118@@ -4979,6 +5015,18 @@
119 # Explicit --chunk-size disable auto chunk sizing.
120 $o->set('chunk-time', 0) if $o->got('chunk-size');
121
122+ foreach my $opt ( qw(max-load critical-load) ) {
123+ next unless $o->has($opt);
124+ my $spec = $o->get($opt);
125+ eval {
126+ MySQLStatusWaiter::_parse_spec($o->get($opt));
127+ };
128+ if ( $EVAL_ERROR ) {
129+ chomp $EVAL_ERROR;
130+ $o->save_error("Invalid --$opt: $EVAL_ERROR");
131+ }
132+ }
133+
134 if ( !$o->get('help') ) {
135 if ( @ARGV ) {
136 $o->save_error('Specify only one DSN on the command line');
137@@ -5226,13 +5274,25 @@
138 };
139 }
140
141- $sys_load = new MySQLStatusWaiter(
142- max_spec => $o->get('max-load'),
143- critical_spec => $o->get('critical-load'),
144- get_status => $get_status,
145- oktorun => sub { return $oktorun },
146- sleep => $sleep,
147- );
148+ eval {
149+ $sys_load = new MySQLStatusWaiter(
150+ max_spec => $o->get('max-load'),
151+ critical_spec => $o->get('critical-load'),
152+ get_status => $get_status,
153+ oktorun => sub { return $oktorun },
154+ sleep => $sleep,
155+ );
156+ };
157+ if ( $EVAL_ERROR ) {
158+ chomp $EVAL_ERROR;
159+ die "Error checking --max-load or --critial-load: $EVAL_ERROR. "
160+ . "Check that the variables specified for --max-load and "
161+ . "--critical-load are spelled correctly and exist in "
162+ . "SHOW GLOBAL STATUS. Current values for these options are:\n"
163+ . " --max-load " . (join(',', @{$o->get('max-load')})) . "\n"
164+ . " --critial-load " . (join(',', @{$o->get('critical-load')}))
165+ . "\n";
166+ }
167
168 if ( $o->get('progress') ) {
169 $replica_lag_pr = new Progress(
170
171=== modified file 'bin/pt-table-checksum'
172--- bin/pt-table-checksum 2012-05-24 17:25:20 +0000
173+++ bin/pt-table-checksum 2012-05-25 21:39:18 +0000
174@@ -5653,18 +5653,24 @@
175 }
176
177 PTDEBUG && _d('Parsing spec for max thresholds');
178- my $max_val_for = _parse_spec(
179- spec => $args{max_spec},
180- get_status => $args{get_status},
181- threshold_factor => 0.2, # +20%
182- );
183+ my $max_val_for = _parse_spec($args{max_spec});
184+ if ( $max_val_for ) {
185+ _check_and_set_vals(
186+ vars => $max_val_for,
187+ get_status => $args{get_status},
188+ threshold_factor => 0.2, # +20%
189+ );
190+ }
191
192 PTDEBUG && _d('Parsing spec for critical thresholds');
193- my $critical_val_for = _parse_spec(
194- spec => $args{critical_spec} || [],
195- get_status => $args{get_status},
196- threshold_factor => 1.0, # double (x2; +100%)
197- );
198+ my $critical_val_for = _parse_spec($args{critical_spec} || []);
199+ if ( $critical_val_for ) {
200+ _check_and_set_vals(
201+ vars => $critical_val_for,
202+ get_status => $args{get_status},
203+ threshold_factor => 1.0, # double (x2; +100%)
204+ );
205+ }
206
207 my $self = {
208 get_status => $args{get_status},
209@@ -5678,27 +5684,29 @@
210 }
211
212 sub _parse_spec {
213- my ( %args ) = @_;
214- my @required_args = qw(spec get_status);
215- foreach my $arg ( @required_args ) {
216- die "I need a $arg argument" unless defined $args{$arg};
217- }
218- my ($spec, $get_status) = @args{@required_args};
219+ my ($spec) = @_;
220
221 return unless $spec && scalar @$spec;
222- my $threshold_factor = $args{threshold_factor} || 0.20;
223
224 my %max_val_for;
225 foreach my $var_val ( @$spec ) {
226+ die "Empty or undefined spec\n" unless $var_val;
227+ $var_val =~ s/^\s+//;
228+ $var_val =~ s/\s+$//g;
229+
230 my ($var, $val) = split /[:=]/, $var_val;
231- die "Invalid spec: $var_val" unless $var;
232+ die "$var_val does not contain a variable\n" unless $var;
233+ die "$var is not a variable name\n" unless $var =~ m/^[a-zA-Z_]+$/;
234+
235 if ( !$val ) {
236- my $init_val = $get_status->($var);
237- PTDEBUG && _d('Initial', $var, 'value:', $init_val);
238- $val = int(($init_val * $threshold_factor) + $init_val);
239- }
240- PTDEBUG && _d('Wait if', $var, '>=', $val);
241- $max_val_for{$var} = $val;
242+ PTDEBUG && _d('Will get intial value for', $var, 'later');
243+ $max_val_for{$var} = undef;
244+ }
245+ else {
246+ die "The value for $var must be a number\n"
247+ unless $val =~ m/^[\d\.]+$/;
248+ $max_val_for{$var} = $val;
249+ }
250 }
251
252 return \%max_val_for;
253@@ -5778,6 +5786,34 @@
254 return;
255 }
256
257+sub _check_and_set_vals {
258+ my (%args) = @_;
259+ my @required_args = qw(vars get_status threshold_factor);
260+ foreach my $arg ( @required_args ) {
261+ die "I need a $arg argument" unless defined $args{$arg};
262+ }
263+ my ($vars, $get_status, $threshold_factor) = @args{@required_args};
264+
265+ PTDEBUG && _d('Checking and setting values');
266+ return unless $vars && scalar %$vars;
267+
268+ foreach my $var ( keys %$vars ) {
269+ my $init_val = $get_status->($var);
270+ die "Variable $var does not exist or its value is undefined\n"
271+ unless defined $init_val;
272+ my $val;
273+ if ( defined $vars->{$var} ) {
274+ $val = $vars->{$var};
275+ }
276+ else {
277+ PTDEBUG && _d('Initial', $var, 'value:', $init_val);
278+ $val = int(($init_val * $threshold_factor) + $init_val);
279+ $vars->{$var} = $val;
280+ }
281+ PTDEBUG && _d('Wait if', $var, '>=', $val);
282+ }
283+}
284+
285 sub _d {
286 my ($package, undef, $line) = caller 0;
287 @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
288@@ -5940,6 +5976,18 @@
289
290 $o->set('chunk-time', 0) if $o->got('chunk-size');
291
292+ foreach my $opt ( qw(max-load critical-load) ) {
293+ next unless $o->has($opt);
294+ my $spec = $o->get($opt);
295+ eval {
296+ MySQLStatusWaiter::_parse_spec($o->get($opt));
297+ };
298+ if ( $EVAL_ERROR ) {
299+ chomp $EVAL_ERROR;
300+ $o->save_error("Invalid --$opt: $EVAL_ERROR");
301+ }
302+ }
303+
304 if ( !$o->get('help') ) {
305 if ( @ARGV > 1 ) {
306 $o->save_error("More than one host specified; only one allowed");
307@@ -6299,12 +6347,22 @@
308 };
309 }
310
311- $sys_load = new MySQLStatusWaiter(
312- max_spec => $o->get('max-load'),
313- get_status => $get_status,
314- oktorun => sub { return $oktorun },
315- sleep => $sleep,
316- );
317+ eval {
318+ $sys_load = new MySQLStatusWaiter(
319+ max_spec => $o->get('max-load'),
320+ get_status => $get_status,
321+ oktorun => sub { return $oktorun },
322+ sleep => $sleep,
323+ );
324+ };
325+ if ( $EVAL_ERROR ) {
326+ chomp $EVAL_ERROR;
327+ die "Error checking --max-load: $EVAL_ERROR. "
328+ . "Check that the variables specified for --max-load "
329+ . "are spelled correctly and exist in "
330+ . "SHOW GLOBAL STATUS. Current value for this option is:\n"
331+ . " --max-load " . (join(',', @{$o->get('max-load')})) . "\n";
332+ }
333
334 if ( $o->get('progress') ) {
335 $replica_lag_pr = new Progress(
336
337=== modified file 'lib/MySQLStatusWaiter.pm'
338--- lib/MySQLStatusWaiter.pm 2012-03-28 01:17:17 +0000
339+++ lib/MySQLStatusWaiter.pm 2012-05-25 21:39:18 +0000
340@@ -45,18 +45,24 @@
341 }
342
343 PTDEBUG && _d('Parsing spec for max thresholds');
344- my $max_val_for = _parse_spec(
345- spec => $args{max_spec},
346- get_status => $args{get_status},
347- threshold_factor => 0.2, # +20%
348- );
349+ my $max_val_for = _parse_spec($args{max_spec});
350+ if ( $max_val_for ) {
351+ _check_and_set_vals(
352+ vars => $max_val_for,
353+ get_status => $args{get_status},
354+ threshold_factor => 0.2, # +20%
355+ );
356+ }
357
358 PTDEBUG && _d('Parsing spec for critical thresholds');
359- my $critical_val_for = _parse_spec(
360- spec => $args{critical_spec} || [],
361- get_status => $args{get_status},
362- threshold_factor => 1.0, # double (x2; +100%)
363- );
364+ my $critical_val_for = _parse_spec($args{critical_spec} || []);
365+ if ( $critical_val_for ) {
366+ _check_and_set_vals(
367+ vars => $critical_val_for,
368+ get_status => $args{get_status},
369+ threshold_factor => 1.0, # double (x2; +100%)
370+ );
371+ }
372
373 my $self = {
374 get_status => $args{get_status},
375@@ -79,27 +85,29 @@
376 # Returns:
377 # Hashref with each variable's maximum permitted value.
378 sub _parse_spec {
379- my ( %args ) = @_;
380- my @required_args = qw(spec get_status);
381- foreach my $arg ( @required_args ) {
382- die "I need a $arg argument" unless defined $args{$arg};
383- }
384- my ($spec, $get_status) = @args{@required_args};
385+ my ($spec) = @_;
386
387 return unless $spec && scalar @$spec;
388- my $threshold_factor = $args{threshold_factor} || 0.20;
389
390 my %max_val_for;
391 foreach my $var_val ( @$spec ) {
392+ die "Empty or undefined spec\n" unless $var_val;
393+ $var_val =~ s/^\s+//;
394+ $var_val =~ s/\s+$//g;
395+
396 my ($var, $val) = split /[:=]/, $var_val;
397- die "Invalid spec: $var_val" unless $var;
398+ die "$var_val does not contain a variable\n" unless $var;
399+ die "$var is not a variable name\n" unless $var =~ m/^[a-zA-Z_]+$/;
400+
401 if ( !$val ) {
402- my $init_val = $get_status->($var);
403- PTDEBUG && _d('Initial', $var, 'value:', $init_val);
404- $val = int(($init_val * $threshold_factor) + $init_val);
405- }
406- PTDEBUG && _d('Wait if', $var, '>=', $val);
407- $max_val_for{$var} = $val;
408+ PTDEBUG && _d('Will get intial value for', $var, 'later');
409+ $max_val_for{$var} = undef;
410+ }
411+ else {
412+ die "The value for $var must be a number\n"
413+ unless $val =~ m/^[\d\.]+$/;
414+ $max_val_for{$var} = $val;
415+ }
416 }
417
418 return \%max_val_for;
419@@ -192,6 +200,34 @@
420 return;
421 }
422
423+sub _check_and_set_vals {
424+ my (%args) = @_;
425+ my @required_args = qw(vars get_status threshold_factor);
426+ foreach my $arg ( @required_args ) {
427+ die "I need a $arg argument" unless defined $args{$arg};
428+ }
429+ my ($vars, $get_status, $threshold_factor) = @args{@required_args};
430+
431+ PTDEBUG && _d('Checking and setting values');
432+ return unless $vars && scalar %$vars;
433+
434+ foreach my $var ( keys %$vars ) {
435+ my $init_val = $get_status->($var);
436+ die "Variable $var does not exist or its value is undefined\n"
437+ unless defined $init_val;
438+ my $val;
439+ if ( defined $vars->{$var} ) {
440+ $val = $vars->{$var};
441+ }
442+ else {
443+ PTDEBUG && _d('Initial', $var, 'value:', $init_val);
444+ $val = int(($init_val * $threshold_factor) + $init_val);
445+ $vars->{$var} = $val;
446+ }
447+ PTDEBUG && _d('Wait if', $var, '>=', $val);
448+ }
449+}
450+
451 sub _d {
452 my ($package, undef, $line) = caller 0;
453 @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
454
455=== modified file 't/lib/MySQLStatusWaiter.t'
456--- t/lib/MySQLStatusWaiter.t 2012-03-28 01:17:17 +0000
457+++ t/lib/MySQLStatusWaiter.t 2012-05-25 21:39:18 +0000
458@@ -9,7 +9,7 @@
459 use strict;
460 use warnings FATAL => 'all';
461 use English qw(-no_match_vars);
462-use Test::More tests => 14;
463+use Test::More tests => 17;
464
465 use MySQLStatusWaiter;
466 use PerconaTest;
467@@ -39,11 +39,48 @@
468 return;
469 }
470
471+# #############################################################################
472+# _parse_spec()
473+# #############################################################################
474+
475+throws_ok(
476+ sub { new MySQLStatusWaiter(
477+ max_spec => [qw(100)],
478+ get_status => \&get_status,
479+ sleep => \&sleep,
480+ oktorun => \&oktorun,
481+ ) },
482+ qr/100 is not a variable name/,
483+ "Catch non-variable name"
484+);
485+
486+throws_ok(
487+ sub { new MySQLStatusWaiter(
488+ max_spec => [qw(foo=bar)],
489+ get_status => \&get_status,
490+ sleep => \&sleep,
491+ oktorun => \&oktorun,
492+ ) },
493+ qr/value for foo must be a number/,
494+ "Catch non-number value"
495+);
496+
497+throws_ok(
498+ sub { new MySQLStatusWaiter(
499+ max_spec => [qw(foo)],
500+ get_status => \&get_status,
501+ sleep => \&sleep,
502+ oktorun => \&oktorun,
503+ ) },
504+ qr/foo does not exist/,
505+ "Catch non-existent variable"
506+);
507+
508 # ############################################################################
509 # Use initial vals + 20%.
510 # ############################################################################
511 @vals = (
512- # initial values
513+ # initial check for existence
514 { Threads_connected => 10, },
515 { Threads_running => 5, },
516
517@@ -68,6 +105,8 @@
518 { Threads_running => 5, },
519 );
520
521+$oktorun = 1;
522+
523 my $sw = new MySQLStatusWaiter(
524 oktorun => \&oktorun,
525 get_status => \&get_status,
526@@ -127,6 +166,10 @@
527 # Use static vals.
528 # ############################################################################
529 @vals = (
530+ # initial check for existence
531+ { Threads_connected => 1, },
532+ { Threads_running => 1, },
533+
534 # first check, no wait
535 { Threads_connected => 1, },
536 { Threads_running => 1, },
537@@ -208,6 +251,10 @@
538 # Critical thresholds (with static vals).
539 # ############################################################################
540 @vals = (
541+ # initial check for existence
542+ { Threads_running => 1, },
543+ { Threads_running => 9, },
544+
545 # first check, no wait
546 { Threads_running => 1, },
547 { Threads_running => 9, },
548
549=== modified file 't/pt-online-schema-change/option_sanity.t'
550--- t/pt-online-schema-change/option_sanity.t 2012-05-25 16:24:32 +0000
551+++ t/pt-online-schema-change/option_sanity.t 2012-05-25 21:39:18 +0000
552@@ -9,7 +9,7 @@
553 use strict;
554 use warnings FATAL => 'all';
555 use English qw(-no_match_vars);
556-use Test::More tests => 6;
557+use Test::More tests => 8;
558
559 use PerconaTest;
560
561@@ -58,6 +58,20 @@
562 "Cannot --alter-foreign-keys-method=drop_swap with --no-drop-new-table"
563 );
564
565+$output = `$cmd h=127.1,P=12345,u=msandbox,p=msandbox,D=mysql,t=user --max-load 100 --alter "ENGINE=MyISAM" --dry-run`;
566+like(
567+ $output,
568+ qr/Invalid --max-load/,
569+ "Validates --max-load"
570+);
571+
572+$output = `$cmd h=127.1,P=12345,u=msandbox,p=msandbox,D=mysql,t=user --critical-load 100 --alter "ENGINE=MyISAM" --dry-run`;
573+like(
574+ $output,
575+ qr/Invalid --critical-load/,
576+ "Validates --critical-load"
577+);
578+
579 # #############################################################################
580 # Done.
581 # #############################################################################
582
583=== modified file 't/pt-table-checksum/option_sanity.t'
584--- t/pt-table-checksum/option_sanity.t 2011-12-27 17:24:35 +0000
585+++ t/pt-table-checksum/option_sanity.t 2012-05-25 21:39:18 +0000
586@@ -9,7 +9,7 @@
587 use strict;
588 use warnings FATAL => 'all';
589 use English qw(-no_match_vars);
590-use Test::More tests => 18;
591+use Test::More tests => 19;
592
593 use PerconaTest;
594 shift @INC; # our unshift (above)
595@@ -157,6 +157,17 @@
596 );
597
598 # #############################################################################
599+# --max-load
600+# #############################################################################
601+
602+$output = `$trunk/bin/pt-table-checksum h=127.1,P=12345 --max-load 100`;
603+like(
604+ $output,
605+ qr/Invalid --max-load/,
606+ "Validates --max-load"
607+);
608+
609+# #############################################################################
610 # Done.
611 # #############################################################################
612 exit;

Subscribers

People subscribed via source and target branches