From 15e7ec5f1f3953aa7affe8a2af2b0eb6d42a3e94 Mon Sep 17 00:00:00 2001 From: weichen Date: Mon, 12 Oct 2026 14:57:03 +0000 Subject: [PATCH] Register instance_guard for copy and avoid recycled inodes Why: CI rejected the new table as missing from the storage-migrate copy list, and the replacement test passed on filesystems that reused the deleted inode. Evidence: SELF go test TestCopyOrderCoversAllFixtureTables and TestDatabaseReplacementRefusedBeforeOpen. Impact: SQLite to PostgreSQL copy keeps the guard row. The replacement test burns inodes until the new file is distinct. Refs: docs/recovery/u8-sqlite-instance-guard.md Co-authored-by: Cursor --- cmd/storage-migrate/main.go | 2 ++ internal/instanceguard/guard_test.go | 25 ++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/cmd/storage-migrate/main.go b/cmd/storage-migrate/main.go index cfee408..39bc0c2 100644 --- a/cmd/storage-migrate/main.go +++ b/cmd/storage-migrate/main.go @@ -295,6 +295,8 @@ var copyOrder = []string{ "login_keys", // U1 I3:服务实例 DB 身份(无外键;迁移须保留以免目标库丢锚) "agent_system_identity", + // U8:活动服务锁的库内标记(无外键;迁移须保留以免目标库丢掉锁根) + "instance_guard", } const controlDDL = ` diff --git a/internal/instanceguard/guard_test.go b/internal/instanceguard/guard_test.go index 9c125cc..b2c1807 100644 --- a/internal/instanceguard/guard_test.go +++ b/internal/instanceguard/guard_test.go @@ -75,9 +75,32 @@ func TestDatabaseReplacementRefusedBeforeOpen(t *testing.T) { if err := os.Remove(db); err != nil { t.Fatal(err) } - if err := os.WriteFile(db, []byte("replaced"), 0o600); err != nil { + raw, err := os.ReadFile(db + ".lock") + if err != nil { t.Fatal(err) } + rec, err := parseRecord(string(raw)) + if err != nil || rec == nil { + t.Fatal(err) + } + for i := 0; i < 16; i++ { + if err := os.WriteFile(db, []byte("replaced"), 0o600); err != nil { + t.Fatal(err) + } + _, ino, exists, err := statFile(db) + if err != nil { + t.Fatal(err) + } + if exists && ino != rec.DBIno { + break + } + if err := os.Remove(db); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "inode-burn-"+string(rune('a'+i))), []byte("x"), 0o600); err != nil { + t.Fatal(err) + } + } lease, err := Acquire(dir) if err != nil { t.Fatal(err)