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
connection default;
# Cleanly shutdown mysqld
disconnect con1;
# Corrupt FIL_PAGE_OFFSET in bug16720368.ibd,
# Corrupt FIL_PAGE_TYPE in bug16720368.ibd,
# and recompute innodb_checksum_algorithm=crc32
# restart
SELECT COUNT(*) FROM bug16720368;
......
......@@ -43,7 +43,7 @@ connection default;
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
perl;
do "$ENV{MTR_SUITE_DIR}/include/crc32.pl";
......@@ -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
sysseek(FILE, 3*$ps, 0) || die "Unable to seek $file\n";
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
if ($full_crc32)
{
......@@ -86,7 +86,7 @@ INSERT INTO bug16720368_1 VALUES(1);
-- echo # Shut down the server to uncorrupt the data.
-- source include/shutdown_mysqld.inc
# Uncorrupt the FIL_PAGE_OFFSET.
# Uncorrupt the FIL_PAGE_TYPE.
perl;
do "$ENV{MTR_SUITE_DIR}/include/crc32.pl";
my $file = "$ENV{MYSQLD_DATADIR}/test/bug16720368.ibd";
......@@ -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
sysseek(FILE, 3*$ps, 0) || die "Unable to seek $file\n";
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
if ($full_crc32)
{
......
......@@ -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);
print OUT pack("N",$ck).$head.pack("x[12]").$body.pack("Nx[4]",$ck);
# 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).
## FIL_PAGE_OFFSET
$head = pack("Nx[18]", 7);
......
......@@ -61,5 +61,9 @@ let SEARCH_PATTERN=page id mismatch;
--source include/search_pattern_in_file.inc
--remove_file $resultlog
# prevent purge from crashing on page ID mismatch
let $restart_parameters=--innodb-force-recovery=2;
--source include/start_mysqld.inc
drop table t1;
let $restart_parameters=;
--source include/restart_mysqld.inc
......@@ -654,7 +654,7 @@ dict_build_index_def_step(
index = node->index;
table = dict_table_open_on_name(
node->table_name, true, DICT_ERR_IGNORE_DROP);
node->table_name, true, DICT_ERR_IGNORE_TABLESPACE);
if (!table) {
return DB_TABLE_NOT_FOUND;
......
......@@ -2225,7 +2225,7 @@ dict_load_tablespace(
return;
}
if (ignore_err == DICT_ERR_IGNORE_DROP) {
if (ignore_err >= DICT_ERR_IGNORE_TABLESPACE) {
table->file_unreadable = true;
return;
}
......@@ -2412,6 +2412,11 @@ static dict_table_t *dict_load_table_one(const span<const char> &name,
table->corrupted = true;
table->file_unreadable = true;
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 {
const page_id_t page_id(table->space->id, root);
mtr.start();
......
......@@ -1373,7 +1373,7 @@ fts_cache_add_doc(
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,
DICT_ERR_IGNORE_DROP))
DICT_ERR_IGNORE_TABLESPACE))
{
table->release();
if (rename)
......@@ -1505,7 +1505,7 @@ static dberr_t fts_lock_table(trx_t *trx, const char *table_name)
ut_ad(purge_sys.must_wait_FTS());
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);
/* Wait for purge threads to stop using the table. */
......
......@@ -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),
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));
return block;
......
/*****************************************************************************
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
the terms of the GNU General Public License as published by the Free Software
......@@ -109,10 +109,7 @@ btr_cur_position(
buf_block_t* block, /*!< in: buffer block of rec */
btr_cur_t* cursor) /*!< out: cursor */
{
ut_ad(page_align(rec) == block->frame);
page_cur_position(rec, block, btr_cur_get_page_cur(cursor));
cursor->index = index;
}
......
......@@ -82,8 +82,12 @@ enum dict_err_ignore_t {
incomplete index definitions. */
/** ignore all errors above */
DICT_ERR_IGNORE_ALL = 15,
/** prepare to drop the table; do not attempt to load tablespace */
DICT_ERR_IGNORE_DROP = 31
/** prepare some DDL operation;
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. */
......
......@@ -1196,6 +1196,8 @@ void mtr_t::page_lock(buf_block_t *block, ulint rw_latch)
#endif /* BTR_CUR_HASH_ADAPT */
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);
}
......
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