Pessimistic RR: Resumed DELETE fails to see newly committed data, inconsistent with MySQL's Current Read behavior
- Dominant language
- Go
- Stars
- 40.5k
- Forks
- 6.2k
- PR merge metrics
- PR metrics pending
Description
## Bug Report
### 1. Minimal reproduce step (Required)Duplicate of #
/* --- Session Initialization --- */
DROP TABLE IF EXISTS mtest;
CREATE TABLE mtest(c0 CHAR(17), c1 CHAR(7), c2 TEXT);
INSERT IGNORE INTO mtest(c0, c1, c2) VALUES (" q軝", "_}娫vuf", "1W8jX>");
INSERT IGNORE INTO mtest(c0, c1) VALUES ("", "");
INSERT INTO mtest(c0, c2) VALUES ("8", "y");
INSERT INTO mtest(c0, c1, c2) VALUES ("+", "LEy", "G");
INSERT INTO mtest(c0, c2) VALUES ("J9HXﲼ>", "{");
/* --- Step-by-Step Execution --- */
-- Step 1: Session B starts a pessimistic transaction and locks all rows
/* Session B */ BEGIN PESSIMISTIC;
/* Session B */ UPDATE mtest SET c0 = ".%", c1 = "", c2 = ">av" WHERE TRUE;
-- Step 2: Session A attempts to delete rows where c1 is empty
/* Session A */ BEGIN PESSIMISTIC;
/* Session A */ DELETE FROM mtest WHERE c1 = ''; -- [EXPECTED: BLOCKED by Session B]
-- Step 3: Session B performs an additional update and commits
/* Session B */ UPDATE mtest SET c2 = "" WHERE c1 = 'LEy';
/* Session B */ COMMIT; -- Locks are released here. Session A should resume.
-- Step 4: Session A resumes the DELETE and commits
/* Session A */ -- (DELETE resumes and finishes)
/* Session A */ COMMIT;
-- Step 5: Check the final state
SELECT * FROM mtest; - - [.%, , >av, .%, , >av, .%, , >av, .%, , >av, .%, , >av]
### 2. What did you expect to see? (Required)
In REPEATABLE-READ isolation with pessimistic mode, TiDB is expected to follow MySQL compatibility for DML statements (Current Read).
Since Session B committed changes that set c1 = '' for all rows, Session A's DELETE statement, upon being unblocked, should re-evaluate the rows, see the newly committed values, and delete the matching rows. The final table should not contain the rows that Session B just updated to c1=''.
### 3. What did you see instead (Required)
Session A's DELETE statement silently skipped the rows modified by Session B. After both transactions committed, the rows that should have been deleted still exist in the table with the values committed by Session B.
mysql> SELECT * FROM mtest;
+------+----+------+
| c0 | c1 | c2 |
+------+----+------+
| .% | | >av | -- This row matches c1='' but was NOT deleted!
| .% | | >av |
| .% | | >av |
| .% | | >av |
| .% | | >av |
+------+----+------+
This indicates a visibility failure in the lock-wait-and-resume logic, where the resumed statement performs a "Stale Read" using an outdated snapshot instead of refreshing its ForUpdateTS to see the latest committed data.
### 4. What is your TiDB version? (Required)
Release Version: v7.5.1
Edition: Community
Git Commit Hash: https://github.com/pingcap/tidb/commit/7d16cc79e81bbf573124df3fd9351c26963f3e70
Git Branch: heads/refs/tags/v7.5.1
UTC Build Time: 2024-02-27 14:28:32
GoVersion: go1.21.6
Race Enabled: false
Check Table Before Drop: false
Store: tikv
Contributor guide
Assessment
This issue has not been assessed yet.