Hi all,
I'd like to share a bug fix introduced by the following PRs:
- Master: https://github.com/apache/iotdb/pull/18389
- Dev/1.3: https://github.com/apache/iotdb/pull/18390
This bug may throw IndexOutOfBoundsException: Index 0 out of bounds for
length 0 in AlignedTVList.delete() / deleteTime() when a DELETE races with
a query that sorts the shared working TVList in place.
The root cause is a concurrency issue on TVList:
- The query path calls AlignedTVList.sort() in place on the shared (still
writable) working TVList. sort() is synchronized on the TVList instance and
rebuilds indices non-atomically (indices = new ArrayList<>() then fills it).
- The delete path (AlignedTVList.delete() / deleteTime() / delete(column) /
deleteColumn() and TVList.delete()) was not synchronized. A concurrent
DELETE could call indices.get(0) while indices was momentarily empty,
throwing IndexOutOfBoundsException, or read half-rebuilt indices and
silently delete wrong rows.
The fix makes the delete methods of AlignedTVList (and TVList.delete() for
the non-aligned path) synchronized on the same TVList instance as sort(),
matching the existing monitor already used by putAlignedValue / clone /
cloneForFlushSort.
A concurrency audit of the delete path was also done:
- All runtime delete paths converge to
TsFileProcessor.deleteDataInMemory(), which holds
flushQueryLock.writeLock() before touching the TVList, so the lock order
(flushQueryLock -> tvlist monitor) stays consistent with the query path and
no deadlock is introduced.
- WAL recovery paths only call memTable.delete() during single-threaded
startup, so there is no concurrent query/sort there.
Main changes include:
- Synchronize the delete methods of AlignedTVList (delete / deleteTime /
delete(column) / deleteColumn) and TVList.delete() with sort().
- Audit the lock order of the delete path to confirm no deadlock is
introduced.
Feedback and suggestions are welcome.
大家好,
我想分享以下 PR 中修复的一个并发问题:
- Master:https://github.com/apache/iotdb/pull/18389
- Dev/1.3:https://github.com/apache/iotdb/pull/18390
当 DELETE 与在共享的 working TVList 上执行原地排序的查询并发发生时,该问题可能抛出
IndexOutOfBoundsException: Index 0 out of bounds for length 0。
根本原因是 TVList 上的并发同步问题:
- 查询路径会调用 AlignedTVList.sort() 对共享(仍可写)的 working TVList 进行原地排序。sort() 对
TVList 实例加 synchronized,并以非原子方式重建 indices(先 indices = new
ArrayList<>(),再填充)。
- 删除路径(AlignedTVList.delete() / deleteTime() / delete(column) /
deleteColumn() 以及非对齐路径的 TVList.delete())此前没有加同步。并发的 DELETE 可能恰好在 indices
为空的瞬间调用 indices.get(0),从而抛出 IndexOutOfBoundsException,或者读到重建了一半的
indices,导致静默删除错误的行。
本次修复将 AlignedTVList 的删除方法与 sort() 在同一个 TVList 实例上设置为 synchronized,与
putAlignedValue / clone / cloneForFlushSort 已有的 monitor 保持一致。
同时对该修复进行了删除路径的并发审计:
- 所有运行时删除路径最终都汇聚到 TsFileProcessor.deleteDataInMemory(),该路径在访问 TVList 前持有
flushQueryLock.writeLock(),因此锁顺序(flushQueryLock -> tvlist
monitor)与查询路径保持一致,不会引入死锁。
- WAL 恢复路径仅在单线程启动阶段调用 memTable.delete(),不存在并发的查询/排序。
主要修改包括:
- 将 AlignedTVList 的删除方法(delete / deleteTime / delete(column) /
deleteColumn)与 TVList.delete() 与 sort() 同步。
- 审计删除路径的锁顺序,确认不会引入死锁。
欢迎大家提出反馈和建议。
Best regards,
Wenwei Shu

Reply via email to