From 08cb5d848314006111b0c379db6a1fce220579aa Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 31 Mar 2021 14:23:56 +0200 Subject: MDEV-25221 Do not remove source file, if copy_file() fails in mariabackup --move-back Remove an incompletely copied destination file. --- extra/mariabackup/backup_copy.cc | 14 +++++++----- extra/mariabackup/datasink.h | 6 ++++++ extra/mariabackup/ds_archive.cc | 1 + extra/mariabackup/ds_buffer.cc | 1 + extra/mariabackup/ds_compress.cc | 1 + extra/mariabackup/ds_local.cc | 6 ++++++ extra/mariabackup/ds_stdout.cc | 1 + extra/mariabackup/ds_tmpfile.cc | 1 + extra/mariabackup/ds_xbstream.cc | 1 + .../suite/mariabackup/error_during_copyback.result | 9 ++++++++ .../suite/mariabackup/error_during_copyback.test | 25 ++++++++++++++++++++++ 11 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 mysql-test/suite/mariabackup/error_during_copyback.result create mode 100644 mysql-test/suite/mariabackup/error_during_copyback.test diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index d3fa3605c21..5637ec3d4d7 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -1066,6 +1066,7 @@ copy_file(ds_ctxt_t *datasink, ds_file_t *dstfile = NULL; datafile_cur_t cursor; xb_fil_cur_result_t res; + DBUG_ASSERT(datasink->datasink->remove); const char *dst_path = (xtrabackup_copy_back || xtrabackup_move_back)? dst_file_path : trim_dotslash(dst_file_path); @@ -1091,6 +1092,7 @@ copy_file(ds_ctxt_t *datasink, if (ds_write(dstfile, cursor.buf, cursor.buf_read)) { goto error; } + DBUG_EXECUTE_IF("copy_file_error", errno=ENOSPC;goto error;); } if (res == XB_FIL_CUR_ERROR) { @@ -1112,6 +1114,7 @@ copy_file(ds_ctxt_t *datasink, error: datafile_close(&cursor); if (dstfile != NULL) { + datasink->datasink->remove(dstfile->path); ds_close(dstfile); } @@ -1156,17 +1159,18 @@ move_file(ds_ctxt_t *datasink, if (my_rename(src_file_path, dst_file_path_abs, MYF(0)) != 0) { if (my_errno == EXDEV) { - bool ret; - ret = copy_file(datasink, src_file_path, - dst_file_path, thread_n); + /* Fallback to copy/unlink */ + if(!copy_file(datasink, src_file_path, + dst_file_path, thread_n)) + return false; msg(thread_n,"Removing %s", src_file_path); if (unlink(src_file_path) != 0) { my_strerror(errbuf, sizeof(errbuf), errno); - msg("Error: unlink %s failed: %s", + msg("Warning: unlink %s failed: %s", src_file_path, errbuf); } - return(ret); + return true; } my_strerror(errbuf, sizeof(errbuf), my_errno); msg("Can not move file %s to %s: %s", diff --git a/extra/mariabackup/datasink.h b/extra/mariabackup/datasink.h index 201bbfd3267..5c82556b9ba 100644 --- a/extra/mariabackup/datasink.h +++ b/extra/mariabackup/datasink.h @@ -50,9 +50,15 @@ struct datasink_struct { ds_file_t *(*open)(ds_ctxt_t *ctxt, const char *path, MY_STAT *stat); int (*write)(ds_file_t *file, const unsigned char *buf, size_t len); int (*close)(ds_file_t *file); + int (*remove)(const char *path); void (*deinit)(ds_ctxt_t *ctxt); }; + +static inline int dummy_remove(const char *) { + return 0; +} + /* Supported datasink types */ typedef enum { DS_TYPE_STDOUT, diff --git a/extra/mariabackup/ds_archive.cc b/extra/mariabackup/ds_archive.cc index 3826029e120..18f13fbcf3a 100644 --- a/extra/mariabackup/ds_archive.cc +++ b/extra/mariabackup/ds_archive.cc @@ -56,6 +56,7 @@ datasink_t datasink_archive = { &archive_open, &archive_write, &archive_close, + &dummy_remove, &archive_deinit }; diff --git a/extra/mariabackup/ds_buffer.cc b/extra/mariabackup/ds_buffer.cc index e906edc9e84..9dc040d533b 100644 --- a/extra/mariabackup/ds_buffer.cc +++ b/extra/mariabackup/ds_buffer.cc @@ -54,6 +54,7 @@ datasink_t datasink_buffer = { &buffer_open, &buffer_write, &buffer_close, + &dummy_remove, &buffer_deinit }; diff --git a/extra/mariabackup/ds_compress.cc b/extra/mariabackup/ds_compress.cc index fb4f3a75bb6..23de4d85116 100644 --- a/extra/mariabackup/ds_compress.cc +++ b/extra/mariabackup/ds_compress.cc @@ -74,6 +74,7 @@ datasink_t datasink_compress = { &compress_open, &compress_write, &compress_close, + &dummy_remove, &compress_deinit }; diff --git a/extra/mariabackup/ds_local.cc b/extra/mariabackup/ds_local.cc index 0f13ddfe9a9..2f0ad2d8705 100644 --- a/extra/mariabackup/ds_local.cc +++ b/extra/mariabackup/ds_local.cc @@ -44,12 +44,18 @@ static int local_write(ds_file_t *file, const uchar *buf, size_t len); static int local_close(ds_file_t *file); static void local_deinit(ds_ctxt_t *ctxt); +static int local_remove(const char *path) +{ + return unlink(path); +} + extern "C" { datasink_t datasink_local = { &local_init, &local_open, &local_write, &local_close, + &local_remove, &local_deinit }; } diff --git a/extra/mariabackup/ds_stdout.cc b/extra/mariabackup/ds_stdout.cc index 9398482feb9..a4abbe426b6 100644 --- a/extra/mariabackup/ds_stdout.cc +++ b/extra/mariabackup/ds_stdout.cc @@ -39,6 +39,7 @@ datasink_t datasink_stdout = { &stdout_open, &stdout_write, &stdout_close, + &dummy_remove, &stdout_deinit }; diff --git a/extra/mariabackup/ds_tmpfile.cc b/extra/mariabackup/ds_tmpfile.cc index ddb23bf469d..9eadd36bec0 100644 --- a/extra/mariabackup/ds_tmpfile.cc +++ b/extra/mariabackup/ds_tmpfile.cc @@ -50,6 +50,7 @@ datasink_t datasink_tmpfile = { &tmpfile_open, &tmpfile_write, &tmpfile_close, + &dummy_remove, &tmpfile_deinit }; diff --git a/extra/mariabackup/ds_xbstream.cc b/extra/mariabackup/ds_xbstream.cc index 105c89d05f7..3b60456f8ed 100644 --- a/extra/mariabackup/ds_xbstream.cc +++ b/extra/mariabackup/ds_xbstream.cc @@ -50,6 +50,7 @@ datasink_t datasink_xbstream = { &xbstream_open, &xbstream_write, &xbstream_close, + &dummy_remove, &xbstream_deinit }; diff --git a/mysql-test/suite/mariabackup/error_during_copyback.result b/mysql-test/suite/mariabackup/error_during_copyback.result new file mode 100644 index 00000000000..9b12c1135d2 --- /dev/null +++ b/mysql-test/suite/mariabackup/error_during_copyback.result @@ -0,0 +1,9 @@ +CREATE TABLE t(i INT) ENGINE INNODB; +INSERT INTO t VALUES(1); +# xtrabackup backup +# xtrabackup prepare +# restart server +SELECT * FROM t; +i +1 +DROP TABLE t; diff --git a/mysql-test/suite/mariabackup/error_during_copyback.test b/mysql-test/suite/mariabackup/error_during_copyback.test new file mode 100644 index 00000000000..3ec9fbfc3c3 --- /dev/null +++ b/mysql-test/suite/mariabackup/error_during_copyback.test @@ -0,0 +1,25 @@ +--source include/have_debug.inc +CREATE TABLE t(i INT) ENGINE INNODB; +INSERT INTO t VALUES(1); +echo # xtrabackup backup; +let $targetdir=$MYSQLTEST_VARDIR/tmp/backup; +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir; +--enable_result_log +echo # xtrabackup prepare; +--disable_result_log +exec $XTRABACKUP --prepare --target-dir=$targetdir; +let $_datadir= `SELECT @@datadir`; +--source include/shutdown_mysqld.inc +rmdir $_datadir; +error 1; +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --copy-back --datadir=$_datadir --target-dir=$targetdir --dbug=+d,copy_file_error; +list_files $_datadir; +rmdir $_datadir; +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --copy-back --datadir=$_datadir --target-dir=$targetdir; +echo # restart server; +--source include/start_mysqld.inc +SELECT * FROM t; +DROP TABLE t; +rmdir $targetdir; + -- cgit v1.2.1