diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2022-10-26 12:52:08 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2022-10-26 12:52:08 +0300 |
commit | 8b6a308e463f937eb8d2498b04967a222c83af90 (patch) | |
tree | b1fc0b2fc3dee2f8ce4f6f6aa4b92d8b51bda6b3 /storage/innobase/btr | |
parent | 78a04a4c22d54dc4f67f067fc9b7a0bc717ebfdd (diff) | |
download | mariadb-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.cc | 1 |
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= |