Commit 993b8edf authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-26933 InnoDB fails to detect page number mismatch

mtr_t::page_lock(): Validate the page number.

ibuf_tree_root_get(): Remove assertions that became redundant.

The assertions in btr_validate_level() are kind of redundant as well,
but because they are ut_a(), they are also present in release builds,
while the ones in mtr_t::page_lock() are only present in debug builds.

btr_cur_position(): Do not duplicate an assertion that is part of
page_cur_position().

dict_load_tablespace(): Introduce a new option
DICT_ERR_IGNORE_TABLESPACE that will suppress loading a tablespace
when a table is going to be dropped.
parent fdc4c3a2
...@@ -11,7 +11,7 @@ InnoDB 0 transactions not purged ...@@ -11,7 +11,7 @@ InnoDB 0 transactions not purged
connection default; connection default;
# Cleanly shutdown mysqld # Cleanly shutdown mysqld
disconnect con1; disconnect con1;
# Corrupt FIL_PAGE_OFFSET in bug16720368.ibd, # Corrupt FIL_PAGE_TYPE in bug16720368.ibd,
# and recompute innodb_checksum_algorithm=crc32 # and recompute innodb_checksum_algorithm=crc32
# restart # restart
SELECT COUNT(*) FROM bug16720368; SELECT COUNT(*) FROM bug16720368;
......
...@@ -43,7 +43,7 @@ connection default; ...@@ -43,7 +43,7 @@ connection default;
disconnect con1; disconnect con1;
-- echo # Corrupt FIL_PAGE_OFFSET in bug16720368.ibd, -- echo # Corrupt FIL_PAGE_TYPE in bug16720368.ibd,
-- echo # and recompute innodb_checksum_algorithm=crc32 -- echo # and recompute innodb_checksum_algorithm=crc32
perl; perl;
do "$ENV{MTR_SUITE_DIR}/include/crc32.pl"; do "$ENV{MTR_SUITE_DIR}/include/crc32.pl";
...@@ -56,7 +56,7 @@ die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps; ...@@ -56,7 +56,7 @@ die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
my $full_crc32 = unpack("N",substr($page,54,4)) & 0x10; # FIL_SPACE_FLAGS my $full_crc32 = unpack("N",substr($page,54,4)) & 0x10; # FIL_SPACE_FLAGS
sysseek(FILE, 3*$ps, 0) || die "Unable to seek $file\n"; sysseek(FILE, 3*$ps, 0) || die "Unable to seek $file\n";
die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps; die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
substr($page,4,4)=pack("N",0xc001cafe); substr($page,24,2)='42';
my $polynomial = 0x82f63b78; # CRC-32C my $polynomial = 0x82f63b78; # CRC-32C
if ($full_crc32) if ($full_crc32)
{ {
...@@ -86,7 +86,7 @@ INSERT INTO bug16720368_1 VALUES(1); ...@@ -86,7 +86,7 @@ INSERT INTO bug16720368_1 VALUES(1);
-- echo # Shut down the server to uncorrupt the data. -- echo # Shut down the server to uncorrupt the data.
-- source include/shutdown_mysqld.inc -- source include/shutdown_mysqld.inc
# Uncorrupt the FIL_PAGE_OFFSET. # Uncorrupt the FIL_PAGE_TYPE.
perl; perl;
do "$ENV{MTR_SUITE_DIR}/include/crc32.pl"; do "$ENV{MTR_SUITE_DIR}/include/crc32.pl";
my $file = "$ENV{MYSQLD_DATADIR}/test/bug16720368.ibd"; my $file = "$ENV{MYSQLD_DATADIR}/test/bug16720368.ibd";
...@@ -98,7 +98,7 @@ die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps; ...@@ -98,7 +98,7 @@ die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
my $full_crc32 = unpack("N",substr($page,54,4)) & 0x10; # FIL_SPACE_FLAGS my $full_crc32 = unpack("N",substr($page,54,4)) & 0x10; # FIL_SPACE_FLAGS
sysseek(FILE, 3*$ps, 0) || die "Unable to seek $file\n"; sysseek(FILE, 3*$ps, 0) || die "Unable to seek $file\n";
die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps; die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
substr($page,4,4)=pack("N",3); substr($page,24,2)=pack("H*","45BF");
my $polynomial = 0x82f63b78; # CRC-32C my $polynomial = 0x82f63b78; # CRC-32C
if ($full_crc32) if ($full_crc32)
{ {
......
...@@ -57,7 +57,14 @@ my $body = pack("x[8]Nx[10]Nx[16312]", 768, 97937874); ...@@ -57,7 +57,14 @@ my $body = pack("x[8]Nx[10]Nx[16312]", 768, 97937874);
my $ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial); my $ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial);
print OUT pack("N",$ck).$head.pack("x[12]").$body.pack("Nx[4]",$ck); print OUT pack("N",$ck).$head.pack("x[12]").$body.pack("Nx[4]",$ck);
# Dummy pages 1..6. # Dummy pages 1..6.
print OUT chr(0) x (6 * 16384); $body = pack("x[16338]");
for (my($page) = 1; $page < 7; $page++)
{
## FIL_PAGE_OFFSET
$head = pack("Nx[18]", $page);
$ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial);
print OUT pack("N",$ck).$head.pack("x[16350]Nx[4]",$ck);
}
# Dictionary header page (page 7). # Dictionary header page (page 7).
## FIL_PAGE_OFFSET ## FIL_PAGE_OFFSET
$head = pack("Nx[18]", 7); $head = pack("Nx[18]", 7);
......
...@@ -61,5 +61,9 @@ let SEARCH_PATTERN=page id mismatch; ...@@ -61,5 +61,9 @@ let SEARCH_PATTERN=page id mismatch;
--source include/search_pattern_in_file.inc --source include/search_pattern_in_file.inc
--remove_file $resultlog --remove_file $resultlog
# prevent purge from crashing on page ID mismatch
let $restart_parameters=--innodb-force-recovery=2;
--source include/start_mysqld.inc --source include/start_mysqld.inc
drop table t1; drop table t1;
let $restart_parameters=;
--source include/restart_mysqld.inc
...@@ -654,7 +654,7 @@ dict_build_index_def_step( ...@@ -654,7 +654,7 @@ dict_build_index_def_step(
index = node->index; index = node->index;
table = dict_table_open_on_name( table = dict_table_open_on_name(
node->table_name, true, DICT_ERR_IGNORE_DROP); node->table_name, true, DICT_ERR_IGNORE_TABLESPACE);
if (!table) { if (!table) {
return DB_TABLE_NOT_FOUND; return DB_TABLE_NOT_FOUND;
......
...@@ -2225,7 +2225,7 @@ dict_load_tablespace( ...@@ -2225,7 +2225,7 @@ dict_load_tablespace(
return; return;
} }
if (ignore_err == DICT_ERR_IGNORE_DROP) { if (ignore_err >= DICT_ERR_IGNORE_TABLESPACE) {
table->file_unreadable = true; table->file_unreadable = true;
return; return;
} }
...@@ -2412,6 +2412,11 @@ static dict_table_t *dict_load_table_one(const span<const char> &name, ...@@ -2412,6 +2412,11 @@ static dict_table_t *dict_load_table_one(const span<const char> &name,
table->corrupted = true; table->corrupted = true;
table->file_unreadable = true; table->file_unreadable = true;
err = DB_CORRUPTION; err = DB_CORRUPTION;
} else if (table->space->id
&& ignore_err == DICT_ERR_IGNORE_DROP) {
/* Do not bother to load data from .ibd files
only to delete the .ibd files. */
goto corrupted;
} else { } else {
const page_id_t page_id(table->space->id, root); const page_id_t page_id(table->space->id, root);
mtr.start(); mtr.start();
......
...@@ -1373,7 +1373,7 @@ fts_cache_add_doc( ...@@ -1373,7 +1373,7 @@ fts_cache_add_doc(
static dberr_t fts_drop_table(trx_t *trx, const char *table_name, bool rename) static dberr_t fts_drop_table(trx_t *trx, const char *table_name, bool rename)
{ {
if (dict_table_t *table= dict_table_open_on_name(table_name, true, if (dict_table_t *table= dict_table_open_on_name(table_name, true,
DICT_ERR_IGNORE_DROP)) DICT_ERR_IGNORE_TABLESPACE))
{ {
table->release(); table->release();
if (rename) if (rename)
...@@ -1505,7 +1505,7 @@ static dberr_t fts_lock_table(trx_t *trx, const char *table_name) ...@@ -1505,7 +1505,7 @@ static dberr_t fts_lock_table(trx_t *trx, const char *table_name)
ut_ad(purge_sys.must_wait_FTS()); ut_ad(purge_sys.must_wait_FTS());
if (dict_table_t *table= dict_table_open_on_name(table_name, false, if (dict_table_t *table= dict_table_open_on_name(table_name, false,
DICT_ERR_IGNORE_DROP)) DICT_ERR_IGNORE_TABLESPACE))
{ {
dberr_t err= lock_table_for_trx(table, trx, LOCK_X); dberr_t err= lock_table_for_trx(table, trx, LOCK_X);
/* Wait for purge threads to stop using the table. */ /* Wait for purge threads to stop using the table. */
......
...@@ -341,8 +341,6 @@ static buf_block_t *ibuf_tree_root_get(mtr_t *mtr) ...@@ -341,8 +341,6 @@ static buf_block_t *ibuf_tree_root_get(mtr_t *mtr)
page_id_t(IBUF_SPACE_ID, FSP_IBUF_TREE_ROOT_PAGE_NO), page_id_t(IBUF_SPACE_ID, FSP_IBUF_TREE_ROOT_PAGE_NO),
0, RW_SX_LATCH, mtr); 0, RW_SX_LATCH, mtr);
ut_ad(page_get_space_id(block->frame) == IBUF_SPACE_ID);
ut_ad(page_get_page_no(block->frame) == FSP_IBUF_TREE_ROOT_PAGE_NO);
ut_ad(ibuf.empty == page_is_empty(block->frame)); ut_ad(ibuf.empty == page_is_empty(block->frame));
return block; return block;
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2018, 2020, MariaDB Corporation. Copyright (c) 2018, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -109,10 +109,7 @@ btr_cur_position( ...@@ -109,10 +109,7 @@ btr_cur_position(
buf_block_t* block, /*!< in: buffer block of rec */ buf_block_t* block, /*!< in: buffer block of rec */
btr_cur_t* cursor) /*!< out: cursor */ btr_cur_t* cursor) /*!< out: cursor */
{ {
ut_ad(page_align(rec) == block->frame);
page_cur_position(rec, block, btr_cur_get_page_cur(cursor)); page_cur_position(rec, block, btr_cur_get_page_cur(cursor));
cursor->index = index; cursor->index = index;
} }
......
...@@ -82,8 +82,12 @@ enum dict_err_ignore_t { ...@@ -82,8 +82,12 @@ enum dict_err_ignore_t {
incomplete index definitions. */ incomplete index definitions. */
/** ignore all errors above */ /** ignore all errors above */
DICT_ERR_IGNORE_ALL = 15, DICT_ERR_IGNORE_ALL = 15,
/** prepare to drop the table; do not attempt to load tablespace */ /** prepare some DDL operation;
DICT_ERR_IGNORE_DROP = 31 do not attempt to load tablespace */
DICT_ERR_IGNORE_TABLESPACE = 31,
/** prepare to drop the table; do not attempt to load tablespace
or the metadata */
DICT_ERR_IGNORE_DROP = 63
}; };
/** Quiescing states for flushing tables to disk. */ /** Quiescing states for flushing tables to disk. */
......
...@@ -1196,6 +1196,8 @@ void mtr_t::page_lock(buf_block_t *block, ulint rw_latch) ...@@ -1196,6 +1196,8 @@ void mtr_t::page_lock(buf_block_t *block, ulint rw_latch)
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
done: done:
ut_ad(page_id_t(page_get_space_id(block->frame),
page_get_page_no(block->frame)) == block->page.id());
memo_push(block, fix_type); memo_push(block, fix_type);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment