Summary
SetMeta / SetMetaInt (DbWriter.cs:1888-1894) issue an UPSERT against the meta key/value table without wrapping it in a transaction or sharing the caller's transaction. When the writer process crashes between the metadata UPDATE and the next dependent write (e.g. clearing a readiness bit, then writing rows under that schema), the on-disk DB is left with metadata that says "schema vN" but rows that match vN-1, or vice versa. Because there is no commit boundary, recovery has to make a best-guess decision about which side is "real".
Where
src/CodeIndex/Database/DbWriter.cs:1888-1894 (SetMeta)
- Callers across
IndexCommandRunner and DbContext migration paths
Suggested approach
(1) Audit every SetMeta / SetMetaInt call site and require either an enclosing BeginTransaction (existing pattern via _transactionDepth) or a single statement that the caller can recover from. (2) Add a SetMetaWithGuard(key, value, Action commit) helper that opens a transaction, performs the UPSERT, runs commit() (the dependent write), then commits, so the metadata stamp and the dependent state become atomic. (3) Add an integrity test that kill -9 between metadata write and dependent write leaves the DB in a recoverable, well-defined state (either both old or both new). (4) Document the contract in DEVELOPER_GUIDE under "Metadata invariants".
Summary
SetMeta/SetMetaInt(DbWriter.cs:1888-1894) issue an UPSERT against themetakey/value table without wrapping it in a transaction or sharing the caller's transaction. When the writer process crashes between the metadata UPDATE and the next dependent write (e.g. clearing a readiness bit, then writing rows under that schema), the on-disk DB is left with metadata that says "schema vN" but rows that match vN-1, or vice versa. Because there is no commit boundary, recovery has to make a best-guess decision about which side is "real".Where
src/CodeIndex/Database/DbWriter.cs:1888-1894(SetMeta)IndexCommandRunnerandDbContextmigration pathsSuggested approach
(1) Audit every
SetMeta/SetMetaIntcall site and require either an enclosingBeginTransaction(existing pattern via_transactionDepth) or a single statement that the caller can recover from. (2) Add aSetMetaWithGuard(key, value, Action commit)helper that opens a transaction, performs the UPSERT, runscommit()(the dependent write), then commits, so the metadata stamp and the dependent state become atomic. (3) Add an integrity test thatkill -9between metadata write and dependent write leaves the DB in a recoverable, well-defined state (either both old or both new). (4) Document the contract in DEVELOPER_GUIDE under "Metadata invariants".