| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- 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)
- }
|