~percona-toolkit-dev/percona-toolkit/release-2.2.2

507.1.4 by Daniel Nichter
Stripping down pt-upgrade; work in progress.
1
# This program is copyright 2013 Percona Ireland Ltd.
2
# Feedback and improvements are welcome.
3
#
4
# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
5
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
6
# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
7
#
8
# This program is free software; you can redistribute it and/or modify it under
9
# the terms of the GNU General Public License as published by the Free Software
10
# Foundation, version 2; OR the Perl Artistic License.  On UNIX and similar
11
# systems, you can issue `man perlgpl' or `man perlartistic' to read these
12
# licenses.
13
#
14
# You should have received a copy of the GNU General Public License along with
15
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16
# Place, Suite 330, Boston, MA  02111-1307  USA.
17
# ###########################################################################
18
# UpgradeResults package
19
# ###########################################################################
20
{
21
package UpgradeResults;
22
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
23
use strict;
24
use warnings FATAL => 'all';
507.1.4 by Daniel Nichter
Stripping down pt-upgrade; work in progress.
25
use English qw(-no_match_vars);
26
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
27
507.1.30 by Daniel Nichter
eval the critical parts. Use specific exit codes. Add --run-time, --progress, --continue-on-error, and --defaults-file. Uncomment the version check call. Update the docs.
28
use Data::Dumper;
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
29
use Digest::MD5 qw(md5_hex);
30
31
use Lmo;
32
33
has 'max_class_size' => (
34
    is       => 'ro',
35
    isa      => 'Int',
36
    required => 1,
37
);
38
39
has 'max_examples' => (
40
    is       => 'ro',
41
    isa      => 'Int',
42
    required => 1,
43
);
44
45
has 'classes' => (
507.1.4 by Daniel Nichter
Stripping down pt-upgrade; work in progress.
46
    is       => 'rw',
47
    isa      => 'HashRef',
48
    required => 0,
49
    default  => sub { return {} },
50
);
51
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
52
sub save_diffs {
53
   my ($self, %args) = @_;
54
507.1.10 by Daniel Nichter
Test pt-upgrade host-to-host. Implement diff_query_times(). Export $test_diff from PerconaTest instead of doing diag() in no_diff().
55
   my $event            = $args{event};
56
   my $query_time_diffs = $args{query_time_diffs};
57
   my $warning_diffs    = $args{warning_diffs};
58
   my $row_diffs        = $args{row_diffs};
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
59
60
   my $class = $self->class(event => $event);
61
62
   if ( my $query = $self->_can_save(event => $event, class => $class) ) {
507.1.10 by Daniel Nichter
Test pt-upgrade host-to-host. Implement diff_query_times(). Export $test_diff from PerconaTest instead of doing diag() in no_diff().
63
      if ( $query_time_diffs
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
64
           && scalar @{$class->{query_time_diffs}} < $self->max_examples ) {
65
         push @{$class->{query_time_diffs}}, [
66
            $query,
507.1.37 by Daniel Nichter
Functional test and fix query time diffs.
67
            $query_time_diffs,
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
68
         ];
69
      }
70
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
71
      if ( $warning_diffs && @$warning_diffs
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
72
           && scalar @{$class->{warning_diffs}} < $self->max_examples ) {
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
73
         push @{$class->{warning_diffs}}, [
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
74
            $query,
75
            $warning_diffs,
76
         ];
77
      }
78
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
79
      if ( $row_diffs && @$row_diffs
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
80
           && scalar @{$class->{row_diffs}} < $self->max_examples ) {
81
         push @{$class->{row_diffs}}, [
82
            $query,
83
            $row_diffs,
84
         ];
85
      }
86
   }
87
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
88
   $self->report_if_ready(class => $class);
89
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
90
   return;
91
}
92
93
sub save_error {
94
   my ($self, %args) = @_;
95
96
   my $event  = $args{event};
97
   my $error1 = $args{error1};
98
   my $error2 = $args{error2};
99
100
   my $class = $self->class(event => $event);
101
102
   if ( my $query = $self->_can_save(event => $event, class => $class) ) {
103
      if ( scalar @{$class->{errors}} < $self->max_examples ) {
104
         push @{$class->{errors}}, [
105
            $query,
106
            $error1,
107
            $error2,
108
         ];
109
      }
110
   }
111
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
112
   $self->report_if_ready(class => $class);
113
114
   return;
115
}
116
117
sub save_failed_query {
118
   my ($self, %args) = @_;
119
120
   my $event  = $args{event};
121
   my $error1 = $args{error1};
122
   my $error2 = $args{error2};
123
124
   my $class = $self->class(event => $event);
125
126
   if ( my $query = $self->_can_save(event => $event, class => $class) ) {
127
      if ( scalar @{$class->{failures}} < $self->max_examples ) {
128
         push @{$class->{failures}}, [
129
            $query,
130
            $error1,
131
            $error2,
132
         ];
133
      }
134
   }
135
136
   $self->report_if_ready(class => $class);
137
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
138
   return;
139
}
140
141
sub _can_save {
142
   my ($self, %args) = @_;
143
   my $event = $args{event};
144
   my $class = $args{class};
145
   my $query = $event->{arg};
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
146
   if ( $class->{reported} ) {
147
      PTDEBUG && _d('Class already reported');
148
      return;
149
   }
150
   $class->{total_queries}++;
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
151
   if ( exists $class->{unique_queries}->{$query}
152
        || scalar keys %{$class->{unique_queries}} < $self->max_class_size ) {
153
      $class->{unique_queries}->{$query}++;
154
      return $query;
155
   }
156
   PTDEBUG && _d('Too many queries in class, discarding', $query);
157
   $class->{discarded}++;
158
   return;
159
}
160
161
sub class {
162
   my ($self, %args) = @_;
163
   my $event = $args{event};
164
165
   my $id      = uc(substr(md5_hex($event->{fingerprint}), -16));
166
   my $classes = $self->classes;
167
   my $class   = $classes->{$id};
168
   if ( !$class ) {
169
      $class = $self->_new_class(
170
         id    => $id,
171
         event => $event,
172
      );
173
      $classes->{$id} = $class;
174
   }
175
   return $class;
176
}
177
178
sub _new_class {
179
   my ($self, %args) = @_;
180
   my $id    = $args{id};
181
   my $event = $args{event};
182
   PTDEBUG && _d('New query class:', $id, $event->{fingerprint});
183
   my $class = {
184
      id               => $id,
185
      fingerprint      => $event->{fingerprint},
186
      discarded        => 0,
187
      unique_queries   => {
188
         $event->{arg} => 0,
189
      },
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
190
      failures         => [],  # error on both hosts
191
      errors           => [],  # error on one host
192
      query_time_diffs => [],
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
193
      warning_diffs    => [],
194
      row_diffs        => [],
195
   };
196
   return $class;
197
}
198
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
199
sub report_unreported_classes {
200
   my ($self) = @_;
507.1.30 by Daniel Nichter
eval the critical parts. Use specific exit codes. Add --run-time, --progress, --continue-on-error, and --defaults-file. Uncomment the version check call. Update the docs.
201
   my $success = 1;
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
202
   my $classes = $self->classes;
203
   foreach my $id ( sort keys %$classes ) {
507.1.30 by Daniel Nichter
eval the critical parts. Use specific exit codes. Add --run-time, --progress, --continue-on-error, and --defaults-file. Uncomment the version check call. Update the docs.
204
      eval {
205
         my $class = $classes->{$id};
206
         my $reason;
207
         if ( !scalar @{$class->{failures}} ) {
208
            $reason = 'it has diffs';
209
         }
210
         elsif (    scalar @{$class->{errors}}
211
                 || scalar @{$class->{query_time_diffs}}
212
                 || scalar @{$class->{warning_diffs}}
213
                 || scalar @{$class->{row_diffs}} ) {
214
            $reason = 'it has SQL errors and diffs';
215
         }
216
         else {
217
            $reason = 'it has SQL errors'
218
         }
219
         $self->report_class(
220
            class   => $class,
221
            reasons => ["$reason, but hasn't been reported yet"],
222
         );
223
         $class = { reported => 1 };
224
      };
225
      if ( $EVAL_ERROR ) {
226
         $success = 1;
227
         warn Dumper($classes->{$id});
228
         warn "Error reporting query class $id: $EVAL_ERROR";
229
      }
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
230
   }
507.1.30 by Daniel Nichter
eval the critical parts. Use specific exit codes. Add --run-time, --progress, --continue-on-error, and --defaults-file. Uncomment the version check call. Update the docs.
231
   return $success;
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
232
}
233
234
sub report_if_ready {
235
   my ($self, %args) = @_;
236
   my $class = $args{class};
237
238
   my $max_examples = $self->max_class_size;
239
   my @report_reasons;
240
241
   if ( scalar keys %{$class->{unique_queries}} >= $self->max_class_size ) {
242
      push @report_reasons, "it's full (--max-class-size)";
243
   }
244
245
   if ( scalar @{$class->{query_time_diffs}} >= $max_examples ) {
246
      push @report_reasons, "there are $max_examples query diffs";
247
   }
248
249
   if ( scalar @{$class->{warning_diffs}} >= $max_examples ) {
250
      push @report_reasons, "there are $max_examples warning diffs";
251
   }
252
253
   if ( scalar @{$class->{row_diffs}} >= $self->max_examples ) {
254
      push @report_reasons, "there are $max_examples row diffs";
255
   }
256
257
   if ( scalar @{$class->{errors}} >= $self->max_examples ) {
258
      push @report_reasons, "there are $max_examples query errors";
259
   }
260
261
   if ( scalar @{$class->{failures}} >= $self->max_examples ) {
262
      push @report_reasons, "there are $max_examples failed queries";
263
   }
264
265
   if ( scalar @report_reasons ) {
266
      PTDEBUG && _d('Reporting class because', @report_reasons);
267
      $self->report_class(
268
         class   => $class,
269
         reasons => \@report_reasons,
270
      );
271
      $class = { reported => 1 };
272
   }
273
274
   return;
275
}
276
277
sub report_class {
278
   my ($self, %args) = @_;
279
   my $class   = $args{class};
280
   my $reasons = $args{reasons};
281
282
   PTDEBUG && _d('Reporting class', $class->{id}, $class->{fingerprint});
283
284
   $self->_print_class_header(
285
      class   => $class,
286
      reasons => $reasons,
287
   );
288
289
   if ( scalar @{$class->{failures}} ) {
290
      $self->_print_failures(
291
         failures => $class->{failures},
292
      );
293
   }
294
295
   if ( scalar @{$class->{errors}} ) {
507.1.10 by Daniel Nichter
Test pt-upgrade host-to-host. Implement diff_query_times(). Export $test_diff from PerconaTest instead of doing diag() in no_diff().
296
      $self->_print_errors(
297
         errors => $class->{errors},
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
298
      );
299
   }
300
301
   if ( scalar @{$class->{query_time_diffs}} ) {
302
      $self->_print_diffs(
507.1.10 by Daniel Nichter
Test pt-upgrade host-to-host. Implement diff_query_times(). Export $test_diff from PerconaTest instead of doing diag() in no_diff().
303
         diffs     => $class->{query_time_diffs},
304
         name      => 'Query time',
305
         formatter => \&_format_query_times,
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
306
      );
307
   }
308
309
   if ( scalar @{$class->{warning_diffs}} ) {
507.1.10 by Daniel Nichter
Test pt-upgrade host-to-host. Implement diff_query_times(). Export $test_diff from PerconaTest instead of doing diag() in no_diff().
310
      $self->_print_diffs(
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
311
         diffs     => $class->{warning_diffs},
312
         name      => 'Warning',
313
         formatter => \&_format_warnings,
314
      );
315
   }
316
317
   if ( scalar @{$class->{row_diffs}} ) {
507.1.10 by Daniel Nichter
Test pt-upgrade host-to-host. Implement diff_query_times(). Export $test_diff from PerconaTest instead of doing diag() in no_diff().
318
      $self->_print_diffs(
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
319
         diffs     => $class->{row_diffs},
320
         name      => 'Row',
321
         formatter => \&_format_rows,
322
      );
323
   }
324
325
   return;
326
}
327
328
# This is a terrible hack due to two things: 1) our own util/update-modules
329
# things lines starting with multiple # are package headers; 2) the same
330
# util strips all comment lines start with #.  So if we use the literal #
331
# for this header, util/update-modules will remove them from the code.
332
# *facepalm*
333
my $class_header_format = <<'EOF';
507.1.21 by Daniel Nichter
Implement all MySQL log parsers. Add report sections, and --report.
334
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
335
%s
336
%s
337
%s
338
339
Reporting class because %s.
340
341
Total queries      %s
342
Unique queries     %s
343
Discarded queries  %s
344
345
%s
346
EOF
347
348
sub _print_class_header {
349
   my ($self, %args) = @_;
350
   my $class   = $args{class};
351
   my @reasons = @{ $args{reasons} };
352
353
   my $unique_queries = do {
354
      my $i = 0;
355
      map { $i += $_ } values %{$class->{unique_queries}};
356
      $i;
357
   };
358
   PTDEBUG && _d('Unique queries:', $unique_queries);
359
360
   my $reasons;
361
   if ( scalar @reasons > 1 ) {
362
      $reasons = join(', ', @reasons[0..($#reasons - 1)])
363
               . ', and ' . $reasons[-1];
364
   }
365
   else {
366
      $reasons = $reasons[0];
367
   }
368
   PTDEBUG && _d('Reasons:', $reasons);
369
370
   printf $class_header_format,
371
      ('#' x 72),
372
      ('# Query class ' . ($class->{id} || '?')),
373
      ('#' x 72),
374
      ($reasons                || '?'),
375
      (defined $class->{total_queries} ? $class->{total_queries} : '?'),
376
      (defined $unique_queries         ? $unique_queries         : '?'),
377
      (defined $class->{discarded}     ? $class->{discarded}     : '?'),
378
      ($class->{fingerprint}   || '?');
379
380
   return;
381
}
382
383
sub _print_diff_header {
384
   my ($self, %args) = @_;
385
   my $name  = $args{name}  || '?';
386
   my $count = $args{count} || '?';
387
   print "\n##\n## $name diffs: $count\n##\n";
388
   return;
389
}
390
391
sub _print_failures {
392
   my ($self, %args) = @_;
393
   my $failures = $args{failures};
394
395
   my $n_failures = scalar @$failures;
396
397
   print "\n##\n## SQL errors: $n_failures\n##\n";
398
399
   my $failno = 1;
400
   foreach my $failure ( @$failures ) {
401
      print "\n-- $failno.\n";
402
      if ( ($failure->[1] || '') eq ($failure->[2] || '') ) {
403
         printf "\nOn both hosts:\n\n" . ($failure->[1] || '') . "\n";
404
      }
405
      else {
406
         printf "\n%s\n\nvs.\n\n%s\n",
407
            ($failure->[1] || ''),
408
            ($failure->[2] || '');
409
      }
410
      print "\n" . ($failure->[0] || '?') . "\n";
411
      $failno++;
412
   }
413
414
   return;
415
}
416
507.1.10 by Daniel Nichter
Test pt-upgrade host-to-host. Implement diff_query_times(). Export $test_diff from PerconaTest instead of doing diag() in no_diff().
417
sub _print_errors {
418
   my ($self, %args) = @_;
419
   my $errors = $args{errors};
420
421
   $self->_print_diff_header(
422
      name  => 'Query errors',
423
      count => scalar @$errors,
424
   );
425
426
   my $fmt = "\n%s\n\nvs.\n\n%s\n";
427
428
   my $errorno = 1;
429
   foreach my $error ( @$errors ) {
430
      print "\n-- $errorno.\n";
431
      printf $fmt,
432
         ($error->[1] || 'No error'),
433
         ($error->[2] || 'No error');
434
      print "\n" . ($error->[0] || '?') . "\n";
435
      $errorno++;
436
   }
437
438
   return;
439
}
440
441
sub _print_diffs {
442
   my ($self, %args) = @_;
443
   my $diffs     = $args{diffs};
444
   my $name      = $args{name};
445
   my $formatter = $args{formatter};
446
447
   $self->_print_diff_header(
448
      name  => $name,
449
      count => scalar @$diffs,
450
   );
451
452
   my $diffno = 1;
453
   foreach my $diff ( @$diffs ) {
561 by Daniel Nichter
Fix query time diff formatting in pt-upgrade.
454
      my $query     = $diff->[0];
455
      my $diff_vals = $diff->[1];
507.1.10 by Daniel Nichter
Test pt-upgrade host-to-host. Implement diff_query_times(). Export $test_diff from PerconaTest instead of doing diag() in no_diff().
456
      print "\n-- $diffno.\n";
561 by Daniel Nichter
Fix query time diff formatting in pt-upgrade.
457
      my $formatted_diff_vals = $formatter->($diff_vals);
458
      print $formatted_diff_vals || '?';
459
      print "\n" . ($query || '?') . "\n";
507.1.10 by Daniel Nichter
Test pt-upgrade host-to-host. Implement diff_query_times(). Export $test_diff from PerconaTest instead of doing diag() in no_diff().
460
      $diffno++;
461
   }
462
463
   return;
464
}
465
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
466
my $warning_format = <<'EOL';
467
   Code: %s
468
  Level: %s
469
Message: %s
470
EOL
471
472
sub _format_warnings {
473
   my ($warnings) = @_;
474
   return unless $warnings && @$warnings;
475
   my @warnings;
476
   foreach my $warn ( @$warnings ) {
477
      my $code  = $warn->[0];
478
      my $warn1 = $warn->[1];
479
      my $warn2 = $warn->[2];
480
      my $host1_warn
481
         = $warn1 ? sprintf $warning_format, 
482
                       ($warn1->{Code}    || $warn1->{code}    || '?'),
483
                       ($warn1->{Level}   || $warn1->{level}   || '?'),
484
                       ($warn1->{Message} || $warn1->{message} || '?')
485
         :          "No warning $code\n";
486
      my $host2_warn
487
         = $warn2 ? sprintf $warning_format, 
488
                       ($warn2->{Code}    || $warn2->{code}    || '?'),
489
                       ($warn2->{Level}   || $warn2->{level}   || '?'),
490
                       ($warn2->{Message} || $warn2->{message} || '?')
491
         :          "No warning $code\n";
492
493
      my $warning = sprintf "\n%s\nvs.\n\n%s", $host1_warn, $host2_warn;
494
      push @warnings, $warning;
495
   }
496
   return join("\n\n", @warnings);
497
}
498
499
sub _format_rows {
500
   my ($rows) = @_;
501
   return unless $rows && @$rows;
502
   my @diffs;
503
   foreach my $row ( @$rows ) {
507.1.10 by Daniel Nichter
Test pt-upgrade host-to-host. Implement diff_query_times(). Export $test_diff from PerconaTest instead of doing diag() in no_diff().
504
      if ( !defined $row->[1] || !defined $row->[2] ) {
505
         # missing rows
506
         my $n_missing_rows = $row->[0];
507
         my $missing_rows   = $row->[1] || $row->[2];
508
         my $dir            = !defined $row->[1] ? '>' : '<';
509
         my $diff
510
            = '@ first ' . scalar @$missing_rows
511
            . ' of ' . ($n_missing_rows || '?') . " missing rows\n";
512
         foreach my $row ( @$missing_rows ) {
513
            $diff .= "$dir "
514
                   . join(',', map {defined $_ ? $_ : 'NULL'} @$row) . "\n";
515
         }
516
         push @diffs, $diff;
517
      }
518
      else {
519
         # diff rows
520
         my $rowno = $row->[0];
521
         my $cols1 = $row->[1];
522
         my $cols2 = $row->[2];
523
         my $diff
524
            = "@ row " . ($rowno || '?') . "\n"
525
            . '< ' . join(',', map {defined $_ ? $_ : 'NULL'} @$cols1) . "\n"
526
            . '> ' . join(',', map {defined $_ ? $_ : 'NULL'} @$cols2) . "\n";
527
         push @diffs, $diff;
528
      }
507.1.8 by Daniel Nichter
Largely working, but un-tested, pt-upgrade 2.2 for host-to-host comparison. Add EventExecutor.pm.
529
   }
530
   return "\n" . join("\n", @diffs);
531
}
532
507.1.10 by Daniel Nichter
Test pt-upgrade host-to-host. Implement diff_query_times(). Export $test_diff from PerconaTest instead of doing diag() in no_diff().
533
sub _format_query_times {
534
   my ($query_times) = @_;
507.1.36 by Daniel Nichter
Fix and test UpgradeResults::format_query_times001().
535
   return unless $query_times;
561 by Daniel Nichter
Fix query time diff formatting in pt-upgrade.
536
   my $fmt = "\n%s vs. %s seconds (%sx increase)\n";
507.1.36 by Daniel Nichter
Fix and test UpgradeResults::format_query_times001().
537
   my $diff = sprintf $fmt,
561 by Daniel Nichter
Fix query time diff formatting in pt-upgrade.
538
      ($query_times->[0] || '?'),
507.1.36 by Daniel Nichter
Fix and test UpgradeResults::format_query_times001().
539
      ($query_times->[1] || '?'),
561 by Daniel Nichter
Fix query time diff formatting in pt-upgrade.
540
      ($query_times->[2] || '?');
507.1.36 by Daniel Nichter
Fix and test UpgradeResults::format_query_times001().
541
   return $diff;
507.1.10 by Daniel Nichter
Test pt-upgrade host-to-host. Implement diff_query_times(). Export $test_diff from PerconaTest instead of doing diag() in no_diff().
542
}
543
507.1.7 by Daniel Nichter
First working scaffolding and fondation of host-to-host comparison.
544
sub _d {
545
   my ($package, undef, $line) = caller 0;
546
   @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
547
        map { defined $_ ? $_ : 'undef' }
548
        @_;
549
   print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
550
}
551
552
no Lmo;
507.1.4 by Daniel Nichter
Stripping down pt-upgrade; work in progress.
553
1;
554
}
555
# ###########################################################################
556
# End UpgradeResults package
557
# ###########################################################################