Commit e322af20 authored by Vlad Lesin's avatar Vlad Lesin

MDEV-22929 MariaBackup option to report and/or continue when corruption is encountered

Ignore innodb page corruption error and continue backup with error
message.

DO NOT MERGE IT until the fix is approved by Engineering team.
parent 607467bd
...@@ -454,12 +454,17 @@ xb_fil_cur_read( ...@@ -454,12 +454,17 @@ xb_fil_cur_read(
retry_count--; retry_count--;
if (retry_count == 0) { if (retry_count == 0) {
const char *ignore_corruption_warn = opt_ignore_innodb_page_corruption ?
" WARNING!!! The corruption is ignored due to"
" ignore-innodb-page-corruption option, the backup can contain"
" corrupted data." : "";
msg(cursor->thread_n, msg(cursor->thread_n,
"Error: failed to read page after " "Error: failed to read page after "
"10 retries. File %s seems to be " "10 retries. File %s seems to be "
"corrupted.", cursor->abs_path); "corrupted.%s", cursor->abs_path, ignore_corruption_warn);
ret = XB_FIL_CUR_ERROR;
buf_page_print(page, cursor->page_size); buf_page_print(page, cursor->page_size);
if (!opt_ignore_innodb_page_corruption)
ret = XB_FIL_CUR_ERROR;
break; break;
} }
msg(cursor->thread_n, "Database page corruption detected at page " msg(cursor->thread_n, "Database page corruption detected at page "
......
...@@ -300,6 +300,7 @@ my_bool opt_noversioncheck = FALSE; ...@@ -300,6 +300,7 @@ my_bool opt_noversioncheck = FALSE;
my_bool opt_no_backup_locks = FALSE; my_bool opt_no_backup_locks = FALSE;
my_bool opt_decompress = FALSE; my_bool opt_decompress = FALSE;
my_bool opt_remove_original; my_bool opt_remove_original;
my_bool opt_ignore_innodb_page_corruption;
my_bool opt_lock_ddl_per_table = FALSE; my_bool opt_lock_ddl_per_table = FALSE;
static my_bool opt_check_privileges; static my_bool opt_check_privileges;
...@@ -833,7 +834,9 @@ enum options_xtrabackup ...@@ -833,7 +834,9 @@ enum options_xtrabackup
OPT_LOCK_DDL_PER_TABLE, OPT_LOCK_DDL_PER_TABLE,
OPT_ROCKSDB_DATADIR, OPT_ROCKSDB_DATADIR,
OPT_BACKUP_ROCKSDB, OPT_BACKUP_ROCKSDB,
OPT_XTRA_CHECK_PRIVILEGES OPT_XTRA_CHECK_PRIVILEGES,
OPT_XB_IGNORE_INNODB_PAGE_CORRUPTION
}; };
struct my_option xb_client_options[]= { struct my_option xb_client_options[]= {
...@@ -1230,6 +1233,13 @@ struct my_option xb_client_options[]= { ...@@ -1230,6 +1233,13 @@ struct my_option xb_client_options[]= {
" uses old (pre-4.1.1) protocol.", " uses old (pre-4.1.1) protocol.",
&opt_secure_auth, &opt_secure_auth, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, &opt_secure_auth, &opt_secure_auth, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
0}, 0},
{"ignore-innodb-page-corruption", OPT_XB_IGNORE_INNODB_PAGE_CORRUPTION,
"Continue backup with error message if innodb page corrupted. "
"This option can cause data incosistency in restored backup.",
&opt_ignore_innodb_page_corruption, &opt_ignore_innodb_page_corruption, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#define MYSQL_CLIENT #define MYSQL_CLIENT
#include "sslopt-longopts.h" #include "sslopt-longopts.h"
#undef MYSQL_CLIENT #undef MYSQL_CLIENT
......
...@@ -110,6 +110,8 @@ extern my_bool opt_remove_original; ...@@ -110,6 +110,8 @@ extern my_bool opt_remove_original;
extern my_bool opt_extended_validation; extern my_bool opt_extended_validation;
extern my_bool opt_encrypted_backup; extern my_bool opt_encrypted_backup;
extern my_bool opt_lock_ddl_per_table; extern my_bool opt_lock_ddl_per_table;
extern my_bool opt_ignore_innodb_page_corruption;
extern char *opt_incremental_history_name; extern char *opt_incremental_history_name;
extern char *opt_incremental_history_uuid; extern char *opt_incremental_history_uuid;
......
call mtr.add_suppression("\\[ERROR\\] InnoDB: The page \\[page id: space=[1-9][0-9]*, page number=3\\] in file '.*test.t1\\.ibd' cannot be decrypted.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: Table `test`\\.`t1` has an unreadable root page");
CREATE TABLE t1(c VARCHAR(128)) ENGINE INNODB;
insert into t1 select repeat('a',100);
# Corrupt the table
# xtrabackup backup must fail due to page corruption
FOUND 1 /Database page corruption detected.*/ in backup.log
# xtrabackup backup must ignore page corruption due to --ignore-innodb-page-corruption option
FOUND 1 /Database page corruption detected.*/ in backup.log
drop table t1;
--source include/innodb_page_size.inc
call mtr.add_suppression("\\[ERROR\\] InnoDB: The page \\[page id: space=[1-9][0-9]*, page number=3\\] in file '.*test.t1\\.ibd' cannot be decrypted.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: Table `test`\\.`t1` has an unreadable root page");
CREATE TABLE t1(c VARCHAR(128)) ENGINE INNODB;
insert into t1 select repeat('a',100);
let MYSQLD_DATADIR=`select @@datadir`;
let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
--source include/shutdown_mysqld.inc
--echo # Corrupt the table
perl;
use strict;
use warnings;
use Fcntl qw(:DEFAULT :seek);
do "$ENV{MTR_SUITE_DIR}/../innodb/include/crc32.pl";
my $page_size = $ENV{INNODB_PAGE_SIZE};
sysopen IBD_FILE, "$ENV{MYSQLD_DATADIR}/test/t1.ibd", O_RDWR
|| die "Cannot open t1.ibd\n";
sysread(IBD_FILE, $_, 38) || die "Cannot read t1.ibd\n";
my $space = unpack("x[34]N", $_);
$space += 10; # generate wrong space id
sysseek(IBD_FILE, $page_size * 3, SEEK_SET) || die "Cannot seek t1.ibd\n";
my $head = pack("Nx[18]", 10); # generate wrong page number
my $body = chr(0) x ($page_size - 38 - 8);
# Calculate innodb_checksum_algorithm=crc32 for the unencrypted page.
# The following bytes are excluded:
# bytes 0..3 (the checksum is stored there)
# bytes 26..37 (encryption key version, post-encryption checksum, tablespace id)
# bytes $page_size-8..$page_size-1 (checksum, LSB of FIL_PAGE_LSN)
my $polynomial = 0x82f63b78; # CRC-32C
my $ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial);
my $page= pack("N",$ck).$head.pack("NNN",1,$ck,$space).$body.pack("Nx[4]",$ck);
die unless syswrite(IBD_FILE, $page, $page_size) == $page_size;
close IBD_FILE;
EOF
--source include/start_mysqld.inc
let $targetdir=$MYSQLTEST_VARDIR/tmp/backup;
let $backuplog=$MYSQLTEST_VARDIR/tmp/backup.log;
--echo # xtrabackup backup must fail due to page corruption
--disable_result_log
--error 1
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir > $backuplog;
--enable_result_log
--let SEARCH_PATTERN=Database page corruption detected.*
--let SEARCH_FILE=$backuplog
--source include/search_pattern_in_file.inc
--rmdir $targetdir
--remove_file $backuplog
--echo # xtrabackup backup must ignore page corruption due to --ignore-innodb-page-corruption option
--disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --ignore-innodb-page-corruption --target-dir=$targetdir > $backuplog;
--enable_result_log
--let SEARCH_PATTERN=Database page corruption detected.*
--let SEARCH_FILE=$backuplog
--source include/search_pattern_in_file.inc
--rmdir $targetdir
--remove_file $backuplog
drop table t1;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment