概要
2026-09-13 对 Ubuntu 部署的只读分析发现:当前高频 database is locked 主要来自共享索引库 memory.v2.sqlite3,其多连接写入缺少覆盖全部入口的按库串行化;与此同时,runtime.sqlite 主库共享锁缺失仍有独立异常线索。两者属于需要一起梳理的 SQLite 锁生命周期问题,但尚未证明是同一个缺陷。
本 issue 聚焦索引库写入契约、事务边界及可观测性;#2948 跟踪后台轮次被全量重建阻塞,#2951 跟踪主库 sidecar divergence 与 GUI 重试放大。不要用索引竞争替代对主库锁丢失的独立归因。
环境与已确认的证据
- 运行二进制:
0.39.0 (e7bb6139),通过运行进程的 exe 核实,已包含 8bbd9d84 的 O_PATH 修复。不能继续将本次主库 sidecar 删除直接归因于已修复的普通 File::open/close 路径。
- 2026-09-13 05:50–06:10 UTC(北京时间 13:50–14:10),3614 条 journal 记录中:
- 245 次
memory index enqueue failed after canonical storage write。
- 1 次
memory index outbox apply failed; retaining rows for ordered retry。
- 246 条
Error code 5 是上述错误的多行明细,不是额外 246 次故障。
- 未见
runtime db begin immediate transaction still locked 或 runtime db transaction still locked。
/proc/locks 中索引 SHM offset 120 的写锁属于 Holon 进程;该进程有多个索引主库 FD。同进程不同连接仍可能竞争。
- 06:14:01 / 06:14:04 UTC 快照均见索引写锁,索引 WAL 从 17027992 增至 17052712 bytes;这不能证明同一事务持续持锁,也不能证明永久死锁。
- 三次快照未列出
runtime.sqlite 主库的 POSIX 共享锁,但存在其 SHM offset 128 的读锁,所采文件 nlink=1。尚无具体释放者的系统调用证据。
当前锁机制
| 路径 |
契约 |
维护锁 RuntimeDbLock |
独立 lock_path 上的 flock,Drop 解锁;不能替代 SQLite 事务锁 |
| 主库写入 |
按规范化数据库路径共享 ticket queue → Mutex<Connection> → BEGIN IMMEDIATE → commit/rollback → 释放 mutex/ticket |
| 主库普通读取 |
另外开连接,不走写队列 |
| 主库竞争等待 |
busy_timeout=30 秒;部分 BUSY/LOCKED 路径无限退避重试,等待时仍占 writer mutex/ticket |
| 索引库写入 |
多个 MemoryIndex 连接,busy_timeout=5 秒;各 AppStorage 的 mutex 不构成覆盖所有连接的按库写队列 |
代码风险与待验证假设
rebuild() 在首次 DELETE 后持有写事务,再执行 collect_documents() 的源读取与全量重建,扩大持锁窗口。它是高优先级竞争候选,但本轮未捕获持锁事务调用栈,不能认定采样中的锁必属 rebuild。
consume_pending_sources / consume_runtime_outbox 使用 deferred transaction,apply_pending_source_tx 先读 source_state 再写,存在快照升级失败风险。日志只有主错误码 5,未证实扩展码 SQLITE_BUSY_SNAPSHOT(517)。
- enqueue 失败后丢弃缓存连接、标 dirty 并通知后台;self-heal 可请求 rebuild,存在“竞争 → dirty → 更重重建 → 更多竞争”的潜在放大链,尚未证明该循环持续发生。
- enqueue 告警发生在 canonical storage write 之后;不能据此认定原业务数据写入失败。outbox apply 失败会保留未消费行。
源码定位(部署提交):
src/runtime_db/{connection,write_queue,mod}.rs
src/memory/index.rs:rebuild、consume_pending_sources、consume_runtime_outbox、apply_pending_source_tx
src/storage/index_outbox.rs、src/storage/mod.rs
src/host.rs:后台 self-heal / rebuild 调度
建议修复范围
- 为索引库定义按库共享的写入入口,覆盖 enqueue、消费、rebuild、查询触发的刷新,并保留跨进程竞争处理。
- 将慢源读取/计算移出写事务;若使用分批或 staging,必须同时保证原子可见性与游标一致性。
- 对读后写事务明确采用 IMMEDIATE 或整事务回滚重试;定义总等待/取消边界,而非仅增加 busy_timeout。
- 日志区分数据库角色、操作类型、扩展错误码,记录队列等待和事务持锁耗时。
- 主库共享锁缺失另行做有界系统调用取证,不再次连接生产库试探删除。
验收标准
调查边界
本轮只读取源码、journal 和 /proc 元数据;未连接生产 SQLite,未重启或修改服务,未改代码。没有完成锁释放者的系统调用归因,也没有运行修复测试。
概要
2026-09-13 对 Ubuntu 部署的只读分析发现:当前高频
database is locked主要来自共享索引库memory.v2.sqlite3,其多连接写入缺少覆盖全部入口的按库串行化;与此同时,runtime.sqlite主库共享锁缺失仍有独立异常线索。两者属于需要一起梳理的 SQLite 锁生命周期问题,但尚未证明是同一个缺陷。本 issue 聚焦索引库写入契约、事务边界及可观测性;#2948 跟踪后台轮次被全量重建阻塞,#2951 跟踪主库 sidecar divergence 与 GUI 重试放大。不要用索引竞争替代对主库锁丢失的独立归因。
环境与已确认的证据
0.39.0 (e7bb6139),通过运行进程的 exe 核实,已包含8bbd9d84的 O_PATH 修复。不能继续将本次主库 sidecar 删除直接归因于已修复的普通 File::open/close 路径。memory index enqueue failed after canonical storage write。memory index outbox apply failed; retaining rows for ordered retry。Error code 5是上述错误的多行明细,不是额外 246 次故障。runtime db begin immediate transaction still locked或runtime db transaction still locked。/proc/locks中索引 SHM offset 120 的写锁属于 Holon 进程;该进程有多个索引主库 FD。同进程不同连接仍可能竞争。runtime.sqlite主库的 POSIX 共享锁,但存在其 SHM offset 128 的读锁,所采文件 nlink=1。尚无具体释放者的系统调用证据。当前锁机制
RuntimeDbLockflock,Drop 解锁;不能替代 SQLite 事务锁Mutex<Connection>→BEGIN IMMEDIATE→ commit/rollback → 释放 mutex/ticketMemoryIndex连接,busy_timeout=5 秒;各 AppStorage 的 mutex 不构成覆盖所有连接的按库写队列代码风险与待验证假设
rebuild()在首次 DELETE 后持有写事务,再执行collect_documents()的源读取与全量重建,扩大持锁窗口。它是高优先级竞争候选,但本轮未捕获持锁事务调用栈,不能认定采样中的锁必属 rebuild。consume_pending_sources/consume_runtime_outbox使用 deferred transaction,apply_pending_source_tx先读 source_state 再写,存在快照升级失败风险。日志只有主错误码 5,未证实扩展码SQLITE_BUSY_SNAPSHOT(517)。源码定位(部署提交):
src/runtime_db/{connection,write_queue,mod}.rssrc/memory/index.rs:rebuild、consume_pending_sources、consume_runtime_outbox、apply_pending_source_txsrc/storage/index_outbox.rs、src/storage/mod.rssrc/host.rs:后台 self-heal / rebuild 调度建议修复范围
验收标准
调查边界
本轮只读取源码、journal 和
/proc元数据;未连接生产 SQLite,未重启或修改服务,未改代码。没有完成锁释放者的系统调用归因,也没有运行修复测试。