• Marko Mäkelä's avatar
    WIP: MDEV-17603 REPLACE and INSERT…ON DUPLICATE KEY UPDATE are deadlock-prone · aed761ce
    Marko Mäkelä authored
    Implement an alternative fix for the bug whose original fix
    mysql/mysql-server@c93b0d9a972cb6f98fd445f2b69d924350f9128a
    in MySQL 5.7.4 caused problems.
    
    This is based on
    mysql/mysql-server@e0e4bacddf421550baca3578bc0db13693874fdb
    in MySQL 5.7.26.
    
    When performing a rollback to the start of the current row
    operation in REPLACE or INSERT...ON DUPLICATE KEY UPDATE
    we were not maintaining serializability, because we would
    release implicit locks that could already have been acquired
    for some of the indexes.
    
    lock_rec_convert_impl_to_expl_for_trx(): Declare globally.
    
    undo_node_t::convert_impl_to_expl(): Convert an implicit lock
    to an explicit one during a partial rollback.
    
    row_insert_for_mysql(): Set trx->duplicates=ULINT_UNDEFINED
    for rolling back the current row operation. This will allow
    undo_node_t::convert_impl_to_expl() to be effective only
    for this use case, not for other scenarios, such as
    rolling back to the start of the statement, or
    ROLLBACK TO SAVEPOINT.
    
    FIXME: Neither innodb.auto_increment_dup,log-bin nor the
    upstream fix (which we did not add) innodb.iodku pass.
    While the undo_node_t::convert_impl_to_expl() is working
    as intended, what happens in innodb.auto_increment_dup,log-bin
    is that the newly created explicit record lock for the record
    heap number 6 on the PRIMARY key root page (3) will be released
    when that record is deleted moments later, with the following
    stack trace:
    
    lock_rec_reset_nth_bit
    lock_rec_reset_and_release_wait_low
    lock_rec_reset_and_release_wait
    lock_update_delete
    btr_cur_optimistic_delete_func
    row_undo_ins_remove_clust_rec
    row_undo_ins
    row_undo
    row_undo_step
    que_thr_step
    que_run_threads_low
    que_run_threads
    trx_rollback_to_savepoint_low
    trx_rollback_to_savepoint
    row_mysql_handle_errors
    row_insert_for_mysql
    
    The idea might work with predicate locks, which we do not have.
    This entire scenario could also be fixed by MDEV-16232, which
    could allow the entire operation to be protected with page latches.
    aed761ce
trx0trx.cc 76.4 KB