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

Proposed by Alexey Kopytov
Status: Merged
Approved by: Laurynas Biveinis
Approved revision: no longer in the source branch.
Merged at revision: 465
Proposed branch: lp:~akopytov/percona-xtrabackup/bug803636-2.0
Merge into: lp:percona-xtrabackup/2.0
Diff against target: 400 lines (+167/-28)
4 files modified
doc/source/innobackupex/how_innobackupex_works.rst (+7/-0)
doc/source/innobackupex/innobackupex_option_reference.rst (+7/-1)
innobackupex (+122/-27)
test/t/bug803636.sh (+31/-0)
To merge this branch: bzr merge lp:~akopytov/percona-xtrabackup/bug803636-2.0
Reviewer Review Type Date Requested Status
Laurynas Biveinis (community) Approve
Review via email: mp+123040@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote :
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'doc/source/innobackupex/how_innobackupex_works.rst'
2--- doc/source/innobackupex/how_innobackupex_works.rst 2012-02-14 08:31:46 +0000
3+++ doc/source/innobackupex/how_innobackupex_works.rst 2012-09-06 09:53:29 +0000
4@@ -71,3 +71,10 @@
5 |innobackupex| will read the read from the :file:`my.cnf` the variables :term:`datadir`, :term:`innodb_data_home_dir`, :term:`innodb_data_file_path`, :term:`innodb_log_group_home_dir` and check that the directories exist.
6
7 It will copy the |MyISAM| tables, indexes, etc. (:term:`.frm`, :term:`.MRG`, :term:`.MYD`, :term:`.MYI`, :term:`.TRG`, :term:`.TRN`, :term:`.ARM`, :term:`.ARZ`, :term:`.CSM`, :term:`.CSV` and :term:`.opt` files) first, |InnoDB| tables and indexes next and the log files at last. It will preserve file's attributes when copying them, you may have to change the files' ownership to ``mysql`` before starting the database server, as they will be owned by the user who created the backup.
8+
9+Alternatively, the :option:`--move-back` option may be used to restore a
10+backup. This option is similar to :option:`--copy-back` with the only
11+difference that instead of copying files it moves them to their target
12+locations. As this option removes backup files, it must be used with
13+caution. It is useful in cases when there is not enough free disk space
14+to hold both data files and their backup copies.
15
16=== modified file 'doc/source/innobackupex/innobackupex_option_reference.rst'
17--- doc/source/innobackupex/innobackupex_option_reference.rst 2012-08-02 12:38:15 +0000
18+++ doc/source/innobackupex/innobackupex_option_reference.rst 2012-09-06 09:53:29 +0000
19@@ -30,6 +30,12 @@
20
21 Copy all the files in a previously made backup from the backup directory to their original locations.
22
23+.. option:: --move-back
24+
25+ Move all the files in a previously made backup from the backup
26+ directory to their original locations. As this option removes
27+ backup files, it must be used with caution.
28+
29 .. option:: --include=REGEXP
30
31 This option is a regular expression to be matched against table names in ``databasename.tablename`` format. It is passed directly to :program:`xtrabackup` 's :option:`xtrabackup --tables` option. See the :program:`xtrabackup` documentation for details.
32@@ -101,7 +107,7 @@
33
34 .. option:: --ibbackup = 'autodetect'
35
36- This option accepts a string argument that specifies which xtrabackup binary should be used. The string should be the command used to run *XtraBackup*. The option can be useful if the :program:`xtrabackup` binary is not in your search path or working directory and the database server is not accessible at the moment. If this option is not specified, :program:`innobackupex` attempts to determine the binary to use automatically. By default, :program:`xtrabackup` is the command used. When option :option:`--apply-log` is specified, the binary is used whose name is in the file :file:`xtrabackup_binary` in the backup directory, if that file exists, or will attempt to autodetect it. However, if :option:`--copy-back` is selected, :program:`xtrabackup` is used unless other is specified.
37+ This option accepts a string argument that specifies which xtrabackup binary should be used. The string should be the command used to run *XtraBackup*. The option can be useful if the :program:`xtrabackup` binary is not in your search path or working directory and the database server is not accessible at the moment. If this option is not specified, :program:`innobackupex` attempts to determine the binary to use automatically. By default, :program:`xtrabackup` is the command used. When option :option:`--apply-log` is specified, the binary is used whose name is in the file :file:`xtrabackup_binary` in the backup directory, if that file exists, or will attempt to autodetect it. However, if :option:`--copy-back` or :option:`--move-back` is used, :program:`xtrabackup` is used unless other is specified.
38
39 .. option:: --incremental
40
41
42=== modified file 'innobackupex'
43--- innobackupex 2012-08-02 12:38:15 +0000
44+++ innobackupex 2012-09-06 09:53:29 +0000
45@@ -72,6 +72,7 @@
46 my $option_apply_log = '';
47 my $option_redo_only = '';
48 my $option_copy_back = '';
49+my $option_move_back = '';
50 my $option_include = '';
51 my $option_databases = '';
52 my $option_tables_file = '';
53@@ -237,7 +238,7 @@
54 print_version();
55
56 # initialize global variables and perform some checks
57-if ($option_copy_back) {
58+if ($option_copy_back || $option_move_back) {
59 $option_ibbackup_binary = 'xtrabackup' if ($option_ibbackup_binary eq 'autodetect');
60 } elsif ($option_apply_log) {
61 # Read XtraBackup version from backup dir
62@@ -279,7 +280,10 @@
63
64 if ($option_copy_back) {
65 # copy files from backup directory back to their original locations
66- copy_back();
67+ copy_back(0);
68+} elsif ($option_move_back) {
69+ # move files from backup directory back to their original locations
70+ copy_back(1);
71 } elsif ($option_apply_log) {
72 # expand data files in backup directory by applying log files to them
73 apply_log();
74@@ -574,10 +578,41 @@
75 }
76
77 #
78-# Callback function for copy_dir_recursively that actually does all
79-# the copying work
80-#
81-sub copy_file() {
82+# copy() wrapper with error handling
83+#
84+sub copy_file {
85+ my $src_path = shift;
86+ my $dst_path = shift;
87+
88+ print STDERR "$prefix Copying '$src_path' to '$dst_path'\n";
89+ copy($src_path, $dst_path) or Die "copy failed: $!";
90+}
91+
92+#
93+# move() wrapper with error handling
94+#
95+sub move_file {
96+ my $src_path = shift;
97+ my $dst_path = shift;
98+
99+ print STDERR "$prefix Moving '$src_path' to '$dst_path'\n";
100+ move($src_path, $dst_path) or Die "move failed: $!";
101+}
102+
103+
104+#
105+# Auxiliary function called from find() callbacks to copy or move files and create directories
106+# when necessary.
107+#
108+# SYNOPSIS
109+#
110+# process_file(\&process_func);
111+#
112+# &process_func is a code reference that does the actual file operation
113+#
114+sub process_file {
115+ my $process_func = shift;
116+
117 if (/$copy_dir_exclude_regexp/) {
118 return;
119 }
120@@ -593,16 +628,29 @@
121 } else {
122 # Don't overwrite files unless $copy_dir_overwrite is 1
123 if (!$copy_dir_overwrite && -e "$copy_dir_dst/$_") {
124- Die "Failed to copy file $File::Find::name: " .
125- "file $copy_dir_dst/$_ exists";
126+ Die "Failed to process file $File::Find::name: " .
127+ "not overwriting file $copy_dir_dst/$_";
128 }
129
130- print STDERR "$prefix Copying '$File::Find::name' to '$dst_path'\n";
131- copy($File::Find::name, $dst_path) or Die "copy failed: $!";
132+ &$process_func($File::Find::name, $dst_path);
133 }
134 }
135
136 #
137+# find() callback to copy files
138+#
139+sub copy_file_callback {
140+ process_file(\&copy_file);
141+}
142+
143+#
144+# find() callback to move files
145+#
146+sub move_file_callback {
147+ process_file(\&move_file);
148+}
149+
150+#
151 # copy_dir_recursively subroutine does a recursive copy of a specified
152 # directory excluding files matching a specifies regexp. If $overwrite
153 # is 1, it overwrites the existing files.
154@@ -623,7 +671,29 @@
155 $copy_dir_exclude_regexp = shift;
156 $copy_dir_overwrite = shift;
157
158- find(\&copy_file, $copy_dir_src);
159+ find(\&copy_file_callback, $copy_dir_src);
160+}
161+
162+#
163+# Similar to copy_dir_recursively, but moves files instead.
164+#
165+# SYNOPSIS
166+#
167+# move_dir_recursively($src_dir, $dst_dir, $exclude_regexp,
168+# $overwrite);
169+#
170+# TODO
171+#
172+# use rsync when --rsync is specified
173+#
174+sub move_dir_recursively {
175+ # Clean paths and remove trailing slashes if any
176+ $copy_dir_src = File::Spec->canonpath(shift);
177+ $copy_dir_dst = File::Spec->canonpath(shift);
178+ $copy_dir_exclude_regexp = shift;
179+ $copy_dir_overwrite = shift;
180+
181+ find(\&move_file_callback, $copy_dir_src);
182 }
183
184 #
185@@ -631,6 +701,7 @@
186 # back to their original locations.
187 #
188 sub copy_back {
189+ my $move_flag = shift;
190 my $orig_datadir = get_option(\%config, $option_defaults_group, 'datadir');
191 my $orig_ibdata_dir =
192 get_option(\%config, $option_defaults_group, 'innodb_data_home_dir');
193@@ -647,6 +718,14 @@
194 my $compressed_data_file = '.*\.ibz$';
195 my $file;
196 my $backup_innodb_data_file_path;
197+
198+ # check whether files should be copied or moved to dest directory
199+ my $move_or_copy_file = $move_flag ? \&move_file : \&copy_file;
200+ my $move_or_copy_dir = $move_flag ?
201+ \&move_dir_recursively : \&copy_dir_recursively;
202+ my $operation = $move_flag ? "move" : "copy";
203+
204+
205 # check that original data directories exist and they are empty
206 if_directory_exists_and_empty($orig_datadir, "Original data");
207 if_directory_exists_and_empty($orig_ibdata_dir, "Original InnoDB data");
208@@ -678,7 +757,8 @@
209 Die "Backup data file '$backup_dir/$filename' does not exist, but "
210 . "its compressed copy '${path}.ibz' exists. Check "
211 . "that you have run '$innobackup_script --apply-log --uncompress "
212- . "...' before attempting '$innobackup_script --copy-back ...' !";
213+ . "...' before attempting '$innobackup_script --copy-back ...' "
214+ . "or '$innobackup_script --move-back ...' !";
215 } else {
216 Die "Backup data file '$backup_dir/$filename' does not exist.";
217 }
218@@ -691,38 +771,34 @@
219
220 # copy files to original data directory
221 my $excluded_regexp = '^(' . $excluded_files . ')$';
222- print STDERR "$prefix Starting to copy files in '$backup_dir'\n";
223+ print STDERR "$prefix Starting to $operation files in '$backup_dir'\n";
224 print STDERR "$prefix back to original data directory '$orig_datadir'\n";
225- copy_dir_recursively($backup_dir, $orig_datadir, $excluded_regexp, 0);
226+ &$move_or_copy_dir($backup_dir, $orig_datadir, $excluded_regexp, 0);
227
228 # copy InnoDB data files to original InnoDB data directory
229- print STDERR "\n$prefix Starting to copy InnoDB system tablespace\n";
230+ print STDERR "\n$prefix Starting to $operation InnoDB system tablespace\n";
231 print STDERR "$prefix in '$backup_dir'\n";
232 print STDERR "$prefix back to original InnoDB data directory '$orig_ibdata_dir'\n";
233 foreach my $a (split(/;/, $orig_innodb_data_file_path)) {
234 # get the relative pathname of a data file
235 my $path = (split(/:/,$a))[0];
236 my $filename = (split(/\/+/, $path))[-1];
237- print STDERR "$prefix Copying file '$backup_dir/$filename'\n";
238 $src_name = escape_path("$backup_dir/$filename");
239 $dst_name = escape_path("$orig_ibdata_dir/$path");
240- system("$CP_CMD \"$src_name\" \"$dst_name\"")
241- and Die "Failed to copy file '$filename': $!";
242+ &$move_or_copy_file($src_name, $dst_name);
243 }
244
245 # copy InnoDB log files to original InnoDB log directory
246 opendir(DIR, $backup_dir)
247 || Die "Can't open directory '$backup_dir': $!\n";
248- print STDERR "\n$prefix Starting to copy InnoDB log files\n";
249+ print STDERR "\n$prefix Starting to $operation InnoDB log files\n";
250 print STDERR "$prefix in '$backup_dir'\n";
251 print STDERR "$prefix back to original InnoDB log directory '$orig_iblog_dir'\n";
252 while (defined($file = readdir(DIR))) {
253 if ($file =~ /'^' . $iblog_files . '$'/ && -f "$backup_dir/$file") {
254- print STDERR "$prefix Copying file '$backup_dir/$file'\n";
255 $src_name = escape_path("$backup_dir/$file");
256 $dst_name = escape_path("$orig_iblog_dir");
257- system("$CP_CMD \"$src_name\" \"$dst_name\"")
258- and Die "Failed to copy file '$file': $!";
259+ &$move_or_copy_file($src_name, $dst_name);
260 }
261 }
262 closedir(DIR);
263@@ -1528,10 +1604,12 @@
264 my $run = '';
265
266 # print some instructions to the user
267- if (!$option_apply_log && !$option_copy_back) {
268+ if (!$option_apply_log && !$option_copy_back && !$option_move_back) {
269 $run = 'backup';
270 } elsif ($option_copy_back) {
271 $run = 'copy-back';
272+ } elsif ($option_move_back) {
273+ $run = 'move-back';
274 } else {
275 $run = 'apply-log';
276 }
277@@ -1541,7 +1619,7 @@
278
279 # check that MySQL client program and InnoDB Hot Backup program
280 # are runnable via shell
281- if (!$option_copy_back) {
282+ if (!$option_copy_back && !$option_move_back) {
283 # we are making a backup or applying log to backup
284 if (!$option_apply_log) {
285 # we are making a backup, we need mysql server
286@@ -1589,7 +1667,7 @@
287 #$innodb_log_group_home_dir =
288 # get_option(\%config, 'mysqld', 'innodb_log_group_home_dir');
289
290- if (!$option_apply_log && !$option_copy_back) {
291+ if (!$option_apply_log && !$option_copy_back && !$option_move_back) {
292 # we are making a backup, create a new backup directory
293 if (!$option_remote_host) {
294 $backup_dir = File::Spec->rel2abs(make_backup_dir());
295@@ -1619,7 +1697,7 @@
296 }
297 }
298 write_backup_config_file($backup_config_file);
299- } elsif ($option_copy_back) {
300+ } elsif ($option_copy_back || $option_move_back) {
301 #$backup_config_file = $backup_dir . '/backup-my.cnf';
302 #read_config_file($backup_config_file, \%backup_config);
303 }
304@@ -1715,6 +1793,7 @@
305 'apply-log' => \$option_apply_log,
306 'redo-only' => \$option_redo_only,
307 'copy-back' => \$option_copy_back,
308+ 'move-back' => \$option_move_back,
309 'include=s' => \$option_include,
310 'databases=s' => \$option_databases,
311 'tables-file=s', => \$option_tables_file,
312@@ -1765,6 +1844,11 @@
313 exit(0);
314 }
315
316+ if ($option_copy_back && $option_move_back) {
317+ print STDERR "$prefix --copy-back and --move-back options are " .
318+ "mutually exclusive";
319+ }
320+
321 if ($option_compress == 0) {
322 # compression level no specified, use default level
323 $option_compress = $default_compression_level;
324@@ -1792,7 +1876,7 @@
325 # get options file name
326 #$config_file = $ARGV[0];
327
328- if (!$option_apply_log && !$option_copy_back) {
329+ if (!$option_apply_log && !$option_copy_back && !$option_move_back) {
330 # we are making a backup, get backup root directory
331 $backup_root = $ARGV[0];
332 if ($option_incremental && !$option_incremental_lsn) {
333@@ -2635,6 +2719,8 @@
334
335 innobackupex --copy-back [--defaults-file=MY.CNF] [--defaults-group=GROUP-NAME] BACKUP-DIR
336
337+innobackupex --move-back [--defaults-file=MY.CNF] [--defaults-group=GROUP-NAME] BACKUP-DIR
338+
339 =head1 DESCRIPTION
340
341 The first command line above makes a hot backup of a MySQL database.
342@@ -2663,6 +2749,11 @@
343 The MY.CNF options file defines the original location of the database.
344 The BACKUP-DIR is the path to a backup directory created by xtrabackup.
345
346+The --move-back command is similar to --copy-back with the only difference that
347+it moves files to their original locations rather than copies them. As this
348+option removes backup files, it must be used with caution. It may be useful in
349+cases when there is not enough free disk space to copy files.
350+
351 On success the exit code innobackupex is 0. A non-zero exit code
352 indicates an error.
353
354@@ -2691,6 +2782,10 @@
355
356 Copy all the files in a previously made backup from the backup directory to their original locations.
357
358+=item --move-back
359+
360+Move all the files in a previously made backup from the backup directory to the actual datadir location. Use with caution, as it removes backup files.
361+
362 =item --databases=LIST
363
364 This option specifies the list of databases that innobackupex should back up. The option accepts a string argument. The list is of the form "databasename1[.table_name1] databasename2[.table_name2] . . .". If this option is not specified, all databases containing MyISAM and InnoDB tables will be backed up. Please make sure that --databases contains all of the InnoDB databases and tables, so that all of the innodb.frm files are also backed up. In case the list is very long, this can be specified in a file, and the full path of the file can be specified instead of the list. (See option --tables-file.)
365
366=== added file 'test/t/bug803636.sh'
367--- test/t/bug803636.sh 1970-01-01 00:00:00 +0000
368+++ test/t/bug803636.sh 2012-09-06 09:53:29 +0000
369@@ -0,0 +1,31 @@
370+########################################################################
371+# Bug #803636: "moves files" option needed with --copy-back
372+########################################################################
373+
374+. inc/common.sh
375+
376+start_server --innodb_file_per_table
377+
378+load_sakila
379+
380+# Backup
381+innobackupex --no-timestamp $topdir/backup
382+
383+stop_server
384+
385+rm -r $mysql_datadir
386+
387+# Prepare
388+innobackupex --apply-log $topdir/backup
389+
390+# Restore
391+mkdir -p $mysql_datadir
392+innobackupex --move-back $topdir/backup
393+
394+# Check that there are no data files in the backup directory
395+run_cmd_expect_failure ls -R $topdir/backup/*/*.{ibd,MYD,MYI,frm}
396+
397+start_server
398+
399+# Verify data
400+run_cmd ${MYSQL} ${MYSQL_ARGS} -e "SELECT count(*) from actor" sakila

Subscribers

People subscribed via source and target branches