Merge lp:~akopytov/percona-xtrabackup/bug1130627-2.0 into lp:percona-xtrabackup/2.0

Proposed by Alexey Kopytov
Status: Merged
Approved by: Sergei Glushchenko
Approved revision: no longer in the source branch.
Merged at revision: 512
Proposed branch: lp:~akopytov/percona-xtrabackup/bug1130627-2.0
Merge into: lp:percona-xtrabackup/2.0
Diff against target: 351 lines (+183/-55)
3 files modified
innobackupex (+38/-17)
src/xtrabackup.cc (+71/-38)
test/t/bug1130627.sh (+74/-0)
To merge this branch: bzr merge lp:~akopytov/percona-xtrabackup/bug1130627-2.0
Reviewer Review Type Date Requested Status
Sergei Glushchenko (community) g2 Approve
Review via email: mp+151895@code.launchpad.net

Description of the change

    Bug #1130627: Can't backup individual partitions

    The bug is a regression introduced in 2.0.5 by the fix for bug
    #711166. The fix introduced partition suffix ('#P#...') trimming in
    tables names before checking them against regular expressions specified
    by the --include option in innobackupex or the --tables option in
    xtrabackup. Which made impossible partial backups of partitioned tables.

    Fixed in both innobackupex and xtrabackup by first checking the table
    name without the suffix trimmed, and then repeating the check with the
    suffix trimmed if the former check fails.

    This patch also fixes bug #1131084 "Unneccessary/debug print in
    xtrabackup output" and a few other minor issues introduced by the fix
    for bug #711166.

http://jenkins.percona.com/view/XtraBackup/job/percona-xtrabackup-2.0-param/357/

To post a comment you must log in.
Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

Alexey,

* get_table_name_with_part_suffic - is it a typo?
* innobackupex change affects only --include option (which is regex) and
  doesn't affects --databases option, i.e. with --databases option individual
  partitions still cannot be backed up
* while xtrabackup change affects both --tables and --tables-file (one with regexp, another one without)
  which looks to me as kind of inconsistency
* check_if_table_matches_regexps doesn't look like a good name since it not
  only matches against regexps, but also against table names from --tables-file
* would also be nice to have testcases which take a backup only of some partitions
  with different combinations of options

review: Needs Fixing (g2)
Revision history for this message
Alexey Kopytov (akopytov) wrote :

Hi Sergei,

On Thu, 07 Mar 2013 05:26:19 -0000, Sergei Glushchenko wrote:
> Review: Needs Fixing g2
>
> Alexey,
>
> * get_table_name_with_part_suffic - is it a typo?

Yes, thanks.

> * innobackupex change affects only --include option (which is regex) and
> doesn't affects --databases option, i.e. with --databases option individual
> partitions still cannot be backed up

Yes, I've made all the necessary corrections for --databases and
--tables-file, but --databases is currently broken due to bug #569387.
So the corresponding part of the test case should be uncommented once fixed.

> * while xtrabackup change affects both --tables and --tables-file (one with regexp, another one without)
> which looks to me as kind of inconsistency

Yep, it should now be consistent.

> * check_if_table_matches_regexps doesn't look like a good name since it not
> only matches against regexps, but also against table names from --tables-file

Agree, renamed to check_if_table_matches_filters()

> * would also be nice to have testcases which take a backup only of some partitions
> with different combinations of options
>

Added, with the caveat re. --databases mentioned above.

I'm currently waiting on Jenkins runs, will update the MP when they are
done.

Revision history for this message
Alexey Kopytov (akopytov) wrote :
Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

Alexey,

Everything looks good except I don't see testcase, which you mentioned as added. Probably you forget to bzr add them?

Revision history for this message
Sergei Glushchenko (sergei.glushchenko) :
review: Needs Fixing (g2)
Revision history for this message
Alexey Kopytov (akopytov) wrote :

Whoops :) Good catch!

Revision history for this message
Alexey Kopytov (akopytov) wrote :
Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

Approve

review: Approve (g2)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'innobackupex'
2--- innobackupex 2013-02-04 07:32:47 +0000
3+++ innobackupex 2013-03-07 11:50:26 +0000
4@@ -1137,12 +1137,14 @@
5 foreach $file (@list) {
6 next unless check_if_required($subdir, $file);
7 if($option_include) {
8- my $table_name;
9-
10- $table_name = get_table_name($file);
11-
12- if (!("$subdir.$table_name" =~ /$option_include/)) {
13- print STDERR "'$file' is skipped.\n";
14+ my $table = get_table_name($file);
15+ my $table_part = get_table_name_with_part_suffix($file);
16+
17+ if (!("$subdir.$table_part" =~ /$option_include/ ||
18+ "$subdir.$table" =~ /$option_include/)) {
19+ if ($print_each_file) {
20+ print STDERR "'$file' is skipped.\n";
21+ }
22 next;
23 }
24 }
25@@ -2177,13 +2179,18 @@
26 next unless check_if_required($database, $file);
27
28 if($option_include) {
29- my $table_name = get_table_name($file);
30- if (!("$database.$table_name" =~ /$option_include/)) {
31- print STDERR "$database.$file is skipped because it does not match $option_include.\n";
32- next;
33- }
34+ my $table = get_table_name($file);
35+ my $table_part = get_table_name_with_part_suffix($file);
36+
37+ if (!("$database.$table_part" =~ /$option_include/ ||
38+ "$database.$table" =~ /$option_include/)) {
39+
40+ if ($print_each_file) {
41+ print STDERR "$database.$file is skipped because it does not match '$option_include'.\n";
42+ }
43+ next;
44+ }
45 }
46-
47
48 if ($print_each_file) {
49 print STDERR "$prefix Backing up file '$source_dir/$database/$file'\n";
50@@ -2519,6 +2526,17 @@
51 # 1 table name
52 #
53 sub get_table_name {
54+ my $table;
55+
56+ $table = get_table_name_with_part_suffix($_[0]);
57+ # trim partition suffix
58+ $table = (split('#P#', $table))[0];
59+
60+ return $table;
61+}
62+
63+# Like get_table_name(), but keeps the partition suffix if present
64+sub get_table_name_with_part_suffix {
65 my $table_path = shift;
66 my $filename;
67 my $table;
68@@ -2527,8 +2545,6 @@
69 $filename = (reverse(split(/\//, $table_path)))[0];
70 # get name of the table by removing file suffix
71 $table = (split(/\./, $filename))[0];
72- # and partition suffix
73- $table = (split('#P#', $table))[0];
74
75 return $table;
76 }
77@@ -2546,14 +2562,16 @@
78 my $db_count = scalar keys %databases_list;
79 my $tbl_count = scalar keys %table_list;
80 my $table;
81+ my $table_part;
82
83 if ( $db_count == 0 && $tbl_count == 0 ) {
84 # No databases defined with --databases option, include all databases,
85 # and no tables defined with --tables-file option, include all tables.
86- return 1;
87+ return 1;
88 }
89 else {
90 if ( $table_path ) {
91+ $table_part = get_table_name_with_part_suffix($table_path);
92 $table = get_table_name($table_path);
93 }
94 }
95@@ -2564,7 +2582,9 @@
96 if (defined $table_path) {
97 my $db_hash = $databases_list{$db};
98 $db_count = keys %$db_hash;
99- if ($db_count > 0 && ! defined $databases_list{$db}->{$table}) {
100+ if ($db_count > 0 &&
101+ !defined $databases_list{$db}->{$table_part} &&
102+ !defined $databases_list{$db}->{$table}) {
103 # --databases option specified, but table is not included
104 return 0;
105 }
106@@ -2581,7 +2601,8 @@
107 # Filter for --tables-file.
108 if ( $tbl_count ) {
109 return 0 unless exists $table_list{$db};
110- return 0 if $table && !$table_list{$db}->{$table};
111+ return 0 if $table && !$table_list{$db}->{$table_part} &&
112+ !$table_list{$db}->{$table};
113 }
114
115 return 1; # backup the table
116
117=== modified file 'src/xtrabackup.cc'
118--- src/xtrabackup.cc 2013-03-01 06:54:51 +0000
119+++ src/xtrabackup.cc 2013-03-07 11:50:26 +0000
120@@ -2971,6 +2971,46 @@
121 }
122
123 /************************************************************************
124+Checks if a given table name matches any of specifications in the --tables or
125+--tables-file options.
126+
127+@return TRUE on match. */
128+static my_bool
129+check_if_table_matches_filters(const char *name)
130+{
131+ int regres;
132+ int i;
133+ xtrabackup_tables_t* table;
134+
135+ if (xtrabackup_tables) {
136+
137+ regres = REG_NOMATCH;
138+
139+ for (i = 0; i < tables_regex_num; i++) {
140+ regres = xb_regexec(&tables_regex[i], name, 1,
141+ tables_regmatch, 0);
142+ if (regres != REG_NOMATCH) {
143+
144+ return(TRUE);
145+ }
146+ }
147+ }
148+
149+ if (xtrabackup_tables_file) {
150+
151+ XB_HASH_SEARCH(name_hash, tables_hash, ut_fold_string(name),
152+ table, (void) 0,
153+ !strcmp(table->name, name));
154+ if (table) {
155+
156+ return(TRUE);
157+ }
158+ }
159+
160+ return(FALSE);
161+}
162+
163+/************************************************************************
164 Checks if a table specified as a path should be skipped from backup
165 based on the --tables or --tables-file options.
166
167@@ -3009,37 +3049,24 @@
168 }
169 buf[dbname_len - 1] = 0;
170
171+ /* For partitioned tables first try to match against the regexp
172+ without truncating the #P#... suffix so we can backup individual
173+ partitions with regexps like '^test[.]t#P#p5' */
174+ if (check_if_table_matches_filters(buf)) {
175+
176+ return(FALSE);
177+ }
178 if ((eptr = strstr(buf, "#P#")) != NULL) {
179+
180 *eptr = 0;
181- }
182-
183- if (xtrabackup_tables) {
184- int regres = REG_NOMATCH;
185- int i;
186- for (i = 0; i < tables_regex_num; i++) {
187- regres = xb_regexec(&tables_regex[i], buf, 1,
188- tables_regmatch, 0);
189- if (regres != REG_NOMATCH) {
190- break;
191- }
192- }
193- if (regres == REG_NOMATCH) {
194- return(TRUE);
195- }
196- }
197-
198- if (xtrabackup_tables_file) {
199- xtrabackup_tables_t* table;
200-
201- XB_HASH_SEARCH(name_hash, tables_hash, ut_fold_string(buf),
202- table, (void) 0,
203- !strcmp(table->name, buf));
204- if (!table) {
205- return(TRUE);
206- }
207- }
208-
209- return(FALSE);
210+
211+ if (check_if_table_matches_filters(buf)) {
212+
213+ return(FALSE);
214+ }
215+ }
216+
217+ return(TRUE);
218 }
219
220 /***********************************************************************
221@@ -3313,8 +3340,7 @@
222
223 if ((!trx_sys_sys_space(node->space->id))
224 && check_if_skip_table(node->name, "ibd")) {
225- printf("[%02u] Skipping %s.\n",
226- thread_n, node->name);
227+ msg("[%02u] Skipping %s.\n", thread_n, node->name);
228 return(FALSE);
229 }
230
231@@ -4337,6 +4363,8 @@
232
233 p = xtrabackup_tables;
234 for (i=0; i < tables_regex_num; i++) {
235+ int rc;
236+
237 next = strchr(p, ',');
238 ut_a(next || i == tables_regex_num - 1);
239
240@@ -4344,10 +4372,18 @@
241 if (i != tables_regex_num - 1)
242 *(next - 1) = '\0';
243
244- xb_regerror(xb_regcomp(&tables_regex[i], p,
245- REG_EXTENDED),
246- &tables_regex[i], errbuf, sizeof(errbuf));
247- msg("xtrabackup: tables regcomp(%s): %s\n", p, errbuf);
248+ rc = xb_regcomp(&tables_regex[i], p,
249+ REG_EXTENDED);
250+
251+ if (rc) {
252+
253+ xb_regerror(rc, &tables_regex[i], errbuf,
254+ sizeof(errbuf));
255+ msg("xtrabackup: regcomp(%s) failed: %s\n",
256+ p, errbuf);
257+
258+ exit(EXIT_FAILURE);
259+ }
260
261 if (i != tables_regex_num - 1)
262 *(next - 1) = ',';
263@@ -4394,9 +4430,6 @@
264
265 HASH_INSERT(xtrabackup_tables_t, name_hash, tables_hash,
266 ut_fold_string(table->name), table);
267-
268- msg("xtrabackup: table '%s' is registered to the "
269- "list.\n", table->name);
270 }
271 }
272 }
273
274=== added file 'test/t/bug1130627.sh'
275--- test/t/bug1130627.sh 1970-01-01 00:00:00 +0000
276+++ test/t/bug1130627.sh 2013-03-07 11:50:26 +0000
277@@ -0,0 +1,74 @@
278+########################################################################
279+# Bug #1130627: Can't backup individual partitions
280+########################################################################
281+
282+. inc/common.sh
283+. inc/ib_part.sh
284+
285+start_server --innodb_file_per_table
286+
287+require_partitioning
288+
289+run_cmd $MYSQL $MYSQL_ARGS test <<EOF
290+CREATE TABLE t_innodb (
291+ i INT NOT NULL AUTO_INCREMENT,
292+ c CHAR(10) DEFAULT NULL,
293+ PRIMARY KEY (i)
294+) ENGINE=InnoDB
295+/*!50100 PARTITION BY HASH (i)
296+PARTITIONS 10 */;
297+
298+CREATE TABLE t_myisam (
299+ i INT NOT NULL AUTO_INCREMENT,
300+ c CHAR(10) DEFAULT NULL,
301+ PRIMARY KEY (i)
302+) ENGINE=MyISAM
303+/*!50100 PARTITION BY HASH (i)
304+PARTITIONS 10 */;
305+EOF
306+
307+# Force a checkpoint
308+stop_server
309+start_server --innodb_file_per_table
310+
311+# Test that specifying partitions with --include works
312+innobackupex --no-timestamp --include='^test.*#P#p5' $topdir/backup
313+innobackupex --apply-log $topdir/backup
314+
315+file_cnt=`ls $topdir/backup/test | wc -l`
316+
317+test "$file_cnt" -eq 3
318+
319+test -f $topdir/backup/test/t_innodb#P#p5.ibd
320+test -f $topdir/backup/test/t_myisam#P#p5.MYD
321+test -f $topdir/backup/test/t_myisam#P#p5.MYI
322+
323+rm -rf $topdir/backup
324+
325+# Test that specifying partitions with --databases works
326+# TODO: uncomment when bug #569387 is fixed
327+
328+# innobackupex --no-timestamp \
329+# --databases='test.t_myisam#P#p5 test.t_innodb#P#p5' $topdir/backup
330+# innobackupex --apply-log $topdir/backup
331+
332+# test "$file_cnt" -eq 3
333+# test -f $topdir/backup/test/t_innodb#P#p5.ibd
334+# test -f $topdir/backup/test/t_myisam#P#p5.MYD
335+# test -f $topdir/backup/test/t_myisam#P#p5.MYI
336+
337+# rm -rf $topdir/backup
338+
339+# Test that specifying partitions with --tables-file works
340+cat >$topdir/tables_file <<EOF
341+test.t_myisam#P#p5
342+test.t_innodb#P#p5
343+EOF
344+innobackupex --no-timestamp --tables-file=$topdir/tables_file $topdir/backup
345+innobackupex --apply-log $topdir/backup
346+
347+test "$file_cnt" -eq 3
348+test -f $topdir/backup/test/t_myisam#P#p5.MYD
349+test -f $topdir/backup/test/t_myisam#P#p5.MYI
350+
351+rm -rf $topdir/backup

Subscribers

People subscribed via source and target branches