summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVlad Lesin <vlad_lesin@mail.ru>2020-08-20 16:49:40 +0300
committerVlad Lesin <vlad_lesin@mail.ru>2020-08-20 16:49:40 +0300
commite322af20513711e57b9e09105a11fc6dd2f7078c (patch)
tree835332151556232ae32db89a67b519958e7c00b1
parent607467bd63db2c6ca64610eb9f4e703711f4dfc6 (diff)
downloadmariadb-git-bb-10.3-10.3.23-MDEV-22929.tar.gz
MDEV-22929 MariaBackup option to report and/or continue when corruption is encounteredbb-10.3-10.3.23-MDEV-22929
Ignore innodb page corruption error and continue backup with error message. DO NOT MERGE IT until the fix is approved by Engineering team.
-rw-r--r--extra/mariabackup/fil_cur.cc9
-rw-r--r--extra/mariabackup/xtrabackup.cc12
-rw-r--r--extra/mariabackup/xtrabackup.h2
-rw-r--r--mysql-test/suite/mariabackup/ignore_page_corruption.result10
-rw-r--r--mysql-test/suite/mariabackup/ignore_page_corruption.test74
5 files changed, 104 insertions, 3 deletions
diff --git a/extra/mariabackup/fil_cur.cc b/extra/mariabackup/fil_cur.cc
index 67d1fb173c0..9a46c17fa2a 100644
--- a/extra/mariabackup/fil_cur.cc
+++ b/extra/mariabackup/fil_cur.cc
@@ -454,12 +454,17 @@ read_retry:
retry_count--;
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,
"Error: failed to read page after "
"10 retries. File %s seems to be "
- "corrupted.", cursor->abs_path);
- ret = XB_FIL_CUR_ERROR;
+ "corrupted.%s", cursor->abs_path, ignore_corruption_warn);
buf_page_print(page, cursor->page_size);
+ if (!opt_ignore_innodb_page_corruption)
+ ret = XB_FIL_CUR_ERROR;
break;
}
msg(cursor->thread_n, "Database page corruption detected at page "
diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc
index 5246ffbda20..41427eb2576 100644
--- a/extra/mariabackup/xtrabackup.cc
+++ b/extra/mariabackup/xtrabackup.cc
@@ -300,6 +300,7 @@ my_bool opt_noversioncheck = FALSE;
my_bool opt_no_backup_locks = FALSE;
my_bool opt_decompress = FALSE;
my_bool opt_remove_original;
+my_bool opt_ignore_innodb_page_corruption;
my_bool opt_lock_ddl_per_table = FALSE;
static my_bool opt_check_privileges;
@@ -833,7 +834,9 @@ enum options_xtrabackup
OPT_LOCK_DDL_PER_TABLE,
OPT_ROCKSDB_DATADIR,
OPT_BACKUP_ROCKSDB,
- OPT_XTRA_CHECK_PRIVILEGES
+ OPT_XTRA_CHECK_PRIVILEGES,
+
+ OPT_XB_IGNORE_INNODB_PAGE_CORRUPTION
};
struct my_option xb_client_options[]= {
@@ -1230,6 +1233,13 @@ struct my_option xb_client_options[]= {
" uses old (pre-4.1.1) protocol.",
&opt_secure_auth, &opt_secure_auth, 0, GET_BOOL, NO_ARG, 1, 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
#include "sslopt-longopts.h"
#undef MYSQL_CLIENT
diff --git a/extra/mariabackup/xtrabackup.h b/extra/mariabackup/xtrabackup.h
index 2dbdd442f95..a87042c10b7 100644
--- a/extra/mariabackup/xtrabackup.h
+++ b/extra/mariabackup/xtrabackup.h
@@ -110,6 +110,8 @@ extern my_bool opt_remove_original;
extern my_bool opt_extended_validation;
extern my_bool opt_encrypted_backup;
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_uuid;
diff --git a/mysql-test/suite/mariabackup/ignore_page_corruption.result b/mysql-test/suite/mariabackup/ignore_page_corruption.result
new file mode 100644
index 00000000000..fd1a43a20e9
--- /dev/null
+++ b/mysql-test/suite/mariabackup/ignore_page_corruption.result
@@ -0,0 +1,10 @@
+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;
diff --git a/mysql-test/suite/mariabackup/ignore_page_corruption.test b/mysql-test/suite/mariabackup/ignore_page_corruption.test
new file mode 100644
index 00000000000..8e067bf15b1
--- /dev/null
+++ b/mysql-test/suite/mariabackup/ignore_page_corruption.test
@@ -0,0 +1,74 @@
+--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;