• Aleksey Midenkov's avatar
    MDEV-18706 ER_LOCK_DEADLOCK on concurrent read and insert into already locked gap · 1904b11b
    Aleksey Midenkov authored
    * Cause
    No real deadlock, but incomplete conflict detection:
    
    1. Con1-X blocks on Def-X lock (p.2 in test);
    2. Def-II-X has to wait Con1-X and here conflict resolution starts (p.3 in test);
    3. Conflict resolution goes through a tree of locks:
      a. (Def-II-X, Def-X): ok
      b. (Def-II-X, Con1-X): conflict, traversing from Con1-X
      c. (Con1-X, Def-X): conflict, found cycle (because resolution started from Def).
    
    The weak point here is 2. (lock_rec_has_to_wait()), because Def-II-X
    doesn't have to wait Con1: Def already got X "next-key" lock that also
    holds the gap before the record.
    
    * Fix
    Allow lock in `lock_rec_other_has_conflicting()` if there is already
    non-waiting stronger or equal lock in this transaction
    (`lock_rec_has_expl()`).
    
    row_search_mvcc(): SELECT FOR UPDATE skips inserted records when
    next-key lock is released. Fixed by stepping back before wait and
    stepping forward before acquire: it steps into the gap again and
    discovers newly inserted records. Note that change to row_sel() is not
    required as it is used for internal queries only.
    
    * Test fixes
    innodb.auto_increment_dup: log-bin behaves like skip-log-bin because
    of no bogus deadlock on UPDATE.
    
    versioning.update: originally described deadlock from this task is now
    disappeared.
    1904b11b
innodb-lock.opt 34 Bytes