Merge lp:~percona-toolkit-dev/percona-toolkit/fix-sync-ignore-bug-1002365 into lp:percona-toolkit/2.1

Proposed by Daniel Nichter
Status: Merged
Merged at revision: 260
Proposed branch: lp:~percona-toolkit-dev/percona-toolkit/fix-sync-ignore-bug-1002365
Merge into: lp:percona-toolkit/2.1
Diff against target: 286 lines (+127/-47)
3 files modified
bin/pt-table-sync (+52/-44)
lib/TableChecksum.pm (+1/-2)
t/pt-table-sync/filters.t (+74/-1)
To merge this branch: bzr merge lp:~percona-toolkit-dev/percona-toolkit/fix-sync-ignore-bug-1002365
Reviewer Review Type Date Requested Status
Daniel Nichter Approve
Review via email: mp+106712@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Daniel Nichter (daniel-nichter) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/pt-table-sync'
2--- bin/pt-table-sync 2012-05-17 14:54:36 +0000
3+++ bin/pt-table-sync 2012-05-21 21:57:26 +0000
4@@ -4248,10 +4248,9 @@
5 . "FROM $table "
6 . "WHERE master_cnt <> this_cnt OR master_crc <> this_crc "
7 . "OR ISNULL(master_crc) <> ISNULL(this_crc)";
8-
9 PTDEBUG && _d($sql);
10 my $diffs = $dbh->selectall_arrayref($sql, { Slice => {} });
11- return @$diffs;
12+ return $diffs;
13 }
14
15 sub _d {
16@@ -7988,11 +7987,16 @@
17 tbl => undef, # set later
18 };
19
20- # Filters for --databases and --tables. We have to do these manually
21- # since we don't use MySQLFind for --replicate.
22- my $databases = $o->get('databases');
23- my $tables = $o->get('tables');
24+ # Used to filter which tables are synced.
25+ # https://bugs.launchpad.net/percona-toolkit/+bug/1002365
26+ my $schema_iter = new SchemaIterator(
27+ dbh => $src->{dbh},
28+ OptionParser => $o,
29+ TableParser => $args{TableParser},
30+ Quoter => $args{Quoter},
31+ );
32
33+ my %skip_table;
34 my $exit_status = 0;
35
36 # Connect to the master and treat it as the source, then find
37@@ -8008,30 +8012,29 @@
38
39 # First, check that the master (source) has no discrepancies itself,
40 # and ignore tables that do.
41- my %skip_table;
42- map { $skip_table{$_->{db}}->{$_->{tbl}}++ }
43- $checksum->find_replication_differences(
44- $src->{dbh}, $o->get('replicate'));
45+ my $src_diffs = $checksum->find_replication_differences(
46+ $src->{dbh}, $o->get('replicate'));
47+ map { $skip_table{lc $_->{db}}->{lc $_->{tbl}}++ } @$src_diffs;
48
49 # Now check the slave for differences and sync them if necessary.
50- my @diffs = filter_diffs(
51- \%skip_table,
52- $databases,
53- $tables,
54- $checksum->find_replication_differences(
55- $dst->{dbh}, $o->get('replicate'))
56+ my $dst_diffs = $checksum->find_replication_differences(
57+ $dst->{dbh}, $o->get('replicate'));
58+ my $diffs = filter_diffs(
59+ diffs => $dst_diffs,
60+ SchemaIterator => $schema_iter,
61+ skip_table => \%skip_table,
62 );
63
64 if ( $o->get('verbose') ) {
65- print_header("# Syncing via replication " . $dp->as_string($dst->{dsn})
66+ print_header("# Syncing via replication " .$dp->as_string($dst->{dsn})
67 . ($o->get('dry-run') ?
68 ' in dry-run mode, without accessing or comparing data' : ''));
69 }
70
71- if ( @diffs ) {
72+ if ( $diffs && scalar @$diffs ) {
73 lock_server(src => $src, dst => $dst, %args);
74
75- foreach my $diff ( @diffs ) {
76+ foreach my $diff ( @$diffs ) {
77 $src->{db} = $dst->{db} = $diff->{db};
78 $src->{tbl} = $dst->{tbl} = $diff->{tbl};
79
80@@ -8056,7 +8059,6 @@
81 # The DSN is the master. Connect to each slave, find differences,
82 # then sync them.
83 else {
84- my %skip_table;
85 $ms->recurse_to_slaves(
86 { dbh => $src->{dbh},
87 dsn => $src->{dsn},
88@@ -8064,20 +8066,20 @@
89 recurse => 1,
90 callback => sub {
91 my ( $dsn, $dbh, $level, $parent ) = @_;
92- my @diffs = $checksum
93- ->find_replication_differences($dbh, $o->get('replicate'));
94+ my $all_diffs = $checksum->find_replication_differences(
95+ $dbh, $o->get('replicate'));
96 if ( !$level ) {
97 # This is the master; don't sync any tables that are wrong
98 # here, for obvious reasons.
99- map { $skip_table{$_->{db}}->{$_->{tbl}}++ } @diffs;
100+ map { $skip_table{lc $_->{db}}->{lc $_->{tbl}}++ }
101+ @$all_diffs;
102 }
103 else {
104 # This is a slave.
105- @diffs = filter_diffs(
106- \%skip_table,
107- $databases,
108- $tables,
109- @diffs
110+ my $diffs = filter_diffs(
111+ diffs => $all_diffs,
112+ SchemaIterator => $schema_iter,
113+ skip_table => \%skip_table,
114 );
115
116 if ( $o->get('verbose') ) {
117@@ -8089,7 +8091,7 @@
118 : ''));
119 }
120
121- if ( @diffs ) {
122+ if ( $diffs && scalar @$diffs ) {
123 my $dst = {
124 dsn => $dsn,
125 dbh => $dbh,
126@@ -8100,7 +8102,7 @@
127
128 lock_server(src => $src, dst => $dst, %args);
129
130- foreach my $diff ( @diffs ) {
131+ foreach my $diff ( @$diffs ) {
132 $src->{db} = $dst->{db} = $diff->{db};
133 $src->{tbl} = $dst->{tbl} = $diff->{tbl};
134
135@@ -8794,22 +8796,28 @@
136 # filters. This sub is called in <sync_via_replication()> to implement
137 # schema object filters like --databases and --tables.
138 #
139-# Parameters:
140-# $skip_table - Hashref of databases and tables to skip
141-# $databases - Hashref of databases to skip
142-# $tables - Hashref of tables to skip
143-# @diffs - Array of hashrefs, one for each different slave table
144-#
145 # Returns:
146-# Array of different slave tables that pass the filters
147+# Arrayref of different slave tables that pass the filters
148 sub filter_diffs {
149- my ( $skip_table, $databases, $tables, @diffs ) = @_;
150- return grep {
151- my ($db, $tbl) = $q->split_unquote($_->{table});
152- !$skip_table->{$db}->{$tbl}
153- && (!$databases || $databases->{$db})
154- && (!$tables || ($tables->{$tbl} || $tables->{$_->{table}}))
155- } @diffs;
156+ my ( %args ) = @_;
157+ my @required_args = qw(diffs SchemaIterator skip_table);
158+ foreach my $arg ( @required_args ) {
159+ die "I need a $arg argument" unless $args{$arg};
160+ }
161+ my ($diffs, $si, $skip_table) = @args{@required_args};
162+
163+ my @filtered_diffs;
164+ foreach my $diff ( @$diffs ) {
165+ my $db = lc $diff->{db};
166+ my $tbl = lc $diff->{tbl};
167+ if ( !$skip_table->{$db}->{$tbl}
168+ && $si->database_is_allowed($db)
169+ && $si->table_is_allowed($db, $tbl) ) {
170+ push @filtered_diffs, $diff;
171+ }
172+ }
173+
174+ return \@filtered_diffs;
175 }
176
177 # Sub: disconnect
178
179=== modified file 'lib/TableChecksum.pm'
180--- lib/TableChecksum.pm 2012-01-19 19:46:56 +0000
181+++ lib/TableChecksum.pm 2012-05-21 21:57:26 +0000
182@@ -480,10 +480,9 @@
183 . "FROM $table "
184 . "WHERE master_cnt <> this_cnt OR master_crc <> this_crc "
185 . "OR ISNULL(master_crc) <> ISNULL(this_crc)";
186-
187 PTDEBUG && _d($sql);
188 my $diffs = $dbh->selectall_arrayref($sql, { Slice => {} });
189- return @$diffs;
190+ return $diffs;
191 }
192
193 sub _d {
194
195=== modified file 't/pt-table-sync/filters.t'
196--- t/pt-table-sync/filters.t 2011-12-22 22:43:15 +0000
197+++ t/pt-table-sync/filters.t 2012-05-21 21:57:26 +0000
198@@ -29,7 +29,7 @@
199 plan skip_all => 'Cannot connect to sandbox slave';
200 }
201 else {
202- plan tests => 4;
203+ plan tests => 8;
204 }
205
206 # Previous tests slave 12347 to 12346 which makes pt-table-checksum
207@@ -106,6 +106,79 @@
208 );
209
210 # #############################################################################
211+# pt-table-sync --ignore-* options don't work with --replicate
212+# https://bugs.launchpad.net/percona-toolkit/+bug/1002365
213+# #############################################################################
214+$sb->wipe_clean($master_dbh);
215+
216+$sb->load_file("master", "t/pt-table-sync/samples/simple-tbls.sql");
217+PerconaTest::wait_for_table($slave_dbh, "test.mt1", "id=10");
218+
219+# Create a checksum diff in a table that we're going to ignore
220+# when we sync.
221+$slave_dbh->do("INSERT INTO test.empty_it VALUES (null,11,11,'eleven')");
222+
223+# Create the checksums.
224+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 ''`);
225+
226+# Make sure all the tables were checksummed.
227+my $rows = $master_dbh->selectall_arrayref("SELECT DISTINCT db, tbl FROM percona.checksums ORDER BY db, tbl");
228+is_deeply(
229+ $rows,
230+ [ [qw(test empty_it) ],
231+ [qw(test empty_mt) ],
232+ [qw(test it1) ],
233+ [qw(test it2) ],
234+ [qw(test mt1) ],
235+ [qw(test mt2) ],
236+ ],
237+ "Six checksum tables (bug 1002365)"
238+);
239+
240+# Sync the checksummed tables, but ignore the table with the diff we created.
241+$output = output(
242+ sub { pt_table_sync::main("h=127.1,P=12346,u=msandbox,p=msandbox",
243+ qw(--print --sync-to-master --replicate percona.checksums),
244+ "--ignore-tables", "test.empty_it") },
245+ stderr => 1,
246+);
247+
248+is(
249+ $output,
250+ "",
251+ "Table ignored, nothing to sync (bug 1002365)"
252+);
253+
254+# Sync the checksummed tables, but ignore the database.
255+$output = output(
256+ sub { pt_table_sync::main("h=127.1,P=12346,u=msandbox,p=msandbox",
257+ qw(--print --sync-to-master --replicate percona.checksums),
258+ "--ignore-databases", "test") },
259+ stderr => 1,
260+);
261+
262+is(
263+ $output,
264+ "",
265+ "Database ignored, nothing to sync (bug 1002365)"
266+);
267+
268+# The same should work for just --sync-to-master.
269+$output = output(
270+ sub { pt_table_sync::main("h=127.1,P=12346,u=msandbox,p=msandbox",
271+ qw(--print --sync-to-master),
272+ "--ignore-tables", "test.empty_it",
273+ "--ignore-databases", "percona") },
274+ stderr => 1,
275+);
276+
277+unlike(
278+ $output,
279+ qr/empty_it/,
280+ "Table ignored, nothing to sync-to-master (bug 1002365)"
281+);
282+
283+# #############################################################################
284 # Done.
285 # #############################################################################
286 $sb->wipe_clean($master_dbh);

Subscribers

People subscribed via source and target branches