MDEV-30657 InnoDB: Not applying UNDO_APPEND due to corruption

This almost completely reverts
commit acd23da4c2 and
retains a safe optimization:

recv_sys_t::parse(): Remove any old redo log records for the
truncated tablespace, to free up memory earlier.
If recovery consists of multiple batches, then recv_sys_t::apply()
will must invoke recv_sys_t::trim() again to avoid wrongly
applying old log records to an already truncated undo tablespace.
This commit is contained in:
Marko Mäkelä 2023-02-15 18:16:41 +02:00
commit 5300c0fb76
2 changed files with 21 additions and 7 deletions

View file

@ -266,9 +266,15 @@ private:
@param lsn log sequence number of the shrink operation */
inline void trim(const page_id_t page_id, lsn_t lsn);
/** Truncated undo tablespace size for which truncate has been logged
(indexed by page_id_t::space() - srv_undo_space_id_start), or 0 */
unsigned truncated_undo_spaces[127];
/** Undo tablespaces for which truncate has been logged
(indexed by page_id_t::space() - srv_undo_space_id_start) */
struct trunc
{
/** log sequence number of FILE_CREATE, or 0 if none */
lsn_t lsn;
/** truncated size of the tablespace, or 0 if not truncated */
unsigned pages;
} truncated_undo_spaces[127];
public:
/** The contents of the doublewrite buffer */

View file

@ -1952,7 +1952,8 @@ same_page:
/* The entire undo tablespace will be reinitialized by
innodb_undo_log_truncate=ON. Discard old log for all pages. */
trim({space_id, 0}, recovered_lsn);
truncated_undo_spaces[space_id - srv_undo_space_id_start]= page_no;
truncated_undo_spaces[space_id - srv_undo_space_id_start]=
{ recovered_lsn, page_no };
if (undo_space_trunc)
undo_space_trunc(space_id);
#endif
@ -2677,15 +2678,22 @@ void recv_sys_t::apply(bool last_batch)
for (auto id= srv_undo_tablespaces_open; id--;)
{
if (unsigned pages= truncated_undo_spaces[id])
const trunc& t= truncated_undo_spaces[id];
if (t.lsn)
{
if (fil_space_t *space= fil_space_get(id + srv_undo_space_id_start))
/* The entire undo tablespace will be reinitialized by
innodb_undo_log_truncate=ON. Discard old log for all pages.
Even though we recv_sys_t::parse() already invoked trim(),
this will be needed in case recovery consists of multiple batches
(there was an invocation with !last_batch). */
trim({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{pages} << srv_page_size_shift, true);
os_offset_t{t.pages} << srv_page_size_shift, true);
}
}
}