~percona-core/percona-xtrabackup/2.1

« back to all changes in this revision

Viewing changes to innobackupex

  • Committer: Alexey Kopytov
  • Date: 2013-03-11 07:23:18 UTC
  • mfrom: (486.3.1 2.1)
  • Revision ID: akopytov@gmail.com-20130311072318-2miqd88v72lfmqa5
MergedĀ lp:~akopytov/percona-xtrabackup/use-dbd-mysql-in-innobackupex

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
my @required_perl_version = (5, 0, 5);
40
40
my $required_perl_version_old_style = 5.005;
41
41
 
 
42
# check existence of DBD::mysql module
 
43
eval {
 
44
    require DBD::mysql;
 
45
};
 
46
my $dbd_mysql_installed = $EVAL_ERROR ? 0 : 1;
 
47
 
42
48
# force flush after every write and print
43
49
$| = 1;
44
50
 
53
59
# separately printed when a backup is made
54
60
my $backup_file_print_limit = 9;
55
61
 
56
 
# timeout in seconds for a reply from mysql
57
 
my $mysql_response_timeout = 900;
58
 
 
59
62
# default compression level (this is an argument to ibbackup)
60
63
my $default_compression_level = 1;
61
64
 
121
124
my $option_compact = '';
122
125
my $option_rebuild_indexes = '';
123
126
 
 
127
my %mysql;
 
128
my $option_backup = '';
 
129
 
124
130
# name of the my.cnf configuration file
125
131
#my $config_file = '';
126
132
 
160
166
# prefix for output lines
161
167
my $prefix = "$innobackup_script:";
162
168
 
163
 
# process id of mysql client program (runs as a child process of this script)
164
 
my $mysql_pid = '';
165
 
 
166
169
# mysql server version string
167
170
my $mysql_server_version = '';
168
171
 
169
 
# name of the file where stderr of mysql process is directed
170
 
my $mysql_stderr_fh = File::Temp->new();
171
 
my $mysql_stderr = $mysql_stderr_fh->filename;
172
 
 
173
 
# name of the file where stdout of mysql process is directed
174
 
my $mysql_stdout_fh = File::Temp->new();
175
 
my $mysql_stdout = $mysql_stdout_fh->filename;
176
 
 
177
172
# name of the file where binlog position info is written
178
173
my $binlog_info;
179
174
 
196
191
# a counter for numbering mysql connection checks
197
192
my $hello_id = 0;
198
193
 
199
 
# the request which has been sent to mysqld, but to which
200
 
# mysqld has not yet replied. Empty string denotes that no
201
 
# request has been sent to mysqld or that mysqld has replied
202
 
# to all requests.
203
 
my $current_mysql_request = '';
204
 
 
205
194
# escape sequences for options files
206
195
my %option_value_escapes = ('b' => "\b",
207
196
                            't' => "\t",
255
244
                close XTRABACKUP_BINARY;
256
245
                }
257
246
 
258
 
        else {
 
247
        else {
259
248
                if( $option_ibbackup_binary eq "autodetect" ){
260
249
                        # Try to connect MySQL and get the version
261
 
                        print STDERR "option_ibbackup_binary is autodetect, trying to connect to MySQL\n";
262
 
                        my $options = get_mysql_options();
263
 
                        $mysql_pid = open(*MYSQL_WRITER, "| mysql $options >$mysql_stdout 2>$mysql_stderr ");
264
 
                        print STDERR "Connected to MySQL with pid $mysql_pid\n";
265
 
                        sleep 1;
266
 
                        if ($mysql_pid && $mysql_pid == waitpid($mysql_pid, &WNOHANG)) {
267
 
                                my $reason = `cat $mysql_stderr`;
268
 
                                $mysql_pid = '';
269
 
                                # Failed to connect to MySQL
270
 
                                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";
271
 
                                }
272
 
                        else{
273
 
                                mysql_close();
274
 
                                print STDERR "Connected successfully\n";
275
 
                                $option_ibbackup_binary = set_xtrabackup_version();
276
 
                                }
277
 
                        }
 
250
                        %mysql = mysql_connect(
 
251
                                               abort_on_error => 0,
 
252
                                               keepalives => 0
 
253
                                              );
 
254
                        if ($mysql{dbh}) {
 
255
                            print STDERR "Connected successfully\n";
 
256
                            $option_ibbackup_binary = set_xtrabackup_version();
 
257
                            mysql_close();
 
258
                        } else {
 
259
                            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";
 
260
                        }
278
261
                }
279
 
} elsif ($option_ibbackup_binary eq 'autodetect') {
280
 
    $option_ibbackup_binary = set_xtrabackup_version();
 
262
        }
 
263
} elsif ($option_backup) {
 
264
    # backup
 
265
    %mysql = mysql_connect(abort_on_error => 1, keepalives => 1);
 
266
 
 
267
    if ($option_ibbackup_binary eq 'autodetect') {
 
268
        $option_ibbackup_binary = set_xtrabackup_version();
 
269
    }
281
270
}
282
271
init();
283
272
 
295
284
} else {
296
285
    # make a backup of InnoDB and MyISAM tables, indexes and .frm files.
297
286
    $ibbackup_exit_code = backup();
 
287
 
 
288
    mysql_close(\%mysql);
 
289
 
298
290
    if ($option_stream) {
299
291
      open XTRABACKUP_BINARY, "> $option_tmpdir/$xtrabackup_binary_file"
300
292
        || die "Cannot open file $option_tmpdir/$xtrabackup_binary_file: $!\n";
367
359
#
368
360
sub Die {
369
361
    my $message = shift;
370
 
    my $extra_info = '';
371
362
 
372
363
    # kill all child processes of this process
373
364
    kill_child_processes();
374
365
 
375
 
    if ($current_mysql_request) {
376
 
        $extra_info = " while waiting for reply to MySQL request:" .
377
 
            " '$current_mysql_request'";
378
 
    }
379
 
    die "$prefix Error: $message$extra_info";
 
366
    die "$prefix Error: $message";
380
367
}
381
368
    
382
369
 
388
375
sub backup {
389
376
    my $orig_datadir = get_option(\%config, $option_defaults_group, 'datadir');
390
377
 
391
 
    # check that we can connect to the database. This done by
392
 
    # connecting, issuing a query, and closing the connection.
393
 
    mysql_open();
394
 
    mysql_close();
395
 
 
396
378
    # start ibbackup as a child process
397
379
    start_ibbackup();
398
380
 
399
381
    # wait for ibbackup to suspend itself
400
382
    wait_for_ibbackup_suspend();
401
383
 
402
 
    # connect to database
403
 
    mysql_open();
404
 
 
405
384
    if ($option_safe_slave_backup) {
406
 
      wait_for_safe_slave();
 
385
        wait_for_safe_slave(\%mysql);
407
386
    }
408
387
 
409
388
    # flush tables with read lock
412
391
        backup_files(1);
413
392
 
414
393
        # flush tables with read lock
415
 
        mysql_lockall();
 
394
        mysql_lockall(\%mysql);
416
395
    }
417
396
 
418
397
    if ($option_slave_info) {
419
 
        write_slave_info();
 
398
        write_slave_info(\%mysql);
420
399
    }
421
400
 
422
401
 
428
407
    resume_ibbackup();
429
408
 
430
409
    # release read locks on all tables
431
 
    mysql_unlockall() if !$option_no_lock;
 
410
    mysql_unlockall(\%mysql) if !$option_no_lock;
432
411
 
433
412
    my $ibbackup_exit_code = wait_for_ibbackup_finish();
434
413
 
435
414
    if ( $option_safe_slave_backup && $sql_thread_started) {
436
415
      print STDERR "$prefix: Starting slave SQL thread\n";
437
 
      mysql_send('START SLAVE SQL_THREAD;');
 
416
      mysql_query(\%mysql, 'START SLAVE SQL_THREAD;');
438
417
    }
439
418
 
440
 
    # Close the DB connection
441
 
    mysql_close();
442
 
 
443
419
    # copy ib_lru_dump
444
420
    if (-e "$orig_datadir/ib_lru_dump") {
445
421
        if ($option_stream) {
1085
1061
                  
1086
1062
 
1087
1063
#
1088
 
# get_mysql_options subroutine returns the options to mysql client program
1089
 
# as a string. The options are determined from the options given by the
1090
 
# user to innobackup.
 
1064
# parse_connection_options() subroutine parses connection-related command line
 
1065
# options
1091
1066
#
1092
 
sub get_mysql_options {
1093
 
    my $options = '';
 
1067
sub parse_connection_options {
 
1068
    my $con = shift;
 
1069
 
 
1070
    $con->{dsn} = 'dbi:mysql:';
1094
1071
 
1095
1072
    # this option has to be first
1096
1073
    if ($option_defaults_file) {
1097
 
        $options = "$options --defaults-file='$option_defaults_file'";
 
1074
        $con->{dsn} .= ";mysql_read_default_file=$option_defaults_file";
1098
1075
    }
1099
1076
 
1100
1077
    if ($option_defaults_extra_file) {
1101
 
        $options = $options . " --defaults-extra-file=\"$option_defaults_extra_file\" ";
 
1078
        $con->{dsn} .= ";mysql_read_default_file=$option_defaults_extra_file";
1102
1079
    }
1103
1080
 
 
1081
    $con->{dsn} .= ";mysql_read_default_group=xtrabackup";
 
1082
 
1104
1083
    if ($option_mysql_password) {
1105
 
        $options = "$options --password='$option_mysql_password'";
 
1084
        $con->{dsn_password} = "$option_mysql_password";
1106
1085
    }
1107
1086
    if ($option_mysql_user) {
1108
 
        $options = "$options --user='$option_mysql_user'";
 
1087
        $con->{dsn_user} = "$option_mysql_user";
1109
1088
    }
1110
1089
    if ($option_mysql_host) {
1111
 
        $options = "$options --host='$option_mysql_host'";
 
1090
        $con->{dsn} .= ";host=$option_mysql_host";
1112
1091
    }
1113
1092
    if ($option_mysql_port) {
1114
 
        $options = "$options --port='$option_mysql_port'";
 
1093
        $con->{dsn} .= ";port=$option_mysql_port";
1115
1094
    }
1116
1095
    if ($option_mysql_socket) {
1117
 
        $options = "$options --socket='$option_mysql_socket'";
1118
 
    }
1119
 
    $options = "$options --unbuffered --";
1120
 
    return $options;
1121
 
}
1122
 
 
1123
 
 
1124
 
#
1125
 
# Check that the server is responding to queries
1126
 
#
1127
 
sub mysql_ping {
1128
 
    my $alarm_handler = shift;
1129
 
    my $mysql_pid_copy = $mysql_pid;
1130
 
 
1131
 
    # send a dummy query to mysql child process
1132
 
    $hello_id++;
1133
 
 
1134
 
    my $hello_message = "xtrabackup ping $hello_id";
1135
 
    print MYSQL_WRITER "select '$hello_message';\n" 
1136
 
        or Die "Connection to mysql child process failed: $!";
1137
 
 
1138
 
    # Don't check server's response if running in a signal handler
1139
 
    # because that breaks system() calls
1140
 
    if ($alarm_handler)
1141
 
    {
1142
 
        return 0;
1143
 
    }
1144
 
    # wait for reply
1145
 
    eval {
1146
 
        local $SIG{ALRM} = sub { die "alarm clock restart" };
1147
 
        my $stdout = '';
1148
 
        my $stderr = '';
1149
 
        alarm $mysql_response_timeout;
1150
 
        while (index($stdout, $hello_message) < 0) {
1151
 
            sleep 2;
1152
 
            if ($mysql_pid && $mysql_pid == waitpid($mysql_pid, &WNOHANG)) {
1153
 
                my $reason = `cat $mysql_stderr`;
1154
 
                $mysql_pid = '';
1155
 
                die "mysql child process has died: $reason";
1156
 
            }
1157
 
            $stdout = `cat $mysql_stdout`;
1158
 
            $stderr = `cat $mysql_stderr | grep -v ^Warning`;
1159
 
            if ($stderr) {
1160
 
                # mysql has reported an error, do exit
1161
 
                die "mysql error: $stderr";
1162
 
            }
1163
 
        }
1164
 
        alarm 0;
1165
 
    };
1166
 
    if ($@ =~ /alarm clock restart/) {
1167
 
        Die "Connection to mysql child process (pid=$mysql_pid_copy) timedout."
1168
 
            . " (Time limit of $mysql_response_timeout seconds exceeded."
1169
 
            . " You may adjust time limit by editing the value of parameter"
1170
 
            . " \"\$mysql_response_timeout\" in this script.)";
1171
 
    } elsif ($@) { Die $@; }
1172
 
}
1173
 
 
1174
 
 
1175
 
#
1176
 
# SIGALRM handler which sends a keepalive query to the server
1177
 
#
1178
 
sub catch_sigalrm {
1179
 
  mysql_ping(1);
1180
 
  # Reschedule SIGALRM
1181
 
  alarm $mysql_keep_alive;
1182
 
}
1183
 
 
1184
 
 
1185
 
#
1186
 
# Schedule periodic server pings
 
1096
        $con->{dsn} .= ";mysql_socket=$option_mysql_socket";
 
1097
    }
 
1098
}
 
1099
 
 
1100
#
 
1101
# Start a background process that will send keep-alive queries periodically
 
1102
# using the connection passed as a 'mysql' hash reference
1187
1103
#
1188
1104
sub start_keepalives {
1189
 
  $SIG{ALRM} = \&catch_sigalrm;
1190
 
  alarm $mysql_keep_alive;
 
1105
    my $con = shift;
 
1106
 
 
1107
    if (defined($con->{keep_alive_pid})) {
 
1108
        Die "Keep-alive process has already been started for this connection."
 
1109
    }
 
1110
 
 
1111
    my $keep_alive_pid = fork();
 
1112
 
 
1113
    if ($keep_alive_pid) {
 
1114
        # parent process
 
1115
        $con->{keep_alive_pid} = $keep_alive_pid;
 
1116
 
 
1117
        return;
 
1118
    }
 
1119
 
 
1120
    # child process
 
1121
    $con->{dbh}->{InactiveDestroy} = 1;
 
1122
 
 
1123
    my $rc = 0;
 
1124
    my $hello_id = 0;
 
1125
 
 
1126
    # send dummy queries to connection until interrupted with SIGINT or a
 
1127
    # connection error
 
1128
    while (!$rc) {
 
1129
        sleep $mysql_keep_alive;
 
1130
 
 
1131
        my $hello_message = "xtrabackup ping " . $hello_id++;
 
1132
 
 
1133
        eval {
 
1134
            $con->{dbh}->selectrow_array("select '$hello_message'");
 
1135
        };
 
1136
 
 
1137
        if ($EVAL_ERROR) {
 
1138
            $rc = 255;
 
1139
        }
 
1140
    }
 
1141
 
 
1142
    exit $rc;
1191
1143
}
1192
1144
 
1193
1145
#
1194
 
# Cancel periodic server pings
 
1146
# Stop the background keep-alive process
1195
1147
#
1196
1148
sub stop_keepalives {
1197
 
  alarm 0;
1198
 
  $SIG{ALRM} = "DEFAULT";
1199
 
}
1200
 
 
1201
 
#
1202
 
# mysql_open subroutine starts mysql as a child process with
1203
 
# a pipe connection.
1204
 
#
1205
 
sub mysql_open {
1206
 
    my $options = get_mysql_options();
1207
 
    # run mysql as a child process with a pipe connection
1208
 
    $now = current_time();
1209
 
    (my $prt_options = $options) =~ s/--password=[^ ]+ /--password=xxxxxxxx /g;
1210
 
    print STDERR "$now  $prefix Starting mysql with options: $prt_options\n";
1211
 
    $mysql_pid = open(*MYSQL_WRITER, "| mysql $options >$mysql_stdout 2>$mysql_stderr ") or Die "Failed to spawn mysql child process: $!";
1212
 
    MYSQL_WRITER->autoflush(1);
1213
 
    $now = current_time();
1214
 
    print STDERR "$now  $prefix Connected to database with mysql child process (pid=$mysql_pid)\n";
1215
 
    print MYSQL_WRITER "SET SESSION wait_timeout = 2147000;\n" or die "Connection to mysql child process failed: $!";
1216
 
 
1217
 
    mysql_ping(0);
1218
 
 
1219
 
    start_keepalives();
1220
 
}
1221
 
 
1222
 
 
1223
 
#
1224
 
# mysql_send subroutine send a request string to mysql child process.
1225
 
# This subroutine appends a newline character to the request and checks 
1226
 
# that mysqld receives the query.
 
1149
    my $con = shift;
 
1150
 
 
1151
    if (!defined($con->{keep_alive_pid})) {
 
1152
        Die "Keep-alive process has never been started for this connection."
 
1153
    }
 
1154
 
 
1155
    kill 'INT', $con->{keep_alive_pid};
 
1156
    waitpid($con->{keep_alive_pid}, 0);
 
1157
    my $rc = $? >> 8;
 
1158
 
 
1159
    if ($rc != 0) {
 
1160
        Die "Keep-alive process died with exit code " . $rc;
 
1161
    }
 
1162
    undef $con->{keep_alive_pid};
 
1163
}
 
1164
 
 
1165
#
 
1166
# mysql_connect subroutine connects to MySQL server
 
1167
#
 
1168
sub mysql_connect {
 
1169
    my %con;
 
1170
    my %args = (
 
1171
                  # Defaults
 
1172
                  abort_on_error => 1,
 
1173
                  keepalives => 0,
 
1174
                  @_
 
1175
               );
 
1176
 
 
1177
    $con{abort_on_error} = $args{abort_on_error};
 
1178
    $con{keepalives} = $args{keepalives};
 
1179
 
 
1180
    parse_connection_options(\%con);
 
1181
 
 
1182
    $now = current_time();
 
1183
    print STDERR "$now  $prefix Connecting to MySQL server with DSN '" .
 
1184
        $con{dsn} . "' as '" . $con{dsn_user} . "' (using password: ";
 
1185
    if (defined($con{dsn_password})) {
 
1186
        print STDERR "YES).\n";
 
1187
    } else {
 
1188
        print STDERR "NO).\n";
 
1189
    }
 
1190
 
 
1191
    eval {
 
1192
        $con{dbh}=DBI->connect($con{dsn}, $con{dsn_user},
 
1193
                                 $con{dsn_password}, { RaiseError => 1 });
 
1194
    };
 
1195
 
 
1196
    if ($EVAL_ERROR) {
 
1197
        $con{connect_error}=$EVAL_ERROR;
 
1198
    } else {
 
1199
        $now = current_time();
 
1200
        print STDERR "$now  $prefix Connected to MySQL server\n";
 
1201
    }
 
1202
 
 
1203
    if ($args{abort_on_error}) {
 
1204
        if (!$dbd_mysql_installed) {
 
1205
            die "ERROR: Failed to connect to MySQL server as " .
 
1206
                "DBD::mysql module is not installed";
 
1207
        } else {
 
1208
            if (!$con{dbh}) {
 
1209
                die "ERROR: Failed to connect to MySQL server: " .
 
1210
                    $con{connect_error};
 
1211
            }
 
1212
        }
 
1213
    }
 
1214
 
 
1215
    if ($con{dbh} && $con{keepalives}) {
 
1216
        start_keepalives(\%con);
 
1217
    }
 
1218
 
 
1219
    return %con;
 
1220
}
 
1221
 
 
1222
#
 
1223
# mysql_query subroutine send a query to MySQL server child process.
1227
1224
# Parameters:
1228
 
#    request  request string
1229
 
#
1230
 
sub mysql_send {
1231
 
    my $request = shift;
1232
 
 
1233
 
    stop_keepalives();
1234
 
 
1235
 
    $current_mysql_request = $request;
1236
 
    print MYSQL_WRITER "$request\n";
1237
 
    mysql_ping(0);
1238
 
    $current_mysql_request = '';
1239
 
 
1240
 
    start_keepalives();
1241
 
}
1242
 
    
1243
 
 
1244
 
#
1245
 
# mysql_close subroutine terminates mysql child process gracefully.
 
1225
#    query     query to execute
 
1226
#
 
1227
sub mysql_query {
 
1228
  my ($con, $query) = @_;
 
1229
 
 
1230
  eval {
 
1231
      if ($con->{keepalives}) {
 
1232
          stop_keepalives($con);
 
1233
      }
 
1234
 
 
1235
      if ($query eq 'SHOW VARIABLES') {
 
1236
          $con->{vars} = $con->{dbh}->selectall_hashref('SHOW VARIABLES',
 
1237
                                                        'Variable_name');
 
1238
      } elsif ($query eq 'SHOW STATUS') {
 
1239
          $con->{status} = $con->{dbh}->selectall_hashref('SHOW STATUS',
 
1240
                                                        'Variable_name');
 
1241
      } elsif ($query eq 'SHOW MASTER STATUS') {
 
1242
          $con->{master_status} =
 
1243
              $con->{dbh}->selectrow_hashref("SHOW MASTER STATUS");
 
1244
      } elsif ($query eq 'SHOW SLAVE STATUS') {
 
1245
          $con->{slave_status} =
 
1246
              $con->{dbh}->selectrow_hashref("SHOW SLAVE STATUS");
 
1247
      } else {
 
1248
          $con->{dbh}->do($query);
 
1249
      }
 
1250
 
 
1251
      if ($con->{keepalives}) {
 
1252
          start_keepalives($con);
 
1253
      }
 
1254
  };
 
1255
  if ($EVAL_ERROR) {
 
1256
      Die "\nError executing '$query': $EVAL_ERROR\n";
 
1257
  }
 
1258
}
 
1259
 
 
1260
 
 
1261
sub get_mysql_vars {
 
1262
  mysql_query($_[0], 'SHOW VARIABLES')
 
1263
}
 
1264
 
 
1265
sub get_mysql_status {
 
1266
  mysql_query($_[0], 'SHOW STATUS');
 
1267
}
 
1268
 
 
1269
sub get_mysql_master_status {
 
1270
  mysql_query($_[0], "SHOW MASTER STATUS");
 
1271
}
 
1272
 
 
1273
sub get_mysql_slave_status {
 
1274
  mysql_query($_[0], "SHOW SLAVE STATUS");
 
1275
}
 
1276
 
 
1277
#
 
1278
# mysql_close subroutine closes connection to MySQL server gracefully.
1246
1279
1247
1280
sub mysql_close {
1248
 
    stop_keepalives();
1249
 
 
1250
 
    print MYSQL_WRITER "quit\n";
 
1281
    my $con = shift;
 
1282
 
 
1283
    if ($con->{keepalives}) {
 
1284
        stop_keepalives($con);
 
1285
    };
 
1286
 
 
1287
    $con->{dbh}->disconnect();
 
1288
 
1251
1289
    $now = current_time();
1252
1290
    print STDERR "$now  $prefix Connection to database server closed\n";
1253
 
    $mysql_pid = '';
1254
1291
}
1255
1292
 
1256
 
 
1257
1293
#
1258
1294
# write_binlog_info subroutine retrieves MySQL binlog position and
1259
1295
# saves it in a file. It also prints it to stdout.
1260
1296
#
1261
1297
sub write_binlog_info {
1262
 
    my @lines;
1263
 
    my $position = '';
1264
 
    my $filename = '';
 
1298
    my $con = shift;
1265
1299
 
1266
1300
    # get binlog position
1267
 
    mysql_send 'SHOW MASTER STATUS\G';
 
1301
    get_mysql_master_status($con);
1268
1302
 
1269
1303
    # get the name of the last binlog file and position in it
1270
1304
    # from the SHOW MASTER STATUS output
1271
 
    file_to_array($mysql_stdout, \@lines);
1272
 
    foreach (@lines) {
1273
 
        $filename = $1 if /^\s+File:\s(\S+)\s*$/;
1274
 
        $position = $1 if /^\s+Position:\s(\d+)\s*$/;
1275
 
    }
 
1305
    my $filename = $con->{master_status}->{File};
 
1306
    my $position = $con->{master_status}->{Position};
1276
1307
 
1277
1308
    # write binlog info file
1278
1309
    open(FILE, ">$binlog_info") || Die "Failed to open file '$binlog_info': $!";
1293
1324
# saves it in a file. It also prints it to stdout.
1294
1325
#
1295
1326
sub write_galera_info {
 
1327
    my $con = shift;
1296
1328
    my @lines;
1297
1329
    my @info_lines = ();
1298
1330
    my $position = '';
1299
1331
    my $filename = '';
1300
1332
 
1301
1333
    # get binlog position
1302
 
    mysql_send "SHOW STATUS LIKE 'wsrep_local_state_uuid';";
1303
 
    mysql_send "SHOW STATUS LIKE 'wsrep_last_committed';";
1304
 
 
1305
 
    # get "show master status" output lines (2) from mysql output
1306
 
    file_to_array($mysql_stdout, \@lines);
 
1334
    get_mysql_status($con);
1307
1335
 
1308
1336
    open(FILE, ">$galera_info") || 
1309
1337
         Die "Failed to open file '$galera_info': $!";
1310
1338
 
1311
 
    foreach my $line (@lines) {
1312
 
        if ($line =~ m/wsrep_local_state_uuid/) {
1313
 
            $line =~ s/wsrep_local_state_uuid\s*//g;
1314
 
            print FILE  "$line:";
1315
 
        }
1316
 
    }
1317
 
 
1318
 
    foreach my $line (@lines) {
1319
 
        if ($line =~ m/wsrep_last_committed/) {
1320
 
            $line =~ s/wsrep_last_committed\s*//g;
1321
 
            print FILE  "$line\n";
1322
 
        }
1323
 
    }
 
1339
    print FILE $con->{status}->{wsrep_local_state_uuid}->{Value};
 
1340
    print FILE $con->{status}->{wsrep_last_committed}->{Value};
1324
1341
 
1325
1342
    close(FILE);
1326
1343
 
1339
1356
# also saves it in $msql_slave_position variable.
1340
1357
#
1341
1358
sub write_slave_info {
 
1359
    my $con = shift;
 
1360
 
1342
1361
    my @lines;
1343
1362
    my @info_lines;
1344
1363
    my $position = '';
1345
1364
    my $filename = '';
1346
1365
    my $master= '';
1347
 
        
1348
 
    # get slave status. Use single quotes here, otherwise
1349
 
    # \G is evaluated as a control character.
1350
 
    mysql_send 'SHOW SLAVE STATUS\G';
 
1366
 
 
1367
    # get slave status
 
1368
    get_mysql_slave_status($con);
1351
1369
 
1352
1370
    # get output of the "show slave status" command from mysql output
1353
1371
    # and extract binlog position of the master server
1354
 
    file_to_array($mysql_stdout, \@lines);
1355
 
    for (@lines) {
1356
 
        $master = $1 if /Master_Host:\s*(\S*)\s*$/;
1357
 
        $filename = $1 if /Master_Log_File:\s*(\S*)\s*$/;
1358
 
        $position = $1 if /Master_Log_Pos:\s*(\S*)\s*$/;
 
1372
    $master = $con->{slave_status}->{Master_Host};
 
1373
    $filename = $con->{slave_status}->{Relay_Master_Log_File};
 
1374
    $position = $con->{slave_status}->{Exec_Master_Log_Pos};
 
1375
 
 
1376
    if (!defined($master) || !defined($filename) || !defined($position)) {
 
1377
        Die "Failed to get master binlog coordinates from SHOW SLAVE STATUS";
1359
1378
    }
1360
1379
 
1361
1380
    # print slave status to a file
1377
1396
# mysql_lockall subroutine puts a read lock on all tables in all databases.
1378
1397
1379
1398
sub mysql_lockall {
 
1399
    my $con = shift;
 
1400
 
1380
1401
    $now = current_time();
1381
1402
    print STDERR "$now  $prefix Starting to lock all tables...\n";
1382
1403
 
1383
 
    mysql_send "USE mysql;";
1384
 
#    mysql_send "DROP TABLE IF EXISTS ibbackup_binlog_marker;";
1385
 
#    if (compare_versions($mysql_server_version, '4.1.0') == -1) {
1386
 
#        # MySQL server version is 4.0 or older, ENGINE keyword not supported
1387
 
#        mysql_send "CREATE TABLE ibbackup_binlog_marker(a INT) TYPE=INNODB;";
1388
 
#    } else {
1389
 
#        # MySQL server version is 4.1 or newer, use ENGINE keyword
1390
 
#        mysql_send "CREATE TABLE ibbackup_binlog_marker(a INT) ENGINE=INNODB;";
1391
 
#    }
1392
 
    mysql_send "SET AUTOCOMMIT=0;";
1393
 
#    mysql_send "INSERT INTO ibbackup_binlog_marker VALUES (1);";
1394
1404
    if (compare_versions($mysql_server_version, '4.0.22') == 0
1395
1405
        || compare_versions($mysql_server_version, '4.1.7') == 0) {
1396
1406
        # MySQL server version is 4.0.22 or 4.1.7
1397
 
        mysql_send "COMMIT;";
1398
 
        mysql_send "FLUSH TABLES WITH READ LOCK;";
 
1407
        mysql_query($con, "COMMIT");
 
1408
        mysql_query($con, "FLUSH TABLES WITH READ LOCK");
1399
1409
    } else {
1400
1410
        # MySQL server version is other than 4.0.22 or 4.1.7
1401
 
        mysql_send "FLUSH TABLES WITH READ LOCK;";
1402
 
        mysql_send "COMMIT;";
 
1411
        mysql_query($con, "FLUSH TABLES WITH READ LOCK");
 
1412
        mysql_query($con, "COMMIT");
1403
1413
    }
1404
 
    write_binlog_info;
 
1414
    write_binlog_info($con);
1405
1415
    write_galera_info if $option_galera_info;
1406
1416
        
1407
1417
    $now = current_time();
1414
1424
# databases.
1415
1425
1416
1426
sub mysql_unlockall {
1417
 
    mysql_send "UNLOCK TABLES;";
1418
 
#    mysql_send "DROP TABLE IF EXISTS ibbackup_binlog_marker;";
 
1427
    my $con = shift;
 
1428
 
 
1429
    mysql_query ($con, "UNLOCK TABLES");
1419
1430
 
1420
1431
    $now = current_time();
1421
1432
    print STDERR "$now  $prefix All tables unlocked\n";
1422
1433
}
1423
1434
 
1424
 
 
1425
 
#
1426
 
# catch_sigpipe subroutine is a signal handler for SIGPIPE.
1427
 
#
1428
 
sub catch_sigpipe {
1429
 
    my $rcode;
1430
 
 
1431
 
    if ($mysql_pid && (-1 == ($rcode = waitpid($mysql_pid, &WNOHANG))
1432
 
                       || $rcode == $mysql_pid)) {
1433
 
        my $reason = `cat $mysql_stderr`;
1434
 
        print STDERR "Pipe to mysql child process broken: $reason at";
1435
 
        system("date +'%H:%M:%S'");
1436
 
        exit(1);
1437
 
    } else {
1438
 
        Die "Broken pipe";
1439
 
    }
1440
 
}
1441
 
 
1442
 
 
1443
1435
#
1444
1436
# kill_child_processes subroutine kills all child processes of this process.
1445
1437
#
1448
1440
        kill($kill_signal, $ibbackup_pid);
1449
1441
        $ibbackup_pid = '';
1450
1442
    }
1451
 
    
1452
 
    if ($mysql_pid) {
1453
 
        kill($kill_signal, $mysql_pid);
1454
 
        $mysql_pid = '';
1455
 
    }
1456
1443
}
1457
1444
 
1458
1445
 
1581
1568
    print STDERR "           At the end of a successful $run run $innobackup_script\n";
1582
1569
    print STDERR "           prints \"completed OK!\".\n\n";
1583
1570
 
1584
 
    # check that MySQL client program and InnoDB Hot Backup program
1585
 
    # are runnable via shell
1586
1571
    if (!$option_copy_back && !$option_move_back) {
1587
1572
        # we are making a backup or applying log to backup
1588
1573
        if (!$option_apply_log) {
1589
1574
            # we are making a backup, we need mysql server
1590
 
            my $output = '';
1591
 
            my @lines = ();
1592
 
 
1593
 
            # check that we have mysql client program
1594
 
            require_external('mysql', '--version', 'Ver ([^,]+)', 
1595
 
                             \$mysql_version);
1596
 
            
1597
 
            # get mysql server version
1598
 
            my $options = get_mysql_options();
1599
 
            @lines = split('\n', 
1600
 
                           `mysql $options -e "select \@\@version"`);
1601
 
            $mysql_server_version = $lines[1];
 
1575
            get_mysql_vars(\%mysql);
 
1576
            $mysql_server_version = $mysql{vars}->{version}->{Value};
1602
1577
            print STDERR "$prefix Using mysql server version $mysql_server_version\n";
1603
1578
        }
1604
1579
        #require_external($option_ibbackup_binary, '--license', 
1615
1590
                . " v2.0 in order to use --include option.\n";
1616
1591
        }
1617
1592
    }
1618
 
    
1619
 
    # set signal handlers
1620
 
    $SIG{PIPE} = \&catch_sigpipe;
1621
1593
 
1622
1594
    # read MySQL options file
1623
1595
    #read_config_file($config_file, \%config);
1838
1810
        exit(1);
1839
1811
    }
1840
1812
 
1841
 
    # get options file name
1842
 
    #$config_file = $ARGV[0];
1843
 
 
1844
1813
    if (!$option_apply_log && !$option_copy_back && !$option_move_back) {
1845
1814
        # we are making a backup, get backup root directory
 
1815
        $option_backup = "1";
1846
1816
        $backup_root = $ARGV[0];
1847
1817
        if ($option_incremental && !$option_incremental_lsn) {
1848
1818
            my @dirs = `ls -1 -t $backup_root`;
2541
2511
}
2542
2512
 
2543
2513
sub set_xtrabackup_version {
2544
 
# Based on MySQL version choose correct binary
2545
 
#  MySQL 5.1.* with InnoDB plugin - xtrabackup
2546
 
#  MariaDB 5.1.* - xtrabackup
2547
 
#  MariaDB 5.2.* - xtrabackup
2548
 
#  MariaDB 5.3.* - xtrabackup
2549
 
#  Percona Server 5.0 - xtrabackup_51
2550
 
#  Percona Server 5.1 - xtrabackup
2551
 
#  Percona Server 5.5 - xtrabackup_55
2552
 
#  MySQL 5.5.* - xtrabackup_55
2553
 
#  MariaDB 5.5.* - xtrabackup_55
2554
 
 
2555
 
my @lines;
2556
 
my $var_version = '';
2557
 
my $var_innodb_version = '';
2558
 
my $ibbackup_binary;
2559
 
mysql_open();
2560
 
mysql_send "SHOW VARIABLES LIKE 'version'\\G";
2561
 
file_to_array($mysql_stdout, \@lines);
2562
 
for (@lines) {
2563
 
        $var_version = $1 if /Value:\s+(\S+)/;
2564
 
        }
2565
 
mysql_send "SHOW VARIABLES LIKE 'innodb_version'\\G";
2566
 
file_to_array($mysql_stdout, \@lines);
2567
 
for (@lines) {
2568
 
        $var_innodb_version = $1 if /Value:\s+(\S+)/;
2569
 
        }
2570
 
if($var_version =~ m/5\.0\.\d/){
 
2514
    # Based on MySQL version choose correct binary
 
2515
    #  MySQL 5.1.* with InnoDB plugin - xtrabackup
 
2516
    #  MariaDB 5.1.* - xtrabackup
 
2517
    #  MariaDB 5.2.* - xtrabackup
 
2518
    #  MariaDB 5.3.* - xtrabackup
 
2519
    #  Percona Server 5.0 - xtrabackup_51
 
2520
    #  Percona Server 5.1 - xtrabackup
 
2521
    #  Percona Server 5.5 - xtrabackup_55
 
2522
    #  MySQL 5.5.* - xtrabackup_55
 
2523
    #  MariaDB 5.5.* - xtrabackup_55
 
2524
 
 
2525
    my $var_version = '';
 
2526
    my $var_innodb_version = '';
 
2527
    my $ibbackup_binary;
 
2528
 
 
2529
    get_mysql_vars(\%mysql);
 
2530
 
 
2531
    $var_version = $mysql{vars}->{version}->{Value};
 
2532
    $var_innodb_version = $mysql{vars}->{innodb_version}->{Value};
 
2533
 
 
2534
 
 
2535
    if($var_version =~ m/5\.0\.\d/) {
2571
2536
        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.";
2572
 
}
2573
 
if($var_version =~ m/5\.1\.\d/ and $var_innodb_version =~ m/.*/){
 
2537
    }
 
2538
 
 
2539
    if($var_version =~ m/5\.1\.\d/ && $var_innodb_version =~ m/.*/) {
2574
2540
        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.";
2575
 
}
2576
 
if($var_version =~ m/5\.1\.\d/ and $var_innodb_version =~ m/1\.0\.\d+$/){
2577
 
        $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup');
2578
 
}
2579
 
if($var_version =~ m/5\.1\.\d/ and $var_innodb_version =~ m/1\.0\.\d+-(rel)?\d/){
2580
 
        $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup');
2581
 
}
2582
 
if($var_version =~ m/5\.2\.\d/){
2583
 
    $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup');
2584
 
}
2585
 
if($var_version =~ m/5\.3\.\d/){
2586
 
    $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup');
2587
 
}
2588
 
if($var_version =~ m/5\.5\.\d/){
 
2541
    }
 
2542
 
 
2543
    if($var_version =~ m/5\.1\.\d/ && $var_innodb_version =~ m/1\.0\.\d+$/) {
 
2544
        $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup');
 
2545
    }
 
2546
 
 
2547
    if($var_version =~ m/5\.1\.\d/ && $var_innodb_version =~ m/1\.0\.\d+-(rel)?\d/){
 
2548
        $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup');
 
2549
    }
 
2550
 
 
2551
    if($var_version =~ m/5\.2\.\d/){
 
2552
        $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup');
 
2553
    }
 
2554
 
 
2555
    if($var_version =~ m/5\.3\.\d/){
 
2556
        $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup');
 
2557
    }
 
2558
 
 
2559
    if($var_version =~ m/5\.5\.\d/){
2589
2560
        $ibbackup_binary = ($win eq 1 ? 'xtrabackup.exe' : 'xtrabackup_55');
2590
 
}
2591
 
mysql_close();
2592
 
return $ibbackup_binary;
 
2561
    }
 
2562
 
 
2563
    return $ibbackup_binary;
2593
2564
}
2594
2565
 
2595
2566
# Wait until it's safe to backup a slave.  Returns immediately if
2596
2567
# the host isn't a slave.  Currently there's only one check:
2597
2568
# Slave_open_temp_tables has to be zero.  Dies on timeout.
2598
2569
sub wait_for_safe_slave {
 
2570
   my $con = shift;
 
2571
 
2599
2572
   my @lines;
2600
2573
   # whether host is detected as slave in safe slave backup mode
2601
2574
   my $host_is_slave = 0;
2602
2575
 
2603
2576
   $sql_thread_started = 0;
 
2577
   get_mysql_slave_status($con);
2604
2578
 
2605
 
   mysql_send 'SHOW SLAVE STATUS\G;';
2606
 
   file_to_array($mysql_stdout, \@lines);
2607
 
   foreach my $line ( @lines ) {
2608
 
      if ( $line =~ m/Read_Master_Log_Pos/ ) {
 
2579
   if (defined($con->{slave_status}->{Read_Master_Log_Pos})) {
2609
2580
         $host_is_slave = 1;
2610
 
     } elsif ( $line =~ m/Slave_SQL_Running:.*Yes/ ) {
 
2581
   }
 
2582
 
 
2583
   if ($con->{slave_status}->{Slave_SQL_Running} =~ m/Yes/ ) {
2611
2584
         $sql_thread_started = 1;
2612
 
     }
2613
2585
   }
 
2586
 
2614
2587
   if ( !$host_is_slave ) {
2615
2588
      print STDERR "$prefix: Not checking slave open temp tables for --safe-slave-backup because host is not a slave\n";
2616
2589
      return;
2617
2590
   }
2618
2591
 
2619
2592
   if ($sql_thread_started) {
2620
 
       mysql_send 'STOP SLAVE SQL_THREAD;';
 
2593
       mysql_query($con, 'STOP SLAVE SQL_THREAD');
2621
2594
   }
2622
2595
 
2623
 
   my $open_temp_tables = get_slave_open_temp_tables();
 
2596
   my $open_temp_tables = get_slave_open_temp_tables($con);
2624
2597
   print STDERR "$prefix: Slave open temp tables: $open_temp_tables\n";
2625
2598
 
2626
2599
   return if $open_temp_tables == 0;
2630
2603
   while ( $n_attempts-- ) {
2631
2604
      print STDERR "$prefix: Starting slave SQL thread, waiting $sleep_time seconds, then checking Slave_open_temp_tables again ($n_attempts attempts remaining)...\n";
2632
2605
      
2633
 
      mysql_send 'START SLAVE SQL_THREAD;';
 
2606
      mysql_query($con, 'START SLAVE SQL_THREAD');
2634
2607
      sleep $sleep_time;
2635
 
      mysql_send 'STOP SLAVE SQL_THREAD;';
 
2608
      mysql_query($con, 'STOP SLAVE SQL_THREAD');
2636
2609
 
2637
 
      $open_temp_tables = get_slave_open_temp_tables();
 
2610
      $open_temp_tables = get_slave_open_temp_tables($con);
2638
2611
      print STDERR "$prefix: Slave open temp tables: $open_temp_tables\n";
2639
2612
      if ( !$open_temp_tables ) {
2640
2613
         print STDERR "$prefix: Slave is safe to backup\n";
2645
2618
   # Restart the slave if it was running at start
2646
2619
   if ($sql_thread_started) {
2647
2620
       print STDERR "Restarting slave SQL thread.\n";
2648
 
       mysql_send 'START SLAVE SQL_THREAD;';
 
2621
       mysql_query($con, 'START SLAVE SQL_THREAD');
2649
2622
   }
2650
2623
 
2651
2624
   Die "Slave_open_temp_tables did not become zero after waiting $option_safe_slave_backup_timeout seconds";
2652
2625
}
2653
2626
 
2654
2627
sub get_slave_open_temp_tables {
2655
 
   my @lines;
2656
 
   mysql_send 'SHOW STATUS LIKE "slave_open_temp_tables"\G;';
2657
 
   file_to_array($mysql_stdout, \@lines);
2658
 
   my $last_value;
2659
 
   for my $i ( 0..$#lines ) {
2660
 
      $last_value = $i + 1
2661
 
         if $lines[$i] =~ m/Variable_name: Slave_open_temp_tables/i;
2662
 
   }
2663
 
   Die "SHOW STATUS LIKE 'slave_open_temp_tables' did not return anything"
2664
 
      unless $last_value;
2665
 
 
2666
 
   Die "Failed to get Slave_open_temp_tables from SHOW STATUS"
2667
 
      unless defined $lines[$last_value];
2668
 
 
2669
 
   my ($n) = $lines[$last_value] =~ m/(\d+)/;
2670
 
   return $n;
 
2628
    my $con = shift;
 
2629
 
 
2630
    get_mysql_status($con);
 
2631
 
 
2632
    if (!defined($con->{status}->{Slave_open_temp_tables})) {
 
2633
        Die "Failed to get Slave_open_temp_tables from SHOW STATUS"
 
2634
    }
 
2635
    if (!defined($con->{status}->{Slave_open_temp_tables}->{Value})) {
 
2636
        Die "SHOW STATUS LIKE 'slave_open_temp_tables' did not return anything"
 
2637
    }
 
2638
 
 
2639
   return $con->{status}->{Slave_open_temp_tables}->{Value};
2671
2640
}
2672
2641
 
2673
2642
=pod