Commit 7c7161a1 authored by Thirunarayanan Balathandayuthapani's avatar Thirunarayanan Balathandayuthapani Committed by Marko Mäkelä

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.
parent a2641b26
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;
--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;
...@@ -963,7 +963,7 @@ fil_space_extend_must_retry( ...@@ -963,7 +963,7 @@ fil_space_extend_must_retry(
we have set the node->being_extended flag. */ we have set the node->being_extended flag. */
mutex_exit(&fil_system->mutex); mutex_exit(&fil_system->mutex);
ut_ad(size > space->size); ut_ad(size >= space->size);
ulint last_page_no = space->size; ulint last_page_no = space->size;
const ulint file_start_page_no = last_page_no - node->size; const ulint file_start_page_no = last_page_no - node->size;
......
...@@ -152,9 +152,13 @@ struct file_name_t { ...@@ -152,9 +152,13 @@ struct file_name_t {
/** Status of the tablespace */ /** Status of the tablespace */
fil_status status; fil_status status;
/** FSP_SIZE of tablespace */
ulint size;
/** Constructor */ /** Constructor */
file_name_t(std::string name_, bool deleted) : 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 */ /** Map of dirty tablespaces during recovery */
...@@ -326,6 +330,11 @@ fil_name_process( ...@@ -326,6 +330,11 @@ fil_name_process(
ut_ad(space != NULL); ut_ad(space != NULL);
if (f.space == NULL || f.space == space) { 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.name = fname.name;
f.space = space; f.space = space;
f.status = file_name_t::NORMAL; f.status = file_name_t::NORMAL;
...@@ -2394,11 +2403,24 @@ recv_parse_log_rec( ...@@ -2394,11 +2403,24 @@ recv_parse_log_rec(
} }
if (*page_no == 0 && *type == MLOG_4BYTES if (*page_no == 0 && *type == MLOG_4BYTES
&& apply
&& mach_read_from_2(old_ptr) == FSP_HEADER_OFFSET + FSP_SIZE) { && mach_read_from_2(old_ptr) == FSP_HEADER_OFFSET + FSP_SIZE) {
old_ptr += 2; old_ptr += 2;
fil_space_set_recv_size(*space,
mach_parse_compressed(&old_ptr, ulint size = mach_parse_compressed(&old_ptr, end_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); return(new_ptr - ptr);
......
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