Skip to content

Commit 3fdd390

Browse files
committed
MDEV-14441 InnoDB hangs when setting innodb_adaptive_hash_index=OFF during UPDATE
This race condition is a regression caused by MDEV-12121. btr_cur_update_in_place(): Determine block->index!=NULL only once in order to determine whether an adaptive hash index bucket needs to be exclusively locked and unlocked. If we evaluated block->index multiple times, and the adaptive hash index was disabled before we locked the adaptive hash index, then we would never release the adaptive hash index bucket latch, which would eventually lead to InnoDB hanging.
1 parent 9c6fc7b commit 3fdd390

File tree

1 file changed

+26
-22
lines changed

1 file changed

+26
-22
lines changed

storage/innobase/btr/btr0cur.cc

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
44
Copyright (c) 2008, Google Inc.
55
Copyright (c) 2012, Facebook Inc.
6-
Copyright (c) 2015, 2017, MariaDB Corporation.
6+
Copyright (c) 2015, 2018, MariaDB Corporation.
77
88
Portions of this file contain modifications contributed and copyrighted by
99
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -3692,34 +3692,38 @@ btr_cur_update_in_place(
36923692
|| row_get_rec_trx_id(rec, index, offsets));
36933693

36943694
#ifdef BTR_CUR_HASH_ADAPT
3695-
if (block->index) {
3696-
/* TO DO: Can we skip this if none of the fields
3697-
index->search_info->curr_n_fields
3698-
are being updated? */
3699-
3700-
/* The function row_upd_changes_ord_field_binary works only
3701-
if the update vector was built for a clustered index, we must
3702-
NOT call it if index is secondary */
3703-
3704-
if (!dict_index_is_clust(index)
3705-
|| row_upd_changes_ord_field_binary(index, update, thr,
3706-
NULL, NULL)) {
3707-
3708-
/* Remove possible hash index pointer to this record */
3709-
btr_search_update_hash_on_delete(cursor);
3695+
{
3696+
rw_lock_t* ahi_latch = block->index
3697+
? btr_get_search_latch(block->index) : NULL;
3698+
if (ahi_latch) {
3699+
/* TO DO: Can we skip this if none of the fields
3700+
index->search_info->curr_n_fields
3701+
are being updated? */
3702+
3703+
/* The function row_upd_changes_ord_field_binary
3704+
does not work on a secondary index. */
3705+
3706+
if (!dict_index_is_clust(index)
3707+
|| row_upd_changes_ord_field_binary(
3708+
index, update, thr, NULL, NULL)) {
3709+
3710+
/* Remove possible hash index pointer
3711+
to this record */
3712+
btr_search_update_hash_on_delete(cursor);
3713+
}
37103714
}
37113715

3712-
btr_search_x_lock(index);
3713-
}
3716+
rw_lock_x_lock(ahi_latch);
37143717

3715-
assert_block_ahi_valid(block);
3718+
assert_block_ahi_valid(block);
37163719
#endif /* BTR_CUR_HASH_ADAPT */
37173720

3718-
row_upd_rec_in_place(rec, index, offsets, update, page_zip);
3721+
row_upd_rec_in_place(rec, index, offsets, update, page_zip);
37193722

37203723
#ifdef BTR_CUR_HASH_ADAPT
3721-
if (block->index) {
3722-
btr_search_x_unlock(index);
3724+
if (ahi_latch) {
3725+
rw_lock_x_unlock(ahi_latch);
3726+
}
37233727
}
37243728
#endif /* BTR_CUR_HASH_ADAPT */
37253729

0 commit comments

Comments
 (0)