| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- package main
- import (
- "git.ycl.pub/yl32940/TsDB2/DB"
- "fmt"
- "os"
- "time"
- )
- type Record struct {
- DB.BaseModel
- Name string `vrtx:"maxlen:32"`
- Age int64
- Score int64
- Dept string `vrtx:"maxlen:16"`
- }
- const dbPath = "no_commit_test.db"
- func main() {
- fmt.Println("==============================================")
- fmt.Println(" TsDB2 不手动 Commit 场景测试")
- fmt.Println("==============================================")
- failed := 0 // 任一场景失败则以非零码退出, 让 make test 能感知
- // ========== 场景 1: 只 Insert, 不 Commit, 直接 Close ==========
- fmt.Println("\n========== 场景 1: Insert → Close (无手动 Commit) ==========")
- os.Remove(dbPath)
- db1, _ := DB.Open(dbPath)
- // 使用默认 autoCommitDelay (1秒), 不手动禁用
- tbl1, _ := DB.UseTable[Record](db1, "test")
- for i := 1; i <= 10000; i++ {
- tbl1.Insert(&Record{
- Name: fmt.Sprintf("Emp%07d", i),
- Age: int64(20 + (i % 50)),
- Score: int64(i % 1000),
- Dept: fmt.Sprintf("dept_%d", i%10),
- })
- }
- fmt.Println(" 插入 10000 行 (未手动 Commit)")
- // 直接 Close — Close 内部会调用 Commit
- db1.Close()
- fi, _ := os.Stat(dbPath)
- fmt.Printf(" Close 后文件大小: %.2f MB\n", float64(fi.Size())/1024/1024)
- // 重开验证
- db1b, _ := DB.Open(dbPath)
- tbl1b, _ := DB.UseTable[Record](db1b, "test")
- cnt1, _ := tbl1b.Count()
- row, _ := tbl1b.Find(1)
- name1 := ""
- if row != nil {
- name1 = row.Name
- }
- db1b.Close()
- fmt.Printf(" 重开后 Count: %d, Find(1).Name: %s\n", cnt1, name1)
- if cnt1 == 10000 && name1 == "Emp0000001" {
- fmt.Println(" ✅ 场景 1 通过: Close 自动提交, 数据持久化")
- } else {
- fmt.Println(" ❌ 场景 1 失败: 数据丢失!")
- failed++
- }
- // ========== 场景 2: Insert → 等待自动提交 (防抖 1 秒) ==========
- fmt.Println("\n========== 场景 2: Insert → 等待 2 秒 (自动提交) ==========")
- os.Remove(dbPath)
- db2, _ := DB.Open(dbPath)
- // 默认 autoCommitDelay = 1 秒
- tbl2, _ := DB.UseTable[Record](db2, "test")
- for i := 1; i <= 5000; i++ {
- tbl2.Insert(&Record{
- Name: fmt.Sprintf("Emp%07d", i),
- Age: int64(20 + (i % 50)),
- Score: int64(i % 1000),
- Dept: fmt.Sprintf("dept_%d", i%10),
- })
- }
- fmt.Println(" 插入 5000 行 (未手动 Commit)")
- fmt.Println(" 等待 2 秒让自动提交触发...")
- time.Sleep(2 * time.Second)
- // 模拟崩溃: 不 Close, 直接退出 (用新进程打开同一个文件)
- // 先关闭 db2 但不让它 Commit (模拟异常)
- // 实际上 Close() 总会 Commit, 所以这里用另一种方式:
- // 我们直接重开文件, 看自动提交是否已经刷盘
- db2.Close()
- fi, _ = os.Stat(dbPath)
- fmt.Printf(" 等待后文件大小: %.2f MB\n", float64(fi.Size())/1024/1024)
- db2b, _ := DB.Open(dbPath)
- tbl2b, _ := DB.UseTable[Record](db2b, "test")
- cnt2, _ := tbl2b.Count()
- db2b.Close()
- fmt.Printf(" 重开后 Count: %d\n", cnt2)
- if cnt2 == 5000 {
- fmt.Println(" ✅ 场景 2 通过: 防抖自动提交生效")
- } else {
- fmt.Println(" ❌ 场景 2 失败: 自动提交未生效")
- failed++
- }
- // ========== 场景 3: 禁用自动提交 + 不手动 Commit + Close ==========
- fmt.Println("\n========== 场景 3: 禁用自动提交 → Insert → Close ==========")
- os.Remove(dbPath)
- db3, _ := DB.Open(dbPath)
- db3.SetAutoCommitDelay(0) // 禁用防抖
- tbl3, _ := DB.UseTable[Record](db3, "test")
- for i := 1; i <= 5000; i++ {
- tbl3.Insert(&Record{
- Name: fmt.Sprintf("Emp%07d", i),
- Age: int64(20 + (i % 50)),
- Score: int64(i % 1000),
- Dept: fmt.Sprintf("dept_%d", i%10),
- })
- }
- fmt.Println(" 插入 5000 行 (禁用自动提交, 未手动 Commit)")
- // Close 仍然会调用 Commit
- db3.Close()
- fi, _ = os.Stat(dbPath)
- fmt.Printf(" Close 后文件大小: %.2f MB\n", float64(fi.Size())/1024/1024)
- db3b, _ := DB.Open(dbPath)
- tbl3b, _ := DB.UseTable[Record](db3b, "test")
- cnt3, _ := tbl3b.Count()
- db3b.Close()
- fmt.Printf(" 重开后 Count: %d\n", cnt3)
- if cnt3 == 5000 {
- fmt.Println(" ✅ 场景 3 通过: Close 兜底提交生效")
- } else {
- fmt.Println(" ❌ 场景 3 失败: Close 兜底未生效")
- failed++
- }
- // ========== 场景 4: 脏页阈值自动提交 ==========
- fmt.Println("\n========== 场景 4: 大量 Insert 触发脏页阈值自动提交 ==========")
- os.Remove(dbPath)
- db4, _ := DB.Open(dbPath)
- db4.SetAutoCommitDelay(0) // 禁用防抖, 只靠脏页阈值
- tbl4, _ := DB.UseTable[Record](db4, "test")
- // 每行约 72 bytes → 16KB/页 ≈ 228 行/页
- // 脏页阈值 2000 页 → 约 456000 行触发一次自动提交
- // 插入 100000 行, 观察中间是否触发自动提交
- for i := 1; i <= 100000; i++ {
- tbl4.Insert(&Record{
- Name: fmt.Sprintf("Emp%07d", i),
- Age: int64(20 + (i % 50)),
- Score: int64(i % 1000),
- Dept: fmt.Sprintf("dept_%d", i%10),
- })
- if i%20000 == 0 {
- fi, _ := os.Stat(dbPath)
- fmt.Printf(" [%d 行] 文件大小: %.2f MB\n", i, float64(fi.Size())/1024/1024)
- }
- }
- fmt.Println(" 插入 100000 行 (仅靠脏页阈值自动提交)")
- // 不手动 Commit, 直接 Close
- db4.Close()
- fi, _ = os.Stat(dbPath)
- fmt.Printf(" Close 后文件大小: %.2f MB\n", float64(fi.Size())/1024/1024)
- db4b, _ := DB.Open(dbPath)
- tbl4b, _ := DB.UseTable[Record](db4b, "test")
- cnt4, _ := tbl4b.Count()
- row4, _ := tbl4b.Find(50000)
- name4 := ""
- if row4 != nil {
- name4 = row4.Name
- }
- db4b.Close()
- fmt.Printf(" 重开后 Count: %d, Find(50000).Name: %s\n", cnt4, name4)
- // Emp%07d 格式: 50000 → "Emp0050000" (7位数字)
- if cnt4 == 100000 && name4 == "Emp0050000" {
- fmt.Println(" ✅ 场景 4 通过: 脏页阈值 + Close 兜底")
- } else {
- fmt.Printf(" ❌ 场景 4 失败: 期望 Count=100000 Name=Emp0050000, 实际 Count=%d Name=%s\n", cnt4, name4)
- failed++
- }
- // ========== 场景 5: 连续 Insert 100 万行, 不手动 Commit ==========
- fmt.Println("\n========== 场景 5: 100 万行, 不手动 Commit ==========")
- os.Remove(dbPath)
- db5, _ := DB.Open(dbPath)
- // 使用默认自动提交 (1 秒防抖 + 脏页阈值)
- tbl5, _ := DB.UseTable[Record](db5, "test")
- t0 := time.Now()
- for i := 1; i <= 1_000_000; i++ {
- tbl5.Insert(&Record{
- Name: fmt.Sprintf("Emp%07d", i),
- Age: int64(20 + (i % 50)),
- Score: int64(i % 1000),
- Dept: fmt.Sprintf("dept_%d", i%10),
- })
- if i%200000 == 0 {
- fi, _ := os.Stat(dbPath)
- fmt.Printf(" [%d 行] 文件: %.1f MB, 耗时: %.1fs\n", i, float64(fi.Size())/1024/1024, time.Since(t0).Seconds())
- }
- }
- fmt.Printf(" 插入完成, 耗时: %.2fs\n", time.Since(t0).Seconds())
- // 直接 Close, 不手动 Commit
- db5.Close()
- fi, _ = os.Stat(dbPath)
- fmt.Printf(" Close 后文件: %.2f MB\n", float64(fi.Size())/1024/1024)
- db5b, _ := DB.Open(dbPath)
- tbl5b, _ := DB.UseTable[Record](db5b, "test")
- cnt5, _ := tbl5b.Count()
- row5a, _ := tbl5b.Find(1)
- row5b, _ := tbl5b.Find(1000000)
- name5a, name5b := "", ""
- if row5a != nil {
- name5a = row5a.Name
- }
- if row5b != nil {
- name5b = row5b.Name
- }
- db5b.Close()
- fmt.Printf(" 重开后 Count: %d, Find(1): %s, Find(1000000): %s\n", cnt5, name5a, name5b)
- if cnt5 == 1000000 && name5a == "Emp0000001" && name5b == "Emp1000000" {
- fmt.Println(" ✅ 场景 5 通过: 100 万行无手动 Commit, 数据完整!")
- } else {
- fmt.Println(" ❌ 场景 5 失败")
- failed++
- }
- //os.Remove(dbPath)
- fmt.Println("\n==============================================")
- fmt.Println(" 测试完成!")
- fmt.Println("==============================================")
- if failed > 0 {
- fmt.Printf(" ⚠️ 共 %d 个场景失败\n", failed)
- os.Exit(1)
- }
- }
|