diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 2bb20ce843c63..85b0bfaca3d06 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -2694,6 +2694,35 @@ static bool innodb_init() /* ================= common ================= */ +/** Read the backup_info file during prepare to know whether +it is working on partial backup target directory */ +static +void xtrabackup_read_backup_info_file(const char *dir, + const char *name) noexcept +{ + char filename[FN_REFLEN]; + snprintf(filename, sizeof(filename), "%s/%s", dir, name); + FILE *fp= fopen(filename, "r"); + char key[8], value; + if (!fp) + { + msg("Error: cannot open %s", filename); + return; + } + + while (!feof(fp)) + { + if (fscanf(fp, "%7s = %c\n", key, &value) == 2) + if (strcmp(key, "partial") == 0) + { + if (value == 'Y') + srv_prepare_partial_backup= true; + break; + } + } + fclose(fp); +} + /*********************************************************************** Read backup meta info. @return TRUE on success, FALSE on failure. */ @@ -6796,6 +6825,7 @@ static bool xtrabackup_prepare_func(char** argv) return(false); } + xtrabackup_read_backup_info_file(xtrabackup_target_dir, MB_INFO); if (!strcmp(metadata_type, "full-backuped")) { if (xtrabackup_incremental) { msg("error: applying incremental backup " diff --git a/mysql-test/suite/mariabackup/partial_backup_prepare.result b/mysql-test/suite/mariabackup/partial_backup_prepare.result new file mode 100644 index 0000000000000..81c8f413e7b20 --- /dev/null +++ b/mysql-test/suite/mariabackup/partial_backup_prepare.result @@ -0,0 +1,15 @@ +CREATE TABLE t1(i INT) ENGINE INNODB; +CREATE TABLE t2(i INT) ENGINE INNODB; +INSERT INTO t1 VALUES(1); +INSERT INTO t2 VALUES(2); +set global innodb_log_checkpoint_now = 1; +INSERT INTO t1 select * from seq_1_to_1024; +INSERT INTO t2 select * from seq_1_to_1024; +# restart +# xtrabackup backup +# xtrabackup prepare +t1.cfg +ALTER TABLE t1 DISCARD TABLESPACE; +ALTER TABLE t1 IMPORT TABLESPACE; +SELECT * FROM t1; +DROP TABLE t1, t2; diff --git a/mysql-test/suite/mariabackup/partial_backup_prepare.test b/mysql-test/suite/mariabackup/partial_backup_prepare.test new file mode 100644 index 0000000000000..0731b9c70108e --- /dev/null +++ b/mysql-test/suite/mariabackup/partial_backup_prepare.test @@ -0,0 +1,37 @@ +--source include/have_innodb.inc +--source include/have_sequence.inc +--source include/have_debug.inc +--source include/not_embedded.inc + +CREATE TABLE t1(i INT) ENGINE INNODB; +CREATE TABLE t2(i INT) ENGINE INNODB; + +INSERT INTO t1 VALUES(1); +INSERT INTO t2 VALUES(2); + +let $targetdir=$MYSQLTEST_VARDIR/tmp/backup; +let $backup_log=$MYSQLTEST_VARDIR/tmp/backup.log; +let $prepare_log=$MYSQLTEST_VARDIR/tmp/prepare.log; +set global innodb_log_checkpoint_now = 1; +INSERT INTO t1 select * from seq_1_to_1024; +INSERT INTO t2 select * from seq_1_to_1024; +--source include/restart_mysqld.inc +echo # xtrabackup backup; +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --dbug=+d,use_old_checkpoint --skip-innodb-log-checkpoint-now --backup "--tables=test.*1" --target-dir=$targetdir --parallel=10 > $backup_log 2>&1; + +echo # xtrabackup prepare; +--disable_result_log +exec $XTRABACKUP --prepare --export --target-dir=$targetdir --dbug=+d,partial_backup_test > $prepare_log 2>&1; + +list_files $targetdir/test *.cfg; + +let $MYSQLD_DATADIR= `select @@datadir`; +ALTER TABLE t1 DISCARD TABLESPACE; +copy_file $targetdir/test/t1.ibd $MYSQLD_DATADIR/test/t1.ibd; +copy_file $targetdir/test/t1.cfg $MYSQLD_DATADIR/test/t1.cfg; +ALTER TABLE t1 IMPORT TABLESPACE; +SELECT * FROM t1; +DROP TABLE t1, t2; +remove_file $backup_log; +remove_file $prepare_log; +rmdir $targetdir; diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index dd48e2ad8214e..508d0de54b0f7 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -329,6 +329,8 @@ extern enum srv_operation_mode srv_operation; /** whether this is the server's first start after mariabackup --prepare */ extern bool srv_start_after_restore; +extern bool srv_prepare_partial_backup; + extern my_bool srv_print_innodb_monitor; extern my_bool srv_print_innodb_lock_monitor; extern ibool srv_print_verbose_log; diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index b34a09b066a8d..51fc026081b54 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -1175,7 +1175,6 @@ static void fil_name_process(const char *name, ulint len, uint32_t space_id, || f.name != fname.name) { reload: fil_space_t* space; - /* Check if the tablespace file exists and contains the space_id. If not, ignore the file after displaying a note. Abort if there are multiple files with the @@ -1232,6 +1231,18 @@ static void fil_name_process(const char *name, ulint len, uint32_t space_id, break; } + /* In case of prepare on partial backup, + InnoDB can't find some tablespace on target + directory. If InnoDB encounters redo log + for the tablespace before FILE_* record then + InnoDB should rename the file name in + recv_spaces from "" to name which encountered + during FILE_* record */ + if (srv_prepare_partial_backup && + strcmp(fname.name.c_str(), "") == 0) { + f.name= fname.name; + } + if (srv_force_recovery || srv_operation == SRV_OPERATION_RESTORE) { /* Without innodb_force_recovery, @@ -1249,6 +1260,17 @@ static void fil_name_process(const char *name, ulint len, uint32_t space_id, int(fname.name.size()), fname.name.data(), space_id); } + + DBUG_EXECUTE_IF("partial_backup_test", + char *exist= + strstr(const_cast(name), + "t2.ibd"); + static uint32_t n_exist= 0; + if (exist && n_exist == 0) + { + n_exist++; + recv_spaces.erase(space_id); + }); break; case FIL_LOAD_DEFER: @@ -1751,13 +1773,26 @@ dberr_t recv_sys_t::find_checkpoint() continue; } + DBUG_EXECUTE_IF("use_old_checkpoint", + if (log_sys.next_checkpoint_lsn > 0) { + if (checkpoint_lsn > log_sys.next_checkpoint_lsn) + goto skip_lsn; + else goto assign_lsn; + } + ); if (checkpoint_lsn >= log_sys.next_checkpoint_lsn) { +#ifndef DBUG_OFF +assign_lsn: +#endif /* !DBUG_OFF */ log_sys.next_checkpoint_lsn= checkpoint_lsn; log_sys.next_checkpoint_no= field == log_t::CHECKPOINT_1; lsn= end_lsn; } } +#ifndef DBUG_OFF +skip_lsn: +#endif /* !DBUG_OFF */ if (!log_sys.next_checkpoint_lsn) goto got_no_checkpoint; if (!memcmp(creator, "Backup ", 7)) diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 43470e586760d..4ff6b57ef149c 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -314,6 +314,9 @@ enum srv_operation_mode srv_operation; /** whether this is the server's first start after mariabackup --prepare */ bool srv_start_after_restore; +/** Whether mariabackup --prepare working on partial backup target */ +bool srv_prepare_partial_backup; + /* Set the following to 0 if you want InnoDB to write messages on stderr on startup/shutdown. Not enabled on the embedded server. */ ibool srv_print_verbose_log;