PostgreSQL: concurrent DeleteTable calls exhaust a shared pool waiting on a second connection
维护者通常 4 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 55/100
调研方向
Read crates/storage-postgres/src/worker_store.rs at process_transitions and crates/storage-postgres/src/lib.rs at the data_conn branch to trace when the catalog and data pools are shared. Then inspect backup_engine::restore_server_slot_count for the semaphore pattern and tests around DeleteTable and drop_table_storage. Done means concurrent calls with one database and pool size N complete promptly, with no rows left DELETING.
由索引模型根据 Issue 内容生成。
描述
Where
crates/storage-postgres/src/worker_store.rs, process_transitions: the pass opens a catalog transaction (self.pool.begin()), selects the candidate row, and then calls drop_table_storage(&self.data_pool, ...), which begins a second transaction on data_pool. When no separate data database is configured, data_pool is a clone of the catalog pool (crates/storage-postgres/src/lib.rs, the data_conn branch), so both transactions come from one pool.
This applies to the pass DeleteTable runs for its own table (finish_table_delete, PR #504) and to the poller pass. The poller runs one pass at a time, so it needs two connections; DeleteTable calls run concurrently, one scoped pass each.
Measured
PostgreSQL 16.15, one scratch database for catalog and data, pool_size 10, no poller running, concurrent DeleteTable calls each awaiting its scoped pass (probe kept at issues/pr-sweep-2026-10-26/504-lock-timeout/v-probe-pool.rs.txt on the development host; not part of the tree):
| Concurrent DeleteTable calls | Response time | Rows left DELETING |
|---|---|---|
| 5 | all within 0.12 s | 0 |
| 24 | all 24 answered after 30.07 s | 20 |
With more concurrent calls than the pool has connections, every connection is held by a catalog transaction waiting for a second connection that none can get, until sqlx's 30 s acquire timeout fails the drop. The clients get TableStatus: DELETING (the acquire failure takes the existing "drop failed, leave the row for the poller" path), and the poller finishes the rows once connections are free. No data is lost; the cost is 30 s of latency on each call and a pool that serves nothing else for that time.
Not measured with a separate data database, where the two pools are distinct and the deadlock cannot form.
Suggested fix
Cap concurrent scoped passes at pool_size / 2 with a semaphore taken before self.pool.begin(), which leaves each pass a connection for its second acquire; backup_engine::restore_server_slot_count does the same for restores. Alternatively, when data_pool is the catalog pool, run the drop on the catalog transaction's own connection, which is a larger change to drop_table_storage.
A test: with pool_size N and one database, issue 2N concurrent DeleteTable calls on 2N tables and assert every call returns within a few seconds and no row is left DELETING after the calls return.
- 主要语言
- Rust
- 星标
- 517
- 派生
- 60
- 平均合并
- 4 天 10 小时
- 30 天内合并 PR
- 37
环境准备
- 提供 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
ExtendDB/extenddb 的其他 Issue
-
难度 2/5 3-5 天 新手友好度 65/100
维护者通常 4 天内回复
-
documentation
难度 2/5 1-3 小时 新手友好度 84/100
ExtendDB/extenddb#658 · 1 条评论 ·
维护者通常 4 天内回复
-
backend:postgresql bug
难度 2/5 1-3 小时 新手友好度 70/100
维护者通常 4 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 4 天内回复
-
backend:mongodb bug
难度 2/5 1-3 小时 新手友好度 77/100
维护者通常 4 天内回复
查看 ExtendDB/extenddb 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 76/100
维护者通常 1 天内回复
-
area:ci kind:bug priority:p3 ready
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 1 天内回复
-
tech-debt
难度 2/5 1-3 小时 新手友好度 72/100
srikanth235/centraid#1155 ·
维护者通常 1 天内回复
-
dotfiles: failed batch untrack removes earlier tracking declarations可能已有人在做 @jdx 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 2 天内回复