Zhengcy05 commented on issue #8197:
URL: 
https://github.com/apache/incubator-seata/issues/8197#issuecomment-5276818193

   I looked into this issue, and the evidence points to a race between the 
initial commit cleanup and the scheduled async-commit worker, rather than a 
late branch registration.
   
   For an AT transaction, `DefaultCore.commit()` changes the global status to 
`AsyncCommitting` before `globalSession.clean()` has finished releasing all 
file locks. The scheduled `handleAsyncCommitting()` task can observe that 
status and call `doGlobalCommit(..., true)` without acquiring the same 
`GlobalSession` lock.
   
   The async commit path then removes committed `BranchSession` objects while 
`FileLockManager.releaseGlobalSessionLock()` is iterating the same `ArrayList`, 
which explains the `ConcurrentModificationException`.
   
   This also explains the residual lock: while the status is `AsyncCommitting`, 
`GlobalSession.unlockBranch()` assumes that the initial global cleanup has 
already released the lock and skips the per-branch unlock. If that branch is 
removed after the initial cleanup aborts, subsequent cleanup can no longer find 
it, leaving the entry in `FileLocker.LOCK_MAP`.
   
   I suggest serializing the scheduled async-commit handling with the same 
`GlobalSession` lock and rechecking the status inside the lock. A snapshot-only 
change in `FileLockManager` would avoid the iterator exception but would not 
guarantee that a concurrently removed branch has been unlocked.
   
   Below is my understanding of the timing of this bug。
   ```mermaid
   sequenceDiagram
       autonumber
       participant A as Commit Thread A
       participant GS as GlobalSession
       participant BL as branchSessions (ArrayList)
       participant B as Async Commit Thread B
   
       A->>GS: Acquire GlobalSession lock
       activate A
       A->>GS: Change status to AsyncCommitting
       Note over A,GS: Global lock cleanup has not finished
   
       B->>GS: Scheduled task observes AsyncCommitting
       activate B
       Note over B,GS: Thread B does not acquire the GlobalSession lock
   
       A->>BL: Iterate branches to release global locks
       loop For each BranchSession
           A->>BL: Read next branch
       end
   
       B->>B: Commit branch successfully
       B->>BL: Remove committed BranchSession
   
       BL--xA: Iterator detects concurrent modification
       Note over A,BL: ConcurrentModificationException
       deactivate A
   
       Note over GS,BL: Cleanup stops before all global locks are released
       deactivate B
   ```
   Chinese Version
   ```mermaid
   sequenceDiagram
       autonumber
       participant A as 提交线程 A
       participant GS as GlobalSession
       participant BL as branchSessions(ArrayList)
       participant B as 异步提交线程 B
   
       A->>GS: 获取 GlobalSession 锁
       activate A
       A->>GS: 将状态修改为 AsyncCommitting
       Note over A,GS: 此时全局锁清理尚未完成
   
       B->>GS: 定时任务发现 AsyncCommitting 状态
       activate B
       Note over B,GS: 线程 B 没有获取 GlobalSession 锁
   
       A->>BL: 遍历分支并释放全局锁
       loop 遍历每个 BranchSession
           A->>BL: 读取下一个分支
       end
   
       B->>B: 分支提交成功
       B->>BL: 删除已提交的 BranchSession
   
       BL--xA: 迭代器检测到并发修改
       Note over A,BL: 抛出 ConcurrentModificationException
       deactivate A
   
       Note over GS,BL: 清理被中断,部分全局锁未能释放
       deactivate B
   ```
   
   If this direction looks good, I’d like to work on it and add a concurrency 
regression test.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to