[MDEV-26206] gap lock is not set if implicit lock exists Created: 2021-07-21 Updated: 2021-08-24 Resolved: 2021-08-19 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Storage Engine - InnoDB |
| Affects Version/s: | 10.3.9, 10.4, 10.5, 10.6 |
| Fix Version/s: | 10.3.32, 10.4.22, 10.5.13, 10.6.5 |
| Type: | Bug | Priority: | Critical |
| Reporter: | Vladislav Lesin | Assignee: | Vladislav Lesin |
| Resolution: | Fixed | Votes: | 1 |
| Labels: | regression | ||
| Attachments: |
|
||||||||||||||||
| Issue Links: |
|
||||||||||||||||
| Description |
|
After the following commit:
lock_rec_convert_impl_to_expl() does not create explicit lock if the caller holds implicit lock. Suppose we have the following call stack:
If lock type is LOCK_GAP or LOCK_ORDINARY, and the transaction holds implicit lock for the record, then explicit gap-lock will not be set for the record, as lock_rec_convert_impl_to_expl() returns true and lock_rec_convert_impl_to_expl() bypasses lock_rec_lock() call. The following test shows the issue:
|
| Comments |
| Comment by Vladislav Lesin [ 2021-07-23 ] | |||||||||||||||||||||||||||||||
|
The initial idea for the fix was to bypass lock_rec_convert_impl_to_expl() call if requested lock is not LOCK_REC_NOT_GAP in lock_clust_rec_read_check_and_lock() and lock_sec_rec_read_check_and_lock(). But after I implemented it there were some rpl tests failed. Before So, before It looks like implicit to explicit lock conversion is unnecessary for that case. But when I removed it, I got some rpl tests failed. Particularly binlog_encryption.rpl_parallel_innodb_lock_conflict failed here:
(7, NULL) row was not found on slave. So, it looks like that explicit non-gap lock is necessary and used somehow, I don't understand how. When I left the same logic as it was before | |||||||||||||||||||||||||||||||
| Comment by Vladislav Lesin [ 2021-07-26 ] | |||||||||||||||||||||||||||||||
|
I found the error in my previous try to avoid implicit to explicit lock conversion if the transaction itself holds the implicit lock on the record, and gap lock is requested for the record. Pushed 10.6 and 10.3 versions for testing (bb-10.6- The fix also influence | |||||||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2021-07-30 ] | |||||||||||||||||||||||||||||||
|
The 10.3 version of this changes each return true in lock_rec_convert_impl_to_expl() to return !gap_lock; which refers to an added Boolean parameter. As far as I can tell, there is no need to change lock_rec_convert_impl_to_expl() at all, but instead only a need to change the callers: Each call
can be replaced with
and it should still be equivalent to the proposed fix. In the 10.6 version, it is slightly different, maybe something like the following:
Either way, as far as I can tell, only the functions lock_sec_rec_read_check_and_lock() and lock_clust_rec_read_check_and_lock() would have to be changed. Maybe we could move the lock_table_has(…, LOCK_X) up a few callers in the call stack, and pass the BTR_NO_LOCKING_FLAG to each index operation if we are already holding an exclusive table lock? | |||||||||||||||||||||||||||||||
| Comment by Vladislav Lesin [ 2021-08-10 ] | |||||||||||||||||||||||||||||||
|
When I tried to move table lock checking from lock_rec_lock() to the higher level, my initial idea was to set prebuilt->select_lock_type = LOCK_NONE before row_search_mvcc() call, but it does not work because prebuilt->select_lock_type == LOCK_X it treated as "UPDATE" execution inside of row_search_mvcc(), and for "UPDATE" persistent cursor position must be stored. The other idea was to move the check inside of row_search_mvcc(). The corresponding patch table-locked.diff The current 10.6 version contains the fix for lock_rec_convert_impl_to_expl() as Marko suggested in the previous comment, and it's under RQG testing. |