Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
[8.0] rec_get_offsets optimize: avoid redundant dict_table_is_comp() …
…in hot path

Add rec_get_offsets_with_comp() which accepts a pre-computed compact flag,
avoiding repeated dict_table_is_comp(index->table) calls inside the function
on every invocation. Apply the optimization in:
- page_copy_rec_list_end_to_created_page (page0cur.cc): cache compact once
  before the record copy loop.
- row_search_mvcc (row0sel.cc): reuse the existing comp variable at 6 call
  sites in the hot scan path.

Ported from boostdb-patches/0001-rec_get_offsets-optimize.patch
(originally targeting Percona Server 5.7.44-53). Adapted for 8.0:
- ibool -> bool
- file/line -> ut::Location
- mem_heap_create_at -> mem_heap_create(size, location)
- rec_get_n_fields_old(rec) -> rec_get_n_fields_old(rec, index)
- Implementation moved to rem/rec.h and rem/rec.cc
- The locks_ok hunk is not applicable (semi-consistent read path restructured)

Signed-off-by: wjunLu <wjunlu217@gmail.com>
  • Loading branch information
wjunLu committed May 7, 2026
commit a27d19c43684adfbc5051f128c4c2392ae170692
7 changes: 5 additions & 2 deletions storage/innobase/page/page0cur.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -2134,8 +2136,9 @@ 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)) {
Expand Down
54 changes: 54 additions & 0 deletions storage/innobase/rem/rec.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<ulint *>(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(
Expand Down
21 changes: 21 additions & 0 deletions storage/innobase/rem/rec.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,27 @@ 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(
Expand Down
36 changes: 20 additions & 16 deletions storage/innobase/row/row0sel.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -4906,8 +4908,9 @@ 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);
Expand Down Expand Up @@ -4998,8 +5001,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))) {
Expand Down Expand Up @@ -5628,8 +5631,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;
}

Expand Down Expand Up @@ -5782,13 +5786,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,
Expand Down