mirror of
https://github.com/MariaDB/server.git
synced 2026-05-16 20:07:13 +02:00
MDEV-15374 Server hangs and aborts with long semaphore wait or assertion `len < ((ulint) srv_page_size)' fails in trx_undo_rec_copy upon ROLLBACK on temporary table
Problem: ======= InnoDB cleans all temporary undo logs during commit. During rollback of secondary index entry, InnoDB tries to build the previous version of clustered index. It leads to access of freed undo page during previous transaction commit and it leads to undo log corruption. Solution: ========= During rollback, temporary undo logs should not try to build the previous version of the record.
This commit is contained in:
parent
469a4b02ce
commit
211842dd86
2 changed files with 16 additions and 18 deletions
|
|
@ -428,7 +428,7 @@ row_undo_mod_del_mark_or_remove_sec_low(
|
|||
btr_pcur_t pcur;
|
||||
btr_cur_t* btr_cur;
|
||||
ibool success;
|
||||
ibool old_has;
|
||||
ibool old_has = FALSE;
|
||||
dberr_t err = DB_SUCCESS;
|
||||
mtr_t mtr;
|
||||
mtr_t mtr_vers;
|
||||
|
|
@ -504,10 +504,15 @@ row_undo_mod_del_mark_or_remove_sec_low(
|
|||
&mtr_vers);
|
||||
ut_a(success);
|
||||
|
||||
old_has = row_vers_old_has_index_entry(FALSE,
|
||||
btr_pcur_get_rec(&(node->pcur)),
|
||||
&mtr_vers, index, entry,
|
||||
0, 0);
|
||||
/* For temporary table, we can skip to check older version of
|
||||
clustered index entry. Because the purge won't process
|
||||
any no-redo rollback segment undo logs. */
|
||||
if (!dict_table_is_temporary(node->table)) {
|
||||
old_has = row_vers_old_has_index_entry(
|
||||
FALSE, btr_pcur_get_rec(&(node->pcur)),
|
||||
&mtr_vers, index, entry, 0, 0);
|
||||
}
|
||||
|
||||
if (old_has) {
|
||||
err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG,
|
||||
btr_cur, TRUE, thr, &mtr);
|
||||
|
|
|
|||
|
|
@ -2087,13 +2087,11 @@ err_exit:
|
|||
|
||||
/** Copy an undo record to heap.
|
||||
@param[in] roll_ptr roll pointer to a record that exists
|
||||
@param[in] is_temp whether this is a temporary table
|
||||
@param[in,out] heap memory heap where copied */
|
||||
static
|
||||
trx_undo_rec_t*
|
||||
trx_undo_get_undo_rec_low(
|
||||
roll_ptr_t roll_ptr,
|
||||
bool is_temp,
|
||||
mem_heap_t* heap)
|
||||
{
|
||||
trx_undo_rec_t* undo_rec;
|
||||
|
|
@ -2109,10 +2107,7 @@ trx_undo_get_undo_rec_low(
|
|||
&offset);
|
||||
ut_ad(page_no > FSP_FIRST_INODE_PAGE_NO);
|
||||
ut_ad(offset >= TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
|
||||
rseg = is_temp
|
||||
? trx_sys->temp_rsegs[rseg_id]
|
||||
: trx_sys->rseg_array[rseg_id];
|
||||
ut_ad(is_temp == !rseg->is_persistent());
|
||||
rseg = trx_sys->rseg_array[rseg_id];
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
|
|
@ -2128,7 +2123,6 @@ trx_undo_get_undo_rec_low(
|
|||
|
||||
/** Copy an undo record to heap.
|
||||
@param[in] roll_ptr roll pointer to record
|
||||
@param[in] is_temp whether this is a temporary table
|
||||
@param[in,out] heap memory heap where copied
|
||||
@param[in] trx_id id of the trx that generated
|
||||
the roll pointer: it points to an
|
||||
|
|
@ -2143,7 +2137,6 @@ static MY_ATTRIBUTE((warn_unused_result))
|
|||
bool
|
||||
trx_undo_get_undo_rec(
|
||||
roll_ptr_t roll_ptr,
|
||||
bool is_temp,
|
||||
mem_heap_t* heap,
|
||||
trx_id_t trx_id,
|
||||
const table_name_t& name,
|
||||
|
|
@ -2155,7 +2148,7 @@ trx_undo_get_undo_rec(
|
|||
|
||||
missing_history = purge_sys->view.changes_visible(trx_id, name);
|
||||
if (!missing_history) {
|
||||
*undo_rec = trx_undo_get_undo_rec_low(roll_ptr, is_temp, heap);
|
||||
*undo_rec = trx_undo_get_undo_rec_low(roll_ptr, heap);
|
||||
}
|
||||
|
||||
rw_lock_s_unlock(&purge_sys->latch);
|
||||
|
|
@ -2236,19 +2229,19 @@ trx_undo_prev_version_build(
|
|||
return(true);
|
||||
}
|
||||
|
||||
const bool is_temp = dict_table_is_temporary(index->table);
|
||||
ut_ad(!dict_table_is_temporary(index->table));
|
||||
|
||||
rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
|
||||
|
||||
ut_ad(!index->table->skip_alter_undo);
|
||||
|
||||
if (trx_undo_get_undo_rec(
|
||||
roll_ptr, is_temp, heap, rec_trx_id, index->table->name,
|
||||
roll_ptr, heap, rec_trx_id, index->table->name,
|
||||
&undo_rec)) {
|
||||
if (v_status & TRX_UNDO_PREV_IN_PURGE) {
|
||||
/* We are fetching the record being purged */
|
||||
ut_ad(!is_temp);
|
||||
undo_rec = trx_undo_get_undo_rec_low(
|
||||
roll_ptr, is_temp, heap);
|
||||
roll_ptr, heap);
|
||||
} else {
|
||||
/* The undo record may already have been purged,
|
||||
during purge or semi-consistent read. */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue