Merge lp:~sergei.glushchenko/percona-xtrabackup/21-bug856400 into lp:percona-xtrabackup/2.1
- 21-bug856400
- Merge into 2.1
Status: | Merged |
---|---|
Approved by: | Alexey Kopytov |
Approved revision: | no longer in the source branch. |
Merged at revision: | 554 |
Proposed branch: | lp:~sergei.glushchenko/percona-xtrabackup/21-bug856400 |
Merge into: | lp:percona-xtrabackup/2.1 |
Diff against target: |
726 lines (+378/-102) 3 files modified
innobackupex (+96/-37) src/xtrabackup.cc (+162/-65) test/t/bug856400.sh (+120/-0) |
To merge this branch: | bzr merge lp:~sergei.glushchenko/percona-xtrabackup/21-bug856400 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexey Kopytov (community) | Approve | ||
George Ormond Lorch III (community) | g2 | Approve | |
Review via email: mp+152362@code.launchpad.net |
Commit message
Description of the change
Bug 856400
Remove dropped tables from a full backup when merging an incremental one
The problem is that between full and incremental backups such a DDL
operations as DROP TABLE and ALTER TABLE DROP PARTITION are possible.
Incremental backup doesn't contain dropped tablespaces, while full
backup still does.
Solution is to enumerate all tablespaces in datadir (which present on
filesystem) and drop those which doesn't present in fil_system directory.
This is done once incremental backup is applied to full backup and
prepared.
Minor code refactoring has been done to avoid code duplication for
enumerating files in data directory.
Sergei Glushchenko (sergei.glushchenko) wrote : | # |
George Ormond Lorch III (gl-az) wrote : | # |
George Ormond Lorch III (gl-az) : | # |
Sergei Glushchenko (sergei.glushchenko) wrote : | # |
George's comments on 2.0 version of MP have been addressed.
http://
George Ormond Lorch III (gl-az) : | # |
Alexey Kopytov (akopytov) wrote : | # |
Same comments as in the 2.0 MP.
Sergei Glushchenko (sergei.glushchenko) wrote : | # |
innobackupex part implemented
http://
Sergei Glushchenko (sergei.glushchenko) wrote : | # |
Updated with the changes from 2.0
http://
Alexey Kopytov (akopytov) : | # |
Preview Diff
1 | === modified file 'innobackupex' |
2 | --- innobackupex 2013-04-17 07:54:33 +0000 |
3 | +++ innobackupex 2013-04-17 12:08:29 +0000 |
4 | @@ -225,6 +225,7 @@ |
5 | my $xtrabackup_binary_file = 'xtrabackup_binary'; |
6 | my $xtrabackup_pid_file = 'xtrabackup_pid'; |
7 | my %rsync_files_hash; |
8 | +my %processed_files; |
9 | |
10 | my $xb_fn_suspended_at_start = "/xtrabackup_suspended_1"; |
11 | my $xb_fn_suspended_at_end = "/xtrabackup_suspended_2"; |
12 | @@ -234,7 +235,8 @@ |
13 | |
14 | my $copy_dir_src; |
15 | my $copy_dir_dst; |
16 | -my $copy_dir_exclude_regexp; |
17 | +my $cleanup_dir_dst; |
18 | +my $process_dir_exclude_regexp; |
19 | my $copy_dir_overwrite; |
20 | |
21 | ###################################################################### |
22 | @@ -608,7 +610,7 @@ |
23 | sub process_file { |
24 | my $process_func = shift; |
25 | |
26 | - if (/$copy_dir_exclude_regexp/) { |
27 | + if (/$process_dir_exclude_regexp/) { |
28 | return; |
29 | } |
30 | (my $dst_path = $File::Find::name) =~ s/^$copy_dir_src/$copy_dir_dst/; |
31 | @@ -628,6 +630,8 @@ |
32 | } |
33 | |
34 | &$process_func($File::Find::name, $dst_path); |
35 | + (my $rel_path = $File::Find::name) =~ s/^$copy_dir_src//; |
36 | + $processed_files{$rel_path} = 1; |
37 | } |
38 | } |
39 | |
40 | @@ -646,9 +650,30 @@ |
41 | } |
42 | |
43 | # |
44 | +# find() callback to remove files |
45 | +# |
46 | +sub remove_file_callback { |
47 | + if (/$process_dir_exclude_regexp/) { |
48 | + return; |
49 | + } |
50 | + if (-d "$File::Find::name") { |
51 | + return; |
52 | + } |
53 | + (my $rel_path = $File::Find::name) =~ s/^$cleanup_dir_dst//; |
54 | + if (!($rel_path =~ m/\//)) { |
55 | + return; |
56 | + } |
57 | + if (! exists $processed_files{$rel_path}) { |
58 | + unlink($File::Find::name) or |
59 | + Die("Cannot remove file $File::Find::name"); |
60 | + } |
61 | +} |
62 | + |
63 | +# |
64 | # copy_dir_recursively subroutine does a recursive copy of a specified |
65 | # directory excluding files matching a specifies regexp. If $overwrite |
66 | -# is 1, it overwrites the existing files. |
67 | +# is 1, it overwrites the existing files. It also updates processed_files |
68 | +# hash with the relative paths of files been copied. |
69 | # |
70 | # SYNOPSIS |
71 | # |
72 | @@ -663,9 +688,10 @@ |
73 | # Clean paths and remove trailing slashes if any |
74 | $copy_dir_src = File::Spec->canonpath(shift); |
75 | $copy_dir_dst = File::Spec->canonpath(shift); |
76 | - $copy_dir_exclude_regexp = shift; |
77 | + $process_dir_exclude_regexp = shift; |
78 | $copy_dir_overwrite = shift; |
79 | |
80 | + undef %processed_files; |
81 | find(\©_file_callback, $copy_dir_src); |
82 | } |
83 | |
84 | @@ -685,13 +711,50 @@ |
85 | # Clean paths and remove trailing slashes if any |
86 | $copy_dir_src = File::Spec->canonpath(shift); |
87 | $copy_dir_dst = File::Spec->canonpath(shift); |
88 | - $copy_dir_exclude_regexp = shift; |
89 | + $process_dir_exclude_regexp = shift; |
90 | $copy_dir_overwrite = shift; |
91 | |
92 | + undef %processed_files; |
93 | find(\&move_file_callback, $copy_dir_src); |
94 | } |
95 | |
96 | # |
97 | +# cleanup_dir_recursively subroutine removes files from directory |
98 | +# excluding files matching a specifies regexp and files listed in |
99 | +# processed_files. |
100 | +# |
101 | +# SYNOPSIS |
102 | +# |
103 | +# cleanup_dir_recursively($dir, $exclude_regexp); |
104 | +# |
105 | +sub cleanup_dir_recursively { |
106 | + # Clean paths and remove trailing slashes if any |
107 | + $cleanup_dir_dst = File::Spec->canonpath(shift); |
108 | + $process_dir_exclude_regexp = shift; |
109 | + find(\&remove_file_callback, $cleanup_dir_dst); |
110 | +} |
111 | + |
112 | +# |
113 | +# parse_innodb_data_file_path parse innodb_data_file_path and returns |
114 | +# it components as array of hash refs. Each hash ref has two components |
115 | +# the one named 'path' is the data file path as specified in the |
116 | +# innodb-data-file-path, second one named 'filename' is the data file name |
117 | +# |
118 | +sub parse_innodb_data_file_path { |
119 | + my $innodb_data_file_path = shift; |
120 | + my @data_file_paths = (); |
121 | + |
122 | + foreach my $data_file (split(/;/, $innodb_data_file_path)) { |
123 | + my $data_file_path = (split(/:/,$data_file))[0]; |
124 | + my $data_file_name = (split(/\/+/, $data_file_path))[-1]; |
125 | + push(@data_file_paths, {path => $data_file_path, |
126 | + filename => $data_file_name}); |
127 | + } |
128 | + |
129 | + return @data_file_paths; |
130 | +} |
131 | + |
132 | +# |
133 | # copy_back subroutine copies data and index files from backup directory |
134 | # back to their original locations. |
135 | # |
136 | @@ -750,24 +813,26 @@ |
137 | |
138 | # make a list of all ibdata files in the backup directory and all |
139 | # directories in the backup directory under which there are ibdata files |
140 | - foreach my $a (split(/;/, $orig_innodb_data_file_path)) { |
141 | - my $path = (split(/:/,$a))[0]; |
142 | - my $filename = (split(/\/+/, $path))[-1]; |
143 | + foreach my $c (parse_innodb_data_file_path($orig_innodb_data_file_path)) { |
144 | |
145 | # check that the backup data file exists |
146 | - if (! -e "$backup_dir/$filename") { |
147 | - if (-e "$backup_dir/${filename}.ibz") { |
148 | - Die "Backup data file '$backup_dir/$filename' does not exist, but " |
149 | - . "its compressed copy '${path}.ibz' exists. Check " |
150 | - . "that you have run '$innobackup_script --apply-log --uncompress " |
151 | - . "...' before attempting '$innobackup_script --copy-back ...' " |
152 | + if (! -e "$backup_dir/$c->{filename}") { |
153 | + if (-e "$backup_dir/$c->{filename}.ibz") { |
154 | + Die "Backup data file '$backup_dir/$c->{filename}' " |
155 | + . "does not exist, but " |
156 | + . "its compressed copy '$c->{path}.ibz' exists. Check " |
157 | + . "that you have run " |
158 | + . "'$innobackup_script --apply-log --uncompress " |
159 | + . "...' before attempting " |
160 | + . "'$innobackup_script --copy-back ...' " |
161 | . "or '$innobackup_script --move-back ...' !"; |
162 | } else { |
163 | - Die "Backup data file '$backup_dir/$filename' does not exist."; |
164 | + Die "Backup data file '$backup_dir/$c->{filename}' " |
165 | + . "does not exist."; |
166 | } |
167 | } |
168 | |
169 | - $excluded_files .= "|\Q$filename\E"; |
170 | + $excluded_files .= "|\Q$c->{filename}\E"; |
171 | } |
172 | |
173 | # copy files from backup dir to their original locations |
174 | @@ -782,12 +847,10 @@ |
175 | print STDERR "\n$prefix Starting to $operation InnoDB system tablespace\n"; |
176 | print STDERR "$prefix in '$backup_dir'\n"; |
177 | print STDERR "$prefix back to original InnoDB data directory '$orig_ibdata_dir'\n"; |
178 | - foreach my $a (split(/;/, $orig_innodb_data_file_path)) { |
179 | + foreach my $c (parse_innodb_data_file_path($orig_innodb_data_file_path)) { |
180 | # get the relative pathname of a data file |
181 | - my $path = (split(/:/,$a))[0]; |
182 | - my $filename = (split(/\/+/, $path))[-1]; |
183 | - $src_name = escape_path("$backup_dir/$filename"); |
184 | - $dst_name = escape_path("$orig_ibdata_dir/$path"); |
185 | + $src_name = escape_path("$backup_dir/$c->{filename}"); |
186 | + $dst_name = escape_path("$orig_ibdata_dir/$c->{path}"); |
187 | &$move_or_copy_file($src_name, $dst_name); |
188 | } |
189 | |
190 | @@ -857,6 +920,9 @@ |
191 | $options .= " --tmpdir=$option_tmpdir"; |
192 | } |
193 | |
194 | + my $innodb_data_file_path = |
195 | + get_option(\%config, $option_defaults_group, 'innodb_data_file_path'); |
196 | + |
197 | # run ibbackup as a child process |
198 | $cmdline = "$option_ibbackup_binary $options"; |
199 | |
200 | @@ -893,23 +959,16 @@ |
201 | if ( $option_incremental_dir ) { |
202 | print STDERR "$prefix Starting to copy non-InnoDB files in '$option_incremental_dir'\n"; |
203 | print STDERR "$prefix to the full backup directory '$backup_dir'\n"; |
204 | - copy_dir_recursively($option_incremental_dir, $backup_dir, |
205 | - '^(\.\.?|backup-my\.cnf|xtrabackup_logfile|' . |
206 | - 'xtrabackup_binary|xtrabackup_checkpoints|' . |
207 | - '.*\.delta|.*\.meta|ib_logfile.*)$', 1); |
208 | - # If the latest backup has no file, we need to remove the old |
209 | - # xtrabackup_slave_info file, because it is out of date |
210 | - # TODO: this will not be needed when bug #856400 is fixed. |
211 | - if ( -e "$backup_dir/xtrabackup_slave_info" ) { |
212 | - print STDERR "\n$now $prefix No updated xtrabackup_slave_info found in incremental dir, removing stale xtrabackup_slave_info file from target dir."; |
213 | - $cmdline = "rm $backup_dir/xtrabackup_slave_info"; |
214 | - $rcode = system("$cmdline"); |
215 | - if ($rcode) { |
216 | - # failure |
217 | - Die "\n$prefix Failed to remove stale xtrabackup_slave_info in $backup_dir"; |
218 | - } |
219 | - |
220 | + my @skip_list = ('\.\.?','backup-my\.cnf','xtrabackup_logfile', |
221 | + 'xtrabackup_binary','xtrabackup_checkpoints', |
222 | + '.*\.delta','.*\.meta','ib_logfile.*'); |
223 | + copy_dir_recursively($option_incremental_dir, $backup_dir, |
224 | + '^(' . join('|', @skip_list) . ')$', 1); |
225 | + foreach my $c (parse_innodb_data_file_path($innodb_data_file_path)) { |
226 | + push(@skip_list, "\Q$c->{filename}\E"); |
227 | } |
228 | + cleanup_dir_recursively($backup_dir, |
229 | + '^(' . join('|', @skip_list, '.*\.ibd') . ')$'); |
230 | } |
231 | |
232 | } |
233 | |
234 | === modified file 'src/xtrabackup.cc' |
235 | --- src/xtrabackup.cc 2013-04-17 07:54:33 +0000 |
236 | +++ src/xtrabackup.cc 2013-04-17 12:08:29 +0000 |
237 | @@ -121,6 +121,8 @@ |
238 | char *xtrabackup_tables_file = NULL; |
239 | hash_table_t* tables_hash; |
240 | |
241 | +hash_table_t* inc_dir_tables_hash; |
242 | + |
243 | struct xtrabackup_tables_struct{ |
244 | char* name; |
245 | hash_node_t name_hash; |
246 | @@ -2643,7 +2645,7 @@ |
247 | } |
248 | |
249 | table = static_cast<xtrabackup_tables_t *> |
250 | - (malloc(sizeof(xtrabackup_tables_t) |
251 | + (ut_malloc(sizeof(xtrabackup_tables_t) |
252 | + strlen(name_buf) + 1)); |
253 | memset(table, '\0', sizeof(xtrabackup_tables_t) + strlen(name_buf) + 1); |
254 | table->name = ((char*)table) + sizeof(xtrabackup_tables_t); |
255 | @@ -2657,6 +2659,37 @@ |
256 | |
257 | static |
258 | void |
259 | +xb_tables_hash_free(hash_table_t* hash) |
260 | +{ |
261 | + ulint i; |
262 | + |
263 | + /* free the hash elements */ |
264 | + for (i = 0; i < hash_get_n_cells(hash); i++) { |
265 | + xtrabackup_tables_t* table; |
266 | + |
267 | + table = static_cast<xtrabackup_tables_t *> |
268 | + (HASH_GET_FIRST(hash, i)); |
269 | + |
270 | + while (table) { |
271 | + xtrabackup_tables_t* prev_table = table; |
272 | + |
273 | + table = static_cast<xtrabackup_tables_t *> |
274 | + (HASH_GET_NEXT(name_hash, prev_table)); |
275 | + |
276 | + HASH_DELETE(xtrabackup_tables_t, name_hash, hash, |
277 | + ut_fold_string(prev_table->name), prev_table); |
278 | + ut_free(prev_table); |
279 | + } |
280 | + } |
281 | + |
282 | + /* free hash */ |
283 | + hash_table_free(hash); |
284 | +} |
285 | + |
286 | +/************************************************************************ |
287 | +Destroy table filters for partial backup. */ |
288 | +static |
289 | +void |
290 | xb_filters_free() |
291 | { |
292 | if (xtrabackup_tables) { |
293 | @@ -2670,29 +2703,7 @@ |
294 | } |
295 | |
296 | if (xtrabackup_tables_file) { |
297 | - ulint i; |
298 | - |
299 | - /* free the hash elements */ |
300 | - for (i = 0; i < hash_get_n_cells(tables_hash); i++) { |
301 | - xtrabackup_tables_t* table; |
302 | - |
303 | - table = static_cast<xtrabackup_tables_t *> |
304 | - (HASH_GET_FIRST(tables_hash, i)); |
305 | - |
306 | - while (table) { |
307 | - xtrabackup_tables_t* prev_table = table; |
308 | - |
309 | - table = static_cast<xtrabackup_tables_t *> |
310 | - (HASH_GET_NEXT(name_hash, prev_table)); |
311 | - |
312 | - HASH_DELETE(xtrabackup_tables_t, name_hash, tables_hash, |
313 | - ut_fold_string(prev_table->name), prev_table); |
314 | - free(prev_table); |
315 | - } |
316 | - } |
317 | - |
318 | - /* free tables_hash */ |
319 | - hash_table_free(tables_hash); |
320 | + xb_tables_hash_free(tables_hash); |
321 | } |
322 | } |
323 | |
324 | @@ -3994,12 +4005,13 @@ |
325 | size_t real_name_len, /* out: buffer size for real_name */ |
326 | ibool* success) /* out: indicates error. TRUE = success */ |
327 | { |
328 | - char dest_dir[FN_REFLEN]; |
329 | - char dest_space_name[FN_REFLEN]; |
330 | - ibool ok; |
331 | - fil_space_t* fil_space; |
332 | - os_file_t file = 0; |
333 | - ulint tablespace_flags; |
334 | + char dest_dir[FN_REFLEN]; |
335 | + char dest_space_name[FN_REFLEN]; |
336 | + ibool ok; |
337 | + fil_space_t* fil_space; |
338 | + os_file_t file = 0; |
339 | + ulint tablespace_flags; |
340 | + xtrabackup_tables_t* table; |
341 | |
342 | ut_a(dbname != NULL || |
343 | trx_sys_sys_space(space_id) || |
344 | @@ -4038,6 +4050,16 @@ |
345 | goto found; |
346 | } |
347 | |
348 | + /* remember space name for further reference */ |
349 | + table = static_cast<xtrabackup_tables_t *> |
350 | + (ut_malloc(sizeof(xtrabackup_tables_t) + |
351 | + strlen(dest_space_name) + 1)); |
352 | + |
353 | + table->name = ((char*)table) + sizeof(xtrabackup_tables_t); |
354 | + strcpy(table->name, dest_space_name); |
355 | + HASH_INSERT(xtrabackup_tables_t, name_hash, inc_dir_tables_hash, |
356 | + ut_fold_string(table->name), table); |
357 | + |
358 | mutex_enter(&fil_system->mutex); |
359 | fil_space = xb_space_get_by_name(dest_space_name); |
360 | mutex_exit(&fil_system->mutex); |
361 | @@ -4154,7 +4176,7 @@ |
362 | const char* dbname, /* in: database name (ibdata: NULL) */ |
363 | const char* filename, /* in: file name (not a path), |
364 | including the .delta extension */ |
365 | - my_bool check_newer __attribute__((unused))) |
366 | + void* /*data*/) |
367 | { |
368 | os_file_t src_file = XB_FILE_UNDEFINED; |
369 | os_file_t dst_file = XB_FILE_UNDEFINED; |
370 | @@ -4347,11 +4369,61 @@ |
371 | } |
372 | |
373 | /************************************************************************ |
374 | -Applies all .delta files from incremental_dir to the full backup. |
375 | -@return TRUE on success. */ |
376 | -static |
377 | -ibool |
378 | -xtrabackup_apply_deltas(my_bool check_newer) |
379 | +Callback to handle datadir entry. Function of this type will be called |
380 | +for each entry which matches the mask by xb_process_datadir. |
381 | +@return should return TRUE on success */ |
382 | +typedef ibool (*handle_datadir_entry_func_t)( |
383 | +/*=========================================*/ |
384 | + const char* data_home_dir, /*!<in: path to datadir */ |
385 | + const char* db_name, /*!<in: database name */ |
386 | + const char* file_name, /*!<in: file name with suffix */ |
387 | + void* arg); /*!<in: caller-provided data */ |
388 | + |
389 | +/************************************************************************ |
390 | +Callback to handle datadir entry. Deletes entry if it has no matching |
391 | +fil_space in fil_system directory. |
392 | +@return FALSE if delete attempt was unsuccessful */ |
393 | +static |
394 | +ibool |
395 | +rm_if_not_found( |
396 | + const char* data_home_dir, /*!<in: path to datadir */ |
397 | + const char* db_name, /*!<in: database name */ |
398 | + const char* file_name, /*!<in: file name with suffix */ |
399 | + void* arg __attribute__((unused))) |
400 | +{ |
401 | + char name[FN_REFLEN]; |
402 | + xtrabackup_tables_t* table; |
403 | + |
404 | + snprintf(name, FN_REFLEN, "%s%s/%s", |
405 | + xb_dict_prefix, db_name, file_name); |
406 | + name[strlen(name) - XB_DICT_SUFFIX_LEN] = '\0'; |
407 | + |
408 | + XB_HASH_SEARCH(name_hash, inc_dir_tables_hash, ut_fold_string(name), |
409 | + table, (void) 0, |
410 | + !strcmp(table->name, name)); |
411 | + |
412 | + if (!table) { |
413 | + snprintf(name, FN_REFLEN, "%s/%s/%s", data_home_dir, |
414 | + db_name, file_name); |
415 | + return os_file_delete(name); |
416 | + } |
417 | + |
418 | + return(TRUE); |
419 | +} |
420 | + |
421 | +/************************************************************************ |
422 | +Function enumerates files in datadir (provided by path) which are matched |
423 | +by provided suffix. For each entry callback is called. |
424 | +@return FALSE if callback for some entry returned FALSE */ |
425 | +static |
426 | +ibool |
427 | +xb_process_datadir( |
428 | + const char* path, /*!<in: datadir path */ |
429 | + const char* suffix, /*!<in: suffix to match |
430 | + against */ |
431 | + handle_datadir_entry_func_t func, /*!<in: callback */ |
432 | + void* data) /*!<in: additional argument for |
433 | + callback */ |
434 | { |
435 | ulint ret; |
436 | char dbpath[FN_REFLEN]; |
437 | @@ -4359,56 +4431,59 @@ |
438 | os_file_dir_t dbdir; |
439 | os_file_stat_t dbinfo; |
440 | os_file_stat_t fileinfo; |
441 | - dberr_t err = DB_SUCCESS; |
442 | + ulint suffix_len; |
443 | + dberr_t err = DB_SUCCESS; |
444 | static char current_dir[2]; |
445 | |
446 | current_dir[0] = FN_CURLIB; |
447 | current_dir[1] = 0; |
448 | srv_data_home = current_dir; |
449 | |
450 | + suffix_len = strlen(suffix); |
451 | + |
452 | /* datafile */ |
453 | - dbdir = os_file_opendir(xtrabackup_incremental_dir, FALSE); |
454 | + dbdir = os_file_opendir(path, FALSE); |
455 | |
456 | if (dbdir != NULL) { |
457 | - ret = fil_file_readdir_next_file(&err, xtrabackup_incremental_dir, dbdir, |
458 | + ret = fil_file_readdir_next_file(&err, path, dbdir, |
459 | &fileinfo); |
460 | while (ret == 0) { |
461 | if (fileinfo.type == OS_FILE_TYPE_DIR) { |
462 | goto next_file_item_1; |
463 | } |
464 | |
465 | - if (strlen(fileinfo.name) > 6 |
466 | - && 0 == strcmp(fileinfo.name + |
467 | - strlen(fileinfo.name) - 6, |
468 | - ".delta")) { |
469 | - if (!xtrabackup_apply_delta( |
470 | - xtrabackup_incremental_dir, NULL, |
471 | - fileinfo.name, check_newer)) |
472 | + if (strlen(fileinfo.name) > suffix_len |
473 | + && 0 == strcmp(fileinfo.name + |
474 | + strlen(fileinfo.name) - suffix_len, |
475 | + suffix)) { |
476 | + if (!func( |
477 | + path, NULL, |
478 | + fileinfo.name, data)) |
479 | { |
480 | - return FALSE; |
481 | + return(FALSE); |
482 | } |
483 | } |
484 | next_file_item_1: |
485 | ret = fil_file_readdir_next_file(&err, |
486 | - xtrabackup_incremental_dir, dbdir, |
487 | + path, dbdir, |
488 | &fileinfo); |
489 | } |
490 | |
491 | os_file_closedir(dbdir); |
492 | } else { |
493 | msg("xtrabackup: Cannot open dir %s\n", |
494 | - xtrabackup_incremental_dir); |
495 | + path); |
496 | } |
497 | |
498 | /* single table tablespaces */ |
499 | - dir = os_file_opendir(xtrabackup_incremental_dir, FALSE); |
500 | + dir = os_file_opendir(path, FALSE); |
501 | |
502 | if (dir == NULL) { |
503 | msg("xtrabackup: Cannot open dir %s\n", |
504 | - xtrabackup_incremental_dir); |
505 | + path); |
506 | } |
507 | |
508 | - ret = fil_file_readdir_next_file(&err, xtrabackup_incremental_dir, dir, |
509 | + ret = fil_file_readdir_next_file(&err, path, dir, |
510 | &dbinfo); |
511 | while (ret == 0) { |
512 | if (dbinfo.type == OS_FILE_TYPE_FILE |
513 | @@ -4417,7 +4492,7 @@ |
514 | goto next_datadir_item; |
515 | } |
516 | |
517 | - sprintf(dbpath, "%s/%s", xtrabackup_incremental_dir, |
518 | + sprintf(dbpath, "%s/%s", path, |
519 | dbinfo.name); |
520 | srv_normalize_path_for_win(dbpath); |
521 | |
522 | @@ -4434,18 +4509,19 @@ |
523 | goto next_file_item_2; |
524 | } |
525 | |
526 | - if (strlen(fileinfo.name) > 6 |
527 | - && 0 == strcmp(fileinfo.name + |
528 | - strlen(fileinfo.name) - 6, |
529 | - ".delta")) { |
530 | - /* The name ends in .delta; try opening |
531 | + if (strlen(fileinfo.name) > suffix_len |
532 | + && 0 == strcmp(fileinfo.name + |
533 | + strlen(fileinfo.name) - |
534 | + suffix_len, |
535 | + suffix)) { |
536 | + /* The name ends in suffix; process |
537 | the file */ |
538 | - if (!xtrabackup_apply_delta( |
539 | - xtrabackup_incremental_dir, |
540 | + if (!func( |
541 | + path, |
542 | dbinfo.name, |
543 | - fileinfo.name, check_newer)) |
544 | + fileinfo.name, data)) |
545 | { |
546 | - return FALSE; |
547 | + return(FALSE); |
548 | } |
549 | } |
550 | next_file_item_2: |
551 | @@ -4458,13 +4534,24 @@ |
552 | } |
553 | next_datadir_item: |
554 | ret = fil_file_readdir_next_file(&err, |
555 | - xtrabackup_incremental_dir, |
556 | + path, |
557 | dir, &dbinfo); |
558 | } |
559 | |
560 | os_file_closedir(dir); |
561 | |
562 | - return TRUE; |
563 | + return(TRUE); |
564 | +} |
565 | + |
566 | +/************************************************************************ |
567 | +Applies all .delta files from incremental_dir to the full backup. |
568 | +@return TRUE on success. */ |
569 | +static |
570 | +ibool |
571 | +xtrabackup_apply_deltas() |
572 | +{ |
573 | + return xb_process_datadir(xtrabackup_incremental_dir, ".delta", |
574 | + xtrabackup_apply_delta, NULL); |
575 | } |
576 | |
577 | static my_bool |
578 | @@ -4657,12 +4744,22 @@ |
579 | goto error; |
580 | } |
581 | |
582 | - if(!xtrabackup_apply_deltas(TRUE)) { |
583 | + inc_dir_tables_hash = hash_create(1000); |
584 | + |
585 | + if(!xtrabackup_apply_deltas()) { |
586 | xb_data_files_close(); |
587 | + xb_tables_hash_free(inc_dir_tables_hash); |
588 | goto error; |
589 | } |
590 | |
591 | xb_data_files_close(); |
592 | + |
593 | + /* Cleanup datadir from tablespaces deleted between full and |
594 | + incremental backups */ |
595 | + |
596 | + xb_process_datadir("./", ".ibd", rm_if_not_found, NULL); |
597 | + |
598 | + xb_tables_hash_free(inc_dir_tables_hash); |
599 | } |
600 | sync_close(); |
601 | sync_initialized = FALSE; |
602 | |
603 | === added file 'test/t/bug856400.sh' |
604 | --- test/t/bug856400.sh 1970-01-01 00:00:00 +0000 |
605 | +++ test/t/bug856400.sh 2013-04-17 12:08:29 +0000 |
606 | @@ -0,0 +1,120 @@ |
607 | +######################################################################## |
608 | +# Bug #856400: RENAME TABLE causes incremental prepare to fail |
609 | +######################################################################## |
610 | + |
611 | +. inc/common.sh |
612 | +. inc/ib_part.sh |
613 | + |
614 | +start_server --innodb_file_per_table |
615 | + |
616 | +require_partitioning |
617 | + |
618 | +run_cmd $MYSQL $MYSQL_ARGS test <<EOF |
619 | +CREATE TABLE t1(a INT) ENGINE=InnoDB; |
620 | +INSERT INTO t1 VALUES (1), (2), (3); |
621 | + |
622 | +CREATE TABLE t2(a INT) ENGINE=InnoDB; |
623 | +INSERT INTO t2 VALUES (4), (5), (6); |
624 | + |
625 | +CREATE TABLE p ( |
626 | + a int |
627 | +) ENGINE=InnoDB |
628 | +PARTITION BY RANGE (a) |
629 | +(PARTITION p0 VALUES LESS THAN (100), |
630 | + PARTITION p1 VALUES LESS THAN (200), |
631 | + PARTITION p2 VALUES LESS THAN (300), |
632 | + PARTITION p3 VALUES LESS THAN (400)); |
633 | + |
634 | +INSERT INTO p VALUES (1), (101), (201), (301); |
635 | + |
636 | + |
637 | +CREATE TABLE isam_t1(a INT) ENGINE=MyISAM; |
638 | +INSERT INTO isam_t1 VALUES (1), (2), (3); |
639 | + |
640 | +CREATE TABLE isam_t2(a INT) ENGINE=MyISAM; |
641 | +INSERT INTO isam_t2 VALUES (4), (5), (6); |
642 | + |
643 | +CREATE TABLE isam_p ( |
644 | + a int |
645 | +) ENGINE=MyISAM |
646 | +PARTITION BY RANGE (a) |
647 | +(PARTITION p0 VALUES LESS THAN (100), |
648 | + PARTITION p1 VALUES LESS THAN (200), |
649 | + PARTITION p2 VALUES LESS THAN (300), |
650 | + PARTITION p3 VALUES LESS THAN (400)); |
651 | + |
652 | +INSERT INTO isam_p VALUES (1), (101), (201), (301); |
653 | + |
654 | +EOF |
655 | + |
656 | +# Full backup |
657 | +vlog "Creating full backup" |
658 | +innobackupex --no-timestamp $topdir/full |
659 | + |
660 | +vlog "Making changes" |
661 | + |
662 | +run_cmd $MYSQL $MYSQL_ARGS test <<EOF |
663 | + |
664 | +DROP TABLE t1; |
665 | + |
666 | +DROP TABLE t2; |
667 | +CREATE TABLE t2(a INT) ENGINE=InnoDB; |
668 | +INSERT INTO t2 VALUES (40), (50), (60); |
669 | + |
670 | +ALTER TABLE p DROP PARTITION p0; |
671 | +ALTER TABLE p DROP PARTITION p1; |
672 | +ALTER TABLE p ADD PARTITION (PARTITION p4 VALUES LESS THAN (500)); |
673 | +ALTER TABLE p ADD PARTITION (PARTITION p5 VALUES LESS THAN (600)); |
674 | + |
675 | +INSERT INTO p VALUES (401), (501); |
676 | + |
677 | + |
678 | +DROP TABLE isam_t1; |
679 | +DROP TABLE isam_t2; |
680 | +CREATE TABLE isam_t2(a INT) ENGINE=MyISAM; |
681 | + |
682 | +INSERT INTO isam_t2 VALUES (40), (50), (60); |
683 | + |
684 | +ALTER TABLE isam_p DROP PARTITION p0; |
685 | +ALTER TABLE isam_p DROP PARTITION p1; |
686 | +ALTER TABLE isam_p ADD PARTITION (PARTITION p4 VALUES LESS THAN (500)); |
687 | +ALTER TABLE isam_p ADD PARTITION (PARTITION p5 VALUES LESS THAN (600)); |
688 | + |
689 | +INSERT INTO isam_p VALUES (401), (501); |
690 | + |
691 | +EOF |
692 | + |
693 | +vlog "Creating incremental backup" |
694 | + |
695 | +innobackupex --incremental --no-timestamp \ |
696 | + --incremental-basedir=$topdir/full $topdir/inc |
697 | + |
698 | +vlog "Preparing backup" |
699 | + |
700 | +innobackupex --apply-log --redo-only $topdir/full |
701 | +vlog "Log applied to full backup" |
702 | + |
703 | +innobackupex --apply-log --redo-only --incremental-dir=$topdir/inc \ |
704 | + $topdir/full |
705 | +vlog "Delta applied to full backup" |
706 | + |
707 | +innobackupex --apply-log $topdir/full |
708 | +vlog "Data prepared for restore" |
709 | + |
710 | +ls -al $topdir/full/test/* |
711 | + |
712 | +# we expect to see |
713 | +# 5 InnoDB tablespaces |
714 | +count=`ls $topdir/full/test/*.ibd | wc -l` |
715 | +vlog "$count .ibd in restore, expecting 5" |
716 | +test $count -eq 5 |
717 | + |
718 | +# 5 MyISAM data files |
719 | +count=`ls $topdir/full/test/*.MYD | wc -l` |
720 | +vlog "$count .MYD in restore, expecting 5" |
721 | +test $count -eq 5 |
722 | + |
723 | +# and 10 tables overall |
724 | +count=`ls $topdir/full/test/*.frm | wc -l` |
725 | +vlog "$count .frm in restore, expecting 4" |
726 | +test $count -eq 4 |
http:// jenkins. percona. com/view/ XtraBackup/ job/percona- xtrabackup- 2.1-param/ 204/