Merge lp:~percona-toolkit-dev/percona-toolkit/release-2.1.7 into lp:percona-toolkit/2.1

Proposed by Brian Fraser
Status: Merged
Approved by: Daniel Nichter
Approved revision: 472
Merged at revision: 465
Proposed branch: lp:~percona-toolkit-dev/percona-toolkit/release-2.1.7
Merge into: lp:percona-toolkit/2.1
Diff against target: 2375 lines (+1038/-520)
47 files modified
Changelog (+5/-0)
Makefile.PL (+1/-1)
bin/pt-align (+1/-1)
bin/pt-archiver (+2/-2)
bin/pt-config-diff (+2/-2)
bin/pt-deadlock-logger (+2/-2)
bin/pt-diskstats (+2/-2)
bin/pt-duplicate-key-checker (+2/-2)
bin/pt-fifo-split (+1/-1)
bin/pt-find (+2/-2)
bin/pt-fingerprint (+1/-1)
bin/pt-fk-error-logger (+2/-2)
bin/pt-heartbeat (+2/-2)
bin/pt-index-usage (+2/-2)
bin/pt-ioprofile (+1/-1)
bin/pt-kill (+2/-2)
bin/pt-log-player (+1/-1)
bin/pt-mext (+1/-1)
bin/pt-mysql-summary (+1/-1)
bin/pt-online-schema-change (+2/-2)
bin/pt-pmp (+1/-1)
bin/pt-query-advisor (+2/-2)
bin/pt-query-digest (+2/-2)
bin/pt-show-grants (+1/-1)
bin/pt-sift (+1/-1)
bin/pt-slave-delay (+2/-2)
bin/pt-slave-find (+1/-1)
bin/pt-slave-restart (+2/-2)
bin/pt-stalk (+1/-1)
bin/pt-summary (+1/-1)
bin/pt-table-checksum (+241/-128)
bin/pt-table-sync (+3/-2)
bin/pt-table-usage (+1/-1)
bin/pt-tcp-model (+1/-1)
bin/pt-trend (+1/-1)
bin/pt-upgrade (+2/-2)
bin/pt-variable-advisor (+2/-2)
bin/pt-visual-explain (+1/-1)
config/deb/changelog (+7/-0)
config/sphinx-build/conf.py (+1/-1)
docs/percona-toolkit.pod (+1/-1)
docs/release_notes.rst (+18/-0)
lib/Percona/Toolkit.pm (+1/-1)
lib/Percona/XtraDB/Cluster.pm (+55/-88)
lib/Sandbox.pm (+90/-54)
t/pt-table-checksum/pxc.t (+554/-193)
t/pt-table-checksum/samples/a-z-cluster.sql (+10/-0)
To merge this branch: bzr merge lp:~percona-toolkit-dev/percona-toolkit/release-2.1.7
Reviewer Review Type Date Requested Status
Brian Fraser (community) Approve
Daniel Nichter Approve
Review via email: mp+134921@code.launchpad.net
To post a comment you must log in.
468. By Daniel Nichter

Finish PXC section of ptc docs.

469. By Daniel Nichter

Alphabetize the opts and fix 2 typos.

470. By Daniel Nichter

Don't suppress STDOUT in Sandbox.pm subs so die may have something to say.

Revision history for this message
Daniel Nichter (daniel-nichter) :
review: Approve
471. By Daniel Nichter

Update Percona::Toolkit::VERSION and Changelog.

Revision history for this message
Brian Fraser (fraserbn) :
review: Approve
472. By Daniel Nichter

Check and update tool versions, release notes, user docs, etc. before build.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Changelog'
2--- Changelog 2012-11-13 15:22:01 +0000
3+++ Changelog 2012-11-19 18:49:19 +0000
4@@ -1,5 +1,10 @@
5 Changelog for Percona Toolkit
6
7+v2.1.7 released 2012-11-19
8+
9+ * Fixed bug 1080384: pt-table-checksum 2.1.6 crashes using PTDEBUG
10+ * Fixed bug 1080385: pt-table-checksum 2.1.6 --check-binlog-format doesn't ignore PXC nodes
11+
12 v2.1.6 released 2012-11-13
13
14 * pt-online-schema-change: Columns can now be renamed without data loss
15
16=== modified file 'Makefile.PL'
17--- Makefile.PL 2012-11-13 15:22:01 +0000
18+++ Makefile.PL 2012-11-19 18:49:19 +0000
19@@ -2,7 +2,7 @@
20
21 WriteMakefile(
22 NAME => 'percona-toolkit',
23- VERSION => '2.1.6',
24+ VERSION => '2.1.7',
25 EXE_FILES => [ <bin/*> ],
26 MAN1PODS => {
27 'docs/percona-toolkit.pod' => 'blib/man1/percona-toolkit.1p',
28
29=== modified file 'bin/pt-align'
30--- bin/pt-align 2012-11-13 15:22:01 +0000
31+++ bin/pt-align 2012-11-19 18:49:19 +0000
32@@ -218,6 +218,6 @@
33
34 =head1 VERSION
35
36-pt-align 2.1.6
37+pt-align 2.1.7
38
39 =cut
40
41=== modified file 'bin/pt-archiver'
42--- bin/pt-archiver 2012-11-13 15:22:01 +0000
43+++ bin/pt-archiver 2012-11-19 18:49:19 +0000
44@@ -39,7 +39,7 @@
45 # ###########################################################################
46 {
47 package Percona::Toolkit;
48-our $VERSION = '2.1.6';
49+our $VERSION = '2.1.7';
50
51 1;
52 }
53@@ -7539,6 +7539,6 @@
54
55 =head1 VERSION
56
57-pt-archiver 2.1.6
58+pt-archiver 2.1.7
59
60 =cut
61
62=== modified file 'bin/pt-config-diff'
63--- bin/pt-config-diff 2012-11-13 15:22:01 +0000
64+++ bin/pt-config-diff 2012-11-19 18:49:19 +0000
65@@ -38,7 +38,7 @@
66 # ###########################################################################
67 {
68 package Percona::Toolkit;
69-our $VERSION = '2.1.6';
70+our $VERSION = '2.1.7';
71
72 1;
73 }
74@@ -4836,6 +4836,6 @@
75
76 =head1 VERSION
77
78-pt-config-diff 2.1.6
79+pt-config-diff 2.1.7
80
81 =cut
82
83=== modified file 'bin/pt-deadlock-logger'
84--- bin/pt-deadlock-logger 2012-11-13 15:22:01 +0000
85+++ bin/pt-deadlock-logger 2012-11-19 18:49:19 +0000
86@@ -36,7 +36,7 @@
87 # ###########################################################################
88 {
89 package Percona::Toolkit;
90-our $VERSION = '2.1.6';
91+our $VERSION = '2.1.7';
92
93 1;
94 }
95@@ -4777,6 +4777,6 @@
96
97 =head1 VERSION
98
99-pt-deadlock-logger 2.1.6
100+pt-deadlock-logger 2.1.7
101
102 =cut
103
104=== modified file 'bin/pt-diskstats'
105--- bin/pt-diskstats 2012-11-13 15:22:01 +0000
106+++ bin/pt-diskstats 2012-11-19 18:49:19 +0000
107@@ -38,7 +38,7 @@
108 # ###########################################################################
109 {
110 package Percona::Toolkit;
111-our $VERSION = '2.1.6';
112+our $VERSION = '2.1.7';
113
114 1;
115 }
116@@ -5567,6 +5567,6 @@
117
118 =head1 VERSION
119
120-pt-diskstats 2.1.6
121+pt-diskstats 2.1.7
122
123 =cut
124
125=== modified file 'bin/pt-duplicate-key-checker'
126--- bin/pt-duplicate-key-checker 2012-11-13 15:22:01 +0000
127+++ bin/pt-duplicate-key-checker 2012-11-19 18:49:19 +0000
128@@ -39,7 +39,7 @@
129 # ###########################################################################
130 {
131 package Percona::Toolkit;
132-our $VERSION = '2.1.6';
133+our $VERSION = '2.1.7';
134
135 1;
136 }
137@@ -5417,6 +5417,6 @@
138
139 =head1 VERSION
140
141-pt-duplicate-key-checker 2.1.6
142+pt-duplicate-key-checker 2.1.7
143
144 =cut
145
146=== modified file 'bin/pt-fifo-split'
147--- bin/pt-fifo-split 2012-11-13 15:22:01 +0000
148+++ bin/pt-fifo-split 2012-11-19 18:49:19 +0000
149@@ -1568,6 +1568,6 @@
150
151 =head1 VERSION
152
153-pt-fifo-split 2.1.6
154+pt-fifo-split 2.1.7
155
156 =cut
157
158=== modified file 'bin/pt-find'
159--- bin/pt-find 2012-11-13 15:22:01 +0000
160+++ bin/pt-find 2012-11-19 18:49:19 +0000
161@@ -35,7 +35,7 @@
162 # ###########################################################################
163 {
164 package Percona::Toolkit;
165-our $VERSION = '2.1.6';
166+our $VERSION = '2.1.7';
167
168 1;
169 }
170@@ -4898,6 +4898,6 @@
171
172 =head1 VERSION
173
174-pt-find 2.1.6
175+pt-find 2.1.7
176
177 =cut
178
179=== modified file 'bin/pt-fingerprint'
180--- bin/pt-fingerprint 2012-11-13 15:22:01 +0000
181+++ bin/pt-fingerprint 2012-11-19 18:49:19 +0000
182@@ -2148,6 +2148,6 @@
183
184 =head1 VERSION
185
186-pt-fingerprint 2.1.6
187+pt-fingerprint 2.1.7
188
189 =cut
190
191=== modified file 'bin/pt-fk-error-logger'
192--- bin/pt-fk-error-logger 2012-11-13 15:22:01 +0000
193+++ bin/pt-fk-error-logger 2012-11-19 18:49:19 +0000
194@@ -35,7 +35,7 @@
195 # ###########################################################################
196 {
197 package Percona::Toolkit;
198-our $VERSION = '2.1.6';
199+our $VERSION = '2.1.7';
200
201 1;
202 }
203@@ -4026,6 +4026,6 @@
204
205 =head1 VERSION
206
207-pt-fk-error-logger 2.1.6
208+pt-fk-error-logger 2.1.7
209
210 =cut
211
212=== modified file 'bin/pt-heartbeat'
213--- bin/pt-heartbeat 2012-11-13 15:22:01 +0000
214+++ bin/pt-heartbeat 2012-11-19 18:49:19 +0000
215@@ -37,7 +37,7 @@
216 # ###########################################################################
217 {
218 package Percona::Toolkit;
219-our $VERSION = '2.1.6';
220+our $VERSION = '2.1.7';
221
222 1;
223 }
224@@ -5928,6 +5928,6 @@
225
226 =head1 VERSION
227
228-pt-heartbeat 2.1.6
229+pt-heartbeat 2.1.7
230
231 =cut
232
233=== modified file 'bin/pt-index-usage'
234--- bin/pt-index-usage 2012-11-13 15:22:01 +0000
235+++ bin/pt-index-usage 2012-11-19 18:49:19 +0000
236@@ -45,7 +45,7 @@
237 # ###########################################################################
238 {
239 package Percona::Toolkit;
240-our $VERSION = '2.1.6';
241+our $VERSION = '2.1.7';
242
243 1;
244 }
245@@ -7451,6 +7451,6 @@
246
247 =head1 VERSION
248
249-pt-index-usage 2.1.6
250+pt-index-usage 2.1.7
251
252 =cut
253
254=== modified file 'bin/pt-ioprofile'
255--- bin/pt-ioprofile 2012-11-13 15:22:01 +0000
256+++ bin/pt-ioprofile 2012-11-19 18:49:19 +0000
257@@ -1103,7 +1103,7 @@
258
259 =head1 VERSION
260
261-pt-ioprofile 2.1.6
262+pt-ioprofile 2.1.7
263
264 =cut
265
266
267=== modified file 'bin/pt-kill'
268--- bin/pt-kill 2012-11-13 15:22:01 +0000
269+++ bin/pt-kill 2012-11-19 18:49:19 +0000
270@@ -43,7 +43,7 @@
271 # ###########################################################################
272 {
273 package Percona::Toolkit;
274-our $VERSION = '2.1.6';
275+our $VERSION = '2.1.7';
276
277 1;
278 }
279@@ -7786,6 +7786,6 @@
280
281 =head1 VERSION
282
283-pt-kill 2.1.6
284+pt-kill 2.1.7
285
286 =cut
287
288=== modified file 'bin/pt-log-player'
289--- bin/pt-log-player 2012-11-13 15:22:01 +0000
290+++ bin/pt-log-player 2012-11-19 18:49:19 +0000
291@@ -3657,6 +3657,6 @@
292
293 =head1 VERSION
294
295-pt-log-player 2.1.6
296+pt-log-player 2.1.7
297
298 =cut
299
300=== modified file 'bin/pt-mext'
301--- bin/pt-mext 2012-11-13 15:22:01 +0000
302+++ bin/pt-mext 2012-11-19 18:49:19 +0000
303@@ -282,7 +282,7 @@
304
305 =head1 VERSION
306
307-pt-mext 2.1.6
308+pt-mext 2.1.7
309
310 =cut
311
312
313=== modified file 'bin/pt-mysql-summary'
314--- bin/pt-mysql-summary 2012-11-13 15:22:01 +0000
315+++ bin/pt-mysql-summary 2012-11-19 18:49:19 +0000
316@@ -2904,7 +2904,7 @@
317
318 =head1 VERSION
319
320-pt-mysql-summary 2.1.6
321+pt-mysql-summary 2.1.7
322
323 =cut
324
325
326=== modified file 'bin/pt-online-schema-change'
327--- bin/pt-online-schema-change 2012-11-13 15:22:01 +0000
328+++ bin/pt-online-schema-change 2012-11-19 18:49:19 +0000
329@@ -50,7 +50,7 @@
330 # ###########################################################################
331 {
332 package Percona::Toolkit;
333-our $VERSION = '2.1.6';
334+our $VERSION = '2.1.7';
335
336 1;
337 }
338@@ -10617,6 +10617,6 @@
339
340 =head1 VERSION
341
342-pt-online-schema-change 2.1.6
343+pt-online-schema-change 2.1.7
344
345 =cut
346
347=== modified file 'bin/pt-pmp'
348--- bin/pt-pmp 2012-11-13 15:22:01 +0000
349+++ bin/pt-pmp 2012-11-19 18:49:19 +0000
350@@ -396,7 +396,7 @@
351
352 =head1 VERSION
353
354-pt-pmp 2.1.6
355+pt-pmp 2.1.7
356
357 =cut
358
359
360=== modified file 'bin/pt-query-advisor'
361--- bin/pt-query-advisor 2012-11-13 15:22:01 +0000
362+++ bin/pt-query-advisor 2012-11-19 18:49:19 +0000
363@@ -46,7 +46,7 @@
364 # ###########################################################################
365 {
366 package Percona::Toolkit;
367-our $VERSION = '2.1.6';
368+our $VERSION = '2.1.7';
369
370 1;
371 }
372@@ -8700,6 +8700,6 @@
373
374 =head1 VERSION
375
376-pt-query-advisor 2.1.6
377+pt-query-advisor 2.1.7
378
379 =cut
380
381=== modified file 'bin/pt-query-digest'
382--- bin/pt-query-digest 2012-11-13 15:22:01 +0000
383+++ bin/pt-query-digest 2012-11-19 18:49:19 +0000
384@@ -64,7 +64,7 @@
385 # ###########################################################################
386 {
387 package Percona::Toolkit;
388-our $VERSION = '2.1.6';
389+our $VERSION = '2.1.7';
390
391 1;
392 }
393@@ -17412,6 +17412,6 @@
394
395 =head1 VERSION
396
397-pt-query-digest 2.1.6
398+pt-query-digest 2.1.7
399
400 =cut
401
402=== modified file 'bin/pt-show-grants'
403--- bin/pt-show-grants 2012-11-13 15:22:01 +0000
404+++ bin/pt-show-grants 2012-11-19 18:49:19 +0000
405@@ -2304,6 +2304,6 @@
406
407 =head1 VERSION
408
409-pt-show-grants 2.1.6
410+pt-show-grants 2.1.7
411
412 =cut
413
414=== modified file 'bin/pt-sift'
415--- bin/pt-sift 2012-11-13 15:22:01 +0000
416+++ bin/pt-sift 2012-11-19 18:49:19 +0000
417@@ -781,7 +781,7 @@
418
419 =head1 VERSION
420
421-pt-sift 2.1.6
422+pt-sift 2.1.7
423
424 =cut
425
426
427=== modified file 'bin/pt-slave-delay'
428--- bin/pt-slave-delay 2012-11-13 15:22:01 +0000
429+++ bin/pt-slave-delay 2012-11-19 18:49:19 +0000
430@@ -36,7 +36,7 @@
431 # ###########################################################################
432 {
433 package Percona::Toolkit;
434-our $VERSION = '2.1.6';
435+our $VERSION = '2.1.7';
436
437 1;
438 }
439@@ -4598,6 +4598,6 @@
440
441 =head1 VERSION
442
443-pt-slave-delay 2.1.6
444+pt-slave-delay 2.1.7
445
446 =cut
447
448=== modified file 'bin/pt-slave-find'
449--- bin/pt-slave-find 2012-11-13 15:22:01 +0000
450+++ bin/pt-slave-find 2012-11-19 18:49:19 +0000
451@@ -4022,6 +4022,6 @@
452
453 =head1 VERSION
454
455-pt-slave-find 2.1.6
456+pt-slave-find 2.1.7
457
458 =cut
459
460=== modified file 'bin/pt-slave-restart'
461--- bin/pt-slave-restart 2012-11-13 15:22:01 +0000
462+++ bin/pt-slave-restart 2012-11-19 18:49:19 +0000
463@@ -37,7 +37,7 @@
464 # ###########################################################################
465 {
466 package Percona::Toolkit;
467-our $VERSION = '2.1.6';
468+our $VERSION = '2.1.7';
469
470 1;
471 }
472@@ -5522,6 +5522,6 @@
473
474 =head1 VERSION
475
476-pt-slave-restart 2.1.6
477+pt-slave-restart 2.1.7
478
479 =cut
480
481=== modified file 'bin/pt-stalk'
482--- bin/pt-stalk 2012-11-13 15:22:01 +0000
483+++ bin/pt-stalk 2012-11-19 18:49:19 +0000
484@@ -1937,7 +1937,7 @@
485
486 =head1 VERSION
487
488-pt-stalk 2.1.6
489+pt-stalk 2.1.7
490
491 =cut
492
493
494=== modified file 'bin/pt-summary'
495--- bin/pt-summary 2012-11-13 15:22:01 +0000
496+++ bin/pt-summary 2012-11-19 18:49:19 +0000
497@@ -2673,7 +2673,7 @@
498
499 =head1 VERSION
500
501-pt-summary 2.1.6
502+pt-summary 2.1.7
503
504 =cut
505
506
507=== modified file 'bin/pt-table-checksum'
508--- bin/pt-table-checksum 2012-11-16 14:36:59 +0000
509+++ bin/pt-table-checksum 2012-11-19 18:49:19 +0000
510@@ -53,7 +53,7 @@
511 # ###########################################################################
512 {
513 package Percona::Toolkit;
514-our $VERSION = '2.1.6';
515+our $VERSION = '2.1.7';
516
517 1;
518 }
519@@ -3375,87 +3375,66 @@
520 # See https://launchpad.net/percona-toolkit for more information.
521 # ###########################################################################
522 {
523-
524 package Percona::XtraDB::Cluster;
525+
526+use strict;
527+use warnings FATAL => 'all';
528+use English qw(-no_match_vars);
529+use constant PTDEBUG => $ENV{PTDEBUG} || 0;
530+
531 use Mo;
532-use constant PTDEBUG => $ENV{PTDEBUG} || 0;
533+use Data::Dumper;
534+
535+sub get_cluster_name {
536+ my ($self, $cxn) = @_;
537+ my $sql = "SHOW VARIABLES LIKE 'wsrep\_cluster\_name'";
538+ PTDEBUG && _d($cxn->name, $sql);
539+ my (undef, $cluster_name) = $cxn->dbh->selectrow_array($sql);
540+ return $cluster_name;
541+}
542
543 sub is_cluster_node {
544 my ($self, $cxn) = @_;
545- return $self->{is_cluster_node}->{$cxn} if defined $self->{is_cluster_node}->{$cxn};
546
547- my $sql = "SHOW VARIABLES LIKE 'wsrep_on'";
548- PTDEBUG && _d($sql);
549+ my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'";
550+ PTDEBUG && _d($cxn->name, $sql);
551 my $row = $cxn->dbh->selectrow_arrayref($sql);
552- PTDEBUG && _d(defined $row ? @$row : 'undef');
553- $self->{is_cluster_node}->{$cxn} = $row && $row->[1]
554- ? ($row->[1] eq 'ON' || $row->[1] eq '1')
555- : 0;
556-
557- return $self->{is_cluster_node}->{$cxn};
558+ PTDEBUG && _d(Dumper($row));
559+ return unless $row && $row->[1] && ($row->[1] eq 'ON' || $row->[1] eq '1');
560+
561+ my $cluster_name = $self->get_cluster_name($cxn);
562+ return $cluster_name;
563+}
564+
565+sub same_node {
566+ my ($self, $cxn1, $cxn2) = @_;
567+
568+ my $sql = "SHOW VARIABLES LIKE 'wsrep\_sst\_receive\_address'";
569+ PTDEBUG && _d($cxn1->name, $sql);
570+ my (undef, $val1) = $cxn1->dbh->selectrow_array($sql);
571+ PTDEBUG && _d($cxn2->name, $sql);
572+ my (undef, $val2) = $cxn2->dbh->selectrow_array($sql);
573+
574+ return ($val1 || '') eq ($val2 || '');
575 }
576
577 sub same_cluster {
578 my ($self, $cxn1, $cxn2) = @_;
579- return unless $self->is_cluster_node($cxn1) && $self->is_cluster_node($cxn2);
580- return if $self->is_master_of($cxn1, $cxn2) || $self->is_master_of($cxn2, $cxn1);
581-
582- my $sql = q{SHOW VARIABLES LIKE 'wsrep_cluster_name'};
583- PTDEBUG && _d($sql);
584- my (undef, $row) = $cxn1->dbh->selectrow_array($sql);
585- my (undef, $cxn2_row) = $cxn2->dbh->selectrow_array($sql);
586-
587- return unless $row eq $cxn2_row;
588-
589- $sql = q{SHOW VARIABLES LIKE 'wsrep_cluster_address'};
590- PTDEBUG && _d($sql);
591- my (undef, $addr) = $cxn1->dbh->selectrow_array($sql);
592- my (undef, $cxn2_addr) = $cxn2->dbh->selectrow_array($sql);
593-
594- return if $addr eq 'gcomm://' && $cxn2_addr eq 'gcomm://';
595-
596- if ( $addr eq 'gcomm://' ) {
597- $addr = $self->_find_full_gcomm_addr($cxn1->dbh);
598- }
599- elsif ( $cxn2_addr eq 'gcomm://' ) {
600- $cxn2_addr = $self->_find_full_gcomm_addr($cxn2->dbh);
601- }
602-
603- return 1 if lc($addr) eq lc($cxn2_addr);
604-
605- return 1;
606-}
607-
608-sub is_master_of {
609- my ($self, $cxn1, $cxn2) = @_;
610-
611- my $cxn2_dbh = $cxn2->dbh;
612- my $sql = q{SHOW SLAVE STATUS};
613- PTDEBUG && _d($sql);
614- local $cxn2_dbh->{FetchHashKeyName} = 'NAME_lc';
615- my $slave_status = $cxn2_dbh->selectrow_hashref($sql);
616- return unless ref($slave_status) eq 'HASH';
617-
618- my $port = $cxn1->dsn->{P};
619- return unless $slave_status->{master_port} eq $port;
620- return 1 if $cxn1->dsn->{h} eq $slave_status->{master_host};
621-
622- my $host = scalar gethostbyname($cxn1->dsn->{h});
623- my $master_host = scalar gethostbyname($slave_status->{master_host});
624- return 1 if $master_host eq $host;
625- return;
626-}
627-
628-sub _find_full_gcomm_addr {
629- my ($self, $dbh) = @_;
630-
631- my $sql = q{SHOW VARIABLES LIKE 'wsrep_provider_options'};
632- PTDEBUG && _d($sql);
633- my (undef, $provider_opts) = $dbh->selectrow_array($sql);
634- my ($prov_addr) = $provider_opts =~ m{\Qgmcast.listen_addr\E\s*=\s*tcp://([^:]+:[0-9]+)\s*;}i;
635- my $full_gcomm = "gcomm://$prov_addr";
636- PTDEBUG && _d("gcomm address: ", $full_gcomm);
637- return $full_gcomm;
638+
639+ return 0 if !$self->is_cluster_node($cxn1) || !$self->is_cluster_node($cxn2);
640+
641+ my $cluster1 = $self->get_cluster_name($cxn1);
642+ my $cluster2 = $self->get_cluster_name($cxn2);
643+
644+ return ($cluster1 || '') eq ($cluster2 || '');
645+}
646+
647+sub _d {
648+ my ($package, undef, $line) = caller 0;
649+ @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
650+ map { defined $_ ? $_ : 'undef' }
651+ @_;
652+ print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
653 }
654
655 1;
656@@ -8658,9 +8637,13 @@
657 $have_time = sub { return 1; };
658 }
659
660- # PXC helper class
661+ # ########################################################################
662+ # Set up PXC stuff.
663+ # ########################################################################
664 my $cluster = Percona::XtraDB::Cluster->new();
665-
666+ my %cluster_name_for;
667+ $cluster_name_for{$master_cxn} = $cluster->is_cluster_node($master_cxn);
668+
669 # ########################################################################
670 # If this is not a dry run (--explain was not specified), then we're
671 # going to checksum the tables, so do the necessary preparations and
672@@ -8678,7 +8661,7 @@
673
674 my $slaves = []; # all slaves (that we can find)
675 my $slave_lag_cxns; # slaves whose lag we'll check
676-
677+
678 my $replica_lag; # ReplicaLagWaiter object
679 my $replica_lag_pr; # Progress for ReplicaLagWaiter
680 my $sys_load; # MySQLStatusWaiter object
681@@ -8697,9 +8680,29 @@
682 dbh => $master_dbh,
683 dsn => $master_dsn,
684 make_cxn => sub {
685- return $make_cxn->(@_, prev_dsn => $master_cxn->dsn());
686+ my $cxn = $make_cxn->(@_, prev_dsn => $master_cxn->dsn());
687+ $cluster_name_for{$cxn} = $cluster->is_cluster_node($cxn);
688+ return $cxn;
689 },
690 );
691+
692+ # If the "master" is a cluster node, then a DSN table should have been
693+ # used, and it may have all nodes' DSNs so the user can run the tool
694+ # on any node, in which case it has the "master" node, the DSN given
695+ # on the command line. So detect and remove this dupe.
696+ if ( $cluster_name_for{$master_cxn} ) {
697+ @$slaves = grep {
698+ my $slave_cxn = $_;
699+ if ( $cluster->same_node($master_cxn, $slave_cxn) ) {
700+ PTDEBUG && _d('Removing ', $slave_cxn->name, 'from slaves',
701+ 'because it is the master');
702+ 0;
703+ }
704+ else {
705+ $slave_cxn;
706+ }
707+ } @$slaves;
708+ }
709 PTDEBUG && _d(scalar @$slaves, 'slaves found');
710
711 # https://bugs.launchpad.net/percona-toolkit/+bug/938068
712@@ -8711,7 +8714,10 @@
713 }
714
715 my $err = '';
716- for my $slave_cxn (@$slaves) {
717+ for my $slave_cxn ( @$slaves ) {
718+ # https://bugs.launchpad.net/percona-toolkit/+bug/1080385
719+ next if $cluster_name_for{$slave_cxn};
720+
721 my $slave_binlog = 'STATEMENT';
722 if ( VersionParser->new($slave_cxn->dbh) >= '5.1.5' ) {
723 ($slave_binlog) = $slave_cxn->dbh->selectrow_array(
724@@ -8730,42 +8736,91 @@
725 die $err if $err;
726 }
727
728- if ( $cluster->is_cluster_node($master_cxn) ) {
729+ if ( $cluster_name_for{$master_cxn} ) {
730 if ( !@$slaves ) {
731 die $master_cxn->name() . " is a cluster node but no other nodes "
732 . "or regular replicas were found. Use --recursion-method=dsn "
733 . "to specify the other nodes in the cluster.\n";
734 }
735- else {
736- my $err = '';
737- for my $slave (@$slaves) {
738- if ( $cluster->is_cluster_node($slave)
739- && !$cluster->same_cluster($slave, $master_cxn) ) {
740- $err .= $slave->name() . " is a cluster node, but doesn't "
741- . "belong to the same cluster as " . $master_cxn->name()
742- . ". This is not currently supported; You can try "
743- . "using --recursion-method=dsn to specify all nodes "
744- . "in the slave cluster.\n"
745- }
746+
747+ # Make sure the master and all node are in the same cluster.
748+ my @other_cluster;
749+ foreach my $slave ( @$slaves ) {
750+ next unless $cluster_name_for{$slave};
751+ if ( $cluster_name_for{$master_cxn} ne $cluster_name_for{$slave}) {
752+ push @other_cluster, $slave;
753 }
754- warn $err if $err;
755+ }
756+ if ( @other_cluster ) {
757+ die $master_cxn->name . " is in cluster "
758+ . $cluster_name_for{$master_cxn} . " but these nodes are "
759+ . "in other clusters:\n"
760+ . join("\n",
761+ map {' ' . $_->name . " is in cluster $cluster_name_for{$_}"}
762+ @other_cluster) . "\n"
763+ . "All nodes must be in the same cluster. "
764+ . "For more information, please read the Percona XtraDB "
765+ . "Cluster section of the tool's documentation.\n";
766 }
767 }
768 elsif ( @$slaves ) {
769+ # master is not a cluster node, but what about the slaves?
770+ my $direct_slave; # master -> direct_slave
771+ my @slaves; # traditional slaves
772+ my @nodes; # cluster nodes
773+ foreach my $slave ( @$slaves ) {
774+ if ( !$cluster_name_for{$slave} ) {
775+ push @slaves, $slave;
776+ next;
777+ }
778+
779+ my $is_master_of = eval {
780+ $ms->is_master_of($master_cxn->dbh, $slave->dbh);
781+ };
782+ if ( $EVAL_ERROR && $EVAL_ERROR =~ m/is not a slave/ ) {
783+ push @nodes, $slave;
784+ }
785+ elsif ( $is_master_of ) {
786+ $direct_slave = $slave;
787+ }
788+ else {
789+ # Another error could have happened but we don't really
790+ # care. We know for sure the slave is a node, so just
791+ # presume that and carry on.
792+ push @nodes, $slave;
793+ }
794+ }
795+
796 my $err = '';
797- for my $slave (@$slaves) {
798- if ( $cluster->is_cluster_node($slave) ) {
799- $err .= $slave->name() . " is a cluster node, but "
800- . $master_cxn->name() . " is not. This is not currently "
801- . "supported; You can try to specify "
802- . "all nodes in the cluster with "
803- . "--recursion-method=dsn if you want them checksummed.\n"
804+ if ( @nodes ) {
805+ if ( $direct_slave ) {
806+ warn "Diffs will only be detected if the cluster is "
807+ . "consistent with " . $direct_slave->name . " because "
808+ . $master_cxn->name . " is a traditional replication master "
809+ . " but these replicas are cluster nodes:\n"
810+ . join("\n", map { ' ' . $_->name } @nodes) . "\n"
811+ . "For more information, please read the Percona XtraDB "
812+ . "Cluster section of the tool's documentation.\n";
813+ }
814+ else {
815+ warn "Diffs may not be detected on these cluster nodes "
816+ . "because the direct replica of " . $master_cxn->name
817+ . " was not found or specified:\n"
818+ . join("\n", map { ' ' . $_->name } @nodes) . "\n"
819+ . "For more information, please read the Percona XtraDB "
820+ . "Cluster section of the tool's documentation.\n";
821+ }
822+
823+ if ( @slaves ) {
824+ warn "Diffs will only be detected on these replicas if "
825+ . "they replicate from " . $master_cxn->name . ":\n"
826+ . join("\n", map { ' ' . $_->name } @slaves) . "\n"
827+ . "For more information, please read the Percona XtraDB "
828+ . "Cluster section of the tool's documentation.\n";
829 }
830 }
831- warn $err if $err;
832 }
833-
834-
835+
836 if ( $o->get('check-slave-lag') ) {
837 PTDEBUG && _d('Will use --check-slave-lag to check for slave lag');
838 my $cxn = $make_cxn->(
839@@ -8785,8 +8840,7 @@
840 # to appear should be sufficient.
841 @$slave_lag_cxns = grep {
842 my $slave_cxn = $_;
843- if ( $cluster->is_cluster_node($slave_cxn)
844- && $cluster->same_cluster($master_cxn, $slave_cxn) ) {
845+ if ( $cluster_name_for{$slave_cxn} ) {
846 warn "Not checking replica lag on " . $slave_cxn->name()
847 . " because it is a cluster node.\n";
848 0;
849@@ -10688,6 +10742,79 @@
850 SET boundaries = COALESCE(CONCAT('id BETWEEN ', lower_boundary,
851 ' AND ', upper_boundary), '1=1');
852
853+=head1 Percona XtraDB Cluster
854+
855+pt-table-checksum works with Percona XtraDB Cluster (PXC) 5.5.27-23.6 and newer.
856+The number of possible Percona XtraDB Cluster setups is large given that
857+it can be used with regular replication as well. Therefore, only the setups
858+listed below are supported and known to work. Other setups, like cluster
859+to cluster, are not support and probably don't work.
860+
861+Except where noted, all of the following supported setups require that you
862+use the C<dsn> method for L<"--recursion-method"> to specify cluster nodes.
863+Also, the lag check (see L<"REPLICA CHECKS">) is not performed for cluster
864+nodes.
865+
866+=over
867+
868+=item Single cluster
869+
870+The simplest PXC setup is a single cluster: all servers are cluster nodes,
871+and there are no regular replicas. If all nodes are specified in the
872+DSN table (see L<"--recursion-method">), then you can run the tool on any
873+node and any diffs on any other nodes will be detected.
874+
875+All nodes must be in the same cluster (have the same C<wsrep_cluster_name>
876+value), else the tool exits with an error. Although it's possible to have
877+different clusters with the same name, this should not be done and is not
878+supported. This applies to all supported setups.
879+
880+=item Single cluster with replicas
881+
882+Cluster nodes can also be regular masters and replicate to regular replicas.
883+However, the tool can only detect diffs on a replica if ran on the replica's
884+"master node". For example, if the cluster setup is,
885+
886+ node1 <-> node2 <-> node3
887+ | |
888+ | +-> replica3
889+ +-> replica2
890+
891+you can detect diffs on replica3 by running the tool on node3, but to detect
892+diffs on replica2 you must run the tool again on node2. If you run the tool
893+on node1, it will not detect diffs on either replica.
894+
895+Currently, the tool does not detect this setup or warn about replicas that
896+cannot be checked (e.g. replica2 when running on node3).
897+
898+Replicas in this setup are still subject to L<"--[no]check-binlog-format">.
899+
900+=item Master to single cluster
901+
902+It is possible for a regular master to replicate to a cluster, as if the
903+cluster were one logical slave, like:
904+
905+ master -> node1 <-> node2 <-> node3
906+
907+The tool supports this setup but only if ran on the master and if all nodes
908+in the cluster are consistent with the "direct replica" (node1 in this example)
909+of the master. For example, if all nodes have value "foo" for row 1 but
910+the master has value "bar" for the same row, this diff will be detected.
911+Or if only node1 has this diff, it will also be detected. But if only node2
912+or node3 has this diff, it will not be detected. Therefore, this setup is
913+used to check that the master and the cluster as a whole are consistent.
914+
915+In this setup, the tool can automatically detect the "direct replica" (node1)
916+when ran on the master, so you do not have to use the C<dsn> method for
917+L<"--recursion-method"> because node1 will represent the entire cluster,
918+which is why all other nodes must be consistent with it.
919+
920+The tool warns when it detects this setup to remind you that it only works
921+when used as described above. These warnings do not affect the exit status
922+of the tool; they're only reminders to help avoid false-positive results.
923+
924+=back
925+
926 =head1 OUTPUT
927
928 The tool prints tabular results, one line per table:
929@@ -10749,7 +10876,7 @@
930
931 If L<"--replicate-check-only"> is specified, only checksum differences on
932 detected replicas are printed. The output is different: one paragraph per
933-replica, one checksum difference per line, and values are separted by spaces:
934+replica, one checksum difference per line, and values are separated by spaces:
935
936 Differences on h=127.0.0.1,P=12346
937 TABLE CHUNK CNT_DIFF CRC_DIFF CHUNK_INDEX LOWER_BOUNDARY UPPER_BOUNDARY
938@@ -10816,20 +10943,20 @@
939
940 Prompt for a password when connecting to MySQL.
941
942+=item --[no]check-binlog-format
943+
944+default: yes
945+
946+Check that the C<binlog_format> is the same on all servers.
947+
948+See "Replicas using row-based replication" under L<"LIMITATIONS">.
949+
950 =item --check-interval
951
952 type: time; default: 1; group: Throttle
953
954 Sleep time between checks for L<"--max-lag">.
955
956-=item --[no]check-binlog-format
957-
958-default: yes
959-
960-Check that the C<binlog_format> is the same on all servers.
961-
962-See "Replicas using row-based replication" under L<"LIMITATIONS">.
963-
964 =item --[no]check-plan
965
966 default: yes
967@@ -11329,7 +11456,7 @@
968
969 The C<none> method prevents the tool from connecting to any replicas.
970 This effectively disables all the L<"REPLICA CHECKS"> because there will
971-not be any replicas to check. Thefore, this method is not recommended.
972+not be any replicas to check. Therefore, this method is not recommended.
973
974 =item --replicate
975
976@@ -11538,7 +11665,7 @@
977
978 =item 2. L<"--replicate"> table
979
980-pt-table-cheksum checks that the L<"--replicate"> table exists on all
981+pt-table-checksum checks that the L<"--replicate"> table exists on all
982 replicas, else checksumming can break replication when updates to the table
983 on the master replicate to a replica that doesn't have the table. This
984 check cannot be disabled, and the tool wait forever until the table
985@@ -11668,24 +11795,10 @@
986 further replicas.
987
988 The tool automatically checks the C<binlog_format> on all servers.
989-See L<"--[no]check-binlog-format">
990+See L<"--[no]check-binlog-format"> .
991
992 (L<Bug 899415|https://bugs.launchpad.net/percona-toolkit/+bug/899415>)
993
994-=item Percona XtraDB Cluster
995-
996-pt-table-checksum works with Percona XtraDB Cluster 5.5.27-23.6 and newer.
997-The C<dsn> method for L<"--recursion-method"> must be used to specify cluster
998-nodes and regular replicas because nodes are not regular replicas so they
999-cannot be detected automatically. The lag check (see L<"REPLICA CHECKS">)
1000-is not performed for cluster nodes.
1001-
1002-Mixed replication setups are not currently supported. For example, the tool
1003-does not work completely if the master host is replicating to a cluster,
1004-or if the cluster is replicating to another cluster. In short, the only
1005-supported setup is a single cluster with nodes optionally having traditional
1006-replication slaves.
1007-
1008 =back
1009
1010 =head1 BUGS
1011@@ -11769,6 +11882,6 @@
1012
1013 =head1 VERSION
1014
1015-pt-table-checksum 2.1.6
1016+pt-table-checksum 2.1.7
1017
1018 =cut
1019
1020=== modified file 'bin/pt-table-sync'
1021--- bin/pt-table-sync 2012-11-13 15:22:01 +0000
1022+++ bin/pt-table-sync 2012-11-19 18:49:19 +0000
1023@@ -22,6 +22,7 @@
1024 TableSyncStream
1025 TableParser
1026 RowDiff
1027+ MySQLDump
1028 ChangeHandler
1029 TableChunker
1030 TableChecksum
1031@@ -51,7 +52,7 @@
1032 # ###########################################################################
1033 {
1034 package Percona::Toolkit;
1035-our $VERSION = '2.1.6';
1036+our $VERSION = '2.1.7';
1037
1038 1;
1039 }
1040@@ -12606,6 +12607,6 @@
1041
1042 =head1 VERSION
1043
1044-pt-table-sync 2.1.6
1045+pt-table-sync 2.1.7
1046
1047 =cut
1048
1049=== modified file 'bin/pt-table-usage'
1050--- bin/pt-table-usage 2012-11-13 15:22:01 +0000
1051+++ bin/pt-table-usage 2012-11-19 18:49:19 +0000
1052@@ -7380,6 +7380,6 @@
1053
1054 =head1 VERSION
1055
1056-pt-table-usage 2.1.6
1057+pt-table-usage 2.1.7
1058
1059 =cut
1060
1061=== modified file 'bin/pt-tcp-model'
1062--- bin/pt-tcp-model 2012-11-13 15:22:01 +0000
1063+++ bin/pt-tcp-model 2012-11-19 18:49:19 +0000
1064@@ -2529,6 +2529,6 @@
1065
1066 =head1 VERSION
1067
1068-pt-tcp-model 2.1.6
1069+pt-tcp-model 2.1.7
1070
1071 =cut
1072
1073=== modified file 'bin/pt-trend'
1074--- bin/pt-trend 2012-11-13 15:22:01 +0000
1075+++ bin/pt-trend 2012-11-19 18:49:19 +0000
1076@@ -2230,6 +2230,6 @@
1077
1078 =head1 VERSION
1079
1080-pt-trend 2.1.6
1081+pt-trend 2.1.7
1082
1083 =cut
1084
1085=== modified file 'bin/pt-upgrade'
1086--- bin/pt-upgrade 2012-11-13 15:22:01 +0000
1087+++ bin/pt-upgrade 2012-11-19 18:49:19 +0000
1088@@ -58,7 +58,7 @@
1089 # ###########################################################################
1090 {
1091 package Percona::Toolkit;
1092-our $VERSION = '2.1.6';
1093+our $VERSION = '2.1.7';
1094
1095 1;
1096 }
1097@@ -13117,6 +13117,6 @@
1098
1099 =head1 VERSION
1100
1101-pt-upgrade 2.1.6
1102+pt-upgrade 2.1.7
1103
1104 =cut
1105
1106=== modified file 'bin/pt-variable-advisor'
1107--- bin/pt-variable-advisor 2012-11-13 15:22:01 +0000
1108+++ bin/pt-variable-advisor 2012-11-19 18:49:19 +0000
1109@@ -40,7 +40,7 @@
1110 # ###########################################################################
1111 {
1112 package Percona::Toolkit;
1113-our $VERSION = '2.1.6';
1114+our $VERSION = '2.1.7';
1115
1116 1;
1117 }
1118@@ -5870,6 +5870,6 @@
1119
1120 =head1 VERSION
1121
1122-pt-variable-advisor 2.1.6
1123+pt-variable-advisor 2.1.7
1124
1125 =cut
1126
1127=== modified file 'bin/pt-visual-explain'
1128--- bin/pt-visual-explain 2012-11-13 15:22:01 +0000
1129+++ bin/pt-visual-explain 2012-11-19 18:49:19 +0000
1130@@ -3139,6 +3139,6 @@
1131
1132 =head1 VERSION
1133
1134-pt-visual-explain 2.1.6
1135+pt-visual-explain 2.1.7
1136
1137 =cut
1138
1139=== modified file 'config/deb/changelog'
1140--- config/deb/changelog 2012-11-13 15:22:01 +0000
1141+++ config/deb/changelog 2012-11-19 18:49:19 +0000
1142@@ -1,3 +1,10 @@
1143+percona-toolkit (2.1.7) unstable; urgency=low
1144+
1145+ * Fixed bug 1080384: pt-table-checksum 2.1.6 crashes using PTDEBUG
1146+ * Fixed bug 1080385: pt-table-checksum 2.1.6 --check-binlog-format doesn't ignore PXC nodes
1147+
1148+ -- Percona Toolkit Developers <toolkit-dev@percona.com> Mon, 19 Nov 2012 18:43:13 +0000
1149+
1150 percona-toolkit (2.1.6) unstable; urgency=low
1151
1152 * pt-online-schema-change: Columns can now be renamed without data loss
1153
1154=== modified file 'config/sphinx-build/conf.py'
1155--- config/sphinx-build/conf.py 2012-11-13 15:22:01 +0000
1156+++ config/sphinx-build/conf.py 2012-11-19 18:49:19 +0000
1157@@ -50,7 +50,7 @@
1158 # The short X.Y version.
1159 version = '2.1'
1160 # The full version, including alpha/beta/rc tags.
1161-release = '2.1.6'
1162+release = '2.1.7'
1163
1164 # The language for content autogenerated by Sphinx. Refer to documentation
1165 # for a list of supported languages.
1166
1167=== modified file 'docs/percona-toolkit.pod'
1168--- docs/percona-toolkit.pod 2012-11-13 15:22:01 +0000
1169+++ docs/percona-toolkit.pod 2012-11-19 18:49:19 +0000
1170@@ -510,6 +510,6 @@
1171
1172 =head1 VERSION
1173
1174-Percona Toolkit v2.1.6 released 2012-11-13
1175+Percona Toolkit v2.1.7 released 2012-11-19
1176
1177 =cut
1178
1179=== modified file 'docs/release_notes.rst'
1180--- docs/release_notes.rst 2012-11-13 15:22:01 +0000
1181+++ docs/release_notes.rst 2012-11-19 18:49:19 +0000
1182@@ -1,6 +1,24 @@
1183 Release Notes
1184 *************
1185
1186+v2.1.7 released 2012-11-19
1187+==========================
1188+
1189+Percona Toolkit 2.1.7 has been released which is a hotfix for two bugs when using pt-table-checksum with Percona XtraDB Cluster:
1190+
1191+* Bug 1080384: pt-table-checksum 2.1.6 crashes using PTDEBUG
1192+* Bug 1080385: pt-table-checksum 2.1.6 --check-binlog-format doesn't ignore PXC nodes
1193+
1194+If you're using pt-table-checksum with a Percona XtraDB Cluster, you should upgrade. Otherwise, users can wait until the next full release.
1195+
1196+Percona Toolkit packages can be downloaded from http://www.percona.com/downloads/percona-toolkit/ or the Percona Software Repositories (http://www.percona.com/software/repositories/).
1197+
1198+Changelog
1199+---------
1200+
1201+* Fixed bug 1080384: pt-table-checksum 2.1.6 crashes using PTDEBUG
1202+* Fixed bug 1080385: pt-table-checksum 2.1.6 --check-binlog-format doesn't ignore PXC nodes
1203+
1204 v2.1.6 released 2012-11-13
1205 ==========================
1206
1207
1208=== modified file 'lib/Percona/Toolkit.pm'
1209--- lib/Percona/Toolkit.pm 2012-11-13 15:10:25 +0000
1210+++ lib/Percona/Toolkit.pm 2012-11-19 18:49:19 +0000
1211@@ -19,7 +19,7 @@
1212 # ###########################################################################
1213 {
1214 package Percona::Toolkit;
1215-our $VERSION = '2.1.6';
1216+our $VERSION = '2.1.7';
1217
1218 1;
1219 }
1220
1221=== modified file 'lib/Percona/XtraDB/Cluster.pm'
1222--- lib/Percona/XtraDB/Cluster.pm 2012-11-08 20:38:04 +0000
1223+++ lib/Percona/XtraDB/Cluster.pm 2012-11-19 18:49:19 +0000
1224@@ -1,4 +1,4 @@
1225-# This program is copyright 2011 Percona Inc.
1226+# This program is copyright 2012 Percona Inc.
1227 # Feedback and improvements are welcome.
1228 #
1229 # THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1230@@ -19,105 +19,72 @@
1231 # ###########################################################################
1232 {
1233 # Package: Percona::XtraDB::Cluster
1234-# Percona::XtraDB::Cluster has helper methods to deal with Percona XtraDB Cluster
1235-# based servers
1236-
1237+# Helper methods for dealing with Percona XtraDB Cluster nodes.
1238 package Percona::XtraDB::Cluster;
1239+
1240+use strict;
1241+use warnings FATAL => 'all';
1242+use English qw(-no_match_vars);
1243+use constant PTDEBUG => $ENV{PTDEBUG} || 0;
1244+
1245 use Mo;
1246-use constant PTDEBUG => $ENV{PTDEBUG} || 0;
1247+use Data::Dumper;
1248+
1249+sub get_cluster_name {
1250+ my ($self, $cxn) = @_;
1251+ my $sql = "SHOW VARIABLES LIKE 'wsrep\_cluster\_name'";
1252+ PTDEBUG && _d($cxn->name, $sql);
1253+ my (undef, $cluster_name) = $cxn->dbh->selectrow_array($sql);
1254+ return $cluster_name;
1255+}
1256
1257 sub is_cluster_node {
1258 my ($self, $cxn) = @_;
1259- return $self->{is_cluster_node}->{$cxn} if defined $self->{is_cluster_node}->{$cxn};
1260
1261- my $sql = "SHOW VARIABLES LIKE 'wsrep_on'";
1262- PTDEBUG && _d($sql);
1263+ my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'";
1264+ PTDEBUG && _d($cxn->name, $sql);
1265 my $row = $cxn->dbh->selectrow_arrayref($sql);
1266- PTDEBUG && _d(defined $row ? @$row : 'undef');
1267- $self->{is_cluster_node}->{$cxn} = $row && $row->[1]
1268- ? ($row->[1] eq 'ON' || $row->[1] eq '1')
1269- : 0;
1270-
1271- return $self->{is_cluster_node}->{$cxn};
1272+ PTDEBUG && _d(Dumper($row));
1273+ return unless $row && $row->[1] && ($row->[1] eq 'ON' || $row->[1] eq '1');
1274+
1275+ my $cluster_name = $self->get_cluster_name($cxn);
1276+ return $cluster_name;
1277+}
1278+
1279+sub same_node {
1280+ my ($self, $cxn1, $cxn2) = @_;
1281+
1282+ my $sql = "SHOW VARIABLES LIKE 'wsrep\_sst\_receive\_address'";
1283+ PTDEBUG && _d($cxn1->name, $sql);
1284+ my (undef, $val1) = $cxn1->dbh->selectrow_array($sql);
1285+ PTDEBUG && _d($cxn2->name, $sql);
1286+ my (undef, $val2) = $cxn2->dbh->selectrow_array($sql);
1287+
1288+ return ($val1 || '') eq ($val2 || '');
1289 }
1290
1291 sub same_cluster {
1292 my ($self, $cxn1, $cxn2) = @_;
1293- return unless $self->is_cluster_node($cxn1) && $self->is_cluster_node($cxn2);
1294- return if $self->is_master_of($cxn1, $cxn2) || $self->is_master_of($cxn2, $cxn1);
1295-
1296- my $sql = q{SHOW VARIABLES LIKE 'wsrep_cluster_name'};
1297- PTDEBUG && _d($sql);
1298- my (undef, $row) = $cxn1->dbh->selectrow_array($sql);
1299- my (undef, $cxn2_row) = $cxn2->dbh->selectrow_array($sql);
1300-
1301- return unless $row eq $cxn2_row;
1302-
1303- # Now it becomes tricky. Ostensibly clusters shouldn't have the
1304- # same name, but tell that to the world.
1305- $sql = q{SHOW VARIABLES LIKE 'wsrep_cluster_address'};
1306- PTDEBUG && _d($sql);
1307- my (undef, $addr) = $cxn1->dbh->selectrow_array($sql);
1308- my (undef, $cxn2_addr) = $cxn2->dbh->selectrow_array($sql);
1309-
1310- # If they both have gcomm://, then they are both the first
1311- # node of a cluster, so they can't be in the same one.
1312- return if $addr eq 'gcomm://' && $cxn2_addr eq 'gcomm://';
1313-
1314- if ( $addr eq 'gcomm://' ) {
1315- $addr = $self->_find_full_gcomm_addr($cxn1->dbh);
1316- }
1317- elsif ( $cxn2_addr eq 'gcomm://' ) {
1318- $cxn2_addr = $self->_find_full_gcomm_addr($cxn2->dbh);
1319- }
1320-
1321- # Meanwhile, if they have the same address, then
1322- # they are definitely part of the same cluster
1323- return 1 if lc($addr) eq lc($cxn2_addr);
1324-
1325- # However, this still leaves us with the issue that
1326- # the cluster addresses could look like this:
1327- # node1 -> node2, node2 -> node1,
1328- # or
1329- # node1 -> node2 addr,
1330- # node2 -> node3 addr,
1331- # node3 -> node1 addr,
1332- # TODO No clue what to do here
1333- return 1;
1334-}
1335-
1336-sub is_master_of {
1337- my ($self, $cxn1, $cxn2) = @_;
1338-
1339- my $cxn2_dbh = $cxn2->dbh;
1340- my $sql = q{SHOW SLAVE STATUS};
1341- PTDEBUG && _d($sql);
1342- local $cxn2_dbh->{FetchHashKeyName} = 'NAME_lc';
1343- my $slave_status = $cxn2_dbh->selectrow_hashref($sql);
1344- return unless ref($slave_status) eq 'HASH';
1345-
1346- my $port = $cxn1->dsn->{P};
1347- return unless $slave_status->{master_port} eq $port;
1348- return 1 if $cxn1->dsn->{h} eq $slave_status->{master_host};
1349-
1350- # They might be the same but in different format
1351- my $host = scalar gethostbyname($cxn1->dsn->{h});
1352- my $master_host = scalar gethostbyname($slave_status->{master_host});
1353- return 1 if $master_host eq $host;
1354- return;
1355-}
1356-
1357-sub _find_full_gcomm_addr {
1358- my ($self, $dbh) = @_;
1359-
1360- my $sql = q{SHOW VARIABLES LIKE 'wsrep_provider_options'};
1361- PTDEBUG && _d($sql);
1362- my (undef, $provider_opts) = $dbh->selectrow_array($sql);
1363- my ($prov_addr) = $provider_opts =~ m{\Qgmcast.listen_addr\E\s*=\s*tcp://([^:]+:[0-9]+)\s*;}i;
1364- my $full_gcomm = "gcomm://$prov_addr";
1365- PTDEBUG && _d("gcomm address: ", $full_gcomm);
1366- return $full_gcomm;
1367+
1368+ # They can't be the same cluster if one of them isn't in a cluster.
1369+ return 0 if !$self->is_cluster_node($cxn1) || !$self->is_cluster_node($cxn2);
1370+
1371+ my $cluster1 = $self->get_cluster_name($cxn1);
1372+ my $cluster2 = $self->get_cluster_name($cxn2);
1373+
1374+ return ($cluster1 || '') eq ($cluster2 || '');
1375+}
1376+
1377+sub _d {
1378+ my ($package, undef, $line) = caller 0;
1379+ @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
1380+ map { defined $_ ? $_ : 'undef' }
1381+ @_;
1382+ print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
1383 }
1384
1385 1;
1386 }
1387+# ###########################################################################
1388+# End Percona::XtraDB::Cluster package
1389+# ###########################################################################
1390
1391=== modified file 'lib/Sandbox.pm'
1392--- lib/Sandbox.pm 2012-11-08 20:47:00 +0000
1393+++ lib/Sandbox.pm 2012-11-19 18:49:19 +0000
1394@@ -53,6 +53,20 @@
1395 master4 => 2901,
1396 master5 => 2902,
1397 master6 => 2903,
1398+ node1 => 12345, # pxc...
1399+ node2 => 12346,
1400+ node3 => 12347,
1401+ node4 => 2900,
1402+ node5 => 2901,
1403+ node6 => 2902,
1404+ cmaster => 12349, # master -> cluster
1405+ cslave1 => 12348, # cluster -> slave
1406+);
1407+
1408+my %server_type = (
1409+ master => 1,
1410+ slave => 1,
1411+ node => 1,
1412 );
1413
1414 my $test_dbs = qr/^(?:mysql|information_schema|sakila|performance_schema|percona_test)$/;
1415@@ -315,9 +329,9 @@
1416
1417 # Dings a heartbeat on the master, and waits until the slave catches up fully.
1418 sub wait_for_slaves {
1419- my $self = shift;
1420+ my ($self, $slave) = @_;
1421 my $master_dbh = $self->get_dbh_for('master');
1422- my $slave2_dbh = $self->get_dbh_for('slave2');
1423+ my $slave2_dbh = $self->get_dbh_for($slave || 'slave2');
1424 my ($ping) = $master_dbh->selectrow_array("SELECT MD5(RAND())");
1425 $master_dbh->do("UPDATE percona_test.sentinel SET ping='$ping' WHERE id=1");
1426 PerconaTest::wait_until(
1427@@ -329,14 +343,6 @@
1428 );
1429 }
1430
1431-sub _d {
1432- my ($package, undef, $line) = caller 0;
1433- @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
1434- map { defined $_ ? $_ : 'undef' }
1435- @_;
1436- print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
1437-}
1438-
1439 # Verifies that master, slave1, and slave2 have a faithful copy of the mysql and
1440 # sakila databases. The reference data is inserted into percona_test.checksums
1441 # by util/checksum-test-dataset when sandbox/test-env starts the environment.
1442@@ -438,12 +444,40 @@
1443 }
1444
1445 sub start_sandbox {
1446- my ($self, $mode, $server, $master_server) = @_;
1447- my $port = $port_for{$server};
1448- my $master_port = $master_server ? $port_for{$master_server} : '';
1449- my $out = `$trunk/sandbox/start-sandbox $mode $port $master_port`;
1450- die $out if $CHILD_ERROR;
1451- return $out;
1452+ my ($self, %args) = @_;
1453+ my @required_args = qw(type server);
1454+ foreach my $arg ( @required_args ) {
1455+ die "I need a $arg argument" unless $args{$arg};
1456+ };
1457+ my ($type, $server) = @args{@required_args};
1458+ my $env = $args{env} || '';
1459+
1460+ die "Invalid server type: $type" unless $server_type{$type};
1461+ _check_server($server);
1462+ my $port = $port_for{$server};
1463+
1464+ if ( $type eq 'master') {
1465+ my $out = `$env $trunk/sandbox/start-sandbox $type $port`;
1466+ die $out if $CHILD_ERROR;
1467+ }
1468+ elsif ( $type eq 'slave' ) {
1469+ die "I need a slave arg" unless $args{master};
1470+ _check_server($args{master});
1471+ my $master_port = $port_for{$args{master}};
1472+
1473+ my $out = `$env $trunk/sandbox/start-sandbox $type $port $master_port`;
1474+ die $out if $CHILD_ERROR;
1475+ }
1476+ elsif ( $type eq 'node' ) {
1477+ my $first_node = $args{first_node} ? $port_for{$args{first_node}} : '';
1478+ my $out = `$env $trunk/sandbox/start-sandbox cluster $port $first_node`;
1479+ die $out if $CHILD_ERROR;
1480+ }
1481+
1482+ my $dbh = $self->get_dbh_for($server, $args{cxn_opts});
1483+ my $dsn = $self->dsn_for($server);
1484+
1485+ return $dbh, $dsn;
1486 }
1487
1488 sub stop_sandbox {
1489@@ -456,44 +490,38 @@
1490
1491 sub start_cluster {
1492 my ($self, %args) = @_;
1493- my $cluster_size = $args{cluster_size} || 3;
1494-
1495- my $out = '';
1496-
1497- my ($node1, @nodes) = map {
1498- my $node_name = "node$_";
1499- $node_name = "_$node_name" while exists $port_for{$node_name};
1500- $port_for{$node_name} = $self->_get_unused_port();
1501- $node_name
1502- } 1..$cluster_size;
1503-
1504- local $ENV{CLUSTER_NAME} = $args{cluster_name} if $args{cluster_name};
1505- $self->start_sandbox("cluster", $node1);
1506- for my $node ( @nodes ) {
1507- $self->start_sandbox("cluster", $node, $node1);
1508- }
1509-
1510- return ($node1, @nodes);
1511-}
1512-
1513-# Lifted from Nginx::Test on CPAN
1514-sub _get_unused_port {
1515- my $port = 50000 + int (rand() * 5000);
1516-
1517- while ($port++ < 64000) {
1518- my $sock = IO::Socket::INET->new (
1519- Listen => 5,
1520- LocalAddr => '127.0.0.1',
1521- LocalPort => $port,
1522- Proto => 'tcp',
1523- ReuseAddr => 1
1524- ) or next;
1525-
1526- $sock->close;
1527- return $port;
1528- }
1529-
1530- die "Cannot find an open port";
1531+ my @required_args = qw(nodes);
1532+ foreach my $arg ( @required_args ) {
1533+ die "I need a $arg argument" unless $args{$arg};
1534+ };
1535+ my ($nodes) = @args{@required_args};
1536+
1537+ foreach my $node ( @$nodes ) {
1538+ _check_server($node);
1539+ }
1540+
1541+ Test::More::diag("Starting cluster with @$nodes");
1542+ my %connect;
1543+
1544+ my $first_node = shift @$nodes;
1545+ my ($dbh, $dsn) = $self->start_sandbox(
1546+ type => "node",
1547+ server => $first_node,
1548+ env => $args{env},
1549+ );
1550+ $connect{$first_node} = { dbh => $dbh, dsn => $dsn };
1551+
1552+ foreach my $node ( @$nodes ) {
1553+ my ($dbh, $dsn) = $self->start_sandbox(
1554+ server => $node,
1555+ type => "node",
1556+ first_node => $first_node,
1557+ env => $args{env},
1558+ );
1559+ $connect{$node} = { dbh => $dbh, dsn => $dsn };
1560+ }
1561+
1562+ return \%connect;
1563 }
1564
1565 sub port_for {
1566@@ -501,6 +529,14 @@
1567 return $port_for{$server};
1568 }
1569
1570+sub _d {
1571+ my ($package, undef, $line) = caller 0;
1572+ @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
1573+ map { defined $_ ? $_ : 'undef' }
1574+ @_;
1575+ print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
1576+}
1577+
1578 1;
1579 }
1580 # ###########################################################################
1581
1582=== modified file 't/pt-table-checksum/pxc.t'
1583--- t/pt-table-checksum/pxc.t 2012-11-07 07:06:50 +0000
1584+++ t/pt-table-checksum/pxc.t 2012-11-19 18:49:19 +0000
1585@@ -11,7 +11,6 @@
1586 use English qw(-no_match_vars);
1587 use Test::More;
1588 use Data::Dumper;
1589-use File::Spec::Functions;
1590
1591 # Hostnames make testing less accurate. Tests need to see
1592 # that such-and-such happened on specific slave hosts, but
1593@@ -28,21 +27,29 @@
1594
1595 my $dp = new DSNParser(opts=>$dsn_opts);
1596 my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
1597-my $master_dbh = $sb->get_dbh_for('master');
1598-
1599-my $db_flavor = VersionParser->new($master_dbh)->flavor();
1600-
1601-if ( !$master_dbh ) {
1602- plan skip_all => 'Cannot connect to sandbox master';
1603-}
1604-elsif ( $db_flavor !~ /XtraDB Cluster/ ) {
1605+my $node1 = $sb->get_dbh_for('node1');
1606+my $node2 = $sb->get_dbh_for('node2');
1607+my $node3 = $sb->get_dbh_for('node3');
1608+
1609+my $db_flavor = VersionParser->new($node1)->flavor();
1610+
1611+if ( $db_flavor !~ /XtraDB Cluster/ ) {
1612 plan skip_all => "PXC tests";
1613 }
1614+elsif ( !$node1 ) {
1615+ plan skip_all => 'Cannot connect to cluster node1';
1616+}
1617+elsif ( !$node2 ) {
1618+ plan skip_all => 'Cannot connect to cluster node2';
1619+}
1620+elsif ( !$node3 ) {
1621+ plan skip_all => 'Cannot connect to cluster node3';
1622+}
1623
1624 # The sandbox servers run with lock_wait_timeout=3 and it's not dynamic
1625 # so we need to specify --lock-wait-timeout=3 else the tool will die.
1626-my $master_dsn = 'h=127.1,P=12345,u=msandbox,p=msandbox';
1627-my @args = ($master_dsn, qw(--lock-wait-timeout 3));
1628+my $node1_dsn = $sb->dsn_for('node1');
1629+my @args = ($node1_dsn, qw(--lock-wait-timeout 3));
1630 my $output;
1631 my $exit_status;
1632 my $sample = "t/pt-table-checksum/samples/";
1633@@ -52,191 +59,545 @@
1634 # https://bugs.launchpad.net/percona-toolkit/+bug/1062563
1635 # #############################################################################
1636
1637-sub make_dbh_differ {
1638- my ($dbh, @vals) = @_;
1639- @vals = (@vals ? @vals : 1);
1640- # Make them differ...
1641- $dbh->do("DROP DATABASE IF EXISTS bug_1062563");
1642- $dbh->do("CREATE DATABASE bug_1062563");
1643- $dbh->do("CREATE TABLE bug_1062563.ptc_pxc (i int)");
1644-
1645- # Now make this node different from the rest
1646- $dbh->do("set sql_log_bin=0");
1647- $dbh->do("INSERT INTO bug_1062563.ptc_pxc (i) VALUES ($_)") for @vals;
1648- $dbh->do("set sql_log_bin=1");
1649-}
1650-
1651-diag("Creating a 5-node PXC cluster...");
1652-my @nodes = $sb->start_cluster(cluster_size => 5);
1653-diag("Nodes: ", Dumper( { map { $_ => $sb->port_for($_) } @nodes } ));
1654-
1655-my $node2 = $nodes[1];
1656-my $node2_dbh = $sb->get_dbh_for($node2);
1657-
1658-my $node2_slave = "master3";
1659-
1660-diag("Creating a slave for $node2...");
1661-{
1662- local $ENV{BINLOG_FORMAT} = 'ROW';
1663- diag($sb->start_sandbox("slave", $node2_slave, $node2));
1664-}
1665-my $node_slave_dbh = $sb->get_dbh_for($node2_slave);
1666-
1667-make_dbh_differ($node2_dbh);
1668-
1669-# And make its slave differ as well
1670-PerconaTest::wait_for_table($sb->get_dbh_for($nodes[-1]), "bug_1062563.ptc_pxc");
1671-PerconaTest::wait_for_table($node_slave_dbh, "bug_1062563.ptc_pxc");
1672-$node_slave_dbh->do("INSERT INTO bug_1062563.ptc_pxc (i) VALUES ($_)") for 3, 4;
1673-
1674-my $dsns_table_sql = catfile(qw(t lib samples MasterSlave dsn_table.sql));
1675-$sb->load_file($node2, $dsns_table_sql, undef, no_wait => 1);
1676-$node2_dbh->do("DELETE FROM dsn_t.dsns"); # Delete 12346
1677-my $sth = $node2_dbh->prepare("INSERT INTO dsn_t.dsns VALUES (null, null, ?)");
1678-for my $dsn ( map { $sb->dsn_for($_) } @nodes[0,2..$#nodes], $node2_slave ) {
1679- $sth->execute($dsn);
1680-}
1681-
1682-my $node2_dsn = $sb->dsn_for($node2);
1683-$output = output(
1684- sub { pt_table_checksum::main(
1685- $node2_dsn, qw(--lock-wait-timeout 3),
1686- qw(-d bug_1062563),
1687- '--recursion-method', "dsn=D=dsn_t,t=dsns"
1688- ) },
1689- stderr => 1,
1690-);
1691-
1692-is(
1693- PerconaTest::count_checksum_results($output, 'diffs'),
1694- 1,
1695- "Bug 1062563: Detects diffs between PXC nodes"
1696-) or diag($output);
1697-
1698-my @cluster_nodes = $output =~ /(because it is a cluster node)/g;
1699-is(
1700- scalar(@cluster_nodes),
1701- 4,
1702- "Skips all the cluster nodes in the dsns table"
1703-) or diag($output);
1704-
1705-# Now try with just the slave
1706-
1707-$node2_dbh->do("DELETE FROM dsn_t.dsns");
1708-$sth->execute($sb->dsn_for($node2_slave));
1709-
1710-$output = output(
1711- sub { pt_table_checksum::main(
1712- $node2_dsn, qw(--lock-wait-timeout 3),
1713- qw(--chunk-size 1),
1714- qw(-d bug_1062563),
1715- '--recursion-method', "dsn=D=dsn_t,t=dsns"
1716- ) },
1717- stderr => 1,
1718-);
1719-
1720-is(
1721- PerconaTest::count_checksum_results($output, 'diffs'),
1722- 1,
1723- "Bug 1062563: Detects diffs on slaves where the master is a PXC node"
1724-) or diag($output);
1725-
1726-$sth->finish();
1727-diag("Stopping the PXC cluster and the slave...");
1728-$sb->stop_sandbox($node2_slave, @nodes);
1729-
1730-# Now checking that cluster -> cluster works
1731-
1732-diag("Creating two 3-node clusters...");
1733-my @cluster1 = $sb->start_cluster(cluster_size => 3, cluster_name => "pt_test_cluster_1");
1734-my @cluster2 = $sb->start_cluster(cluster_size => 3, cluster_name => "pt_test_cluster_2");
1735-diag("Cluster 1: ", Dumper( { map { $_ => $sb->port_for($_) } @cluster1 } ));
1736-diag("Cluster 2: ", Dumper( { map { $_ => $sb->port_for($_) } @cluster2 } ));
1737-
1738-$sb->set_as_slave($cluster2[0], $cluster1[0]);
1739-
1740-my $cluster1_dbh = $sb->get_dbh_for($cluster1[0]);
1741-my $cluster2_dbh = $sb->get_dbh_for($cluster2[0]);
1742-make_dbh_differ($cluster1_dbh);
1743-
1744-# And make its slave differ as well
1745-PerconaTest::wait_for_table($sb->get_dbh_for($cluster2[-1]), "bug_1062563.ptc_pxc");
1746-PerconaTest::wait_for_table($sb->get_dbh_for($cluster1[-1]), "bug_1062563.ptc_pxc");
1747-PerconaTest::wait_for_table($cluster2_dbh, "bug_1062563.ptc_pxc");
1748-$cluster2_dbh->do("INSERT INTO bug_1062563.ptc_pxc (i) VALUES ($_)") for 3, 4;
1749-
1750-$dsns_table_sql = catfile(qw(t lib samples MasterSlave dsn_table.sql));
1751-$sb->load_file($cluster1[0], $dsns_table_sql, undef, no_wait => 1);
1752-$cluster1_dbh->do("DELETE FROM dsn_t.dsns"); # Delete 12346
1753-$sth = $cluster1_dbh->prepare("INSERT INTO dsn_t.dsns VALUES (null, null, ?)");
1754-for my $dsn ( map { $sb->dsn_for($_) } @cluster1[1..$#cluster1], $cluster2[0] ) {
1755- $sth->execute($dsn);
1756-}
1757-$sth->finish();
1758-
1759-my $cluster1_dsn = $sb->dsn_for($cluster1[0]);
1760-$output = output(
1761- sub { pt_table_checksum::main(
1762- $cluster1_dsn, qw(--lock-wait-timeout 3),
1763- qw(-d bug_1062563),
1764- '--recursion-method', "dsn=D=dsn_t,t=dsns"
1765- ) },
1766- stderr => 1,
1767-);
1768-
1769-is(
1770- PerconaTest::count_checksum_results($output, 'diffs'),
1771- 1,
1772- "Bug 1062563: Detects diffs between PXC nodes when cluster -> cluster"
1773-) or diag($output);
1774-
1775-like(
1776- $output,
1777- qr/is a cluster node, but doesn't belong to the same cluster as/, #'
1778- "Shows a warning when cluster -> cluster"
1779-) or diag($output);
1780-
1781-diag("Starting master1...");
1782-$sb->start_sandbox("master", "master1");
1783-diag("Setting it as master of a node in the first cluster");
1784-$sb->set_as_slave($cluster1[0], "master1");
1785-
1786-my $master1_dbh = $sb->get_dbh_for("master1");
1787-make_dbh_differ($master1_dbh, 10..50);
1788-
1789-my $master1_dsn = $sb->dsn_for("master1");
1790-$output = output(
1791- sub { pt_table_checksum::main(
1792- $master1_dsn, qw(--lock-wait-timeout 3),
1793- qw(-d bug_1062563),
1794- ) },
1795- stderr => 1,
1796-);
1797-
1798-is(
1799- PerconaTest::count_checksum_results($output, 'diffs'),
1800- 1,
1801- "Bug 1062563: Detects diffs when master -> cluster"
1802-) or diag($output);
1803-
1804-is(
1805- PerconaTest::count_checksum_results($output, 'rows'),
1806- 41,
1807- "Bug 1062563: Correct number of rows for master -> cluster"
1808-) or diag($output);
1809-
1810-like(
1811- $output,
1812- qr/is a cluster node, but .*? is not. This is not currently supported/,
1813- "Shows a warning when master -> cluster"
1814-) or diag($output);
1815-
1816-diag("Stopping both clusters and master1...");
1817-$sb->stop_sandbox(@cluster1, @cluster2, "master1");
1818+# #############################################################################
1819+# Check just a cluster
1820+# #############################################################################
1821+
1822+# This DSN table has node2 and node3 (12346 and 12347) but not node1 (12345)
1823+# because it was originally created for traditional setups which require only
1824+# slave DSNs, but the DSN table for a PXC setup can/should contain DSNs for
1825+# all nodes so the user can run pxc on any node and find all the others.
1826+$sb->load_file('node1', "$sample/dsn-table.sql");
1827+$node1->do(qq/INSERT INTO dsns.dsns VALUES (1, 1, '$node1_dsn')/);
1828+
1829+# First a little test to make sure the tool detects and bails out
1830+# if no other cluster nodes are detected, in which case the user
1831+# probably didn't specifying --recursion-method dsn.
1832+$output = output(
1833+ sub { pt_table_checksum::main(@args) },
1834+ stderr => 1,
1835+);
1836+
1837+like(
1838+ $output,
1839+ qr/h=127.1,P=12345 is a cluster node but no other nodes/,
1840+ "Dies if no other nodes are found"
1841+);
1842+
1843+$output = output(
1844+ sub { pt_table_checksum::main(@args,
1845+ '--recursion-method', "dsn=$node1_dsn,D=dsns,t=dsns")
1846+ },
1847+ stderr => 1,
1848+);
1849+
1850+is(
1851+ PerconaTest::count_checksum_results($output, 'errors'),
1852+ 0,
1853+ "No diffs: no errors"
1854+);
1855+
1856+is(
1857+ PerconaTest::count_checksum_results($output, 'skipped'),
1858+ 0,
1859+ "No diffs: no skips"
1860+);
1861+
1862+is(
1863+ PerconaTest::count_checksum_results($output, 'diffs'),
1864+ 0,
1865+ "No diffs: no diffs"
1866+);
1867+
1868+# Now really test checksumming a cluster. To create a diff we have to disable
1869+# the binlog. Although PXC doesn't need or use the binlog to communicate
1870+# (it has its own broadcast-based protocol implemented via the Galera lib)
1871+# it still respects sql_log_bin, so we can make a change on one node without
1872+# affecting the others.
1873+$sb->load_file('node1', "$sample/a-z.sql");
1874+$node2->do("set sql_log_bin=0");
1875+$node2->do("update test.t set c='zebra' where c='z'");
1876+$node2->do("set sql_log_bin=1");
1877+
1878+my ($row) = $node2->selectrow_array("select c from test.t order by c desc limit 1");
1879+is(
1880+ $row,
1881+ "zebra",
1882+ "Node2 is changed"
1883+);
1884+
1885+($row) = $node1->selectrow_array("select c from test.t order by c desc limit 1");
1886+is(
1887+ $row,
1888+ "z",
1889+ "Node1 not changed"
1890+);
1891+
1892+($row) = $node3->selectrow_array("select c from test.t order by c desc limit 1");
1893+is(
1894+ $row,
1895+ "z",
1896+ "Node3 not changed"
1897+);
1898+
1899+$output = output(
1900+ sub { pt_table_checksum::main(@args,
1901+ '--recursion-method', "dsn=$node1_dsn,D=dsns,t=dsns")
1902+ },
1903+ stderr => 1,
1904+);
1905+
1906+is(
1907+ PerconaTest::count_checksum_results($output, 'errors'),
1908+ 0,
1909+ "1 diff: no errors"
1910+);
1911+
1912+is(
1913+ PerconaTest::count_checksum_results($output, 'skipped'),
1914+ 0,
1915+ "1 diff: no skips"
1916+);
1917+
1918+is(
1919+ PerconaTest::count_checksum_results($output, 'diffs'),
1920+ 1,
1921+ "1 diff: 1 diff"
1922+) or diag($output);
1923+
1924+# 11-17T13:02:54 0 1 26 1 0 0.021 test.t
1925+like(
1926+ $output,
1927+ qr/^\S+\s+ # ts
1928+ 0\s+ # errors
1929+ 1\s+ # diffs
1930+ 26\s+ # rows
1931+ \d+\s+ # chunks
1932+ 0\s+ # skipped
1933+ \S+\s+ # time
1934+ test.t$ # table
1935+ /xm,
1936+ "1 diff: it's in test.t"
1937+);
1938+
1939+# #############################################################################
1940+# cluster, node1 -> slave, run on node1
1941+# #############################################################################
1942+
1943+my ($slave_dbh, $slave_dsn) = $sb->start_sandbox(
1944+ server => 'cslave1',
1945+ type => 'slave',
1946+ master => 'node1',
1947+ env => q/BINLOG_FORMAT="ROW"/,
1948+);
1949+
1950+# Add the slave to the DSN table.
1951+$node1->do(qq/INSERT INTO dsns.dsns VALUES (4, 3, '$slave_dsn')/);
1952+
1953+# Fix what we changed earlier on node2 so the cluster is consistent.
1954+$node2->do("set sql_log_bin=0");
1955+$node2->do("update test.t set c='z' where c='zebra'");
1956+$node2->do("set sql_log_bin=1");
1957+
1958+# Wait for the slave to apply the binlogs from node1 (its master).
1959+# Then change it so it's not consistent.
1960+PerconaTest::wait_for_table($slave_dbh, 'test.t');
1961+$sb->wait_for_slaves('cslave1');
1962+$slave_dbh->do("update test.t set c='zebra' where c='z'");
1963+
1964+# Another quick test first: the tool should complain about the slave's
1965+# binlog format but only the slave's, not the cluster nodes:
1966+# https://bugs.launchpad.net/percona-toolkit/+bug/1080385
1967+# Cluster nodes default to ROW format because that's what Galeara
1968+# works best with, even though it doesn't really use binlogs.
1969+$output = output(
1970+ sub { pt_table_checksum::main(@args,
1971+ '--recursion-method', "dsn=$node1_dsn,D=dsns,t=dsns")
1972+ },
1973+ stderr => 1,
1974+);
1975+
1976+like(
1977+ $output,
1978+ qr/replica h=127.1,P=12348 has binlog_format ROW/,
1979+ "--check-binlog-format warns about slave's binlog format"
1980+);
1981+
1982+# Now really test that diffs on the slave are detected.
1983+$output = output(
1984+ sub { pt_table_checksum::main(@args,
1985+ '--recursion-method', "dsn=$node1_dsn,D=dsns,t=dsns",
1986+ qw(--no-check-binlog-format)),
1987+ },
1988+ stderr => 1,
1989+);
1990+
1991+is(
1992+ PerconaTest::count_checksum_results($output, 'diffs'),
1993+ 1,
1994+ "Detects diffs on slave of cluster node1"
1995+) or diag($output);
1996+
1997+$slave_dbh->disconnect;
1998+$sb->stop_sandbox('cslave1');
1999+
2000+# #############################################################################
2001+# cluster, node2 -> slave, run on node1
2002+#
2003+# Does not work because we only set binglog_format=STATEMENT on node1 which
2004+# does not affect other nodes, so node2 gets checksum queries in STATEMENT
2005+# format, executes them, but then logs the results in ROW format (since ROW
2006+# format is the default for cluster nodes) which doesn't work on the slave
2007+# (i.e. the slave doesn't execute the query). So any diffs on the slave are
2008+# not detected.
2009+# #############################################################################
2010+
2011+($slave_dbh, $slave_dsn) = $sb->start_sandbox(
2012+ server => 'cslave1',
2013+ type => 'slave',
2014+ master => 'node2',
2015+ env => q/BINLOG_FORMAT="ROW"/,
2016+);
2017+
2018+# Wait for the slave to apply the binlogs from node2 (its master).
2019+# Then change it so it's not consistent.
2020+PerconaTest::wait_for_table($slave_dbh, 'test.t');
2021+$sb->wait_for_slaves('cslave1');
2022+$slave_dbh->do("update test.t set c='zebra' where c='z'");
2023+
2024+($row) = $slave_dbh->selectrow_array("select c from test.t order by c desc limit 1");
2025+is(
2026+ $row,
2027+ "zebra",
2028+ "Slave is changed"
2029+);
2030+
2031+$output = output(
2032+ sub { pt_table_checksum::main(@args,
2033+ '--recursion-method', "dsn=$node1_dsn,D=dsns,t=dsns",
2034+ qw(--no-check-binlog-format -d test)),
2035+ },
2036+ stderr => 1,
2037+);
2038+
2039+is(
2040+ PerconaTest::count_checksum_results($output, 'diffs'),
2041+ 0,
2042+ "Limitation: does not detect diffs on slave of cluster node2"
2043+) or diag($output);
2044+
2045+$slave_dbh->disconnect;
2046+$sb->stop_sandbox('cslave1');
2047+
2048+# Restore the original DSN table.
2049+$node1->do(qq/DELETE FROM dsns.dsns WHERE id=4/);
2050+
2051+# #############################################################################
2052+# master -> node1 in cluster, run on master
2053+# #############################################################################
2054+
2055+my ($master_dbh, $master_dsn) = $sb->start_sandbox(
2056+ server => 'cmaster',
2057+ type => 'master',
2058+ env => q/BINLOG_FORMAT="ROW"/,
2059+);
2060+
2061+# CAREFUL: The master and the cluster are different, so we must load dbs on
2062+# the master then flush the logs, else node1 will apply the master's binlogs
2063+# and blow up because it already had these dbs.
2064+
2065+# Remember: this DSN table only has node2 and node3 (12346 and 12347) which is
2066+# sufficient for this test.
2067+$sb->load_file('cmaster', "$sample/dsn-table.sql");
2068+
2069+# We have to load a-z-cluster.sql else the pk id won'ts match because nodes use
2070+# auto-inc offsets but the master doesn't.
2071+$sb->load_file('cmaster', "$sample/a-z-cluster.sql");
2072+
2073+$master_dbh->do("FLUSH LOGS");
2074+$master_dbh->do("RESET MASTER");
2075+
2076+$sb->set_as_slave('node1', 'cmaster');
2077+
2078+# Notice: no --recursion-method=dsn yet. Since node1 is a traditional slave
2079+# of the master, ptc should auto-detect it, which we'll test later by making
2080+# the slave differ.
2081+$output = output(
2082+ sub { pt_table_checksum::main($master_dsn,
2083+ qw(-d test))
2084+ },
2085+ stderr => 1,
2086+);
2087+
2088+is(
2089+ PerconaTest::count_checksum_results($output, 'errors'),
2090+ 0,
2091+ "master->cluster no diffs: no errors"
2092+);
2093+
2094+is(
2095+ PerconaTest::count_checksum_results($output, 'skipped'),
2096+ 0,
2097+ "master->cluster no diffs: no skips"
2098+);
2099+
2100+is(
2101+ PerconaTest::count_checksum_results($output, 'diffs'),
2102+ 0,
2103+ "master->cluster no diffs: no diffs"
2104+) or diag($output);
2105+
2106+# Make a diff on node1. If ptc is really auto-detecting node1, then it
2107+# should report this diff.
2108+$node1->do("set sql_log_bin=0");
2109+$node1->do("update test.t set c='zebra' where c='z'");
2110+$node1->do("set sql_log_bin=1");
2111+
2112+$output = output(
2113+ sub { pt_table_checksum::main($master_dsn,
2114+ qw(-d test))
2115+ },
2116+ stderr => 1,
2117+);
2118+
2119+is(
2120+ PerconaTest::count_checksum_results($output, 'errors'),
2121+ 0,
2122+ "master->cluster 1 diff: no errors"
2123+);
2124+
2125+is(
2126+ PerconaTest::count_checksum_results($output, 'skipped'),
2127+ 0,
2128+ "master->cluster 1 diff: no skips"
2129+);
2130+
2131+is(
2132+ PerconaTest::count_checksum_results($output, 'diffs'),
2133+ 1,
2134+ "master->cluster 1 diff: 1 diff"
2135+) or diag($output);
2136+
2137+# 11-17T13:02:54 0 1 26 1 0 0.021 test.t
2138+like(
2139+ $output,
2140+ qr/^\S+\s+ # ts
2141+ 0\s+ # errors
2142+ 1\s+ # diffs
2143+ 26\s+ # rows
2144+ \d+\s+ # chunks
2145+ 0\s+ # skipped
2146+ \S+\s+ # time
2147+ test.t$ # table
2148+ /xm,
2149+ "master->cluster 1 diff: it's in test.t"
2150+);
2151+
2152+# Use the DSN table to check for diffs on node2 and node3. This works
2153+# because the diff is on node1 and node1 is the direct slave of the master,
2154+# so the checksum query will replicate from the master in STATEMENT format,
2155+# node1 will execute it, find the diff, then broadcast that result to all
2156+# other nodes. -- Remember: the DSN table on the master has node2 and node3.
2157+$output = output(
2158+ sub { pt_table_checksum::main($master_dsn,
2159+ '--recursion-method', "dsn=$master_dsn,D=dsns,t=dsns",
2160+ qw(-d test))
2161+ },
2162+ stderr => 1,
2163+);
2164+
2165+is(
2166+ PerconaTest::count_checksum_results($output, 'errors'),
2167+ 0,
2168+ "...check other nodes: no errors"
2169+);
2170+
2171+is(
2172+ PerconaTest::count_checksum_results($output, 'skipped'),
2173+ 0,
2174+ "...check other nodes: no skips"
2175+);
2176+
2177+is(
2178+ PerconaTest::count_checksum_results($output, 'diffs'),
2179+ 1,
2180+ "...check other nodes: 1 diff"
2181+) or diag($output);
2182+
2183+# 11-17T13:02:54 0 1 26 1 0 0.021 test.t
2184+like(
2185+ $output,
2186+ qr/^\S+\s+ # ts
2187+ 0\s+ # errors
2188+ 1\s+ # diffs
2189+ 26\s+ # rows
2190+ \d+\s+ # chunks
2191+ 0\s+ # skipped
2192+ \S+\s+ # time
2193+ test.t$ # table
2194+ /xm,
2195+ "...check other nodes: it's in test.t"
2196+);
2197+
2198+like(
2199+ $output,
2200+ qr/the direct replica of h=127.1,P=12349 was not found or specified/,
2201+ "Warns that direct replica of the master isn't found or specified",
2202+);
2203+
2204+# Use the other DSN table with all three nodes. Now the tool should
2205+# give a more specific warning than that ^.
2206+$output = output(
2207+ sub { pt_table_checksum::main($master_dsn,
2208+ '--recursion-method', "dsn=$node1_dsn,D=dsns,t=dsns",
2209+ qw(-d test))
2210+ },
2211+ stderr => 1,
2212+);
2213+
2214+is(
2215+ PerconaTest::count_checksum_results($output, 'diffs'),
2216+ 1,
2217+ "...check all nodes: 1 diff"
2218+) or diag($output);
2219+
2220+# 11-17T13:02:54 0 1 26 1 0 0.021 test.t
2221+like(
2222+ $output,
2223+ qr/^\S+\s+ # ts
2224+ 0\s+ # errors
2225+ 1\s+ # diffs
2226+ 26\s+ # rows
2227+ \d+\s+ # chunks
2228+ 0\s+ # skipped
2229+ \S+\s+ # time
2230+ test.t$ # table
2231+ /xm,
2232+ "...check all nodes: it's in test.t"
2233+);
2234+
2235+like(
2236+ $output,
2237+ qr/Diffs will only be detected if the cluster is consistent with h=127.1,P=12345 because h=127.1,P=12349/,
2238+ "Warns that diffs only detected if cluster consistent with direct replica",
2239+);
2240+
2241+# Restore node1 so the cluster is consistent, but then make node2 differ.
2242+# ptc should NOT detect this diff because the checksum query will replicate
2243+# to node1, node1 isn't different, so it broadcasts the result in ROW format
2244+# that all is ok, which node2 gets and thus false reports. This is why
2245+# those ^ warnings exist.
2246+$node1->do("set sql_log_bin=0");
2247+$node1->do("update test.t set c='z' where c='zebra'");
2248+$node1->do("set sql_log_bin=1");
2249+
2250+$node2->do("set sql_log_bin=0");
2251+$node2->do("update test.t set c='zebra' where c='z'");
2252+$node2->do("set sql_log_bin=1");
2253+
2254+($row) = $node2->selectrow_array("select c from test.t order by c desc limit 1");
2255+is(
2256+ $row,
2257+ "zebra",
2258+ "Node2 is changed again"
2259+);
2260+
2261+($row) = $node1->selectrow_array("select c from test.t order by c desc limit 1");
2262+is(
2263+ $row,
2264+ "z",
2265+ "Node1 not changed again"
2266+);
2267+
2268+($row) = $node3->selectrow_array("select c from test.t order by c desc limit 1");
2269+is(
2270+ $row,
2271+ "z",
2272+ "Node3 not changed again"
2273+);
2274+
2275+# the other DSN table with all three nodes, but it won't matter because
2276+# node1 is going to broadcast the false-positive that there are no diffs.
2277+$output = output(
2278+ sub { pt_table_checksum::main($master_dsn,
2279+ '--recursion-method', "dsn=$node1_dsn,D=dsns,t=dsns",
2280+ qw(-d test))
2281+ },
2282+ stderr => 1,
2283+);
2284+
2285+is(
2286+ PerconaTest::count_checksum_results($output, 'diffs'),
2287+ 0,
2288+ "Limitation: diff not on direct replica not detected"
2289+) or diag($output);
2290+
2291+# ###########################################################################
2292+# Be sure to stop the slave on node1, else further test will die with:
2293+# Failed to execute -e "change master to master_host='127.0.0.1',
2294+# master_user='msandbox', master_password='msandbox', master_port=12349"
2295+# on node1: ERROR 1198 (HY000) at line 1: This operation cannot be performed
2296+# with a running slave; run STOP SLAVE first
2297+# ###########################################################################
2298+$master_dbh->disconnect;
2299+$sb->stop_sandbox('cmaster');
2300+$node1->do("STOP SLAVE");
2301+$node1->do("RESET SLAVE");
2302+
2303+# #############################################################################
2304+# cluster -> cluster
2305+#
2306+# This is not supported. The link between the two clusters is probably
2307+# a traditional MySQL replication setup in ROW format, so any checksum
2308+# results will be lost across it.
2309+# #############################################################################
2310+
2311+my $c = $sb->start_cluster(
2312+ nodes => [qw(node4 node5 node6)],
2313+ env => q/CLUSTER_NAME="cluster2"/,
2314+);
2315+
2316+# Load the same db just in case this does work (it shouldn't), then there
2317+# will be normal results instead of an error because the db is missing.
2318+$sb->load_file('node4', "$sample/a-z.sql");
2319+
2320+# Add node4 in the cluster2 to the DSN table.
2321+$node1->do(qq/INSERT INTO dsns.dsns VALUES (5, null, '$c->{node4}->{dsn}')/);
2322+
2323+$output = output(
2324+ sub { pt_table_checksum::main(@args,
2325+ '--recursion-method', "dsn=$node1_dsn,D=dsns,t=dsns",
2326+ qw(-d test))
2327+ },
2328+ stderr => 1,
2329+);
2330+
2331+like(
2332+ $output,
2333+ qr/h=127.1,P=12345 is in cluster pt_sandbox_cluster/,
2334+ "Detects that node1 is in pt_sandbox_cluster"
2335+);
2336+
2337+like(
2338+ $output,
2339+ qr/h=127.1,P=2900 is in cluster cluster2/,
2340+ "Detects that node4 is in cluster2"
2341+);
2342+
2343+unlike(
2344+ $output,
2345+ qr/test/,
2346+ "Different clusters, no results"
2347+);
2348+
2349+$sb->stop_sandbox(qw(node4 node5 node6));
2350+
2351+# Restore the DSN table in case there are more tests.
2352+$node1->do(qq/DELETE FROM dsns.dsns WHERE id=5/);
2353
2354 # #############################################################################
2355 # Done.
2356 # #############################################################################
2357-$sb->wipe_clean($master_dbh);
2358+$sb->wipe_clean($node1);
2359 ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
2360 done_testing;
2361
2362=== added file 't/pt-table-checksum/samples/a-z-cluster.sql'
2363--- t/pt-table-checksum/samples/a-z-cluster.sql 1970-01-01 00:00:00 +0000
2364+++ t/pt-table-checksum/samples/a-z-cluster.sql 2012-11-19 18:49:19 +0000
2365@@ -0,0 +1,10 @@
2366+drop database if exists test;
2367+create database test;
2368+use test;
2369+
2370+create table t (
2371+ id int auto_increment primary key,
2372+ c varchar(16) not null
2373+) engine=innodb;
2374+
2375+INSERT INTO `t` VALUES (1,'a'),(4,'b'),(7,'c'),(10,'d'),(13,'e'),(16,'f'),(19,'g'),(22,'h'),(25,'i'),(28,'j'),(31,'k'),(34,'l'),(37,'m'),(40,'n'),(43,'o'),(46,'p'),(49,'q'),(52,'r'),(55,'s'),(58,'t'),(61,'u'),(64,'v'),(67,'w'),(70,'x'),(73,'y'),(76,'z');

Subscribers

People subscribed via source and target branches