package main import ( "git.ycl.pub/yl32940/TsDB2/DB" "fmt" "os" "runtime" "time" ) // ========== 数据模型 ========== type Record struct { DB.BaseModel Name string `vrtx:"maxlen:32"` Age int64 Score int64 Dept string `vrtx:"maxlen:16"` } const dbPath = "memtest.db" const N = 200_000 // 20万行测试 func main() { os.Remove(dbPath) // ========== 1. 打开数据库, 禁用防抖, 只靠脏页阈值 ========== fmt.Println("========== 1. 打开数据库 ==========") db, err := DB.Open(dbPath) if err != nil { panic(err) } // 禁用防抖自动提交 — 测试脏页阈值是否独立工作 db.SetAutoCommitDelay(0) tbl, err := DB.UseTable[Record](db, "test") if err != nil { panic(err) } fmt.Println(" 表创建/打开成功") // ========== 2. 批量插入 + 内存监控 ========== fmt.Printf("\n========== 2. 插入 %d 行 (禁用防抖, 仅脏页阈值触发) ==========\n", N) runtime.GC() var mStart runtime.MemStats runtime.ReadMemStats(&mStart) t0 := time.Now() lastCommitTime := t0 commitCount := 0 for i := 0; i < N; i++ { rec := &Record{ Name: fmt.Sprintf("user_%d", i), Age: int64(20 + i%50), Score: int64(i % 1000), Dept: fmt.Sprintf("dept_%d", i%10), } if err := tbl.Insert(rec); err != nil { panic(err) } // 每 2 万行打印一次内存状态 if (i+1)%20000 == 0 { var m runtime.MemStats runtime.ReadMemStats(&m) allocMB := float64(m.Alloc) / 1024 / 1024 totalMB := float64(m.TotalAlloc) / 1024 / 1024 elapsed := time.Since(t0).Seconds() // 检查 BufferPool 状态 db.DebugDBState() fmt.Printf(" [%6d行] Alloc=%.1fMB Total=%.1fMB 耗时=%.1fs\n", i+1, allocMB, totalMB, elapsed) // 检查是否内存暴涨 (超过 500MB 就报警) if allocMB > 500 { fmt.Printf(" ⚠️ 内存Alloc超过500MB! 脏页阈值可能未生效!\n") } // 记录 commit 次数变化 now := time.Now() if now.Sub(lastCommitTime) > time.Second { commitCount++ lastCommitTime = now } } } insertTime := time.Since(t0) var mAfterInsert runtime.MemStats runtime.ReadMemStats(&mAfterInsert) fmt.Printf("\n 插入完成: 耗时=%.1fs, Alloc=%.1fMB\n", insertTime.Seconds(), float64(mAfterInsert.Alloc)/1024/1024) // ========== 3. 手动 Commit 剩余脏页 ========== fmt.Println("\n========== 3. 手动 Commit ==========") t1 := time.Now() if err := db.Commit(); err != nil { panic(err) } fmt.Printf(" Commit 耗时: %.1fs\n", time.Since(t1).Seconds()) // ========== 4. 验证行数 ========== fmt.Println("\n========== 4. 验证行数 ==========") count, err := tbl.Count() if err != nil { panic(err) } fmt.Printf(" 当前行数: %d (期望 %d)\n", count, N) if count != int64(N) { fmt.Printf(" ❌ 行数不匹配!\n") } else { fmt.Printf(" ✅ 行数正确\n") } // ========== 5. 关闭并重开验证持久化 ========== fmt.Println("\n========== 5. 关闭 → 重开验证 ==========") if err := db.Close(); err != nil { panic(err) } db2, err := DB.Open(dbPath) if err != nil { panic(err) } defer db2.Close() tbl2, err := DB.UseTable[Record](db2, "test") if err != nil { panic(err) } count2, err := tbl2.Count() if err != nil { panic(err) } fmt.Printf(" 重开后行数: %d (期望 %d)\n", count2, N) if count2 != int64(N) { fmt.Printf(" ❌ 数据丢失!\n") } else { fmt.Printf(" ✅ 数据完整持久化\n") } // ========== 6. 抽查几条数据 ========== fmt.Println("\n========== 6. 抽查数据 ==========") rec1, err := tbl2.Find(1) if err != nil { fmt.Printf(" Find(1) error: %v\n", err) } else { fmt.Printf(" Row#1: Name=%s Age=%d Score=%d Dept=%s\n", rec1.Name, rec1.Age, rec1.Score, rec1.Dept) } recLast, err := tbl2.Find(uint64(N)) if err != nil { fmt.Printf(" Find(%d) error: %v\n", N, err) } else { fmt.Printf(" Row#%d: Name=%s Age=%d Score=%d Dept=%s\n", N, recLast.Name, recLast.Age, recLast.Score, recLast.Dept) } // ========== 总结 ========== fmt.Println("\n========== 总结 ==========") var mFinal runtime.MemStats runtime.ReadMemStats(&mFinal) fmt.Printf(" 最终 Alloc=%.1fMB, TotalAlloc=%.1fMB\n", float64(mFinal.Alloc)/1024/1024, float64(mFinal.TotalAlloc)/1024/1024) fmt.Printf(" 插入耗时: %.1fs\n", insertTime.Seconds()) fmt.Printf(" 脏页阈值: %d 页 (≈%.0fMB)\n", 10000, float64(10000*16384)/1024/1024) // 判断是否内存泄漏 allocMB := float64(mFinal.Alloc) / 1024 / 1024 if allocMB < 200 { fmt.Println(" ✅ 内存控制良好 (< 200MB), 脏页阈值生效!") } else if allocMB < 500 { fmt.Println(" ⚠️ 内存偏高 (200-500MB), 可能需要调低阈值") } else { fmt.Println(" ❌ 内存泄漏! (> 500MB)") os.Exit(1) // 让 make test / CI 能感知失败 } //os.Remove(dbPath) }