In certain situations, while one transaction was waiting for a row lock,
InnoDB could grant another transaction a lock that conflicted with the waiting
lock, but not with other already granted locks. Then if the page was
reorganised, the granted lock could be moved to the head of the lock queue.
This could end up with a situation where the waiting lock is now waiting for
the granted lock, and this wait was never reported to replication. This could
cause parallel replication to hang for --innodb-lock-wait-timeout if the
waiting transaction is before the granted one.

This patch fixes the issue by adding logic, so that when a lock is granted and
added to a lock queue, a wait is reported against this lock for any already
waiting locks. (This supplements the wait reports made when a waiting lock
is added to the queue).

Signed-off-by: Kristian Nielsen <[email protected]>
---
 storage/innobase/lock/lock0lock.cc | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/storage/innobase/lock/lock0lock.cc 
b/storage/innobase/lock/lock0lock.cc
index 3e4e619b3a0..c5b83b5be6c 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -1580,7 +1580,8 @@ TRANSACTIONAL_TARGET
 static void lock_rec_add_to_queue(unsigned type_mode, const hash_cell_t &cell,
                                   const page_id_t id, const page_t *page,
                                   ulint heap_no, dict_index_t *index,
-                                  trx_t *trx, bool caller_owns_trx_mutex)
+                                  trx_t *trx, bool caller_owns_trx_mutex,
+                                  bool report_waits= false)
 {
        ut_d(lock_sys.hash_get(type_mode).assert_locked(id));
        ut_ad(xtest() || caller_owns_trx_mutex == trx->mutex_is_owner());
@@ -1637,15 +1638,27 @@ static void lock_rec_add_to_queue(unsigned type_mode, 
const hash_cell_t &cell,
        if (type_mode & LOCK_WAIT) {
                goto create;
        } else if (lock_t *first_lock = lock_sys_t::get_first(cell, id)) {
+               bool do_create= false;
                for (lock_t* lock = first_lock;;) {
                        if (lock->is_waiting()
                            && lock_rec_get_nth_bit(lock, heap_no)) {
-                               goto create;
+#ifdef HAVE_REPLICATION
+                               if (report_waits)
+                               {
+                                       do_create= true;
+                                       
thd_rpl_deadlock_check(lock->trx->mysql_thd,
+                                                              trx->mysql_thd);
+                               }
+                               else
+#endif
+                                       goto create;
                        }
                        if (!(lock = lock_rec_get_next_on_page(lock))) {
                                break;
                        }
                }
+               if (do_create)
+                       goto create;
 
                /* Look for a similar record lock on the same page:
                if one is found and there are no waiting lock requests,
@@ -1821,7 +1834,7 @@ lock_rec_lock(
         {
           /* Set the requested lock on the record. */
           lock_rec_add_to_queue(mode, g.cell(), id, block->page.frame, heap_no,
-                                index, trx, true);
+                                index, trx, true, true);
           err= DB_SUCCESS_LOCKED_REC;
         }
       }
-- 
2.47.3

_______________________________________________
commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to