• Marko Mäkelä's avatar
    MDEV-29883 Deadlock between InnoDB statistics update and BLOB insert · 8b6a308e
    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
btr0btr.cc 159 KB