mirror of
https://github.com/MariaDB/server.git
synced 2025-04-26 11:49:09 +03:00
In commit 24648768b443f6adeb8a0f4302958bfb300d536f (MDEV-30136) the parameter innodb_flush_method was deprecated, with no direct replacement for innodb_flush_method=O_DIRECT_NO_FSYNC. Let us change innodb_doublewrite from Boolean to ENUM that can be changed while the server is running: OFF: Assume that writes of innodb_page_size are atomic ON: Prevent torn writes (the default) fast: Like ON, but avoid synchronizing writes to data files The deprecated start-up parameter innodb_flush_method=NO_FSYNC will cause innodb_doublewrite=ON to be changed to innodb_doublewrite=fast, which will prevent InnoDB from making any durable writes to data files. This would normally be done right before the log checkpoint LSN is updated. Depending on the file systems being used and their configuration, this may or may not be safe. The value innodb_doublewrite=fast differs from the previous combination of innodb_doublewrite=ON and innodb_flush_method=O_DIRECT_NO_FSYNC by always invoking os_file_flush() on the doublewrite buffer itself in buf_dblwr_t::flush_buffered_writes_completed(). This should be safer when there are multiple doublewrite batches between checkpoints. Typically, once per second, buf_flush_page_cleaner() would write out up to innodb_io_capacity pages and advance the log checkpoint. Also typically, innodb_io_capacity>128, which is the size of the doublewrite buffer in pages. Should os_file_flush_func() not be invoked between doublewrite batches, writes could be reordered in an unsafe way. The setting innodb_doublewrite=fast could be safe when the doublewrite buffer (the first file of the system tablespace) and the data files reside in the same file system. This was tested by running "./mtr --rr innodb.alter_kill". On the first server startup, with innodb_doublewrite=fast, os_file_flush_func() would only be invoked on the ibdata1 file and possibly ib_logfile0. On subsequent startups with innodb_doublewrite=OFF, os_file_flush_func() will be invoked on the individual data files during log_checkpoint(). Note: The setting debug_no_sync (in the code, my_disable_sync) would disable all durable writes to InnoDB files, which would be much less safe. IORequest::Type: Introduce special values WRITE_DBL and PUNCH_DBL for asynchronous writes that are submitted via the doublewrite buffer. In this way, fil_space_t::use_doublewrite() or buf_dblwr.in_use() will only be consulted during buf_page_t::flush() and the doublewrite buffer can be enabled or disabled without any fear of inconsistency. buf_dblwr_t::block_size: Replaces block_size(). buf_dblwr_t::flush_buffered_writes(): If !in_use() and the doublewrite buffer is empty, just invoke fil_flush_file_spaces() and return. The doublewrite buffer could have been disabled while a batch was in progress. innodb_init_params(): If innodb_flush_method=O_DIRECT_NO_FSYNC, set innodb_doublewrite=fast or innodb_doublewrite=fearless. Thanks to Mark Callaghan for reporting this, and Vladislav Vaintroub for feedback.
180 lines
5.9 KiB
Plaintext
180 lines
5.9 KiB
Plaintext
--source include/have_innodb.inc
|
|
# The embedded server does not support restarting in mysql-test-run.
|
|
-- source include/not_embedded.inc
|
|
-- source include/no_valgrind_without_big.inc
|
|
-- source include/innodb_checksum_algorithm.inc
|
|
|
|
let MYSQLD_DATADIR=`select @@datadir`;
|
|
let PAGE_SIZE=`select @@innodb_page_size`;
|
|
|
|
SELECT @@innodb_doublewrite;
|
|
SET GLOBAL innodb_doublewrite=fast;
|
|
|
|
-- disable_query_log
|
|
call mtr.add_suppression("InnoDB: innodb_force_recovery is on.");
|
|
call mtr.add_suppression("InnoDB: Ignoring tablespace for.*bug16720368");
|
|
call mtr.add_suppression("Found 1 prepared XA transactions");
|
|
call mtr.add_suppression("InnoDB: Operating system error.*in a file operation");
|
|
call mtr.add_suppression("InnoDB: \(The error means\|If you are\)");
|
|
call mtr.add_suppression("InnoDB: Ignoring tablespace `test/bug16720368` because it could not be opened");
|
|
call mtr.add_suppression("InnoDB: Tablespace .* was not found at.*bug16735660");
|
|
call mtr.add_suppression("InnoDB: Plugin initialization aborted*");
|
|
call mtr.add_suppression("Plugin 'InnoDB' init function returned error.");
|
|
call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed.");
|
|
call mtr.add_suppression("Table .*bug16720368.* is corrupted");
|
|
-- enable_query_log
|
|
|
|
-- echo #
|
|
-- echo # Bug#16720368 INNODB CRASHES ON BROKEN #SQL*.IBD FILE AT STARTUP
|
|
-- echo #
|
|
|
|
SET GLOBAL innodb_stats_persistent=0;
|
|
|
|
CREATE TABLE bug16720368_1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
|
|
|
connect (con1,localhost,root);
|
|
CREATE TABLE bug16720368 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
|
INSERT INTO bug16720368 (a) VALUES (1),(2),(3),(4),(5),(6),(7),(8);
|
|
--source include/wait_all_purged.inc
|
|
|
|
connection default;
|
|
|
|
-- echo # Cleanly shutdown mysqld
|
|
-- source include/shutdown_mysqld.inc
|
|
|
|
disconnect con1;
|
|
|
|
-- echo # Corrupt FIL_PAGE_TYPE in bug16720368.ibd,
|
|
-- echo # and recompute innodb_checksum_algorithm=crc32
|
|
perl;
|
|
do "$ENV{MTR_SUITE_DIR}/include/crc32.pl";
|
|
my $file = "$ENV{MYSQLD_DATADIR}/test/bug16720368.ibd";
|
|
open(FILE, "+<$file") || die "Unable to open $file";
|
|
binmode FILE;
|
|
my $ps= $ENV{PAGE_SIZE};
|
|
my $page;
|
|
die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
|
|
my $full_crc32 = unpack("N",substr($page,54,4)) & 0x10; # FIL_SPACE_FLAGS
|
|
sysseek(FILE, 3*$ps, 0) || die "Unable to seek $file\n";
|
|
die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
|
|
substr($page,24,2)='42';
|
|
my $polynomial = 0x82f63b78; # CRC-32C
|
|
if ($full_crc32)
|
|
{
|
|
my $ck = mycrc32(substr($page, 0, $ps-4), 0, $polynomial);
|
|
substr($page, $ps-4, 4) = pack("N", $ck);
|
|
}
|
|
else
|
|
{
|
|
my $ck= pack("N",mycrc32(substr($page, 4, 22), 0, $polynomial) ^
|
|
mycrc32(substr($page, 38, $ps - 38 - 8), 0, $polynomial));
|
|
substr($page,0,4)=$ck;
|
|
substr($page,$ps-8,4)=$ck;
|
|
}
|
|
sysseek(FILE, 3*$ps, 0) || die "Unable to rewind $file\n";
|
|
syswrite(FILE, $page, $ps)==$ps || die "Unable to write $file\n";
|
|
close(FILE) || die "Unable to close $file";
|
|
EOF
|
|
|
|
-- let $restart_parameters=--innodb-flush-method=O_DIRECT
|
|
-- source include/start_mysqld.inc
|
|
-- let $restart_parameters=
|
|
|
|
SELECT @@innodb_doublewrite;
|
|
--error ER_TABLE_CORRUPT
|
|
SELECT COUNT(*) FROM bug16720368;
|
|
--error ER_TABLE_CORRUPT
|
|
INSERT INTO bug16720368 VALUES(1);
|
|
INSERT INTO bug16720368_1 VALUES(1);
|
|
|
|
-- echo # Shut down the server to uncorrupt the data.
|
|
-- source include/shutdown_mysqld.inc
|
|
|
|
# Uncorrupt the FIL_PAGE_TYPE.
|
|
perl;
|
|
do "$ENV{MTR_SUITE_DIR}/include/crc32.pl";
|
|
my $file = "$ENV{MYSQLD_DATADIR}/test/bug16720368.ibd";
|
|
open(FILE, "+<$file") || die "Unable to open $file";
|
|
binmode FILE;
|
|
my $ps= $ENV{PAGE_SIZE};
|
|
my $page;
|
|
die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
|
|
my $full_crc32 = unpack("N",substr($page,54,4)) & 0x10; # FIL_SPACE_FLAGS
|
|
sysseek(FILE, 3*$ps, 0) || die "Unable to seek $file\n";
|
|
die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
|
|
substr($page,24,2)=pack("H*","45BF");
|
|
my $polynomial = 0x82f63b78; # CRC-32C
|
|
if ($full_crc32)
|
|
{
|
|
my $ck = mycrc32(substr($page, 0, $ps-4), 0, $polynomial);
|
|
substr($page, $ps-4, 4) = pack("N", $ck);
|
|
}
|
|
else
|
|
{
|
|
my $ck= pack("N",mycrc32(substr($page, 4, 22), 0, $polynomial) ^
|
|
mycrc32(substr($page, 38, $ps - 38 - 8), 0, $polynomial));
|
|
substr($page,0,4)=$ck;
|
|
substr($page,$ps-8,4)=$ck;
|
|
}
|
|
sysseek(FILE, 3*$ps, 0) || die "Unable to rewind $file\n";
|
|
syswrite(FILE, $page, $ps)==$ps || die "Unable to write $file\n";
|
|
close(FILE) || die "Unable to close $file";
|
|
EOF
|
|
|
|
-- source include/start_mysqld.inc
|
|
|
|
INSERT INTO bug16720368 VALUES(9,1);
|
|
SELECT COUNT(*) FROM bug16720368;
|
|
# A debug assertion would fail in buf_block_align_instance()
|
|
# if we did not uncorrupt the page number first.
|
|
DROP TABLE bug16720368, bug16720368_1;
|
|
|
|
-- echo #
|
|
-- echo # Bug#16735660 ASSERT TABLE2 == NULL, ROLLBACK OF RESURRECTED TXNS,
|
|
-- echo # DICT_TABLE_ADD_TO_CACHE
|
|
-- echo #
|
|
|
|
CREATE TEMPORARY TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
|
BEGIN;
|
|
INSERT INTO t1 VALUES(42);
|
|
|
|
-- connect (con1,localhost,root)
|
|
|
|
CREATE TABLE bug16735660 (a INT PRIMARY KEY) ENGINE=InnoDB;
|
|
|
|
XA START 'x';
|
|
--source ../include/no_checkpoint_start.inc
|
|
INSERT INTO bug16735660 VALUES(1),(2),(3);
|
|
XA END 'x';
|
|
XA PREPARE 'x';
|
|
--connection default
|
|
--let CLEANUP_IF_CHECKPOINT=XA ROLLBACK 'x';DROP TABLE bug16735660;
|
|
--source ../include/no_checkpoint_end.inc
|
|
|
|
-- disconnect con1
|
|
-- move_file $MYSQLD_DATADIR/test/bug16735660.ibd $MYSQLD_DATADIR/bug16735660.omg
|
|
|
|
-- echo # Attempt to start without an *.ibd file.
|
|
let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err;
|
|
--source include/start_mysqld.inc
|
|
|
|
let SEARCH_PATTERN= \[ERROR\] InnoDB: Tablespace [0-9]+ was not found at .*test.bug16735660.ibd;
|
|
-- source include/search_pattern_in_file.inc
|
|
|
|
-- move_file $MYSQLD_DATADIR/bug16735660.omg $MYSQLD_DATADIR/test/bug16735660.ibd
|
|
|
|
-- source include/restart_mysqld.inc
|
|
|
|
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
|
--disable_ps2_protocol
|
|
SELECT * FROM bug16735660;
|
|
--enable_ps2_protocol
|
|
|
|
XA RECOVER;
|
|
XA ROLLBACK 'x';
|
|
|
|
--disable_ps2_protocol
|
|
SELECT * FROM bug16735660;
|
|
--enable_ps2_protocol
|
|
DROP TABLE bug16735660;
|