Merge lp:~sergei.glushchenko/percona-xtrabackup/bug489290_targetdir_rel_pwd into lp:percona-xtrabackup/2.0

Proposed by Sergei Glushchenko
Status: Rejected
Rejected by: Alexey Kopytov
Proposed branch: lp:~sergei.glushchenko/percona-xtrabackup/bug489290_targetdir_rel_pwd
Merge into: lp:percona-xtrabackup/2.0
Diff against target: 235 lines (+153/-7)
6 files modified
doc/source/xtrabackup_bin/creating_a_backup.rst (+1/-1)
doc/source/xtrabackup_bin/xbk_option_reference.rst (+1/-1)
innobackupex (+5/-5)
kewpie/percona_tests/xtrabackup_main/bug489290_test.py (+90/-0)
test/t/bug489290.sh (+42/-0)
xtrabackup.c (+14/-0)
To merge this branch: bzr merge lp:~sergei.glushchenko/percona-xtrabackup/bug489290_targetdir_rel_pwd
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Needs Information
Review via email: mp+88694@code.launchpad.net

Description of the change

Behaviour of '--target-dir' option changed. If relative path specified, it considered to be relative to the directory where xtrabackup executed.

Jenkins: http://jenkins.percona.com/view/Percona%20Xtrabackup/job/percona-xtrabackup-trunk-kewpie/21/
(it may be a bit hard to see if it breaks anything as everything isn't passing everywhere yet)

To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote :

Sergei,

On 16.01.12 17:55, Sergei Glushchenko wrote:

> Jenkins: http://jenkins.percona.com/view/Percona%20Xtrabackup/job/percona-xtrabackup-trunk-kewpie/21/
> (it may be a bit hard to see if it breaks anything as everything isn't passing everywhere yet)
>

Um, it's insanity. I suggest we don't use kewpie until we have a clean
baseline. Can you please rewrite that test case to the old testing
framework?

> +/**************************************************************************
> +Expands target dir name to full path name if it is relative.*/
> +static void
> +expand_target_dir_name()
> +{
> + char current_dir[FN_REFLEN];
> + size_t current_dir_len;
> +
> + /* xtrabackup_target_dir should be relative to pwd, not to datadir.
> + convert it to absolute path if it's relative */
> + if (xtrabackup_target_dir && (xtrabackup_target_dir[0] != FN_LIBCHAR))
> + {
> + if (my_getwd(current_dir, sizeof(current_dir), MYF(MY_WME)))
> + {
> + fprintf(stderr, "xtrabackup: cannot my_getwd\n");

You don't have to do that. With the MY_WME flag my_getwd() will print
the following message on error:

Can't get working directory (Errcode: %d)

So there's no need for an explicit error message. I know it's a
copy-paste from elsewhere, but that code does not have to do that either.

> + exit(EXIT_FAILURE);
> + }
> + current_dir_len = strlen(current_dir);
> + strnmov(current_dir + current_dir_len, xtrabackup_target_dir,
> + sizeof(current_dir) - current_dir_len - 1);
> + cleanup_dirname(xtrabackup_real_target_dir, current_dir);
> + xtrabackup_target_dir = xtrabackup_real_target_dir;

Wouldn't cleanup_dirname(xtrabackup_target_dir, xtrabackup_target_dir)
be sufficient? It just looks like you're duplicating a part of
cleanup_dirname().

Or, even better, why not use unpack_dirname() to allow "~" in
--target-dir argument?

> + }
> +
> +}
> +
> static void
> xtrabackup_backup_func(void)
> {
> @@ -3706,6 +3732,9 @@
> fprintf(stderr, "xtrabackup: uses posix_fadvise().\n");
> #endif
>
> + /* ensure target dir will not be relative to datadir */
> + expand_target_dir_name();
> +
> /* cd to datadir */
>
> if (my_setwd(mysql_real_data_home,MYF(MY_WME)))
> @@ -4622,6 +4651,9 @@
> {
> ulint n;
>
> + /* ensure target dir will not be relative to datadir */
> + expand_target_dir_name();
> +

Would calling expand_target_dir_name() or cleanup_dirname() or
unpack_dirname() from get_one_option() be a better place to do the
conversion to avoid code duplication?

> /* cd to datadir */
>
> if (my_setwd(mysql_real_data_home,MYF(MY_WME)))
>
 needsfixing

Revision history for this message
Alexey Kopytov (akopytov) wrote :

Please also merge multiple revisions into a single one.

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

Aleksey,

> > Jenkins: http://jenkins.percona.com/view/Percona%20Xtrabackup/job/percona-xtrabackup-trunk-kewpie/21/
> > (it may be a bit hard to see if it breaks anything as everything isn't passing everywhere yet)
> >
>
> Um, it's insanity. I suggest we don't use kewpie until we have a clean
> baseline. Can you please rewrite that test case to the old testing
> framework?

That is probably so but it wasn't my initiative to use kewpie for this test.

> Would calling expand_target_dir_name() or cleanup_dirname() or
> unpack_dirname() from get_one_option() be a better place to do the
> conversion to avoid code duplication?

Yes. It will help us to avoid code duplication, but in this case we will do extra work when using xtrabackup with --prepare option. Besides it wouldn't help us if we're not specifying --target-dir option.

> You don't have to do that. With the MY_WME flag my_getwd() will print
> the following message on error:
>
> Can't get working directory (Errcode: %d)

I thought that it is the good practice to start error message with "xtrabackup:".
It could help when doing output parsing.

> Wouldn't cleanup_dirname(xtrabackup_target_dir, xtrabackup_target_dir)
> be sufficient? It just looks like you're duplicating a part of
> cleanup_dirname().

You wouldn't beleive it, but after call to normalize_dirname, cleanup_dirname, etc string "./xtrabackup_backupfiles/" will stay the same. I'm using cleanup_dirname in order to "cleanup" dirname, for example to remove extra "/./", "//", etc.

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

What's wrong if I make multiple revisions in one branch?

Revision history for this message
Alexey Kopytov (akopytov) wrote :

Sergei,

On 24.01.12 9:06, Sergei Glushchenko wrote:
> Aleksey,
>
>>> Jenkins: http://jenkins.percona.com/view/Percona%20Xtrabackup/job/percona-xtrabackup-trunk-kewpie/21/
>>> (it may be a bit hard to see if it breaks anything as everything isn't passing everywhere yet)
>>>
>>
>> Um, it's insanity. I suggest we don't use kewpie until we have a clean
>> baseline. Can you please rewrite that test case to the old testing
>> framework?
>
> That is probably so but it wasn't my initiative to use kewpie for this test.
>

I think it's a good initiative to use something when it's actually ready
to be used, and don't use it when it's not.

>> Would calling expand_target_dir_name() or cleanup_dirname() or
>> unpack_dirname() from get_one_option() be a better place to do the
>> conversion to avoid code duplication?
>
> Yes. It will help us to avoid code duplication, but in this case we will do extra work when using xtrabackup with --prepare option.

Why?

> Besides it wouldn't help us if we're not specifying --target-dir option.
>

Then you can do it in main() after the call to handle_options.

>> You don't have to do that. With the MY_WME flag my_getwd() will print
>> the following message on error:
>>
>> Can't get working directory (Errcode: %d)
>
> I thought that it is the good practice to start error message with "xtrabackup:".
> It could help when doing output parsing.
>

I don't see any use in it. XtraBackup can print messages starting with
"InnoDB:", "xtrabackup:", or without any prefix. So I don't think there
are tools that depend on a specific format, simply because there is no
consistent format.

>> Wouldn't cleanup_dirname(xtrabackup_target_dir, xtrabackup_target_dir)
>> be sufficient? It just looks like you're duplicating a part of
>> cleanup_dirname().
>
> You wouldn't beleive it, but after call to normalize_dirname, cleanup_dirname, etc string "./xtrabackup_backupfiles/" will stay the same. I'm using cleanup_dirname in order to "cleanup" dirname, for example to remove extra "/./", "//", etc.
>

Right, they don't actually unpack "." at the start. So using
my_realpath() instead should do the trick.

Revision history for this message
Alexey Kopytov (akopytov) wrote :

On 24.01.12 9:08, Sergei Glushchenko wrote:
> What's wrong if I make multiple revisions in one branch?

It's not very friendly to people who read the revision history. No
matter what is your goal when you do so, you would like to see something
like "Fixed bug ..." instead of the following:

"
374. By Sergei Glushchenko (sergei.glushchenko: 222) on 2012-01-16

    testcase renamed
373. By Sergei Glushchenko (sergei.glushchenko: 222) on 2012-01-13

    doc change committed
372. By Sergei Glushchenko (sergei.glushchenko: 222) on 2012-01-13

    testcase committed
371. By Sergei Glushchenko (sergei.glushchenko: 222) on 2012-01-13

    fix committed
"

Right?

It's OK to have multiple revisions for your personal use when you are
working on something. But will the above make any sense to a reader once
they are merged? I don't think so. So I always try to merge revisions
before submitting a MP.

When I have to make some changes once the original revision has been
merged, that's a different story of course. In this case it must be a
separate revision.

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

I also find it useful when revision comments include the bug number, the bug synopsis, and a few sentences describing the original problem (i.e. the root cause analysis for the bug), and the solution to that problem. This both simplifies code reviews, and increases readability of revision history.

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

Alexey,

> Right, they don't actually unpack "." at the start. So using
> my_realpath() instead should do the trick.

Thanks for suggestion! Looks like my_realpath() have exactly the same behavior I need.

I will keep kewpie test and will write another one using old framework. That was my first intention actually. But Stewart told me that kewpie will be sufficient.

As for merging multiple revisions into single one, I find that it reasonable. What is the best way to do that? My suggestion is to use "bzr uncommit" multiple times and then "bzr commit" for the whole bunch of changes, and after that "bzr push --overwrite". Is there any better way to do that?

Revision history for this message
Alexey Kopytov (akopytov) wrote :

On 24.01.12 15:12, Sergei Glushchenko wrote:
> As for merging multiple revisions into single one, I find that it reasonable. What is the best way to do that? My suggestion is to use "bzr uncommit" multiple times and then "bzr commit" for the whole bunch of changes, and after that "bzr push --overwrite". Is there any better way to do that?

Yes, "bzr uncommit" (either with -r, or simply multiple time) + "bzr
commit" + "bzr push --overwrite", see
https://code.launchpad.net/~hrvojem/percona-xtrabackup/mngtools/+merge/89194/comments/192080

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

Fix for bug #489290.
Bug description:
 ./xtrabackup --backup
creates database "xtrabackup_backupfiles".
The reasons are following:
1. Default value for target-dir option is "./xtrabackup_backupfiles/"
2. xtrabackup changes current working directory to datadir when backup option is specified
Suggested fix is to use my_load_path for target-dir value before changing working directory. Some code in innobackupex rely on this behaviour (--stream mode) so it was changed too.

new Jenkins build:
http://jenkins.percona.com/view/Percona%20Xtrabackup/job/percona-xtrabackup-param/115/

Revision history for this message
Alexey Kopytov (akopytov) wrote :

As discussed on IRC, the fix for this bug essentially fixes a part of bug #489290. So this bugfix depends on the fix for bug #489290 and should be rebased on the latter once its merged to trunk.

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

Sergei,

Do you really need expand_target_dir_name()? It looks like all you have to do is "my_load_path(xtrabackup_real_target_dir, xtrabackup_target_dir, NULL);". I don't see a reason to wrap that single line into a separate function.

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

Sorry, commented on a wrong MP.

Unmerged revisions

390. By Sergei Glushchenko

Bug 489290:
 ./xtrabackup --backup
creates database "xtrabackup_backupfiles".
The reasons are following:
1. Default value for target-dir option is "./xtrabackup_backupfiles/"
2. xtrabackup changes current working directory to datadir when backup option is specified
Solution is to use my_load_path to expand target-dir value before changing working directory.

389. By Stewart Smith

merge other patches from 1.6: bug711207

388. By Stewart Smith

merge fix for placement of xtrabackup_suspended and xtrabackup_checkpoint

387. By Stewart Smith

merge innodb version detection failure fix

386. By Stewart Smith

merge 1.9.0 release notes

385. By Stewart Smith

merge fix for bug 733658: pass options to both ssh and scp

384. By Stewart Smith

merge trademark policy in docs

383. By Stewart Smith

merge fix of broken links in docs

382. By Hrvoje Matijakovic

Merge from lp:~hrvojem/percona-xtrabackup/bug919203

381. By Hrvoje Matijakovic

Merge from lp:~hrvojem/percona-xtrabackup/mngtools.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'doc/source/xtrabackup_bin/creating_a_backup.rst'
2--- doc/source/xtrabackup_bin/creating_a_backup.rst 2011-07-07 05:32:50 +0000
3+++ doc/source/xtrabackup_bin/creating_a_backup.rst 2012-01-26 03:26:24 +0000
4@@ -18,7 +18,7 @@
5
6 xtrabackup --backup --datadir=/var/lib/mysql/ --target-dir=/data/backups/mysql/
7
8-This takes a backup of :file:`/var/lib/mysql` and stores it at :file:`/data/backups/mysql/`. The :option:`--target-dir` option deserves special explanation. Because the backup is performed from the data directory itself, **the target directory is relative to the data directory unless you specify an absolute path**. If you specify a relative path such as ``--target-dir=backups``, for example, don't look for the backup in the directory from which you executed |xtrabackup| - it will be a subdirectory of the :option:`--datadir` directory instead!
9+This takes a backup of :file:`/var/lib/mysql` and stores it at :file:`/data/backups/mysql/`. If you specify a relative path, the target directory will be relative to the current directory.
10
11 During the backup process, you should see a lot of output showing the data files being copied, as well as the log file thread repeatedly scanning the log files and copying from it. Here is an example that shows the log thread scanning the log in the background, and a file copying thread working on the ``ibdata1`` file: ::
12
13
14=== modified file 'doc/source/xtrabackup_bin/xbk_option_reference.rst'
15--- doc/source/xtrabackup_bin/xbk_option_reference.rst 2011-07-28 05:29:04 +0000
16+++ doc/source/xtrabackup_bin/xbk_option_reference.rst 2012-01-26 03:26:24 +0000
17@@ -121,7 +121,7 @@
18
19 This option specifies the destination directory for the backup. If the directory does not exist, :program:`xtrabackup` creates it. If the directory does exist and is empty, :program:`xtrabackup` will succeed. :program:`xtrabackup` will not overwrite existing files, however; it will fail with operating system error 17, ``file exists``.
20
21- Note that for :option:`--backup`, if this option is a relative path, it is interpreted as being relative to the :option:`--datadir`, not relative to the current working directory from which :program:`xtrabackup` is executed. For :option:`--prepare`, relative paths are interpreted as being relative to the current working directory.
22+ Note that for :option:`--backup`, if this option is a relative path, it is interpreted as being relative to the current working directory from which :program:`xtrabackup` is executed. For :option:`--prepare`, relative paths are interpreted as being relative to the current working directory.
23
24 .. option:: --throttle
25
26
27=== modified file 'innobackupex'
28--- innobackupex 2012-01-23 21:39:00 +0000
29+++ innobackupex 2012-01-26 03:26:24 +0000
30@@ -436,9 +436,9 @@
31 and Die "Failed to stream 'xtrabackup_logfile': $!";
32 unlink $tmp_logfile || Die "Failed to delete '$tmp_logfile': $!";
33
34- system("cd $orig_datadir; tar chf - xtrabackup_checkpoints")
35+ system("cd $option_tmpdir; tar chf - xtrabackup_checkpoints")
36 and Die "Failed to stream 'xtrabackup_checkpoints': $!";
37- unlink "$orig_datadir/xtrabackup_checkpoints" || Die "Failed to delete '$orig_datadir/xtrabackup_checkpoints': $!";
38+ unlink "$option_tmpdir/xtrabackup_checkpoints" || Die "Failed to delete '$option_tmpdir/xtrabackup_checkpoints': $!";
39 }
40
41 print STDERR "\n$prefix Backup created in directory '$backup_dir'\n";
42@@ -807,8 +807,8 @@
43 if (!$option_remote_host && !$option_stream) {
44 $options = $options . " --target-dir=$backup_dir";
45 } else {
46- #(datadir) for 'xtrabackup_suspended' and 'xtrabackup_checkpoints'
47- $options = $options . " --log-stream --target-dir=./";
48+ #(tmpdir) for 'xtrabackup_suspended' and 'xtrabackup_checkpoints'
49+ $options = $options . " --log-stream --target-dir=$option_tmpdir";
50 }
51
52 # prepare command line for running ibbackup
53@@ -1589,7 +1589,7 @@
54 $galera_info = $backup_dir . '/xtrabackup_galera_info';
55 $slave_info = $backup_dir . '/xtrabackup_slave_info';
56 } else {
57- $suspend_file = get_option(\%config, 'mysqld', 'datadir') . '/xtrabackup_suspended';
58+ $suspend_file = $option_tmpdir . '/xtrabackup_suspended';
59 $tmp_logfile = $option_tmpdir . '/xtrabackup_logfile';
60 if ($option_stream) {
61 $backup_config_file = $option_tmpdir . '/backup-my.cnf';
62
63=== added file 'kewpie/percona_tests/xtrabackup_main/bug489290_test.py'
64--- kewpie/percona_tests/xtrabackup_main/bug489290_test.py 1970-01-01 00:00:00 +0000
65+++ kewpie/percona_tests/xtrabackup_main/bug489290_test.py 2012-01-26 03:26:24 +0000
66@@ -0,0 +1,90 @@
67+#! /usr/bin/env python
68+# -*- mode: python; indent-tabs-mode: nil; -*-
69+# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
70+#
71+# Copyright (C) 2012 Sergei Glushcenko
72+#
73+#
74+# This program is free software; you can redistribute it and/or modify
75+# it under the terms of the GNU General Public License as published by
76+# the Free Software Foundation; either version 2 of the License, or
77+# (at your option) any later version.
78+#
79+# This program is distributed in the hope that it will be useful,
80+# but WITHOUT ANY WARRANTY; without even the implied warranty of
81+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
82+# GNU General Public License for more details.
83+#
84+# You should have received a copy of the GNU General Public License
85+# along with this program; if not, write to the Free Software
86+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
87+
88+import os
89+import time
90+import shutil
91+import signal
92+import subprocess
93+
94+from lib.util.mysqlBaseTestCase import mysqlBaseTestCase
95+
96+server_requirements = [[]]
97+servers = []
98+server_manager = None
99+test_executor = None
100+# we explicitly use the --no-timestamp option
101+# here. We will be using a generic / vanilla backup dir
102+backup_path = None
103+
104+class basicTest(mysqlBaseTestCase):
105+
106+ def setUp(self):
107+ master_server = servers[0] # assumption that this is 'master'
108+ backup_path = os.path.join(master_server.vardir, '_xtrabackup')
109+ # remove backup path
110+ if os.path.exists(backup_path):
111+ shutil.rmtree(backup_path)
112+
113+ def test_bug489290(self):
114+ self.servers = servers
115+ logging = test_executor.logging
116+ if servers[0].type not in ['mysql','percona']:
117+ return
118+ else:
119+ xtrabackup = test_executor.system_manager.xtrabackup_path
120+ master_server = servers[0] # assumption that this is 'master'
121+ backup_path = os.path.join(master_server.vardir, 'full_backup')
122+ backup_path_rel = os.path.relpath(backup_path)
123+ output_path = os.path.join(master_server.vardir, 'innobackupex.out')
124+
125+ self.assertFalse(os.path.exists(backup_path))
126+
127+ # populate our server with a test bed
128+ test_cmd = "./gentest.pl --gendata=conf/percona/percona.zz"
129+ retcode, output = self.execute_randgen(test_cmd, test_executor, master_server)
130+
131+ # take a backup
132+ cmd = [ xtrabackup
133+ , "--defaults-file=%s" %master_server.cnf_file
134+ , "--datadir=%s" %master_server.datadir
135+ , "--backup"
136+ , "--target-dir=%s" %backup_path_rel
137+ ]
138+ cmd = " ".join(cmd)
139+ retcode, output = self.execute_cmd(cmd, output_path, os.getcwd(), True)
140+ self.assertTrue(retcode==0,output)
141+
142+ # assure that backup been put in the right place
143+ self.assertTrue(os.path.exists(backup_path))
144+
145+ # prepare backup
146+ cmd = [ xtrabackup
147+ , "--defaults-file=%s" %master_server.cnf_file
148+ , "--prepare"
149+ , "--target-dir=%s" %backup_path_rel
150+ ]
151+ cmd = " ".join(cmd)
152+ retcode, output = self.execute_cmd(cmd, output_path, os.getcwd(), True)
153+ self.assertTrue(retcode==0,output)
154+
155+ # assure that backup been put in the right place
156+ self.assertTrue(os.path.exists(backup_path))
157
158=== added file 'test/t/bug489290.sh'
159--- test/t/bug489290.sh 1970-01-01 00:00:00 +0000
160+++ test/t/bug489290.sh 2012-01-26 03:26:24 +0000
161@@ -0,0 +1,42 @@
162+. inc/common.sh
163+
164+init
165+run_mysqld
166+load_dbase_schema sakila
167+load_dbase_data sakila
168+
169+backup_dir=$topdir/backup
170+mkdir -p $backup_dir
171+vlog "Backup created in directory $backup_dir"
172+
173+cwd=`pwd`
174+cd $topdir
175+
176+# Backup
177+xtrabackup --datadir=$mysql_datadir --backup --target-dir=backup
178+
179+# Stat
180+xtrabackup --datadir=$mysql_datadir --stat --target-dir=backup
181+
182+# Assure that directory is correct
183+if [ ! -f $backup_dir/ibdata1 ] ; then
184+ vlog "Backup not found in $backup_dir"
185+ exit -1
186+fi
187+
188+# Prepare
189+xtrabackup --datadir=$mysql_datadir --prepare --target-dir=backup
190+
191+cd $cwd
192+
193+stop_mysqld
194+
195+# Restore
196+rm -rf $mysql_datadir/ibdata1 $mysql_datadir/ib_logfile* \
197+ $mysql_datadir/test/*.ibd
198+cp -r $topdir/backup/* $mysql_datadir
199+
200+run_mysqld
201+
202+# Check sakila
203+run_cmd ${MYSQL} ${MYSQL_ARGS} -e "SELECT count(*) from actor" sakila
204
205=== modified file 'xtrabackup.c'
206--- xtrabackup.c 2012-01-09 05:27:16 +0000
207+++ xtrabackup.c 2012-01-26 03:26:24 +0000
208@@ -3696,6 +3696,17 @@
209 OS_THREAD_DUMMY_RETURN;
210 }
211
212+/**************************************************************************
213+Uses my_realpath to build absolute path for target dir.*/
214+static void
215+expand_target_dir_name()
216+{
217+ char buf[FN_REFLEN];
218+
219+ strnmov(buf, xtrabackup_target_dir, sizeof(buf) - 1);
220+ xtrabackup_target_dir = my_load_path(xtrabackup_real_target_dir, buf, NULL);
221+}
222+
223 static void
224 xtrabackup_backup_func(void)
225 {
226@@ -6209,6 +6220,9 @@
227 exit(EXIT_FAILURE);
228 }
229
230+ /* Ensure target dir is not relative to datadir */
231+ expand_target_dir_name();
232+
233 /* Redirect stdout to stderr for not doing a streaming backup or dumping
234 configuration for --print-param. */
235 if (!xtrabackup_stream && !xtrabackup_print_param && dup2(2, 1) < 0) {

Subscribers

People subscribed via source and target branches