Skip to content

Commit 9c8bdc6

Browse files
committed
MDEV-35049: btr_search_check_free_space_in_heap() is a bottleneck
Let us use implement a simple fixed-size allocator for the adaptive hash index, insted of complicating mem_heap_t or mem_block_info_t. MEM_HEAP_BTR_SEARCH: Remove. mem_block_info_t::free_block(), mem_heap_free_block_free(): Remove. mem_heap_free_top(), mem_heap_get_top(): Remove. btr_sea::partition::spare: Replaces mem_block_info_t::free_block. This keeps one spare block per adaptive hash index partition, to process an insert. We must not wait for buf_pool.mutex while holding any btr_sea::partition::latch. That is why we cache one block for future allocations. This is protected by a new btr_sea::partition::blocks_mutex in order to relieve pressure on btr_sea::partition::latch. btr_sea::partition::prepare_insert(): Replaces btr_search_check_free_space_in_heap(). btr_sea::partition::erase(): Replaces ha_search_and_delete_if_found(). btr_sea::partition::cleanup_after_erase(): Replaces the most part of ha_delete_hash_node(). Unlike the previous implementation, we will retain a spare block for prepare_insert(). This should reduce some contention on buf_pool.mutex. btr_search.n_parts: Replaces btr_ahi_parts. btr_search.enabled: Replaces btr_search_enabled. This must hold whenever buf_block_t::index is set while a thread is holding a btr_sea::partition::latch. dict_index_t::search_info: Remove pointer indirection, and use Atomic_relaxed or Atomic_counter for most fields. btr_search_guess_on_hash(): Let the caller ensure that latch_mode is BTR_MODIFY_LEAF or BTR_SEARCH_LEAF. Release btr_sea::partition::latch before buffer-fixing the block. The page latch that we already acquired is preventing buffer pool eviction. We must validate both block->index and block->page.state while holding part.latch in order to avoid race conditions with buffer page relocation or buf_pool_t::resize(). btr_search_check_guess(): Remove the constant parameter can_only_compare_to_cursor_rec=false. ahi_node: Replaces ha_node_t. This has been tested by running the regression test suite with the adaptive hash index enabled: ./mtr --mysqld=--loose-innodb-adaptive-hash-index=ON Reviewed by: Vladislav Lesin
1 parent 5e8714b commit 9c8bdc6

33 files changed

+911
-1547
lines changed

extra/mariabackup/xtrabackup.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,8 +1845,8 @@ struct my_option xb_server_options[] =
18451845
#ifdef BTR_CUR_HASH_ADAPT
18461846
{"innodb_adaptive_hash_index", OPT_INNODB_ADAPTIVE_HASH_INDEX,
18471847
"Enable InnoDB adaptive hash index (disabled by default).",
1848-
&btr_search_enabled,
1849-
&btr_search_enabled,
1848+
&btr_search.enabled,
1849+
&btr_search.enabled,
18501850
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
18511851
#endif /* BTR_CUR_HASH_ADAPT */
18521852
{"innodb_autoextend_increment", OPT_INNODB_AUTOEXTEND_INCREMENT,
@@ -2402,7 +2402,7 @@ static bool innodb_init_param()
24022402
srv_page_size = 0;
24032403
srv_page_size_shift = 0;
24042404
#ifdef BTR_CUR_HASH_ADAPT
2405-
btr_ahi_parts = 1;
2405+
btr_search.n_parts = 1;
24062406
#endif /* BTR_CUR_HASH_ADAPT */
24072407

24082408
if (innobase_page_size != (1LL << 14)) {

storage/innobase/CMakeLists.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,6 @@ SET(INNOBASE_SOURCES
193193
include/btr0pcur.h
194194
include/btr0pcur.inl
195195
include/btr0sea.h
196-
include/btr0sea.inl
197196
include/btr0types.h
198197
include/buf0buddy.h
199198
include/buf0buf.h
@@ -259,8 +258,6 @@ SET(INNOBASE_SOURCES
259258
include/gis0rtree.inl
260259
include/gis0type.h
261260
include/ha_prototypes.h
262-
include/ha0ha.h
263-
include/ha0ha.inl
264261
include/ha0storage.h
265262
include/ha0storage.inl
266263
include/handler0alter.h

storage/innobase/btr/btr0btr.cc

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ btr_root_block_get(
280280
#ifndef BTR_CUR_ADAPT
281281
static constexpr buf_block_t *guess= nullptr;
282282
#else
283-
buf_block_t *&guess= btr_search_get_info(index)->root_guess;
283+
buf_block_t *&guess= index->search_info.root_guess;
284284
guess=
285285
#endif
286286
block=
@@ -1085,7 +1085,7 @@ dberr_t dict_index_t::clear(que_thr_t *thr)
10851085
#ifndef BTR_CUR_ADAPT
10861086
static constexpr buf_block_t *guess= nullptr;
10871087
#else
1088-
buf_block_t *&guess= btr_search_get_info(this)->root_guess;
1088+
buf_block_t *&guess= search_info.root_guess;
10891089
guess=
10901090
#endif
10911091
root_block= buf_page_get_gen({table->space_id, page},
@@ -1095,14 +1095,12 @@ dberr_t dict_index_t::clear(que_thr_t *thr)
10951095
{
10961096
btr_free_but_not_root(root_block, mtr.get_log_mode()
10971097
#ifdef BTR_CUR_HASH_ADAPT
1098-
,n_ahi_pages() != 0
1098+
,any_ahi_pages()
10991099
#endif
11001100
);
1101-
1101+
btr_search_drop_page_hash_index(root_block, false);
11021102
#ifdef BTR_CUR_HASH_ADAPT
1103-
if (root_block->index)
1104-
btr_search_drop_page_hash_index(root_block, false);
1105-
ut_ad(n_ahi_pages() == 0);
1103+
ut_ad(!any_ahi_pages());
11061104
#endif
11071105
mtr.memset(root_block, PAGE_HEADER + PAGE_BTR_SEG_LEAF,
11081106
FSEG_HEADER_SIZE, 0);
@@ -1147,7 +1145,7 @@ void btr_drop_temporary_table(const dict_table_t &table)
11471145
#ifndef BTR_CUR_ADAPT
11481146
static constexpr buf_block_t *guess= nullptr;
11491147
#else
1150-
buf_block_t *guess= index->search_info->root_guess;
1148+
buf_block_t *guess= index->search_info.root_guess;
11511149
#endif
11521150
if (buf_block_t *block= buf_page_get_gen({SRV_TMP_SPACE_ID, index->page},
11531151
0, RW_X_LATCH, guess, BUF_GET,

storage/innobase/btr/btr0cur.cc

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,18 +1122,19 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode,
11221122
#ifndef BTR_CUR_ADAPT
11231123
guess= nullptr;
11241124
#else
1125-
btr_search_t *info= btr_search_get_info(index());
1125+
auto info= &index()->search_info;
11261126
guess= info->root_guess;
11271127

11281128
# ifdef BTR_CUR_HASH_ADAPT
11291129
# ifdef UNIV_SEARCH_PERF_STAT
11301130
info->n_searches++;
11311131
# endif
1132-
bool ahi_enabled= btr_search_enabled;
1133-
/* We do a dirty read of btr_search_enabled below,
1134-
and btr_search_guess_on_hash() will have to check it again. */
1135-
if (!ahi_enabled);
1136-
else if (btr_search_guess_on_hash(index(), info, tuple, mode,
1132+
if (latch_mode > BTR_MODIFY_LEAF)
1133+
/* The adaptive hash index cannot be useful for these searches. */;
1134+
/* We do a dirty read of btr_search.enabled below,
1135+
and btr_search_guess_on_hash() will have to check it again. */
1136+
else if (!btr_search.enabled);
1137+
else if (btr_search_guess_on_hash(index(), tuple, mode,
11371138
latch_mode, this, mtr))
11381139
{
11391140
/* Search using the hash index succeeded */
@@ -1397,7 +1398,7 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode,
13971398

13981399
reached_latched_leaf:
13991400
#ifdef BTR_CUR_HASH_ADAPT
1400-
if (ahi_enabled && !(tuple->info_bits & REC_INFO_MIN_REC_FLAG))
1401+
if (btr_search.enabled && !(tuple->info_bits & REC_INFO_MIN_REC_FLAG))
14011402
{
14021403
if (page_cur_search_with_match_bytes(tuple, mode,
14031404
&up_match, &up_bytes,
@@ -1422,18 +1423,18 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode,
14221423
goto need_opposite_intention;
14231424

14241425
#ifdef BTR_CUR_HASH_ADAPT
1425-
/* We do a dirty read of btr_search_enabled here. We will
1426-
properly check btr_search_enabled again in
1426+
/* We do a dirty read of btr_search.enabled here. We will recheck in
14271427
btr_search_build_page_hash_index() before building a page hash
14281428
index, while holding search latch. */
1429-
if (!btr_search_enabled);
1429+
if (!btr_search.enabled);
14301430
else if (tuple->info_bits & REC_INFO_MIN_REC_FLAG)
14311431
/* This may be a search tuple for btr_pcur_t::restore_position(). */
14321432
ut_ad(tuple->is_metadata() ||
14331433
(tuple->is_metadata(tuple->info_bits ^ REC_STATUS_INSTANT)));
14341434
else if (index()->table->is_temporary());
1435-
else if (!rec_is_metadata(page_cur.rec, *index()))
1436-
btr_search_info_update(index(), this);
1435+
else if (!rec_is_metadata(page_cur.rec, *index()) &&
1436+
index()->search_info.hash_analysis_useful())
1437+
search_info_update();
14371438
#endif /* BTR_CUR_HASH_ADAPT */
14381439

14391440
goto func_exit;
@@ -1660,18 +1661,18 @@ dberr_t btr_cur_t::pessimistic_search_leaf(const dtuple_t *tuple,
16601661
ut_ad(low_match != ULINT_UNDEFINED || mode != PAGE_CUR_LE);
16611662

16621663
#ifdef BTR_CUR_HASH_ADAPT
1663-
/* We do a dirty read of btr_search_enabled here. We will
1664-
properly check btr_search_enabled again in
1664+
/* We do a dirty read of btr_search.enabled here. We will recheck in
16651665
btr_search_build_page_hash_index() before building a page hash
16661666
index, while holding search latch. */
1667-
if (!btr_search_enabled);
1667+
if (!btr_search.enabled);
16681668
else if (tuple->info_bits & REC_INFO_MIN_REC_FLAG)
16691669
/* This may be a search tuple for btr_pcur_t::restore_position(). */
16701670
ut_ad(tuple->is_metadata() ||
16711671
(tuple->is_metadata(tuple->info_bits ^ REC_STATUS_INSTANT)));
16721672
else if (index()->table->is_temporary());
1673-
else if (!rec_is_metadata(page_cur.rec, *index()))
1674-
btr_search_info_update(index(), this);
1673+
else if (!rec_is_metadata(page_cur.rec, *index()) &&
1674+
index()->search_info.hash_analysis_useful())
1675+
search_info_update();
16751676
#endif /* BTR_CUR_HASH_ADAPT */
16761677
err= DB_SUCCESS;
16771678
}
@@ -1774,8 +1775,7 @@ dberr_t btr_cur_search_to_nth_level(ulint level,
17741775
#ifndef BTR_CUR_ADAPT
17751776
buf_block_t *block= nullptr;
17761777
#else
1777-
btr_search_t *info= btr_search_get_info(index);
1778-
buf_block_t *block= info->root_guess;
1778+
buf_block_t *block= index->search_info.root_guess;
17791779
#endif /* BTR_CUR_ADAPT */
17801780

17811781
ut_ad(mtr->memo_contains_flagged(&index->lock,
@@ -2520,12 +2520,10 @@ btr_cur_optimistic_insert(
25202520
ut_ad(flags == BTR_NO_LOCKING_FLAG);
25212521
} else if (index->table->is_temporary()) {
25222522
} else {
2523-
srw_spin_lock* ahi_latch = btr_search_sys.get_latch(*index);
25242523
if (!reorg && cursor->flag == BTR_CUR_HASH) {
2525-
btr_search_update_hash_node_on_insert(
2526-
cursor, ahi_latch);
2524+
btr_search_update_hash_node_on_insert(cursor);
25272525
} else {
2528-
btr_search_update_hash_on_insert(cursor, ahi_latch);
2526+
btr_search_update_hash_on_insert(cursor);
25292527
}
25302528
}
25312529
#endif /* BTR_CUR_HASH_ADAPT */
@@ -2698,8 +2696,7 @@ btr_cur_pessimistic_insert(
26982696
ut_ad(!(flags & BTR_CREATE_FLAG));
26992697
} else if (index->table->is_temporary()) {
27002698
} else {
2701-
btr_search_update_hash_on_insert(
2702-
cursor, btr_search_sys.get_latch(*index));
2699+
btr_search_update_hash_on_insert(cursor);
27032700
}
27042701
#endif /* BTR_CUR_HASH_ADAPT */
27052702
if (inherit && !(flags & BTR_NO_LOCKING_FLAG)) {
@@ -3249,9 +3246,9 @@ btr_cur_update_in_place(
32493246

32503247
#ifdef BTR_CUR_HASH_ADAPT
32513248
{
3252-
srw_spin_lock* ahi_latch = block->index
3253-
? btr_search_sys.get_latch(*index) : NULL;
3254-
if (ahi_latch) {
3249+
auto part = block->index
3250+
? &btr_search.get_part(*index) : nullptr;
3251+
if (part) {
32553252
/* TO DO: Can we skip this if none of the fields
32563253
index->search_info->curr_n_fields
32573254
are being updated? */
@@ -3269,7 +3266,7 @@ btr_cur_update_in_place(
32693266
btr_search_update_hash_on_delete(cursor);
32703267
}
32713268

3272-
ahi_latch->wr_lock(SRW_LOCK_CALL);
3269+
part->latch.wr_lock(SRW_LOCK_CALL);
32733270
}
32743271

32753272
assert_block_ahi_valid(block);
@@ -3279,8 +3276,8 @@ btr_cur_update_in_place(
32793276
mtr);
32803277

32813278
#ifdef BTR_CUR_HASH_ADAPT
3282-
if (ahi_latch) {
3283-
ahi_latch->wr_unlock();
3279+
if (part) {
3280+
part->latch.wr_unlock();
32843281
}
32853282
}
32863283
#endif /* BTR_CUR_HASH_ADAPT */

0 commit comments

Comments
 (0)