-
Marko Mäkelä authored
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 c533308a). The calls for acquiring tablespace latch had previously been moved in commit 87839258 and commit 1e9c922f. The hang was introduced in commit 2e814d47 which imported mysql/mysql-server@ac74632293bea967b352d1b472abedeeaa921b98 which failed to strengthen the locking requirements of the function btr_get_size().
8b6a308e