diff options
author | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2019-01-28 14:38:39 +0530 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-02-01 09:15:53 +0200 |
commit | 7c7161a1bd150e61f530933f096a8035932071af (patch) | |
tree | 6da3317045e40f76221c8652ba9053336d3aab6f | |
parent | a2641b26111116adabe1e1c06b768d8c3e06e129 (diff) | |
download | mariadb-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.result | 32 | ||||
-rw-r--r-- | mysql-test/suite/mariabackup/incremental_ddl_before_backup.test | 50 | ||||
-rw-r--r-- | storage/innobase/fil/fil0fil.cc | 2 | ||||
-rw-r--r-- | storage/innobase/log/log0recv.cc | 30 |
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); |