summaryrefslogtreecommitdiff
path: root/storage/innobase/btr
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2022-10-26 12:52:08 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2022-10-26 12:52:08 +0300
commit8b6a308e463f937eb8d2498b04967a222c83af90 (patch)
treeb1fc0b2fc3dee2f8ce4f6f6aa4b92d8b51bda6b3 /storage/innobase/btr
parent78a04a4c22d54dc4f67f067fc9b7a0bc717ebfdd (diff)
downloadmariadb-git-8b6a308e463f937eb8d2498b04967a222c83af90.tar.gz
MDEV-29883 Deadlock between InnoDB statistics update and BLOB insert
The test innodb.innodb-wl5522-debug would occasionally hang (especially when run with ./mtr --rr) due to a deadlock between btr_store_big_rec_extern_fields() and dict_stats_analyze_index(). The two threads would acquire the clustered index root page latch and the tablespace latch in the opposite order. The deadlock was possible because dict_stats_analyze_index() was holding the index latch in shared mode and an index root page latch, while waiting for the tablespace latch. If a stronger dict_index_t::lock had been held by dict_stats_analyze_index(), any operations that free or allocate index pages would have been blocked. In each caller of fseg_n_reserved_pages() except ibuf_init_at_db_start() which is a special case for ibuf.index at database startup, we must hold an index latch that prevents concurrent allocation or freeing of index pages. Any operation that allocates or free pages that belong to an index tree must first acquire an index latch in Update or Exclusive mode, and while holding that, acquire an index root page latch in Update or Exclusive mode. dict_index_t::clear(): Also acquire an index latch. Otherwise, the test innodb.insert_into_empty could hang. btr_get_size_and_reserved(): Assert that a strong enough index latch is being held. Only acquire a shared fil_space_t::latch; we are only reading, not modifying any data. dict_stats_update_transient_for_index(), dict_stats_analyze_index(): Acquire a strong enough index latch. Only acquire a shared fil_space_t::latch. These operations had followed the same order of acquiring latches in every InnoDB version since the very beginning (commit c533308a158795f91247e9fe3c7304fa5e7d2b3c). The calls for acquiring tablespace latch had previously been moved in commit 87839258f86196dfca1d3af2a947e570e13eeb94 and commit 1e9c922fa726b22f4522f2a4de0fcb6595404086. The hang was introduced in commit 2e814d4702d71a04388386a9f591d14a35980bfe which imported mysql/mysql-server@ac74632293bea967b352d1b472abedeeaa921b98 which failed to strengthen the locking requirements of the function btr_get_size().
Diffstat (limited to 'storage/innobase/btr')
-rw-r--r--storage/innobase/btr/btr0btr.cc1
1 files changed, 1 insertions, 0 deletions
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc
index e503215e05b..04677c1e1d3 100644
--- a/storage/innobase/btr/btr0btr.cc
+++ b/storage/innobase/btr/btr0btr.cc
@@ -1102,6 +1102,7 @@ dberr_t dict_index_t::clear(que_thr_t *thr)
mtr.set_log_mode(MTR_LOG_NO_REDO);
else
set_modified(mtr);
+ mtr_sx_lock_index(this, &mtr);
dberr_t err;
if (buf_block_t *root_block=