MDEV-29999 innodb_undo_log_truncate=ON is not crash safe

If a log checkpoint occurs at the end LSN of mtr.commit_shrink(space)
in trx_purge_truncate_history(), then recovery may fail because
it could try to apply too old log records to too old copies of
undo log pages. This was repeated with the following test:

./mtr innodb.undo_log_truncate,4k,strict_full_crc32

recv_sys_t::trim(): Move some code to the caller.

recv_sys_t::apply(): For undo tablespace truncation, discard
all old redo log for the undo tablespace, and then truncate
the file to the desired size.

Tested by: Matthias Leich
This commit is contained in:
Marko Mäkelä 2022-11-15 16:56:13 +02:00
commit 0b25551a61

View file

@ -745,14 +745,6 @@ inline void recv_sys_t::trim(const page_id_t page_id, lsn_t lsn)
pages.erase(r);
}
}
if (fil_space_t* space = fil_space_get(page_id.space())) {
ut_ad(UT_LIST_GET_LEN(space->chain) == 1);
fil_node_t* file = UT_LIST_GET_FIRST(space->chain);
ut_ad(file->is_open());
os_file_truncate(file->name, file->handle,
os_offset_t{page_id.page_no()}
<< srv_page_size_shift, true);
}
DBUG_VOID_RETURN;
}
@ -2694,7 +2686,17 @@ void recv_sys_t::apply(bool last_batch)
{
const trunc& t= truncated_undo_spaces[id];
if (t.lsn)
trim(page_id_t(id + srv_undo_space_id_start, t.pages), t.lsn);
{
trim(page_id_t(id + srv_undo_space_id_start, 0), t.lsn);
if (fil_space_t *space = fil_space_get(id + srv_undo_space_id_start))
{
ut_ad(UT_LIST_GET_LEN(space->chain) == 1);
fil_node_t *file= UT_LIST_GET_FIRST(space->chain);
ut_ad(file->is_open());
os_file_truncate(file->name, file->handle,
os_offset_t{t.pages} << srv_page_size_shift, true);
}
}
}
fil_system.extend_to_recv_size();