summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThirunarayanan Balathandayuthapani <thiru@mariadb.com>2018-04-23 11:22:58 +0530
committerThirunarayanan Balathandayuthapani <thiru@mariadb.com>2018-04-23 11:22:58 +0530
commit211842dd86f28f4610bc87ea221730c82c0e2494 (patch)
treef09276f9b81a5d63db11697e13f595253ce1f56a
parent469a4b02ceb39ff405077414d9220f0a5ffbb360 (diff)
downloadmariadb-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.cc15
-rw-r--r--storage/innobase/trx/trx0rec.cc19
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. */