mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-28 08:51:44 +00:00
Merge fix-953141-recursion-method-array
This commit is contained in:
115
bin/pt-archiver
115
bin/pt-archiver
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
# ########################################################################
|
||||
|
151
bin/pt-heartbeat
151
bin/pt-heartbeat
@@ -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.
|
||||
|
||||
|
121
bin/pt-kill
121
bin/pt-kill
@@ -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
|
||||
|
@@ -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:
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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:
|
||||
|
||||
|
@@ -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.
|
||||
|
||||
|
Reference in New Issue
Block a user