Use SchemaIterator for filtering --sync-to-master and --replicate. Return arrayref from TableChecksum::find_replication_differences().

This commit is contained in:
Daniel Nichter
2012-05-21 15:50:40 -06:00
parent 2c5ea7c49d
commit d0d296ee16
3 changed files with 85 additions and 51 deletions
+50 -42
View File
@@ -4248,10 +4248,9 @@ sub find_replication_differences {
. "FROM $table " . "FROM $table "
. "WHERE master_cnt <> this_cnt OR master_crc <> this_crc " . "WHERE master_cnt <> this_cnt OR master_crc <> this_crc "
. "OR ISNULL(master_crc) <> ISNULL(this_crc)"; . "OR ISNULL(master_crc) <> ISNULL(this_crc)";
PTDEBUG && _d($sql); PTDEBUG && _d($sql);
my $diffs = $dbh->selectall_arrayref($sql, { Slice => {} }); my $diffs = $dbh->selectall_arrayref($sql, { Slice => {} });
return @$diffs; return $diffs;
} }
sub _d { sub _d {
@@ -7988,11 +7987,16 @@ sub sync_via_replication {
tbl => undef, # set later tbl => undef, # set later
}; };
# Filters for --databases and --tables. We have to do these manually # Used to filter which tables are synced.
# since we don't use MySQLFind for --replicate. # https://bugs.launchpad.net/percona-toolkit/+bug/1002365
my $databases = $o->get('databases'); my $schema_iter = new SchemaIterator(
my $tables = $o->get('tables'); dbh => $src->{dbh},
OptionParser => $o,
TableParser => $args{TableParser},
Quoter => $args{Quoter},
);
my %skip_table;
my $exit_status = 0; my $exit_status = 0;
# Connect to the master and treat it as the source, then find # Connect to the master and treat it as the source, then find
@@ -8008,18 +8012,17 @@ sub sync_via_replication {
# First, check that the master (source) has no discrepancies itself, # First, check that the master (source) has no discrepancies itself,
# and ignore tables that do. # and ignore tables that do.
my %skip_table; my $src_diffs = $checksum->find_replication_differences(
map { $skip_table{$_->{db}}->{$_->{tbl}}++ }
$checksum->find_replication_differences(
$src->{dbh}, $o->get('replicate')); $src->{dbh}, $o->get('replicate'));
map { $skip_table{lc $_->{db}}->{lc $_->{tbl}}++ } @$src_diffs;
# Now check the slave for differences and sync them if necessary. # Now check the slave for differences and sync them if necessary.
my @diffs = filter_diffs( my $dst_diffs = $checksum->find_replication_differences(
\%skip_table, $dst->{dbh}, $o->get('replicate'));
$databases, my $diffs = filter_diffs(
$tables, diffs => $dst_diffs,
$checksum->find_replication_differences( SchemaIterator => $schema_iter,
$dst->{dbh}, $o->get('replicate')) skip_table => \%skip_table,
); );
if ( $o->get('verbose') ) { if ( $o->get('verbose') ) {
@@ -8028,10 +8031,10 @@ sub sync_via_replication {
' in dry-run mode, without accessing or comparing data' : '')); ' in dry-run mode, without accessing or comparing data' : ''));
} }
if ( @diffs ) { if ( $diffs && scalar @$diffs ) {
lock_server(src => $src, dst => $dst, %args); lock_server(src => $src, dst => $dst, %args);
foreach my $diff ( @diffs ) { foreach my $diff ( @$diffs ) {
$src->{db} = $dst->{db} = $diff->{db}; $src->{db} = $dst->{db} = $diff->{db};
$src->{tbl} = $dst->{tbl} = $diff->{tbl}; $src->{tbl} = $dst->{tbl} = $diff->{tbl};
@@ -8056,7 +8059,6 @@ sub sync_via_replication {
# The DSN is the master. Connect to each slave, find differences, # The DSN is the master. Connect to each slave, find differences,
# then sync them. # then sync them.
else { else {
my %skip_table;
$ms->recurse_to_slaves( $ms->recurse_to_slaves(
{ dbh => $src->{dbh}, { dbh => $src->{dbh},
dsn => $src->{dsn}, dsn => $src->{dsn},
@@ -8064,20 +8066,20 @@ sub sync_via_replication {
recurse => 1, recurse => 1,
callback => sub { callback => sub {
my ( $dsn, $dbh, $level, $parent ) = @_; my ( $dsn, $dbh, $level, $parent ) = @_;
my @diffs = $checksum my $all_diffs = $checksum->find_replication_differences(
->find_replication_differences($dbh, $o->get('replicate')); $dbh, $o->get('replicate'));
if ( !$level ) { if ( !$level ) {
# This is the master; don't sync any tables that are wrong # This is the master; don't sync any tables that are wrong
# here, for obvious reasons. # here, for obvious reasons.
map { $skip_table{$_->{db}}->{$_->{tbl}}++ } @diffs; map { $skip_table{lc $_->{db}}->{lc $_->{tbl}}++ }
@$all_diffs;
} }
else { else {
# This is a slave. # This is a slave.
@diffs = filter_diffs( my $diffs = filter_diffs(
\%skip_table, diffs => $all_diffs,
$databases, SchemaIterator => $schema_iter,
$tables, skip_table => \%skip_table,
@diffs
); );
if ( $o->get('verbose') ) { if ( $o->get('verbose') ) {
@@ -8089,7 +8091,7 @@ sub sync_via_replication {
: '')); : ''));
} }
if ( @diffs ) { if ( $diffs && scalar @$diffs ) {
my $dst = { my $dst = {
dsn => $dsn, dsn => $dsn,
dbh => $dbh, dbh => $dbh,
@@ -8100,7 +8102,7 @@ sub sync_via_replication {
lock_server(src => $src, dst => $dst, %args); lock_server(src => $src, dst => $dst, %args);
foreach my $diff ( @diffs ) { foreach my $diff ( @$diffs ) {
$src->{db} = $dst->{db} = $diff->{db}; $src->{db} = $dst->{db} = $diff->{db};
$src->{tbl} = $dst->{tbl} = $diff->{tbl}; $src->{tbl} = $dst->{tbl} = $diff->{tbl};
@@ -8794,22 +8796,28 @@ sub ok_to_sync {
# filters. This sub is called in <sync_via_replication()> to implement # filters. This sub is called in <sync_via_replication()> to implement
# schema object filters like --databases and --tables. # schema object filters like --databases and --tables.
# #
# Parameters:
# $skip_table - Hashref of databases and tables to skip
# $databases - Hashref of databases to skip
# $tables - Hashref of tables to skip
# @diffs - Array of hashrefs, one for each different slave table
#
# Returns: # Returns:
# Array of different slave tables that pass the filters # Arrayref of different slave tables that pass the filters
sub filter_diffs { sub filter_diffs {
my ( $skip_table, $databases, $tables, @diffs ) = @_; my ( %args ) = @_;
return grep { my @required_args = qw(diffs SchemaIterator skip_table);
my ($db, $tbl) = $q->split_unquote($_->{table}); foreach my $arg ( @required_args ) {
!$skip_table->{$db}->{$tbl} die "I need a $arg argument" unless $args{$arg};
&& (!$databases || $databases->{$db}) }
&& (!$tables || ($tables->{$tbl} || $tables->{$_->{table}})) my ($diffs, $si, $skip_table) = @args{@required_args};
} @diffs;
my @filtered_diffs;
foreach my $diff ( @$diffs ) {
my $db = lc $diff->{db};
my $tbl = lc $diff->{tbl};
if ( !$skip_table->{$db}->{$tbl}
&& $si->database_is_allowed($db)
&& $si->table_is_allowed($db, $tbl) ) {
push @filtered_diffs, $diff;
}
}
return \@filtered_diffs;
} }
# Sub: disconnect # Sub: disconnect
+1 -2
View File
@@ -480,10 +480,9 @@ sub find_replication_differences {
. "FROM $table " . "FROM $table "
. "WHERE master_cnt <> this_cnt OR master_crc <> this_crc " . "WHERE master_cnt <> this_cnt OR master_crc <> this_crc "
. "OR ISNULL(master_crc) <> ISNULL(this_crc)"; . "OR ISNULL(master_crc) <> ISNULL(this_crc)";
PTDEBUG && _d($sql); PTDEBUG && _d($sql);
my $diffs = $dbh->selectall_arrayref($sql, { Slice => {} }); my $diffs = $dbh->selectall_arrayref($sql, { Slice => {} });
return @$diffs; return $diffs;
} }
sub _d { sub _d {
+32 -5
View File
@@ -29,7 +29,7 @@ elsif ( !$slave_dbh ) {
plan skip_all => 'Cannot connect to sandbox slave'; plan skip_all => 'Cannot connect to sandbox slave';
} }
else { else {
plan tests => 6; plan tests => 8;
} }
# Previous tests slave 12347 to 12346 which makes pt-table-checksum # Previous tests slave 12347 to 12346 which makes pt-table-checksum
@@ -109,9 +109,7 @@ is(
# pt-table-sync --ignore-* options don't work with --replicate # pt-table-sync --ignore-* options don't work with --replicate
# https://bugs.launchpad.net/percona-toolkit/+bug/1002365 # https://bugs.launchpad.net/percona-toolkit/+bug/1002365
# ############################################################################# # #############################################################################
$sb->wipe_clean($master_dbh);
$master_dbh->do("DROP DATABASE IF EXISTS percona");
$master_dbh->do("DROP DATABASE IF EXISTS test");
$sb->load_file("master", "t/pt-table-sync/samples/simple-tbls.sql"); $sb->load_file("master", "t/pt-table-sync/samples/simple-tbls.sql");
PerconaTest::wait_for_table($slave_dbh, "test.mt1", "id=10"); PerconaTest::wait_for_table($slave_dbh, "test.mt1", "id=10");
@@ -121,7 +119,7 @@ PerconaTest::wait_for_table($slave_dbh, "test.mt1", "id=10");
$slave_dbh->do("INSERT INTO test.empty_it VALUES (null,11,11,'eleven')"); $slave_dbh->do("INSERT INTO test.empty_it VALUES (null,11,11,'eleven')");
# Create the checksums. # Create the checksums.
diag(`$trunk/bin/pt-table-checksum h=127.1,P=12345,u=msandbox,p=msandbox -d test --quiet --lock-wait-timeout 3 --max-load ''`); diag(`$trunk/bin/pt-table-checksum h=127.1,P=12345,u=msandbox,p=msandbox -d test --quiet --quiet --lock-wait-timeout 3 --max-load ''`);
# Make sure all the tables were checksummed. # Make sure all the tables were checksummed.
my $rows = $master_dbh->selectall_arrayref("SELECT DISTINCT db, tbl FROM percona.checksums ORDER BY db, tbl"); my $rows = $master_dbh->selectall_arrayref("SELECT DISTINCT db, tbl FROM percona.checksums ORDER BY db, tbl");
@@ -151,6 +149,35 @@ is(
"Table ignored, nothing to sync (bug 1002365)" "Table ignored, nothing to sync (bug 1002365)"
); );
# Sync the checksummed tables, but ignore the database.
$output = output(
sub { pt_table_sync::main("h=127.1,P=12346,u=msandbox,p=msandbox",
qw(--print --sync-to-master --replicate percona.checksums),
"--ignore-databases", "test") },
stderr => 1,
);
is(
$output,
"",
"Database ignored, nothing to sync (bug 1002365)"
);
# The same should work for just --sync-to-master.
$output = output(
sub { pt_table_sync::main("h=127.1,P=12346,u=msandbox,p=msandbox",
qw(--print --sync-to-master),
"--ignore-tables", "test.empty_it",
"--ignore-databases", "percona") },
stderr => 1,
);
unlike(
$output,
qr/empty_it/,
"Table ignored, nothing to sync-to-master (bug 1002365)"
);
# ############################################################################# # #############################################################################
# Done. # Done.
# ############################################################################# # #############################################################################