Commit b1646d04 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-30567 rec_get_offsets() is not optimal

rec_init_offsets_comp_ordinary(), rec_init_offsets(),
rec_get_offsets_reverse(), rec_get_nth_field_offs_old():
Simplify some bitwise arithmetics to avoid conditional jumps,
and add branch prediction hints with the assumption that most
variable-length columns are short.

Tested by: Matthias Leich
parent 948fb3c2
...@@ -217,8 +217,7 @@ rec_get_n_extern_new( ...@@ -217,8 +217,7 @@ rec_get_n_extern_new(
stored in one byte for 0..127. The length stored in one byte for 0..127. The length
will be encoded in two bytes when it is 128 or will be encoded in two bytes when it is 128 or
more, or when the field is stored externally. */ more, or when the field is stored externally. */
if (DATA_BIG_COL(col)) { if (UNIV_UNLIKELY(len & 0x80) && DATA_BIG_COL(col)) {
if (len & 0x80) {
/* 1exxxxxxx xxxxxxxx */ /* 1exxxxxxx xxxxxxxx */
if (len & 0x40) { if (len & 0x40) {
n_extern++; n_extern++;
...@@ -226,7 +225,6 @@ rec_get_n_extern_new( ...@@ -226,7 +225,6 @@ rec_get_n_extern_new(
lens--; lens--;
} }
} }
}
} while (++i < n); } while (++i < n);
return(n_extern); return(n_extern);
...@@ -244,6 +242,10 @@ enum rec_leaf_format { ...@@ -244,6 +242,10 @@ enum rec_leaf_format {
REC_LEAF_INSTANT REC_LEAF_INSTANT
}; };
#if defined __GNUC__ && !defined __clang__ && __GNUC__ < 11
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wconversion" /* GCC 5 to 10 need this */
#endif
/** Determine the offset to each field in a leaf-page record /** Determine the offset to each field in a leaf-page record
in ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED. in ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED.
This is a special case of rec_init_offsets() and rec_get_offsets_func(). This is a special case of rec_init_offsets() and rec_get_offsets_func().
...@@ -361,8 +363,7 @@ rec_init_offsets_comp_ordinary( ...@@ -361,8 +363,7 @@ rec_init_offsets_comp_ordinary(
do { do {
if (mblob) { if (mblob) {
if (i == index->first_user_field()) { if (i == index->first_user_field()) {
offs = static_cast<rec_offs>(offs offs += FIELD_REF_SIZE;
+ FIELD_REF_SIZE);
len = combine(offs, STORED_OFFPAGE); len = combine(offs, STORED_OFFPAGE);
any |= REC_OFFS_EXTERNAL; any |= REC_OFFS_EXTERNAL;
field--; field--;
...@@ -433,27 +434,23 @@ rec_init_offsets_comp_ordinary( ...@@ -433,27 +434,23 @@ rec_init_offsets_comp_ordinary(
stored in one byte for 0..127. The length stored in one byte for 0..127. The length
will be encoded in two bytes when it is 128 or will be encoded in two bytes when it is 128 or
more, or when the field is stored externally. */ more, or when the field is stored externally. */
if ((len & 0x80) && DATA_BIG_COL(col)) { if (UNIV_UNLIKELY(len & 0x80) && DATA_BIG_COL(col)) {
/* 1exxxxxxx xxxxxxxx */ /* 1exxxxxxx xxxxxxxx */
len = static_cast<rec_offs>(len << 8 len <<= 8;
| *lens--); len |= *lens--;
offs = static_cast<rec_offs>(offs static_assert(STORED_OFFPAGE == 0x4000, "");
+ get_value(len)); static_assert(REC_OFFS_EXTERNAL == 0x4000, "");
if (UNIV_UNLIKELY(len & 0x4000)) { const rec_offs ext = len & REC_OFFS_EXTERNAL;
ut_ad(index->is_primary()); offs += get_value(len);
any |= REC_OFFS_EXTERNAL; len = offs | ext;
len = combine(offs, STORED_OFFPAGE); any |= ext;
} else { ut_ad(!ext || index->is_primary());
len = offs;
}
continue; continue;
} }
len = offs = static_cast<rec_offs>(offs + len); len = offs += len;
} else { } else {
len = offs = static_cast<rec_offs>(offs len = offs += field->fixed_len;
+ field->fixed_len);
} }
} while (field++, rec_offs_base(offsets)[++i] = len, } while (field++, rec_offs_base(offsets)[++i] = len,
i < rec_offs_n_fields(offsets)); i < rec_offs_n_fields(offsets));
...@@ -478,7 +475,7 @@ rec_offs_make_valid( ...@@ -478,7 +475,7 @@ rec_offs_make_valid(
{ {
const bool is_alter_metadata = leaf const bool is_alter_metadata = leaf
&& rec_is_alter_metadata(rec, *index); && rec_is_alter_metadata(rec, *index);
ut_ad(is_alter_metadata ut_ad((leaf && rec_is_metadata(rec, *index))
|| index->is_dummy || index->is_ibuf() || index->is_dummy || index->is_ibuf()
|| (leaf || (leaf
? rec_offs_n_fields(offsets) ? rec_offs_n_fields(offsets)
...@@ -572,7 +569,8 @@ rec_offs_validate( ...@@ -572,7 +569,8 @@ rec_offs_validate(
} }
/* index->n_def == 0 for dummy indexes if !comp */ /* index->n_def == 0 for dummy indexes if !comp */
ut_ad(!comp || index->n_def); ut_ad(!comp || index->n_def);
ut_ad(!index->n_def || i <= max_n_fields); ut_ad(!index->n_def || i <= max_n_fields
|| rec_is_metadata(rec, *index));
} }
while (i--) { while (i--) {
ulint curr = get_value(rec_offs_base(offsets)[1 + i]); ulint curr = get_value(rec_offs_base(offsets)[1 + i]);
...@@ -610,7 +608,7 @@ rec_init_offsets( ...@@ -610,7 +608,7 @@ rec_init_offsets(
ulint i = 0; ulint i = 0;
rec_offs offs; rec_offs offs;
/* This assertion was relaxed for the btr_cur_open_at_index_side() /* This assertion was relaxed for the btr_cur_t::open_leaf()
call in btr_cur_instant_init_low(). We cannot invoke call in btr_cur_instant_init_low(). We cannot invoke
index->is_instant(), because the same assertion would fail there index->is_instant(), because the same assertion would fail there
until btr_cur_instant_init_low() has invoked until btr_cur_instant_init_low() has invoked
...@@ -678,8 +676,7 @@ rec_init_offsets( ...@@ -678,8 +676,7 @@ rec_init_offsets(
do { do {
rec_offs len; rec_offs len;
if (UNIV_UNLIKELY(i == n_node_ptr_field)) { if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
len = offs = static_cast<rec_offs>( len = offs += REC_NODE_PTR_SIZE;
offs + REC_NODE_PTR_SIZE);
goto resolved; goto resolved;
} }
...@@ -719,29 +716,25 @@ rec_init_offsets( ...@@ -719,29 +716,25 @@ rec_init_offsets(
encoded in two bytes when it is 128 or encoded in two bytes when it is 128 or
more, or when the field is stored more, or when the field is stored
externally. */ externally. */
if (DATA_BIG_COL(col)) { if (UNIV_UNLIKELY(len & 0x80)
if (len & 0x80) { && DATA_BIG_COL(col)) {
/* 1exxxxxxx xxxxxxxx */ /* 1exxxxxxx xxxxxxxx */
len = static_cast<rec_offs>( len <<= 8;
len << 8 | *lens--); len |= *lens--;
/* B-tree node pointers /* B-tree node pointers
must not contain externally must not contain externally
stored columns. Thus stored columns. Thus
the "e" flag must be 0. */ the "e" flag must be 0. */
ut_a(!(len & 0x4000)); ut_a(!(len & 0x4000));
offs = static_cast<rec_offs>( offs += len & 0x3fff;
offs + get_value(len));
len = offs; len = offs;
goto resolved; goto resolved;
} }
}
len = offs = static_cast<rec_offs>(offs + len); len = offs += len;
} else { } else {
len = offs = static_cast<rec_offs>( len = offs += field->fixed_len;
offs + field->fixed_len);
} }
resolved: resolved:
rec_offs_base(offsets)[i + 1] = len; rec_offs_base(offsets)[i + 1] = len;
...@@ -758,35 +751,30 @@ rec_init_offsets( ...@@ -758,35 +751,30 @@ rec_init_offsets(
rec_offs any; rec_offs any;
if (rec_get_1byte_offs_flag(rec)) { if (rec_get_1byte_offs_flag(rec)) {
offs = static_cast<rec_offs>(offs + n_fields); offs += static_cast<rec_offs>(n_fields);
any = offs; any = offs;
/* Determine offsets to fields */ /* Determine offsets to fields */
do { do {
offs = rec_1_get_field_end_info(rec, i); offs = rec_1_get_field_end_info(rec, i);
if (offs & REC_1BYTE_SQL_NULL_MASK) { if (offs & REC_1BYTE_SQL_NULL_MASK) {
offs &= static_cast<rec_offs>( offs ^= REC_1BYTE_SQL_NULL_MASK
~REC_1BYTE_SQL_NULL_MASK); | SQL_NULL;
set_type(offs, SQL_NULL);
} }
rec_offs_base(offsets)[1 + i] = offs; rec_offs_base(offsets)[1 + i] = offs;
} while (++i < n); } while (++i < n);
} else { } else {
offs = static_cast<rec_offs>(offs + 2 * n_fields); offs += static_cast<rec_offs>(2 * n_fields);
any = offs; any = offs;
/* Determine offsets to fields */ /* Determine offsets to fields */
do { do {
offs = rec_2_get_field_end_info(rec, i); offs = rec_2_get_field_end_info(rec, i);
if (offs & REC_2BYTE_SQL_NULL_MASK) { static_assert(REC_2BYTE_SQL_NULL_MASK
offs &= static_cast<rec_offs>( == SQL_NULL, "");
~REC_2BYTE_SQL_NULL_MASK); static_assert(REC_2BYTE_EXTERN_MASK
set_type(offs, SQL_NULL); == STORED_OFFPAGE, "");
} static_assert(REC_OFFS_EXTERNAL
if (offs & REC_2BYTE_EXTERN_MASK) { == STORED_OFFPAGE, "");
offs &= static_cast<rec_offs>( any |= (offs & REC_OFFS_EXTERNAL);
~REC_2BYTE_EXTERN_MASK);
set_type(offs, STORED_OFFPAGE);
any |= REC_OFFS_EXTERNAL;
}
rec_offs_base(offsets)[1 + i] = offs; rec_offs_base(offsets)[1 + i] = offs;
} while (++i < n); } while (++i < n);
} }
...@@ -838,7 +826,7 @@ rec_get_offsets_func( ...@@ -838,7 +826,7 @@ rec_get_offsets_func(
bool alter_metadata = false; bool alter_metadata = false;
ut_ad(index->n_core_fields >= n_core); ut_ad(index->n_core_fields >= n_core);
/* This assertion was relaxed for the btr_cur_open_at_index_side() /* This assertion was relaxed for the btr_cur_t::open_leaf()
call in btr_cur_instant_init_low(). We cannot invoke call in btr_cur_instant_init_low(). We cannot invoke
index->is_instant(), because the same assertion would fail there index->is_instant(), because the same assertion would fail there
until btr_cur_instant_init_low() has invoked until btr_cur_instant_init_low() has invoked
...@@ -863,6 +851,9 @@ rec_get_offsets_func( ...@@ -863,6 +851,9 @@ rec_get_offsets_func(
ut_ad(!n_core); ut_ad(!n_core);
n = dict_index_get_n_unique_in_tree_nonleaf(index) + 1; n = dict_index_get_n_unique_in_tree_nonleaf(index) + 1;
break; break;
default:
ut_ad("corrupted record header" == 0);
/* fall through */
case REC_STATUS_INFIMUM: case REC_STATUS_INFIMUM:
case REC_STATUS_SUPREMUM: case REC_STATUS_SUPREMUM:
/* infimum or supremum record */ /* infimum or supremum record */
...@@ -873,9 +864,6 @@ rec_get_offsets_func( ...@@ -873,9 +864,6 @@ rec_get_offsets_func(
: PAGE_HEAP_NO_SUPREMUM)); : PAGE_HEAP_NO_SUPREMUM));
n = 1; n = 1;
break; break;
default:
ut_error;
return(NULL);
} }
} else { } else {
n = rec_get_n_fields_old(rec); n = rec_get_n_fields_old(rec);
...@@ -897,9 +885,7 @@ rec_get_offsets_func( ...@@ -897,9 +885,7 @@ rec_get_offsets_func(
ut_ad(!is_user_rec || !n_core || index->is_dummy ut_ad(!is_user_rec || !n_core || index->is_dummy
|| dict_index_is_ibuf(index) || dict_index_is_ibuf(index)
|| n == n_fields /* btr_pcur_restore_position() */ || n == n_fields /* btr_pcur_restore_position() */
|| (n + (index->id == DICT_INDEXES_ID) || (n + (index->id == DICT_INDEXES_ID) >= n_core));
>= n_core && n <= index->n_fields
+ unsigned(rec_is_alter_metadata(rec, false))));
if (is_user_rec && n_core && n < index->n_fields) { if (is_user_rec && n_core && n < index->n_fields) {
ut_ad(!index->is_dummy); ut_ad(!index->is_dummy);
...@@ -1000,8 +986,7 @@ rec_get_offsets_reverse( ...@@ -1000,8 +986,7 @@ rec_get_offsets_reverse(
do { do {
rec_offs len; rec_offs len;
if (UNIV_UNLIKELY(i == n_node_ptr_field)) { if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
len = offs = static_cast<rec_offs>( len = offs += REC_NODE_PTR_SIZE;
offs + REC_NODE_PTR_SIZE);
goto resolved; goto resolved;
} }
...@@ -1038,30 +1023,23 @@ rec_get_offsets_reverse( ...@@ -1038,30 +1023,23 @@ rec_get_offsets_reverse(
stored in one byte for 0..127. The length stored in one byte for 0..127. The length
will be encoded in two bytes when it is 128 or will be encoded in two bytes when it is 128 or
more, or when the field is stored externally. */ more, or when the field is stored externally. */
if (DATA_BIG_COL(col)) { if (UNIV_UNLIKELY(len & 0x80) && DATA_BIG_COL(col)) {
if (len & 0x80) {
/* 1exxxxxxx xxxxxxxx */ /* 1exxxxxxx xxxxxxxx */
len = static_cast<rec_offs>( len &= 0x7f;
len << 8 | *lens++); len <<= 8;
len |= *lens++;
offs = static_cast<rec_offs>( static_assert(STORED_OFFPAGE == 0x4000, "");
offs + get_value(len)); static_assert(REC_OFFS_EXTERNAL == 0x4000, "");
if (UNIV_UNLIKELY(len & 0x4000)) { rec_offs ext = len & REC_OFFS_EXTERNAL;
any_ext = REC_OFFS_EXTERNAL; offs += get_value(len);
len = combine(offs, len = offs | ext;
STORED_OFFPAGE); any_ext |= ext;
} else {
len = offs;
}
goto resolved; goto resolved;
} }
}
len = offs = static_cast<rec_offs>(offs + len); len = offs += len;
} else { } else {
len = offs = static_cast<rec_offs>(offs len = offs += field->fixed_len;
+ field->fixed_len);
} }
resolved: resolved:
rec_offs_base(offsets)[i + 1] = len; rec_offs_base(offsets)[i + 1] = len;
...@@ -1101,7 +1079,7 @@ rec_get_nth_field_offs_old( ...@@ -1101,7 +1079,7 @@ rec_get_nth_field_offs_old(
return(os); return(os);
} }
next_os = next_os & ~REC_1BYTE_SQL_NULL_MASK; next_os &= ~REC_1BYTE_SQL_NULL_MASK;
} else { } else {
os = rec_2_get_field_start_offs(rec, n); os = rec_2_get_field_start_offs(rec, n);
...@@ -1113,8 +1091,7 @@ rec_get_nth_field_offs_old( ...@@ -1113,8 +1091,7 @@ rec_get_nth_field_offs_old(
return(os); return(os);
} }
next_os = next_os & ~(REC_2BYTE_SQL_NULL_MASK next_os &= ~(REC_2BYTE_SQL_NULL_MASK | REC_2BYTE_EXTERN_MASK);
| REC_2BYTE_EXTERN_MASK);
} }
*len = next_os - os; *len = next_os - os;
...@@ -1267,7 +1244,8 @@ rec_get_converted_size_comp_prefix_low( ...@@ -1267,7 +1244,8 @@ rec_get_converted_size_comp_prefix_low(
} else if (dfield_is_ext(dfield)) { } else if (dfield_is_ext(dfield)) {
ut_ad(DATA_BIG_COL(field->col)); ut_ad(DATA_BIG_COL(field->col));
extra_size += 2; extra_size += 2;
} else if (len < 128 || !DATA_BIG_COL(field->col)) { } else if (UNIV_LIKELY(len < 128)
|| !DATA_BIG_COL(field->col)) {
extra_size++; extra_size++;
} else { } else {
/* For variable-length columns, we look up the /* For variable-length columns, we look up the
...@@ -1618,14 +1596,7 @@ rec_convert_dtuple_to_rec_comp( ...@@ -1618,14 +1596,7 @@ rec_convert_dtuple_to_rec_comp(
/* set the null flag if necessary */ /* set the null flag if necessary */
if (dfield_is_null(field)) { if (dfield_is_null(field)) {
#if defined __GNUC__ && !defined __clang__ && __GNUC__ < 6
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wconversion" /* GCC 5 may need this here */
#endif
*nulls |= static_cast<byte>(null_mask); *nulls |= static_cast<byte>(null_mask);
#if defined __GNUC__ && !defined __clang__ && __GNUC__ < 6
# pragma GCC diagnostic pop
#endif
null_mask <<= 1; null_mask <<= 1;
continue; continue;
} }
...@@ -1734,6 +1705,9 @@ rec_convert_dtuple_to_rec_new( ...@@ -1734,6 +1705,9 @@ rec_convert_dtuple_to_rec_new(
REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT); REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT);
return buf; return buf;
} }
#if defined __GNUC__ && !defined __clang__ && __GNUC__ < 11
# pragma GCC diagnostic pop /* ignored "-Wconversion" */
#endif
/*********************************************************//** /*********************************************************//**
Builds a physical record out of a data tuple and Builds a physical record out of a data tuple and
...@@ -2096,15 +2070,13 @@ rec_copy_prefix_to_buf( ...@@ -2096,15 +2070,13 @@ rec_copy_prefix_to_buf(
stored in one byte for 0..127. The length stored in one byte for 0..127. The length
will be encoded in two bytes when it is 128 or will be encoded in two bytes when it is 128 or
more, or when the column is stored externally. */ more, or when the column is stored externally. */
if (DATA_BIG_COL(col)) { if (UNIV_UNLIKELY(len & 0x80) && DATA_BIG_COL(col)) {
if (len & 0x80) {
/* 1exxxxxx */ /* 1exxxxxx */
len &= 0x3f; len &= 0x3f;
len <<= 8; len <<= 8;
len |= *lens--; len |= *lens--;
UNIV_PREFETCH_R(lens); UNIV_PREFETCH_R(lens);
} }
}
prefix_len += len; prefix_len += len;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment