Skip to content

Commit c6e58a8

Browse files
committed
MDEV-30753 fixup: Unsafe buffer page restoration
trx_purge_free_segment(): The buffer-fix only prevents a block from being freed completely from the buffer pool, but it will not prevent the block from being evicted. Recheck the page identifier after acquiring an exclusive page latch. If it has changed, backtrack and invoke buf_page_get_gen() to look up the page normally.
1 parent 210db29 commit c6e58a8

File tree

1 file changed

+13
-2
lines changed

1 file changed

+13
-2
lines changed

storage/innobase/trx/trx0purge.cc

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,19 +367,30 @@ void trx_purge_free_segment(mtr_t &mtr, trx_rseg_t* rseg, fil_addr_t hdr_addr)
367367
block->frame, &mtr))
368368
{
369369
block->fix();
370+
const page_id_t id{block->page.id()};
370371
mtr.commit();
371372
/* NOTE: If the server is killed after the log that was produced
372373
up to this point was written, and before the log from the mtr.commit()
373374
in our caller is written, then the pages belonging to the
374375
undo log will become unaccessible garbage.
375376
376-
This does not matters when using multiple innodb_undo_tablespaces;
377+
This does not matter when using multiple innodb_undo_tablespaces;
377378
innodb_undo_log_truncate=ON will be able to reclaim the space. */
378379
log_free_check();
379380
mtr.start();
380381
ut_ad(rw_lock_s_lock_nowait(block->debug_latch, __FILE__, __LINE__));
381382
rw_lock_x_lock(&block->lock);
382-
mtr_memo_push(&mtr, block, MTR_MEMO_PAGE_X_FIX);
383+
if (UNIV_UNLIKELY(block->page.id() != id))
384+
{
385+
block->unfix();
386+
rw_lock_x_unlock(&block->lock);
387+
ut_d(rw_lock_s_unlock(block->debug_latch));
388+
block= buf_page_get(id, 0, RW_X_LATCH, &mtr);
389+
if (!block)
390+
return;
391+
}
392+
else
393+
mtr_memo_push(&mtr, block, MTR_MEMO_PAGE_X_FIX);
383394
}
384395

385396
while (!fseg_free_step(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER +

0 commit comments

Comments
 (0)