Merge lp:~akopytov/percona-xtrabackup/use-dbd-mysql-in-innobackupex into lp:percona-xtrabackup/2.1
- use-dbd-mysql-in-innobackupex
- Merge into 2.1
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Alexey Kopytov | ||||
Approved revision: | 487 | ||||
Merged at revision: | 494 | ||||
Proposed branch: | lp:~akopytov/percona-xtrabackup/use-dbd-mysql-in-innobackupex | ||||
Merge into: | lp:percona-xtrabackup/2.1 | ||||
Diff against target: |
1067 lines (+346/-381) 4 files modified
doc/source/innobackupex/privileges.rst (+0/-4) innobackupex (+340/-371) test/t/bug729843.sh (+2/-3) test/t/bug977101.sh (+4/-3) |
||||
To merge this branch: | bzr merge lp:~akopytov/percona-xtrabackup/use-dbd-mysql-in-innobackupex | ||||
Related bugs: |
|
||||
Related blueprints: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Stewart Smith (community) | Approve | ||
Daniel Nichter (community) | Needs Fixing | ||
Laurynas Biveinis (community) | Approve | ||
Review via email:
|
Commit message
Description of the change
Blueprint "Use Perl DBD::MySQL for server communication in
innobackupex".
https:/

Alexey Kopytov (akopytov) wrote : | # |

Alexey Kopytov (akopytov) wrote : | # |
Had to rework keepalives as the signal-based implementation was conflicting with DBD due to a Perl bug resulting in sporadic failures in the previous Jenkins build. Jenkins build with changed keepalive logic: http://

Alexey Kopytov (akopytov) wrote : | # |
Setting to Work In Progress, because I'd like to include fix for bug #1092235. That, however, would require reverting the documentation fix for bug #1092235 in this branch. Will implement a proper fix and update docs once the limitation is documented and merged to main branches.

Alexey Kopytov (akopytov) wrote : | # |
Reverted the documentation fix for bug #1092235. Ready for reviews.
http://

Laurynas Biveinis (laurynas-biveinis) wrote : | # |
I have reviewed this, but this MP about exceeds my Perl skills. Please get a quick glance from Daniel or Brian, or some other Perl expert. Thus approving but leaving at "Needs Review."

Daniel Nichter (daniel-nichter) wrote : | # |
I don't know if the script declares this in its main package, but if not:
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
No production Perl program should run without those. Then:
s/$@/$EVAL_ERROR/g
s/$!/$CHILD_ERROR/g
etc. See http://
---
This
20 +# check existence of DBD::mysql module
21 +my $dbd_mysql_
22 +
23 +BEGIN {
24 + eval "use DBD::mysql";
25 + $dbd_mysql_
26 +}
27 +
is better written like:
eval {
require DBD::mysql;
};
my $have_dbd_mysql = $EVAL_ERROR ? 0 : 1;
---
Typo:
322 + Die "Keep-alive process has already been started for this connection."
395 + Die "Keep-alive process has never been started for this connection."
etc.
s/Die/die/
---
With hashes like
45 +my %mysql;
97 + %mysql = mysql_connect({
152 + wait_for_
it's best to return and pass hashrefs (and arrayrefs). So instead of
return %hash
a sub should
my %hash = ( ... );
return \%hash;
or
my $hash = { ... };
return $hash;
I almost never use "regular" arrays (@foo) or hashes (%foo) unless there's a good reason.
And sometimes using a hash like this is a sign that the hash should be turned into a class/object.
---
For sub args like
97 + %mysql = mysql_connect({
98 + abort_on_error => 0,
99 + keepalives => 0
100 + });
the general standard is
hello(arg1 => "foo", arg2 => $bar); # caller
sub hello {
my (%args) = @_;
my $args1 = $args{args1};
my $args2 = $args{args2};
...
Then you can do things like check for required args, have optional args (e.g. $optional_arg = $args{whatever} || 42;).
---
For eval like
347 + eval {
348 + $con->{
349 + };
350 +
351 + $rc = 255 if $@;
it's good to adopt this style:
eval {
...
};
if ( $EVAL_ERROR ) {
...
}
So always put an explicit check of $EVAL_ERROR after and eval {} block. This is core Perl's equivalent to try {} catch {}. (There's a real try-catch syntax with a non-core module, but it has serious limitations imho.)
---
Using 'and' as in
846 -if($var_version =~ m/5\.1\.\d/ and $var_innodb_version =~ m/.*/){
isn't preferred because it has different precedence than '&&', so '&&' is used in most cases. 'or' is the common exception in Perl, used very often like:
open my $fh, '>', $file or die "Error opening $file: $OS_ERROR";
===
Setting review to "Needs Fixing" because of "Die" (see above); that will cause the tool to die with a syntax error rather than the intended error message.

Alexey Kopytov (akopytov) wrote : | # |
Hi Daniel,
Thanks for the review.
On Mon, 04 Feb 2013 21:56:20 -0000, Daniel Nichter wrote:
> Review: Needs Fixing
>
> I don't know if the script declares this in its main package, but if not:
>
> use strict;
> use warnings FATAL => 'all';
> use English qw(-no_match_vars);
>
We have:
use strict;
use English qw(-no_match_vars);
> No production Perl program should run without those. Then:
>
> s/$@/$EVAL_ERROR/g
> s/$!/$CHILD_ERROR/g
>
> etc. See http://
>
The above page describes "$@" as a synonym for "$EVAL_ERROR", and "$?"
as a synonym for "$CHILD_ERROR". It doesn't explain why one form would
be preferable over the other one. In fact, examples use the short form
"@" and "$?".
> ---
>
> This
>
> 20 +# check existence of DBD::mysql module
> 21 +my $dbd_mysql_
> 22 +
> 23 +BEGIN {
> 24 + eval "use DBD::mysql";
> 25 + $dbd_mysql_
> 26 +}
> 27 +
>
> is better written like:
>
> eval {
> require DBD::mysql;
> };
> my $have_dbd_mysql = $EVAL_ERROR ? 0 : 1;
>
OK.
> ---
>
> Typo:
>
> 322 + Die "Keep-alive process has already been started for this connection."
> 395 + Die "Keep-alive process has never been started for this connection."
> etc.
>
> s/Die/die/
>
No, we do have the Die subroutine in innobackupex. Which also makes sure
we call all child processes before calling real "die".
> ---
>
> With hashes like
>
> 45 +my %mysql;
> 97 + %mysql = mysql_connect({
> 152 + wait_for_
>
> it's best to return and pass hashrefs (and arrayrefs). So instead of
>
> return %hash
>
> a sub should
>
> my %hash = ( ... );
> return \%hash;
>
> or
>
> my $hash = { ... };
> return $hash;
>
> I almost never use "regular" arrays (@foo) or hashes (%foo) unless there's a good reason.
>
Yes, my take on this is that if hash is supposed to be small, it's
acceptable to return the hash itself rather than a reference, as that
provides cleaner syntax. There are other implications of returning
hashes, but none of them seem to apply to our case which is very very
simple.
> And sometimes using a hash like this is a sign that the hash should be turned into a class/object.
>
> ---
>
> For sub args like
>
> 97 + %mysql = mysql_connect({
> 98 + abort_on_error => 0,
> 99 + keepalives => 0
> 100 + });
>
> the general standard is
>
> hello(arg1 => "foo", arg2 => $bar); # caller
>
> sub hello {
> my (%args) = @_;
> my $args1 = $args{args1};
> my $args2 = $args{args2};
> ...
>
> Then you can do things like check for required args, have optional args (e.g. $optional_arg = $args{whatever} || 42;).
>
Sure, but that's exactly what I use. I.e. pass a hash of arguments, have
optional args, etc.?
> ---
>
> For eval like
>
> 347 + eval {
> 348 + $con->{
> 349 + };
> 350 +
> 351 + $rc = 255 if $@;
>
> it's good to adopt this style:
>
> eval {
> ...
> };
> if ( $EVAL_ERROR ) {
> ...
> ...
- 487. By Alexey Kopytov
-
Blueprint "Use Perl DBD::MySQL for server communication in innobackupex".
https:/
/blueprints. launchpad. net/percona- xtrabackup/ +spec/use- dbd-mysql- in-innobackupex

Alexey Kopytov (akopytov) wrote : | # |
Changes made:
- s/$@/$EVAL_ERROR/g. I didn't do the same for CHILD_ERROR, as we have plenty of existing code using $!, and that would blow the diff for this change unnecessarily.
- rewrote the DBD::mysql detection code as suggested
- rewrote "$rc = 255 if $@;" constructs as suggested ("if ($EVAL_ERROR) {...}")
- replaced "and" with "&&" in the existing code touched by this patch.
I have also reported bug #1116177 as a followup to the "use warnings FATAL => 'all'" suggestion, as that seems to reveal a couple of bugs in the existing code which should be fixed in all branches.
Jenkins build with the updated branch: http://

Alexey Kopytov (akopytov) wrote : | # |
No response from Danial, assuming approved.

Stewart Smith (stewart) wrote : | # |
I'm in full support of this patch even if it breaks something, maintenance will be improved by several orders of magnitude.
Preview Diff
1 | === modified file 'doc/source/innobackupex/privileges.rst' |
2 | --- doc/source/innobackupex/privileges.rst 2013-01-17 15:08:37 +0000 |
3 | +++ doc/source/innobackupex/privileges.rst 2013-02-05 11:56:22 +0000 |
4 | @@ -66,7 +66,3 @@ |
5 | mysql> CREATE USER 'bkpuser'@'localhost' IDENTIFIED BY 's3cret'; |
6 | mysql> GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'bkpuser'@'localhost'; |
7 | mysql> FLUSH PRIVILEGES; |
8 | - |
9 | -.. note:: |
10 | - |
11 | - Connection-related parameters are only recognized in the [client] and [mysql] groups in configuration files. Adding custom groups like [xtrabackup] will work only if XtraBackup binary is used, it will not work with the innobackupex. |
12 | |
13 | === modified file 'innobackupex' |
14 | --- innobackupex 2013-01-22 01:23:45 +0000 |
15 | +++ innobackupex 2013-02-05 11:56:22 +0000 |
16 | @@ -39,6 +39,12 @@ |
17 | my @required_perl_version = (5, 0, 5); |
18 | my $required_perl_version_old_style = 5.005; |
19 | |
20 | +# check existence of DBD::mysql module |
21 | +eval { |
22 | + require DBD::mysql; |
23 | +}; |
24 | +my $dbd_mysql_installed = $EVAL_ERROR ? 0 : 1; |
25 | + |
26 | # force flush after every write and print |
27 | $| = 1; |
28 | |
29 | @@ -53,9 +59,6 @@ |
30 | # separately printed when a backup is made |
31 | my $backup_file_print_limit = 9; |
32 | |
33 | -# timeout in seconds for a reply from mysql |
34 | -my $mysql_response_timeout = 900; |
35 | - |
36 | # default compression level (this is an argument to ibbackup) |
37 | my $default_compression_level = 1; |
38 | |
39 | @@ -121,6 +124,9 @@ |
40 | my $option_compact = ''; |
41 | my $option_rebuild_indexes = ''; |
42 | |
43 | +my %mysql; |
44 | +my $option_backup = ''; |
45 | + |
46 | # name of the my.cnf configuration file |
47 | #my $config_file = ''; |
48 | |
49 | @@ -160,20 +166,9 @@ |
50 | # prefix for output lines |
51 | my $prefix = "$innobackup_script:"; |
52 | |
53 | -# process id of mysql client program (runs as a child process of this script) |
54 | -my $mysql_pid = ''; |
55 | - |
56 | # mysql server version string |
57 | my $mysql_server_version = ''; |
58 | |
59 | -# name of the file where stderr of mysql process is directed |
60 | -my $mysql_stderr_fh = File::Temp->new(); |
61 | -my $mysql_stderr = $mysql_stderr_fh->filename; |
62 | - |
63 | -# name of the file where stdout of mysql process is directed |
64 | -my $mysql_stdout_fh = File::Temp->new(); |
65 | -my $mysql_stdout = $mysql_stdout_fh->filename; |
66 | - |
67 | # name of the file where binlog position info is written |
68 | my $binlog_info; |
69 | |
70 | @@ -196,12 +191,6 @@ |
71 | # a counter for numbering mysql connection checks |
72 | my $hello_id = 0; |
73 | |
74 | -# the request which has been sent to mysqld, but to which |
75 | -# mysqld has not yet replied. Empty string denotes that no |
76 | -# request has been sent to mysqld or that mysqld has replied |
77 | -# to all requests. |
78 | -my $current_mysql_request = ''; |
79 | - |
80 | # escape sequences for options files |
81 | my %option_value_escapes = ('b' => "\b", |
82 | 't' => "\t", |
83 | @@ -255,29 +244,29 @@ |
84 | close XTRABACKUP_BINARY; |
85 | } |
86 | |
87 | - else { |
88 | + else { |
89 | if( $option_ibbackup_binary eq "autodetect" ){ |
90 | # Try to connect MySQL and get the version |
91 | - print STDERR "option_ibbackup_binary is autodetect, trying to connect to MySQL\n"; |
92 | - my $options = get_mysql_options(); |
93 | - $mysql_pid = open(*MYSQL_WRITER, "| mysql $options >$mysql_stdout 2>$mysql_stderr "); |
94 | - print STDERR "Connected to MySQL with pid $mysql_pid\n"; |
95 | - sleep 1; |
96 | - if ($mysql_pid && $mysql_pid == waitpid($mysql_pid, &WNOHANG)) { |
97 | - my $reason = `cat $mysql_stderr`; |
98 | - $mysql_pid = ''; |
99 | - # Failed to connect to MySQL |
100 | - die "Failed to connect to MySQL server to detect version.\nYou must set xtrabackup version to use with --ibbackup option.\nPossible values are xtrabackup_55 (for MySQL 5.5) or xtrabackup (for MySQL 5.1 with InnoDB plugin or Percona Server)\n"; |
101 | - } |
102 | - else{ |
103 | - mysql_close(); |
104 | - print STDERR "Connected successfully\n"; |
105 | - $option_ibbackup_binary = set_xtrabackup_version(); |
106 | - } |
107 | - } |
108 | + %mysql = mysql_connect( |
109 | + abort_on_error => 0, |
110 | + keepalives => 0 |
111 | + ); |
112 | + if ($mysql{dbh}) { |
113 | + print STDERR "Connected successfully\n"; |
114 | + $option_ibbackup_binary = set_xtrabackup_version(); |
115 | + mysql_close(); |
116 | + } else { |
117 | + die "Failed to connect to MySQL server to detect version.\nYou must set xtrabackup version to use with --ibbackup option.\nPossible values are xtrabackup_55 (for MySQL 5.5) or xtrabackup (for MySQL 5.1 with InnoDB plugin or Percona Server)\n"; |
118 | + } |
119 | } |
120 | -} elsif ($option_ibbackup_binary eq 'autodetect') { |
121 | - $option_ibbackup_binary = set_xtrabackup_version(); |
122 | + } |
123 | +} elsif ($option_backup) { |
124 | + # backup |
125 | + %mysql = mysql_connect(abort_on_error => 1, keepalives => 1); |
126 | + |
127 | + if ($option_ibbackup_binary eq 'autodetect') { |
128 | + $option_ibbackup_binary = set_xtrabackup_version(); |
129 | + } |
130 | } |
131 | init(); |
132 | |
133 | @@ -295,6 +284,9 @@ |
134 | } else { |
135 | # make a backup of InnoDB and MyISAM tables, indexes and .frm files. |
136 | $ibbackup_exit_code = backup(); |
137 | + |
138 | + mysql_close(\%mysql); |
139 | + |
140 | if ($option_stream) { |
141 | open XTRABACKUP_BINARY, "> $option_tmpdir/$xtrabackup_binary_file" |
142 | || die "Cannot open file $option_tmpdir/$xtrabackup_binary_file: $!\n"; |
143 | @@ -367,16 +359,11 @@ |
144 | # |
145 | sub Die { |
146 | my $message = shift; |
147 | - my $extra_info = ''; |
148 | |
149 | # kill all child processes of this process |
150 | kill_child_processes(); |
151 | |
152 | - if ($current_mysql_request) { |
153 | - $extra_info = " while waiting for reply to MySQL request:" . |
154 | - " '$current_mysql_request'"; |
155 | - } |
156 | - die "$prefix Error: $message$extra_info"; |
157 | + die "$prefix Error: $message"; |
158 | } |
159 | |
160 | |
161 | @@ -388,22 +375,14 @@ |
162 | sub backup { |
163 | my $orig_datadir = get_option(\%config, $option_defaults_group, 'datadir'); |
164 | |
165 | - # check that we can connect to the database. This done by |
166 | - # connecting, issuing a query, and closing the connection. |
167 | - mysql_open(); |
168 | - mysql_close(); |
169 | - |
170 | # start ibbackup as a child process |
171 | start_ibbackup(); |
172 | |
173 | # wait for ibbackup to suspend itself |
174 | wait_for_ibbackup_suspend(); |
175 | |
176 | - # connect to database |
177 | - mysql_open(); |
178 | - |
179 | if ($option_safe_slave_backup) { |
180 | - wait_for_safe_slave(); |
181 | + wait_for_safe_slave(\%mysql); |
182 | } |
183 | |
184 | # flush tables with read lock |
185 | @@ -412,11 +391,11 @@ |
186 | backup_files(1); |
187 | |
188 | # flush tables with read lock |
189 | - mysql_lockall(); |
190 | + mysql_lockall(\%mysql); |
191 | } |
192 | |
193 | if ($option_slave_info) { |
194 | - write_slave_info(); |
195 | + write_slave_info(\%mysql); |
196 | } |
197 | |
198 | |
199 | @@ -428,18 +407,15 @@ |
200 | resume_ibbackup(); |
201 | |
202 | # release read locks on all tables |
203 | - mysql_unlockall() if !$option_no_lock; |
204 | + mysql_unlockall(\%mysql) if !$option_no_lock; |
205 | |
206 | my $ibbackup_exit_code = wait_for_ibbackup_finish(); |
207 | |
208 | if ( $option_safe_slave_backup && $sql_thread_started) { |
209 | print STDERR "$prefix: Starting slave SQL thread\n"; |
210 | - mysql_send('START SLAVE SQL_THREAD;'); |
211 | + mysql_query(\%mysql, 'START SLAVE SQL_THREAD;'); |
212 | } |
213 | |
214 | - # Close the DB connection |
215 | - mysql_close(); |
216 | - |
217 | # copy ib_lru_dump |
218 | if (-e "$orig_datadir/ib_lru_dump") { |
219 | if ($option_stream) { |
220 | @@ -1084,194 +1060,249 @@ |
221 | |
222 | |
223 | # |
224 | -# get_mysql_options subroutine returns the options to mysql client program |
225 | -# as a string. The options are determined from the options given by the |
226 | -# user to innobackup. |
227 | +# parse_connection_options() subroutine parses connection-related command line |
228 | +# options |
229 | # |
230 | -sub get_mysql_options { |
231 | - my $options = ''; |
232 | +sub parse_connection_options { |
233 | + my $con = shift; |
234 | + |
235 | + $con->{dsn} = 'dbi:mysql:'; |
236 | |
237 | # this option has to be first |
238 | if ($option_defaults_file) { |
239 | - $options = "$options --defaults-file='$option_defaults_file'"; |
240 | + $con->{dsn} .= ";mysql_read_default_file=$option_defaults_file"; |
241 | } |
242 | |
243 | if ($option_defaults_extra_file) { |
244 | - $options = $options . " --defaults-extra-file=\"$option_defaults_extra_file\" "; |
245 | + $con->{dsn} .= ";mysql_read_default_file=$option_defaults_extra_file"; |
246 | } |
247 | |
248 | + $con->{dsn} .= ";mysql_read_default_group=xtrabackup"; |
249 | + |
250 | if ($option_mysql_password) { |
251 | - $options = "$options --password='$option_mysql_password'"; |
252 | + $con->{dsn_password} = "$option_mysql_password"; |
253 | } |
254 | if ($option_mysql_user) { |
255 | - $options = "$options --user='$option_mysql_user'"; |
256 | + $con->{dsn_user} = "$option_mysql_user"; |
257 | } |
258 | if ($option_mysql_host) { |
259 | - $options = "$options --host='$option_mysql_host'"; |
260 | + $con->{dsn} .= ";host=$option_mysql_host"; |
261 | } |
262 | if ($option_mysql_port) { |
263 | - $options = "$options --port='$option_mysql_port'"; |
264 | + $con->{dsn} .= ";port=$option_mysql_port"; |
265 | } |
266 | if ($option_mysql_socket) { |
267 | - $options = "$options --socket='$option_mysql_socket'"; |
268 | - } |
269 | - $options = "$options --unbuffered --"; |
270 | - return $options; |
271 | -} |
272 | - |
273 | - |
274 | -# |
275 | -# Check that the server is responding to queries |
276 | -# |
277 | -sub mysql_ping { |
278 | - my $alarm_handler = shift; |
279 | - my $mysql_pid_copy = $mysql_pid; |
280 | - |
281 | - # send a dummy query to mysql child process |
282 | - $hello_id++; |
283 | - |
284 | - my $hello_message = "xtrabackup ping $hello_id"; |
285 | - print MYSQL_WRITER "select '$hello_message';\n" |
286 | - or Die "Connection to mysql child process failed: $!"; |
287 | - |
288 | - # Don't check server's response if running in a signal handler |
289 | - # because that breaks system() calls |
290 | - if ($alarm_handler) |
291 | - { |
292 | - return 0; |
293 | - } |
294 | - # wait for reply |
295 | - eval { |
296 | - local $SIG{ALRM} = sub { die "alarm clock restart" }; |
297 | - my $stdout = ''; |
298 | - my $stderr = ''; |
299 | - alarm $mysql_response_timeout; |
300 | - while (index($stdout, $hello_message) < 0) { |
301 | - sleep 2; |
302 | - if ($mysql_pid && $mysql_pid == waitpid($mysql_pid, &WNOHANG)) { |
303 | - my $reason = `cat $mysql_stderr`; |
304 | - $mysql_pid = ''; |
305 | - die "mysql child process has died: $reason"; |
306 | - } |
307 | - $stdout = `cat $mysql_stdout`; |
308 | - $stderr = `cat $mysql_stderr | grep -v ^Warning`; |
309 | - if ($stderr) { |
310 | - # mysql has reported an error, do exit |
311 | - die "mysql error: $stderr"; |
312 | - } |
313 | - } |
314 | - alarm 0; |
315 | - }; |
316 | - if ($@ =~ /alarm clock restart/) { |
317 | - Die "Connection to mysql child process (pid=$mysql_pid_copy) timedout." |
318 | - . " (Time limit of $mysql_response_timeout seconds exceeded." |
319 | - . " You may adjust time limit by editing the value of parameter" |
320 | - . " \"\$mysql_response_timeout\" in this script.)"; |
321 | - } elsif ($@) { Die $@; } |
322 | -} |
323 | - |
324 | - |
325 | -# |
326 | -# SIGALRM handler which sends a keepalive query to the server |
327 | -# |
328 | -sub catch_sigalrm { |
329 | - mysql_ping(1); |
330 | - # Reschedule SIGALRM |
331 | - alarm $mysql_keep_alive; |
332 | -} |
333 | - |
334 | - |
335 | -# |
336 | -# Schedule periodic server pings |
337 | + $con->{dsn} .= ";mysql_socket=$option_mysql_socket"; |
338 | + } |
339 | +} |
340 | + |
341 | +# |
342 | +# Start a background process that will send keep-alive queries periodically |
343 | +# using the connection passed as a 'mysql' hash reference |
344 | # |
345 | sub start_keepalives { |
346 | - $SIG{ALRM} = \&catch_sigalrm; |
347 | - alarm $mysql_keep_alive; |
348 | + my $con = shift; |
349 | + |
350 | + if (defined($con->{keep_alive_pid})) { |
351 | + Die "Keep-alive process has already been started for this connection." |
352 | + } |
353 | + |
354 | + my $keep_alive_pid = fork(); |
355 | + |
356 | + if ($keep_alive_pid) { |
357 | + # parent process |
358 | + $con->{keep_alive_pid} = $keep_alive_pid; |
359 | + |
360 | + return; |
361 | + } |
362 | + |
363 | + # child process |
364 | + $con->{dbh}->{InactiveDestroy} = 1; |
365 | + |
366 | + my $rc = 0; |
367 | + my $hello_id = 0; |
368 | + |
369 | + # send dummy queries to connection until interrupted with SIGINT or a |
370 | + # connection error |
371 | + while (!$rc) { |
372 | + sleep $mysql_keep_alive; |
373 | + |
374 | + my $hello_message = "xtrabackup ping " . $hello_id++; |
375 | + |
376 | + eval { |
377 | + $con->{dbh}->selectrow_array("select '$hello_message'"); |
378 | + }; |
379 | + |
380 | + if ($EVAL_ERROR) { |
381 | + $rc = 255; |
382 | + } |
383 | + } |
384 | + |
385 | + exit $rc; |
386 | } |
387 | |
388 | # |
389 | -# Cancel periodic server pings |
390 | +# Stop the background keep-alive process |
391 | # |
392 | sub stop_keepalives { |
393 | - alarm 0; |
394 | - $SIG{ALRM} = "DEFAULT"; |
395 | -} |
396 | - |
397 | -# |
398 | -# mysql_open subroutine starts mysql as a child process with |
399 | -# a pipe connection. |
400 | -# |
401 | -sub mysql_open { |
402 | - my $options = get_mysql_options(); |
403 | - # run mysql as a child process with a pipe connection |
404 | - $now = current_time(); |
405 | - (my $prt_options = $options) =~ s/--password=[^ ]+ /--password=xxxxxxxx /g; |
406 | - print STDERR "$now $prefix Starting mysql with options: $prt_options\n"; |
407 | - $mysql_pid = open(*MYSQL_WRITER, "| mysql $options >$mysql_stdout 2>$mysql_stderr ") or Die "Failed to spawn mysql child process: $!"; |
408 | - MYSQL_WRITER->autoflush(1); |
409 | - $now = current_time(); |
410 | - print STDERR "$now $prefix Connected to database with mysql child process (pid=$mysql_pid)\n"; |
411 | - print MYSQL_WRITER "SET SESSION wait_timeout = 2147000;\n" or die "Connection to mysql child process failed: $!"; |
412 | - |
413 | - mysql_ping(0); |
414 | - |
415 | - start_keepalives(); |
416 | -} |
417 | - |
418 | - |
419 | -# |
420 | -# mysql_send subroutine send a request string to mysql child process. |
421 | -# This subroutine appends a newline character to the request and checks |
422 | -# that mysqld receives the query. |
423 | + my $con = shift; |
424 | + |
425 | + if (!defined($con->{keep_alive_pid})) { |
426 | + Die "Keep-alive process has never been started for this connection." |
427 | + } |
428 | + |
429 | + kill 'INT', $con->{keep_alive_pid}; |
430 | + waitpid($con->{keep_alive_pid}, 0); |
431 | + my $rc = $? >> 8; |
432 | + |
433 | + if ($rc != 0) { |
434 | + Die "Keep-alive process died with exit code " . $rc; |
435 | + } |
436 | + undef $con->{keep_alive_pid}; |
437 | +} |
438 | + |
439 | +# |
440 | +# mysql_connect subroutine connects to MySQL server |
441 | +# |
442 | +sub mysql_connect { |
443 | + my %con; |
444 | + my %args = ( |
445 | + # Defaults |
446 | + abort_on_error => 1, |
447 | + keepalives => 0, |
448 | + @_ |
449 | + ); |
450 | + |
451 | + $con{abort_on_error} = $args{abort_on_error}; |
452 | + $con{keepalives} = $args{keepalives}; |
453 | + |
454 | + parse_connection_options(\%con); |
455 | + |
456 | + $now = current_time(); |
457 | + print STDERR "$now $prefix Connecting to MySQL server with DSN '" . |
458 | + $con{dsn} . "' as '" . $con{dsn_user} . "' (using password: "; |
459 | + if (defined($con{dsn_password})) { |
460 | + print STDERR "YES).\n"; |
461 | + } else { |
462 | + print STDERR "NO).\n"; |
463 | + } |
464 | + |
465 | + eval { |
466 | + $con{dbh}=DBI->connect($con{dsn}, $con{dsn_user}, |
467 | + $con{dsn_password}, { RaiseError => 1 }); |
468 | + }; |
469 | + |
470 | + if ($EVAL_ERROR) { |
471 | + $con{connect_error}=$EVAL_ERROR; |
472 | + } else { |
473 | + $now = current_time(); |
474 | + print STDERR "$now $prefix Connected to MySQL server\n"; |
475 | + } |
476 | + |
477 | + if ($args{abort_on_error}) { |
478 | + if (!$dbd_mysql_installed) { |
479 | + die "ERROR: Failed to connect to MySQL server as " . |
480 | + "DBD::mysql module is not installed"; |
481 | + } else { |
482 | + if (!$con{dbh}) { |
483 | + die "ERROR: Failed to connect to MySQL server: " . |
484 | + $con{connect_error}; |
485 | + } |
486 | + } |
487 | + } |
488 | + |
489 | + if ($con{dbh} && $con{keepalives}) { |
490 | + start_keepalives(\%con); |
491 | + } |
492 | + |
493 | + return %con; |
494 | +} |
495 | + |
496 | +# |
497 | +# mysql_query subroutine send a query to MySQL server child process. |
498 | # Parameters: |
499 | -# request request string |
500 | -# |
501 | -sub mysql_send { |
502 | - my $request = shift; |
503 | - |
504 | - stop_keepalives(); |
505 | - |
506 | - $current_mysql_request = $request; |
507 | - print MYSQL_WRITER "$request\n"; |
508 | - mysql_ping(0); |
509 | - $current_mysql_request = ''; |
510 | - |
511 | - start_keepalives(); |
512 | -} |
513 | - |
514 | - |
515 | -# |
516 | -# mysql_close subroutine terminates mysql child process gracefully. |
517 | +# query query to execute |
518 | +# |
519 | +sub mysql_query { |
520 | + my ($con, $query) = @_; |
521 | + |
522 | + eval { |
523 | + if ($con->{keepalives}) { |
524 | + stop_keepalives($con); |
525 | + } |
526 | + |
527 | + if ($query eq 'SHOW VARIABLES') { |
528 | + $con->{vars} = $con->{dbh}->selectall_hashref('SHOW VARIABLES', |
529 | + 'Variable_name'); |
530 | + } elsif ($query eq 'SHOW STATUS') { |
531 | + $con->{status} = $con->{dbh}->selectall_hashref('SHOW STATUS', |
532 | + 'Variable_name'); |
533 | + } elsif ($query eq 'SHOW MASTER STATUS') { |
534 | + $con->{master_status} = |
535 | + $con->{dbh}->selectrow_hashref("SHOW MASTER STATUS"); |
536 | + } elsif ($query eq 'SHOW SLAVE STATUS') { |
537 | + $con->{slave_status} = |
538 | + $con->{dbh}->selectrow_hashref("SHOW SLAVE STATUS"); |
539 | + } else { |
540 | + $con->{dbh}->do($query); |
541 | + } |
542 | + |
543 | + if ($con->{keepalives}) { |
544 | + start_keepalives($con); |
545 | + } |
546 | + }; |
547 | + if ($EVAL_ERROR) { |
548 | + Die "\nError executing '$query': $EVAL_ERROR\n"; |
549 | + } |
550 | +} |
551 | + |
552 | + |
553 | +sub get_mysql_vars { |
554 | + mysql_query($_[0], 'SHOW VARIABLES') |
555 | +} |
556 | + |
557 | +sub get_mysql_status { |
558 | + mysql_query($_[0], 'SHOW STATUS'); |
559 | +} |
560 | + |
561 | +sub get_mysql_master_status { |
562 | + mysql_query($_[0], "SHOW MASTER STATUS"); |
563 | +} |
564 | + |
565 | +sub get_mysql_slave_status { |
566 | + mysql_query($_[0], "SHOW SLAVE STATUS"); |
567 | +} |
568 | + |
569 | +# |
570 | +# mysql_close subroutine closes connection to MySQL server gracefully. |
571 | # |
572 | sub mysql_close { |
573 | - stop_keepalives(); |
574 | - |
575 | - print MYSQL_WRITER "quit\n"; |
576 | + my $con = shift; |
577 | + |
578 | + if ($con->{keepalives}) { |
579 | + stop_keepalives($con); |
580 | + }; |
581 | + |
582 | + $con->{dbh}->disconnect(); |
583 | + |
584 | $now = current_time(); |
585 | print STDERR "$now $prefix Connection to database server closed\n"; |
586 | - $mysql_pid = ''; |
587 | } |
588 | |
589 | - |
590 | # |
591 | # write_binlog_info subroutine retrieves MySQL binlog position and |
592 | # saves it in a file. It also prints it to stdout. |
593 | # |
594 | sub write_binlog_info { |
595 | - my @lines; |
596 | - my $position = ''; |
597 | - my $filename = ''; |
598 | + my $con = shift; |
599 | |
600 | # get binlog position |
601 | - mysql_send 'SHOW MASTER STATUS\G'; |
602 | + get_mysql_master_status($con); |
603 | |
604 | # get the name of the last binlog file and position in it |
605 | # from the SHOW MASTER STATUS output |
606 | - file_to_array($mysql_stdout, \@lines); |
607 | - foreach (@lines) { |
608 | - $filename = $1 if /^\s+File:\s(\S+)\s*$/; |
609 | - $position = $1 if /^\s+Position:\s(\d+)\s*$/; |
610 | - } |
611 | + my $filename = $con->{master_status}->{File}; |
612 | + my $position = $con->{master_status}->{Position}; |
613 | |
614 | # write binlog info file |
615 | open(FILE, ">$binlog_info") || Die "Failed to open file '$binlog_info': $!"; |
616 | @@ -1292,34 +1323,20 @@ |
617 | # saves it in a file. It also prints it to stdout. |
618 | # |
619 | sub write_galera_info { |
620 | + my $con = shift; |
621 | my @lines; |
622 | my @info_lines = (); |
623 | my $position = ''; |
624 | my $filename = ''; |
625 | |
626 | # get binlog position |
627 | - mysql_send "SHOW STATUS LIKE 'wsrep_local_state_uuid';"; |
628 | - mysql_send "SHOW STATUS LIKE 'wsrep_last_committed';"; |
629 | - |
630 | - # get "show master status" output lines (2) from mysql output |
631 | - file_to_array($mysql_stdout, \@lines); |
632 | + get_mysql_status($con); |
633 | |
634 | open(FILE, ">$galera_info") || |
635 | Die "Failed to open file '$galera_info': $!"; |
636 | |
637 | - foreach my $line (@lines) { |
638 | - if ($line =~ m/wsrep_local_state_uuid/) { |
639 | - $line =~ s/wsrep_local_state_uuid\s*//g; |
640 | - print FILE "$line:"; |
641 | - } |
642 | - } |
643 | - |
644 | - foreach my $line (@lines) { |
645 | - if ($line =~ m/wsrep_last_committed/) { |
646 | - $line =~ s/wsrep_last_committed\s*//g; |
647 | - print FILE "$line\n"; |
648 | - } |
649 | - } |
650 | + print FILE $con->{status}->{wsrep_local_state_uuid}->{Value}; |
651 | + print FILE $con->{status}->{wsrep_last_committed}->{Value}; |
652 | |
653 | close(FILE); |
654 | |
655 | @@ -1338,23 +1355,25 @@ |
656 | # also saves it in $msql_slave_position variable. |
657 | # |
658 | sub write_slave_info { |
659 | + my $con = shift; |
660 | + |
661 | my @lines; |
662 | my @info_lines; |
663 | my $position = ''; |
664 | my $filename = ''; |
665 | my $master= ''; |
666 | - |
667 | - # get slave status. Use single quotes here, otherwise |
668 | - # \G is evaluated as a control character. |
669 | - mysql_send 'SHOW SLAVE STATUS\G'; |
670 | + |
671 | + # get slave status |
672 | + get_mysql_slave_status($con); |
673 | |
674 | # get output of the "show slave status" command from mysql output |
675 | # and extract binlog position of the master server |
676 | - file_to_array($mysql_stdout, \@lines); |
677 | - for (@lines) { |
678 | - $master = $1 if /Master_Host:\s*(\S*)\s*$/; |
679 | - $filename = $1 if /Master_Log_File:\s*(\S*)\s*$/; |
680 | - $position = $1 if /Master_Log_Pos:\s*(\S*)\s*$/; |
681 | + $master = $con->{slave_status}->{Master_Host}; |
682 | + $filename = $con->{slave_status}->{Relay_Master_Log_File}; |
683 | + $position = $con->{slave_status}->{Exec_Master_Log_Pos}; |
684 | + |
685 | + if (!defined($master) || !defined($filename) || !defined($position)) { |
686 | + Die "Failed to get master binlog coordinates from SHOW SLAVE STATUS"; |
687 | } |
688 | |
689 | # print slave status to a file |
690 | @@ -1376,31 +1395,22 @@ |
691 | # mysql_lockall subroutine puts a read lock on all tables in all databases. |
692 | # |
693 | sub mysql_lockall { |
694 | + my $con = shift; |
695 | + |
696 | $now = current_time(); |
697 | print STDERR "$now $prefix Starting to lock all tables...\n"; |
698 | |
699 | - mysql_send "USE mysql;"; |
700 | -# mysql_send "DROP TABLE IF EXISTS ibbackup_binlog_marker;"; |
701 | -# if (compare_versions($mysql_server_version, '4.1.0') == -1) { |
702 | -# # MySQL server version is 4.0 or older, ENGINE keyword not supported |
703 | -# mysql_send "CREATE TABLE ibbackup_binlog_marker(a INT) TYPE=INNODB;"; |
704 | -# } else { |
705 | -# # MySQL server version is 4.1 or newer, use ENGINE keyword |
706 | -# mysql_send "CREATE TABLE ibbackup_binlog_marker(a INT) ENGINE=INNODB;"; |
707 | -# } |
708 | - mysql_send "SET AUTOCOMMIT=0;"; |
709 | -# mysql_send "INSERT INTO ibbackup_binlog_marker VALUES (1);"; |
710 | if (compare_versions($mysql_server_version, '4.0.22') == 0 |
711 | || compare_versions($mysql_server_version, '4.1.7') == 0) { |
712 | # MySQL server version is 4.0.22 or 4.1.7 |
713 | - mysql_send "COMMIT;"; |
714 | - mysql_send "FLUSH TABLES WITH READ LOCK;"; |
715 | + mysql_query($con, "COMMIT"); |
716 | + mysql_query($con, "FLUSH TABLES WITH READ LOCK"); |
717 | } else { |
718 | # MySQL server version is other than 4.0.22 or 4.1.7 |
719 | - mysql_send "FLUSH TABLES WITH READ LOCK;"; |
720 | - mysql_send "COMMIT;"; |
721 | + mysql_query($con, "FLUSH TABLES WITH READ LOCK"); |
722 | + mysql_query($con, "COMMIT"); |
723 | } |
724 | - write_binlog_info; |
725 | + write_binlog_info($con); |
726 | write_galera_info if $option_galera_info; |
727 | |
728 | $now = current_time(); |
729 | @@ -1413,32 +1423,14 @@ |
730 | # databases. |
731 | # |
732 | sub mysql_unlockall { |
733 | - mysql_send "UNLOCK TABLES;"; |
734 | -# mysql_send "DROP TABLE IF EXISTS ibbackup_binlog_marker;"; |
735 | + my $con = shift; |
736 | + |
737 | + mysql_query ($con, "UNLOCK TABLES"); |
738 | |
739 | $now = current_time(); |
740 | print STDERR "$now $prefix All tables unlocked\n"; |
741 | } |
742 | |
743 | - |
744 | -# |
745 | -# catch_sigpipe subroutine is a signal handler for SIGPIPE. |
746 | -# |
747 | -sub catch_sigpipe { |
748 | - my $rcode; |
749 | - |
750 | - if ($mysql_pid && (-1 == ($rcode = waitpid($mysql_pid, &WNOHANG)) |
751 | - || $rcode == $mysql_pid)) { |
752 | - my $reason = `cat $mysql_stderr`; |
753 | - print STDERR "Pipe to mysql child process broken: $reason at"; |
754 | - system("date +'%H:%M:%S'"); |
755 | - exit(1); |
756 | - } else { |
757 | - Die "Broken pipe"; |
758 | - } |
759 | -} |
760 | - |
761 | - |
762 | # |
763 | # kill_child_processes subroutine kills all child processes of this process. |
764 | # |
765 | @@ -1447,11 +1439,6 @@ |
766 | kill($kill_signal, $ibbackup_pid); |
767 | $ibbackup_pid = ''; |
768 | } |
769 | - |
770 | - if ($mysql_pid) { |
771 | - kill($kill_signal, $mysql_pid); |
772 | - $mysql_pid = ''; |
773 | - } |
774 | } |
775 | |
776 | |
777 | @@ -1580,24 +1567,12 @@ |
778 | print STDERR " At the end of a successful $run run $innobackup_script\n"; |
779 | print STDERR " prints \"completed OK!\".\n\n"; |
780 | |
781 | - # check that MySQL client program and InnoDB Hot Backup program |
782 | - # are runnable via shell |
783 | if (!$option_copy_back && !$option_move_back) { |
784 | # we are making a backup or applying log to backup |
785 | if (!$option_apply_log) { |
786 | # we are making a backup, we need mysql server |
787 | - my $output = ''; |
788 | - my @lines = (); |
789 | - |
790 | - # check that we have mysql client program |
791 | - require_external('mysql', '--version', 'Ver ([^,]+)', |
792 | - \$mysql_version); |
793 | - |
794 | - # get mysql server version |
795 | - my $options = get_mysql_options(); |
796 | - @lines = split('\n', |
797 | - `mysql $options -e "select \@\@version"`); |
798 | - $mysql_server_version = $lines[1]; |
799 | + get_mysql_vars(\%mysql); |
800 | + $mysql_server_version = $mysql{vars}->{version}->{Value}; |
801 | print STDERR "$prefix Using mysql server version $mysql_server_version\n"; |
802 | } |
803 | #require_external($option_ibbackup_binary, '--license', |
804 | @@ -1614,9 +1589,6 @@ |
805 | . " v2.0 in order to use --include option.\n"; |
806 | } |
807 | } |
808 | - |
809 | - # set signal handlers |
810 | - $SIG{PIPE} = \&catch_sigpipe; |
811 | |
812 | # read MySQL options file |
813 | #read_config_file($config_file, \%config); |
814 | @@ -1837,11 +1809,9 @@ |
815 | exit(1); |
816 | } |
817 | |
818 | - # get options file name |
819 | - #$config_file = $ARGV[0]; |
820 | - |
821 | if (!$option_apply_log && !$option_copy_back && !$option_move_back) { |
822 | # we are making a backup, get backup root directory |
823 | + $option_backup = "1"; |
824 | $backup_root = $ARGV[0]; |
825 | if ($option_incremental && !$option_incremental_lsn) { |
826 | my @dirs = `ls -1 -t $backup_root`; |
827 | @@ -2540,86 +2510,89 @@ |
828 | } |
829 | |
830 | sub set_xtrabackup_version { |
831 | -# Based on MySQL version choose correct binary |
832 | -# MySQL 5.1.* with InnoDB plugin - xtrabackup |
833 | -# MariaDB 5.1.* - xtrabackup |
834 | -# MariaDB 5.2.* - xtrabackup |
835 | -# MariaDB 5.3.* - xtrabackup |
836 | -# Percona Server 5.0 - xtrabackup_51 |
837 | -# Percona Server 5.1 - xtrabackup |
838 | -# Percona Server 5.5 - xtrabackup_55 |
839 | -# MySQL 5.5.* - xtrabackup_55 |
840 | -# MariaDB 5.5.* - xtrabackup_55 |
841 | - |
842 | -my @lines; |
843 | -my $var_version = ''; |
844 | -my $var_innodb_version = ''; |
845 | -my $ibbackup_binary; |
846 | -mysql_open(); |
847 | -mysql_send "SHOW VARIABLES LIKE 'version'\\G"; |
848 | -file_to_array($mysql_stdout, \@lines); |
849 | -for (@lines) { |
850 | - $var_version = $1 if /Value:\s+(\S+)/; |
851 | - } |
852 | -mysql_send "SHOW VARIABLES LIKE 'innodb_version'\\G"; |
853 | -file_to_array($mysql_stdout, \@lines); |
854 | -for (@lines) { |
855 | - $var_innodb_version = $1 if /Value:\s+(\S+)/; |
856 | - } |
857 | -if($var_version =~ m/5\.0\.\d/){ |
858 | + # Based on MySQL version choose correct binary |
859 | + # MySQL 5.1.* with InnoDB plugin - xtrabackup |
860 | + # MariaDB 5.1.* - xtrabackup |
861 | + # MariaDB 5.2.* - xtrabackup |
862 | + # MariaDB 5.3.* - xtrabackup |
863 | + # Percona Server 5.0 - xtrabackup_51 |
864 | + # Percona Server 5.1 - xtrabackup |
865 | + # Percona Server 5.5 - xtrabackup_55 |
866 | + # MySQL 5.5.* - xtrabackup_55 |
867 | + # MariaDB 5.5.* - xtrabackup_55 |
868 | + |
869 | + my $var_version = ''; |
870 | + my $var_innodb_version = ''; |
871 | + my $ibbackup_binary; |
872 | + |
873 | + get_mysql_vars(\%mysql); |
874 | + |
875 | + $var_version = $mysql{vars}->{version}->{Value}; |
876 | + $var_innodb_version = $mysql{vars}->{innodb_version}->{Value}; |
877 | + |
878 | + |
879 | + if($var_version =~ m/5\.0\.\d/) { |
880 | Die "MySQL 5.0 support was removed in Percona XtraBackup 2.1. The last version to support MySQL 5.0 was Percona XtraBackup 2.0."; |
881 | -} |
882 | -if($var_version =~ m/5\.1\.\d/ and $var_innodb_version =~ m/.*/){ |
883 | + } |
884 | + |
885 | + if($var_version =~ m/5\.1\.\d/ && $var_innodb_version =~ m/.*/) { |
886 | Die "Support for MySQL 5.1 with builtin InnoDB (not the plugin) was removed in Percona XtraBackup 2.1. The last version to support MySQL 5.1 with builtin InnoDB was Percona XtraBackup 2.0."; |
887 | -} |
888 | -if($var_version =~ m/5\.1\.\d/ and $var_innodb_version =~ m/1\.0\.\d+$/){ |
889 | - $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup'); |
890 | -} |
891 | -if($var_version =~ m/5\.1\.\d/ and $var_innodb_version =~ m/1\.0\.\d+-(rel)?\d/){ |
892 | - $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup'); |
893 | -} |
894 | -if($var_version =~ m/5\.2\.\d/){ |
895 | - $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup'); |
896 | -} |
897 | -if($var_version =~ m/5\.3\.\d/){ |
898 | - $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup'); |
899 | -} |
900 | -if($var_version =~ m/5\.5\.\d/){ |
901 | + } |
902 | + |
903 | + if($var_version =~ m/5\.1\.\d/ && $var_innodb_version =~ m/1\.0\.\d+$/) { |
904 | + $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup'); |
905 | + } |
906 | + |
907 | + if($var_version =~ m/5\.1\.\d/ && $var_innodb_version =~ m/1\.0\.\d+-(rel)?\d/){ |
908 | + $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup'); |
909 | + } |
910 | + |
911 | + if($var_version =~ m/5\.2\.\d/){ |
912 | + $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup'); |
913 | + } |
914 | + |
915 | + if($var_version =~ m/5\.3\.\d/){ |
916 | + $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup'); |
917 | + } |
918 | + |
919 | + if($var_version =~ m/5\.5\.\d/){ |
920 | $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup_55'); |
921 | -} |
922 | -mysql_close(); |
923 | -return $ibbackup_binary; |
924 | + } |
925 | + |
926 | + return $ibbackup_binary; |
927 | } |
928 | |
929 | # Wait until it's safe to backup a slave. Returns immediately if |
930 | # the host isn't a slave. Currently there's only one check: |
931 | # Slave_open_temp_tables has to be zero. Dies on timeout. |
932 | sub wait_for_safe_slave { |
933 | + my $con = shift; |
934 | + |
935 | my @lines; |
936 | # whether host is detected as slave in safe slave backup mode |
937 | my $host_is_slave = 0; |
938 | |
939 | $sql_thread_started = 0; |
940 | + get_mysql_slave_status($con); |
941 | |
942 | - mysql_send 'SHOW SLAVE STATUS\G;'; |
943 | - file_to_array($mysql_stdout, \@lines); |
944 | - foreach my $line ( @lines ) { |
945 | - if ( $line =~ m/Read_Master_Log_Pos/ ) { |
946 | + if (defined($con->{slave_status}->{Read_Master_Log_Pos})) { |
947 | $host_is_slave = 1; |
948 | - } elsif ( $line =~ m/Slave_SQL_Running:.*Yes/ ) { |
949 | + } |
950 | + |
951 | + if ($con->{slave_status}->{Slave_SQL_Running} =~ m/Yes/ ) { |
952 | $sql_thread_started = 1; |
953 | - } |
954 | } |
955 | + |
956 | if ( !$host_is_slave ) { |
957 | print STDERR "$prefix: Not checking slave open temp tables for --safe-slave-backup because host is not a slave\n"; |
958 | return; |
959 | } |
960 | |
961 | if ($sql_thread_started) { |
962 | - mysql_send 'STOP SLAVE SQL_THREAD;'; |
963 | + mysql_query($con, 'STOP SLAVE SQL_THREAD'); |
964 | } |
965 | |
966 | - my $open_temp_tables = get_slave_open_temp_tables(); |
967 | + my $open_temp_tables = get_slave_open_temp_tables($con); |
968 | print STDERR "$prefix: Slave open temp tables: $open_temp_tables\n"; |
969 | |
970 | return if $open_temp_tables == 0; |
971 | @@ -2629,11 +2602,11 @@ |
972 | while ( $n_attempts-- ) { |
973 | print STDERR "$prefix: Starting slave SQL thread, waiting $sleep_time seconds, then checking Slave_open_temp_tables again ($n_attempts attempts remaining)...\n"; |
974 | |
975 | - mysql_send 'START SLAVE SQL_THREAD;'; |
976 | + mysql_query($con, 'START SLAVE SQL_THREAD'); |
977 | sleep $sleep_time; |
978 | - mysql_send 'STOP SLAVE SQL_THREAD;'; |
979 | + mysql_query($con, 'STOP SLAVE SQL_THREAD'); |
980 | |
981 | - $open_temp_tables = get_slave_open_temp_tables(); |
982 | + $open_temp_tables = get_slave_open_temp_tables($con); |
983 | print STDERR "$prefix: Slave open temp tables: $open_temp_tables\n"; |
984 | if ( !$open_temp_tables ) { |
985 | print STDERR "$prefix: Slave is safe to backup\n"; |
986 | @@ -2644,29 +2617,25 @@ |
987 | # Restart the slave if it was running at start |
988 | if ($sql_thread_started) { |
989 | print STDERR "Restarting slave SQL thread.\n"; |
990 | - mysql_send 'START SLAVE SQL_THREAD;'; |
991 | + mysql_query($con, 'START SLAVE SQL_THREAD'); |
992 | } |
993 | |
994 | Die "Slave_open_temp_tables did not become zero after waiting $option_safe_slave_backup_timeout seconds"; |
995 | } |
996 | |
997 | sub get_slave_open_temp_tables { |
998 | - my @lines; |
999 | - mysql_send 'SHOW STATUS LIKE "slave_open_temp_tables"\G;'; |
1000 | - file_to_array($mysql_stdout, \@lines); |
1001 | - my $last_value; |
1002 | - for my $i ( 0..$#lines ) { |
1003 | - $last_value = $i + 1 |
1004 | - if $lines[$i] =~ m/Variable_name: Slave_open_temp_tables/i; |
1005 | - } |
1006 | - Die "SHOW STATUS LIKE 'slave_open_temp_tables' did not return anything" |
1007 | - unless $last_value; |
1008 | - |
1009 | - Die "Failed to get Slave_open_temp_tables from SHOW STATUS" |
1010 | - unless defined $lines[$last_value]; |
1011 | - |
1012 | - my ($n) = $lines[$last_value] =~ m/(\d+)/; |
1013 | - return $n; |
1014 | + my $con = shift; |
1015 | + |
1016 | + get_mysql_status($con); |
1017 | + |
1018 | + if (!defined($con->{status}->{Slave_open_temp_tables})) { |
1019 | + Die "Failed to get Slave_open_temp_tables from SHOW STATUS" |
1020 | + } |
1021 | + if (!defined($con->{status}->{Slave_open_temp_tables}->{Value})) { |
1022 | + Die "SHOW STATUS LIKE 'slave_open_temp_tables' did not return anything" |
1023 | + } |
1024 | + |
1025 | + return $con->{status}->{Slave_open_temp_tables}->{Value}; |
1026 | } |
1027 | |
1028 | =pod |
1029 | |
1030 | === modified file 'test/t/bug729843.sh' |
1031 | --- test/t/bug729843.sh 2012-06-04 18:29:48 +0000 |
1032 | +++ test/t/bug729843.sh 2013-02-05 11:56:22 +0000 |
1033 | @@ -12,9 +12,8 @@ |
1034 | # Don't use run_cmd_* or innobackupex functions here to avoid logging |
1035 | # the full command line (including the password in plaintext) |
1036 | set +e |
1037 | -$IB_BIN $IB_ARGS --password=secret $topdir/backup 2>&1 | tee $logfile |
1038 | +$IB_BIN $IB_ARGS --password=secretpassword $topdir/backup 2>&1 | tee $logfile |
1039 | set -e |
1040 | |
1041 | # Check that the password was not logged in plaintext |
1042 | -run_cmd grep -- "--password=xxxxxxxx" $logfile |
1043 | -run_cmd_expect_failure grep -- "--password=secret" $logfile |
1044 | +run_cmd_expect_failure grep -- "secretpassword" $logfile |
1045 | |
1046 | === modified file 'test/t/bug977101.sh' |
1047 | --- test/t/bug977101.sh 2012-06-08 18:46:19 +0000 |
1048 | +++ test/t/bug977101.sh 2013-02-05 11:56:22 +0000 |
1049 | @@ -17,15 +17,16 @@ |
1050 | |
1051 | # Check that binlog info is correct with --safe-slave-backup |
1052 | innobackupex --no-timestamp --safe-slave-backup $topdir/backup |
1053 | -egrep -q '^mysql-bin.000001[[:space:]]+[0-9]+[[:space:]]+$' \ |
1054 | +run_cmd egrep -q '^mysql-bin.000001[[:space:]]+[0-9]+[[:space:]]+$' \ |
1055 | $topdir/backup/xtrabackup_binlog_info |
1056 | |
1057 | # Check that both binlog info and slave info are correct with |
1058 | # --safe-slave-backup |
1059 | rm -rf $topdir/backup |
1060 | innobackupex --no-timestamp --slave-info --safe-slave-backup $topdir/backup |
1061 | -egrep -q '^mysql-bin.000001[[:space:]]+[0-9]+[[:space:]]+$' \ |
1062 | +run_cmd egrep -q '^mysql-bin.000001[[:space:]]+[0-9]+[[:space:]]+$' \ |
1063 | $topdir/backup/xtrabackup_binlog_info |
1064 | -egrep -q '^CHANGE MASTER TO MASTER_LOG_FILE='\''mysql-bin.000001'\'', MASTER_LOG_POS=[0-9]+$' \ |
1065 | +run_cmd egrep -q \ |
1066 | + '^CHANGE MASTER TO MASTER_LOG_FILE='\''mysql-bin.000001'\'', MASTER_LOG_POS=[0-9]+$' \ |
1067 | $topdir/backup/xtrabackup_slave_info |
1068 |
http:// jenkins. percona. com/view/ XtraBackup/ job/percona- xtrabackup- 2.1-param/ 152/