Details
-
Bug
-
Status: Confirmed (View Workflow)
-
Minor
-
Resolution: Unresolved
-
10.11, 11.4, 11.8, 12.3, 13.1, 12.3.3
-
None
-
MariaDB 12.3.3-MariaDB-ubu2404 on Linux x86_64
Description
MariaDB 12.3.3-MariaDB-ubu2404 on Linux x86_64 omits the detailed InnoDB deadlock report from the diagnostics of an asynchronously selected victim. The victim receives error 1213, but its diagnostics contain only the ordinary deadlock message even when innodb_print_all_deadlocks=ON. The full report is written to the server log, and the same diagnostics handler captures it when the event transaction is both the detector and victim.
This occurs when InnoDB selects an event-scheduler transaction as the victim of a deadlock detected by another session while detailed deadlock reporting is enabled.
Reproducer
Run the following as a user permitted to set the two global variables and create events. The first schedule makes the lighter event transaction the victim while the main connection detects the deadlock. The second schedule is a control in which the event transaction detects the cycle and becomes the victim.
DROP DATABASE IF EXISTS deadlock_diag; |
SET GLOBAL event_scheduler=ON; |
SET GLOBAL innodb_print_all_deadlocks=ON; |
CREATE DATABASE deadlock_diag; |
USE deadlock_diag; |
|
|
CREATE TABLE coord |
(name VARCHAR(32) PRIMARY KEY, val INT NOT NULL) ENGINE=MyISAM; |
INSERT INTO coord VALUES ('event_locked',0),('main_ready',0),('done',0); |
|
|
CREATE TABLE locks |
(id INT PRIMARY KEY) ENGINE=InnoDB; |
INSERT INTO locks VALUES (1),(2); |
|
|
CREATE TABLE weight |
(id INT PRIMARY KEY, v INT NOT NULL) ENGINE=InnoDB; |
INSERT INTO weight SELECT seq, 0 FROM seq_1_to_100; |
|
|
CREATE TABLE diagnostics |
(scenario VARCHAR(32), condition_no INT, mysql_errno INT, |
level_name VARCHAR(16), message_text LONGTEXT) |
ENGINE=MyISAM;
|
|
|
DELIMITER //
|
CREATE PROCEDURE worker() |
BEGIN
|
DECLARE v_count INT DEFAULT 0; |
DECLARE v_i INT DEFAULT 1; |
DECLARE v_errno INT; |
DECLARE v_level VARCHAR(16); |
DECLARE v_message LONGTEXT; |
DECLARE CONTINUE HANDLER FOR 1213 |
BEGIN |
GET DIAGNOSTICS v_count = NUMBER;
|
SET v_i=1; |
WHILE v_i <= v_count DO
|
GET DIAGNOSTICS CONDITION v_i
|
v_errno = MYSQL_ERRNO, v_level = CLASS_ORIGIN, v_message = MESSAGE_TEXT;
|
INSERT INTO diagnostics |
VALUES ('alternate_victim',v_i,v_errno,v_level,v_message); |
SET v_i=v_i+1; |
END WHILE; |
END; |
|
|
START TRANSACTION; |
SELECT id INTO @sink FROM locks WHERE id=1 FOR UPDATE; |
UPDATE coord SET val=1 WHERE name='event_locked'; |
WHILE (SELECT val FROM coord WHERE name='main_ready')=0 DO |
DO SLEEP(0.01);
|
END WHILE; |
SELECT id INTO @sink FROM locks WHERE id=2 FOR UPDATE; |
COMMIT; |
UPDATE coord SET val=1 WHERE name='done'; |
END// |
|
|
CREATE PROCEDURE control_worker() |
BEGIN
|
DECLARE v_count INT DEFAULT 0; |
DECLARE v_i INT DEFAULT 1; |
DECLARE v_errno INT; |
DECLARE v_level VARCHAR(16); |
DECLARE v_message LONGTEXT; |
DECLARE CONTINUE HANDLER FOR 1213 |
BEGIN |
GET DIAGNOSTICS v_count = NUMBER;
|
SET v_i=1; |
WHILE v_i <= v_count DO
|
GET DIAGNOSTICS CONDITION v_i
|
v_errno = MYSQL_ERRNO, v_level = CLASS_ORIGIN, v_message = MESSAGE_TEXT;
|
INSERT INTO diagnostics |
VALUES ('current_victim_control',v_i,v_errno,v_level,v_message); |
SET v_i=v_i+1; |
END WHILE; |
END; |
|
|
START TRANSACTION; |
SELECT id INTO @sink FROM locks WHERE id=1 FOR UPDATE; |
UPDATE coord SET val=1 WHERE name='event_locked'; |
WHILE (SELECT val FROM coord WHERE name='main_ready')=0 DO |
DO SLEEP(0.01);
|
END WHILE; |
DO SLEEP(1);
|
SELECT id INTO @sink FROM locks WHERE id=2 FOR UPDATE; |
COMMIT; |
UPDATE coord SET val=1 WHERE name='done'; |
END// |
DELIMITER ;
|
|
|
CREATE EVENT deadlock_event |
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 SECOND |
ON COMPLETION PRESERVE DO CALL worker(); |
|
|
SELECT SLEEP(2); |
SELECT val AS event_locked FROM coord WHERE name='event_locked'; |
START TRANSACTION; |
UPDATE weight SET v=v+1; |
SELECT id FROM locks WHERE id=2 FOR UPDATE; |
UPDATE coord SET val=1 WHERE name='main_ready'; |
SELECT SLEEP(1); |
SELECT id FROM locks WHERE id=1 FOR UPDATE; |
COMMIT; |
SELECT SLEEP(1); |
|
|
SELECT name,val FROM coord ORDER BY name; |
|
|
UPDATE coord SET val=0; |
CREATE EVENT control_event |
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 SECOND |
ON COMPLETION PRESERVE DO CALL control_worker(); |
SELECT SLEEP(2); |
SELECT val AS control_event_locked FROM coord WHERE name='event_locked'; |
START TRANSACTION; |
UPDATE weight SET v=v+1; |
SELECT id FROM locks WHERE id=2 FOR UPDATE; |
UPDATE coord SET val=1 WHERE name='main_ready'; |
SELECT id FROM locks WHERE id=1 FOR UPDATE; |
COMMIT; |
SELECT SLEEP(1); |
|
|
SELECT scenario,condition_no,mysql_errno, |
message_text LIKE '%*** WE ROLL BACK TRANSACTION%' AS has_report, |
LEFT(message_text,120) AS message_prefix |
FROM diagnostics ORDER BY scenario,condition_no; |
|
|
DROP DATABASE deadlock_diag; |
SET GLOBAL innodb_print_all_deadlocks=OFF; |
SET GLOBAL event_scheduler=OFF; |
Observed result
The alternate victim receives two 1213 conditions, but neither contains the detailed-report marker. The control captures the report through the same GET DIAGNOSTICS handler:
scenario condition_no mysql_errno has_report message_prefix
|
alternate_victim 1 1213 0 Deadlock found when trying to get lock; try restarting transaction
|
alternate_victim 2 1213 0 Deadlock found when trying to get lock; try restarting transaction
|
current_victim_control 1 1213 1 ... *** (1) TRANSACTION: ...
|
current_victim_control 2 1213 1 ... *** (1) TRANSACTION: ...
|
current_victim_control 3 1213 1 ... *** (1) TRANSACTION: ...
|
For the first schedule, the server log confirms that the main transaction held 103 row locks with 100 undo entries, the event transaction held two row locks, and InnoDB selected transaction (2), the event transaction:
*** WE ROLL BACK TRANSACTION (2)
|
Expected result
The event transaction selected as the alternate victim should receive a diagnostics condition containing the detailed deadlock report, including *** WE ROLL BACK TRANSACTION, just as the detector/victim control does. The report should be attached to the execution context that receives ER_LOCK_DEADLOCK, rather than being available only when that context also detects the cycle.
Attachments
Issue Links
- relates to
-
MDEV-30973 Enhance output of innodb deadlocks (SAMU-124, SAMU-131)
-
- Closed
-