# [Critical bug] The atomicity of the transaction is destroyed

## Issue

悲观事务的一个 critical bug，会导致悲观事务的原子性被破坏，可能引发数据索引不一致或丢数据问题。

### Bug 现象

* 事务写入的部分数据丢失：

* 若发生数据或索引丢失，用户侧可能看到的报错：

* Error 8021: inconsistent extra index PRIMARY, handle 60195209 not found in table

* Error 1105: can not be duplicated row, due to old row not found. handle 7321690 not found

* 日志中可能看到 ERROR 级别输出，该日志代表事务原子性被破坏：

* 2PC failed commit key after primary key committed

    * DML 执行失败，用户侧报错：

        * tikv aborts txn: Txn(Mvcc(PessimisticLockRolledBack {...}))

    * 冲突事务解锁失败，导致 DML 执行失败，没有数据丢失，可能的报错：

        * unexpected resolve err: abort: Txn(Mvcc(Committed {...}))

### 触发条件

悲观事务，且事务内第一条语句执行失败或内部重试，如发生 duplicate entry、lock wait timeout、write conflict 等错误，再次执行时修改的 key 集合发生变化，导致事务 primary key 变化。

其他事务与该事务失败语句加的锁发生写写冲突，并成功清理悲观锁，当再遇到该事务提交时写下的锁时，会直接回滚，导致事务原子性被破坏。

### Oncall issue

水滴筹 - v4.0.7 - 索引和数据不一致，<https://internal.pingcap.net/jira/browse/ONCALL-2264>

Bugfix PR：

<https://github.com/pingcap/tidb/pull/21689>

Docs：

悲观事务原子性被破坏问题，<https://docs.google.com/document/d/1zv6x63Aw1VuAYw6-NCiV_xSbL4HtYMmqJAOmBrtj99s/edit#heading=h.u727lnex5p2>

## Root Cause

悲观事务的 primary key 在第一条 DML 执行成功后才能被确定，如果其他事务成功清理该事务之前加的锁，TiDB 就会缓存该事务的回滚状态，之后遇到该事务的其他锁时会直接回滚，但有可能该事务最终提交成功，导致事务原子性被破坏。

## Diagnostic Steps

## Resolution

<https://github.com/pingcap/tidb/pull/21689>

## Workaround

N/A