diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-09-22 14:15:00 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-09-22 14:15:00 +0300 |
commit | 1cb218c37cc3fe01a1ff2fe9b1cbfb591e90d5ce (patch) | |
tree | f5be99c4e6675ac4fd8b4123de07d0058d303b55 /mysql-test/suite | |
parent | 21d19ed45b1b71c2815559a8ad68888a4bfe902f (diff) | |
download | mariadb-git-1cb218c37cc3fe01a1ff2fe9b1cbfb591e90d5ce.tar.gz |
MDEV-26450: Corruption due to innodb_undo_log_truncatebb-10.2-MDEV-26450
At least since commit 055a3334adc004bd3a897990c2f93178e6bb5f90
(MDEV-13564) the undo log truncation in InnoDB did not work correctly.
The main issue is that during the execution of
trx_purge_truncate_history() some pages of the newly truncated
undo tablespace could be discarded.
fsp_try_extend_data_file(): Apply the peculiar rounding of
fil_space_t::size_in_header only to the system tablespace,
whose size can be expressed in megabytes in a configuration parameter.
Other files may freely grow by a number of pages.
fseg_alloc_free_page_low(): Do allow the extension of undo tablespaces,
and mention the file name in the error message.
mtr_t::commit_shrink(): Implement crash-safe shrinking of a tablespace
file. First, durably write the log, then shrink the file, and finally
release the page latches of the rebuilt tablespace. Refactored from
trx_purge_truncate_history().
log_write_and_flush_prepare(), log_write_and_flush(): New functions
to durably write log during mtr_t::commit_shrink().
Diffstat (limited to 'mysql-test/suite')
-rw-r--r-- | mysql-test/suite/innodb/r/undo_truncate.result | 22 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/undo_truncate.test | 64 |
2 files changed, 5 insertions, 81 deletions
diff --git a/mysql-test/suite/innodb/r/undo_truncate.result b/mysql-test/suite/innodb/r/undo_truncate.result index 89171d36d0f..67a587b3c1c 100644 --- a/mysql-test/suite/innodb/r/undo_truncate.result +++ b/mysql-test/suite/innodb/r/undo_truncate.result @@ -10,28 +10,12 @@ SET @trunc_start= WHERE variable_name = 'innodb_undo_truncations'); create table t1(keyc int primary key, c char(100)) engine = innodb; create table t2(keyc int primary key, c char(100)) engine = innodb; -CREATE PROCEDURE populate_t1() -BEGIN -DECLARE i INT DEFAULT 1; -while (i <= 20000) DO -insert into t1 values (i, 'a'); -SET i = i + 1; -END WHILE; -END | -CREATE PROCEDURE populate_t2() -BEGIN -DECLARE i INT DEFAULT 1; -while (i <= 20000) DO -insert into t2 values (i, 'a'); -SET i = i + 1; -END WHILE; -END | connect con1,localhost,root,,; begin; -call populate_t1(); +insert into t1 select seq,'a' from seq_1_to_20000; connect con2,localhost,root,,; begin; -call populate_t2(); +insert into t2 select seq,'a' from seq_1_to_20000; connection con1; update t1 set c = 'mysql'; connection con2; @@ -53,8 +37,6 @@ commit; disconnect con2; connection default; drop table t1, t2; -drop PROCEDURE populate_t1; -drop PROCEDURE populate_t2; InnoDB 0 transactions not purged SET GLOBAL innodb_undo_logs = @save_undo_logs; SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; diff --git a/mysql-test/suite/innodb/t/undo_truncate.test b/mysql-test/suite/innodb/t/undo_truncate.test index 4f350e380ee..9feee84491a 100644 --- a/mysql-test/suite/innodb/t/undo_truncate.test +++ b/mysql-test/suite/innodb/t/undo_truncate.test @@ -5,6 +5,7 @@ # --source include/innodb_page_size.inc --source include/innodb_page_size_small.inc --source include/have_undo_tablespaces.inc +--source include/have_sequence.inc call mtr.add_suppression("InnoDB: The transaction log size is too large"); @@ -27,37 +28,14 @@ WHERE variable_name = 'innodb_undo_truncations'); create table t1(keyc int primary key, c char(100)) engine = innodb; create table t2(keyc int primary key, c char(100)) engine = innodb; # -delimiter |; -CREATE PROCEDURE populate_t1() -BEGIN - DECLARE i INT DEFAULT 1; - while (i <= 20000) DO - insert into t1 values (i, 'a'); - SET i = i + 1; - END WHILE; -END | -delimiter ;| -# -delimiter |; -CREATE PROCEDURE populate_t2() -BEGIN - DECLARE i INT DEFAULT 1; - while (i <= 20000) DO - insert into t2 values (i, 'a'); - SET i = i + 1; - END WHILE; -END | -delimiter ;| -# -# let DATADIR = `select @@datadir`; connect (con1,localhost,root,,); begin; -send call populate_t1(); +send insert into t1 select seq,'a' from seq_1_to_20000; connect (con2,localhost,root,,); begin; -send call populate_t2(); +send insert into t2 select seq,'a' from seq_1_to_20000; connection con1; reap; send update t1 set c = 'mysql'; connection con2; reap; send update t2 set c = 'mysql'; @@ -67,25 +45,12 @@ connection con1; reap; send delete from t1; connection con2; reap; delete from t2; connection con1; reap; -let CHECKFILE = $MYSQL_TMP_DIR/check.txt; -perl; -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1) - = stat("$ENV{DATADIR}/undo001"); -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2) - = stat("$ENV{DATADIR}/undo002"); -open(OUT, ">$ENV{CHECKFILE}") || die; -print OUT "let \$size1='$size1,$size2';\n"; -close(OUT); -EOF - SET GLOBAL innodb_undo_log_truncate = 1; commit; disconnect con1; connection con2; commit; disconnect con2; connection default; drop table t1, t2; -drop PROCEDURE populate_t1; -drop PROCEDURE populate_t2; --source include/wait_all_purged.inc @@ -100,29 +65,6 @@ if (`select @@innodb_page_size IN (4096,8192,16384)`) source include/wait_condition.inc; } ---source $CHECKFILE -perl; -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1) - = stat("$ENV{DATADIR}/undo001"); -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2) - = stat("$ENV{DATADIR}/undo002"); -open(OUT, ">$ENV{CHECKFILE}") || die; -print OUT "let \$size2='$size1,$size2';\n"; -close(OUT); -EOF - ---source $CHECKFILE ---remove_file $CHECKFILE - -if ($size1 == $size2) -{ - # This fails for innodb_page_size=64k, occasionally also for 32k. - if (`select @@innodb_page_size IN (4096,8192,16384)`) - { - echo Truncation did not happen: $size1; - } -} - SET GLOBAL innodb_undo_logs = @save_undo_logs; SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; SET GLOBAL innodb_undo_log_truncate = @save_truncate; |