mariadb/mysql-test/suite/mariabackup/xbstream.test
Thirunarayanan Balathandayuthapani 2d1e019f4f MDEV-36871 mariadb-backup incremental segfault querying mariadb_backup_history
Problem:
=========
(1) Mariabackup tries to read the history data from
mysql.mariadb_backup_history and fails with segfault. Reason is that
mariabackup does force innodb_log_checkpoint_now from commit 652f33e0a44661d6093993d49d3e83d770904413(MDEV-30000).
Mariabackup sends the "innodb_log_checkpoint_now=1" query to server and
reads the result set for the query later in the code because the query
may trigger the page thread to flush the pages. But before reading the
query result for innodb_log_checkpoint_now=1, mariabackup does execute
the select query for the history table (mysql.mariadb_backup_history)
and wrongly reads the query result of innodb_log_checkpoint_now. This leads
to assertion in mariabackup.

(2) The recording of incremental backups has the format as "tar"
when mbstream was used. The xb_stream_fmt_t only had XB_STREAM_FMT_NONE
and XB_STREAM_FMT_XBSTREAM and hence in the mysql.mariadb_backup_history
table the format was recorded as "tar" for the "mbstream" due to the
offset in the xb_stream_name array within mariadb-backup.

(3) Also under Windows the full path of mariabackup was recorded in the the
history.

(4) select_incremental_lsn_from_history(): Name of the backup and UUID
of the history record variable could lead to buffer overflow while
copying the variable value from global variable.

Solution:
=========
(1) Move the reading of history data from mysql.mariadb_backup_history
after reading the result of innodb_log_checkpoint_now=1 query

(2) We've removed the "tar" element from the xb_stream_name. As the
"xbstream" was never used, the format name is changed to mbstream.
As the table needs alteration the "mbstream" appended instead of
the unused xbstream in the table. "tar" is left in the enum as
the previous recordings are still possible.

(3) The Windows path separator is used to store just the executable
name as the tool in the mariadb_backup_history table.

(4) select_incremental_lsn_from_history(): Check and validate
the length of incremental history name and incremental history uuid
before copying into temporary buffer

Thanks to Daniel black for contributing the code for solution (2) and (3)
2025-06-23 10:26:43 +10:00

51 lines
1.7 KiB
Text

--source include/innodb_page_size.inc
CREATE TABLE t(i INT) ENGINE INNODB;
INSERT INTO t VALUES(1);
let $targetdir=$MYSQLTEST_VARDIR/tmp/backup;
let $incr_dir=$MYSQLTEST_VARDIR/tmp/backup_incr;
mkdir $targetdir;
mkdir $incr_dir;
let $streamfile=$MYSQLTEST_VARDIR/tmp/backup.xb;
let $stream_incr_file=$MYSQLTEST_VARDIR/tmp/backup_incr.xb;
echo # xtrabackup full backup to stream;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --parallel=10 --databases-exclude=foobar --history=fullback --stream=xbstream > $streamfile 2>$targetdir/backup_stream.log;
INSERT INTO t VALUES(2), (3), (4);
echo # xtrabackup incremental backup to stream;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --incremental-history-name=fullback --history=incr_1 --stream=xbstream > $stream_incr_file 2>$targetdir/backup_incr.log;
echo # checking recording of history;
--replace_result mariabackup.exe mariabackup
--vertical_results
SELECT tool_name, name, partial, incremental, format, compressed
FROM mysql.mariadb_backup_history
ORDER BY innodb_from_lsn;
--horizontal_results
echo # xbstream extract;
--disable_result_log
exec $XBSTREAM -x -C $targetdir < $streamfile;
echo # xtrabackup prepare;
exec $XTRABACKUP --prepare --target-dir=$targetdir;
echo # xbstream extract for incremental backup;
exec $XBSTREAM -x -C $incr_dir < $stream_incr_file;
echo # xtrabackup incremental prepare;
exec $XTRABACKUP --prepare --target-dir=$targetdir --incremental-dir=$incr_dir;
-- source include/restart_and_restore.inc
--enable_result_log
SELECT * FROM t;
DROP TABLE t;
DROP TABLE mysql.mariadb_backup_history;
rmdir $targetdir;
remove_file $streamfile;
remove_file $stream_incr_file;