mirror of
https://github.com/MariaDB/server.git
synced 2026-04-25 09:45:31 +02:00
MDEV-25221 Do not remove source file, if copy_file() fails in mariabackup --move-back
Remove an incompletely copied destination file.
This commit is contained in:
parent
35ee4aa4e3
commit
08cb5d8483
11 changed files with 61 additions and 5 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ datasink_t datasink_archive = {
|
|||
&archive_open,
|
||||
&archive_write,
|
||||
&archive_close,
|
||||
&dummy_remove,
|
||||
&archive_deinit
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ datasink_t datasink_buffer = {
|
|||
&buffer_open,
|
||||
&buffer_write,
|
||||
&buffer_close,
|
||||
&dummy_remove,
|
||||
&buffer_deinit
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ datasink_t datasink_compress = {
|
|||
&compress_open,
|
||||
&compress_write,
|
||||
&compress_close,
|
||||
&dummy_remove,
|
||||
&compress_deinit
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ datasink_t datasink_stdout = {
|
|||
&stdout_open,
|
||||
&stdout_write,
|
||||
&stdout_close,
|
||||
&dummy_remove,
|
||||
&stdout_deinit
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ datasink_t datasink_tmpfile = {
|
|||
&tmpfile_open,
|
||||
&tmpfile_write,
|
||||
&tmpfile_close,
|
||||
&dummy_remove,
|
||||
&tmpfile_deinit
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ datasink_t datasink_xbstream = {
|
|||
&xbstream_open,
|
||||
&xbstream_write,
|
||||
&xbstream_close,
|
||||
&dummy_remove,
|
||||
&xbstream_deinit
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
25
mysql-test/suite/mariabackup/error_during_copyback.test
Normal file
25
mysql-test/suite/mariabackup/error_during_copyback.test
Normal file
|
|
@ -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;
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue