mirror of
https://github.com/MariaDB/server.git
synced 2025-01-30 18:41:56 +01:00
504202bd7f
The function fsp_header_get_space_id() returns ulint instead of uint32_t, only to be able to complain that the two adjacent tablespace ID fields in the page differ. Remove the function, and merge the check to the callers. Also, make some more use of aligned_malloc().
462 lines
14 KiB
Text
462 lines
14 KiB
Text
--echo #
|
|
--echo # Bug #17335427 INNODB CAN NOT USE THE DOUBLEWRITE BUFFER PROPERLY
|
|
--echo # Bug #18144349 INNODB CANNOT USE THE DOUBLEWRITE BUFFER FOR THE FIRST
|
|
--echo # PAGE OF SYSTEM TABLESPACE
|
|
--echo #
|
|
|
|
--source include/innodb_page_size.inc
|
|
--source include/have_debug.inc
|
|
--source include/not_embedded.inc
|
|
# This test is slow on buildbot.
|
|
--source include/big_test.inc
|
|
|
|
# Slow shutdown and restart to make sure ibuf merge is finished
|
|
SET GLOBAL innodb_fast_shutdown = 0;
|
|
--disable_query_log
|
|
call mtr.add_suppression("InnoDB: Data file .* uses page size .* but the innodb_page_size start-up parameter is");
|
|
call mtr.add_suppression("InnoDB: adjusting FSP_SPACE_FLAGS");
|
|
call mtr.add_suppression("InnoDB: New log files created");
|
|
call mtr.add_suppression("InnoDB: Cannot create doublewrite buffer: the first file in innodb_data_file_path must be at least (3|6|12)M\\.");
|
|
call mtr.add_suppression("InnoDB: Database creation was aborted");
|
|
call mtr.add_suppression("Plugin 'InnoDB' (init function returned error|registration as a STORAGE ENGINE failed)");
|
|
call mtr.add_suppression("InnoDB: A bad Space ID was found in datafile");
|
|
call mtr.add_suppression("InnoDB: Checksum mismatch in datafile: ");
|
|
call mtr.add_suppression("InnoDB: Inconsistent tablespace ID in .*t1\\.ibd");
|
|
--enable_query_log
|
|
--source include/restart_mysqld.inc
|
|
|
|
let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
|
|
let MYSQLD_DATADIR=`select @@datadir`;
|
|
let ALGO=`select @@innodb_checksum_algorithm`;
|
|
let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err;
|
|
|
|
show variables like 'innodb_doublewrite';
|
|
show variables like 'innodb_fil_make_page_dirty_debug';
|
|
show variables like 'innodb_saved_page_number_debug';
|
|
|
|
create table t1 (f1 int primary key, f2 blob) engine=innodb;
|
|
|
|
start transaction;
|
|
insert into t1 values(1, repeat('#',12));
|
|
insert into t1 values(2, repeat('+',12));
|
|
insert into t1 values(3, repeat('/',12));
|
|
insert into t1 values(4, repeat('-',12));
|
|
insert into t1 values(5, repeat('.',12));
|
|
commit work;
|
|
|
|
--echo # ---------------------------------------------------------------
|
|
--echo # Test Begin: Test if recovery works if first page of user
|
|
--echo # tablespace is full of zeroes.
|
|
|
|
select space from information_schema.innodb_sys_tables
|
|
where name = 'test/t1' into @space_id;
|
|
|
|
--echo # Ensure that dirty pages of table t1 is flushed.
|
|
flush tables t1 for export;
|
|
unlock tables;
|
|
|
|
begin;
|
|
insert into t1 values (6, repeat('%', 12));
|
|
|
|
--source ../include/no_checkpoint_start.inc
|
|
|
|
--echo # Make the first page dirty for table t1
|
|
set global innodb_saved_page_number_debug = 0;
|
|
set global innodb_fil_make_page_dirty_debug = @space_id;
|
|
|
|
--echo # Ensure that dirty pages of table t1 are flushed.
|
|
set global innodb_buf_flush_list_now = 1;
|
|
|
|
--let CLEANUP_IF_CHECKPOINT=drop table t1;
|
|
--source ../include/no_checkpoint_end.inc
|
|
|
|
--echo # Make the first page (page_no=0) of the user tablespace
|
|
--echo # full of zeroes.
|
|
--echo #
|
|
--echo # MDEV-11623: Use old FSP_SPACE_FLAGS in the doublewrite buffer.
|
|
|
|
perl;
|
|
use IO::Handle;
|
|
do "$ENV{MTR_SUITE_DIR}/include/crc32.pl";
|
|
my $polynomial = 0x82f63b78; # CRC-32C
|
|
my $algo = $ENV{ALGO};
|
|
die "Unsupported innodb_checksum_algorithm=$algo\n" unless $algo =~ /crc32/;
|
|
|
|
my $fname= "$ENV{'MYSQLD_DATADIR'}test/t1.ibd";
|
|
my $page_size = $ENV{INNODB_PAGE_SIZE};
|
|
my $page;
|
|
do "$ENV{MTR_SUITE_DIR}/../innodb/include/crc32.pl";
|
|
open(FILE, "+<", $fname) or die;
|
|
sysread(FILE, $page, $page_size)==$page_size||die "Unable to read $name\n";
|
|
my $page1 = $page;
|
|
substr($page1, 34, 4) = pack("N", 0);
|
|
my $polynomial0 = 0x82f63b78; # CRC-32C
|
|
my $ck0 = mycrc32(substr($page1, 0, ($page_size-4)), 0, $polynomial0);
|
|
substr($page1, ($page_size - 4), 4) = pack("N", $ck0);
|
|
sysseek(FILE, 0, 0)||die "Unable to seek $fname\n";
|
|
die unless syswrite(FILE, $page1, $page_size) == $page_size;
|
|
close FILE;
|
|
|
|
open(FILE, "+<", "$ENV{MYSQLD_DATADIR}ibdata1")||die "cannot open ibdata1\n";
|
|
sysseek(FILE, 6 * $page_size - 190, 0)||die "Unable to seek ibdata1\n";
|
|
sysread(FILE, $_, 12) == 12||die "Unable to read TRX_SYS\n";
|
|
my($magic,$d1,$d2)=unpack "NNN", $_;
|
|
die "magic=$magic, $d1, $d2\n" unless $magic == 536853855 && $d2 >= $d1 + 64;
|
|
sysseek(FILE, $d1 * $page_size, 0)||die "Unable to seek ibdata1\n";
|
|
# Find the page in the doublewrite buffer
|
|
for (my $d = $d1; $d < $d2 + 64; $d++)
|
|
{
|
|
sysread(FILE, $_, $page_size)==$page_size||die "Cannot read doublewrite\n";
|
|
next unless $_ eq $page;
|
|
sysseek(FILE, $d * $page_size, 0)||die "Unable to seek ibdata1\n";
|
|
# Write buggy MariaDB 10.1.x FSP_SPACE_FLAGS to the doublewrite buffer
|
|
my($flags) = unpack "x[54]N", $_;
|
|
my $badflags = ($flags & 0x3f);
|
|
my $compression_level=6;
|
|
$badflags |= 1<<6|$compression_level<<7 if ($flags & 1 << 16);
|
|
$badflags |= ($flags & 15 << 6) << 7; # PAGE_SSIZE
|
|
|
|
substr ($_, 54, 4) = pack("N", $badflags);
|
|
if ($algo =~ /full_crc32/)
|
|
{
|
|
my $ck = mycrc32(substr($_, 0, $page_size - 4), 0, $polynomial);
|
|
substr($_, $page_size - 4, 4) = pack("N", $ck);
|
|
}
|
|
else
|
|
{
|
|
# Replace the innodb_checksum_algorithm=crc32 checksum
|
|
my $ck= pack("N",
|
|
mycrc32(substr($_, 4, 22), 0, $polynomial) ^
|
|
mycrc32(substr($_, 38, $page_size - 38 - 8), 0,
|
|
$polynomial));
|
|
substr ($_, 0, 4) = $ck;
|
|
substr ($_, $page_size - 8, 4) = $ck;
|
|
}
|
|
syswrite(FILE, $_, $page_size)==$page_size||die;
|
|
close(FILE);
|
|
exit 0;
|
|
}
|
|
die "Did not find the page in the doublewrite buffer ($d1,$d2)\n";
|
|
EOF
|
|
|
|
--source include/start_mysqld.inc
|
|
|
|
check table t1;
|
|
select f1, f2 from t1;
|
|
|
|
--echo # Test End
|
|
--echo # ---------------------------------------------------------------
|
|
--echo # Test Begin: Test if recovery works if first page of user
|
|
--echo # tablespace is corrupted.
|
|
|
|
select space from information_schema.innodb_sys_tables
|
|
where name = 'test/t1' into @space_id;
|
|
|
|
--echo # Ensure that dirty pages of table t1 is flushed.
|
|
flush tables t1 for export;
|
|
unlock tables;
|
|
|
|
begin;
|
|
insert into t1 values (6, repeat('%', 12));
|
|
|
|
--source ../include/no_checkpoint_start.inc
|
|
|
|
--echo # Make the first page dirty for table t1
|
|
set global innodb_saved_page_number_debug = 0;
|
|
set global innodb_fil_make_page_dirty_debug = @space_id;
|
|
|
|
--echo # Ensure that dirty pages of table t1 are flushed.
|
|
set global innodb_buf_flush_list_now = 1;
|
|
|
|
--source include/no_checkpoint_end.inc
|
|
|
|
--echo # Corrupt the first page (page_no=0) of the user tablespace.
|
|
perl;
|
|
use IO::Handle;
|
|
my $fname= "$ENV{'MYSQLD_DATADIR'}test/t1.ibd";
|
|
my $page_size = $ENV{INNODB_PAGE_SIZE};
|
|
open(FILE, "+<", $fname) or die;
|
|
sysread(FILE, $page, $page_size)==$page_size||die "Unable to read $name\n";
|
|
substr($page, 28, 4) = pack("N", 1000);
|
|
sysseek(FILE, 0, 0)||die "Unable to seek $fname\n";
|
|
die unless syswrite(FILE, $page, $page_size) == $page_size;
|
|
close FILE;
|
|
EOF
|
|
|
|
--source include/start_mysqld.inc
|
|
|
|
check table t1;
|
|
select f1, f2 from t1;
|
|
|
|
--echo # Test End
|
|
--echo # ---------------------------------------------------------------
|
|
--echo # Test Begin: Test if recovery works if 2nd page of user
|
|
--echo # tablespace is full of zeroes.
|
|
|
|
select space from information_schema.innodb_sys_tables
|
|
where name = 'test/t1' into @space_id;
|
|
|
|
--echo # Ensure that dirty pages of table t1 is flushed.
|
|
flush tables t1 for export;
|
|
unlock tables;
|
|
|
|
begin;
|
|
insert into t1 values (6, repeat('%', 400));
|
|
|
|
--source ../include/no_checkpoint_start.inc
|
|
|
|
--echo # Make the 2nd page dirty for table t1
|
|
set global innodb_saved_page_number_debug = 1;
|
|
set global innodb_fil_make_page_dirty_debug = @space_id;
|
|
|
|
--echo # Ensure that dirty pages of table t1 are flushed.
|
|
set global innodb_buf_flush_list_now = 1;
|
|
|
|
--source include/no_checkpoint_end.inc
|
|
|
|
--echo # Make the 2nd page (page_no=1) of the tablespace all zeroes.
|
|
perl;
|
|
use IO::Handle;
|
|
my $fname= "$ENV{'MYSQLD_DATADIR'}test/t1.ibd";
|
|
open(FILE, "+<", $fname) or die;
|
|
FILE->autoflush(1);
|
|
binmode FILE;
|
|
seek(FILE, $ENV{'INNODB_PAGE_SIZE'}, SEEK_SET);
|
|
print FILE chr(0) x ($ENV{'INNODB_PAGE_SIZE'});
|
|
close FILE;
|
|
EOF
|
|
|
|
--source include/start_mysqld.inc
|
|
|
|
check table t1;
|
|
select f1, f2 from t1;
|
|
|
|
--echo # Test End
|
|
--echo # ---------------------------------------------------------------
|
|
--echo # Test Begin: Test if recovery works if 2nd page of user
|
|
--echo # tablespace is corrupted.
|
|
|
|
select space from information_schema.innodb_sys_tables
|
|
where name = 'test/t1' into @space_id;
|
|
|
|
--echo # Ensure that dirty pages of table t1 is flushed.
|
|
flush tables t1 for export;
|
|
unlock tables;
|
|
|
|
begin;
|
|
insert into t1 values (6, repeat('%', 400));
|
|
|
|
--source ../include/no_checkpoint_start.inc
|
|
|
|
--echo # Make the 2nd page dirty for table t1
|
|
set global innodb_saved_page_number_debug = 1;
|
|
set global innodb_fil_make_page_dirty_debug = @space_id;
|
|
|
|
--echo # Ensure that the dirty pages of table t1 are flushed.
|
|
set global innodb_buf_flush_list_now = 1;
|
|
|
|
--source include/no_checkpoint_end.inc
|
|
|
|
--echo # Corrupt the 2nd page (page_no=1) of the user tablespace.
|
|
perl;
|
|
use IO::Handle;
|
|
my $fname= "$ENV{'MYSQLD_DATADIR'}test/t1.ibd";
|
|
open(FILE, "+<", $fname) or die;
|
|
FILE->autoflush(1);
|
|
binmode FILE;
|
|
seek(FILE, $ENV{'INNODB_PAGE_SIZE'}, SEEK_SET);
|
|
print FILE chr(0) x ($ENV{'INNODB_PAGE_SIZE'}/2);
|
|
close FILE;
|
|
EOF
|
|
|
|
--source include/start_mysqld.inc
|
|
|
|
check table t1;
|
|
select f1, f2 from t1;
|
|
|
|
--echo # Test End
|
|
--echo # ---------------------------------------------------------------
|
|
--echo # Test Begin: Test if recovery works if first page of
|
|
--echo # system tablespace is full of zeroes.
|
|
|
|
begin;
|
|
insert into t1 values (6, repeat('%', 400));
|
|
|
|
--echo # Ensure that all dirty pages in the system are flushed.
|
|
set global innodb_buf_flush_list_now = 1;
|
|
|
|
--echo # Make the first page dirty for system tablespace
|
|
set global innodb_saved_page_number_debug = 0;
|
|
set global innodb_fil_make_page_dirty_debug = 0;
|
|
|
|
--echo # Ensure that the dirty page of system tablespace is also flushed.
|
|
# We do this after the transaction starts and all dirty pages have been flushed
|
|
# already. So flushing of this specified dirty page will surely keep the
|
|
# copy in doublewrite buffer, and no more writes to doublewrite buffer would
|
|
# overwrite the copy. Thus, we can safely modify the original page when server
|
|
# is down. So do the following testings.
|
|
set global innodb_buf_flush_list_now = 1;
|
|
|
|
--source include/kill_mysqld.inc
|
|
|
|
--echo # Make the first page (page_no=0) of the system tablespace
|
|
--echo # all zeroes.
|
|
perl;
|
|
use IO::Handle;
|
|
my $fname= "$ENV{'MYSQLD_DATADIR'}ibdata1";
|
|
open(FILE, "+<", $fname) or die;
|
|
FILE->autoflush(1);
|
|
binmode FILE;
|
|
print FILE chr(0) x ($ENV{'INNODB_PAGE_SIZE'});
|
|
close FILE;
|
|
EOF
|
|
|
|
--source include/start_mysqld.inc
|
|
|
|
check table t1;
|
|
select f1, f2 from t1;
|
|
|
|
--echo # Test End
|
|
--echo # ---------------------------------------------------------------
|
|
--echo # Test Begin: Test if recovery works if first page of
|
|
--echo # system tablespace is corrupted.
|
|
|
|
begin;
|
|
insert into t1 values (6, repeat('%', 400));
|
|
|
|
--echo # Ensure that all dirty pages in the system are flushed.
|
|
set global innodb_buf_flush_list_now = 1;
|
|
|
|
--echo # Make the first page dirty for system tablespace
|
|
set global innodb_saved_page_number_debug = 0;
|
|
set global innodb_fil_make_page_dirty_debug = 0;
|
|
|
|
--echo # Ensure that the dirty page of system tablespace is also flushed.
|
|
set global innodb_buf_flush_list_now = 1;
|
|
|
|
--source include/kill_mysqld.inc
|
|
|
|
--echo # Corrupt the first page (page_no=0) of the system tablespace.
|
|
perl;
|
|
use IO::Handle;
|
|
my $fname= "$ENV{'MYSQLD_DATADIR'}ibdata1";
|
|
open(FILE, "+<", $fname) or die;
|
|
FILE->autoflush(1);
|
|
binmode FILE;
|
|
print FILE chr(0) x ($ENV{'INNODB_PAGE_SIZE'}/2);
|
|
close FILE;
|
|
EOF
|
|
|
|
--source include/start_mysqld.inc
|
|
|
|
check table t1;
|
|
select f1, f2 from t1;
|
|
|
|
--echo # Test End
|
|
--echo # ---------------------------------------------------------------
|
|
--echo # Test Begin: Test if recovery works if 2nd page of
|
|
--echo # system tablespace is full of zeroes.
|
|
|
|
begin;
|
|
insert into t1 values (6, repeat('%', 400));
|
|
|
|
--echo # Ensure that all dirty pages in the system are flushed.
|
|
set global innodb_buf_flush_list_now = 1;
|
|
|
|
--echo # Make the second page dirty for system tablespace
|
|
set global innodb_saved_page_number_debug = 1;
|
|
set global innodb_fil_make_page_dirty_debug = 0;
|
|
|
|
--echo # Ensure that the dirty page of system tablespace is also flushed.
|
|
set global innodb_buf_flush_list_now = 1;
|
|
|
|
--source include/kill_mysqld.inc
|
|
|
|
--echo # Make the 2nd page (page_no=1) of the system tablespace
|
|
--echo # all zeroes.
|
|
perl;
|
|
use IO::Handle;
|
|
my $fname= "$ENV{'MYSQLD_DATADIR'}ibdata1";
|
|
open(FILE, "+<", $fname) or die;
|
|
FILE->autoflush(1);
|
|
binmode FILE;
|
|
seek(FILE, $ENV{'INNODB_PAGE_SIZE'}, SEEK_SET);
|
|
print FILE chr(0) x ($ENV{'INNODB_PAGE_SIZE'});
|
|
close FILE;
|
|
EOF
|
|
|
|
--source include/start_mysqld.inc
|
|
|
|
check table t1;
|
|
select f1, f2 from t1;
|
|
|
|
--echo # Test End
|
|
--echo # ---------------------------------------------------------------
|
|
--echo # Test Begin: Test if recovery works if 2nd page of
|
|
--echo # system tablespace is corrupted.
|
|
|
|
begin;
|
|
insert into t1 values (6, repeat('%', 400));
|
|
|
|
--echo # Ensure that all dirty pages in the system are flushed.
|
|
set global innodb_buf_flush_list_now = 1;
|
|
|
|
--echo # Make the second page dirty for system tablespace
|
|
set global innodb_saved_page_number_debug = 1;
|
|
set global innodb_fil_make_page_dirty_debug = 0;
|
|
|
|
--echo # Ensure that the dirty page of system tablespace is also flushed.
|
|
set global innodb_buf_flush_list_now = 1;
|
|
|
|
--source include/kill_mysqld.inc
|
|
|
|
--echo # Make the 2nd page (page_no=1) of the system tablespace
|
|
--echo # all zeroes.
|
|
perl;
|
|
use IO::Handle;
|
|
my $fname= "$ENV{'MYSQLD_DATADIR'}ibdata1";
|
|
open(FILE, "+<", $fname) or die;
|
|
FILE->autoflush(1);
|
|
binmode FILE;
|
|
seek(FILE, $ENV{'INNODB_PAGE_SIZE'}, SEEK_SET);
|
|
print FILE chr(0) x ($ENV{'INNODB_PAGE_SIZE'}/2);
|
|
close FILE;
|
|
EOF
|
|
|
|
--source include/start_mysqld.inc
|
|
|
|
check table t1;
|
|
--let SEARCH_PATTERN= InnoDB: .*test.t1\\.ibd
|
|
--source include/search_pattern_in_file.inc
|
|
|
|
select f1, f2 from t1;
|
|
|
|
drop table t1;
|
|
|
|
--echo #
|
|
--echo # MDEV-12600 crash during install_db with innodb_page_size=32K
|
|
--echo # and ibdata1=3M
|
|
--echo #
|
|
let bugdir= $MYSQLTEST_VARDIR/tmp/doublewrite;
|
|
--mkdir $bugdir
|
|
|
|
let $check_no_innodb=SELECT * FROM INFORMATION_SCHEMA.ENGINES
|
|
WHERE engine = 'innodb'
|
|
AND support IN ('YES', 'DEFAULT', 'ENABLED');
|
|
|
|
--let $ibp=--innodb-log-group-home-dir=$bugdir --innodb-data-home-dir=$bugdir
|
|
--let $ibd=$ibp --innodb-undo-tablespaces=0 --innodb-log-files-in-group=2
|
|
--let $ibp=$ibp --innodb-data-file-path=ibdata1:1M;ibdata2:1M:autoextend
|
|
|
|
--let $restart_parameters= $ibp
|
|
--source include/restart_mysqld.inc
|
|
eval $check_no_innodb;
|
|
--let SEARCH_PATTERN= \[ERROR\] InnoDB: Cannot create doublewrite buffer
|
|
--source include/search_pattern_in_file.inc
|
|
--let $restart_parameters=
|
|
--source include/restart_mysqld.inc
|
|
|
|
--remove_file $bugdir/ibdata1
|
|
--remove_file $bugdir/ibdata2
|
|
--remove_file $bugdir/ib_logfile0
|
|
--rmdir $bugdir
|