summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThirunarayanan Balathandayuthapani <thiru@mariadb.com>2019-01-28 14:38:39 +0530
committerMarko Mäkelä <marko.makela@mariadb.com>2019-02-01 09:15:53 +0200
commit7c7161a1bd150e61f530933f096a8035932071af (patch)
tree6da3317045e40f76221c8652ba9053336d3aab6f
parenta2641b26111116adabe1e1c06b768d8c3e06e129 (diff)
downloadmariadb-git-7c7161a1bd150e61f530933f096a8035932071af.tar.gz
MDEV-18194 Incremental prepare tries to access page which is out of tablespace bounds
Problem: ======= Mariabackup incremental prepare creates new tablespace when it encounter new tablespace. It sets the intial size as FIL_IBD_FILE_INITIAL_SIZE (4). But while applying redo log, it tries to access 5th page and then it leads to out of tablespace error. Fix: === While parsing the redo log record, track FSP_SIZE in recv_spaces for the respective space id. Assign the recv_size for the tablespace when it is loaded. Extend the tablespace depends on recv_size while applying the redo log record.
-rw-r--r--mysql-test/suite/mariabackup/incremental_ddl_before_backup.result32
-rw-r--r--mysql-test/suite/mariabackup/incremental_ddl_before_backup.test50
-rw-r--r--storage/innobase/fil/fil0fil.cc2
-rw-r--r--storage/innobase/log/log0recv.cc30
4 files changed, 109 insertions, 5 deletions
diff --git a/mysql-test/suite/mariabackup/incremental_ddl_before_backup.result b/mysql-test/suite/mariabackup/incremental_ddl_before_backup.result
new file mode 100644
index 00000000000..a6273a20ff5
--- /dev/null
+++ b/mysql-test/suite/mariabackup/incremental_ddl_before_backup.result
@@ -0,0 +1,32 @@
+call mtr.add_suppression("InnoDB: New log files created");
+CREATE TABLE t1(i INT) ENGINE INNODB;
+CREATE TABLE t2(i INT PRIMARY KEY) ENGINE INNODB;
+CREATE TABLE t3(i INT) ENGINE INNODB;
+# Create full backup , modify table, then create incremental/differential backup
+create table t4(f1 int not null, f2 int not null)engine=innodb;
+insert into t4 values(1, 2), (2, 2), (3, 3), (5, 5), (6, 6), (4, 4), (9, 9);
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+rename table t4 to t7;
+select count(*) from t7;
+count(*)
+7168
+# XTRABACKUP INCREMENTAL
+# XTRABACKUP PREPARE
+# XTRABACKUP INCREMENTAL PREPARE
+# shutdown server
+# remove datadir
+# xtrabackup move back
+# restart server
+select count(*) from t7;
+count(*)
+7168
+drop table t1, t2, t7, t3;
diff --git a/mysql-test/suite/mariabackup/incremental_ddl_before_backup.test b/mysql-test/suite/mariabackup/incremental_ddl_before_backup.test
new file mode 100644
index 00000000000..2136771b97e
--- /dev/null
+++ b/mysql-test/suite/mariabackup/incremental_ddl_before_backup.test
@@ -0,0 +1,50 @@
+--source include/have_debug.inc
+
+call mtr.add_suppression("InnoDB: New log files created");
+
+let $basedir=$MYSQLTEST_VARDIR/tmp/backup;
+let $incremental_dir=$MYSQLTEST_VARDIR/tmp/backup_inc1;
+
+CREATE TABLE t1(i INT) ENGINE INNODB;
+CREATE TABLE t2(i INT PRIMARY KEY) ENGINE INNODB;
+CREATE TABLE t3(i INT) ENGINE INNODB;
+
+echo # Create full backup , modify table, then create incremental/differential backup;
+--disable_result_log
+exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir;
+--enable_result_log
+
+create table t4(f1 int not null, f2 int not null)engine=innodb;
+insert into t4 values(1, 2), (2, 2), (3, 3), (5, 5), (6, 6), (4, 4), (9, 9);
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+insert into t4 select * from t4;
+rename table t4 to t7;
+select count(*) from t7;
+
+--echo # XTRABACKUP INCREMENTAL
+exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir;
+
+--echo # XTRABACKUP PREPARE
+exec $XTRABACKUP --apply-log-only --prepare --target-dir=$basedir;
+
+--echo # XTRABACKUP INCREMENTAL PREPARE
+exec $XTRABACKUP --prepare --target-dir=$basedir --incremental-dir=$incremental_dir;
+
+let $targetdir=$basedir;
+-- source include/restart_and_restore.inc
+--enable_result_log
+
+select count(*) from t7;
+drop table t1, t2, t7, t3;
+
+# Cleanup
+rmdir $basedir;
+rmdir $incremental_dir;
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 604f43d7639..623aa38be38 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -963,7 +963,7 @@ fil_space_extend_must_retry(
we have set the node->being_extended flag. */
mutex_exit(&fil_system->mutex);
- ut_ad(size > space->size);
+ ut_ad(size >= space->size);
ulint last_page_no = space->size;
const ulint file_start_page_no = last_page_no - node->size;
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index f71067fddf2..bcd6254ebd6 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -152,9 +152,13 @@ struct file_name_t {
/** Status of the tablespace */
fil_status status;
+ /** FSP_SIZE of tablespace */
+ ulint size;
+
/** Constructor */
file_name_t(std::string name_, bool deleted) :
- name(name_), space(NULL), status(deleted ? DELETED: NORMAL) {}
+ name(name_), space(NULL), status(deleted ? DELETED: NORMAL),
+ size(0) {}
};
/** Map of dirty tablespaces during recovery */
@@ -326,6 +330,11 @@ fil_name_process(
ut_ad(space != NULL);
if (f.space == NULL || f.space == space) {
+
+ if (f.size && f.space == NULL) {
+ fil_space_set_recv_size(space->id, f.size);
+ }
+
f.name = fname.name;
f.space = space;
f.status = file_name_t::NORMAL;
@@ -2394,11 +2403,24 @@ recv_parse_log_rec(
}
if (*page_no == 0 && *type == MLOG_4BYTES
+ && apply
&& mach_read_from_2(old_ptr) == FSP_HEADER_OFFSET + FSP_SIZE) {
old_ptr += 2;
- fil_space_set_recv_size(*space,
- mach_parse_compressed(&old_ptr,
- end_ptr));
+
+ ulint size = mach_parse_compressed(&old_ptr, end_ptr);
+
+ recv_spaces_t::iterator it = recv_spaces.find(*space);
+
+ ut_ad(!recv_sys->mlog_checkpoint_lsn
+ || *space == TRX_SYS_SPACE
+ || srv_is_undo_tablespace(*space)
+ || it != recv_spaces.end());
+
+ if (it != recv_spaces.end() && !it->second.space) {
+ it->second.size = size;
+ }
+
+ fil_space_set_recv_size(*space, size);
}
return(new_ptr - ptr);