
CodeGraph 并发锁设计全解析多进程共享 SQLite 索引如何互不干扰【免费下载链接】codegraphPre-indexed code knowledge graph, auto syncs on code changes, for Claude Code, Codex, Gemini, Cursor, OpenCode, AntiGravity, Kiro, CoPilot, and Hermes Agent — fewer tokens, fewer tool calls, 100% local项目地址: https://gitcode.com/GitHub_Trending/co0degr/codegraphCodeGraph 是一款 100% 本地运行的代码知识图谱工具它把整个项目预索引进一个本地 SQLite 文件供 Claude Code、Cursor、Codex、Gemini 等 AI 编程代理直接查询。而多进程共享同一个 SQLite 索引、却互不干扰正是它最硬核的工程细节之一CodeGraph 的并发锁设计让索引进程、git 钩子同步进程和 MCP 服务进程可以安全地读写同一个索引库读操作永远不被写操作阻塞从根源上消灭了database is locked报错。一、问题背景三个进程抢一个索引库CodeGraph 运行时同一个.codegraph/codegraph.db文件背后至少站着三类进程进程职责读写特征MCP 服务进程响应 AI 代理的查询工具调用高频读、偶发写文件监听/同步进程代码变更时增量更新索引持续写git 钩子进程提交时触发codegraph sync突发写SQLite 的默认日志模式下写锁会把所有读者挡在门外——代理一查询就卡死。CodeGraph 用三层防御解决这个问题全部代码可以在 src/db/index.ts 中阅读。二、第一层防线WAL 模式让读不挡写数据库连接初始化时CodeGraph 强制开启预写日志Write-Ahead Logging模式PRAGMA journal_mode WAL; PRAGMA synchronous NORMAL;在 WAL 模式下读者永远不需要等待写者写操作先进入-wal日志文件读操作直接从主库快照读取。官方测试tests/concurrent-locking.test.ts 专门验证了这一点一个连接持有排他写锁时另一个连接的查询依然能在毫秒级内完成而不是忙等或报错。 这也是 README 排障章节的建议如果codegraph status显示Journal:不是wal常见于网络盘或 WSL2 的/mnt分区请把项目移到本地磁盘。参见 README.md。三、第二层防线busy_timeout 从 120 秒缩短到 5 秒跨进程的写-写竞争比如 git 钩子同步和 MCP 服务同时写入靠有界等待处理。关键配置在 src/db/index.tsPRAGMA busy_timeout 5000; -- 必须最先设置这里有两个巧妙之处它必须在所有其他 PRAGMA 之前设置。打开数据库的瞬间如果别的进程正持有写锁后续的 pragma 和首条查询会等锁而不是直接抛错等待上限从旧版的 120 秒缩到 5 秒。旧值会让代理看起来像彻底冻结而 5 秒足以撑过一次正常的增量同步窗口超时就快速失败而非假死。四、跨进程文件锁PID 记录 独占创建 失效自愈SQL 层解决读写互斥应用层还需要一把粗粒度文件锁来防止多个进程同时执行破坏性重建如整库重索引。核心类FileLock位于 src/utils.ts并在 src/index.ts 中被挂到.codegraph/codegraph.lock路径上PID 追踪加锁时把process.pid写进锁文件竞争方读到锁后先检查持有进程是否存活独占创建使用wx标志写锁文件即使两个进程同时通过检查也只有一个能成功创建彻底堵住竞态窗口失效锁自愈进程被杀死的锁会留下僵尸锁。FileLock 通过 PID 存活探测 超时机制识别陈旧锁并自动清除避免用户手动处理一键解锁兜底万一仍然被卡住运行codegraph unlock即可移除陈旧锁文件CLI 参考 README.md相关行为测试见tests/cli-unlock.test.ts。进程内部则另有一把轻量的 Mutex 互斥锁保护同一进程内的并发任务如批量写入两层锁各司其职。五、连接复用MCP 工具不再开第二个连接早期版本有个隐蔽的自锁陷阱MCP 工具调用若携带projectPath参数会为同一个库再开一条连接两条连接互相争抢写锁。修复方案在 src/mcp/tools.ts——工具处理器发现路径解析到默认项目时直接复用现有实例绝不重复open。对应回归测试tests/concurrent-locking.test.ts 并发发射 6 个混合路径的工具调用断言全部成功且database is locked零出现。六、WAL 阀门让写日志涨不大、磁盘爆不了WAL 模式还有个隐藏风险批量建索引时-wal文件会疯狂膨胀曾实测 340MB 的库产生 5.9GB 的 WAL最终撑满磁盘。CodeGraph 的答案是WAL 检查点阀门实现见 src/db/wal-valve.ts软阈值默认 256MB随库大小按比例放大WAL 增量越过阈值时在工作线程上用PRAGMA wal_checkpoint(PASSIVE)回填——PASSIVE 模式永不阻塞写者离主线程执行保证主循环心跳不停转硬上限2× 软阈值 反压写者涨得太快时阀门会在事务间隙暂停写者直到一次完整回填落地这是磁盘跟不上时的诚实代价按增量而非绝对大小触发WAL 文件大小永远不会缩小阀门因此跟踪上次完整回填时的水位线只在真实积压增长时动作自愈兜底进程被杀后残留的巨型 WAL会在下次打开项目时被检查点并裁剪回 64MBsrc/db/index.ts测试见tests/wal-heal.test.ts。七、多代理场景的最佳实践 基于这套并发锁设计几条实用建议多个代理同时干活很安全查询走 WAL 快照互不阻塞写竞争最多等 5 秒索引变大不可怕-wal文件是正常机制空闲时会自动裁剪可用环境变量CODEGRAPH_WAL_VALVE_MB/CODEGRAPH_WAL_HEAL_MB微调阈值详见 README.mdWindows WSL 双端协作要分开SQLite 跨 WSL2/Windows 文件系统边界的锁不可靠官方建议给其中一端设置CODEGRAPH_DIR使用独立索引目录被锁卡住时的自救顺序先看codegraph status的Journal是否为wal→ 再跑codegraph unlock清陈旧锁 → 仍异常则检查是否跨系统盘共享了同一份.codegraph/。八、总结CodeGraph 的并发锁设计是一套教科书式的分层防御WAL 模式解决读写互斥5 秒有界 busy_timeout处理跨进程写竞争PID 文件锁守住破坏性操作的互斥门连接复用消除自锁陷阱WAL 阀门保证日志永不失控。五层机制协同工作让多个代理、多个进程、同一个本地 SQLite 索引从一句口号变成可被tests/concurrent-locking.test.ts 反复验证的工程事实——这也正是它能 100% 本地运行、省 token 省工具调用的底层底气。【免费下载链接】codegraphPre-indexed code knowledge graph, auto syncs on code changes, for Claude Code, Codex, Gemini, Cursor, OpenCode, AntiGravity, Kiro, CoPilot, and Hermes Agent — fewer tokens, fewer tool calls, 100% local项目地址: https://gitcode.com/GitHub_Trending/co0degr/codegraph创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考