MDEV-35174 Possible hang in trx_undo_prev_version()

In commit b7b9f3ce82 (MDEV-34515) we
accidentally made the InnoDB MVCC code acquire a shared
purge_sys.latch twice. Recursive shared latch acquisition may cause a
deadlock of InnoDB threads if another thread in between will start waiting
for an exclusive latch.

purge_sys_t::latch: In debug builds, use srw_lock_debug instead of
srw_spin_lock, so that bugs like this will result in debug assertion
failures.

trx_undo_report_row_operation(): Pass the view_guard to
trx_undo_prev_version() and the rest of the arguments in the same
order, so that the work to permute argument registers is minimized.
This commit is contained in:
Marko Mäkelä 2024-10-16 14:37:44 +03:00
commit a4d2cc931d
2 changed files with 13 additions and 7 deletions

View file

@ -125,7 +125,8 @@ class purge_sys_t
public:
/** latch protecting view, m_enabled */
alignas(CPU_LEVEL1_DCACHE_LINESIZE) mutable srw_spin_lock latch;
alignas(CPU_LEVEL1_DCACHE_LINESIZE)
mutable IF_DBUG(srw_lock_debug,srw_spin_lock) latch;
private:
/** Read view at the start of a purge batch. Any encountered index records
that are older than view will be removed. */

View file

@ -2040,8 +2040,10 @@ err_exit:
static dberr_t trx_undo_prev_version(const rec_t *rec, dict_index_t *index,
rec_offs *offsets, mem_heap_t *heap,
rec_t **old_vers, mem_heap_t *v_heap,
dtuple_t **vrow, ulint v_status,
rec_t **old_vers,
const purge_sys_t::view_guard &check,
ulint v_status,
mem_heap_t *v_heap, dtuple_t **vrow,
const trx_undo_rec_t *undo_rec);
inline const buf_block_t *
@ -2142,7 +2144,8 @@ dberr_t trx_undo_prev_version_build(const rec_t *rec, dict_index_t *index,
if (UNIV_UNLIKELY(end > offset &&
end < srv_page_size - FIL_PAGE_DATA_END))
err= trx_undo_prev_version(rec, index, offsets, heap,
old_vers, v_heap, vrow, v_status, undo_rec);
old_vers, check, v_status, v_heap, vrow,
undo_rec);
}
}
@ -2152,8 +2155,10 @@ dberr_t trx_undo_prev_version_build(const rec_t *rec, dict_index_t *index,
static dberr_t trx_undo_prev_version(const rec_t *rec, dict_index_t *index,
rec_offs *offsets, mem_heap_t *heap,
rec_t **old_vers, mem_heap_t *v_heap,
dtuple_t **vrow, ulint v_status,
rec_t **old_vers,
const purge_sys_t::view_guard &check,
ulint v_status,
mem_heap_t *v_heap, dtuple_t **vrow,
const trx_undo_rec_t *undo_rec)
{
byte type, cmpl_info;
@ -2223,7 +2228,7 @@ static dberr_t trx_undo_prev_version(const rec_t *rec, dict_index_t *index,
the BLOB. */
if (update->info_bits & REC_INFO_DELETED_FLAG
&& purge_sys.is_purgeable(trx_id)) {
&& check.view().changes_visible(trx_id)) {
return DB_SUCCESS;
}