| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- package migrate
- // 临时实验: 活拷文件自愈验证。用真实引擎打开(含 WAL 恢复) → Commit → Close,
- // 对比自愈前后的孤儿页口径。不会碰原件 (先拷到 t.TempDir)。
- // 用法: GO_LIVECOPY=<docker.db 路径> go test ./migrate -run TestLiveCopyHeal -v
- import (
- "fmt"
- "io"
- "os"
- "path/filepath"
- "testing"
- "git.ycl.pub/yl32940/TsDB2/DB/core"
- "git.ycl.pub/yl32940/TsDB2/internal/orphancheck"
- )
- func TestLiveCopyHeal(t *testing.T) {
- src := os.Getenv("GO_LIVECOPY")
- if src == "" {
- t.Skip("GO_LIVECOPY 未设置")
- }
- dst := filepath.Join(t.TempDir(), "docker.db")
- fin, err := os.Open(src)
- if err != nil {
- t.Fatal(err)
- }
- fout, err := os.Create(dst)
- if err != nil {
- t.Fatal(err)
- }
- if _, err := io.Copy(fout, fin); err != nil {
- t.Fatal(err)
- }
- fin.Close()
- fout.Close()
- before, err := orphancheck.Run(dst, orphancheck.Options{EngineBlobScan: true, SamplesPerType: 2})
- if err != nil {
- t.Fatal("自愈前取证:", err)
- }
- fmt.Printf("== 自愈前: analyzer 孤儿=%d (blob 感知=%d, 其中 WAL 残留 %d), 空闲链=%d (声明 %d), WALPending=%v\n",
- len(before.AnalyzerOrphans), len(before.Orphans), before.AnalyzerWalLeft, before.FreeCount, before.FreeDeclared, before.WALPending)
- db, err := core.OpenWithOptions(dst, core.OpenOptions{})
- if err != nil {
- t.Fatal("引擎打开:", err)
- }
- fmt.Printf("引擎打开成功 (WAL 恢复已执行)\n")
- if err := db.Commit(); err != nil {
- t.Fatal("Commit:", err)
- }
- if err := db.Close(); err != nil {
- t.Fatal("Close:", err)
- }
- fmt.Println("引擎 Commit+Close 完成")
- after, err := orphancheck.Run(dst, orphancheck.Options{EngineBlobScan: true, SamplesPerType: 2})
- if err != nil {
- t.Fatal("自愈后取证:", err)
- }
- fmt.Printf("== 自愈后: analyzer 孤儿=%d (blob 感知=%d, 其中 WAL 残留 %d), 空闲链=%d (声明 %d), WALPending=%v\n",
- len(after.AnalyzerOrphans), len(after.Orphans), after.AnalyzerWalLeft, after.FreeCount, after.FreeDeclared, after.WALPending)
- // 第二段: VACUUM 重建 — 行数据不动, 索引/空闲链/孤儿页全部重建到新文件。
- db2, err := core.OpenWithOptions(dst, core.OpenOptions{})
- if err != nil {
- t.Fatal("VACUUM 前打开:", err)
- }
- vres, err := db2.VACUUM()
- if err != nil {
- t.Fatal("VACUUM:", err)
- }
- fmt.Printf("VACUUM 完成: %d 字节 → %d 字节, 复制 %d 行\n", vres.OldFileSize, vres.NewFileSize, vres.RowsCopied)
- if err := db2.Close(); err != nil {
- t.Fatal("VACUUM 后 Close:", err)
- }
- final, err := orphancheck.Run(dst, orphancheck.Options{EngineBlobScan: true, SamplesPerType: 2})
- if err != nil {
- t.Fatal("VACUUM 后取证:", err)
- }
- fmt.Printf("== VACUUM 后: analyzer 孤儿=%d (blob 感知=%d, 其中 WAL 残留 %d), 空闲链=%d (声明 %d), WALPending=%v\n",
- len(final.AnalyzerOrphans), len(final.Orphans), final.AnalyzerWalLeft, final.FreeCount, final.FreeDeclared, final.WALPending)
- fmt.Println("最终文件保留在:", dst)
- if out := os.Getenv("GO_LIVEOUT"); out != "" {
- fin2, _ := os.Open(dst)
- fout2, err := os.Create(out)
- if err != nil {
- t.Fatal(err)
- }
- if _, err := io.Copy(fout2, fin2); err != nil {
- t.Fatal(err)
- }
- fin2.Close()
- fout2.Close()
- fmt.Println("已复制到:", out)
- }
- }
|