Implement and test --recursion-method=none in MasterSlave.pm and pt-table-checksum.

This commit is contained in:
Daniel Nichter
2012-05-17 08:11:30 -06:00
parent 64f4a5bdc0
commit e969d8d9f7
5 changed files with 214 additions and 1 deletions

View File

@@ -2485,6 +2485,9 @@ sub get_slaves {
dsn_table_dsn => $dsn_table_dsn,
);
}
elsif ( $method =~ m/none/i ) {
PTDEBUG && _d('Not getting to slaves');
}
else {
die "Invalid --recursion-method: $method. Valid values are: "
. "dsn=DSN, hosts, or processlist.\n";
@@ -2499,6 +2502,11 @@ sub recurse_to_slaves {
my $dp = $args->{dsn_parser};
my $dsn = $args->{dsn};
if ( lc($args->{method} || '') eq 'none' ) {
PTDEBUG && _d('Not recursing to slaves');
return;
}
my $dbh;
eval {
$dbh = $args->{dbh} || $dp->get_dbh(
@@ -4080,12 +4088,15 @@ sub _next_boundaries {
return 1; # continue nibbling
}
if ( $self->identical_boundaries($self->{lower}, $self->{next_lower}) ) {
PTDEBUG && _d('Infinite loop detected');
my $tbl = $self->{tbl};
my $index = $tbl->{tbl_struct}->{keys}->{$self->{index}};
my $n_cols = scalar @{$index->{cols}};
my $chunkno = $self->{nibbleno};
die "Possible infinite loop detected! "
. "The lower boundary for chunk $chunkno is "
. "<" . join(', ', @{$self->{lower}}) . "> and the lower "
@@ -4112,6 +4123,7 @@ sub _next_boundaries {
}
}
PTDEBUG && _d($self->{ub_sth}->{Statement}, 'params:',
join(', ', @{$self->{lower}}), $self->{limit});
$self->{ub_sth}->execute(@{$self->{lower}}, $self->{limit});

View File

@@ -76,6 +76,10 @@ sub get_slaves {
dsn_table_dsn => $dsn_table_dsn,
);
}
elsif ( $method =~ m/none/i ) {
# https://bugs.launchpad.net/percona-toolkit/+bug/987694
PTDEBUG && _d('Not getting to slaves');
}
else {
die "Invalid --recursion-method: $method. Valid values are: "
. "dsn=DSN, hosts, or processlist.\n";
@@ -110,6 +114,12 @@ sub recurse_to_slaves {
my $dp = $args->{dsn_parser};
my $dsn = $args->{dsn};
if ( lc($args->{method} || '') eq 'none' ) {
# https://bugs.launchpad.net/percona-toolkit/+bug/987694
PTDEBUG && _d('Not recursing to slaves');
return;
}
my $dbh;
eval {
$dbh = $args->{dbh} || $dp->get_dbh(

View File

@@ -9,7 +9,7 @@ BEGIN {
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More tests => 47;
use Test::More tests => 50;
use MasterSlave;
use DSNParser;
@@ -119,6 +119,96 @@ SKIP: {
[],
"get_slaves() by processlist"
);
# ##########################################################################
# --recursion-method=none
# https://bugs.launchpad.net/percona-toolkit/+bug/987694
# ##########################################################################
# Create percona.checksums to make the privs happy.
diag(`/tmp/12345/use -e "create database if not exists percona"`);
diag(`/tmp/12345/use -e "create table if not exists percona.checksums (id int)"`);
# Create a read-only checksum user that can't SHOW SLAVES HOSTS or much else.
diag(`/tmp/12345/use -u root < $trunk/t/lib/samples/ro-checksum-user.sql`);
my $ro_dbh = DBI->connect(
"DBI:mysql:;host=127.0.0.1;port=12345", 'ro_checksum_user', 'msandbox',
{ PrintError => 0, RaiseError => 1 });
my $ro_dsn = {
h => '127.1',
P => '12345',
u => 'ro_checksum_user',
p => 'ro_checksum_user',
};
@ARGV = ('--recursion-method', 'hosts');
$o->get_opts();
throws_ok(
sub {
$slaves = $ms->get_slaves(
OptionParser => $o,
DSNParser => $dp,
Quoter => $q,
dbh => $ro_dbh,
dsn => $ro_dsn,
make_cxn => sub {
my $cxn = new Cxn(
@_,
DSNParser => $dp,
OptionParser => $o,
);
$cxn->connect();
return $cxn;
},
);
},
qr/Access denied/,
"Can't SHOW SLAVE HOSTS without privs (bug 987694)"
);
@ARGV = ('--recursion-method', 'none');
$o->get_opts();
$slaves = $ms->get_slaves(
OptionParser => $o,
DSNParser => $dp,
Quoter => $q,
dbh => $ro_dbh,
dsn => $ro_dsn,
make_cxn => sub {
my $cxn = new Cxn(
@_,
DSNParser => $dp,
OptionParser => $o,
);
$cxn->connect();
return $cxn;
},
);
is_deeply(
$slaves,
[],
"No privs needed for --recursion-method=none (bug 987694)"
);
my $recursed = 0;
$ms->recurse_to_slaves(
{ dsn_parser => $dp,
dbh => $ro_dbh,
dsn => $ro_dsn,
recurse => 2,
callback => sub { $recursed++ },
method => 'none',
});
is(
$recursed,
0,
"recurse_to_slaves() doesn't recurse if method=none"
);
$ro_dbh->disconnect();
diag(`/tmp/12345/use -u root -e "drop user 'ro_checksum_user'\@'%'"`);
}
# #############################################################################

View File

@@ -0,0 +1,3 @@
CREATE USER 'ro_checksum_user'@'%' IDENTIFIED BY 'msandbox';
GRANT SELECT ON sakila.* TO 'ro_checksum_user'@'%';
GRANT SELECT, INSERT, UPDATE, DELETE ON percona.checksums TO 'ro_checksum_user'@'%';

View File

@@ -0,0 +1,98 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
# Hostnames make testing less accurate. Tests need to see
# that such-and-such happened on specific slave hosts, but
# the sandbox servers are all on one host so all slaves have
# the same hostname.
$ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} = 1;
use Data::Dumper;
use PerconaTest;
use Sandbox;
# Fix @INC because pt-table-checksum uses subclass OobNibbleIterator.
shift @INC; # our unshift (above)
shift @INC; # PerconaTest's unshift
require "$trunk/bin/pt-table-checksum";
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');
if ( !$master_dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
elsif ( !$slave_dbh ) {
plan skip_all => 'Cannot connect to sandbox slave1';
}
elsif ( !@{$master_dbh->selectall_arrayref('show databases like "sakila"')} ) {
plan skip_all => 'sakila database is not loaded';
}
else {
plan tests => 2;
}
# The sandbox servers run with lock_wait_timeout=3 and it's not dynamic
# so we need to specify --lock-wait-timeout=3 else the tool will die.
my $master_dsn = 'h=127.1,P=12345';
my @args = (qw(--lock-wait-timeout 3));
my $row;
my $output;
my $exit_status;
my $sample = "t/pt-table-checksum/samples/";
# ############################################################################
# --recursion-method=none to avoid SHOW SLAVE HOSTS
# https://bugs.launchpad.net/percona-toolkit/+bug/987694
# ############################################################################
# Create percona.checksums because ro_checksum_user doesn't have the privs.
pt_table_checksum::main(@args,
"$master_dsn,u=msandbox,p=msandbox",
qw(-t sakila.country --quiet --quiet));
diag(`/tmp/12345/use -u root < $trunk/t/lib/samples/ro-checksum-user.sql`);
PerconaTest::wait_for_table($slave_dbh, "mysql.tables_priv", "user='ro_checksum_user'");
$output = output(
sub { $exit_status = pt_table_checksum::main(@args,
"$master_dsn,u=ro_checksum_user,p=msandbox",
# Comment out this line and the tests fail because ro_checksum_user
# doesn't have privs to SHOW SLAVE HOSTS. This proves that
# --recursion-method none is working.
qw(--recursion-method none)
) },
stderr => 1,
);
is(
$exit_status,
0,
"Read-only user (bug 987694): 0 exit"
);
like(
$output,
qr/ sakila.store$/m,
"Read-only user (bug 987694): checksummed rows"
);
diag(`/tmp/12345/use -u root -e "drop user 'ro_checksum_user'\@'%'"`);
# #############################################################################
# Done.
# #############################################################################
$sb->wipe_clean($master_dbh);
exit;