diff --git a/storage/innobase/page/page0cur.cc b/storage/innobase/page/page0cur.cc index fdb630c230c0..5c1393c1dabe 100644 --- a/storage/innobase/page/page0cur.cc +++ b/storage/innobase/page/page0cur.cc @@ -2091,6 +2091,8 @@ void page_copy_rec_list_end_to_created_page( ut_ad(page_align(rec) != new_page); ut_ad(page_rec_is_comp(rec) == page_is_comp(new_page)); + const bool compact = dict_table_is_comp(index->table); + if (page_rec_is_infimum(rec)) { rec = page_rec_get_next(rec); } @@ -2134,8 +2136,8 @@ void page_copy_rec_list_end_to_created_page( n_recs = 0; do { - offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, - UT_LOCATION_HERE, &heap); + offsets = rec_get_offsets_with_comp( + rec, index, compact, offsets, ULINT_UNDEFINED, UT_LOCATION_HERE, &heap); insert_rec = rec_copy(heap_top, rec, offsets); if (page_is_comp(new_page)) { diff --git a/storage/innobase/rem/rec.cc b/storage/innobase/rem/rec.cc index 6f6973fb7b0b..75ce3c1e6f30 100644 --- a/storage/innobase/rem/rec.cc +++ b/storage/innobase/rem/rec.cc @@ -400,6 +400,60 @@ ulint *rec_get_offsets(const rec_t *rec, const dict_index_t *index, return (offsets); } +ulint *rec_get_offsets_with_comp(const rec_t *rec, const dict_index_t *index, + bool compact, ulint *offsets, ulint n_fields, + ut::Location location, mem_heap_t **heap) { + ulint n; + + ut_ad(rec); + ut_ad(index); + ut_ad(heap); + + if (compact) { + switch (UNIV_EXPECT(rec_get_status(rec), REC_STATUS_ORDINARY)) { + case REC_STATUS_ORDINARY: + n = dict_index_get_n_fields(index); + break; + case REC_STATUS_NODE_PTR: + /* Node pointer records consist of the uniquely identifying fields of + the record followed by a child page number field. */ + n = dict_index_get_n_unique_in_tree_nonleaf(index) + 1; + break; + case REC_STATUS_INFIMUM: + case REC_STATUS_SUPREMUM: + /* infimum or supremum record */ + n = 1; + break; + default: + ut_error; + } + } else { + n = rec_get_n_fields_old(rec, index); + } + + if (UNIV_UNLIKELY(n_fields < n)) { + n = n_fields; + } + + /* The offsets header consists of the allocation size at + offsets[0] and the REC_OFFS_HEADER_SIZE bytes. */ + ulint size = n + (1 + REC_OFFS_HEADER_SIZE); + + if (UNIV_UNLIKELY(!offsets) || + UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) { + if (UNIV_UNLIKELY(!*heap)) { + *heap = mem_heap_create(size * sizeof(ulint), location); + } + offsets = static_cast(mem_heap_alloc(*heap, size * sizeof(ulint))); + + rec_offs_set_n_alloc(offsets, size); + } + + rec_offs_set_n_fields(offsets, n); + rec_init_offsets(rec, index, offsets); + return (offsets); +} + /** The following function determines the offsets to each field in the record. It can reuse a previously allocated array. */ void rec_get_offsets_reverse( diff --git a/storage/innobase/rem/rec.h b/storage/innobase/rem/rec.h index 3a6f43628b2f..7754dc68b236 100644 --- a/storage/innobase/rem/rec.h +++ b/storage/innobase/rem/rec.h @@ -232,6 +232,24 @@ static const uint8_t REC_N_FIELDS_ONE_BYTE_MAX = 0x7F; ulint n_fields, ut::Location location, mem_heap_t **heap); +/** The following function determines the offsets to each field + in the record. It can reuse a previously allocated array. + This variant accepts a pre-computed compact flag to avoid redundant + dict_table_is_comp() calls in hot paths. + @param[in] rec physical record + @param[in] index record descriptor + @param[in] compact pre-computed dict_table_is_comp(index->table) + @param[in,out] offsets array consisting of offsets[0] allocated elements, or an + array from rec_get_offsets(), or NULL + @param[in] n_fields maximum number of initialized fields (ULINT_UNDEFINED is + all fields) + @param[in] location location where called + @param[in,out] heap memory heap + @return the new offsets */ +[[nodiscard]] ulint *rec_get_offsets_with_comp( + const rec_t *rec, const dict_index_t *index, bool compact, ulint *offsets, + ulint n_fields, ut::Location location, mem_heap_t **heap); + /** The following function determines the offsets to each field in the record. It can reuse a previously allocated array. */ void rec_get_offsets_reverse( diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 5cc13784c2e7..27dd3a77621f 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -4788,8 +4788,9 @@ dberr_t row_search_mvcc(byte *buf, page_cur_mode_t mode, to prevent phantoms in ORDER BY ... DESC queries */ const rec_t *next_rec = page_rec_get_next_const(rec); - offsets = rec_get_offsets(next_rec, index, offsets, ULINT_UNDEFINED, - UT_LOCATION_HERE, &heap); + offsets = + rec_get_offsets_with_comp(next_rec, index, comp, offsets, + ULINT_UNDEFINED, UT_LOCATION_HERE, &heap); err = sel_set_rec_lock(pcur, next_rec, index, offsets, prebuilt->select_mode, prebuilt->select_lock_type, LOCK_GAP, thr, &mtr); @@ -4877,8 +4878,9 @@ dberr_t row_search_mvcc(byte *buf, page_cur_mode_t mode, } /** Create offsets based on prebuilt index. */ - offsets = rec_get_offsets(prev_rec, prebuilt->index, offsets, - ULINT_UNDEFINED, UT_LOCATION_HERE, &heap); + offsets = + rec_get_offsets_with_comp(prev_rec, prebuilt->index, comp, offsets, + ULINT_UNDEFINED, UT_LOCATION_HERE, &heap); if (row_sel_store_mysql_rec(end_range_cache, prebuilt, prev_rec, prev_vrow, clust_templ_for_sec, key_index, @@ -4906,8 +4908,8 @@ dberr_t row_search_mvcc(byte *buf, page_cur_mode_t mode, !dict_index_is_spatial(index)) { /* Try to place a lock on the index record */ - offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, - UT_LOCATION_HERE, &heap); + offsets = rec_get_offsets_with_comp( + rec, index, comp, offsets, ULINT_UNDEFINED, UT_LOCATION_HERE, &heap); err = sel_set_rec_lock(pcur, rec, index, offsets, prebuilt->select_mode, prebuilt->select_lock_type, LOCK_ORDINARY, thr, &mtr); @@ -4998,8 +5000,8 @@ dberr_t row_search_mvcc(byte *buf, page_cur_mode_t mode, ut_ad(fil_page_index_page_check(pcur->get_page())); ut_ad(btr_page_get_index_id(pcur->get_page()) == index->id); - offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, - UT_LOCATION_HERE, &heap); + offsets = rec_get_offsets_with_comp(rec, index, comp, offsets, + ULINT_UNDEFINED, UT_LOCATION_HERE, &heap); if (UNIV_UNLIKELY(srv_force_recovery > 0 || (index->table->is_corrupt && srv_pass_corrupt_table == 2))) { @@ -5628,8 +5630,9 @@ dberr_t row_search_mvcc(byte *buf, page_cur_mode_t mode, if (result_rec != rec && !prebuilt->need_to_access_clustered) { /* We used 'offsets' for the clust rec, recalculate them for 'rec' */ - offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, - UT_LOCATION_HERE, &heap); + offsets = + rec_get_offsets_with_comp(rec, index, comp, offsets, + ULINT_UNDEFINED, UT_LOCATION_HERE, &heap); result_rec = rec; } @@ -5782,13 +5785,13 @@ dberr_t row_search_mvcc(byte *buf, page_cur_mode_t mode, auto heap_tmp = mem_heap_create(256, UT_LOCATION_HERE); - offsets1 = rec_get_offsets(prev_rec_debug, index, nullptr, - prev_rec_debug_n_fields, UT_LOCATION_HERE, - &heap_tmp); + offsets1 = rec_get_offsets_with_comp(prev_rec_debug, index, comp, + nullptr, prev_rec_debug_n_fields, + UT_LOCATION_HERE, &heap_tmp); - offsets2 = - rec_get_offsets(prev_rec, index, nullptr, prev_rec_debug_n_fields, - UT_LOCATION_HERE, &heap_tmp); + offsets2 = rec_get_offsets_with_comp(prev_rec, index, comp, nullptr, + prev_rec_debug_n_fields, + UT_LOCATION_HERE, &heap_tmp); ut_ad(!cmp_rec_rec(prev_rec_debug, prev_rec, offsets1, offsets2, index, page_is_spatial_non_leaf(prev_rec, index), nullptr,