diff --git a/innobase/include/row0vers.h b/innobase/include/row0vers.h index 0dd40fda65f..079d841f7f3 100644 --- a/innobase/include/row0vers.h +++ b/innobase/include/row0vers.h @@ -79,7 +79,11 @@ row_vers_build_for_consistent_read( mtr_t* mtr, /* in: mtr holding the latch on rec; it will also hold the latch on purge_view */ dict_index_t* index, /* in: the clustered index */ + ulint** offsets,/* in/out: offsets returned by + rec_get_offsets(rec, index) */ read_view_t* view, /* in: the consistent read view */ + mem_heap_t** offset_heap,/* in/out: memory heap from which + the offsets are allocated */ mem_heap_t* in_heap,/* in: memory heap from which the memory for old_vers is allocated; memory for possible intermediate versions is allocated and freed diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index e478376e67b..3a169ba5384 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -510,6 +510,10 @@ row_sel_build_prev_vers( read_view_t* read_view, /* in: read view */ plan_t* plan, /* in: plan node for table */ rec_t* rec, /* in: record in a clustered index */ + ulint** offsets, /* in/out: offsets returned by + rec_get_offsets(rec, plan->index) */ + mem_heap_t** offset_heap, /* in/out: memory heap from which + the offsets are allocated */ rec_t** old_vers, /* out: old version, or NULL if the record does not exist in the view: i.e., it was freshly inserted @@ -525,8 +529,8 @@ row_sel_build_prev_vers( } err = row_vers_build_for_consistent_read(rec, mtr, plan->index, - read_view, plan->old_vers_heap, - old_vers); + offsets, read_view, offset_heap, + plan->old_vers_heap, old_vers); return(err); } @@ -697,7 +701,8 @@ row_sel_get_clust_rec( node->read_view)) { err = row_sel_build_prev_vers(node->read_view, plan, - clust_rec, &old_vers, mtr); + clust_rec, &offsets, &heap, + &old_vers, mtr); if (err != DB_SUCCESS) { goto err_exit; @@ -1396,14 +1401,18 @@ rec_loop: node->read_view)) { err = row_sel_build_prev_vers(node->read_view, - plan, rec, &old_vers, - &mtr); + plan, rec, + &offsets, &heap, + &old_vers, &mtr); if (err != DB_SUCCESS) { goto lock_wait_or_error; } if (old_vers == NULL) { + offsets = rec_get_offsets( + rec, index, offsets, + ULINT_UNDEFINED, &heap); row_sel_fetch_columns(index, rec, offsets, UT_LIST_GET_FIRST(plan->columns)); @@ -1417,8 +1426,6 @@ rec_loop: } rec = old_vers; - offsets = rec_get_offsets(rec, index, offsets, - ULINT_UNDEFINED, &heap); } } else if (!lock_sec_rec_cons_read_sees(rec, index, node->read_view)) { @@ -2535,6 +2542,10 @@ row_sel_build_prev_vers_for_mysql( dict_index_t* clust_index, /* in: clustered index */ row_prebuilt_t* prebuilt, /* in: prebuilt struct */ rec_t* rec, /* in: record in a clustered index */ + ulint** offsets, /* in/out: offsets returned by + rec_get_offsets(rec, clust_index) */ + mem_heap_t** offset_heap, /* in/out: memory heap from which + the offsets are allocated */ rec_t** old_vers, /* out: old version, or NULL if the record does not exist in the view: i.e., it was freshly inserted @@ -2550,8 +2561,8 @@ row_sel_build_prev_vers_for_mysql( } err = row_vers_build_for_consistent_read(rec, mtr, clust_index, - read_view, prebuilt->old_vers_heap, - old_vers); + offsets, read_view, offset_heap, + prebuilt->old_vers_heap, old_vers); return(err); } @@ -2575,6 +2586,10 @@ row_sel_get_clust_rec_for_mysql( it, NULL if the old version did not exist in the read view, i.e., it was a fresh inserted version */ + ulint** offsets,/* out: offsets returned by + rec_get_offsets(out_rec, clust_index) */ + mem_heap_t** offset_heap,/* in/out: memory heap from which + the offsets are allocated */ mtr_t* mtr) /* in: mtr used to get access to the non-clustered record; the same mtr is used to access the clustered index */ @@ -2584,9 +2599,6 @@ row_sel_get_clust_rec_for_mysql( rec_t* old_vers; ulint err; trx_t* trx; - mem_heap_t* heap = NULL; - ulint offsets_[100] = { 100, }; - ulint* offsets = offsets_; *out_rec = NULL; trx = thr_get_trx(thr); @@ -2642,8 +2654,8 @@ row_sel_get_clust_rec_for_mysql( goto func_exit; } - offsets = rec_get_offsets(clust_rec, clust_index, offsets, - ULINT_UNDEFINED, &heap); + *offsets = rec_get_offsets(clust_rec, clust_index, *offsets, + ULINT_UNDEFINED, offset_heap); if (prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a lock on the index record; we are searching @@ -2651,7 +2663,7 @@ row_sel_get_clust_rec_for_mysql( we set a LOCK_REC_NOT_GAP type lock */ err = lock_clust_rec_read_check_and_lock(0, clust_rec, - clust_index, offsets, + clust_index, *offsets, prebuilt->select_lock_type, LOCK_REC_NOT_GAP, thr); if (err != DB_SUCCESS) { @@ -2669,11 +2681,12 @@ row_sel_get_clust_rec_for_mysql( if (trx->isolation_level > TRX_ISO_READ_UNCOMMITTED && !lock_clust_rec_cons_read_sees(clust_rec, clust_index, - offsets, trx->read_view)) { + *offsets, trx->read_view)) { err = row_sel_build_prev_vers_for_mysql( trx->read_view, clust_index, prebuilt, clust_rec, + offsets, offset_heap, &old_vers, mtr); if (err != DB_SUCCESS) { @@ -2722,9 +2735,6 @@ func_exit: err = DB_SUCCESS; err_exit: - if (heap) { - mem_heap_free(heap); - } return(err); } @@ -3671,6 +3681,7 @@ rec_loop: err = row_sel_build_prev_vers_for_mysql( trx->read_view, clust_index, prebuilt, rec, + &offsets, &heap, &old_vers, &mtr); if (err != DB_SUCCESS) { @@ -3723,7 +3734,8 @@ rec_loop: mtr_has_extra_clust_latch = TRUE; err = row_sel_get_clust_rec_for_mysql(prebuilt, index, rec, - thr, &clust_rec, &mtr); + thr, &clust_rec, + &offsets, &heap, &mtr); if (err != DB_SUCCESS) { goto lock_wait_or_error; @@ -3745,20 +3757,18 @@ rec_loop: if (prebuilt->need_to_access_clustered) { rec = clust_rec; + ut_ad(rec_offs_validate(rec, clust_index, offsets)); + } else { + offsets = rec_get_offsets(rec, index, offsets, + ULINT_UNDEFINED, &heap); } } - if (prebuilt->need_to_access_clustered) { - ut_ad(rec == clust_rec || index == clust_index); - offsets = rec_get_offsets(rec, clust_index, offsets, - ULINT_UNDEFINED, &heap); - } else { - offsets = rec_get_offsets(rec, index, offsets, - ULINT_UNDEFINED, &heap); - } - /* We found a qualifying row */ - + ut_ad(rec_offs_validate(rec, + rec == clust_rec ? clust_index : index, + offsets)); + if (prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD && prebuilt->select_lock_type == LOCK_NONE && !prebuilt->templ_contains_blob @@ -3800,8 +3810,11 @@ rec_loop: } if (prebuilt->clust_index_was_generated) { - offsets = rec_get_offsets(index_rec, index, offsets, + if (rec != index_rec) { + offsets = rec_get_offsets( + index_rec, index, offsets, ULINT_UNDEFINED, &heap); + } row_sel_store_row_id_to_prebuilt(prebuilt, index_rec, index, offsets); } diff --git a/innobase/row/row0vers.c b/innobase/row/row0vers.c index 9ccaf32f2c2..36f6c27636d 100644 --- a/innobase/row/row0vers.c +++ b/innobase/row/row0vers.c @@ -406,7 +406,11 @@ row_vers_build_for_consistent_read( of this records */ mtr_t* mtr, /* in: mtr holding the latch on rec */ dict_index_t* index, /* in: the clustered index */ + ulint** offsets,/* in/out: offsets returned by + rec_get_offsets(rec, index) */ read_view_t* view, /* in: the consistent read view */ + mem_heap_t** offset_heap,/* in/out: memory heap from which + the offsets are allocated */ mem_heap_t* in_heap,/* in: memory heap from which the memory for old_vers is allocated; memory for possible intermediate versions is allocated and freed @@ -418,11 +422,9 @@ row_vers_build_for_consistent_read( rec_t* version; rec_t* prev_version; dulint prev_trx_id; - mem_heap_t* heap; - mem_heap_t* heap2; + mem_heap_t* heap = NULL; byte* buf; ulint err; - ulint* offsets; ut_ad(index->type & DICT_CLUSTERED); ut_ad(mtr_memo_contains(mtr, buf_block_align(rec), MTR_MEMO_PAGE_X_FIX) @@ -432,22 +434,23 @@ row_vers_build_for_consistent_read( ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); #endif /* UNIV_SYNC_DEBUG */ - heap = mem_heap_create(1024); - offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap); + ut_ad(rec_offs_validate(rec, index, *offsets)); ut_ad(!read_view_sees_trx_id(view, - row_get_rec_trx_id(rec, index, offsets))); + row_get_rec_trx_id(rec, index, *offsets))); rw_lock_s_lock(&(purge_sys->latch)); version = rec; for (;;) { - heap2 = heap; + mem_heap_t* heap2 = heap; heap = mem_heap_create(1024); err = trx_undo_prev_version_build(rec, mtr, version, index, - offsets, heap, &prev_version); - mem_heap_free(heap2); /* free version and offsets */ + *offsets, heap, &prev_version); + if (heap2) { + mem_heap_free(heap2); /* free version */ + } if (err != DB_SUCCESS) { break; @@ -461,17 +464,19 @@ row_vers_build_for_consistent_read( break; } - offsets = rec_get_offsets(prev_version, index, NULL, - ULINT_UNDEFINED, &heap); - prev_trx_id = row_get_rec_trx_id(prev_version, index, offsets); + *offsets = rec_get_offsets(prev_version, index, *offsets, + ULINT_UNDEFINED, offset_heap); + prev_trx_id = row_get_rec_trx_id(prev_version, index, + *offsets); if (read_view_sees_trx_id(view, prev_trx_id)) { /* The view already sees this version: we can copy it to in_heap and return */ - buf = mem_heap_alloc(in_heap, rec_offs_size(offsets)); - *old_vers = rec_copy(buf, prev_version, offsets); + buf = mem_heap_alloc(in_heap, rec_offs_size(*offsets)); + *old_vers = rec_copy(buf, prev_version, *offsets); + rec_offs_make_valid(*old_vers, index, *offsets); err = DB_SUCCESS; break;