mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-11-14 22:43:17 +08:00
Running query, files, node, callers, callees, impact, context, explore or affected while `codegraph index` rebuilt a project could make the rebuild fail with "database is locked", and so could the hidden prompt-hook, which Claude Code runs on its own for structural prompts. Each opened the index read-write, so its open ran the writer's repairs: during the rebuild's bulk load they recreated the secondary indexes the indexer had dropped, and the indexer's next write, whose transaction had already read, failed with SQLITE_BUSY_SNAPSHOT (517). PR #2930 fixed the same thing for status. These commands now open the index read-only, through one helper, and leave migrations, index recovery and WAL maintenance to the writer: - query, files, node, callers, callees, impact, context, explore, affected and prompt-hook are read-only. explore and node run the MCP tool handler in process without a lifecycle, so they never sync or open another project. - While another live process holds rebuild.pid they say so in one line on stderr (a --json answer stays parseable), as status does. - The prompt hook stays out of a running rebuild altogether: the index is half-built until it ends, the MCP tools answer "rebuild in progress" meanwhile, and not opening it keeps the hook from holding the file the rebuild replaces. Its gate records the new outcome noop-rebuild. - The hook's one write, filling an empty segment vocabulary (issue #1142), goes through a writer connection of its own, opened only once it holds the index lock, which every index and sync holds while it writes. - status (read-only since PR #2930), sync, index, init and uninit are unchanged; the last four write. A read-only open migrates nothing. QueryBuilder.hasSchema lets each read that needs a later table or column answer as that migration's defaults would: files.generated (v9), unresolved_refs.status and name_tail (v8), and name_segment_vocab (v7). The status pending count from PR #2930 uses it too. Validation (Windows 11, Node 22.22): - The issue's interleaving, each command in another process inside the writer's edge transaction: on main all 14 command forms make the insert fail with errcode 517 and bring the 5 dropped edge indexes back; with this change all 14 inserts succeed and the indexes stay dropped. - Real rebuilds of excalidraw 95307fa1 (736 files) with query and the prompt hook looping beside them, default settings and with the resolution window forced: main failed 6 of 14 ("store worker: database is locked" with an empty index, or "database is locked" partway through resolution), and 12 of its 109 query runs failed at open with SQLITE_BUSY. This change failed 0 of 14, with 0 failures in 299 query and 284 hook runs and the same graph every time (14,236 nodes, 61,210 edges). - Old indexes: 24 command forms on indexes at schemas 4 to 16 (11 schemas rebuilt from a current index, plus indexes built by 0.9.9, 1.4.0, 1.5.0, 1.6.0 and 1.6.2): output identical to main's, which migrates first, 384 of 384. The schema stays as it was, except where the hook fills the vocabulary of a pre-v7 index; that writer's open migrates it, as every read-write open did. - Timing on excalidraw at rest, 22 interleaved runs per command: medians within -5.8% to +3.3%, -0.9% in total. - read-commands-during-rebuild.test.ts: 38/38 pass. With main's sources 35 fail; with only the CLI opens reverted 33, only the schema fallbacks 19, only the read-only vocabulary fill 2. Follow-up to PR #2930. Fixes #2913 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>