Merge fix-953141-recursion-method-array

This commit is contained in:
Daniel Nichter
2012-08-02 12:01:34 -06:00
12 changed files with 975 additions and 544 deletions

View File

@@ -3078,8 +3078,31 @@ use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
sub check_recursion_method {
my ($methods) = @_;
if ( @$methods != 1 ) {
if ( grep({ !m/processlist|hosts/i } @$methods)
&& $methods->[0] !~ /^dsn=/i )
{
die "Invalid combination of recursion methods: "
. join(", ", map { defined($_) ? $_ : 'undef' } @$methods) . ". "
. "Only hosts and processlist may be combined.\n"
}
}
else {
my ($method) = @$methods;
die "Invalid recursion method: " . ( $method || 'undef' )
unless $method && $method =~ m/^(?:processlist$|hosts$|none$|dsn=)/i;
}
}
sub new {
my ( $class, %args ) = @_;
my @required_args = qw(OptionParser DSNParser Quoter);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my $self = {
%args,
replication_thread => {},
@@ -3089,28 +3112,27 @@ sub new {
sub get_slaves {
my ($self, %args) = @_;
my @required_args = qw(make_cxn OptionParser DSNParser Quoter);
my @required_args = qw(make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($make_cxn, $o, $dp) = @args{@required_args};
my ($make_cxn) = @args{@required_args};
my $slaves = [];
my $method = $o->get('recursion-method');
PTDEBUG && _d('Slave recursion method:', $method);
if ( !$method || $method =~ m/processlist|hosts/i ) {
my $slaves = [];
my $dp = $self->{DSNParser};
my $methods = $self->_resolve_recursion_methods($args{dsn});
if ( grep { m/processlist|hosts/i } @$methods ) {
my @required_args = qw(dbh dsn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dbh, $dsn) = @args{@required_args};
$self->recurse_to_slaves(
{ dbh => $dbh,
dsn => $dsn,
dsn_parser => $dp,
recurse => $o->get('recurse'),
method => $o->get('recursion-method'),
callback => sub {
{ dbh => $dbh,
dsn => $dsn,
callback => sub {
my ( $dsn, $dbh, $level, $parent ) = @_;
return unless $level;
PTDEBUG && _d('Found slave:', $dp->as_string($dsn));
@@ -3120,31 +3142,48 @@ sub get_slaves {
}
);
}
elsif ( $method =~ m/^dsn=/i ) {
my ($dsn_table_dsn) = $method =~ m/^dsn=(.+)/i;
elsif ( $methods->[0] =~ m/^dsn=/i ) {
(my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i;
$slaves = $self->get_cxn_from_dsn_table(
%args,
dsn_table_dsn => $dsn_table_dsn,
);
}
elsif ( $method =~ m/none/i ) {
elsif ( $methods->[0] =~ m/none/i ) {
PTDEBUG && _d('Not getting to slaves');
}
else {
die "Invalid --recursion-method: $method. Valid values are: "
. "dsn=DSN, hosts, or processlist.\n";
die "Unexpected recursion methods: @$methods";
}
return $slaves;
}
sub _resolve_recursion_methods {
my ($self, $dsn) = @_;
my $o = $self->{OptionParser};
if ( $o->got('recursion-method') ) {
return $o->get('recursion-method');
}
elsif ( $dsn && ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
return [qw(hosts)];
}
else {
return $o->get('recursion-method');
}
}
sub recurse_to_slaves {
my ( $self, $args, $level ) = @_;
$level ||= 0;
my $dp = $args->{dsn_parser};
my $dsn = $args->{dsn};
my $dp = $self->{DSNParser};
my $recurse = $args->{recurse} || $self->{OptionParser}->get('recurse');
my $dsn = $args->{dsn};
if ( lc($args->{method} || '') eq 'none' ) {
my $methods = $self->_resolve_recursion_methods($dsn);
PTDEBUG && _d('Recursion methods:', @$methods);
if ( lc($methods->[0]) eq 'none' ) {
PTDEBUG && _d('Not recursing to slaves');
return;
}
@@ -3179,11 +3218,11 @@ sub recurse_to_slaves {
$args->{callback}->($dsn, $dbh, $level, $args->{parent});
if ( !defined $args->{recurse} || $level < $args->{recurse} ) {
if ( !defined $recurse || $level < $recurse ) {
my @slaves =
grep { !$_->{master_id} || $_->{master_id} == $id } # Only my slaves.
$self->find_slave_hosts($dp, $dbh, $dsn, $args->{method});
$self->find_slave_hosts($dp, $dbh, $dsn, $methods);
foreach my $slave ( @slaves ) {
PTDEBUG && _d('Recursing from',
@@ -3195,25 +3234,14 @@ sub recurse_to_slaves {
}
sub find_slave_hosts {
my ( $self, $dsn_parser, $dbh, $dsn, $method ) = @_;
my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_;
my @methods = qw(processlist hosts);
if ( $method ) {
@methods = grep { $_ ne $method } @methods;
unshift @methods, $method;
}
else {
if ( ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
@methods = qw(hosts);
}
}
PTDEBUG && _d('Looking for slaves on', $dsn_parser->as_string($dsn),
'using methods', @methods);
'using methods', @$methods);
my @slaves;
METHOD:
foreach my $method ( @methods ) {
foreach my $method ( @$methods ) {
my $find_slaves = "_find_slaves_by_$method";
PTDEBUG && _d('Finding slaves with', $find_slaves);
@slaves = $self->$find_slaves($dsn_parser, $dbh, $dsn);
@@ -3716,13 +3744,16 @@ sub reset_known_replication_threads {
sub get_cxn_from_dsn_table {
my ($self, %args) = @_;
my @required_args = qw(dsn_table_dsn make_cxn DSNParser Quoter);
my @required_args = qw(dsn_table_dsn make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dsn_table_dsn, $make_cxn, $dp, $q) = @args{@required_args};
my ($dsn_table_dsn, $make_cxn) = @args{@required_args};
PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn);
my $dp = $self->{DSNParser};
my $q = $self->{Quoter};
my $dsn = $dp->parse($dsn_table_dsn);
my $dsn_table;
if ( $dsn->{D} && $dsn->{t} ) {
@@ -4054,7 +4085,11 @@ sub main {
my $dsn_defaults = $dp->parse_options($o);
my $dsn = $dp->parse($o->get('check-slave-lag'), $dsn_defaults);
$lag_dbh = $dp->get_dbh($dp->get_cxn_params($dsn), { AutoCommit => 1 });
$ms = new MasterSlave();
$ms = new MasterSlave(
OptionParser => $o,
DSNParser => $dp,
Quoter => $q,
);
}
# ########################################################################

View File

@@ -24,8 +24,31 @@ use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
sub check_recursion_method {
my ($methods) = @_;
if ( @$methods != 1 ) {
if ( grep({ !m/processlist|hosts/i } @$methods)
&& $methods->[0] !~ /^dsn=/i )
{
die "Invalid combination of recursion methods: "
. join(", ", map { defined($_) ? $_ : 'undef' } @$methods) . ". "
. "Only hosts and processlist may be combined.\n"
}
}
else {
my ($method) = @$methods;
die "Invalid recursion method: " . ( $method || 'undef' )
unless $method && $method =~ m/^(?:processlist$|hosts$|none$|dsn=)/i;
}
}
sub new {
my ( $class, %args ) = @_;
my @required_args = qw(OptionParser DSNParser Quoter);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my $self = {
%args,
replication_thread => {},
@@ -35,28 +58,27 @@ sub new {
sub get_slaves {
my ($self, %args) = @_;
my @required_args = qw(make_cxn OptionParser DSNParser Quoter);
my @required_args = qw(make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($make_cxn, $o, $dp) = @args{@required_args};
my ($make_cxn) = @args{@required_args};
my $slaves = [];
my $method = $o->get('recursion-method');
PTDEBUG && _d('Slave recursion method:', $method);
if ( !$method || $method =~ m/processlist|hosts/i ) {
my $slaves = [];
my $dp = $self->{DSNParser};
my $methods = $self->_resolve_recursion_methods($args{dsn});
if ( grep { m/processlist|hosts/i } @$methods ) {
my @required_args = qw(dbh dsn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dbh, $dsn) = @args{@required_args};
$self->recurse_to_slaves(
{ dbh => $dbh,
dsn => $dsn,
dsn_parser => $dp,
recurse => $o->get('recurse'),
method => $o->get('recursion-method'),
callback => sub {
{ dbh => $dbh,
dsn => $dsn,
callback => sub {
my ( $dsn, $dbh, $level, $parent ) = @_;
return unless $level;
PTDEBUG && _d('Found slave:', $dp->as_string($dsn));
@@ -66,31 +88,48 @@ sub get_slaves {
}
);
}
elsif ( $method =~ m/^dsn=/i ) {
my ($dsn_table_dsn) = $method =~ m/^dsn=(.+)/i;
elsif ( $methods->[0] =~ m/^dsn=/i ) {
(my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i;
$slaves = $self->get_cxn_from_dsn_table(
%args,
dsn_table_dsn => $dsn_table_dsn,
);
}
elsif ( $method =~ m/none/i ) {
elsif ( $methods->[0] =~ m/none/i ) {
PTDEBUG && _d('Not getting to slaves');
}
else {
die "Invalid --recursion-method: $method. Valid values are: "
. "dsn=DSN, hosts, or processlist.\n";
die "Unexpected recursion methods: @$methods";
}
return $slaves;
}
sub _resolve_recursion_methods {
my ($self, $dsn) = @_;
my $o = $self->{OptionParser};
if ( $o->got('recursion-method') ) {
return $o->get('recursion-method');
}
elsif ( $dsn && ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
return [qw(hosts)];
}
else {
return $o->get('recursion-method');
}
}
sub recurse_to_slaves {
my ( $self, $args, $level ) = @_;
$level ||= 0;
my $dp = $args->{dsn_parser};
my $dsn = $args->{dsn};
my $dp = $self->{DSNParser};
my $recurse = $args->{recurse} || $self->{OptionParser}->get('recurse');
my $dsn = $args->{dsn};
if ( lc($args->{method} || '') eq 'none' ) {
my $methods = $self->_resolve_recursion_methods($dsn);
PTDEBUG && _d('Recursion methods:', @$methods);
if ( lc($methods->[0]) eq 'none' ) {
PTDEBUG && _d('Not recursing to slaves');
return;
}
@@ -125,11 +164,11 @@ sub recurse_to_slaves {
$args->{callback}->($dsn, $dbh, $level, $args->{parent});
if ( !defined $args->{recurse} || $level < $args->{recurse} ) {
if ( !defined $recurse || $level < $recurse ) {
my @slaves =
grep { !$_->{master_id} || $_->{master_id} == $id } # Only my slaves.
$self->find_slave_hosts($dp, $dbh, $dsn, $args->{method});
$self->find_slave_hosts($dp, $dbh, $dsn, $methods);
foreach my $slave ( @slaves ) {
PTDEBUG && _d('Recursing from',
@@ -141,25 +180,14 @@ sub recurse_to_slaves {
}
sub find_slave_hosts {
my ( $self, $dsn_parser, $dbh, $dsn, $method ) = @_;
my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_;
my @methods = qw(processlist hosts);
if ( $method ) {
@methods = grep { $_ ne $method } @methods;
unshift @methods, $method;
}
else {
if ( ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
@methods = qw(hosts);
}
}
PTDEBUG && _d('Looking for slaves on', $dsn_parser->as_string($dsn),
'using methods', @methods);
'using methods', @$methods);
my @slaves;
METHOD:
foreach my $method ( @methods ) {
foreach my $method ( @$methods ) {
my $find_slaves = "_find_slaves_by_$method";
PTDEBUG && _d('Finding slaves with', $find_slaves);
@slaves = $self->$find_slaves($dsn_parser, $dbh, $dsn);
@@ -662,13 +690,16 @@ sub reset_known_replication_threads {
sub get_cxn_from_dsn_table {
my ($self, %args) = @_;
my @required_args = qw(dsn_table_dsn make_cxn DSNParser Quoter);
my @required_args = qw(dsn_table_dsn make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dsn_table_dsn, $make_cxn, $dp, $q) = @args{@required_args};
my ($dsn_table_dsn, $make_cxn) = @args{@required_args};
PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn);
my $dp = $self->{DSNParser};
my $q = $self->{Quoter};
my $dsn = $dp->parse($dsn_table_dsn);
my $dsn_table;
if ( $dsn->{D} && $dsn->{t} ) {
@@ -1994,7 +2025,7 @@ sub get_dbh {
PTDEBUG && _d($dbh, $sql);
my ($sql_mode) = eval { $dbh->selectrow_array($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error getting the current SQL_MODE: $EVAL_ERROR";
}
$sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
@@ -2004,15 +2035,17 @@ sub get_dbh {
PTDEBUG && _d($dbh, $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting SQL_QUOTE_SHOW_CREATE, SQL_MODE"
. ($sql_mode ? " and $sql_mode" : '')
. ": $EVAL_ERROR";
}
if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
$sql = "/*!40101 SET NAMES $charset*/";
if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) {
$sql = qq{/*!40101 SET NAMES "$charset"*/};
PTDEBUG && _d($dbh, ':', $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting NAMES to $charset: $EVAL_ERROR";
}
PTDEBUG && _d('Enabling charset for STDOUT');
if ( $charset eq 'utf8' ) {
@@ -2024,12 +2057,12 @@ sub get_dbh {
}
}
if ( $self->prop('set-vars') ) {
$sql = "SET " . $self->prop('set-vars');
if ( my $var = $self->prop('set-vars') ) {
$sql = "SET $var";
PTDEBUG && _d($dbh, ':', $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting $var: $EVAL_ERROR";
}
}
}
@@ -3282,6 +3315,13 @@ sub main {
}
}
eval {
MasterSlave::check_recursion_method($o->get('recursion-method'));
};
if ( $EVAL_ERROR ) {
$o->save_error("Invalid --recursion-method: $EVAL_ERROR")
}
$o->usage_or_errors();
# ########################################################################
@@ -3407,7 +3447,11 @@ sub main {
my $master_server_id = $o->get('master-server-id');
if ( !$master_server_id ) {
eval {
my $ms = new MasterSlave();
my $ms = new MasterSlave(
OptionParser => $o,
DSNParser => $dp,
Quoter => $q,
);
my $master_dsn = $ms->get_master_dsn($dbh, $dsn, $dp)
or die "This server is not a slave";
my $master_dbh = $dp->get_dbh($dp->get_cxn_params($master_dsn),
@@ -3734,19 +3778,20 @@ sub check_delay {
# Collect a list of connections to the slaves.
if ( $o->get('recurse') ) {
PTDEBUG && _d('Recursing to slaves');
my $ms = new MasterSlave();
my $ms = new MasterSlave(
OptionParser => $o,
DSNParser => $dp,
Quoter => "Quoter",
);
$ms->recurse_to_slaves(
{ dbh => $dbh,
dsn => $dsn,
dsn_parser => $dp,
recurse => $o->get('recurse'),
callback => sub {
my ( $dsn, $dbh, $level ) = @_;
push @dbhs, $dbh;
PTDEBUG && _d("Found slave", $dp->as_string($dsn));
push @sths, [ $dsn, $dbh->prepare($sql) ];
},
method => $o->get('recursion-method'),
},
);
}
@@ -4235,7 +4280,7 @@ This currently works only with MySQL. See L<"--recursion-method">.
=item --recursion-method
type: string
type: array; default: processlist,hosts
Preferred recursion method used to find slaves.

View File

@@ -3345,8 +3345,31 @@ use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
sub check_recursion_method {
my ($methods) = @_;
if ( @$methods != 1 ) {
if ( grep({ !m/processlist|hosts/i } @$methods)
&& $methods->[0] !~ /^dsn=/i )
{
die "Invalid combination of recursion methods: "
. join(", ", map { defined($_) ? $_ : 'undef' } @$methods) . ". "
. "Only hosts and processlist may be combined.\n"
}
}
else {
my ($method) = @$methods;
die "Invalid recursion method: " . ( $method || 'undef' )
unless $method && $method =~ m/^(?:processlist$|hosts$|none$|dsn=)/i;
}
}
sub new {
my ( $class, %args ) = @_;
my @required_args = qw(OptionParser DSNParser Quoter);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my $self = {
%args,
replication_thread => {},
@@ -3356,28 +3379,27 @@ sub new {
sub get_slaves {
my ($self, %args) = @_;
my @required_args = qw(make_cxn OptionParser DSNParser Quoter);
my @required_args = qw(make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($make_cxn, $o, $dp) = @args{@required_args};
my ($make_cxn) = @args{@required_args};
my $slaves = [];
my $method = $o->get('recursion-method');
PTDEBUG && _d('Slave recursion method:', $method);
if ( !$method || $method =~ m/processlist|hosts/i ) {
my $slaves = [];
my $dp = $self->{DSNParser};
my $methods = $self->_resolve_recursion_methods($args{dsn});
if ( grep { m/processlist|hosts/i } @$methods ) {
my @required_args = qw(dbh dsn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dbh, $dsn) = @args{@required_args};
$self->recurse_to_slaves(
{ dbh => $dbh,
dsn => $dsn,
dsn_parser => $dp,
recurse => $o->get('recurse'),
method => $o->get('recursion-method'),
callback => sub {
{ dbh => $dbh,
dsn => $dsn,
callback => sub {
my ( $dsn, $dbh, $level, $parent ) = @_;
return unless $level;
PTDEBUG && _d('Found slave:', $dp->as_string($dsn));
@@ -3387,31 +3409,48 @@ sub get_slaves {
}
);
}
elsif ( $method =~ m/^dsn=/i ) {
my ($dsn_table_dsn) = $method =~ m/^dsn=(.+)/i;
elsif ( $methods->[0] =~ m/^dsn=/i ) {
(my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i;
$slaves = $self->get_cxn_from_dsn_table(
%args,
dsn_table_dsn => $dsn_table_dsn,
);
}
elsif ( $method =~ m/none/i ) {
elsif ( $methods->[0] =~ m/none/i ) {
PTDEBUG && _d('Not getting to slaves');
}
else {
die "Invalid --recursion-method: $method. Valid values are: "
. "dsn=DSN, hosts, or processlist.\n";
die "Unexpected recursion methods: @$methods";
}
return $slaves;
}
sub _resolve_recursion_methods {
my ($self, $dsn) = @_;
my $o = $self->{OptionParser};
if ( $o->got('recursion-method') ) {
return $o->get('recursion-method');
}
elsif ( $dsn && ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
return [qw(hosts)];
}
else {
return $o->get('recursion-method');
}
}
sub recurse_to_slaves {
my ( $self, $args, $level ) = @_;
$level ||= 0;
my $dp = $args->{dsn_parser};
my $dsn = $args->{dsn};
my $dp = $self->{DSNParser};
my $recurse = $args->{recurse} || $self->{OptionParser}->get('recurse');
my $dsn = $args->{dsn};
if ( lc($args->{method} || '') eq 'none' ) {
my $methods = $self->_resolve_recursion_methods($dsn);
PTDEBUG && _d('Recursion methods:', @$methods);
if ( lc($methods->[0]) eq 'none' ) {
PTDEBUG && _d('Not recursing to slaves');
return;
}
@@ -3446,11 +3485,11 @@ sub recurse_to_slaves {
$args->{callback}->($dsn, $dbh, $level, $args->{parent});
if ( !defined $args->{recurse} || $level < $args->{recurse} ) {
if ( !defined $recurse || $level < $recurse ) {
my @slaves =
grep { !$_->{master_id} || $_->{master_id} == $id } # Only my slaves.
$self->find_slave_hosts($dp, $dbh, $dsn, $args->{method});
$self->find_slave_hosts($dp, $dbh, $dsn, $methods);
foreach my $slave ( @slaves ) {
PTDEBUG && _d('Recursing from',
@@ -3462,25 +3501,14 @@ sub recurse_to_slaves {
}
sub find_slave_hosts {
my ( $self, $dsn_parser, $dbh, $dsn, $method ) = @_;
my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_;
my @methods = qw(processlist hosts);
if ( $method ) {
@methods = grep { $_ ne $method } @methods;
unshift @methods, $method;
}
else {
if ( ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
@methods = qw(hosts);
}
}
PTDEBUG && _d('Looking for slaves on', $dsn_parser->as_string($dsn),
'using methods', @methods);
'using methods', @$methods);
my @slaves;
METHOD:
foreach my $method ( @methods ) {
foreach my $method ( @$methods ) {
my $find_slaves = "_find_slaves_by_$method";
PTDEBUG && _d('Finding slaves with', $find_slaves);
@slaves = $self->$find_slaves($dsn_parser, $dbh, $dsn);
@@ -3983,13 +4011,16 @@ sub reset_known_replication_threads {
sub get_cxn_from_dsn_table {
my ($self, %args) = @_;
my @required_args = qw(dsn_table_dsn make_cxn DSNParser Quoter);
my @required_args = qw(dsn_table_dsn make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dsn_table_dsn, $make_cxn, $dp, $q) = @args{@required_args};
my ($dsn_table_dsn, $make_cxn) = @args{@required_args};
PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn);
my $dp = $self->{DSNParser};
my $q = $self->{Quoter};
my $dsn = $dp->parse($dsn_table_dsn);
my $dsn_table;
if ( $dsn->{D} && $dsn->{t} ) {
@@ -4802,10 +4833,6 @@ my $o;
sub main {
@ARGV = @_; # set global ARGV for this package
my $ms = new MasterSlave();
my $pl = new Processlist(MasterSlave => $ms);
my $qr = new QueryRewriter();
# ########################################################################
# Get configuration information.
# ########################################################################
@@ -4880,6 +4907,14 @@ sub main {
# ########################################################################
# Make input sub that will either get processlist from MySQL or a file.
# ########################################################################
my $ms = new MasterSlave(
OptionParser => $o,
DSNParser => $dp,
Quoter => "Quoter",
);
my $pl = new Processlist(MasterSlave => $ms);
my $qr = new QueryRewriter();
my $cxn;
my $dbh; # $cxn->dbh
my $get_proclist; # callback to SHOW PROCESSLIST

View File

@@ -1935,7 +1935,7 @@ sub get_dbh {
PTDEBUG && _d($dbh, $sql);
my ($sql_mode) = eval { $dbh->selectrow_array($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error getting the current SQL_MODE: $EVAL_ERROR";
}
$sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
@@ -1945,15 +1945,17 @@ sub get_dbh {
PTDEBUG && _d($dbh, $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting SQL_QUOTE_SHOW_CREATE, SQL_MODE"
. ($sql_mode ? " and $sql_mode" : '')
. ": $EVAL_ERROR";
}
if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
$sql = "/*!40101 SET NAMES $charset*/";
if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) {
$sql = qq{/*!40101 SET NAMES "$charset"*/};
PTDEBUG && _d($dbh, ':', $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting NAMES to $charset: $EVAL_ERROR";
}
PTDEBUG && _d('Enabling charset for STDOUT');
if ( $charset eq 'utf8' ) {
@@ -1965,12 +1967,12 @@ sub get_dbh {
}
}
if ( $self->prop('set-vars') ) {
$sql = "SET " . $self->prop('set-vars');
if ( my $var = $self->prop('set-vars') ) {
$sql = "SET $var";
PTDEBUG && _d($dbh, ':', $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting $var: $EVAL_ERROR";
}
}
}
@@ -3333,6 +3335,7 @@ sub new {
dsn_name => $dp->as_string($dsn, [qw(h P S)]),
hostname => '',
set => $args{set},
NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1,
dbh_set => 0,
OptionParser => $o,
DSNParser => $dp,
@@ -3370,7 +3373,10 @@ sub set_dbh {
PTDEBUG && _d($dbh, 'Setting dbh');
$dbh->{FetchHashKeyName} = 'NAME_lc';
if ( !exists $self->{NAME_lc}
|| (defined $self->{NAME_lc} && $self->{NAME_lc}) ) {
$dbh->{FetchHashKeyName} = 'NAME_lc';
}
my $sql = 'SELECT @@hostname, @@server_id';
PTDEBUG && _d($dbh, $sql);
@@ -3446,8 +3452,31 @@ use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
sub check_recursion_method {
my ($methods) = @_;
if ( @$methods != 1 ) {
if ( grep({ !m/processlist|hosts/i } @$methods)
&& $methods->[0] !~ /^dsn=/i )
{
die "Invalid combination of recursion methods: "
. join(", ", map { defined($_) ? $_ : 'undef' } @$methods) . ". "
. "Only hosts and processlist may be combined.\n"
}
}
else {
my ($method) = @$methods;
die "Invalid recursion method: " . ( $method || 'undef' )
unless $method && $method =~ m/^(?:processlist$|hosts$|none$|dsn=)/i;
}
}
sub new {
my ( $class, %args ) = @_;
my @required_args = qw(OptionParser DSNParser Quoter);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my $self = {
%args,
replication_thread => {},
@@ -3457,28 +3486,27 @@ sub new {
sub get_slaves {
my ($self, %args) = @_;
my @required_args = qw(make_cxn OptionParser DSNParser Quoter);
my @required_args = qw(make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($make_cxn, $o, $dp) = @args{@required_args};
my ($make_cxn) = @args{@required_args};
my $slaves = [];
my $method = $o->get('recursion-method');
PTDEBUG && _d('Slave recursion method:', $method);
if ( !$method || $method =~ m/processlist|hosts/i ) {
my $slaves = [];
my $dp = $self->{DSNParser};
my $methods = $self->_resolve_recursion_methods($args{dsn});
if ( grep { m/processlist|hosts/i } @$methods ) {
my @required_args = qw(dbh dsn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dbh, $dsn) = @args{@required_args};
$self->recurse_to_slaves(
{ dbh => $dbh,
dsn => $dsn,
dsn_parser => $dp,
recurse => $o->get('recurse'),
method => $o->get('recursion-method'),
callback => sub {
{ dbh => $dbh,
dsn => $dsn,
callback => sub {
my ( $dsn, $dbh, $level, $parent ) = @_;
return unless $level;
PTDEBUG && _d('Found slave:', $dp->as_string($dsn));
@@ -3488,31 +3516,48 @@ sub get_slaves {
}
);
}
elsif ( $method =~ m/^dsn=/i ) {
my ($dsn_table_dsn) = $method =~ m/^dsn=(.+)/i;
elsif ( $methods->[0] =~ m/^dsn=/i ) {
(my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i;
$slaves = $self->get_cxn_from_dsn_table(
%args,
dsn_table_dsn => $dsn_table_dsn,
);
}
elsif ( $method =~ m/none/i ) {
elsif ( $methods->[0] =~ m/none/i ) {
PTDEBUG && _d('Not getting to slaves');
}
else {
die "Invalid --recursion-method: $method. Valid values are: "
. "dsn=DSN, hosts, or processlist.\n";
die "Unexpected recursion methods: @$methods";
}
return $slaves;
}
sub _resolve_recursion_methods {
my ($self, $dsn) = @_;
my $o = $self->{OptionParser};
if ( $o->got('recursion-method') ) {
return $o->get('recursion-method');
}
elsif ( $dsn && ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
return [qw(hosts)];
}
else {
return $o->get('recursion-method');
}
}
sub recurse_to_slaves {
my ( $self, $args, $level ) = @_;
$level ||= 0;
my $dp = $args->{dsn_parser};
my $dsn = $args->{dsn};
my $dp = $self->{DSNParser};
my $recurse = $args->{recurse} || $self->{OptionParser}->get('recurse');
my $dsn = $args->{dsn};
if ( lc($args->{method} || '') eq 'none' ) {
my $methods = $self->_resolve_recursion_methods($dsn);
PTDEBUG && _d('Recursion methods:', @$methods);
if ( lc($methods->[0]) eq 'none' ) {
PTDEBUG && _d('Not recursing to slaves');
return;
}
@@ -3547,11 +3592,11 @@ sub recurse_to_slaves {
$args->{callback}->($dsn, $dbh, $level, $args->{parent});
if ( !defined $args->{recurse} || $level < $args->{recurse} ) {
if ( !defined $recurse || $level < $recurse ) {
my @slaves =
grep { !$_->{master_id} || $_->{master_id} == $id } # Only my slaves.
$self->find_slave_hosts($dp, $dbh, $dsn, $args->{method});
$self->find_slave_hosts($dp, $dbh, $dsn, $methods);
foreach my $slave ( @slaves ) {
PTDEBUG && _d('Recursing from',
@@ -3563,25 +3608,14 @@ sub recurse_to_slaves {
}
sub find_slave_hosts {
my ( $self, $dsn_parser, $dbh, $dsn, $method ) = @_;
my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_;
my @methods = qw(processlist hosts);
if ( $method ) {
@methods = grep { $_ ne $method } @methods;
unshift @methods, $method;
}
else {
if ( ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
@methods = qw(hosts);
}
}
PTDEBUG && _d('Looking for slaves on', $dsn_parser->as_string($dsn),
'using methods', @methods);
'using methods', @$methods);
my @slaves;
METHOD:
foreach my $method ( @methods ) {
foreach my $method ( @$methods ) {
my $find_slaves = "_find_slaves_by_$method";
PTDEBUG && _d('Finding slaves with', $find_slaves);
@slaves = $self->$find_slaves($dsn_parser, $dbh, $dsn);
@@ -4084,13 +4118,16 @@ sub reset_known_replication_threads {
sub get_cxn_from_dsn_table {
my ($self, %args) = @_;
my @required_args = qw(dsn_table_dsn make_cxn DSNParser Quoter);
my @required_args = qw(dsn_table_dsn make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dsn_table_dsn, $make_cxn, $dp, $q) = @args{@required_args};
my ($dsn_table_dsn, $make_cxn) = @args{@required_args};
PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn);
my $dp = $self->{DSNParser};
my $q = $self->{Quoter};
my $dsn = $dp->parse($dsn_table_dsn);
my $dsn_table;
if ( $dsn->{D} && $dsn->{t} ) {
@@ -5909,6 +5946,13 @@ sub main {
}
}
eval {
MasterSlave::check_recursion_method($o->get('recursion-method'));
};
if ( $EVAL_ERROR ) {
$o->save_error("Invalid --recursion-method: $EVAL_ERROR")
}
$o->usage_or_errors();
if ( $o->get('quiet') ) {
@@ -6006,13 +6050,15 @@ sub main {
# #####################################################################
# Find and connect to slaves.
# #####################################################################
my $ms = new MasterSlave();
$slaves = $ms->get_slaves(
dbh => $cxn->dbh(),
dsn => $cxn->dsn(),
my $ms = new MasterSlave(
OptionParser => $o,
DSNParser => $dp,
Quoter => $q,
);
$slaves = $ms->get_slaves(
dbh => $cxn->dbh(),
dsn => $cxn->dsn(),
make_cxn => sub {
return $make_cxn->(@_, prev_dsn => $cxn->dsn());
},
@@ -8368,7 +8414,7 @@ Default is infinite. See also L<"--recursion-method">.
=item --recursion-method
type: string
type: array; default: processlist,hosts
Preferred recursion method for discovering replicas. Possible methods are:

View File

@@ -10339,8 +10339,31 @@ use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
sub check_recursion_method {
my ($methods) = @_;
if ( @$methods != 1 ) {
if ( grep({ !m/processlist|hosts/i } @$methods)
&& $methods->[0] !~ /^dsn=/i )
{
die "Invalid combination of recursion methods: "
. join(", ", map { defined($_) ? $_ : 'undef' } @$methods) . ". "
. "Only hosts and processlist may be combined.\n"
}
}
else {
my ($method) = @$methods;
die "Invalid recursion method: " . ( $method || 'undef' )
unless $method && $method =~ m/^(?:processlist$|hosts$|none$|dsn=)/i;
}
}
sub new {
my ( $class, %args ) = @_;
my @required_args = qw(OptionParser DSNParser Quoter);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my $self = {
%args,
replication_thread => {},
@@ -10350,28 +10373,27 @@ sub new {
sub get_slaves {
my ($self, %args) = @_;
my @required_args = qw(make_cxn OptionParser DSNParser Quoter);
my @required_args = qw(make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($make_cxn, $o, $dp) = @args{@required_args};
my ($make_cxn) = @args{@required_args};
my $slaves = [];
my $method = $o->get('recursion-method');
PTDEBUG && _d('Slave recursion method:', $method);
if ( !$method || $method =~ m/processlist|hosts/i ) {
my $slaves = [];
my $dp = $self->{DSNParser};
my $methods = $self->_resolve_recursion_methods($args{dsn});
if ( grep { m/processlist|hosts/i } @$methods ) {
my @required_args = qw(dbh dsn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dbh, $dsn) = @args{@required_args};
$self->recurse_to_slaves(
{ dbh => $dbh,
dsn => $dsn,
dsn_parser => $dp,
recurse => $o->get('recurse'),
method => $o->get('recursion-method'),
callback => sub {
{ dbh => $dbh,
dsn => $dsn,
callback => sub {
my ( $dsn, $dbh, $level, $parent ) = @_;
return unless $level;
PTDEBUG && _d('Found slave:', $dp->as_string($dsn));
@@ -10381,31 +10403,48 @@ sub get_slaves {
}
);
}
elsif ( $method =~ m/^dsn=/i ) {
my ($dsn_table_dsn) = $method =~ m/^dsn=(.+)/i;
elsif ( $methods->[0] =~ m/^dsn=/i ) {
(my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i;
$slaves = $self->get_cxn_from_dsn_table(
%args,
dsn_table_dsn => $dsn_table_dsn,
);
}
elsif ( $method =~ m/none/i ) {
elsif ( $methods->[0] =~ m/none/i ) {
PTDEBUG && _d('Not getting to slaves');
}
else {
die "Invalid --recursion-method: $method. Valid values are: "
. "dsn=DSN, hosts, or processlist.\n";
die "Unexpected recursion methods: @$methods";
}
return $slaves;
}
sub _resolve_recursion_methods {
my ($self, $dsn) = @_;
my $o = $self->{OptionParser};
if ( $o->got('recursion-method') ) {
return $o->get('recursion-method');
}
elsif ( $dsn && ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
return [qw(hosts)];
}
else {
return $o->get('recursion-method');
}
}
sub recurse_to_slaves {
my ( $self, $args, $level ) = @_;
$level ||= 0;
my $dp = $args->{dsn_parser};
my $dsn = $args->{dsn};
my $dp = $self->{DSNParser};
my $recurse = $args->{recurse} || $self->{OptionParser}->get('recurse');
my $dsn = $args->{dsn};
if ( lc($args->{method} || '') eq 'none' ) {
my $methods = $self->_resolve_recursion_methods($dsn);
PTDEBUG && _d('Recursion methods:', @$methods);
if ( lc($methods->[0]) eq 'none' ) {
PTDEBUG && _d('Not recursing to slaves');
return;
}
@@ -10440,11 +10479,11 @@ sub recurse_to_slaves {
$args->{callback}->($dsn, $dbh, $level, $args->{parent});
if ( !defined $args->{recurse} || $level < $args->{recurse} ) {
if ( !defined $recurse || $level < $recurse ) {
my @slaves =
grep { !$_->{master_id} || $_->{master_id} == $id } # Only my slaves.
$self->find_slave_hosts($dp, $dbh, $dsn, $args->{method});
$self->find_slave_hosts($dp, $dbh, $dsn, $methods);
foreach my $slave ( @slaves ) {
PTDEBUG && _d('Recursing from',
@@ -10456,25 +10495,14 @@ sub recurse_to_slaves {
}
sub find_slave_hosts {
my ( $self, $dsn_parser, $dbh, $dsn, $method ) = @_;
my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_;
my @methods = qw(processlist hosts);
if ( $method ) {
@methods = grep { $_ ne $method } @methods;
unshift @methods, $method;
}
else {
if ( ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
@methods = qw(hosts);
}
}
PTDEBUG && _d('Looking for slaves on', $dsn_parser->as_string($dsn),
'using methods', @methods);
'using methods', @$methods);
my @slaves;
METHOD:
foreach my $method ( @methods ) {
foreach my $method ( @$methods ) {
my $find_slaves = "_find_slaves_by_$method";
PTDEBUG && _d('Finding slaves with', $find_slaves);
@slaves = $self->$find_slaves($dsn_parser, $dbh, $dsn);
@@ -10977,13 +11005,16 @@ sub reset_known_replication_threads {
sub get_cxn_from_dsn_table {
my ($self, %args) = @_;
my @required_args = qw(dsn_table_dsn make_cxn DSNParser Quoter);
my @required_args = qw(dsn_table_dsn make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dsn_table_dsn, $make_cxn, $dp, $q) = @args{@required_args};
my ($dsn_table_dsn, $make_cxn) = @args{@required_args};
PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn);
my $dp = $self->{DSNParser};
my $q = $self->{Quoter};
my $dsn = $dp->parse($dsn_table_dsn);
my $dsn_table;
if ( $dsn->{D} && $dsn->{t} ) {
@@ -12195,7 +12226,11 @@ sub main {
{ # event
my $misc;
if ( my $ps_dsn = $o->get('processlist') ) {
my $ms = new MasterSlave();
my $ms = new MasterSlave(
OptionParser => $o,
DSNParser => $dp,
Quoter => $q,
);
my $pl = new Processlist(
interval => $o->get('interval') * 1_000_000,
MasterSlave => $ms

View File

@@ -1741,7 +1741,7 @@ sub get_dbh {
PTDEBUG && _d($dbh, $sql);
my ($sql_mode) = eval { $dbh->selectrow_array($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error getting the current SQL_MODE: $EVAL_ERROR";
}
$sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
@@ -1751,15 +1751,17 @@ sub get_dbh {
PTDEBUG && _d($dbh, $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting SQL_QUOTE_SHOW_CREATE, SQL_MODE"
. ($sql_mode ? " and $sql_mode" : '')
. ": $EVAL_ERROR";
}
if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
$sql = "/*!40101 SET NAMES $charset*/";
if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) {
$sql = qq{/*!40101 SET NAMES "$charset"*/};
PTDEBUG && _d($dbh, ':', $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting NAMES to $charset: $EVAL_ERROR";
}
PTDEBUG && _d('Enabling charset for STDOUT');
if ( $charset eq 'utf8' ) {
@@ -1771,12 +1773,12 @@ sub get_dbh {
}
}
if ( $self->prop('set-vars') ) {
$sql = "SET " . $self->prop('set-vars');
if ( my $var = $self->prop('set-vars') ) {
$sql = "SET $var";
PTDEBUG && _d($dbh, ':', $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting $var: $EVAL_ERROR";
}
}
}
@@ -1870,8 +1872,31 @@ use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
sub check_recursion_method {
my ($methods) = @_;
if ( @$methods != 1 ) {
if ( grep({ !m/processlist|hosts/i } @$methods)
&& $methods->[0] !~ /^dsn=/i )
{
die "Invalid combination of recursion methods: "
. join(", ", map { defined($_) ? $_ : 'undef' } @$methods) . ". "
. "Only hosts and processlist may be combined.\n"
}
}
else {
my ($method) = @$methods;
die "Invalid recursion method: " . ( $method || 'undef' )
unless $method && $method =~ m/^(?:processlist$|hosts$|none$|dsn=)/i;
}
}
sub new {
my ( $class, %args ) = @_;
my @required_args = qw(OptionParser DSNParser Quoter);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my $self = {
%args,
replication_thread => {},
@@ -1881,28 +1906,27 @@ sub new {
sub get_slaves {
my ($self, %args) = @_;
my @required_args = qw(make_cxn OptionParser DSNParser Quoter);
my @required_args = qw(make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($make_cxn, $o, $dp) = @args{@required_args};
my ($make_cxn) = @args{@required_args};
my $slaves = [];
my $method = $o->get('recursion-method');
PTDEBUG && _d('Slave recursion method:', $method);
if ( !$method || $method =~ m/processlist|hosts/i ) {
my $slaves = [];
my $dp = $self->{DSNParser};
my $methods = $self->_resolve_recursion_methods($args{dsn});
if ( grep { m/processlist|hosts/i } @$methods ) {
my @required_args = qw(dbh dsn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dbh, $dsn) = @args{@required_args};
$self->recurse_to_slaves(
{ dbh => $dbh,
dsn => $dsn,
dsn_parser => $dp,
recurse => $o->get('recurse'),
method => $o->get('recursion-method'),
callback => sub {
{ dbh => $dbh,
dsn => $dsn,
callback => sub {
my ( $dsn, $dbh, $level, $parent ) = @_;
return unless $level;
PTDEBUG && _d('Found slave:', $dp->as_string($dsn));
@@ -1912,31 +1936,48 @@ sub get_slaves {
}
);
}
elsif ( $method =~ m/^dsn=/i ) {
my ($dsn_table_dsn) = $method =~ m/^dsn=(.+)/i;
elsif ( $methods->[0] =~ m/^dsn=/i ) {
(my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i;
$slaves = $self->get_cxn_from_dsn_table(
%args,
dsn_table_dsn => $dsn_table_dsn,
);
}
elsif ( $method =~ m/none/i ) {
elsif ( $methods->[0] =~ m/none/i ) {
PTDEBUG && _d('Not getting to slaves');
}
else {
die "Invalid --recursion-method: $method. Valid values are: "
. "dsn=DSN, hosts, or processlist.\n";
die "Unexpected recursion methods: @$methods";
}
return $slaves;
}
sub _resolve_recursion_methods {
my ($self, $dsn) = @_;
my $o = $self->{OptionParser};
if ( $o->got('recursion-method') ) {
return $o->get('recursion-method');
}
elsif ( $dsn && ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
return [qw(hosts)];
}
else {
return $o->get('recursion-method');
}
}
sub recurse_to_slaves {
my ( $self, $args, $level ) = @_;
$level ||= 0;
my $dp = $args->{dsn_parser};
my $dsn = $args->{dsn};
my $dp = $self->{DSNParser};
my $recurse = $args->{recurse} || $self->{OptionParser}->get('recurse');
my $dsn = $args->{dsn};
if ( lc($args->{method} || '') eq 'none' ) {
my $methods = $self->_resolve_recursion_methods($dsn);
PTDEBUG && _d('Recursion methods:', @$methods);
if ( lc($methods->[0]) eq 'none' ) {
PTDEBUG && _d('Not recursing to slaves');
return;
}
@@ -1971,11 +2012,11 @@ sub recurse_to_slaves {
$args->{callback}->($dsn, $dbh, $level, $args->{parent});
if ( !defined $args->{recurse} || $level < $args->{recurse} ) {
if ( !defined $recurse || $level < $recurse ) {
my @slaves =
grep { !$_->{master_id} || $_->{master_id} == $id } # Only my slaves.
$self->find_slave_hosts($dp, $dbh, $dsn, $args->{method});
$self->find_slave_hosts($dp, $dbh, $dsn, $methods);
foreach my $slave ( @slaves ) {
PTDEBUG && _d('Recursing from',
@@ -1987,25 +2028,14 @@ sub recurse_to_slaves {
}
sub find_slave_hosts {
my ( $self, $dsn_parser, $dbh, $dsn, $method ) = @_;
my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_;
my @methods = qw(processlist hosts);
if ( $method ) {
@methods = grep { $_ ne $method } @methods;
unshift @methods, $method;
}
else {
if ( ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
@methods = qw(hosts);
}
}
PTDEBUG && _d('Looking for slaves on', $dsn_parser->as_string($dsn),
'using methods', @methods);
'using methods', @$methods);
my @slaves;
METHOD:
foreach my $method ( @methods ) {
foreach my $method ( @$methods ) {
my $find_slaves = "_find_slaves_by_$method";
PTDEBUG && _d('Finding slaves with', $find_slaves);
@slaves = $self->$find_slaves($dsn_parser, $dbh, $dsn);
@@ -2508,13 +2538,16 @@ sub reset_known_replication_threads {
sub get_cxn_from_dsn_table {
my ($self, %args) = @_;
my @required_args = qw(dsn_table_dsn make_cxn DSNParser Quoter);
my @required_args = qw(dsn_table_dsn make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dsn_table_dsn, $make_cxn, $dp, $q) = @args{@required_args};
my ($dsn_table_dsn, $make_cxn) = @args{@required_args};
PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn);
my $dp = $self->{DSNParser};
my $q = $self->{Quoter};
my $dsn = $dp->parse($dsn_table_dsn);
my $dsn_table;
if ( $dsn->{D} && $dsn->{t} ) {
@@ -3330,6 +3363,13 @@ sub main {
$o->save_error("Missing or invalid master host");
}
eval {
MasterSlave::check_recursion_method($o->get('recursion-method'));
};
if ( $EVAL_ERROR ) {
$o->save_error("Invalid --recursion-method: $EVAL_ERROR")
}
$o->usage_or_errors();
# ########################################################################
@@ -3355,14 +3395,15 @@ sub main {
# Despite the name, recursing to slaves actually begins at the specified
# server, so the named server may also be included.
my $ms = new MasterSlave();
my $ms = new MasterSlave(
OptionParser => $o,
DSNParser => $dp,
Quoter => "Quoter",
);
$ms->recurse_to_slaves(
{ dbh => $dbh,
dsn => $master_dsn,
dsn_parser => $dp,
recurse => $o->get('recurse'),
method => $o->get('recursion-method'),
callback => sub {
{ dbh => $dbh,
dsn => $master_dsn,
callback => sub {
my ( $dsn, $dbh, $level, $parent ) = @_;
if ( !$parent ) {
$root = $dsn;
@@ -3710,7 +3751,7 @@ See L<"--recursion-method">.
=item --recursion-method
type: string
type: array; default: processlist,hosts
Preferred recursion method used to find slaves.

View File

@@ -2054,7 +2054,7 @@ sub get_dbh {
PTDEBUG && _d($dbh, $sql);
my ($sql_mode) = eval { $dbh->selectrow_array($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error getting the current SQL_MODE: $EVAL_ERROR";
}
$sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
@@ -2064,15 +2064,17 @@ sub get_dbh {
PTDEBUG && _d($dbh, $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting SQL_QUOTE_SHOW_CREATE, SQL_MODE"
. ($sql_mode ? " and $sql_mode" : '')
. ": $EVAL_ERROR";
}
if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
$sql = "/*!40101 SET NAMES $charset*/";
if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) {
$sql = qq{/*!40101 SET NAMES "$charset"*/};
PTDEBUG && _d($dbh, ':', $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting NAMES to $charset: $EVAL_ERROR";
}
PTDEBUG && _d('Enabling charset for STDOUT');
if ( $charset eq 'utf8' ) {
@@ -2084,12 +2086,12 @@ sub get_dbh {
}
}
if ( $self->prop('set-vars') ) {
$sql = "SET " . $self->prop('set-vars');
if ( my $var = $self->prop('set-vars') ) {
$sql = "SET $var";
PTDEBUG && _d($dbh, ':', $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting $var: $EVAL_ERROR";
}
}
}
@@ -2183,8 +2185,31 @@ use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
sub check_recursion_method {
my ($methods) = @_;
if ( @$methods != 1 ) {
if ( grep({ !m/processlist|hosts/i } @$methods)
&& $methods->[0] !~ /^dsn=/i )
{
die "Invalid combination of recursion methods: "
. join(", ", map { defined($_) ? $_ : 'undef' } @$methods) . ". "
. "Only hosts and processlist may be combined.\n"
}
}
else {
my ($method) = @$methods;
die "Invalid recursion method: " . ( $method || 'undef' )
unless $method && $method =~ m/^(?:processlist$|hosts$|none$|dsn=)/i;
}
}
sub new {
my ( $class, %args ) = @_;
my @required_args = qw(OptionParser DSNParser Quoter);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my $self = {
%args,
replication_thread => {},
@@ -2194,28 +2219,27 @@ sub new {
sub get_slaves {
my ($self, %args) = @_;
my @required_args = qw(make_cxn OptionParser DSNParser Quoter);
my @required_args = qw(make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($make_cxn, $o, $dp) = @args{@required_args};
my ($make_cxn) = @args{@required_args};
my $slaves = [];
my $method = $o->get('recursion-method');
PTDEBUG && _d('Slave recursion method:', $method);
if ( !$method || $method =~ m/processlist|hosts/i ) {
my $slaves = [];
my $dp = $self->{DSNParser};
my $methods = $self->_resolve_recursion_methods($args{dsn});
if ( grep { m/processlist|hosts/i } @$methods ) {
my @required_args = qw(dbh dsn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dbh, $dsn) = @args{@required_args};
$self->recurse_to_slaves(
{ dbh => $dbh,
dsn => $dsn,
dsn_parser => $dp,
recurse => $o->get('recurse'),
method => $o->get('recursion-method'),
callback => sub {
{ dbh => $dbh,
dsn => $dsn,
callback => sub {
my ( $dsn, $dbh, $level, $parent ) = @_;
return unless $level;
PTDEBUG && _d('Found slave:', $dp->as_string($dsn));
@@ -2225,31 +2249,48 @@ sub get_slaves {
}
);
}
elsif ( $method =~ m/^dsn=/i ) {
my ($dsn_table_dsn) = $method =~ m/^dsn=(.+)/i;
elsif ( $methods->[0] =~ m/^dsn=/i ) {
(my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i;
$slaves = $self->get_cxn_from_dsn_table(
%args,
dsn_table_dsn => $dsn_table_dsn,
);
}
elsif ( $method =~ m/none/i ) {
elsif ( $methods->[0] =~ m/none/i ) {
PTDEBUG && _d('Not getting to slaves');
}
else {
die "Invalid --recursion-method: $method. Valid values are: "
. "dsn=DSN, hosts, or processlist.\n";
die "Unexpected recursion methods: @$methods";
}
return $slaves;
}
sub _resolve_recursion_methods {
my ($self, $dsn) = @_;
my $o = $self->{OptionParser};
if ( $o->got('recursion-method') ) {
return $o->get('recursion-method');
}
elsif ( $dsn && ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
return [qw(hosts)];
}
else {
return $o->get('recursion-method');
}
}
sub recurse_to_slaves {
my ( $self, $args, $level ) = @_;
$level ||= 0;
my $dp = $args->{dsn_parser};
my $dsn = $args->{dsn};
my $dp = $self->{DSNParser};
my $recurse = $args->{recurse} || $self->{OptionParser}->get('recurse');
my $dsn = $args->{dsn};
if ( lc($args->{method} || '') eq 'none' ) {
my $methods = $self->_resolve_recursion_methods($dsn);
PTDEBUG && _d('Recursion methods:', @$methods);
if ( lc($methods->[0]) eq 'none' ) {
PTDEBUG && _d('Not recursing to slaves');
return;
}
@@ -2284,11 +2325,11 @@ sub recurse_to_slaves {
$args->{callback}->($dsn, $dbh, $level, $args->{parent});
if ( !defined $args->{recurse} || $level < $args->{recurse} ) {
if ( !defined $recurse || $level < $recurse ) {
my @slaves =
grep { !$_->{master_id} || $_->{master_id} == $id } # Only my slaves.
$self->find_slave_hosts($dp, $dbh, $dsn, $args->{method});
$self->find_slave_hosts($dp, $dbh, $dsn, $methods);
foreach my $slave ( @slaves ) {
PTDEBUG && _d('Recursing from',
@@ -2300,25 +2341,14 @@ sub recurse_to_slaves {
}
sub find_slave_hosts {
my ( $self, $dsn_parser, $dbh, $dsn, $method ) = @_;
my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_;
my @methods = qw(processlist hosts);
if ( $method ) {
@methods = grep { $_ ne $method } @methods;
unshift @methods, $method;
}
else {
if ( ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
@methods = qw(hosts);
}
}
PTDEBUG && _d('Looking for slaves on', $dsn_parser->as_string($dsn),
'using methods', @methods);
'using methods', @$methods);
my @slaves;
METHOD:
foreach my $method ( @methods ) {
foreach my $method ( @$methods ) {
my $find_slaves = "_find_slaves_by_$method";
PTDEBUG && _d('Finding slaves with', $find_slaves);
@slaves = $self->$find_slaves($dsn_parser, $dbh, $dsn);
@@ -2821,13 +2851,16 @@ sub reset_known_replication_threads {
sub get_cxn_from_dsn_table {
my ($self, %args) = @_;
my @required_args = qw(dsn_table_dsn make_cxn DSNParser Quoter);
my @required_args = qw(dsn_table_dsn make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dsn_table_dsn, $make_cxn, $dp, $q) = @args{@required_args};
my ($dsn_table_dsn, $make_cxn) = @args{@required_args};
PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn);
my $dp = $self->{DSNParser};
my $q = $self->{Quoter};
my $dsn = $dp->parse($dsn_table_dsn);
my $dsn_table;
if ( $dsn->{D} && $dsn->{t} ) {
@@ -3113,6 +3146,13 @@ sub main {
}
}
eval {
MasterSlave::check_recursion_method($o->get('recursion-method'));
};
if ( $EVAL_ERROR ) {
$o->save_error("Invalid --recursion-method: $EVAL_ERROR")
}
$o->usage_or_errors();
# ########################################################################
@@ -3178,13 +3218,15 @@ sub main {
# Despite the name, recursing to slaves actually begins at the specified
# server, so the named server may also be watched, if it's a slave.
my $ms = new MasterSlave();
my $ms = new MasterSlave(
OptionParser => $o,
DSNParser => $dp,
Quoter => $q,
);
$ms->recurse_to_slaves(
{ dbh => $dbh,
dsn => $dsn,
dsn_parser => $dp,
recurse => $o->get('recurse') || 0,
callback => sub {
{ dbh => $dbh,
dsn => $dsn,
callback => sub {
my ( $dsn, $dbh, $level ) = @_;
# Test whether we want to watch this server.
eval {
@@ -3206,7 +3248,6 @@ sub main {
my ( $dsn, $dbh, $level ) = @_;
print STDERR "Skipping ", $dp->as_string($dsn), "\n";
},
method => $o->get('recursion-method'),
}
);
@@ -3792,7 +3833,7 @@ password.
=item --recursion-method
type: string
type: array; default: processlist,hosts
Preferred recursion method used to find slaves.

View File

@@ -266,7 +266,7 @@ sub get_dbh {
PTDEBUG && _d($dbh, $sql);
my ($sql_mode) = eval { $dbh->selectrow_array($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error getting the current SQL_MODE: $EVAL_ERROR";
}
$sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
@@ -276,15 +276,17 @@ sub get_dbh {
PTDEBUG && _d($dbh, $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting SQL_QUOTE_SHOW_CREATE, SQL_MODE"
. ($sql_mode ? " and $sql_mode" : '')
. ": $EVAL_ERROR";
}
if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
$sql = "/*!40101 SET NAMES $charset*/";
if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) {
$sql = qq{/*!40101 SET NAMES "$charset"*/};
PTDEBUG && _d($dbh, ':', $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting NAMES to $charset: $EVAL_ERROR";
}
PTDEBUG && _d('Enabling charset for STDOUT');
if ( $charset eq 'utf8' ) {
@@ -296,12 +298,12 @@ sub get_dbh {
}
}
if ( $self->prop('set-vars') ) {
$sql = "SET " . $self->prop('set-vars');
if ( my $var = $self->prop('set-vars') ) {
$sql = "SET $var";
PTDEBUG && _d($dbh, ':', $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting $var: $EVAL_ERROR";
}
}
}
@@ -1901,6 +1903,7 @@ sub new {
dsn_name => $dp->as_string($dsn, [qw(h P S)]),
hostname => '',
set => $args{set},
NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1,
dbh_set => 0,
OptionParser => $o,
DSNParser => $dp,
@@ -1938,7 +1941,10 @@ sub set_dbh {
PTDEBUG && _d($dbh, 'Setting dbh');
$dbh->{FetchHashKeyName} = 'NAME_lc';
if ( !exists $self->{NAME_lc}
|| (defined $self->{NAME_lc} && $self->{NAME_lc}) ) {
$dbh->{FetchHashKeyName} = 'NAME_lc';
}
my $sql = 'SELECT @@hostname, @@server_id';
PTDEBUG && _d($dbh, $sql);
@@ -3030,8 +3036,31 @@ use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
sub check_recursion_method {
my ($methods) = @_;
if ( @$methods != 1 ) {
if ( grep({ !m/processlist|hosts/i } @$methods)
&& $methods->[0] !~ /^dsn=/i )
{
die "Invalid combination of recursion methods: "
. join(", ", map { defined($_) ? $_ : 'undef' } @$methods) . ". "
. "Only hosts and processlist may be combined.\n"
}
}
else {
my ($method) = @$methods;
die "Invalid recursion method: " . ( $method || 'undef' )
unless $method && $method =~ m/^(?:processlist$|hosts$|none$|dsn=)/i;
}
}
sub new {
my ( $class, %args ) = @_;
my @required_args = qw(OptionParser DSNParser Quoter);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my $self = {
%args,
replication_thread => {},
@@ -3041,28 +3070,27 @@ sub new {
sub get_slaves {
my ($self, %args) = @_;
my @required_args = qw(make_cxn OptionParser DSNParser Quoter);
my @required_args = qw(make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($make_cxn, $o, $dp) = @args{@required_args};
my ($make_cxn) = @args{@required_args};
my $slaves = [];
my $method = $o->get('recursion-method');
PTDEBUG && _d('Slave recursion method:', $method);
if ( !$method || $method =~ m/processlist|hosts/i ) {
my $slaves = [];
my $dp = $self->{DSNParser};
my $methods = $self->_resolve_recursion_methods($args{dsn});
if ( grep { m/processlist|hosts/i } @$methods ) {
my @required_args = qw(dbh dsn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dbh, $dsn) = @args{@required_args};
$self->recurse_to_slaves(
{ dbh => $dbh,
dsn => $dsn,
dsn_parser => $dp,
recurse => $o->get('recurse'),
method => $o->get('recursion-method'),
callback => sub {
{ dbh => $dbh,
dsn => $dsn,
callback => sub {
my ( $dsn, $dbh, $level, $parent ) = @_;
return unless $level;
PTDEBUG && _d('Found slave:', $dp->as_string($dsn));
@@ -3072,31 +3100,48 @@ sub get_slaves {
}
);
}
elsif ( $method =~ m/^dsn=/i ) {
my ($dsn_table_dsn) = $method =~ m/^dsn=(.+)/i;
elsif ( $methods->[0] =~ m/^dsn=/i ) {
(my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i;
$slaves = $self->get_cxn_from_dsn_table(
%args,
dsn_table_dsn => $dsn_table_dsn,
);
}
elsif ( $method =~ m/none/i ) {
elsif ( $methods->[0] =~ m/none/i ) {
PTDEBUG && _d('Not getting to slaves');
}
else {
die "Invalid --recursion-method: $method. Valid values are: "
. "dsn=DSN, hosts, or processlist.\n";
die "Unexpected recursion methods: @$methods";
}
return $slaves;
}
sub _resolve_recursion_methods {
my ($self, $dsn) = @_;
my $o = $self->{OptionParser};
if ( $o->got('recursion-method') ) {
return $o->get('recursion-method');
}
elsif ( $dsn && ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
return [qw(hosts)];
}
else {
return $o->get('recursion-method');
}
}
sub recurse_to_slaves {
my ( $self, $args, $level ) = @_;
$level ||= 0;
my $dp = $args->{dsn_parser};
my $dsn = $args->{dsn};
my $dp = $self->{DSNParser};
my $recurse = $args->{recurse} || $self->{OptionParser}->get('recurse');
my $dsn = $args->{dsn};
if ( lc($args->{method} || '') eq 'none' ) {
my $methods = $self->_resolve_recursion_methods($dsn);
PTDEBUG && _d('Recursion methods:', @$methods);
if ( lc($methods->[0]) eq 'none' ) {
PTDEBUG && _d('Not recursing to slaves');
return;
}
@@ -3131,11 +3176,11 @@ sub recurse_to_slaves {
$args->{callback}->($dsn, $dbh, $level, $args->{parent});
if ( !defined $args->{recurse} || $level < $args->{recurse} ) {
if ( !defined $recurse || $level < $recurse ) {
my @slaves =
grep { !$_->{master_id} || $_->{master_id} == $id } # Only my slaves.
$self->find_slave_hosts($dp, $dbh, $dsn, $args->{method});
$self->find_slave_hosts($dp, $dbh, $dsn, $methods);
foreach my $slave ( @slaves ) {
PTDEBUG && _d('Recursing from',
@@ -3147,25 +3192,14 @@ sub recurse_to_slaves {
}
sub find_slave_hosts {
my ( $self, $dsn_parser, $dbh, $dsn, $method ) = @_;
my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_;
my @methods = qw(processlist hosts);
if ( $method ) {
@methods = grep { $_ ne $method } @methods;
unshift @methods, $method;
}
else {
if ( ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
@methods = qw(hosts);
}
}
PTDEBUG && _d('Looking for slaves on', $dsn_parser->as_string($dsn),
'using methods', @methods);
'using methods', @$methods);
my @slaves;
METHOD:
foreach my $method ( @methods ) {
foreach my $method ( @$methods ) {
my $find_slaves = "_find_slaves_by_$method";
PTDEBUG && _d('Finding slaves with', $find_slaves);
@slaves = $self->$find_slaves($dsn_parser, $dbh, $dsn);
@@ -3668,13 +3702,16 @@ sub reset_known_replication_threads {
sub get_cxn_from_dsn_table {
my ($self, %args) = @_;
my @required_args = qw(dsn_table_dsn make_cxn DSNParser Quoter);
my @required_args = qw(dsn_table_dsn make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dsn_table_dsn, $make_cxn, $dp, $q) = @args{@required_args};
my ($dsn_table_dsn, $make_cxn) = @args{@required_args};
PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn);
my $dp = $self->{DSNParser};
my $q = $self->{Quoter};
my $dsn = $dp->parse($dsn_table_dsn);
my $dsn_table;
if ( $dsn->{D} && $dsn->{t} ) {
@@ -6856,6 +6893,13 @@ sub main {
}
}
eval {
MasterSlave::check_recursion_method($o->get('recursion-method'));
};
if ( $EVAL_ERROR ) {
$o->save_error("Invalid --recursion-method: $EVAL_ERROR")
}
$o->usage_or_errors();
# ########################################################################
@@ -7006,7 +7050,11 @@ sub main {
my $q = new Quoter();
my $tp = new TableParser(Quoter => $q);
my $rc = new RowChecksum(Quoter=> $q, OptionParser => $o);
my $ms = new MasterSlave();
my $ms = new MasterSlave(
OptionParser => $o,
DSNParser => $dp,
Quoter => $q,
);
my $slaves; # all slaves (that we can find)
my $slave_lag_cxns; # slaves whose lag we'll check
@@ -7026,12 +7074,9 @@ sub main {
# Find and connect to slaves.
# #####################################################################
$slaves = $ms->get_slaves(
dbh => $master_dbh,
dsn => $master_dsn,
OptionParser => $o,
DSNParser => $dp,
Quoter => $q,
make_cxn => sub {
dbh => $master_dbh,
dsn => $master_dsn,
make_cxn => sub {
return $make_cxn->(@_, prev_dsn => $master_cxn->dsn());
},
);
@@ -9347,7 +9392,7 @@ Default is infinite. See also L<"--recursion-method">.
=item --recursion-method
type: string
type: array; default: processlist,hosts
Preferred recursion method for discovering replicas. Possible methods are:

View File

@@ -1860,7 +1860,7 @@ sub get_dbh {
PTDEBUG && _d($dbh, $sql);
my ($sql_mode) = eval { $dbh->selectrow_array($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error getting the current SQL_MODE: $EVAL_ERROR";
}
$sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1'
@@ -1870,15 +1870,17 @@ sub get_dbh {
PTDEBUG && _d($dbh, $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting SQL_QUOTE_SHOW_CREATE, SQL_MODE"
. ($sql_mode ? " and $sql_mode" : '')
. ": $EVAL_ERROR";
}
if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
$sql = "/*!40101 SET NAMES $charset*/";
if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) {
$sql = qq{/*!40101 SET NAMES "$charset"*/};
PTDEBUG && _d($dbh, ':', $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting NAMES to $charset: $EVAL_ERROR";
}
PTDEBUG && _d('Enabling charset for STDOUT');
if ( $charset eq 'utf8' ) {
@@ -1890,12 +1892,12 @@ sub get_dbh {
}
}
if ( $self->prop('set-vars') ) {
$sql = "SET " . $self->prop('set-vars');
if ( my $var = $self->prop('set-vars') ) {
$sql = "SET $var";
PTDEBUG && _d($dbh, ':', $sql);
eval { $dbh->do($sql) };
if ( $EVAL_ERROR ) {
die $EVAL_ERROR;
die "Error setting $var: $EVAL_ERROR";
}
}
}
@@ -6454,8 +6456,31 @@ use warnings FATAL => 'all';
use English qw(-no_match_vars);
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
sub check_recursion_method {
my ($methods) = @_;
if ( @$methods != 1 ) {
if ( grep({ !m/processlist|hosts/i } @$methods)
&& $methods->[0] !~ /^dsn=/i )
{
die "Invalid combination of recursion methods: "
. join(", ", map { defined($_) ? $_ : 'undef' } @$methods) . ". "
. "Only hosts and processlist may be combined.\n"
}
}
else {
my ($method) = @$methods;
die "Invalid recursion method: " . ( $method || 'undef' )
unless $method && $method =~ m/^(?:processlist$|hosts$|none$|dsn=)/i;
}
}
sub new {
my ( $class, %args ) = @_;
my @required_args = qw(OptionParser DSNParser Quoter);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my $self = {
%args,
replication_thread => {},
@@ -6465,28 +6490,27 @@ sub new {
sub get_slaves {
my ($self, %args) = @_;
my @required_args = qw(make_cxn OptionParser DSNParser Quoter);
my @required_args = qw(make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($make_cxn, $o, $dp) = @args{@required_args};
my ($make_cxn) = @args{@required_args};
my $slaves = [];
my $method = $o->get('recursion-method');
PTDEBUG && _d('Slave recursion method:', $method);
if ( !$method || $method =~ m/processlist|hosts/i ) {
my $slaves = [];
my $dp = $self->{DSNParser};
my $methods = $self->_resolve_recursion_methods($args{dsn});
if ( grep { m/processlist|hosts/i } @$methods ) {
my @required_args = qw(dbh dsn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dbh, $dsn) = @args{@required_args};
$self->recurse_to_slaves(
{ dbh => $dbh,
dsn => $dsn,
dsn_parser => $dp,
recurse => $o->get('recurse'),
method => $o->get('recursion-method'),
callback => sub {
{ dbh => $dbh,
dsn => $dsn,
callback => sub {
my ( $dsn, $dbh, $level, $parent ) = @_;
return unless $level;
PTDEBUG && _d('Found slave:', $dp->as_string($dsn));
@@ -6496,31 +6520,48 @@ sub get_slaves {
}
);
}
elsif ( $method =~ m/^dsn=/i ) {
my ($dsn_table_dsn) = $method =~ m/^dsn=(.+)/i;
elsif ( $methods->[0] =~ m/^dsn=/i ) {
(my $dsn_table_dsn = join ",", @$methods) =~ s/^dsn=//i;
$slaves = $self->get_cxn_from_dsn_table(
%args,
dsn_table_dsn => $dsn_table_dsn,
);
}
elsif ( $method =~ m/none/i ) {
elsif ( $methods->[0] =~ m/none/i ) {
PTDEBUG && _d('Not getting to slaves');
}
else {
die "Invalid --recursion-method: $method. Valid values are: "
. "dsn=DSN, hosts, or processlist.\n";
die "Unexpected recursion methods: @$methods";
}
return $slaves;
}
sub _resolve_recursion_methods {
my ($self, $dsn) = @_;
my $o = $self->{OptionParser};
if ( $o->got('recursion-method') ) {
return $o->get('recursion-method');
}
elsif ( $dsn && ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
return [qw(hosts)];
}
else {
return $o->get('recursion-method');
}
}
sub recurse_to_slaves {
my ( $self, $args, $level ) = @_;
$level ||= 0;
my $dp = $args->{dsn_parser};
my $dsn = $args->{dsn};
my $dp = $self->{DSNParser};
my $recurse = $args->{recurse} || $self->{OptionParser}->get('recurse');
my $dsn = $args->{dsn};
if ( lc($args->{method} || '') eq 'none' ) {
my $methods = $self->_resolve_recursion_methods($dsn);
PTDEBUG && _d('Recursion methods:', @$methods);
if ( lc($methods->[0]) eq 'none' ) {
PTDEBUG && _d('Not recursing to slaves');
return;
}
@@ -6555,11 +6596,11 @@ sub recurse_to_slaves {
$args->{callback}->($dsn, $dbh, $level, $args->{parent});
if ( !defined $args->{recurse} || $level < $args->{recurse} ) {
if ( !defined $recurse || $level < $recurse ) {
my @slaves =
grep { !$_->{master_id} || $_->{master_id} == $id } # Only my slaves.
$self->find_slave_hosts($dp, $dbh, $dsn, $args->{method});
$self->find_slave_hosts($dp, $dbh, $dsn, $methods);
foreach my $slave ( @slaves ) {
PTDEBUG && _d('Recursing from',
@@ -6571,25 +6612,14 @@ sub recurse_to_slaves {
}
sub find_slave_hosts {
my ( $self, $dsn_parser, $dbh, $dsn, $method ) = @_;
my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_;
my @methods = qw(processlist hosts);
if ( $method ) {
@methods = grep { $_ ne $method } @methods;
unshift @methods, $method;
}
else {
if ( ($dsn->{P} || 3306) != 3306 ) {
PTDEBUG && _d('Port number is non-standard; using only hosts method');
@methods = qw(hosts);
}
}
PTDEBUG && _d('Looking for slaves on', $dsn_parser->as_string($dsn),
'using methods', @methods);
'using methods', @$methods);
my @slaves;
METHOD:
foreach my $method ( @methods ) {
foreach my $method ( @$methods ) {
my $find_slaves = "_find_slaves_by_$method";
PTDEBUG && _d('Finding slaves with', $find_slaves);
@slaves = $self->$find_slaves($dsn_parser, $dbh, $dsn);
@@ -7092,13 +7122,16 @@ sub reset_known_replication_threads {
sub get_cxn_from_dsn_table {
my ($self, %args) = @_;
my @required_args = qw(dsn_table_dsn make_cxn DSNParser Quoter);
my @required_args = qw(dsn_table_dsn make_cxn);
foreach my $arg ( @required_args ) {
die "I need a $arg argument" unless $args{$arg};
}
my ($dsn_table_dsn, $make_cxn, $dp, $q) = @args{@required_args};
my ($dsn_table_dsn, $make_cxn) = @args{@required_args};
PTDEBUG && _d('DSN table DSN:', $dsn_table_dsn);
my $dp = $self->{DSNParser};
my $q = $self->{Quoter};
my $dsn = $dp->parse($dsn_table_dsn);
my $dsn_table;
if ( $dsn->{D} && $dsn->{t} ) {
@@ -8320,6 +8353,13 @@ sub main {
return 0;
}
eval {
MasterSlave::check_recursion_method($o->get('recursion-method'));
};
if ( $EVAL_ERROR ) {
$o->save_error("Invalid --recursion-method: $EVAL_ERROR")
}
$o->usage_or_errors();
# ########################################################################
@@ -8338,7 +8378,7 @@ sub main {
# Do the work.
# ########################################################################
my $tp = new TableParser( Quoter => $q );
my $ms = new MasterSlave();
my $ms = new MasterSlave(OptionParser=>$o,DSNParser=>$dp,Quoter=>$q);
my $du = new MySQLDump( cache => 0 );
my $rt = new Retry();
my $chunker = new TableChunker( Quoter => $q, TableParser => $tp );
@@ -8736,11 +8776,10 @@ sub sync_via_replication {
# then sync them.
else {
$ms->recurse_to_slaves(
{ dbh => $src->{dbh},
dsn => $src->{dsn},
dsn_parser => $dp,
recurse => 1,
callback => sub {
{ dbh => $src->{dbh},
dsn => $src->{dsn},
recurse => 1,
callback => sub {
my ( $dsn, $dbh, $level, $parent ) = @_;
my $all_diffs = $checksum->find_replication_differences(
$dbh, $o->get('replicate'));
@@ -8809,7 +8848,6 @@ sub sync_via_replication {
return;
}, # recurse_to_slaves() callback
method => $o->get('recursion-method'),
},
);
} # DSN is master
@@ -10767,7 +10805,7 @@ yourself if you want to sync the tables manually.
=item --recursion-method
type: string
type: array; default: processlist,hosts
Preferred recursion method used to find slaves.