mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-11799 InnoDB can abort if the doublewrite buffer
contains a bad and a good copy Clean up the InnoDB doublewrite buffer code. buf_dblwr_init_or_load_pages(): Do not add empty pages to the buffer. buf_dblwr_process(): Do consider changes to pages that are all zero. Do not abort when finding a corrupted copy of a page in the doublewrite buffer, because there could be multiple copies in the doublewrite buffer, and only one of them needs to be good.
This commit is contained in:
@ -1,4 +1,3 @@
|
|||||||
call mtr.add_suppression("InnoDB: Warning: database page corruption or a failed");
|
|
||||||
CREATE TABLE t1(a CHAR(255),
|
CREATE TABLE t1(a CHAR(255),
|
||||||
b CHAR(255),
|
b CHAR(255),
|
||||||
c CHAR(255),
|
c CHAR(255),
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
call mtr.add_suppression("InnoDB: Warning: database page corruption or a failed");
|
|
||||||
CREATE TABLE t1(a CHAR(255),
|
CREATE TABLE t1(a CHAR(255),
|
||||||
b CHAR(255),
|
b CHAR(255),
|
||||||
c CHAR(255),
|
c CHAR(255),
|
||||||
|
@ -4,10 +4,6 @@
|
|||||||
# Temporary tablename will be unique. This makes sure that future
|
# Temporary tablename will be unique. This makes sure that future
|
||||||
# in-place ALTERs of the same table will not be blocked due to
|
# in-place ALTERs of the same table will not be blocked due to
|
||||||
# temporary tablename.
|
# temporary tablename.
|
||||||
call mtr.add_suppression("InnoDB: Warning: database page corruption or a failed
|
|
||||||
");
|
|
||||||
call mtr.add_suppression("InnoDB: file read of space .* page .*");
|
|
||||||
call mtr.add_suppression("InnoDB: Trying to recover it from the doublewrite buffer.");
|
|
||||||
# Crash the server in ha_innobase::commit_inplace_alter_table()
|
# Crash the server in ha_innobase::commit_inplace_alter_table()
|
||||||
CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL) ENGINE=innodb;
|
CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL) ENGINE=innodb;
|
||||||
SET debug='d,innodb_alter_commit_crash_before_commit';
|
SET debug='d,innodb_alter_commit_crash_before_commit';
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed.*");
|
call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed.*");
|
||||||
CALL mtr.add_suppression("InnoDB: Error: Unable to read tablespace .* page no .* into the buffer pool after 100 attempts");
|
CALL mtr.add_suppression("InnoDB: Error: Unable to read tablespace .* page no .* into the buffer pool after 100 attempts");
|
||||||
CALL mtr.add_suppression("InnoDB: Warning: database page corruption or a failed");
|
|
||||||
CALL mtr.add_suppression("InnoDB: Database page corruption on disk or a failed");
|
CALL mtr.add_suppression("InnoDB: Database page corruption on disk or a failed");
|
||||||
CALL mtr.add_suppression("InnoDB: Space .* file test/t1 read of page .*");
|
CALL mtr.add_suppression("InnoDB: Space .* file test/t1 read of page .*");
|
||||||
CALL mtr.add_suppression("InnoDB: You may have to recover from a backup.");
|
CALL mtr.add_suppression("InnoDB: You may have to recover from a backup.");
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
call mtr.add_suppression("InnoDB: Warning: database page corruption or a failed");
|
|
||||||
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
|
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
|
||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
XA START 'x';
|
XA START 'x';
|
||||||
@ -6,6 +5,7 @@ UPDATE t1 set a=2;
|
|||||||
XA END 'x';
|
XA END 'x';
|
||||||
XA PREPARE 'x';
|
XA PREPARE 'x';
|
||||||
call mtr.add_suppression("Found 1 prepared XA transactions");
|
call mtr.add_suppression("Found 1 prepared XA transactions");
|
||||||
|
# Kill the server
|
||||||
SELECT * FROM t1 LOCK IN SHARE MODE;
|
SELECT * FROM t1 LOCK IN SHARE MODE;
|
||||||
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
|
@ -9,8 +9,6 @@
|
|||||||
--source include/have_debug.inc
|
--source include/have_debug.inc
|
||||||
--source include/have_log_bin.inc
|
--source include/have_log_bin.inc
|
||||||
|
|
||||||
call mtr.add_suppression("InnoDB: Warning: database page corruption or a failed");
|
|
||||||
|
|
||||||
let $file_format_max=`SELECT @@innodb_file_format_max`;
|
let $file_format_max=`SELECT @@innodb_file_format_max`;
|
||||||
CREATE TABLE t1(a CHAR(255),
|
CREATE TABLE t1(a CHAR(255),
|
||||||
b CHAR(255),
|
b CHAR(255),
|
||||||
|
@ -9,8 +9,6 @@
|
|||||||
--source include/have_debug.inc
|
--source include/have_debug.inc
|
||||||
--source include/have_log_bin.inc
|
--source include/have_log_bin.inc
|
||||||
|
|
||||||
call mtr.add_suppression("InnoDB: Warning: database page corruption or a failed");
|
|
||||||
|
|
||||||
let $file_format_max=`SELECT @@innodb_file_format_max`;
|
let $file_format_max=`SELECT @@innodb_file_format_max`;
|
||||||
CREATE TABLE t1(a CHAR(255),
|
CREATE TABLE t1(a CHAR(255),
|
||||||
b CHAR(255),
|
b CHAR(255),
|
||||||
|
@ -20,13 +20,6 @@
|
|||||||
--echo # in-place ALTERs of the same table will not be blocked due to
|
--echo # in-place ALTERs of the same table will not be blocked due to
|
||||||
--echo # temporary tablename.
|
--echo # temporary tablename.
|
||||||
|
|
||||||
# As we intentionally crash below, there could be partially written
|
|
||||||
# pages that are then recovered from the doublewrite buffer
|
|
||||||
call mtr.add_suppression("InnoDB: Warning: database page corruption or a failed
|
|
||||||
");
|
|
||||||
call mtr.add_suppression("InnoDB: file read of space .* page .*");
|
|
||||||
call mtr.add_suppression("InnoDB: Trying to recover it from the doublewrite buffer.");
|
|
||||||
|
|
||||||
let datadir= `select @@datadir`;
|
let datadir= `select @@datadir`;
|
||||||
|
|
||||||
--let $_server_id= `SELECT @@server_id`
|
--let $_server_id= `SELECT @@server_id`
|
||||||
|
@ -21,7 +21,6 @@ source include/have_debug.inc;
|
|||||||
source include/not_windows.inc;
|
source include/not_windows.inc;
|
||||||
|
|
||||||
CALL mtr.add_suppression("InnoDB: Error: Unable to read tablespace .* page no .* into the buffer pool after 100 attempts");
|
CALL mtr.add_suppression("InnoDB: Error: Unable to read tablespace .* page no .* into the buffer pool after 100 attempts");
|
||||||
CALL mtr.add_suppression("InnoDB: Warning: database page corruption or a failed");
|
|
||||||
CALL mtr.add_suppression("InnoDB: Database page corruption on disk or a failed");
|
CALL mtr.add_suppression("InnoDB: Database page corruption on disk or a failed");
|
||||||
CALL mtr.add_suppression("InnoDB: Space .* file test/t1 read of page .*");
|
CALL mtr.add_suppression("InnoDB: Space .* file test/t1 read of page .*");
|
||||||
CALL mtr.add_suppression("InnoDB: You may have to recover from a backup.");
|
CALL mtr.add_suppression("InnoDB: You may have to recover from a backup.");
|
||||||
|
@ -12,11 +12,6 @@ if (`select plugin_auth_version <= "5.6.24" from information_schema.plugins wher
|
|||||||
FLUSH TABLES;
|
FLUSH TABLES;
|
||||||
--enable_query_log
|
--enable_query_log
|
||||||
|
|
||||||
#
|
|
||||||
# We kill server belown with timeout 0 that is not fully safe
|
|
||||||
#
|
|
||||||
call mtr.add_suppression("InnoDB: Warning: database page corruption or a failed");
|
|
||||||
|
|
||||||
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
|
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
|
||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
connect (con1,localhost,root);
|
connect (con1,localhost,root);
|
||||||
@ -25,15 +20,8 @@ connection default;
|
|||||||
|
|
||||||
call mtr.add_suppression("Found 1 prepared XA transactions");
|
call mtr.add_suppression("Found 1 prepared XA transactions");
|
||||||
|
|
||||||
# Kill and restart the server.
|
--source include/kill_mysqld.inc
|
||||||
-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
|
--source include/start_mysqld.inc
|
||||||
-- shutdown_server 0
|
|
||||||
-- source include/wait_until_disconnected.inc
|
|
||||||
|
|
||||||
-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
|
|
||||||
-- enable_reconnect
|
|
||||||
-- source include/wait_until_connected_again.inc
|
|
||||||
-- disable_reconnect
|
|
||||||
|
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
connect (con1,localhost,root);
|
connect (con1,localhost,root);
|
||||||
|
@ -3,7 +3,6 @@ include/rpl_init.inc [topology=1->2]
|
|||||||
call mtr.add_suppression("Checking table:");
|
call mtr.add_suppression("Checking table:");
|
||||||
call mtr.add_suppression("client is using or hasn't closed the table properly");
|
call mtr.add_suppression("client is using or hasn't closed the table properly");
|
||||||
call mtr.add_suppression("Table .* is marked as crashed and should be repaired");
|
call mtr.add_suppression("Table .* is marked as crashed and should be repaired");
|
||||||
call mtr.add_suppression("InnoDB: Warning: database page corruption or a failed");
|
|
||||||
flush tables;
|
flush tables;
|
||||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||||
CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
|
||||||
|
@ -12,11 +12,6 @@
|
|||||||
call mtr.add_suppression("Checking table:");
|
call mtr.add_suppression("Checking table:");
|
||||||
call mtr.add_suppression("client is using or hasn't closed the table properly");
|
call mtr.add_suppression("client is using or hasn't closed the table properly");
|
||||||
call mtr.add_suppression("Table .* is marked as crashed and should be repaired");
|
call mtr.add_suppression("Table .* is marked as crashed and should be repaired");
|
||||||
# We have seen this warning a couple of times in Buildbot. Since we crash the
|
|
||||||
# server deliberately, it seems possible that we could in rare cases crash in
|
|
||||||
# the middle of a page write. The page is recovered from the doublewrite
|
|
||||||
# buffer ("[Note] InnoDB: Recovered the page from the doublewrite buffer.").
|
|
||||||
call mtr.add_suppression("InnoDB: Warning: database page corruption or a failed");
|
|
||||||
flush tables;
|
flush tables;
|
||||||
|
|
||||||
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
|
||||||
|
@ -455,8 +455,11 @@ buf_dblwr_init_or_load_pages(
|
|||||||
os_file_write(path, file, page,
|
os_file_write(path, file, page,
|
||||||
source_page_no * UNIV_PAGE_SIZE,
|
source_page_no * UNIV_PAGE_SIZE,
|
||||||
UNIV_PAGE_SIZE);
|
UNIV_PAGE_SIZE);
|
||||||
} else if (load_corrupt_pages) {
|
} else if (load_corrupt_pages
|
||||||
|
&& !buf_page_is_zeroes(page, FIL_PAGE_DATA)) {
|
||||||
|
/* Each valid page header must contain some
|
||||||
|
nonzero bytes, such as FIL_PAGE_OFFSET
|
||||||
|
or FIL_PAGE_LSN. */
|
||||||
recv_dblwr.add(page);
|
recv_dblwr.add(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,8 +495,6 @@ buf_dblwr_process()
|
|||||||
|
|
||||||
for (std::list<byte*>::iterator i = recv_dblwr.pages.begin();
|
for (std::list<byte*>::iterator i = recv_dblwr.pages.begin();
|
||||||
i != recv_dblwr.pages.end(); ++i, ++page_no_dblwr ) {
|
i != recv_dblwr.pages.end(); ++i, ++page_no_dblwr ) {
|
||||||
bool is_compressed = false;
|
|
||||||
|
|
||||||
page = *i;
|
page = *i;
|
||||||
page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
|
page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
|
||||||
space_id = mach_read_from_4(page + FIL_PAGE_SPACE_ID);
|
space_id = mach_read_from_4(page + FIL_PAGE_SPACE_ID);
|
||||||
@ -501,139 +502,104 @@ buf_dblwr_process()
|
|||||||
if (!fil_tablespace_exists_in_mem(space_id)) {
|
if (!fil_tablespace_exists_in_mem(space_id)) {
|
||||||
/* Maybe we have dropped the single-table tablespace
|
/* Maybe we have dropped the single-table tablespace
|
||||||
and this page once belonged to it: do nothing */
|
and this page once belonged to it: do nothing */
|
||||||
|
continue;
|
||||||
} else if (!fil_check_adress_in_tablespace(space_id,
|
|
||||||
page_no)) {
|
|
||||||
ib_logf(IB_LOG_LEVEL_WARN,
|
|
||||||
"A page in the doublewrite buffer is not "
|
|
||||||
"within space bounds; space id %lu "
|
|
||||||
"page number %lu, page %lu in "
|
|
||||||
"doublewrite buf.",
|
|
||||||
(ulong) space_id, (ulong) page_no,
|
|
||||||
page_no_dblwr);
|
|
||||||
} else {
|
|
||||||
ulint zip_size = fil_space_get_zip_size(space_id);
|
|
||||||
|
|
||||||
/* Read in the actual page from the file */
|
|
||||||
fil_io(OS_FILE_READ,
|
|
||||||
true,
|
|
||||||
space_id,
|
|
||||||
zip_size,
|
|
||||||
page_no,
|
|
||||||
0,
|
|
||||||
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
|
||||||
read_buf,
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
|
|
||||||
/* Is page compressed ? */
|
|
||||||
is_compressed = fil_page_is_compressed_encrypted(read_buf) |
|
|
||||||
fil_page_is_compressed(read_buf);
|
|
||||||
|
|
||||||
/* If page was compressed, decompress it before we
|
|
||||||
check checksum. */
|
|
||||||
if (is_compressed) {
|
|
||||||
fil_decompress_page(NULL, read_buf, UNIV_PAGE_SIZE, NULL, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fil_space_verify_crypt_checksum(read_buf, zip_size)) {
|
|
||||||
/* page is encrypted and checksum is OK */
|
|
||||||
} else if (buf_page_is_corrupted(true, read_buf, zip_size)) {
|
|
||||||
|
|
||||||
fprintf(stderr,
|
|
||||||
"InnoDB: Warning: database page"
|
|
||||||
" corruption or a failed\n"
|
|
||||||
"InnoDB: file read of"
|
|
||||||
" space %lu page %lu.\n"
|
|
||||||
"InnoDB: Trying to recover it from"
|
|
||||||
" the doublewrite buffer.\n",
|
|
||||||
(ulong) space_id, (ulong) page_no);
|
|
||||||
|
|
||||||
/* Is page compressed ? */
|
|
||||||
is_compressed = fil_page_is_compressed_encrypted(page) |
|
|
||||||
fil_page_is_compressed(page);
|
|
||||||
|
|
||||||
/* If page was compressed, decompress it before we
|
|
||||||
check checksum. */
|
|
||||||
if (is_compressed) {
|
|
||||||
fil_decompress_page(NULL, page, UNIV_PAGE_SIZE, NULL, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fil_space_verify_crypt_checksum(page, zip_size)) {
|
|
||||||
/* the doublewrite buffer page is encrypted and OK */
|
|
||||||
} else if (buf_page_is_corrupted(true,
|
|
||||||
page,
|
|
||||||
zip_size)) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"InnoDB: Dump of the page:\n");
|
|
||||||
buf_page_print(
|
|
||||||
read_buf, zip_size,
|
|
||||||
BUF_PAGE_PRINT_NO_CRASH);
|
|
||||||
fprintf(stderr,
|
|
||||||
"InnoDB: Dump of"
|
|
||||||
" corresponding page"
|
|
||||||
" in doublewrite buffer:\n");
|
|
||||||
buf_page_print(
|
|
||||||
page, zip_size,
|
|
||||||
BUF_PAGE_PRINT_NO_CRASH);
|
|
||||||
|
|
||||||
fprintf(stderr,
|
|
||||||
"InnoDB: Also the page in the"
|
|
||||||
" doublewrite buffer"
|
|
||||||
" is corrupt.\n"
|
|
||||||
"InnoDB: Cannot continue"
|
|
||||||
" operation.\n"
|
|
||||||
"InnoDB: You can try to"
|
|
||||||
" recover the database"
|
|
||||||
" with the my.cnf\n"
|
|
||||||
"InnoDB: option:\n"
|
|
||||||
"InnoDB:"
|
|
||||||
" innodb_force_recovery=6\n");
|
|
||||||
ut_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write the good page from the
|
|
||||||
doublewrite buffer to the intended
|
|
||||||
position */
|
|
||||||
|
|
||||||
fil_io(OS_FILE_WRITE,
|
|
||||||
true,
|
|
||||||
space_id,
|
|
||||||
zip_size,
|
|
||||||
page_no,
|
|
||||||
0,
|
|
||||||
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
|
||||||
page,
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
|
|
||||||
ib_logf(IB_LOG_LEVEL_INFO,
|
|
||||||
"Recovered the page from"
|
|
||||||
" the doublewrite buffer.");
|
|
||||||
|
|
||||||
} else if (buf_page_is_zeroes(read_buf, zip_size)) {
|
|
||||||
|
|
||||||
if (!buf_page_is_zeroes(page, zip_size)
|
|
||||||
&& !buf_page_is_corrupted(true, page,
|
|
||||||
zip_size)) {
|
|
||||||
|
|
||||||
/* Database page contained only
|
|
||||||
zeroes, while a valid copy is
|
|
||||||
available in dblwr buffer. */
|
|
||||||
|
|
||||||
fil_io(OS_FILE_WRITE,
|
|
||||||
true,
|
|
||||||
space_id,
|
|
||||||
zip_size,
|
|
||||||
page_no,
|
|
||||||
0,
|
|
||||||
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
|
||||||
page,
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!fil_check_adress_in_tablespace(space_id, page_no)) {
|
||||||
|
ib_logf(IB_LOG_LEVEL_WARN,
|
||||||
|
"A copy of page " ULINTPF ":" ULINTPF
|
||||||
|
" in the doublewrite buffer slot " ULINTPF
|
||||||
|
" is not within space bounds",
|
||||||
|
space_id, page_no, page_no_dblwr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulint zip_size = fil_space_get_zip_size(space_id);
|
||||||
|
ut_ad(!buf_page_is_zeroes(page, zip_size));
|
||||||
|
|
||||||
|
/* Read in the actual page from the file */
|
||||||
|
fil_io(OS_FILE_READ,
|
||||||
|
true,
|
||||||
|
space_id,
|
||||||
|
zip_size,
|
||||||
|
page_no,
|
||||||
|
0,
|
||||||
|
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
||||||
|
read_buf,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
const bool is_all_zero = buf_page_is_zeroes(
|
||||||
|
read_buf, zip_size);
|
||||||
|
|
||||||
|
if (is_all_zero) {
|
||||||
|
/* We will check if the copy in the
|
||||||
|
doublewrite buffer is valid. If not, we will
|
||||||
|
ignore this page (there should be redo log
|
||||||
|
records to initialize it). */
|
||||||
|
} else {
|
||||||
|
if (fil_page_is_compressed_encrypted(read_buf) ||
|
||||||
|
fil_page_is_compressed(read_buf)) {
|
||||||
|
/* Decompress the page before
|
||||||
|
validating the checksum. */
|
||||||
|
fil_decompress_page(
|
||||||
|
NULL, read_buf, UNIV_PAGE_SIZE,
|
||||||
|
NULL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fil_space_verify_crypt_checksum(
|
||||||
|
read_buf, zip_size)
|
||||||
|
|| !buf_page_is_corrupted(
|
||||||
|
true, read_buf, zip_size)) {
|
||||||
|
/* The page is good; there is no need
|
||||||
|
to consult the doublewrite buffer. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We intentionally skip this message for
|
||||||
|
is_all_zero pages. */
|
||||||
|
ib_logf(IB_LOG_LEVEL_INFO,
|
||||||
|
"Trying to recover page " ULINTPF ":" ULINTPF
|
||||||
|
" from the doublewrite buffer.",
|
||||||
|
space_id, page_no);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next, validate the doublewrite page. */
|
||||||
|
if (fil_page_is_compressed_encrypted(page) ||
|
||||||
|
fil_page_is_compressed(page)) {
|
||||||
|
/* Decompress the page before
|
||||||
|
validating the checksum. */
|
||||||
|
fil_decompress_page(
|
||||||
|
NULL, page, UNIV_PAGE_SIZE, NULL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fil_space_verify_crypt_checksum(page, zip_size)
|
||||||
|
&& buf_page_is_corrupted(true, page, zip_size)) {
|
||||||
|
if (!is_all_zero) {
|
||||||
|
ib_logf(IB_LOG_LEVEL_WARN,
|
||||||
|
"A doublewrite copy of page "
|
||||||
|
ULINTPF ":" ULINTPF " is corrupted.",
|
||||||
|
space_id, page_no);
|
||||||
|
}
|
||||||
|
/* Theoretically we could have another good
|
||||||
|
copy for this page in the doublewrite
|
||||||
|
buffer. If not, we will report a fatal error
|
||||||
|
for a corrupted page somewhere else if that
|
||||||
|
page was truly needed. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the good page from the doublewrite buffer to
|
||||||
|
the intended position. */
|
||||||
|
|
||||||
|
fil_io(OS_FILE_WRITE, true, space_id, zip_size, page_no, 0,
|
||||||
|
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
||||||
|
page, NULL, 0);
|
||||||
|
|
||||||
|
ib_logf(IB_LOG_LEVEL_INFO,
|
||||||
|
"Recovered page " ULINTPF ":" ULINTPF " from"
|
||||||
|
" the doublewrite buffer.",
|
||||||
|
space_id, page_no);
|
||||||
}
|
}
|
||||||
|
|
||||||
ut_free(unaligned_read_buf);
|
ut_free(unaligned_read_buf);
|
||||||
|
@ -455,8 +455,11 @@ buf_dblwr_init_or_load_pages(
|
|||||||
os_file_write(path, file, page,
|
os_file_write(path, file, page,
|
||||||
source_page_no * UNIV_PAGE_SIZE,
|
source_page_no * UNIV_PAGE_SIZE,
|
||||||
UNIV_PAGE_SIZE);
|
UNIV_PAGE_SIZE);
|
||||||
} else if (load_corrupt_pages) {
|
} else if (load_corrupt_pages
|
||||||
|
&& !buf_page_is_zeroes(page, FIL_PAGE_DATA)) {
|
||||||
|
/* Each valid page header must contain some
|
||||||
|
nonzero bytes, such as FIL_PAGE_OFFSET
|
||||||
|
or FIL_PAGE_LSN. */
|
||||||
recv_dblwr.add(page);
|
recv_dblwr.add(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,8 +495,6 @@ buf_dblwr_process()
|
|||||||
|
|
||||||
for (std::list<byte*>::iterator i = recv_dblwr.pages.begin();
|
for (std::list<byte*>::iterator i = recv_dblwr.pages.begin();
|
||||||
i != recv_dblwr.pages.end(); ++i, ++page_no_dblwr ) {
|
i != recv_dblwr.pages.end(); ++i, ++page_no_dblwr ) {
|
||||||
bool is_compressed = false;
|
|
||||||
|
|
||||||
page = *i;
|
page = *i;
|
||||||
page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
|
page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
|
||||||
space_id = mach_read_from_4(page + FIL_PAGE_SPACE_ID);
|
space_id = mach_read_from_4(page + FIL_PAGE_SPACE_ID);
|
||||||
@ -501,138 +502,104 @@ buf_dblwr_process()
|
|||||||
if (!fil_tablespace_exists_in_mem(space_id)) {
|
if (!fil_tablespace_exists_in_mem(space_id)) {
|
||||||
/* Maybe we have dropped the single-table tablespace
|
/* Maybe we have dropped the single-table tablespace
|
||||||
and this page once belonged to it: do nothing */
|
and this page once belonged to it: do nothing */
|
||||||
|
continue;
|
||||||
} else if (!fil_check_adress_in_tablespace(space_id,
|
|
||||||
page_no)) {
|
|
||||||
ib_logf(IB_LOG_LEVEL_WARN,
|
|
||||||
"A page in the doublewrite buffer is not "
|
|
||||||
"within space bounds; space id %lu "
|
|
||||||
"page number %lu, page %lu in "
|
|
||||||
"doublewrite buf.",
|
|
||||||
(ulong) space_id, (ulong) page_no,
|
|
||||||
page_no_dblwr);
|
|
||||||
} else {
|
|
||||||
ulint zip_size = fil_space_get_zip_size(space_id);
|
|
||||||
|
|
||||||
/* Read in the actual page from the file */
|
|
||||||
fil_io(OS_FILE_READ,
|
|
||||||
true,
|
|
||||||
space_id,
|
|
||||||
zip_size,
|
|
||||||
page_no,
|
|
||||||
0,
|
|
||||||
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
|
||||||
read_buf,
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
|
|
||||||
/* Is page compressed ? */
|
|
||||||
is_compressed = fil_page_is_compressed_encrypted(read_buf) |
|
|
||||||
fil_page_is_compressed(read_buf);
|
|
||||||
|
|
||||||
/* If page was compressed, decompress it before we
|
|
||||||
check checksum. */
|
|
||||||
if (is_compressed) {
|
|
||||||
fil_decompress_page(NULL, read_buf, UNIV_PAGE_SIZE, NULL, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fil_space_verify_crypt_checksum(read_buf, zip_size)) {
|
|
||||||
/* page is encrypted and checksum is OK */
|
|
||||||
} else if (buf_page_is_corrupted(true, read_buf, zip_size)) {
|
|
||||||
|
|
||||||
fprintf(stderr,
|
|
||||||
"InnoDB: Database page"
|
|
||||||
" corruption or a failed\n"
|
|
||||||
"InnoDB: file read of"
|
|
||||||
" space %lu page %lu.\n"
|
|
||||||
"InnoDB: Trying to recover it from"
|
|
||||||
" the doublewrite buffer.\n",
|
|
||||||
(ulong) space_id, (ulong) page_no);
|
|
||||||
|
|
||||||
/* Is page compressed ? */
|
|
||||||
is_compressed = fil_page_is_compressed_encrypted(page) |
|
|
||||||
fil_page_is_compressed(page);
|
|
||||||
|
|
||||||
/* If page was compressed, decompress it before we
|
|
||||||
check checksum. */
|
|
||||||
if (is_compressed) {
|
|
||||||
fil_decompress_page(NULL, page, UNIV_PAGE_SIZE, NULL, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fil_space_verify_crypt_checksum(page, zip_size)) {
|
|
||||||
/* the doublewrite buffer page is encrypted and OK */
|
|
||||||
} else if (buf_page_is_corrupted(true,
|
|
||||||
page,
|
|
||||||
zip_size)) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"InnoDB: Dump of the page:\n");
|
|
||||||
buf_page_print(
|
|
||||||
read_buf, zip_size,
|
|
||||||
BUF_PAGE_PRINT_NO_CRASH);
|
|
||||||
fprintf(stderr,
|
|
||||||
"InnoDB: Dump of"
|
|
||||||
" corresponding page"
|
|
||||||
" in doublewrite buffer:\n");
|
|
||||||
buf_page_print(
|
|
||||||
page, zip_size,
|
|
||||||
BUF_PAGE_PRINT_NO_CRASH);
|
|
||||||
|
|
||||||
fprintf(stderr,
|
|
||||||
"InnoDB: Also the page in the"
|
|
||||||
" doublewrite buffer"
|
|
||||||
" is corrupt.\n"
|
|
||||||
"InnoDB: Cannot continue"
|
|
||||||
" operation.\n"
|
|
||||||
"InnoDB: You can try to"
|
|
||||||
" recover the database"
|
|
||||||
" with the my.cnf\n"
|
|
||||||
"InnoDB: option:\n"
|
|
||||||
"InnoDB:"
|
|
||||||
" innodb_force_recovery=6\n");
|
|
||||||
ut_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write the good page from the
|
|
||||||
doublewrite buffer to the intended
|
|
||||||
position */
|
|
||||||
|
|
||||||
fil_io(OS_FILE_WRITE,
|
|
||||||
true,
|
|
||||||
space_id,
|
|
||||||
zip_size,
|
|
||||||
page_no,
|
|
||||||
0,
|
|
||||||
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
|
||||||
page,
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
|
|
||||||
ib_logf(IB_LOG_LEVEL_INFO,
|
|
||||||
"Recovered the page from"
|
|
||||||
" the doublewrite buffer.");
|
|
||||||
|
|
||||||
} else if (buf_page_is_zeroes(read_buf, zip_size)) {
|
|
||||||
|
|
||||||
if (!buf_page_is_zeroes(page, zip_size)
|
|
||||||
&& !buf_page_is_corrupted(true, page,
|
|
||||||
zip_size)) {
|
|
||||||
|
|
||||||
/* Database page contained only
|
|
||||||
zeroes, while a valid copy is
|
|
||||||
available in dblwr buffer. */
|
|
||||||
|
|
||||||
fil_io(OS_FILE_WRITE,
|
|
||||||
true,
|
|
||||||
space_id,
|
|
||||||
zip_size,
|
|
||||||
page_no, 0,
|
|
||||||
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
|
||||||
page,
|
|
||||||
NULL,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!fil_check_adress_in_tablespace(space_id, page_no)) {
|
||||||
|
ib_logf(IB_LOG_LEVEL_WARN,
|
||||||
|
"A copy of page " ULINTPF ":" ULINTPF
|
||||||
|
" in the doublewrite buffer slot " ULINTPF
|
||||||
|
" is not within space bounds",
|
||||||
|
space_id, page_no, page_no_dblwr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulint zip_size = fil_space_get_zip_size(space_id);
|
||||||
|
ut_ad(!buf_page_is_zeroes(page, zip_size));
|
||||||
|
|
||||||
|
/* Read in the actual page from the file */
|
||||||
|
fil_io(OS_FILE_READ,
|
||||||
|
true,
|
||||||
|
space_id,
|
||||||
|
zip_size,
|
||||||
|
page_no,
|
||||||
|
0,
|
||||||
|
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
||||||
|
read_buf,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
const bool is_all_zero = buf_page_is_zeroes(
|
||||||
|
read_buf, zip_size);
|
||||||
|
|
||||||
|
if (is_all_zero) {
|
||||||
|
/* We will check if the copy in the
|
||||||
|
doublewrite buffer is valid. If not, we will
|
||||||
|
ignore this page (there should be redo log
|
||||||
|
records to initialize it). */
|
||||||
|
} else {
|
||||||
|
if (fil_page_is_compressed_encrypted(read_buf) ||
|
||||||
|
fil_page_is_compressed(read_buf)) {
|
||||||
|
/* Decompress the page before
|
||||||
|
validating the checksum. */
|
||||||
|
fil_decompress_page(
|
||||||
|
NULL, read_buf, UNIV_PAGE_SIZE,
|
||||||
|
NULL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fil_space_verify_crypt_checksum(
|
||||||
|
read_buf, zip_size)
|
||||||
|
|| !buf_page_is_corrupted(
|
||||||
|
true, read_buf, zip_size)) {
|
||||||
|
/* The page is good; there is no need
|
||||||
|
to consult the doublewrite buffer. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We intentionally skip this message for
|
||||||
|
is_all_zero pages. */
|
||||||
|
ib_logf(IB_LOG_LEVEL_INFO,
|
||||||
|
"Trying to recover page " ULINTPF ":" ULINTPF
|
||||||
|
" from the doublewrite buffer.",
|
||||||
|
space_id, page_no);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next, validate the doublewrite page. */
|
||||||
|
if (fil_page_is_compressed_encrypted(page) ||
|
||||||
|
fil_page_is_compressed(page)) {
|
||||||
|
/* Decompress the page before
|
||||||
|
validating the checksum. */
|
||||||
|
fil_decompress_page(
|
||||||
|
NULL, page, UNIV_PAGE_SIZE, NULL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fil_space_verify_crypt_checksum(page, zip_size)
|
||||||
|
&& buf_page_is_corrupted(true, page, zip_size)) {
|
||||||
|
if (!is_all_zero) {
|
||||||
|
ib_logf(IB_LOG_LEVEL_WARN,
|
||||||
|
"A doublewrite copy of page "
|
||||||
|
ULINTPF ":" ULINTPF " is corrupted.",
|
||||||
|
space_id, page_no);
|
||||||
|
}
|
||||||
|
/* Theoretically we could have another good
|
||||||
|
copy for this page in the doublewrite
|
||||||
|
buffer. If not, we will report a fatal error
|
||||||
|
for a corrupted page somewhere else if that
|
||||||
|
page was truly needed. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the good page from the doublewrite buffer to
|
||||||
|
the intended position. */
|
||||||
|
|
||||||
|
fil_io(OS_FILE_WRITE, true, space_id, zip_size, page_no, 0,
|
||||||
|
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
||||||
|
page, NULL, 0);
|
||||||
|
|
||||||
|
ib_logf(IB_LOG_LEVEL_INFO,
|
||||||
|
"Recovered page " ULINTPF ":" ULINTPF " from"
|
||||||
|
" the doublewrite buffer.",
|
||||||
|
space_id, page_no);
|
||||||
}
|
}
|
||||||
|
|
||||||
ut_free(unaligned_read_buf);
|
ut_free(unaligned_read_buf);
|
||||||
|
Reference in New Issue
Block a user