Rewrite and enhance lib/Percona/XtraDB/Cluster.pm and t/pt-table-checksum/pxc.t. Change how ptc handles various cluster issues. Change lib/Sandbox.pm subs like start_sandbox() and start_cluster(). PXC docs in ptc are a work in progress.

This commit is contained in:
Daniel Nichter
2012-11-18 22:05:30 -07:00
parent 07bee85a00
commit e0f0ea0cdb
5 changed files with 841 additions and 407 deletions

View File

@@ -1,4 +1,4 @@
# This program is copyright 2011 Percona Inc.
# This program is copyright 2012 Percona Inc.
# Feedback and improvements are welcome.
#
# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
@@ -19,104 +19,60 @@
# ###########################################################################
{
# Package: Percona::XtraDB::Cluster
# Percona::XtraDB::Cluster has helper methods to deal with Percona XtraDB Cluster
# based servers
# Helper methods for dealing with Percona XtraDB Cluster nodes.
package Percona::XtraDB::Cluster;
use Mo;
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
use Mo;
use Data::Dumper;
sub get_cluster_name {
my ($self, $cxn) = @_;
my $sql = "SHOW VARIABLES LIKE 'wsrep\_cluster\_name'";
PTDEBUG && _d($cxn->name, $sql);
my (undef, $cluster_name) = $cxn->dbh->selectrow_array($sql);
return $cluster_name;
}
sub is_cluster_node {
my ($self, $cxn) = @_;
return $self->{is_cluster_node}->{$cxn} if defined $self->{is_cluster_node}->{$cxn};
my $sql = "SHOW VARIABLES LIKE 'wsrep_on'";
PTDEBUG && _d($sql);
my $sql = "SHOW VARIABLES LIKE 'wsrep\_on'";
PTDEBUG && _d($cxn->name, $sql);
my $row = $cxn->dbh->selectrow_arrayref($sql);
PTDEBUG && _d(defined $row ? @$row : 'undef');
$self->{is_cluster_node}->{$cxn} = $row && $row->[1]
? ($row->[1] eq 'ON' || $row->[1] eq '1')
: 0;
PTDEBUG && _d(Dumper($row));
return unless $row && $row->[1] && ($row->[1] eq 'ON' || $row->[1] eq '1');
return $self->{is_cluster_node}->{$cxn};
my $cluster_name = $self->get_cluster_name($cxn);
return $cluster_name;
}
sub same_node {
my ($self, $cxn1, $cxn2) = @_;
my $sql = "SHOW VARIABLES LIKE 'wsrep\_sst\_receive\_address'";
PTDEBUG && _d($cxn1->name, $sql);
my (undef, $val1) = $cxn1->dbh->selectrow_array($sql);
PTDEBUG && _d($cxn2->name, $sql);
my (undef, $val2) = $cxn2->dbh->selectrow_array($sql);
return ($val1 || '') eq ($val2 || '');
}
sub same_cluster {
my ($self, $cxn1, $cxn2) = @_;
return unless $self->is_cluster_node($cxn1) && $self->is_cluster_node($cxn2);
return if $self->is_master_of($cxn1, $cxn2) || $self->is_master_of($cxn2, $cxn1);
my $sql = q{SHOW VARIABLES LIKE 'wsrep_cluster_name'};
PTDEBUG && _d($sql);
my (undef, $row) = $cxn1->dbh->selectrow_array($sql);
my (undef, $cxn2_row) = $cxn2->dbh->selectrow_array($sql);
# They can't be the same cluster if one of them isn't in a cluster.
return 0 if !$self->is_cluster_node($cxn1) || !$self->is_cluster_node($cxn2);
return unless $row eq $cxn2_row;
my $cluster1 = $self->get_cluster_name($cxn1);
my $cluster2 = $self->get_cluster_name($cxn2);
# Now it becomes tricky. Ostensibly clusters shouldn't have the
# same name, but tell that to the world.
$sql = q{SHOW VARIABLES LIKE 'wsrep_cluster_address'};
PTDEBUG && _d($sql);
my (undef, $addr) = $cxn1->dbh->selectrow_array($sql);
my (undef, $cxn2_addr) = $cxn2->dbh->selectrow_array($sql);
# If they both have gcomm://, then they are both the first
# node of a cluster, so they can't be in the same one.
return if $addr eq 'gcomm://' && $cxn2_addr eq 'gcomm://';
if ( $addr eq 'gcomm://' ) {
$addr = $self->_find_full_gcomm_addr($cxn1->dbh);
}
elsif ( $cxn2_addr eq 'gcomm://' ) {
$cxn2_addr = $self->_find_full_gcomm_addr($cxn2->dbh);
}
# Meanwhile, if they have the same address, then
# they are definitely part of the same cluster
return 1 if lc($addr) eq lc($cxn2_addr);
# However, this still leaves us with the issue that
# the cluster addresses could look like this:
# node1 -> node2, node2 -> node1,
# or
# node1 -> node2 addr,
# node2 -> node3 addr,
# node3 -> node1 addr,
# TODO No clue what to do here
return 1;
}
sub is_master_of {
my ($self, $cxn1, $cxn2) = @_;
my $cxn2_dbh = $cxn2->dbh;
my $sql = q{SHOW SLAVE STATUS};
PTDEBUG && _d($sql);
local $cxn2_dbh->{FetchHashKeyName} = 'NAME_lc';
my $slave_status = $cxn2_dbh->selectrow_hashref($sql);
return unless ref($slave_status) eq 'HASH';
my $port = $cxn1->dsn->{P};
return unless $slave_status->{master_port} eq $port;
return 1 if $cxn1->dsn->{h} eq $slave_status->{master_host};
# They might be the same but in different format
my $host = scalar gethostbyname($cxn1->dsn->{h});
my $master_host = scalar gethostbyname($slave_status->{master_host});
return 1 if $master_host eq $host;
return;
}
sub _find_full_gcomm_addr {
my ($self, $dbh) = @_;
my $sql = q{SHOW VARIABLES LIKE 'wsrep_provider_options'};
PTDEBUG && _d($sql);
my (undef, $provider_opts) = $dbh->selectrow_array($sql);
my ($prov_addr) = $provider_opts =~ m{\Qgmcast.listen_addr\E\s*=\s*tcp://([^:]+:[0-9]+)\s*;}i;
my $full_gcomm = "gcomm://$prov_addr";
PTDEBUG && _d("gcomm address: ", $full_gcomm);
return $full_gcomm;
return ($cluster1 || '') eq ($cluster2 || '');
}
sub _d {
@@ -129,3 +85,6 @@ sub _d {
1;
}
# ###########################################################################
# End Percona::XtraDB::Cluster package
# ###########################################################################