diff --git a/bin/pt-archiver b/bin/pt-archiver index 81653b8d..705f1fa4 100755 --- a/bin/pt-archiver +++ b/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} ) { @@ -4070,7 +4101,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, + ); } # ######################################################################## diff --git a/bin/pt-heartbeat b/bin/pt-heartbeat index 61424bfe..ed471473 100755 --- a/bin/pt-heartbeat +++ b/bin/pt-heartbeat @@ -24,66 +24,6 @@ use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; -sub new { - my ( $class, %args ) = @_; - my $self = { - %args, - replication_thread => {}, - }; - return bless $self, $class; -} - -sub get_slaves { - my ($self, %args) = @_; - my @required_args = qw(make_cxn recursion_method recurse DSNParser Quoter); - foreach my $arg ( @required_args ) { - die "I need a $arg argument" unless exists $args{$arg}; - } - my ($make_cxn, $methods, $recurse, $dp) = @args{@required_args}; - - my $slaves = []; - - PTDEBUG && _d('Slave recursion method:', $methods); - if ( !@$methods || 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 => $recurse, - method => $methods, - callback => sub { - my ( $dsn, $dbh, $level, $parent ) = @_; - return unless $level; - PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); - push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); - return; - }, - } - ); - } - elsif ( @$methods && $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 ( !@$methods || $methods->[0] =~ m/none/i ) { - PTDEBUG && _d('Not getting to slaves'); - } - else { - die "Unexpected recursion methods: @$methods"; - } - - return $slaves; -} - sub check_recursion_method { my ($methods) = @_; @@ -103,13 +43,93 @@ sub check_recursion_method { } } +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 => {}, + }; + return bless $self, $class; +} + +sub get_slaves { + my ($self, %args) = @_; + my @required_args = qw(make_cxn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($make_cxn) = @args{@required_args}; + + 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, + callback => sub { + my ( $dsn, $dbh, $level, $parent ) = @_; + return unless $level; + PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); + push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); + return; + }, + } + ); + } + 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 ( $methods->[0] =~ m/none/i ) { + PTDEBUG && _d('Not getting to slaves'); + } + else { + 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 ( $args->{method} && lc($args->{method}->[0] || '') 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; } @@ -144,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', @@ -162,14 +182,12 @@ sub recurse_to_slaves { sub find_slave_hosts { my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_; - my @methods = $self->_resolve_recursion_methods($methods, $dsn); - 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); @@ -180,15 +198,6 @@ sub find_slave_hosts { return @slaves; } -sub _resolve_recursion_methods { - my ($self, $methods, $dsn) = @_; - - return @$methods if $methods && @$methods; - return qw( processlist hosts ) if (($dsn->{P} || 3306) == 3306); - PTDEBUG && _d('Port number is non-standard; using only hosts method'); - return qw( hosts ); -} - sub _find_slaves_by_processlist { my ( $self, $dsn_parser, $dbh, $dsn ) = @_; @@ -681,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} ) { @@ -3431,7 +3443,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), @@ -3762,17 +3778,12 @@ sub check_delay { $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->got('recursion-method') - ? $o->get('recursion-method') - : [], }, ); } diff --git a/bin/pt-kill b/bin/pt-kill index 29584395..12381f05 100755 --- a/bin/pt-kill +++ b/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 diff --git a/bin/pt-online-schema-change b/bin/pt-online-schema-change index 75525521..de4f63ac 100755 --- a/bin/pt-online-schema-change +++ b/bin/pt-online-schema-change @@ -3452,66 +3452,6 @@ use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; -sub new { - my ( $class, %args ) = @_; - my $self = { - %args, - replication_thread => {}, - }; - return bless $self, $class; -} - -sub get_slaves { - my ($self, %args) = @_; - my @required_args = qw(make_cxn recursion_method recurse DSNParser Quoter); - foreach my $arg ( @required_args ) { - die "I need a $arg argument" unless exists $args{$arg}; - } - my ($make_cxn, $methods, $recurse, $dp) = @args{@required_args}; - - my $slaves = []; - - PTDEBUG && _d('Slave recursion method:', $methods); - if ( !@$methods || 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 => $recurse, - method => $methods, - callback => sub { - my ( $dsn, $dbh, $level, $parent ) = @_; - return unless $level; - PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); - push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); - return; - }, - } - ); - } - elsif ( @$methods && $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 ( !@$methods || $methods->[0] =~ m/none/i ) { - PTDEBUG && _d('Not getting to slaves'); - } - else { - die "Unexpected recursion methods: @$methods"; - } - - return $slaves; -} - sub check_recursion_method { my ($methods) = @_; @@ -3531,13 +3471,93 @@ sub check_recursion_method { } } +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 => {}, + }; + return bless $self, $class; +} + +sub get_slaves { + my ($self, %args) = @_; + my @required_args = qw(make_cxn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($make_cxn) = @args{@required_args}; + + 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, + callback => sub { + my ( $dsn, $dbh, $level, $parent ) = @_; + return unless $level; + PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); + push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); + return; + }, + } + ); + } + 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 ( $methods->[0] =~ m/none/i ) { + PTDEBUG && _d('Not getting to slaves'); + } + else { + 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 ( $args->{method} && lc($args->{method}->[0] || '') 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; } @@ -3572,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', @@ -3590,14 +3610,12 @@ sub recurse_to_slaves { sub find_slave_hosts { my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_; - my @methods = $self->_resolve_recursion_methods($methods, $dsn); - 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); @@ -3608,15 +3626,6 @@ sub find_slave_hosts { return @slaves; } -sub _resolve_recursion_methods { - my ($self, $methods, $dsn) = @_; - - return @$methods if $methods && @$methods; - return qw( processlist hosts ) if (($dsn->{P} || 3306) == 3306); - PTDEBUG && _d('Port number is non-standard; using only hosts method'); - return qw( hosts ); -} - sub _find_slaves_by_processlist { my ( $self, $dsn_parser, $dbh, $dsn ) = @_; @@ -4109,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} ) { @@ -6033,16 +6045,15 @@ sub main { # ##################################################################### # Find and connect to slaves. # ##################################################################### - my $ms = new MasterSlave(); + my $ms = new MasterSlave( + OptionParser => $o, + DSNParser => $dp, + Quoter => $q, + ); + $slaves = $ms->get_slaves( dbh => $cxn->dbh(), dsn => $cxn->dsn(), - recursion_method => $o->got('recursion-method') - ? $o->get('recursion-method') - : [], - recurse => $o->get('recurse'), - DSNParser => $dp, - Quoter => $q, make_cxn => sub { return $make_cxn->(@_, prev_dsn => $cxn->dsn()); }, diff --git a/bin/pt-query-digest b/bin/pt-query-digest index e4dc5cb9..46c4e898 100755 --- a/bin/pt-query-digest +++ b/bin/pt-query-digest @@ -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 diff --git a/bin/pt-slave-find b/bin/pt-slave-find index b22670be..f37259b1 100755 --- a/bin/pt-slave-find +++ b/bin/pt-slave-find @@ -1872,66 +1872,6 @@ use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; -sub new { - my ( $class, %args ) = @_; - my $self = { - %args, - replication_thread => {}, - }; - return bless $self, $class; -} - -sub get_slaves { - my ($self, %args) = @_; - my @required_args = qw(make_cxn recursion_method recurse DSNParser Quoter); - foreach my $arg ( @required_args ) { - die "I need a $arg argument" unless exists $args{$arg}; - } - my ($make_cxn, $methods, $recurse, $dp) = @args{@required_args}; - - my $slaves = []; - - PTDEBUG && _d('Slave recursion method:', $methods); - if ( !@$methods || 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 => $recurse, - method => $methods, - callback => sub { - my ( $dsn, $dbh, $level, $parent ) = @_; - return unless $level; - PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); - push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); - return; - }, - } - ); - } - elsif ( @$methods && $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 ( !@$methods || $methods->[0] =~ m/none/i ) { - PTDEBUG && _d('Not getting to slaves'); - } - else { - die "Unexpected recursion methods: @$methods"; - } - - return $slaves; -} - sub check_recursion_method { my ($methods) = @_; @@ -1951,13 +1891,93 @@ sub check_recursion_method { } } +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 => {}, + }; + return bless $self, $class; +} + +sub get_slaves { + my ($self, %args) = @_; + my @required_args = qw(make_cxn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($make_cxn) = @args{@required_args}; + + 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, + callback => sub { + my ( $dsn, $dbh, $level, $parent ) = @_; + return unless $level; + PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); + push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); + return; + }, + } + ); + } + 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 ( $methods->[0] =~ m/none/i ) { + PTDEBUG && _d('Not getting to slaves'); + } + else { + 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 ( $args->{method} && lc($args->{method}->[0] || '') 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; } @@ -1992,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', @@ -2010,14 +2030,12 @@ sub recurse_to_slaves { sub find_slave_hosts { my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_; - my @methods = $self->_resolve_recursion_methods($methods, $dsn); - 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); @@ -2028,15 +2046,6 @@ sub find_slave_hosts { return @slaves; } -sub _resolve_recursion_methods { - my ($self, $methods, $dsn) = @_; - - return @$methods if $methods && @$methods; - return qw( processlist hosts ) if (($dsn->{P} || 3306) == 3306); - PTDEBUG && _d('Port number is non-standard; using only hosts method'); - return qw( hosts ); -} - sub _find_slaves_by_processlist { my ( $self, $dsn_parser, $dbh, $dsn ) = @_; @@ -2529,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} ) { @@ -3383,16 +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 => $q, + ); $ms->recurse_to_slaves( - { dbh => $dbh, - dsn => $master_dsn, - dsn_parser => $dp, - recurse => $o->get('recurse'), - method => $o->got('recursion-method') - ? $o->get('recursion-method') - : [], - callback => sub { + { dbh => $dbh, + dsn => $master_dsn, + callback => sub { my ( $dsn, $dbh, $level, $parent ) = @_; if ( !$parent ) { $root = $dsn; diff --git a/bin/pt-slave-restart b/bin/pt-slave-restart index 0814fb78..b0f78761 100755 --- a/bin/pt-slave-restart +++ b/bin/pt-slave-restart @@ -2185,66 +2185,6 @@ use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; -sub new { - my ( $class, %args ) = @_; - my $self = { - %args, - replication_thread => {}, - }; - return bless $self, $class; -} - -sub get_slaves { - my ($self, %args) = @_; - my @required_args = qw(make_cxn recursion_method recurse DSNParser Quoter); - foreach my $arg ( @required_args ) { - die "I need a $arg argument" unless exists $args{$arg}; - } - my ($make_cxn, $methods, $recurse, $dp) = @args{@required_args}; - - my $slaves = []; - - PTDEBUG && _d('Slave recursion method:', $methods); - if ( !@$methods || 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 => $recurse, - method => $methods, - callback => sub { - my ( $dsn, $dbh, $level, $parent ) = @_; - return unless $level; - PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); - push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); - return; - }, - } - ); - } - elsif ( @$methods && $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 ( !@$methods || $methods->[0] =~ m/none/i ) { - PTDEBUG && _d('Not getting to slaves'); - } - else { - die "Unexpected recursion methods: @$methods"; - } - - return $slaves; -} - sub check_recursion_method { my ($methods) = @_; @@ -2264,13 +2204,93 @@ sub check_recursion_method { } } +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 => {}, + }; + return bless $self, $class; +} + +sub get_slaves { + my ($self, %args) = @_; + my @required_args = qw(make_cxn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($make_cxn) = @args{@required_args}; + + 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, + callback => sub { + my ( $dsn, $dbh, $level, $parent ) = @_; + return unless $level; + PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); + push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); + return; + }, + } + ); + } + 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 ( $methods->[0] =~ m/none/i ) { + PTDEBUG && _d('Not getting to slaves'); + } + else { + 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 ( $args->{method} && lc($args->{method}->[0] || '') 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; } @@ -2305,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', @@ -2323,14 +2343,12 @@ sub recurse_to_slaves { sub find_slave_hosts { my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_; - my @methods = $self->_resolve_recursion_methods($methods, $dsn); - 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); @@ -2341,15 +2359,6 @@ sub find_slave_hosts { return @slaves; } -sub _resolve_recursion_methods { - my ($self, $methods, $dsn) = @_; - - return @$methods if $methods && @$methods; - return qw( processlist hosts ) if (($dsn->{P} || 3306) == 3306); - PTDEBUG && _d('Port number is non-standard; using only hosts method'); - return qw( hosts ); -} - sub _find_slaves_by_processlist { my ( $self, $dsn_parser, $dbh, $dsn ) = @_; @@ -2842,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} ) { @@ -3206,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 { @@ -3234,9 +3248,6 @@ sub main { my ( $dsn, $dbh, $level ) = @_; print STDERR "Skipping ", $dp->as_string($dsn), "\n"; }, - method => $o->got('recursion-method') - ? $o->get('recursion-method') - : [], } ); diff --git a/bin/pt-table-checksum b/bin/pt-table-checksum index a2992ea8..189b5828 100755 --- a/bin/pt-table-checksum +++ b/bin/pt-table-checksum @@ -3036,66 +3036,6 @@ use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; -sub new { - my ( $class, %args ) = @_; - my $self = { - %args, - replication_thread => {}, - }; - return bless $self, $class; -} - -sub get_slaves { - my ($self, %args) = @_; - my @required_args = qw(make_cxn recursion_method recurse DSNParser Quoter); - foreach my $arg ( @required_args ) { - die "I need a $arg argument" unless exists $args{$arg}; - } - my ($make_cxn, $methods, $recurse, $dp) = @args{@required_args}; - - my $slaves = []; - - PTDEBUG && _d('Slave recursion method:', $methods); - if ( !@$methods || 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 => $recurse, - method => $methods, - callback => sub { - my ( $dsn, $dbh, $level, $parent ) = @_; - return unless $level; - PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); - push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); - return; - }, - } - ); - } - elsif ( @$methods && $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 ( !@$methods || $methods->[0] =~ m/none/i ) { - PTDEBUG && _d('Not getting to slaves'); - } - else { - die "Unexpected recursion methods: @$methods"; - } - - return $slaves; -} - sub check_recursion_method { my ($methods) = @_; @@ -3115,13 +3055,93 @@ sub check_recursion_method { } } +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 => {}, + }; + return bless $self, $class; +} + +sub get_slaves { + my ($self, %args) = @_; + my @required_args = qw(make_cxn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($make_cxn) = @args{@required_args}; + + 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, + callback => sub { + my ( $dsn, $dbh, $level, $parent ) = @_; + return unless $level; + PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); + push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); + return; + }, + } + ); + } + 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 ( $methods->[0] =~ m/none/i ) { + PTDEBUG && _d('Not getting to slaves'); + } + else { + 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 ( $args->{method} && lc($args->{method}->[0] || '') 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; } @@ -3156,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', @@ -3174,14 +3194,12 @@ sub recurse_to_slaves { sub find_slave_hosts { my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_; - my @methods = $self->_resolve_recursion_methods($methods, $dsn); - 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); @@ -3192,15 +3210,6 @@ sub find_slave_hosts { return @slaves; } -sub _resolve_recursion_methods { - my ($self, $methods, $dsn) = @_; - - return @$methods if $methods && @$methods; - return qw( processlist hosts ) if (($dsn->{P} || 3306) == 3306); - PTDEBUG && _d('Port number is non-standard; using only hosts method'); - return qw( hosts ); -} - sub _find_slaves_by_processlist { my ( $self, $dsn_parser, $dbh, $dsn ) = @_; @@ -3693,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} ) { @@ -7038,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 @@ -7058,15 +7074,9 @@ sub main { # Find and connect to slaves. # ##################################################################### $slaves = $ms->get_slaves( - dbh => $master_dbh, - dsn => $master_dsn, - recursion_method => $o->got('recursion-method') - ? $o->get('recursion-method') - : [], - recurse => $o->get('recurse'), - DSNParser => $dp, - Quoter => $q, - make_cxn => sub { + dbh => $master_dbh, + dsn => $master_dsn, + make_cxn => sub { return $make_cxn->(@_, prev_dsn => $master_cxn->dsn()); }, ); diff --git a/bin/pt-table-sync b/bin/pt-table-sync index c5dcf91c..50299c28 100755 --- a/bin/pt-table-sync +++ b/bin/pt-table-sync @@ -6456,66 +6456,6 @@ use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; -sub new { - my ( $class, %args ) = @_; - my $self = { - %args, - replication_thread => {}, - }; - return bless $self, $class; -} - -sub get_slaves { - my ($self, %args) = @_; - my @required_args = qw(make_cxn recursion_method recurse DSNParser Quoter); - foreach my $arg ( @required_args ) { - die "I need a $arg argument" unless exists $args{$arg}; - } - my ($make_cxn, $methods, $recurse, $dp) = @args{@required_args}; - - my $slaves = []; - - PTDEBUG && _d('Slave recursion method:', $methods); - if ( !@$methods || 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 => $recurse, - method => $methods, - callback => sub { - my ( $dsn, $dbh, $level, $parent ) = @_; - return unless $level; - PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); - push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); - return; - }, - } - ); - } - elsif ( @$methods && $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 ( !@$methods || $methods->[0] =~ m/none/i ) { - PTDEBUG && _d('Not getting to slaves'); - } - else { - die "Unexpected recursion methods: @$methods"; - } - - return $slaves; -} - sub check_recursion_method { my ($methods) = @_; @@ -6535,13 +6475,93 @@ sub check_recursion_method { } } +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 => {}, + }; + return bless $self, $class; +} + +sub get_slaves { + my ($self, %args) = @_; + my @required_args = qw(make_cxn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($make_cxn) = @args{@required_args}; + + 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, + callback => sub { + my ( $dsn, $dbh, $level, $parent ) = @_; + return unless $level; + PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); + push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); + return; + }, + } + ); + } + 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 ( $methods->[0] =~ m/none/i ) { + PTDEBUG && _d('Not getting to slaves'); + } + else { + 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 ( $args->{method} && lc($args->{method}->[0] || '') 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; } @@ -6576,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', @@ -6594,14 +6614,12 @@ sub recurse_to_slaves { sub find_slave_hosts { my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_; - my @methods = $self->_resolve_recursion_methods($methods, $dsn); - 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); @@ -6612,15 +6630,6 @@ sub find_slave_hosts { return @slaves; } -sub _resolve_recursion_methods { - my ($self, $methods, $dsn) = @_; - - return @$methods if $methods && @$methods; - return qw( processlist hosts ) if (($dsn->{P} || 3306) == 3306); - PTDEBUG && _d('Port number is non-standard; using only hosts method'); - return qw( hosts ); -} - sub _find_slaves_by_processlist { my ( $self, $dsn_parser, $dbh, $dsn ) = @_; @@ -7113,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} ) { @@ -8764,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')); @@ -8837,9 +8848,6 @@ sub sync_via_replication { return; }, # recurse_to_slaves() callback - method => $o->got('recursion-method') - ? $o->get('recursion-method') - : [], }, ); } # DSN is master diff --git a/lib/MasterSlave.pm b/lib/MasterSlave.pm index 341302e6..a60f63c4 100644 --- a/lib/MasterSlave.pm +++ b/lib/MasterSlave.pm @@ -1,4 +1,4 @@ -# This program is copyright 2007-2011 Baron Schwartz, 2011 Percona Inc. +# This program is copyright 2007-2011 Baron Schwartz, 2011-2012 Percona Inc. # Feedback and improvements are welcome. # # THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED @@ -27,67 +27,6 @@ use warnings FATAL => 'all'; use English qw(-no_match_vars); use constant PTDEBUG => $ENV{PTDEBUG} || 0; -sub new { - my ( $class, %args ) = @_; - my $self = { - %args, - replication_thread => {}, - }; - return bless $self, $class; -} - -sub get_slaves { - my ($self, %args) = @_; - my @required_args = qw(make_cxn recursion_method recurse DSNParser Quoter); - foreach my $arg ( @required_args ) { - # exists because recurse can be undef - die "I need a $arg argument" unless exists $args{$arg}; - } - my ($make_cxn, $methods, $recurse, $dp) = @args{@required_args}; - - my $slaves = []; - - PTDEBUG && _d('Slave recursion method:', $methods); - if ( !@$methods || 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 => $recurse, - method => $methods, - callback => sub { - my ( $dsn, $dbh, $level, $parent ) = @_; - return unless $level; - PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); - push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); - return; - }, - } - ); - } - elsif ( @$methods && $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 ( !@$methods || $methods->[0] =~ m/none/i ) { - PTDEBUG && _d('Not getting to slaves'); - } - else { - die "Unexpected recursion methods: @$methods"; - } - - return $slaves; -} - # Sub: check_recursion_method # Check that the arrayref of recursion methods passed in is valid sub check_recursion_method { @@ -109,6 +48,86 @@ sub check_recursion_method { } } +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 => {}, + }; + return bless $self, $class; +} + +sub get_slaves { + my ($self, %args) = @_; + my @required_args = qw(make_cxn); + foreach my $arg ( @required_args ) { + die "I need a $arg argument" unless $args{$arg}; + } + my ($make_cxn) = @args{@required_args}; + + 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, + callback => sub { + my ( $dsn, $dbh, $level, $parent ) = @_; + return unless $level; + PTDEBUG && _d('Found slave:', $dp->as_string($dsn)); + push @$slaves, $make_cxn->(dsn => $dsn, dbh => $dbh); + return; + }, + } + ); + } + 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 ( $methods->[0] =~ m/none/i ) { + PTDEBUG && _d('Not getting to slaves'); + } + else { + die "Unexpected recursion methods: @$methods"; + } + + return $slaves; +} + +sub _resolve_recursion_methods { + my ($self, $dsn) = @_; + my $o = $self->{OptionParser}; + if ( $o->got('recursion-method') ) { + # Use whatever the user explicitly gave on the command line. + return $o->get('recursion-method'); + } + elsif ( $dsn && ($dsn->{P} || 3306) != 3306 ) { + # Special case: hosts is best when port is non-standard. + PTDEBUG && _d('Port number is non-standard; using only hosts method'); + return [qw(hosts)]; + } + else { + # Use the option's default. + return $o->get('recursion-method'); + } +} + # Sub: recurse_to_slaves # Descend to slaves by examining SHOW SLAVE HOSTS. # The callback gets the slave's DSN, dbh, parent, and the recursion level @@ -132,10 +151,16 @@ sub check_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 ( $args->{method} && lc($args->{method}->[0] || '') eq 'none' ) { + # Re-resolve the recursion methods for each slave. In most cases + # it won't change, but it could if one slave uses standard port (3306) + # and another does not. + my $methods = $self->_resolve_recursion_methods($dsn); + PTDEBUG && _d('Recursion methods:', @$methods); + if ( lc($methods->[0]) eq 'none' ) { # https://bugs.launchpad.net/percona-toolkit/+bug/987694 PTDEBUG && _d('Not recursing to slaves'); return; @@ -175,13 +200,13 @@ sub recurse_to_slaves { # Call the callback! $args->{callback}->($dsn, $dbh, $level, $args->{parent}); - if ( !defined $args->{recurse} || $level < $args->{recurse} ) { + if ( !defined $recurse || $level < $recurse ) { # Find the slave hosts. Eliminate hosts that aren't slaves of me (as # revealed by server_id and master_id). 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', @@ -207,14 +232,12 @@ sub recurse_to_slaves { sub find_slave_hosts { my ( $self, $dsn_parser, $dbh, $dsn, $methods ) = @_; - my @methods = $self->_resolve_recursion_methods($methods, $dsn); - 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); @@ -225,18 +248,6 @@ sub find_slave_hosts { return @slaves; } -sub _resolve_recursion_methods { - my ($self, $methods, $dsn) = @_; - - # If an explicit recursion method was specified, use that - return @$methods if $methods && @$methods; - # Otherwise, if we're on the standard port, default to processlist and hosts - return qw( processlist hosts ) if (($dsn->{P} || 3306) == 3306); - # Or if on a non-standard port, default to hosts. - PTDEBUG && _d('Port number is non-standard; using only hosts method'); - return qw( hosts ); -} - sub _find_slaves_by_processlist { my ( $self, $dsn_parser, $dbh, $dsn ) = @_; @@ -871,13 +882,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} ) { diff --git a/t/lib/MasterSlave.t b/t/lib/MasterSlave.t index 43ccaa1b..2494e428 100644 --- a/t/lib/MasterSlave.t +++ b/t/lib/MasterSlave.t @@ -22,13 +22,11 @@ use PerconaTest; use Data::Dumper; -my $ms = new MasterSlave(); my $dp = new DSNParser(opts=>$dsn_opts); my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp); my $master_dbh = $sb->get_dbh_for('master'); my $slave_dbh = $sb->get_dbh_for('slave1'); - my $master_dsn = { h => '127.1', P => '12345', @@ -36,28 +34,29 @@ my $master_dsn = { p => 'msandbox', }; -# ############################################################################ -# get_slaves() wrapper around recurse_to_slaves() -# ############################################################################ my $q = new Quoter; my $o = new OptionParser(description => 'MasterSlave'); $o->get_specs("$trunk/bin/pt-table-checksum"); +my $ms = new MasterSlave( + OptionParser => $o, + DSNParser => $dp, + Quoter => $q, +); + +# ############################################################################ +# get_slaves() wrapper around recurse_to_slaves() +# ############################################################################ + SKIP: { skip "Cannot connect to sandbox master", 2 unless $master_dbh; local @ARGV = (); $o->get_opts(); my $slaves = $ms->get_slaves( - dbh => $master_dbh, - dsn => $master_dsn, - recursion_method => $o->got('recursion-method') - ? $o->get('recursion-method') - : [], - recurse => $o->get('recurse'), - DSNParser => $dp, - Quoter => $q, - make_cxn => sub { + dbh => $master_dbh, + dsn => $master_dsn, + make_cxn => sub { my $cxn = new Cxn( @_, DSNParser => $dp, @@ -83,7 +82,7 @@ SKIP: { master_id => 12345, source => 'hosts', }, - 'get_slaves() from recurse_to_slaves() with a default --recursion-method works' + 'get_slaves() from recurse_to_slaves() with a default --recursion-method' ); my ($id) = $slaves->[0]->dbh()->selectrow_array('SELECT @@SERVER_ID'); @@ -102,15 +101,9 @@ SKIP: { $o->get_opts(); $slaves = $ms->get_slaves( - recursion_method => $o->got('recursion-method') - ? $o->get('recursion-method') - : [], - recurse => $o->get('recurse'), - DSNParser => $dp, - Quoter => $q, - dbh => $master_dbh, - dsn => $master_dsn, - make_cxn => sub { + dbh => $master_dbh, + dsn => $master_dsn, + make_cxn => sub { my $cxn = new Cxn( @_, DSNParser => $dp, @@ -154,15 +147,9 @@ SKIP: { throws_ok( sub { $slaves = $ms->get_slaves( - recursion_method => $o->got('recursion-method') - ? $o->get('recursion-method') - : [], - recurse => $o->get('recurse'), - DSNParser => $dp, - Quoter => $q, - dbh => $ro_dbh, - dsn => $ro_dsn, - make_cxn => sub { + dbh => $ro_dbh, + dsn => $ro_dsn, + make_cxn => sub { my $cxn = new Cxn( @_, DSNParser => $dp, @@ -180,15 +167,9 @@ SKIP: { @ARGV = ('--recursion-method', 'none'); $o->get_opts(); $slaves = $ms->get_slaves( - recursion_method => $o->got('recursion-method') - ? $o->get('recursion-method') - : [], - recurse => $o->get('recurse'), - DSNParser => $dp, - Quoter => $q, - dbh => $ro_dbh, - dsn => $ro_dsn, - make_cxn => sub { + dbh => $ro_dbh, + dsn => $ro_dsn, + make_cxn => sub { my $cxn = new Cxn( @_, DSNParser => $dp, @@ -204,14 +185,13 @@ SKIP: { "No privs needed for --recursion-method=none (bug 987694)" ); + @ARGV = ('--recursion-method', 'none', '--recurse', '2'); + $o->get_opts(); my $recursed = 0; $ms->recurse_to_slaves( - { dsn_parser => $dp, - dbh => $ro_dbh, - dsn => $ro_dsn, - recurse => 2, - callback => sub { $recursed++ }, - method => [ 'none' ], + { dbh => $ro_dbh, + dsn => $ro_dsn, + callback => sub { $recursed++ }, }); is( $recursed, @@ -245,10 +225,10 @@ foreach my $port ( values %port_for ) { diag(`$trunk/sandbox/stop-sandbox $port >/dev/null 2>&1`); } } -diag(`$trunk/sandbox/start-sandbox master 2900 >/dev/null 2>&1`); -diag(`$trunk/sandbox/start-sandbox slave 2903 2900 >/dev/null 2>&1`); -diag(`$trunk/sandbox/start-sandbox slave 2901 2900 >/dev/null 2>&1`); -diag(`$trunk/sandbox/start-sandbox slave 2902 2901 >/dev/null 2>&1`); +diag(`$trunk/sandbox/start-sandbox master 2900`); +diag(`$trunk/sandbox/start-sandbox slave 2903 2900`); +diag(`$trunk/sandbox/start-sandbox slave 2901 2900`); +diag(`$trunk/sandbox/start-sandbox slave 2902 2901`); # I discovered something weird while updating this test. Above, you see that # slave2 is started first, then the others. Before, slave2 was started last, @@ -293,11 +273,12 @@ my $skip_callback = sub { . " from $dsn->{source}"); }; +@ARGV = ('--recurse', '2'); +$o->get_opts(); + $ms->recurse_to_slaves( - { dsn_parser => $dp, - dbh => $dbh, + { dbh => $dbh, dsn => $dsn, - recurse => 2, callback => $callback, skip_callback => $skip_callback, }); @@ -685,10 +666,7 @@ $sb->load_file('master', "t/lib/samples/MasterSlave/dsn_table.sql"); $o->get_opts(); my $slaves = $ms->get_slaves( - recursion_method => $o->got('recursion-method') - ? $o->get('recursion-method') - : [], - recurse => $o->get('recurse'), + OptionParser => $o, DSNParser => $dp, Quoter => $q, make_cxn => sub { @@ -735,7 +713,7 @@ eval { like( $EVAL_ERROR, qr/Invalid recursion method: stuff/, - "Invalid recursion methods are caught", + "--recursion-method stuff causes error" ); local $EVAL_ERROR; @@ -746,17 +724,18 @@ eval { like( $EVAL_ERROR, qr/Invalid combination of recursion methods: processlist, stuff/, - "Invalid recursion methods are caught", + "--recursion-method processlist,stuff causes error", ); # ############################################################################# # Done. # ############################################################################# $sb->wipe_clean($master_dbh); -diag(`$trunk/sandbox/stop-sandbox 2903 2902 2901 2900 >/dev/null 2>&1`); +diag(`$trunk/sandbox/stop-sandbox 2903 2902 2901 2900`); diag(`/tmp/12346/use -e "set global read_only=1"`); diag(`/tmp/12347/use -e "set global read_only=1"`); -diag(`$trunk/sandbox/test-env reset >/dev/null 2>&1`); +$sb->wait_for_slaves(); +diag(`$trunk/sandbox/test-env reset`); ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); - done_testing; +exit;