mariadb/mysql-test/main/deadlock_ftwrl.result
Rinat Ibragimov fa5f60681f MDEV-20946: Hard FTWRL deadlock under user level locks
It was possibile for a user to create an interlocked state which may go on
for a significant period of time. There is a tight loop in the FTWRL code
path that tries to repeatedly acquire a read lock. As the weight of FTWRL
lock is the smallest among others, it's always selected by the deadlock
detector, but can never be killed.

Imaging the following sequence:

    connection_0                 connection_1

 GET_LOCK("l1", 0);
                             LOCK TABLES t WRITE;
 FLUSH TABLES WITH READ LOCK;
                             GET_LOCK("l1", 1000);

The GET_LOCK statement in connection_1 triggers the deadlock detector,
which tries to select the lock in FTWRL, since its weight is 0. However,
since a loop in Global_read_lock::lock_global_read_lock() tries to always
win, it tries to acquire lock again. Which invokes the deadlock detector,
and that cycle continues until GET_LOCK in connection_1 times out.

This patch resolves the live-locking by introducing a dynamic bonus to the
deadlock weight associated with every lock. Each lock gets a bonus weight
each time it's selected by the deadlock detector. In case of a live-lock
situation, those locks that cannot be killed, get additional weight each
iteration. Eventually their weight becomes so high that the deadlock
detector shifts its attention to other lock, until it find the one that
can be killed.
2021-03-10 18:08:29 +02:00

21 lines
527 B
Text

CREATE TABLE t1(a INT);
SELECT GET_LOCK("l1", 0);
GET_LOCK("l1", 0)
1
connect con1,localhost,root,,;
LOCK TABLES t1 WRITE;
connection default;
set debug_sync='mdl_acquire_lock_wait SIGNAL ftwrl';
FLUSH TABLES WITH READ LOCK;
connection con1;
set debug_sync='now WAIT_FOR ftwrl';
SELECT GET_LOCK("l1", 1000);
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
disconnect con1;
connection default;
SELECT RELEASE_LOCK("l1");
RELEASE_LOCK("l1")
1
UNLOCK TABLES;
DROP TABLE t1;
set debug_sync='reset';