diff --git a/go/internal/governance/graph_sqlite.go b/go/internal/governance/graph_sqlite.go index 8e9b0f8..8f408c2 100644 --- a/go/internal/governance/graph_sqlite.go +++ b/go/internal/governance/graph_sqlite.go @@ -7,12 +7,16 @@ package governance #cgo LDFLAGS: -lsqlite3 #include #include + +// busy_timeout 是 Go/C 混合文件中直接使用 C 函数 +// sqlite3_busy_timeout 在 sqlite3.h 中声明 */ import "C" import ( "encoding/json" "fmt" + "os" "strings" "sync" "unicode" @@ -32,6 +36,18 @@ func NewSQLiteGraphStore(dbPath string) (*SQLiteGraphStore, error) { if dbPath == "" { dbPath = "/var/lib/memoryweave/graph.db" } + + // 清理 stale WAL/SHM 文件(防止旧进程崩溃后留下这些文件导致锁失败) + // 只有当主 db 文件存在时才清理(避免误删新建库的场景) + if _, err := os.Stat(dbPath); err == nil { + for _, suffix := range []string{"-wal", "-shm", "-journal"} { + f := dbPath + suffix + if _, err := os.Stat(f); err == nil { + os.Remove(f) + } + } + } + cPath := C.CString(dbPath) defer C.free(unsafe.Pointer(cPath)) @@ -43,6 +59,9 @@ func NewSQLiteGraphStore(dbPath string) (*SQLiteGraphStore, error) { return nil, fmt.Errorf("sqlite open graph: %s", msg) } + // 设 10s busy_timeout——等待旧进程/跨进程锁释放,不立即报 "database is locked" + C.sqlite3_busy_timeout(db, 10000) + gs := &SQLiteGraphStore{db: db, path: dbPath} if err := gs.migrate(); err != nil { C.sqlite3_close(db)