diff options
author | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2018-04-23 11:22:58 +0530 |
---|---|---|
committer | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2018-04-23 11:22:58 +0530 |
commit | 211842dd86f28f4610bc87ea221730c82c0e2494 (patch) | |
tree | f09276f9b81a5d63db11697e13f595253ce1f56a | |
parent | 469a4b02ceb39ff405077414d9220f0a5ffbb360 (diff) | |
download | mariadb-git-211842dd86f28f4610bc87ea221730c82c0e2494.tar.gz |
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.
-rw-r--r-- | storage/innobase/row/row0umod.cc | 15 | ||||
-rw-r--r-- | storage/innobase/trx/trx0rec.cc | 19 |
2 files changed, 16 insertions, 18 deletions
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index 76ad0815119..b30194f3562 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -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); diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 358bd458912..1851f30339b 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -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. */ |