SELECT FOR UPDATE does not form expected deadlock with concurrent full-table UPDATE under RC/RR
- Dominant language
- Go
- Stars
- 40.5k
- Forks
- 6.2k
- PR merge metrics
- PR metrics pending
Description
## Bug Report
Please answer these questions before submitting your issue. Thanks!
### 1. Minimal reproduce step (Required)
Run the following test on TiDB v8.5.6. The issue can be reproduced under both READ COMMITTED and REPEATABLE READ.
Step1: Create the initial DBMS state:
```sql
DROP TABLE IF EXISTS t0;
CREATE TABLE t0(
c0 BOOLEAN UNIQUE,
c1 REAL ZEROFILL NOT NULL,
c2 BIGINT,
c3 VARCHAR(100) UNIQUE NOT NULL
);
INSERT INTO t0 VALUES (NULL, 0.71535, 807633510, '');
INSERT INTO t0 VALUES (1, 0.12098, 1600742384, '0.5007103978381064');
INSERT INTO t0 VALUES (2, 0.198, 16007384, '0.50071081064');
```
Step2: Execute the transaction statements in the given order:
Use two sessions.
Session 102:
```sql
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
SELECT * FROM t0 WHERE TRUE FOR UPDATE;
COMMIT;
```
Session 103:
```sql
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
UPDATE t0 SET c2 = 3141 WHERE c0 = 2;
UPDATE t0 SET c2 = DEFAULT, c0 = DEFAULT WHERE TRUE;
COMMIT;
```
Execute the statements in this order:
```sql
[102-0] BEGIN;
[103-0] BEGIN;
[103-1] UPDATE t0 SET c2 = 3141 WHERE c0 = 2;
[102-1] SELECT * FROM t0 WHERE TRUE FOR UPDATE;
-- This statement becomes blocked.
[103-2] UPDATE t0 SET c2 = DEFAULT, c0 = DEFAULT WHERE TRUE;
[102-2] COMMIT;
[102-1] SELECT * FROM t0 WHERE TRUE FOR UPDATE;
-- This statement becomes resumed.
[103-3] COMMIT;
```
Repeat the same schedule with:
```sql
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
```
### 2. What did you expect to see? (Required)
I expected TiDB to report a deadlock.
The expected lock dependency is:
Transaction 103 first updates and locks the row where c0 = 2.
Transaction 102 executes:
```sql
SELECT * FROM t0 WHERE TRUE FOR UPDATE;
```
It should lock other rows and then wait for Transaction 103's locked row.
Transaction 103 then executes:
```sql
UPDATE t0 SET c2 = DEFAULT, c0 = DEFAULT WHERE TRUE;
```
It should try to update the rows locked by Transaction 102.
Therefore:
Transaction 102 waits for Transaction 103.
Transaction 103 waits for Transaction 102.
A deadlock should be detected.
Expected error:
```sql
[103-2] UPDATE t0 SET c2 = DEFAULT, c0 = DEFAULT WHERE TRUE; -- when the update statement is executed
[102-1] SELECT * FROM t0 WHERE TRUE FOR UPDATE; -- the deadlock happened
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
```
This is also the behavior observed on MySQL 8.4.9 and MariaDB 12.2.2 under both READ COMMITTED and REPEATABLE READ.
### 3. What did you see instead (Required)
In TiDB v8.5.6, under both READ COMMITTED and REPEATABLE READ, no deadlock is reported.
After executing:
```sql
UPDATE t0 SET c2 = DEFAULT, c0 = DEFAULT WHERE TRUE;
COMMIT;
```
the blocked statement:
```sql
mysql> SELECT * FROM t0 WHERE TRUE FOR UPDATE;
+------+---------+------+--------------------+
| c0 | c1 | c2 | c3 |
+------+---------+------+--------------------+
| NULL | 0.71535 | NULL | |
| NULL | 0.12098 | NULL | 0.5007103978381064 |
| NULL | 0.198 | NULL | 0.50071081064 |
+------+---------+------+--------------------+
```
is unblocked and returns 3 rows normally.
This is inconsistent with MySQL 8.4.9, where the same schedule reports a deadlock.
### 4. What is your TiDB version? (Required)
```sql
mysql> select version();
+--------------------+
| version() |
+--------------------+
| 8.0.11-TiDB-v8.5.6 |
+--------------------+
```
Contributor guide
Assessment
This issue has not been assessed yet.