Merge lp:~percona-toolkit-dev/percona-toolkit/pt-duplicate-key-checker-skips-report-when-verbose-on-1402730 into lp:~percona-toolkit-dev/percona-toolkit/release-2.2.14

Proposed by Frank Cizmich
Status: Merged
Approved by: Daniel Nichter
Approved revision: 616
Merged at revision: 614
Proposed branch: lp:~percona-toolkit-dev/percona-toolkit/pt-duplicate-key-checker-skips-report-when-verbose-on-1402730
Merge into: lp:~percona-toolkit-dev/percona-toolkit/release-2.2.14
Diff against target: 285 lines (+89/-62)
5 files modified
bin/pt-duplicate-key-checker (+61/-51)
t/pt-duplicate-key-checker/basics.t (+15/-2)
t/pt-duplicate-key-checker/issue_331.t (+2/-2)
t/pt-duplicate-key-checker/samples/issue_331.txt (+3/-3)
t/pt-duplicate-key-checker/samples/simple_dupe_bug_1217013.txt (+8/-4)
To merge this branch: bzr merge lp:~percona-toolkit-dev/percona-toolkit/pt-duplicate-key-checker-skips-report-when-verbose-on-1402730
Reviewer Review Type Date Requested Status
Daniel Nichter Approve
David Bennett (community) Needs Fixing
Review via email: mp+253857@code.launchpad.net

Description of the change

pt-duplicate-key-checker did not work when --verbose option was set
It simply seems an small error in the code made it skip the reporting functions when verbose was set.

Note: also tweaked test case to catch this.

Note2: also added warning about FULLTEXT indexes not being computed in total size, when they exist and are duplicated.

To post a comment you must log in.
Revision history for this message
David Bennett (dbpercona) wrote :

Size of duplicate full text indexes is computed and reported as 0

Due to the variant nature of ft indexes, it would be best to avoid trying to compute the estimated size. I recommend changing the report line to:

  Size Duplicate Indexes ### (not including FULLTEXT indexes)

----

CREATE TABLE `ai5` (
  `id` int(11) NOT NULL,
  `c1` int(11) DEFAULT NULL,
  `c2` int(11) DEFAULT NULL,
  `c3` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`),
  FULLTEXT KEY `c3` (`c3`),
  FULLTEXT KEY `c3_2` (`c3`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

$ ./pt-duplicate-key-checker --verbose --tables=test.ai5
# ########################################################################
# test.ai5
# ########################################################################

# c3_2 (`c3`)
# PRIMARY (`id`)
# c3 (`c3`)

# c3_2 is a duplicate of c3
# Key definitions:
# FULLTEXT KEY `c3_2` (`c3`)
# FULLTEXT KEY `c3` (`c3`),
# Column types:
# `c3` varchar(64) default null
# To remove this duplicate index, execute:
ALTER TABLE `test`.`ai5` DROP INDEX `c3_2`;

# ########################################################################
# Summary of indexes
# ########################################################################

# Size Duplicate Indexes 0
# Total Duplicate Indexes 1
# Total Indexes 3

review: Needs Fixing
Revision history for this message
David Bennett (dbpercona) wrote :

Another edge case that fails, full column unique index duplicating partial unique column index, this should be reported.

---

cat <<EOF |
CREATE TABLE ai6 (
  id int(11) NOT NULL,
  c1 int(11) DEFAULT NULL,
  c2 int(11) DEFAULT NULL,
  c3 varchar(64) DEFAULT NULL,
  c4 varchar(64) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- OLD index entire column
CREATE UNIQUE INDEX c3_full ON ai6 (c3);

-- NEW enforce first 5 characters being unique
CREATE UNIQUE INDEX c3_partial ON ai6 (c3(5));

EOF
mysql -B test
bin/pt-duplicate-key-checker -d test -t ai6

review: Needs Fixing
Revision history for this message
David Bennett (dbpercona) wrote :

Previous comment (630899) appears to be an intermittent failure:

---

$ bin/pt-duplicate-key-checker -d test -t ai6
# ########################################################################
# test.ai6
# ########################################################################

# Uniqueness of c3_full ignored because c3_part is a duplicate constraint
# c3_full is a left-prefix of c3_part
# Key definitions:
# UNIQUE KEY `c3_full` (`c3`),
# UNIQUE KEY `c3_part` (`c3`(5))
# Column types:
# `c3` varchar(64) default null
# To remove this duplicate index, execute:
ALTER TABLE `test`.`ai6` DROP INDEX `c3_full`;

# ########################################################################
# Summary of indexes
# ########################################################################

# Size Duplicate Indexes 67
# Total Duplicate Indexes 1
# Total Indexes 3
$ bin/pt-duplicate-key-checker -d test -t ai6
# ########################################################################
# Summary of indexes
# ########################################################################

# Total Indexes 3
$ bin/pt-duplicate-key-checker -d test -t ai6
# ########################################################################
# Summary of indexes
# ########################################################################

# Total Indexes 3
$ bin/pt-duplicate-key-checker -d test -t ai6
# ########################################################################
# test.ai6
# ########################################################################

# Uniqueness of c3_full ignored because c3_part is a duplicate constraint
# c3_full is a left-prefix of c3_part
# Key definitions:
# UNIQUE KEY `c3_full` (`c3`),
# UNIQUE KEY `c3_part` (`c3`(5))
# Column types:
# `c3` varchar(64) default null
# To remove this duplicate index, execute:
ALTER TABLE `test`.`ai6` DROP INDEX `c3_full`;

# ########################################################################
# Summary of indexes
# ########################################################################

# Size Duplicate Indexes 67
# Total Duplicate Indexes 1
# Total Indexes 3

review: Needs Fixing
Revision history for this message
Frank Cizmich (frank-cizmich) wrote :

Reported intermitent issue as a separate bug.
https://bugs.launchpad.net/percona-toolkit/+bug/1436399

Let's narrow this fix to the original --verbose issue and that the tool issue a warning that FULLTEXT indexes are not computed in the reported total size of duplicates.

615. By Frank Cizmich

Added warning about size of fulltext keys not being computed, if present. Sort key report by key name for ease of testing.

616. By Frank Cizmich

Added sort to some hash loops to make tests consistent. Modified test files accordingly

Revision history for this message
Daniel Nichter (daniel-nichter) wrote :

Did this fix become something else because I don't see where "verbose" is referenced in the diff below? I was expecting to see something like:

- if ( !$opts->{verbose) {
- report()
- }
+ report()

review: Needs Information
Revision history for this message
Frank Cizmich (frank-cizmich) wrote :

The "verbose" part was not visible in the context.

Old code:

            if ( $o->got('verbose') ) {
               print_all_keys($keys, $tbl, \%seen_tbl) if $keys;
               print_all_keys($fks, $tbl, \%seen_tbl) if $fks;
            }
            else {
               PTDEBUG && _d('Getting duplicate keys on',
                  $tbl->{db}, $tbl->{tbl});
                ....etc
New code:

            if ( $o->got('verbose') ) {
               print_all_keys($keys, $tbl, \%seen_tbl) if $keys;
               print_all_keys($fks, $tbl, \%seen_tbl) if $fks;
            }
            PTDEBUG && _d('Getting duplicate keys on',
               $tbl->{db}, $tbl->{tbl});
               ....etc

Revision history for this message
Daniel Nichter (daniel-nichter) wrote :

Ah, I see it now.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/pt-duplicate-key-checker'
2--- bin/pt-duplicate-key-checker 2015-01-23 10:19:56 +0000
3+++ bin/pt-duplicate-key-checker 2015-03-26 18:43:21 +0000
4@@ -2336,7 +2336,8 @@
5 my @dupes;
6
7 KEY:
8- foreach my $key ( values %keys ) {
9+ # sort by key name for consistent testing
10+ foreach my $key ( sort {$a->{name} cmp $b->{name}} values %keys ) {
11 $key->{real_cols} = [ @{$key->{cols}} ];
12
13 $key->{len_cols} = length $key->{colnames};
14@@ -2412,7 +2413,8 @@
15 sub get_duplicate_fks {
16 my ( $self, $fks, %args ) = @_;
17 die "I need a fks argument" unless $fks;
18- my @fks = values %$fks;
19+ # sort by name for consistent testing
20+ my @fks = sort {$a->{name} cmp $b->{name}} values %$fks;
21 my @dupes;
22
23 foreach my $i ( 0..$#fks - 1 ) {
24@@ -4881,7 +4883,7 @@
25 sub main {
26 local @ARGV = @_; # set global ARGV for this package
27
28- my %summary = ( 'Total Indexes' => 0 );
29+ my %summary = ( 'items' => {'Total Indexes' => 0} );
30 my %seen_tbl;
31
32 my $q = new Quoter();
33@@ -4972,51 +4974,49 @@
34 print_all_keys($keys, $tbl, \%seen_tbl) if $keys;
35 print_all_keys($fks, $tbl, \%seen_tbl) if $fks;
36 }
37- else {
38- PTDEBUG && _d('Getting duplicate keys on',
39- $tbl->{db}, $tbl->{tbl});
40- if ( $keys ) {
41- $dk->get_duplicate_keys(
42- $keys,
43- clustered_key => $clustered_key,
44- tbl_info => $tbl,
45- callback => \&print_duplicate_key,
46- %tp_opts,
47- # get_duplicate_keys() ignores these args but passes them
48- # to the callback:
49- dbh => $dbh,
50- is_fk => 0,
51- o => $o,
52- ks => $ks,
53- tp => $tp,
54- q => $q,
55- seen_tbl => \%seen_tbl,
56- summary => \%summary,
57- );
58- }
59- if ( $fks ) {
60- $dk->get_duplicate_fks(
61- $fks,
62- tbl_info => $tbl,
63- callback => \&print_duplicate_key,
64- %tp_opts,
65- # get_duplicate_fks() ignores these args but passes them
66- # to the callback:
67- dbh => $dbh,
68- is_fk => 1,
69- o => $o,
70- ks => $ks,
71- tp => $tp,
72- q => $q,
73- seen_tbl => \%seen_tbl,
74- summary => \%summary,
75- );
76- }
77+ PTDEBUG && _d('Getting duplicate keys on',
78+ $tbl->{db}, $tbl->{tbl});
79+ if ( $keys ) {
80+ $dk->get_duplicate_keys(
81+ $keys,
82+ clustered_key => $clustered_key,
83+ tbl_info => $tbl,
84+ callback => \&print_duplicate_key,
85+ %tp_opts,
86+ # get_duplicate_keys() ignores these args but passes them
87+ # to the callback:
88+ dbh => $dbh,
89+ is_fk => 0,
90+ o => $o,
91+ ks => $ks,
92+ tp => $tp,
93+ q => $q,
94+ seen_tbl => \%seen_tbl,
95+ summary => \%summary,
96+ );
97+ }
98+ if ( $fks ) {
99+ $dk->get_duplicate_fks(
100+ $fks,
101+ tbl_info => $tbl,
102+ callback => \&print_duplicate_key,
103+ %tp_opts,
104+ # get_duplicate_fks() ignores these args but passes them
105+ # to the callback:
106+ dbh => $dbh,
107+ is_fk => 1,
108+ o => $o,
109+ ks => $ks,
110+ tp => $tp,
111+ q => $q,
112+ seen_tbl => \%seen_tbl,
113+ summary => \%summary,
114+ );
115 }
116
117 # Always count Total Keys so print_key_summary won't die
118 # because %summary is empty.
119- $summary{'Total Indexes'} += (scalar keys %$keys)
120+ $summary{items}->{'Total Indexes'} += (scalar keys %$keys)
121 + (scalar keys %$fks)
122 }
123 };
124@@ -5044,7 +5044,8 @@
125 printf $hdr_fmt, "$db.$tbl";
126 printf $hdr_fmt, ('#' x $hdr_width);
127 }
128- foreach my $key ( values %$keys ) {
129+ # Print keys sorted by name (easier to test)
130+ foreach my $key ( sort {$a->{name} cmp $b->{name}} values %$keys ) {
131 print "\n# $key->{name} ($key->{colnames})";
132 }
133 print "\n";
134@@ -5069,6 +5070,10 @@
135 my $summary = $args{summary};
136 my $struct = $tp->parse($args{tbl_info}->{ddl});
137
138+ if ($dupe->{ddl} =~ /FULLTEXT/) {
139+ $summary->{has_fulltext_dupe}++;
140+ }
141+
142 if ( !$seen_tbl->{"$db$tbl"}++ ) {
143 printf $hdr_fmt, ('#' x $hdr_width);
144 printf $hdr_fmt, "$db.$tbl";
145@@ -5111,7 +5116,7 @@
146 print "\n";
147
148 if ( $o->get('summary') && $summary ) {
149- $summary->{'Total Duplicate Indexes'} += 1;
150+ $summary->{'items'}->{'Total Duplicate Indexes'} += 1;
151 my ($size, $chosen_key) = $ks->get_key_size(
152 name => $dupe->{key},
153 cols => $dupe->{cols},
154@@ -5128,7 +5133,7 @@
155 $size ||= 0;
156
157 # Create Size Duplicate Keys summary even if there's no valid keys.
158- $summary->{'Size Duplicate Indexes'} += $size;
159+ $summary->{'items'}->{'Size Duplicate Indexes'} += $size;
160
161 if ( $size ) {
162 if ( $chosen_key && $chosen_key ne $dupe->{key} ) {
163@@ -5143,14 +5148,19 @@
164
165 sub print_key_summary {
166 my ( %summary ) = @_;
167+ my $items = $summary{items};
168 printf $hdr_fmt, ('#' x $hdr_width);
169 printf $hdr_fmt, 'Summary of indexes';
170 printf $hdr_fmt, ('#' x $hdr_width);
171 print "\n";
172- my $max_item = max(map { length($_) } keys %summary);
173- my $line_fmt = "# %-${max_item}s %-s\n";
174- foreach my $item ( sort keys %summary ) {
175- printf $line_fmt, $item, $summary{$item};
176+ my $max_item = max(map { length($_) } keys %$items);
177+ my $line_fmt = "# %-${max_item}s %-s";
178+ foreach my $item ( sort keys %$items ) {
179+ printf $line_fmt, $item, $items->{$item};
180+ if ( $item eq 'Size Duplicate Indexes' && $summary{has_fulltext_dupe} ) {
181+ print ' (not including FULLTEXT indexes)';
182+ }
183+ print "\n";
184 }
185 return;
186 }
187
188=== modified file 't/pt-duplicate-key-checker/basics.t'
189--- t/pt-duplicate-key-checker/basics.t 2013-12-12 03:39:09 +0000
190+++ t/pt-duplicate-key-checker/basics.t 2015-03-26 18:43:21 +0000
191@@ -142,12 +142,25 @@
192
193 ok(
194 no_diff(
195- sub { pt_duplicate_key_checker::main(@args, qw(-t test.domains)) },
196- "$sample/simple_dupe_bug_1217013.txt"),
197+ sub { pt_duplicate_key_checker::main(@args, qw(-t test.domains -v)) },
198+ "$sample/simple_dupe_bug_1217013.txt", keep_output=>1),
199 'Exact unique dupes (bug 1217013)'
200 ) or diag($test_diff);
201
202 # #############################################################################
203+# Same thing, but added --verbose option to test for:
204+# https://bugs.launchpad.net/percona-toolkit/+bug/1402730
205+# #############################################################################
206+
207+ok(
208+ no_diff(
209+ sub { pt_duplicate_key_checker::main(@args, qw(-t test.domains --verbose)) },
210+ "$sample/simple_dupe_bug_1217013.txt", keep_output=>1),
211+ q[--verbose option doesn't skip dupes reporting (bug 1402730)]
212+) or diag($test_diff);
213+
214+
215+# #############################################################################
216 # Done.
217 # #############################################################################
218 $sb->wipe_clean($dbh);
219
220=== modified file 't/pt-duplicate-key-checker/issue_331.t'
221--- t/pt-duplicate-key-checker/issue_331.t 2012-06-03 19:14:30 +0000
222+++ t/pt-duplicate-key-checker/issue_331.t 2015-03-26 18:43:21 +0000
223@@ -41,10 +41,10 @@
224 ok(
225 no_diff(
226 sub { pt_duplicate_key_checker::main(@args, qw(-d issue_331)) },
227- 't/pt-duplicate-key-checker/samples/issue_331.txt',
228+ 't/pt-duplicate-key-checker/samples/issue_331.txt'
229 ),
230 'Issue 331 crash on fks'
231-);
232+) or diag($test_diff);
233
234 # #############################################################################
235 # Done.
236
237=== modified file 't/pt-duplicate-key-checker/samples/issue_331.txt'
238--- t/pt-duplicate-key-checker/samples/issue_331.txt 2011-06-24 22:02:05 +0000
239+++ t/pt-duplicate-key-checker/samples/issue_331.txt 2015-03-26 18:43:21 +0000
240@@ -2,14 +2,14 @@
241 # issue_331.issue_331_t2
242 # ########################################################################
243
244-# FOREIGN KEY fk_1 (`id`) REFERENCES `issue_331`.`issue_331_t1` (`t1_id`) is a duplicate of FOREIGN KEY fk_2 (`id`) REFERENCES `issue_331`.`issue_331_t1` (`t1_id`)
245+# FOREIGN KEY fk_2 (`id`) REFERENCES `issue_331`.`issue_331_t1` (`t1_id`) is a duplicate of FOREIGN KEY fk_1 (`id`) REFERENCES `issue_331`.`issue_331_t1` (`t1_id`)
246 # Key definitions:
247+# CONSTRAINT `fk_2` FOREIGN KEY (`id`) REFERENCES `issue_331_t1` (`t1_id`)
248 # CONSTRAINT `fk_1` FOREIGN KEY (`id`) REFERENCES `issue_331_t1` (`t1_id`)
249-# CONSTRAINT `fk_2` FOREIGN KEY (`id`) REFERENCES `issue_331_t1` (`t1_id`)
250 # Column types:
251 # `id` bigint(20) not null default '0'
252 # To remove this duplicate foreign key, execute:
253-ALTER TABLE `issue_331`.`issue_331_t2` DROP FOREIGN KEY `fk_1`;
254+ALTER TABLE `issue_331`.`issue_331_t2` DROP FOREIGN KEY `fk_2`;
255
256 # MySQL uses the PRIMARY index for this foreign key constraint
257
258
259=== modified file 't/pt-duplicate-key-checker/samples/simple_dupe_bug_1217013.txt'
260--- t/pt-duplicate-key-checker/samples/simple_dupe_bug_1217013.txt 2013-12-12 03:39:09 +0000
261+++ t/pt-duplicate-key-checker/samples/simple_dupe_bug_1217013.txt 2015-03-26 18:43:21 +0000
262@@ -2,15 +2,19 @@
263 # test.domains
264 # ########################################################################
265
266-# Uniqueness of domain ignored because unique_key_domain is a duplicate constraint
267-# domain is a duplicate of unique_key_domain
268+# PRIMARY (`id`)
269+# domain (`domain`)
270+# unique_key_domain (`domain`)
271+
272+# Uniqueness of unique_key_domain ignored because domain is a duplicate constraint
273+# unique_key_domain is a duplicate of domain
274 # Key definitions:
275+# UNIQUE KEY `unique_key_domain` (`domain`)
276 # UNIQUE KEY `domain` (`domain`),
277-# UNIQUE KEY `unique_key_domain` (`domain`)
278 # Column types:
279 # `domain` varchar(175) collate utf8_bin not null
280 # To remove this duplicate index, execute:
281-ALTER TABLE `test`.`domains` DROP INDEX `domain`;
282+ALTER TABLE `test`.`domains` DROP INDEX `unique_key_domain`;
283
284 # ########################################################################
285 # Summary of indexes

Subscribers

People subscribed via source and target branches

to all changes: