Merge lp:~percona-toolkit-dev/percona-toolkit/fix-1062563-1063912-ptc-pxc-bugs into lp:percona-toolkit/2.1

Proposed by Brian Fraser
Status: Superseded
Proposed branch: lp:~percona-toolkit-dev/percona-toolkit/fix-1062563-1063912-ptc-pxc-bugs
Merge into: lp:percona-toolkit/2.1
Diff against target: 1196 lines (+834/-103)
10 files modified
bin/pt-config-diff (+1/-15)
bin/pt-kill (+9/-19)
bin/pt-online-schema-change (+9/-19)
bin/pt-table-checksum (+144/-25)
lib/Cxn.pm (+1/-15)
lib/Percona/XtraDB/Cluster.pm (+123/-0)
lib/Sandbox.pm (+85/-4)
t/lib/Cxn.t (+4/-6)
t/lib/Percona/XtraDB/Cluster.t (+216/-0)
t/pt-table-checksum/pxc.t (+242/-0)
To merge this branch: bzr merge lp:~percona-toolkit-dev/percona-toolkit/fix-1062563-1063912-ptc-pxc-bugs
Reviewer Review Type Date Requested Status
Daniel Nichter Needs Fixing
Review via email: mp+130191@code.launchpad.net

This proposal has been superseded by a proposal from 2012-11-08.

To post a comment you must log in.
417. By Daniel Nichter

Merge fix-pt-upgrade-select-bug-1060774

418. By Daniel Nichter

Merge fix-938068-ptc-slave-binlog-formats

419. By Daniel Nichter

Merge fix-978133-remove-pqd-priv-checks

420. By Daniel Nichter

Redirect sys cmd 2>/dev/null in pt-kill tests to avoid false-positive errors.

421. By Daniel Nichter

Fix RawLogParser.t. Use diag in PerconaTest.pm.

422. By Daniel Nichter

Remove all_privs tests. Update Percona::Toolkit::VERSION.

423. By Daniel Nichter

Make CompareResults.t stable--yet another case of not waiting for replication.

424. By Daniel Nichter

Merge fix-pt-osc-del-trg-bug-1062324.

425. By Daniel Nichter

Merge opt-parsing-exit-status-bug-1039074.

426. By Daniel Nichter

Merge quiet-progress-bug-1039541.

427. By Daniel Nichter

Merge pdl-partitions-bug-1043528.

428. By Daniel Nichter

Merge pt-stalk-iter-1-bug-1070434.

429. By Daniel Nichter

Merge find_my_cnf_file-bug-1070916.

430. By Daniel Nichter

Remove $Sandbox::Percona::Toolkit::VERSION and use $Percona::Toolkit::VERSION instead since it's the authoritative version.

431. By Daniel Nichter

Add deprecation notice to pt-log-player for PT 2.2.

432. By Daniel Nichter

Fix t/pt-slave-delay/auto_restart.t and use direct call, no backticks.

433. By Daniel Nichter

Don't use literal values for t/pt-heartbeat/basics.t 'It is being updated' test. Use direct call rather than backticks.

434. By Daniel Nichter

Make pt-archiver --sleep tests more precise and reliable.

435. By Daniel Nichter

Merge fix-ptc-slave-binglog-formats-on-5.0.

436. By Daniel Nichter

Merge pt-find-docu-bug-1013407

437. By Daniel Nichter

Merge fix-995896-cat-in-daemon

438. By Brian Fraser

Merged fix-821715-enable-local-infile-in-dsn

439. By Brian Fraser

Merged fix-1052722-pt-fifo-split-n-minus-1-rows-initially

440. By Brian Fraser

Updated modules in all tools

Revision history for this message
Daniel Nichter (daniel-nichter) wrote :

Are the new subs in Sandbox.pm and how Cxn.t works with a cluster vestiges of portable-test-suite, or can we do this stuff now with the sandbox/ scripts?

review: Needs Information
Revision history for this message
Brian Fraser (fraserbn) wrote :

->start_sandbox, ->stop_sandbox and ->port_for are pseudo-vestigial (they are wrappers that aren't needed, but I find ->start_sandbox(master => "master3") simpler than `$trunk/sandbox/start-sandbox master 2900` -- mostly because I keep getting the port numbers numbers wrong).

set_as_slave and start_cluster are there mostly for convenience and brevity.

But since they are all ultimately wrappers around the sandbox/ scripts, sure, it could be done.

441. By Daniel Nichter

Merge fix-938660-ptc-chunk-size-limit-0

442. By Daniel Nichter

Merge pt-show-grant-col-privs-bug-866075

443. By Brian Fraser

Merged fix-1059732-ptc-hash-functions

444. By Brian Fraser

bin/pt-table-checksum: Missing word in an error message

445. By Daniel Nichter

Merge fix-1009510-1039569-ptc-check-table-on-replicas

446. By Daniel Nichter

Merged fix-i26211-1058285-821722-implicit-ansi_quotes

Revision history for this message
Daniel Nichter (daniel-nichter) wrote :

The PXC code in Cxn.pm doesn't seem to belong there. Let's move it and its tests to separate files, i.e. Percona/XtraDB/Cluster.pm (or maybe /XtraDBCluster.pm, but that looks a little cluttered to me). Then like I did with t/pt-table-checksum/pxc.c, we can plan skip_all at the start if the sandbox isn't running PXC.

review: Needs Fixing
447. By Brian Fraser

Merged fix-1073532-Mo-Scalar-Util-PP

448. By Brian Fraser

Merged sandbox-get_dbh_for-fix

449. By Brian Fraser

Removed the L option from the dsn_opts exported by PerconaTest, as it was useless and breaking tests, and added an L=1 to a leftover pt-archiver --bulk-insert call

450. By Daniel Nichter

Merge fix-pt-fel-bug-1075773

451. By Brian Fraser

Merged fix-1062563-1063912-ptc-pxc-bugs and resolved conflicts, added the missing Percona::XtraDB::Cluster file

452. By Brian Fraser

Reverted a few unnecessary changes

453. By Brian Fraser

Split the Percona::XtraDB::Cluster tests in two files: One that requires a PXC sandbox, and a general tests file

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bin/pt-config-diff'
--- bin/pt-config-diff 2012-10-31 09:18:34 +0000
+++ bin/pt-config-diff 2012-11-08 20:42:20 +0000
@@ -1466,6 +1466,7 @@
1466use warnings FATAL => 'all';1466use warnings FATAL => 'all';
1467use English qw(-no_match_vars);1467use English qw(-no_match_vars);
1468use Scalar::Util qw(blessed);1468use Scalar::Util qw(blessed);
1469
1469use constant {1470use constant {
1470 PTDEBUG => $ENV{PTDEBUG} || 0,1471 PTDEBUG => $ENV{PTDEBUG} || 0,
1471 PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0,1472 PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0,
@@ -1572,21 +1573,6 @@
1572 return $self->{hostname} || $self->{dsn_name} || 'unknown host';1573 return $self->{hostname} || $self->{dsn_name} || 'unknown host';
1573}1574}
15741575
1575sub is_cluster_node {
1576 my ($self) = @_;
1577 return $self->{is_cluster_node} if defined $self->{is_cluster_node};
1578
1579 my $sql = "SHOW VARIABLES LIKE 'wsrep_on'";
1580 PTDEBUG && _d($sql);
1581 my $row = $self->{dbh}->selectrow_arrayref($sql);
1582 PTDEBUG && _d(defined $row ? @$row : 'undef');
1583 $self->{is_cluster_node} = $row && $row->[1]
1584 ? ($row->[1] eq 'ON' || $row->[1] eq '1')
1585 : 0;
1586
1587 return $self->{is_cluster_node};
1588}
1589
1590sub DESTROY {1576sub DESTROY {
1591 my ($self) = @_;1577 my ($self) = @_;
1592 if ( $self->{dbh}1578 if ( $self->{dbh}
15931579
=== modified file 'bin/pt-kill'
--- bin/pt-kill 2012-11-07 07:12:37 +0000
+++ bin/pt-kill 2012-11-08 20:42:20 +0000
@@ -2478,16 +2478,20 @@
2478$Data::Dumper::Sortkeys = 1;2478$Data::Dumper::Sortkeys = 1;
2479$Data::Dumper::Quotekeys = 0;2479$Data::Dumper::Quotekeys = 0;
24802480
2481local $EVAL_ERROR;
2482eval {
2483 require Quoter;
2484};
2485
2481sub new {2486sub new {
2482 my ( $class, %args ) = @_;2487 my ( $class, %args ) = @_;
2483 my @required_args = qw(Quoter);
2484 foreach my $arg ( @required_args ) {
2485 die "I need a $arg argument" unless $args{$arg};
2486 }
2487 my $self = { %args };2488 my $self = { %args };
2489 $self->{Quoter} ||= Quoter->new();
2488 return bless $self, $class;2490 return bless $self, $class;
2489}2491}
24902492
2493sub Quoter { shift->{Quoter} }
2494
2491sub get_create_table {2495sub get_create_table {
2492 my ( $self, $dbh, $db, $tbl ) = @_;2496 my ( $self, $dbh, $db, $tbl ) = @_;
2493 die "I need a dbh parameter" unless $dbh;2497 die "I need a dbh parameter" unless $dbh;
@@ -4711,6 +4715,7 @@
4711use warnings FATAL => 'all';4715use warnings FATAL => 'all';
4712use English qw(-no_match_vars);4716use English qw(-no_match_vars);
4713use Scalar::Util qw(blessed);4717use Scalar::Util qw(blessed);
4718
4714use constant {4719use constant {
4715 PTDEBUG => $ENV{PTDEBUG} || 0,4720 PTDEBUG => $ENV{PTDEBUG} || 0,
4716 PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0,4721 PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0,
@@ -4817,21 +4822,6 @@
4817 return $self->{hostname} || $self->{dsn_name} || 'unknown host';4822 return $self->{hostname} || $self->{dsn_name} || 'unknown host';
4818}4823}
48194824
4820sub is_cluster_node {
4821 my ($self) = @_;
4822 return $self->{is_cluster_node} if defined $self->{is_cluster_node};
4823
4824 my $sql = "SHOW VARIABLES LIKE 'wsrep_on'";
4825 PTDEBUG && _d($sql);
4826 my $row = $self->{dbh}->selectrow_arrayref($sql);
4827 PTDEBUG && _d(defined $row ? @$row : 'undef');
4828 $self->{is_cluster_node} = $row && $row->[1]
4829 ? ($row->[1] eq 'ON' || $row->[1] eq '1')
4830 : 0;
4831
4832 return $self->{is_cluster_node};
4833}
4834
4835sub DESTROY {4825sub DESTROY {
4836 my ($self) = @_;4826 my ($self) = @_;
4837 if ( $self->{dbh}4827 if ( $self->{dbh}
48384828
=== modified file 'bin/pt-online-schema-change'
--- bin/pt-online-schema-change 2012-11-07 07:12:37 +0000
+++ bin/pt-online-schema-change 2012-11-08 20:42:20 +0000
@@ -2712,16 +2712,20 @@
2712$Data::Dumper::Sortkeys = 1;2712$Data::Dumper::Sortkeys = 1;
2713$Data::Dumper::Quotekeys = 0;2713$Data::Dumper::Quotekeys = 0;
27142714
2715local $EVAL_ERROR;
2716eval {
2717 require Quoter;
2718};
2719
2715sub new {2720sub new {
2716 my ( $class, %args ) = @_;2721 my ( $class, %args ) = @_;
2717 my @required_args = qw(Quoter);
2718 foreach my $arg ( @required_args ) {
2719 die "I need a $arg argument" unless $args{$arg};
2720 }
2721 my $self = { %args };2722 my $self = { %args };
2723 $self->{Quoter} ||= Quoter->new();
2722 return bless $self, $class;2724 return bless $self, $class;
2723}2725}
27242726
2727sub Quoter { shift->{Quoter} }
2728
2725sub get_create_table {2729sub get_create_table {
2726 my ( $self, $dbh, $db, $tbl ) = @_;2730 my ( $self, $dbh, $db, $tbl ) = @_;
2727 die "I need a dbh parameter" unless $dbh;2731 die "I need a dbh parameter" unless $dbh;
@@ -3341,6 +3345,7 @@
3341use warnings FATAL => 'all';3345use warnings FATAL => 'all';
3342use English qw(-no_match_vars);3346use English qw(-no_match_vars);
3343use Scalar::Util qw(blessed);3347use Scalar::Util qw(blessed);
3348
3344use constant {3349use constant {
3345 PTDEBUG => $ENV{PTDEBUG} || 0,3350 PTDEBUG => $ENV{PTDEBUG} || 0,
3346 PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0,3351 PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0,
@@ -3447,21 +3452,6 @@
3447 return $self->{hostname} || $self->{dsn_name} || 'unknown host';3452 return $self->{hostname} || $self->{dsn_name} || 'unknown host';
3448}3453}
34493454
3450sub is_cluster_node {
3451 my ($self) = @_;
3452 return $self->{is_cluster_node} if defined $self->{is_cluster_node};
3453
3454 my $sql = "SHOW VARIABLES LIKE 'wsrep_on'";
3455 PTDEBUG && _d($sql);
3456 my $row = $self->{dbh}->selectrow_arrayref($sql);
3457 PTDEBUG && _d(defined $row ? @$row : 'undef');
3458 $self->{is_cluster_node} = $row && $row->[1]
3459 ? ($row->[1] eq 'ON' || $row->[1] eq '1')
3460 : 0;
3461
3462 return $self->{is_cluster_node};
3463}
3464
3465sub DESTROY {3455sub DESTROY {
3466 my ($self) = @_;3456 my ($self) = @_;
3467 if ( $self->{dbh}3457 if ( $self->{dbh}
34683458
=== modified file 'bin/pt-table-checksum'
--- bin/pt-table-checksum 2012-11-07 07:12:37 +0000
+++ bin/pt-table-checksum 2012-11-08 20:42:20 +0000
@@ -21,6 +21,7 @@
21 OptionParser21 OptionParser
22 Mo22 Mo
23 Cxn23 Cxn
24 Percona::XtraDB::Cluster
24 Quoter25 Quoter
25 VersionParser26 VersionParser
26 TableParser27 TableParser
@@ -3211,6 +3212,7 @@
3211use warnings FATAL => 'all';3212use warnings FATAL => 'all';
3212use English qw(-no_match_vars);3213use English qw(-no_match_vars);
3213use Scalar::Util qw(blessed);3214use Scalar::Util qw(blessed);
3215
3214use constant {3216use constant {
3215 PTDEBUG => $ENV{PTDEBUG} || 0,3217 PTDEBUG => $ENV{PTDEBUG} || 0,
3216 PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0,3218 PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0,
@@ -3317,21 +3319,6 @@
3317 return $self->{hostname} || $self->{dsn_name} || 'unknown host';3319 return $self->{hostname} || $self->{dsn_name} || 'unknown host';
3318}3320}
33193321
3320sub is_cluster_node {
3321 my ($self) = @_;
3322 return $self->{is_cluster_node} if defined $self->{is_cluster_node};
3323
3324 my $sql = "SHOW VARIABLES LIKE 'wsrep_on'";
3325 PTDEBUG && _d($sql);
3326 my $row = $self->{dbh}->selectrow_arrayref($sql);
3327 PTDEBUG && _d(defined $row ? @$row : 'undef');
3328 $self->{is_cluster_node} = $row && $row->[1]
3329 ? ($row->[1] eq 'ON' || $row->[1] eq '1')
3330 : 0;
3331
3332 return $self->{is_cluster_node};
3333}
3334
3335sub DESTROY {3322sub DESTROY {
3336 my ($self) = @_;3323 my ($self) = @_;
3337 if ( $self->{dbh}3324 if ( $self->{dbh}
@@ -3358,6 +3345,104 @@
3358# ###########################################################################3345# ###########################################################################
33593346
3360# ###########################################################################3347# ###########################################################################
3348# Percona::XtraDB::Cluster package
3349# This package is a copy without comments from the original. The original
3350# with comments and its test file can be found in the Bazaar repository at,
3351# lib/Percona/XtraDB/Cluster.pm
3352# t/lib/Percona/XtraDB/Cluster.t
3353# See https://launchpad.net/percona-toolkit for more information.
3354# ###########################################################################
3355{
3356
3357package Percona::XtraDB::Cluster;
3358use Mo;
3359use constant PTDEBUG => $ENV{PTDEBUG} || 0;
3360
3361sub is_cluster_node {
3362 my ($self, $cxn) = @_;
3363 return $self->{is_cluster_node}->{$cxn} if defined $self->{is_cluster_node}->{$cxn};
3364
3365 my $sql = "SHOW VARIABLES LIKE 'wsrep_on'";
3366 PTDEBUG && _d($sql);
3367 my $row = $cxn->dbh->selectrow_arrayref($sql);
3368 PTDEBUG && _d(defined $row ? @$row : 'undef');
3369 $self->{is_cluster_node}->{$cxn} = $row && $row->[1]
3370 ? ($row->[1] eq 'ON' || $row->[1] eq '1')
3371 : 0;
3372
3373 return $self->{is_cluster_node}->{$cxn};
3374}
3375
3376sub same_cluster {
3377 my ($self, $cxn1, $cxn2) = @_;
3378 return unless $self->is_cluster_node($cxn1) && $self->is_cluster_node($cxn2);
3379 return if $self->is_master_of($cxn1, $cxn2) || $self->is_master_of($cxn2, $cxn1);
3380
3381 my $sql = q{SHOW VARIABLES LIKE 'wsrep_cluster_name'};
3382 PTDEBUG && _d($sql);
3383 my (undef, $row) = $cxn1->dbh->selectrow_array($sql);
3384 my (undef, $cxn2_row) = $cxn2->dbh->selectrow_array($sql);
3385
3386 return unless $row eq $cxn2_row;
3387
3388 $sql = q{SHOW VARIABLES LIKE 'wsrep_cluster_address'};
3389 PTDEBUG && _d($sql);
3390 my (undef, $addr) = $cxn1->dbh->selectrow_array($sql);
3391 my (undef, $cxn2_addr) = $cxn2->dbh->selectrow_array($sql);
3392
3393 return if $addr eq 'gcomm://' && $cxn2_addr eq 'gcomm://';
3394
3395 if ( $addr eq 'gcomm://' ) {
3396 $addr = $self->_find_full_gcomm_addr($cxn1->dbh);
3397 }
3398 elsif ( $cxn2_addr eq 'gcomm://' ) {
3399 $cxn2_addr = $self->_find_full_gcomm_addr($cxn2->dbh);
3400 }
3401
3402 return 1 if lc($addr) eq lc($cxn2_addr);
3403
3404 return 1;
3405}
3406
3407sub is_master_of {
3408 my ($self, $cxn1, $cxn2) = @_;
3409
3410 my $cxn2_dbh = $cxn2->dbh;
3411 my $sql = q{SHOW SLAVE STATUS};
3412 PTDEBUG && _d($sql);
3413 local $cxn2_dbh->{FetchHashKeyName} = 'NAME_lc';
3414 my $slave_status = $cxn2_dbh->selectrow_hashref($sql);
3415 return unless ref($slave_status) eq 'HASH';
3416
3417 my $port = $cxn1->dsn->{P};
3418 return unless $slave_status->{master_port} eq $port;
3419 return 1 if $cxn1->dsn->{h} eq $slave_status->{master_host};
3420
3421 my $host = scalar gethostbyname($cxn1->dsn->{h});
3422 my $master_host = scalar gethostbyname($slave_status->{master_host});
3423 return 1 if $master_host eq $host;
3424 return;
3425}
3426
3427sub _find_full_gcomm_addr {
3428 my ($self, $dbh) = @_;
3429
3430 my $sql = q{SHOW VARIABLES LIKE 'wsrep_provider_options'};
3431 PTDEBUG && _d($sql);
3432 my (undef, $provider_opts) = $dbh->selectrow_array($sql);
3433 my ($prov_addr) = $provider_opts =~ m{\Qgmcast.listen_addr\E\s*=\s*tcp://([^:]+:[0-9]+)\s*;}i;
3434 my $full_gcomm = "gcomm://$prov_addr";
3435 PTDEBUG && _d("gcomm address: ", $full_gcomm);
3436 return $full_gcomm;
3437}
3438
34391;
3440}
3441# ###########################################################################
3442# End Percona::XtraDB::Cluster package
3443# ###########################################################################
3444
3445# ###########################################################################
3361# Quoter package3446# Quoter package
3362# This package is a copy without comments from the original. The original3447# This package is a copy without comments from the original. The original
3363# with comments and its test file can be found in the Bazaar repository at,3448# with comments and its test file can be found in the Bazaar repository at,
@@ -5281,7 +5366,7 @@
5281 }5366 }
5282 my ($dbh) = @args{@required_args};5367 my ($dbh) = @args{@required_args};
5283 my $o = $self->{OptionParser};5368 my $o = $self->{OptionParser};
5284 my @funcs = qw(CRC32 FNV1A_64 FNV_64 MD5 SHA1);5369 my @funcs = qw(CRC32 FNV1A_64 FNV_64 MURMUR_HASH MD5 SHA1);
52855370
5286 if ( my $func = $o->get('function') ) {5371 if ( my $func = $o->get('function') ) {
5287 unshift @funcs, $func;5372 unshift @funcs, $func;
@@ -5302,7 +5387,7 @@
5302 PTDEBUG && _d('Chosen hash func:', $result);5387 PTDEBUG && _d('Chosen hash func:', $result);
5303 return $func;5388 return $func;
5304 }5389 }
5305 die $error || 'No hash functions (CRC32, MD5, etc.) are available';5390 die($error || 'No hash functions (CRC32, MD5, etc.) are available');
5306}5391}
53075392
5308sub _get_crc_width {5393sub _get_crc_width {
@@ -8535,6 +8620,9 @@
8535 $have_time = sub { return 1; };8620 $have_time = sub { return 1; };
8536 }8621 }
85378622
8623 # PXC helper class
8624 my $cluster = Percona::XtraDB::Cluster->new();
8625
8538 # ########################################################################8626 # ########################################################################
8539 # If this is not a dry run (--explain was not specified), then we're8627 # If this is not a dry run (--explain was not specified), then we're
8540 # going to checksum the tables, so do the necessary preparations and8628 # going to checksum the tables, so do the necessary preparations and
@@ -8604,12 +8692,42 @@
8604 die $err if $err;8692 die $err if $err;
8605 }8693 }
86068694
8607 if ( $master_cxn->is_cluster_node() && !@$slaves ) {8695 if ( $cluster->is_cluster_node($master_cxn) ) {
8608 die $master_cxn->name() . " is a cluster node but no other nodes "8696 if ( !@$slaves ) {
8609 . "or regular replicas were found. Use --recursion-method=dsn "8697 die $master_cxn->name() . " is a cluster node but no other nodes "
8610 . "to specify the other nodes in the cluster.\n";8698 . "or regular replicas were found. Use --recursion-method=dsn "
8611 }8699 . "to specify the other nodes in the cluster.\n";
86128700 }
8701 else {
8702 my $err = '';
8703 for my $slave (@$slaves) {
8704 if ( $cluster->is_cluster_node($slave)
8705 && !$cluster->same_cluster($slave, $master_cxn) ) {
8706 $err .= $slave->name() . " is a cluster node, but doesn't "
8707 . "belong to the same cluster as " . $master_cxn->name()
8708 . ". This is not currently supported; You can try "
8709 . "using --recursion-method=dsn to specify all nodes "
8710 . "in the slave cluster.\n"
8711 }
8712 }
8713 warn $err if $err;
8714 }
8715 }
8716 elsif ( @$slaves ) {
8717 my $err = '';
8718 for my $slave (@$slaves) {
8719 if ( $cluster->is_cluster_node($slave) ) {
8720 $err .= $slave->name() . " is a cluster node, but "
8721 . $master_cxn->name() . " is not. This is not currently "
8722 . "supported; You can try to specify "
8723 . "all nodes in the cluster with "
8724 . "--recursion-method=dsn if you want them checksummed.\n"
8725 }
8726 }
8727 warn $err if $err;
8728 }
8729
8730
8613 if ( $o->get('check-slave-lag') ) {8731 if ( $o->get('check-slave-lag') ) {
8614 PTDEBUG && _d('Will use --check-slave-lag to check for slave lag');8732 PTDEBUG && _d('Will use --check-slave-lag to check for slave lag');
8615 my $cxn = $make_cxn->(8733 my $cxn = $make_cxn->(
@@ -8629,7 +8747,8 @@
8629 # to appear should be sufficient.8747 # to appear should be sufficient.
8630 @$slave_lag_cxns = grep {8748 @$slave_lag_cxns = grep {
8631 my $slave_cxn = $_;8749 my $slave_cxn = $_;
8632 if ( $slave_cxn->is_cluster_node() ) {8750 if ( $cluster->is_cluster_node($slave_cxn)
8751 && $cluster->same_cluster($master_cxn, $slave_cxn) ) {
8633 warn "Not checking replica lag on " . $slave_cxn->name()8752 warn "Not checking replica lag on " . $slave_cxn->name()
8634 . " because it is a cluster node.\n";8753 . " because it is a cluster node.\n";
8635 0;8754 0;
@@ -8844,7 +8963,7 @@
8844 . "(db, tbl, chunk, chunk_index,"8963 . "(db, tbl, chunk, chunk_index,"
8845 . " lower_boundary, upper_boundary, this_cnt, this_crc) "8964 . " lower_boundary, upper_boundary, this_cnt, this_crc) "
8846 . "SELECT"8965 . "SELECT"
8847 . ($master_cxn->is_cluster_node() ? ' /*!99997*/' : '')8966 . ($cluster->is_cluster_node($master_cxn) ? ' /*!99997*/' : '')
8848 . " ?, ?, ?, ?, ?, ?,";8967 . " ?, ?, ?, ?, ?, ?,";
8849 my $past_cols = " COUNT(*), '0'";8968 my $past_cols = " COUNT(*), '0'";
88508969
88518970
=== modified file 'lib/Cxn.pm'
--- lib/Cxn.pm 2012-10-08 18:53:54 +0000
+++ lib/Cxn.pm 2012-11-08 20:42:20 +0000
@@ -36,6 +36,7 @@
36use warnings FATAL => 'all';36use warnings FATAL => 'all';
37use English qw(-no_match_vars);37use English qw(-no_match_vars);
38use Scalar::Util qw(blessed);38use Scalar::Util qw(blessed);
39
39use constant {40use constant {
40 PTDEBUG => $ENV{PTDEBUG} || 0,41 PTDEBUG => $ENV{PTDEBUG} || 0,
41 # Hostnames make testing less accurate. Tests need to see42 # Hostnames make testing less accurate. Tests need to see
@@ -195,21 +196,6 @@
195 return $self->{hostname} || $self->{dsn_name} || 'unknown host';196 return $self->{hostname} || $self->{dsn_name} || 'unknown host';
196}197}
197198
198sub is_cluster_node {
199 my ($self) = @_;
200 return $self->{is_cluster_node} if defined $self->{is_cluster_node};
201
202 my $sql = "SHOW VARIABLES LIKE 'wsrep_on'";
203 PTDEBUG && _d($sql);
204 my $row = $self->{dbh}->selectrow_arrayref($sql);
205 PTDEBUG && _d(defined $row ? @$row : 'undef');
206 $self->{is_cluster_node} = $row && $row->[1]
207 ? ($row->[1] eq 'ON' || $row->[1] eq '1')
208 : 0;
209
210 return $self->{is_cluster_node};
211}
212
213sub DESTROY {199sub DESTROY {
214 my ($self) = @_;200 my ($self) = @_;
215 if ( $self->{dbh}201 if ( $self->{dbh}
216202
=== added directory 'lib/Percona/XtraDB'
=== added file 'lib/Percona/XtraDB/Cluster.pm'
--- lib/Percona/XtraDB/Cluster.pm 1970-01-01 00:00:00 +0000
+++ lib/Percona/XtraDB/Cluster.pm 2012-11-08 20:42:20 +0000
@@ -0,0 +1,123 @@
1# This program is copyright 2011 Percona Inc.
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# Percona::XtraDB::Cluster package
19# ###########################################################################
20{
21# Package: Percona::XtraDB::Cluster
22# Percona::XtraDB::Cluster has helper methods to deal with Percona XtraDB Cluster
23# based servers
24
25package Percona::XtraDB::Cluster;
26use Mo;
27use constant PTDEBUG => $ENV{PTDEBUG} || 0;
28
29sub is_cluster_node {
30 my ($self, $cxn) = @_;
31 return $self->{is_cluster_node}->{$cxn} if defined $self->{is_cluster_node}->{$cxn};
32
33 my $sql = "SHOW VARIABLES LIKE 'wsrep_on'";
34 PTDEBUG && _d($sql);
35 my $row = $cxn->dbh->selectrow_arrayref($sql);
36 PTDEBUG && _d(defined $row ? @$row : 'undef');
37 $self->{is_cluster_node}->{$cxn} = $row && $row->[1]
38 ? ($row->[1] eq 'ON' || $row->[1] eq '1')
39 : 0;
40
41 return $self->{is_cluster_node}->{$cxn};
42}
43
44sub same_cluster {
45 my ($self, $cxn1, $cxn2) = @_;
46 return unless $self->is_cluster_node($cxn1) && $self->is_cluster_node($cxn2);
47 return if $self->is_master_of($cxn1, $cxn2) || $self->is_master_of($cxn2, $cxn1);
48
49 my $sql = q{SHOW VARIABLES LIKE 'wsrep_cluster_name'};
50 PTDEBUG && _d($sql);
51 my (undef, $row) = $cxn1->dbh->selectrow_array($sql);
52 my (undef, $cxn2_row) = $cxn2->dbh->selectrow_array($sql);
53
54 return unless $row eq $cxn2_row;
55
56 # Now it becomes tricky. Ostensibly clusters shouldn't have the
57 # same name, but tell that to the world.
58 $sql = q{SHOW VARIABLES LIKE 'wsrep_cluster_address'};
59 PTDEBUG && _d($sql);
60 my (undef, $addr) = $cxn1->dbh->selectrow_array($sql);
61 my (undef, $cxn2_addr) = $cxn2->dbh->selectrow_array($sql);
62
63 # If they both have gcomm://, then they are both the first
64 # node of a cluster, so they can't be in the same one.
65 return if $addr eq 'gcomm://' && $cxn2_addr eq 'gcomm://';
66
67 if ( $addr eq 'gcomm://' ) {
68 $addr = $self->_find_full_gcomm_addr($cxn1->dbh);
69 }
70 elsif ( $cxn2_addr eq 'gcomm://' ) {
71 $cxn2_addr = $self->_find_full_gcomm_addr($cxn2->dbh);
72 }
73
74 # Meanwhile, if they have the same address, then
75 # they are definitely part of the same cluster
76 return 1 if lc($addr) eq lc($cxn2_addr);
77
78 # However, this still leaves us with the issue that
79 # the cluster addresses could look like this:
80 # node1 -> node2, node2 -> node1,
81 # or
82 # node1 -> node2 addr,
83 # node2 -> node3 addr,
84 # node3 -> node1 addr,
85 # TODO No clue what to do here
86 return 1;
87}
88
89sub is_master_of {
90 my ($self, $cxn1, $cxn2) = @_;
91
92 my $cxn2_dbh = $cxn2->dbh;
93 my $sql = q{SHOW SLAVE STATUS};
94 PTDEBUG && _d($sql);
95 local $cxn2_dbh->{FetchHashKeyName} = 'NAME_lc';
96 my $slave_status = $cxn2_dbh->selectrow_hashref($sql);
97 return unless ref($slave_status) eq 'HASH';
98
99 my $port = $cxn1->dsn->{P};
100 return unless $slave_status->{master_port} eq $port;
101 return 1 if $cxn1->dsn->{h} eq $slave_status->{master_host};
102
103 # They might be the same but in different format
104 my $host = scalar gethostbyname($cxn1->dsn->{h});
105 my $master_host = scalar gethostbyname($slave_status->{master_host});
106 return 1 if $master_host eq $host;
107 return;
108}
109
110sub _find_full_gcomm_addr {
111 my ($self, $dbh) = @_;
112
113 my $sql = q{SHOW VARIABLES LIKE 'wsrep_provider_options'};
114 PTDEBUG && _d($sql);
115 my (undef, $provider_opts) = $dbh->selectrow_array($sql);
116 my ($prov_addr) = $provider_opts =~ m{\Qgmcast.listen_addr\E\s*=\s*tcp://([^:]+:[0-9]+)\s*;}i;
117 my $full_gcomm = "gcomm://$prov_addr";
118 PTDEBUG && _d("gcomm address: ", $full_gcomm);
119 return $full_gcomm;
120}
121
1221;
123}
0124
=== modified file 'lib/Sandbox.pm'
--- lib/Sandbox.pm 2012-11-07 07:13:50 +0000
+++ lib/Sandbox.pm 2012-11-08 20:42:20 +0000
@@ -39,6 +39,8 @@
39use constant PTDEBUG => $ENV{PTDEBUG} || 0;39use constant PTDEBUG => $ENV{PTDEBUG} || 0;
40use constant PTDEVDEBUG => $ENV{PTDEVDEBUG} || 0;40use constant PTDEVDEBUG => $ENV{PTDEVDEBUG} || 0;
4141
42use IO::Socket::INET;
43
42my $trunk = $ENV{PERCONA_TOOLKIT_BRANCH};44my $trunk = $ENV{PERCONA_TOOLKIT_BRANCH};
4345
44my %port_for = (46my %port_for = (
@@ -74,7 +76,7 @@
74 return if !defined $cmd || !$cmd;76 return if !defined $cmd || !$cmd;
75 my $use = $self->_use_for($server) . " $cmd";77 my $use = $self->_use_for($server) . " $cmd";
76 PTDEBUG && _d('"Executing', $use, 'on', $server);78 PTDEBUG && _d('"Executing', $use, 'on', $server);
77 my $out = `$use 2>&1`;79 my $out = `$use`;
78 if ( $? >> 8 ) {80 if ( $? >> 8 ) {
79 die "Failed to execute $cmd on $server: $out";81 die "Failed to execute $cmd on $server: $out";
80 }82 }
@@ -130,7 +132,7 @@
130}132}
131133
132sub load_file {134sub load_file {
133 my ( $self, $server, $file, $use_db ) = @_;135 my ( $self, $server, $file, $use_db, %args ) = @_;
134 _check_server($server);136 _check_server($server);
135 $file = "$trunk/$file";137 $file = "$trunk/$file";
136 if ( !-f $file ) {138 if ( !-f $file ) {
@@ -141,11 +143,11 @@
141143
142 my $use = $self->_use_for($server) . " $d < $file";144 my $use = $self->_use_for($server) . " $d < $file";
143 PTDEBUG && _d('Loading', $file, 'on', $server, ':', $use);145 PTDEBUG && _d('Loading', $file, 'on', $server, ':', $use);
144 my $out = `$use 2>&1`;146 my $out = `$use`;
145 if ( $? >> 8 ) {147 if ( $? >> 8 ) {
146 die "Failed to execute $file on $server: $out";148 die "Failed to execute $file on $server: $out";
147 }149 }
148 $self->wait_for_slaves();150 $self->wait_for_slaves() unless $args{no_wait};
149}151}
150152
151sub _use_for {153sub _use_for {
@@ -420,6 +422,85 @@
420 return ($output || '') =~ /1/;422 return ($output || '') =~ /1/;
421}423}
422424
425sub set_as_slave {
426 my ($self, $server, $master_server, @extras) = @_;
427 PTDEBUG && _d("Setting $server as slave of $master_server");
428 my $master_port = $port_for{$master_server};
429 my $sql = join ", ", qq{change master to master_host='127.0.0.1'},
430 qq{master_user='msandbox'},
431 qq{master_password='msandbox'},
432 qq{master_port=$master_port},
433 @extras;
434 for my $sql_to_run ($sql, "start slave") {
435 my $out = $self->use($server, qq{-e "$sql_to_run"});
436 PTDEBUG && _d($out);
437 }
438}
439
440sub start_sandbox {
441 my ($self, $mode, $server, $master_server) = @_;
442 my $port = $port_for{$server};
443 my $master_port = $master_server ? $port_for{$master_server} : '';
444 my $out = `$trunk/sandbox/start-sandbox $mode $port $master_port`;
445 die $out if $CHILD_ERROR;
446 return $out;
447}
448
449sub stop_sandbox {
450 my ($self, @sandboxes) = @_;
451 my @ports = @port_for{@sandboxes};
452 my $out = `$trunk/sandbox/stop-sandbox @ports`;
453 die $out if $CHILD_ERROR;
454 return $out;
455}
456
457sub start_cluster {
458 my ($self, %args) = @_;
459 my $cluster_size = $args{cluster_size} || 3;
460
461 my $out = '';
462
463 my ($node1, @nodes) = map {
464 my $node_name = "node$_";
465 $node_name = "_$node_name" while exists $port_for{$node_name};
466 $port_for{$node_name} = $self->_get_unused_port();
467 $node_name
468 } 1..$cluster_size;
469
470 local $ENV{CLUSTER_NAME} = $args{cluster_name} if $args{cluster_name};
471 $self->start_sandbox("cluster", $node1);
472 for my $node ( @nodes ) {
473 $self->start_sandbox("cluster", $node, $node1);
474 }
475
476 return ($node1, @nodes);
477}
478
479# Lifted from Nginx::Test on CPAN
480sub _get_unused_port {
481 my $port = 50000 + int (rand() * 5000);
482
483 while ($port++ < 64000) {
484 my $sock = IO::Socket::INET->new (
485 Listen => 5,
486 LocalAddr => '127.0.0.1',
487 LocalPort => $port,
488 Proto => 'tcp',
489 ReuseAddr => 1
490 ) or next;
491
492 $sock->close;
493 return $port;
494 }
495
496 die "Cannot find an open port";
497}
498
499sub port_for {
500 my ($self, $server) = @_;
501 return $port_for{$server};
502}
503
4231;5041;
424}505}
425# ###########################################################################506# ###########################################################################
426507
=== modified file 't/lib/Cxn.t'
--- t/lib/Cxn.t 2012-07-23 02:37:39 +0000
+++ t/lib/Cxn.t 2012-11-08 20:42:20 +0000
@@ -9,7 +9,8 @@
9use strict;9use strict;
10use warnings FATAL => 'all';10use warnings FATAL => 'all';
11use English qw(-no_match_vars);11use English qw(-no_match_vars);
12use Test::More tests => 19;12use Test::More;
13use Data::Dumper;
1314
14use Sandbox;15use Sandbox;
15use OptionParser;16use OptionParser;
@@ -17,8 +18,7 @@
17use Quoter;18use Quoter;
18use PerconaTest;19use PerconaTest;
19use Cxn;20use Cxn;
2021use VersionParser;
21use Data::Dumper;
2222
23my $q = new Quoter();23my $q = new Quoter();
24my $dp = new DSNParser(opts=>$dsn_opts);24my $dp = new DSNParser(opts=>$dsn_opts);
@@ -248,12 +248,10 @@
248 "Default cxn inherits default connection options"248 "Default cxn inherits default connection options"
249);249);
250250
251@ARGV = ();
252$o->get_opts();
253
254# #############################################################################251# #############################################################################
255# Done.252# Done.
256# #############################################################################253# #############################################################################
257$master_dbh->disconnect() if $master_dbh;254$master_dbh->disconnect() if $master_dbh;
258ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");255ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
256done_testing;
259exit;257exit;
260258
=== added directory 't/lib/Percona'
=== added directory 't/lib/Percona/XtraDB'
=== added file 't/lib/Percona/XtraDB/Cluster.t'
--- t/lib/Percona/XtraDB/Cluster.t 1970-01-01 00:00:00 +0000
+++ t/lib/Percona/XtraDB/Cluster.t 2012-11-08 20:42:20 +0000
@@ -0,0 +1,216 @@
1#!/usr/bin/perl
2
3BEGIN {
4 die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
5 unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
6 unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
7};
8
9use strict;
10use warnings FATAL => 'all';
11use English qw(-no_match_vars);
12use Test::More;
13use Data::Dumper;
14
15# Hostnames make testing less accurate. Tests need to see
16# that such-and-such happened on specific slave hosts, but
17# the sandbox servers are all on one host so all slaves have
18# the same hostname.
19$ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} = 1;
20
21use Sandbox;
22use OptionParser;
23use DSNParser;
24use Quoter;
25use PerconaTest;
26use Cxn;
27use VersionParser;
28
29use Percona::XtraDB::Cluster;
30
31my $q = new Quoter();
32my $dp = new DSNParser(opts=>$dsn_opts);
33my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
34my $master_dbh = $sb->get_dbh_for('master');
35
36my $cluster = Percona::XtraDB::Cluster->new();
37
38if ( !$master_dbh ) {
39 plan skip_all => 'Cannot connect to sandbox master';
40}
41
42my $o = new OptionParser(description => 'Cxn');
43$o->get_specs("$trunk/bin/pt-table-checksum");
44$o->get_opts();
45$dp->prop('set-vars', $o->get('set-vars'));
46
47sub make_cxn {
48 my (%args) = @_;
49 $o->get_opts();
50 return new Cxn(
51 OptionParser => $o,
52 DSNParser => $dp,
53 %args,
54 );
55}
56
57local @ARGV = ();
58$o->get_opts();
59
60diag("Starting master1");
61$sb->start_sandbox("master", "master1");
62
63my ($master_cxn, $slave1_cxn, $master1_cxn)
64 = map {
65 my $cxn = make_cxn( dsn_string => $sb->dsn_for($_) );
66 $cxn->connect();
67 $cxn;
68 } qw( master slave1 master1 );
69
70for my $cxn ( $master_cxn, $slave1_cxn, $master1_cxn ) {
71 ok(
72 !$cluster->is_cluster_node($cxn),
73 "is_cluster_node works correctly for non-nodes " . $cxn->name
74 );
75}
76
77ok($cluster->is_master_of($master_cxn, $slave1_cxn), "is_master_of(master, slave1) is true");
78ok(!$cluster->is_master_of($slave1_cxn, $master_cxn), "is_master_of(slave1, master) is false");
79
80my $db_flavor = VersionParser->new($master_dbh)->flavor();
81SKIP: {
82 skip "PXC-only test", 17
83 unless $db_flavor =~ /XtraDB Cluster/;
84
85 diag("Starting a 1-node PXC");
86 my ($node) = $sb->start_cluster(cluster_size => 1);
87
88 my $cxn1 = make_cxn( dsn_string => $sb->dsn_for($node) );
89 $cxn1->connect();
90 ok(
91 $cluster->is_cluster_node($cxn1),
92 "is_cluster_node works correctly for cluster nodes"
93 );
94
95 ok(
96 !$cluster->is_master_of($master1_cxn, $cxn1),
97 "->is_master_of works correctly for a server unrelated to a cluster"
98 );
99
100 diag("Setting node as a slave of master1");
101 $sb->set_as_slave($node, "master1");
102 ok(
103 $cluster->is_master_of($master1_cxn, $cxn1),
104 "->is_master_of works correctly for master -> cluster"
105 );
106 ok(
107 !$cluster->is_master_of($cxn1, $master1_cxn),
108 "...and the inverse returns the expected result"
109 );
110 ok(
111 !$cluster->same_cluster($master1_cxn, $cxn1),
112 "->same_cluster works for master -> cluster"
113 );
114 diag("Restarting the cluster");
115 diag($sb->stop_sandbox($node));
116 ($node) = $sb->start_cluster(cluster_size => 1);
117 $cxn1 = make_cxn( dsn_string => $sb->dsn_for($node) );
118 $cxn1->connect();
119
120 diag("Setting master1 as a slave of the node");
121 $sb->set_as_slave("master1", $node);
122 ok(
123 $cluster->is_master_of($cxn1, $master1_cxn),
124 "->is_master_of works correctly for cluster -> master"
125 );
126 ok(
127 !$cluster->is_master_of($master1_cxn, $cxn1),
128 "...and the inverse returns the expected result"
129 );
130
131 ok(
132 !$cluster->same_cluster($cxn1, $master1_cxn),
133 "->same_cluster works for cluster -> master"
134 );
135
136 diag("Starting a 2-node PXC");
137 my ($node2, $node3) = $sb->start_cluster(cluster_size => 2);
138
139 my $cxn2 = make_cxn( dsn_string => $sb->dsn_for($node2) );
140 $cxn2->connect();
141 my $cxn3 = make_cxn( dsn_string => $sb->dsn_for($node3) );
142 $cxn3->connect();
143 ok(
144 $cluster->is_cluster_node($cxn2),
145 "is_cluster_node correctly finds that this node is part of a cluster"
146 );
147
148 ok(
149 !$cluster->same_cluster($cxn1, $cxn2),
150 "and same_cluster correctly finds that they don't belong to the same cluster, even when they have the same cluster name"
151 );
152
153 ok(
154 $cluster->same_cluster($cxn2, $cxn3),
155 "...but does find that they are in the same cluster, even if one is node1"
156 );
157
158 TODO: {
159 local $::TODO = "Should detected that (cluster1.node1) (cluster2.node2) come from different clusters, but doesn't";
160 ok(
161 !$cluster->same_cluster($cxn1, $cxn3),
162 "...same_cluster works correctly when they have the same cluster names"
163 );
164 }
165
166 diag("Making the second cluster a slave of the first");
167 $sb->set_as_slave($node2, $node);
168 ok($cluster->is_master_of($cxn1, $cxn2), "is_master_of(cluster1, cluster2) works");
169
170 ok(
171 !$cluster->same_cluster($cxn1, $cxn2),
172 "...same_cluster works correctly when they are cluster1.node1.master -> cluster2.node1.slave"
173 );
174
175 diag($sb->stop_sandbox($node2, $node3));
176 diag("Starting a 3-node cluster");
177 my $node4;
178 ($node2, $node3, $node4)
179 = $sb->start_cluster(
180 cluster_size => 3,
181 cluster_name => "pt_cxn_test",
182 );
183 $cxn2 = make_cxn( dsn_string => $sb->dsn_for($node2) );
184 $cxn2->connect();
185 $cxn3 = make_cxn( dsn_string => $sb->dsn_for($node3) );
186 $cxn3->connect();
187 my $cxn4 = make_cxn( dsn_string => $sb->dsn_for($node4) );
188 $cxn4->connect();
189
190 ok(
191 !$cluster->same_cluster($cxn1, $cxn2),
192 "...same_cluster works correctly when they have different cluster names & the are both gcomm"
193 );
194
195 ok(
196 !$cluster->same_cluster($cxn1, $cxn3),
197 "same_cluster detects that (cluster1.node1) (cluster2.node2) come from different clusters if they have different cluster_names"
198 );
199
200 ok(
201 $cluster->same_cluster($cxn2, $cxn3),
202 "sanity check: but still finds that nodes in the same cluster belong together"
203 );
204
205 diag($sb->stop_sandbox($node, $node2, $node3, $node4));
206}
207
208diag($sb->stop_sandbox("master1"));
209
210# #############################################################################
211# Done.
212# #############################################################################
213$master_dbh->disconnect() if $master_dbh;
214ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
215done_testing;
216exit;
0217
=== added file 't/pt-table-checksum/pxc.t'
--- t/pt-table-checksum/pxc.t 1970-01-01 00:00:00 +0000
+++ t/pt-table-checksum/pxc.t 2012-11-08 20:42:20 +0000
@@ -0,0 +1,242 @@
1#!/usr/bin/env perl
2
3BEGIN {
4 die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
5 unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
6 unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
7};
8
9use strict;
10use warnings FATAL => 'all';
11use English qw(-no_match_vars);
12use Test::More;
13use Data::Dumper;
14use File::Spec::Functions;
15
16# Hostnames make testing less accurate. Tests need to see
17# that such-and-such happened on specific slave hosts, but
18# the sandbox servers are all on one host so all slaves have
19# the same hostname.
20$ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} = 1;
21
22use PerconaTest;
23use Sandbox;
24
25require "$trunk/bin/pt-table-checksum";
26# Do this after requiring ptc, since it uses Mo
27require VersionParser;
28
29my $dp = new DSNParser(opts=>$dsn_opts);
30my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
31my $master_dbh = $sb->get_dbh_for('master');
32
33my $db_flavor = VersionParser->new($master_dbh)->flavor();
34
35if ( !$master_dbh ) {
36 plan skip_all => 'Cannot connect to sandbox master';
37}
38elsif ( $db_flavor !~ /XtraDB Cluster/ ) {
39 plan skip_all => "PXC tests";
40}
41
42# The sandbox servers run with lock_wait_timeout=3 and it's not dynamic
43# so we need to specify --lock-wait-timeout=3 else the tool will die.
44my $master_dsn = 'h=127.1,P=12345,u=msandbox,p=msandbox';
45my @args = ($master_dsn, qw(--lock-wait-timeout 3));
46my $output;
47my $exit_status;
48my $sample = "t/pt-table-checksum/samples/";
49
50# #############################################################################
51# pt-table-checksum v2.1.4 doesn't detect diffs on Percona XtraDB Cluster nodes
52# https://bugs.launchpad.net/percona-toolkit/+bug/1062563
53# #############################################################################
54
55sub make_dbh_differ {
56 my ($dbh, @vals) = @_;
57 @vals = (@vals ? @vals : 1);
58 # Make them differ...
59 $dbh->do("DROP DATABASE IF EXISTS bug_1062563");
60 $dbh->do("CREATE DATABASE bug_1062563");
61 $dbh->do("CREATE TABLE bug_1062563.ptc_pxc (i int)");
62
63 # Now make this node different from the rest
64 $dbh->do("set sql_log_bin=0");
65 $dbh->do("INSERT INTO bug_1062563.ptc_pxc (i) VALUES ($_)") for @vals;
66 $dbh->do("set sql_log_bin=1");
67}
68
69diag("Creating a 5-node PXC cluster...");
70my @nodes = $sb->start_cluster(cluster_size => 5);
71diag("Nodes: ", Dumper( { map { $_ => $sb->port_for($_) } @nodes } ));
72
73my $node2 = $nodes[1];
74my $node2_dbh = $sb->get_dbh_for($node2);
75
76my $node2_slave = "master3";
77
78diag("Creating a slave for $node2...");
79{
80 local $ENV{BINLOG_FORMAT} = 'ROW';
81 diag($sb->start_sandbox("slave", $node2_slave, $node2));
82}
83my $node_slave_dbh = $sb->get_dbh_for($node2_slave);
84
85make_dbh_differ($node2_dbh);
86
87# And make its slave differ as well
88PerconaTest::wait_for_table($sb->get_dbh_for($nodes[-1]), "bug_1062563.ptc_pxc");
89PerconaTest::wait_for_table($node_slave_dbh, "bug_1062563.ptc_pxc");
90$node_slave_dbh->do("INSERT INTO bug_1062563.ptc_pxc (i) VALUES ($_)") for 3, 4;
91
92my $dsns_table_sql = catfile(qw(t lib samples MasterSlave dsn_table.sql));
93$sb->load_file($node2, $dsns_table_sql, undef, no_wait => 1);
94$node2_dbh->do("DELETE FROM dsn_t.dsns"); # Delete 12346
95my $sth = $node2_dbh->prepare("INSERT INTO dsn_t.dsns VALUES (null, null, ?)");
96for my $dsn ( map { $sb->dsn_for($_) } @nodes[0,2..$#nodes], $node2_slave ) {
97 $sth->execute($dsn);
98}
99
100my $node2_dsn = $sb->dsn_for($node2);
101$output = output(
102 sub { pt_table_checksum::main(
103 $node2_dsn, qw(--lock-wait-timeout 3),
104 qw(-d bug_1062563),
105 '--recursion-method', "dsn=D=dsn_t,t=dsns"
106 ) },
107 stderr => 1,
108);
109
110is(
111 PerconaTest::count_checksum_results($output, 'diffs'),
112 1,
113 "Bug 1062563: Detects diffs between PXC nodes"
114) or diag($output);
115
116my @cluster_nodes = $output =~ /(because it is a cluster node)/g;
117is(
118 scalar(@cluster_nodes),
119 4,
120 "Skips all the cluster nodes in the dsns table"
121) or diag($output);
122
123# Now try with just the slave
124
125$node2_dbh->do("DELETE FROM dsn_t.dsns");
126$sth->execute($sb->dsn_for($node2_slave));
127
128$output = output(
129 sub { pt_table_checksum::main(
130 $node2_dsn, qw(--lock-wait-timeout 3),
131 qw(--chunk-size 1),
132 qw(-d bug_1062563),
133 '--recursion-method', "dsn=D=dsn_t,t=dsns"
134 ) },
135 stderr => 1,
136);
137
138is(
139 PerconaTest::count_checksum_results($output, 'diffs'),
140 1,
141 "Bug 1062563: Detects diffs on slaves where the master is a PXC node"
142) or diag($output);
143
144$sth->finish();
145diag("Stopping the PXC cluster and the slave...");
146$sb->stop_sandbox($node2_slave, @nodes);
147
148# Now checking that cluster -> cluster works
149
150diag("Creating two 3-node clusters...");
151my @cluster1 = $sb->start_cluster(cluster_size => 3, cluster_name => "pt_test_cluster_1");
152my @cluster2 = $sb->start_cluster(cluster_size => 3, cluster_name => "pt_test_cluster_2");
153diag("Cluster 1: ", Dumper( { map { $_ => $sb->port_for($_) } @cluster1 } ));
154diag("Cluster 2: ", Dumper( { map { $_ => $sb->port_for($_) } @cluster2 } ));
155
156$sb->set_as_slave($cluster2[0], $cluster1[0]);
157
158my $cluster1_dbh = $sb->get_dbh_for($cluster1[0]);
159my $cluster2_dbh = $sb->get_dbh_for($cluster2[0]);
160make_dbh_differ($cluster1_dbh);
161
162# And make its slave differ as well
163PerconaTest::wait_for_table($sb->get_dbh_for($cluster2[-1]), "bug_1062563.ptc_pxc");
164PerconaTest::wait_for_table($sb->get_dbh_for($cluster1[-1]), "bug_1062563.ptc_pxc");
165PerconaTest::wait_for_table($cluster2_dbh, "bug_1062563.ptc_pxc");
166$cluster2_dbh->do("INSERT INTO bug_1062563.ptc_pxc (i) VALUES ($_)") for 3, 4;
167
168$dsns_table_sql = catfile(qw(t lib samples MasterSlave dsn_table.sql));
169$sb->load_file($cluster1[0], $dsns_table_sql, undef, no_wait => 1);
170$cluster1_dbh->do("DELETE FROM dsn_t.dsns"); # Delete 12346
171$sth = $cluster1_dbh->prepare("INSERT INTO dsn_t.dsns VALUES (null, null, ?)");
172for my $dsn ( map { $sb->dsn_for($_) } @cluster1[1..$#cluster1], $cluster2[0] ) {
173 $sth->execute($dsn);
174}
175$sth->finish();
176
177my $cluster1_dsn = $sb->dsn_for($cluster1[0]);
178$output = output(
179 sub { pt_table_checksum::main(
180 $cluster1_dsn, qw(--lock-wait-timeout 3),
181 qw(-d bug_1062563),
182 '--recursion-method', "dsn=D=dsn_t,t=dsns"
183 ) },
184 stderr => 1,
185);
186
187is(
188 PerconaTest::count_checksum_results($output, 'diffs'),
189 1,
190 "Bug 1062563: Detects diffs between PXC nodes when cluster -> cluster"
191) or diag($output);
192
193like(
194 $output,
195 qr/is a cluster node, but doesn't belong to the same cluster as/, #'
196 "Shows a warning when cluster -> cluster"
197) or diag($output);
198
199diag("Starting master1...");
200$sb->start_sandbox("master", "master1");
201diag("Setting it as master of a node in the first cluster");
202$sb->set_as_slave($cluster1[0], "master1");
203
204my $master1_dbh = $sb->get_dbh_for("master1");
205make_dbh_differ($master1_dbh, 10..50);
206
207my $master1_dsn = $sb->dsn_for("master1");
208$output = output(
209 sub { pt_table_checksum::main(
210 $master1_dsn, qw(--lock-wait-timeout 3),
211 qw(-d bug_1062563),
212 ) },
213 stderr => 1,
214);
215
216is(
217 PerconaTest::count_checksum_results($output, 'diffs'),
218 1,
219 "Bug 1062563: Detects diffs when master -> cluster"
220) or diag($output);
221
222is(
223 PerconaTest::count_checksum_results($output, 'rows'),
224 41,
225 "Bug 1062563: Correct number of rows for master -> cluster"
226) or diag($output);
227
228like(
229 $output,
230 qr/is a cluster node, but .*? is not. This is not currently supported/,
231 "Shows a warning when master -> cluster"
232) or diag($output);
233
234diag("Stopping both clusters and master1...");
235$sb->stop_sandbox(@cluster1, @cluster2, "master1");
236
237# #############################################################################
238# Done.
239# #############################################################################
240$sb->wipe_clean($master_dbh);
241ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
242done_testing;

Subscribers

People subscribed via source and target branches