Skip to content

Commit 4dcd2d8

Browse files
Thirunarayanandr-m
authored andcommitted
MDEV-37412 Corrupted page during recovery aborts the server
Problem: ======= When InnoDB encounters a corrupted page during crash recovery, server would abort due to improper handling of page locks and space references. The recovery process was not properly cleaning up resources when corruption was detected, leading to inconsistent state and server termination. Solution: ========= recover_low(): Move page lock recursive acquisition after deferred/non-deferred page creation logic to ensure consistent locking behavior for both code paths. Ensure proper block recursive unlock for non-deferred tablespaces recv_recover_page(): Simplify corrupted page cleanup by removing redundant space reference handling.
1 parent c40402e commit 4dcd2d8

File tree

3 files changed

+34
-11
lines changed

3 files changed

+34
-11
lines changed

mysql-test/suite/innodb/r/leaf_page_corrupted_during_recovery.result

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ INSERT INTO t1 VALUES(1, 'sql'), (2, 'server'), (3, 'mariadb'),
44
(4, 'mariadb'), (5, 'test1'), (6, 'test2'), (7, 'test3'),
55
(8, 'test4'), (9, 'test5'), (10, 'test6'), (11, 'test7'),
66
(12, 'test8');
7+
call mtr.add_suppression("InnoDB: Cannot apply log to \\[page id: space=[1-9], page number=0\\] of corrupted file '.*mdev_37412\\.ibd'");
8+
SET GLOBAL innodb_log_checkpoint_now=ON;
9+
CREATE TABLE mdev_37412(id INT AUTO_INCREMENT, PRIMARY KEY(id))
10+
STATS_PERSISTENT=0 ENGINE=InnoDB;
11+
# Kill the server
12+
# restart: --debug_dbug=+d,recv_corrupt
13+
SELECT * FROM mdev_37412;
14+
id
15+
DROP TABLE mdev_37412;
716
SELECT COUNT(*) FROM t1;
817
COUNT(*)
918
12

mysql-test/suite/innodb/t/leaf_page_corrupted_during_recovery.test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,23 @@ INSERT INTO t1 VALUES(1, 'sql'), (2, 'server'), (3, 'mariadb'),
2121
(8, 'test4'), (9, 'test5'), (10, 'test6'), (11, 'test7'),
2222
(12, 'test8');
2323

24+
call mtr.add_suppression("InnoDB: Cannot apply log to \\[page id: space=[1-9], page number=0\\] of corrupted file '.*mdev_37412\\.ibd'");
25+
SET GLOBAL innodb_log_checkpoint_now=ON;
26+
--source ../include/no_checkpoint_start.inc
27+
CREATE TABLE mdev_37412(id INT AUTO_INCREMENT, PRIMARY KEY(id))
28+
STATS_PERSISTENT=0 ENGINE=InnoDB;
29+
--let CLEANUP_IF_CHECKPOINT=DROP TABLE t1,mdev_37412;
30+
--source ../include/no_checkpoint_end.inc
31+
32+
--let $restart_parameters=--debug_dbug=+d,recv_corrupt
33+
--source include/start_mysqld.inc
34+
let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err;
35+
let SEARCH_PATTERN= InnoDB: Cannot apply log to \\[page id: space=[1-9], page number=0\\] of corrupted file '.*mdev_37412\\.ibd';
36+
--let $restart_parameters=
2437
let $restart_noprint=2;
2538
--source include/restart_mysqld.inc
39+
SELECT * FROM mdev_37412;
40+
DROP TABLE mdev_37412;
2641

2742
let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
2843
let MYSQLD_DATADIR=`select @@datadir`;

storage/innobase/log/log0recv.cc

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3041,6 +3041,10 @@ static buf_block_t *recv_recover_page(buf_block_t *block, mtr_t &mtr,
30413041
block->page.id().page_no()));
30423042

30433043
log_phys_t::apply_status a= l->apply(*block, recs.last_offset);
3044+
DBUG_EXECUTE_IF("recv_corrupt",
3045+
if (init && init->created &&
3046+
(!space || space->id != 0))
3047+
a= log_phys_t::APPLIED_CORRUPTED;);
30443048

30453049
switch (a) {
30463050
case log_phys_t::APPLIED_NO:
@@ -3112,17 +3116,9 @@ static buf_block_t *recv_recover_page(buf_block_t *block, mtr_t &mtr,
31123116
mtr.discard_modifications();
31133117
mtr.commit();
31143118

3115-
fil_space_t* s = space
3116-
? space
3117-
: fil_space_t::get(block->page.id().space());
3118-
31193119
buf_pool.corrupted_evict(&block->page,
31203120
block->page.state() &
31213121
buf_page_t::LRU_MASK);
3122-
if (!space) {
3123-
s->release();
3124-
}
3125-
31263122
return nullptr;
31273123
}
31283124

@@ -3524,7 +3520,6 @@ inline buf_block_t *recv_sys_t::recover_low(const map::iterator &p, mtr_t &mtr,
35243520
DBUG_LOG("ib_log", "skip log for page " << p->first
35253521
<< " LSN " << end_lsn << " < " << init.lsn);
35263522
fil_space_t *space= fil_space_t::get(p->first.space());
3527-
35283523
mtr.start();
35293524
mtr.set_log_mode(MTR_LOG_NO_REDO);
35303525

@@ -3544,7 +3539,6 @@ inline buf_block_t *recv_sys_t::recover_low(const map::iterator &p, mtr_t &mtr,
35443539
zip_size= fil_space_t::zip_size(flags);
35453540
block= buf_page_create_deferred(p->first.space(), zip_size, &mtr, b);
35463541
ut_ad(block == b);
3547-
block->page.lock.x_lock_recursive();
35483542
}
35493543
else
35503544
{
@@ -3563,6 +3557,8 @@ inline buf_block_t *recv_sys_t::recover_low(const map::iterator &p, mtr_t &mtr,
35633557
}
35643558
}
35653559

3560+
/* Released in buf_pool_t::corrupted_evict(), recover_deferred() or below */
3561+
block->page.lock.x_lock_recursive();
35663562
ut_d(mysql_mutex_lock(&mutex));
35673563
ut_ad(&recs == &pages.find(p->first)->second);
35683564
ut_d(mysql_mutex_unlock(&mutex));
@@ -3571,8 +3567,11 @@ inline buf_block_t *recv_sys_t::recover_low(const map::iterator &p, mtr_t &mtr,
35713567
ut_ad(mtr.has_committed());
35723568

35733569
if (space)
3570+
{
35743571
space->release();
3575-
3572+
if (block)
3573+
block->page.lock.x_unlock();
3574+
}
35763575
return block ? block : reinterpret_cast<buf_block_t*>(-1);
35773576
}
35783577

0 commit comments

Comments
 (0)