• Marko Mäkelä's avatar
    MDEV-13637 InnoDB change buffer housekeeping can cause redo log overrun and possibly deadlocks · f87cb652
    Marko Mäkelä authored
    The function ibuf_remove_free_page() may be called while the caller
    is holding several mutexes or rw-locks. Because of this, this
    housekeeping loop may cause performance glitches for operations that
    involve tables that are stored in the InnoDB system tablespace.
    Also deadlocks might be possible.
    
    The worst impact of all is that due to the mutexes being held, calls to
    log_free_check() had to be skipped during this housekeeping.
    This means that the cyclic InnoDB redo log may be overwritten.
    If the system crashes during this, it would be unable to recover.
    
    The entry point to the problematic code is ibuf_free_excess_pages().
    It would make sense to call it before acquiring any mutexes or rw-locks,
    in any 'pessimistic' operation that involves the system tablespace.
    
    fseg_create_general(), fseg_alloc_free_page_general(): Do not call
    ibuf_free_excess_pages() while potentially holding some latches.
    
    ibuf_remove_free_page(): Do call log_free_check(), like every operation
    that is about to generate redo log should do.
    
    ibuf_free_excess_pages(): Remove some assertions that are replaced
    by stricter assertions in the log_free_check() that is now called by
    ibuf_remove_free_page().
    
    row_mtr_start(): New function, to perform necessary preparations when
    starting a mini-transaction for row operations. For pessimistic operations
    on secondary indexes that are located in the system tablespace,
    this includes calling ibuf_free_excess_pages().
    
    row_undo_ins_remove_sec_low(), row_undo_mod_del_mark_or_remove_sec_low(),
    row_undo_mod_del_unmark_sec_and_undo_update(): Call row_mtr_start().
    
    row_ins_sec_index_entry(): Call ibuf_free_excess_pages() if the operation
    may involve allocating pages and change buffering in the system tablespace.
    
    row_upd_sec_index_entry(): Slightly refactor the code. The
    delete-marking of the old entry is done in-place. It could be
    change-buffered, but the old code should be unlikely to have
    invoked ibuf_free_excess_pages() in this case.
    f87cb652
row0upd.cc 91.8 KB