# [Known-Issues] truncate 多个表，时间漂移导致 DDL 阻塞

## Key Words

TiDB, DDL

## Description

需要 truncate 许多表，重新灌数据。发现如下问题：

1. 当前基本没有系统压力，DDL owner也正常，但是发现 DDL 已经阻塞。
2. 当前时间是 6月7号，并且数据库时间正常，但是已经执行完的 DDL 时间为何是 9 月份呢？
 
## Root Cause

背景情况说明：

- 系统在5月31号发生时间漂移，直接跳到 9月20号，然后有跳会到正常时间。
- tso 的计算方式是 `timestamp(ms)<< 18 + logic`，记为 `(ts,logic)`。
- tso 只会单调递增。所以如果系统漂移到之前的时间，tso 取的 ts 值也就不会发生变化了。
- 两种 `secondary key` 锁清理： 
    - `async cleanup` 查看 `primary key` 是否存在来清锁。
    - `resolve lock` 是查看 lock 的 ttl 是否过期来清锁。 每个 lock 都会有 n 秒的 lease 时间，记为 ttl.
        - 所以，lock 的 tso 的 ts 时间的 ttl 秒之后，才会 resolve 成功

根因分析：

- 系统时间漂移到9月20号，导致 tso 都是 9月20号的；
- 某个 prewrite 发生失败，导致 `secondary key` 锁残留；lock 的 tso 记为`(ts1,logic-1)`；
- 系统时间恢复正常，但是 tso 还是 `(ts1,logic-n)`，即 ts1 不会变，仅仅是 logic 值变化；
- 执行 ddl 的时候需要获取 tidb-server 的内存 mutex，然后到 tikv 获取下一个 `globalID`，最终会对该 Key 执行 resolve lock
- 该 key 正好有 lock 残留；由于取到的当前时间比 ts1 小，导致该 lock 不会过期，导致不断重试 resolve lock
- 导致其它 ddl 等待获取 tidb-server 的内存 mutex，卡住。即，其它所有 ddl 都卡住。

## Diagnostic Steps

发现 ddl 无法推进，查看 goroutine 出现如下信息，那么可以去确认 pd是否时间发生漂移

- 查看 goroutine ，可以看到某个 ddl 在进行 `GenGlobalIDs`/`resolveLocks` 等函数调用；
- 如果有其它 ddl ，都卡在了 `GenGlobalIDs`/`(*Mutex).Lock(...)`，并且耗时很长（比如这里耗时长的有几小时）；

如果 pd 的时间发生漂移，可以通过如下方式验证：

1. 查看 ddl job 时间是否正常
2. 查看 pd 日志验证时间是否发生漂移
    如果时间发生漂移，必然会出现如下错误日志。并且，会记录上次的时间和要设置的新时间。

    ```
    [ERROR] [tso.go:210]["system time may be incorrect"] [last=xxxx] [next=xxxxx] [error="[PD:common:ErrIncorrectSystemTime]...]
    ```

## Workaround

时间漂移导致 GC ， resolve lock 会有问题，导致系统不正常。整个系统都存在风险，这种情况下最好重新构建集群、迁移数据。

## Affected Version

All
