main.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. package main
  2. import (
  3. "git.ycl.pub/yl32940/TsDB2/DB"
  4. "fmt"
  5. "os"
  6. "time"
  7. )
  8. type Record struct {
  9. DB.BaseModel
  10. Name string `vrtx:"maxlen:32"`
  11. Age int64
  12. Score int64
  13. Dept string `vrtx:"maxlen:16"`
  14. }
  15. const dbPath = "no_commit_test.db"
  16. func main() {
  17. fmt.Println("==============================================")
  18. fmt.Println(" TsDB2 不手动 Commit 场景测试")
  19. fmt.Println("==============================================")
  20. failed := 0 // 任一场景失败则以非零码退出, 让 make test 能感知
  21. // ========== 场景 1: 只 Insert, 不 Commit, 直接 Close ==========
  22. fmt.Println("\n========== 场景 1: Insert → Close (无手动 Commit) ==========")
  23. os.Remove(dbPath)
  24. db1, _ := DB.Open(dbPath)
  25. // 使用默认 autoCommitDelay (1秒), 不手动禁用
  26. tbl1, _ := DB.UseTable[Record](db1, "test")
  27. for i := 1; i <= 10000; i++ {
  28. tbl1.Insert(&Record{
  29. Name: fmt.Sprintf("Emp%07d", i),
  30. Age: int64(20 + (i % 50)),
  31. Score: int64(i % 1000),
  32. Dept: fmt.Sprintf("dept_%d", i%10),
  33. })
  34. }
  35. fmt.Println(" 插入 10000 行 (未手动 Commit)")
  36. // 直接 Close — Close 内部会调用 Commit
  37. db1.Close()
  38. fi, _ := os.Stat(dbPath)
  39. fmt.Printf(" Close 后文件大小: %.2f MB\n", float64(fi.Size())/1024/1024)
  40. // 重开验证
  41. db1b, _ := DB.Open(dbPath)
  42. tbl1b, _ := DB.UseTable[Record](db1b, "test")
  43. cnt1, _ := tbl1b.Count()
  44. row, _ := tbl1b.Find(1)
  45. name1 := ""
  46. if row != nil {
  47. name1 = row.Name
  48. }
  49. db1b.Close()
  50. fmt.Printf(" 重开后 Count: %d, Find(1).Name: %s\n", cnt1, name1)
  51. if cnt1 == 10000 && name1 == "Emp0000001" {
  52. fmt.Println(" ✅ 场景 1 通过: Close 自动提交, 数据持久化")
  53. } else {
  54. fmt.Println(" ❌ 场景 1 失败: 数据丢失!")
  55. failed++
  56. }
  57. // ========== 场景 2: Insert → 等待自动提交 (防抖 1 秒) ==========
  58. fmt.Println("\n========== 场景 2: Insert → 等待 2 秒 (自动提交) ==========")
  59. os.Remove(dbPath)
  60. db2, _ := DB.Open(dbPath)
  61. // 默认 autoCommitDelay = 1 秒
  62. tbl2, _ := DB.UseTable[Record](db2, "test")
  63. for i := 1; i <= 5000; i++ {
  64. tbl2.Insert(&Record{
  65. Name: fmt.Sprintf("Emp%07d", i),
  66. Age: int64(20 + (i % 50)),
  67. Score: int64(i % 1000),
  68. Dept: fmt.Sprintf("dept_%d", i%10),
  69. })
  70. }
  71. fmt.Println(" 插入 5000 行 (未手动 Commit)")
  72. fmt.Println(" 等待 2 秒让自动提交触发...")
  73. time.Sleep(2 * time.Second)
  74. // 模拟崩溃: 不 Close, 直接退出 (用新进程打开同一个文件)
  75. // 先关闭 db2 但不让它 Commit (模拟异常)
  76. // 实际上 Close() 总会 Commit, 所以这里用另一种方式:
  77. // 我们直接重开文件, 看自动提交是否已经刷盘
  78. db2.Close()
  79. fi, _ = os.Stat(dbPath)
  80. fmt.Printf(" 等待后文件大小: %.2f MB\n", float64(fi.Size())/1024/1024)
  81. db2b, _ := DB.Open(dbPath)
  82. tbl2b, _ := DB.UseTable[Record](db2b, "test")
  83. cnt2, _ := tbl2b.Count()
  84. db2b.Close()
  85. fmt.Printf(" 重开后 Count: %d\n", cnt2)
  86. if cnt2 == 5000 {
  87. fmt.Println(" ✅ 场景 2 通过: 防抖自动提交生效")
  88. } else {
  89. fmt.Println(" ❌ 场景 2 失败: 自动提交未生效")
  90. failed++
  91. }
  92. // ========== 场景 3: 禁用自动提交 + 不手动 Commit + Close ==========
  93. fmt.Println("\n========== 场景 3: 禁用自动提交 → Insert → Close ==========")
  94. os.Remove(dbPath)
  95. db3, _ := DB.Open(dbPath)
  96. db3.SetAutoCommitDelay(0) // 禁用防抖
  97. tbl3, _ := DB.UseTable[Record](db3, "test")
  98. for i := 1; i <= 5000; i++ {
  99. tbl3.Insert(&Record{
  100. Name: fmt.Sprintf("Emp%07d", i),
  101. Age: int64(20 + (i % 50)),
  102. Score: int64(i % 1000),
  103. Dept: fmt.Sprintf("dept_%d", i%10),
  104. })
  105. }
  106. fmt.Println(" 插入 5000 行 (禁用自动提交, 未手动 Commit)")
  107. // Close 仍然会调用 Commit
  108. db3.Close()
  109. fi, _ = os.Stat(dbPath)
  110. fmt.Printf(" Close 后文件大小: %.2f MB\n", float64(fi.Size())/1024/1024)
  111. db3b, _ := DB.Open(dbPath)
  112. tbl3b, _ := DB.UseTable[Record](db3b, "test")
  113. cnt3, _ := tbl3b.Count()
  114. db3b.Close()
  115. fmt.Printf(" 重开后 Count: %d\n", cnt3)
  116. if cnt3 == 5000 {
  117. fmt.Println(" ✅ 场景 3 通过: Close 兜底提交生效")
  118. } else {
  119. fmt.Println(" ❌ 场景 3 失败: Close 兜底未生效")
  120. failed++
  121. }
  122. // ========== 场景 4: 脏页阈值自动提交 ==========
  123. fmt.Println("\n========== 场景 4: 大量 Insert 触发脏页阈值自动提交 ==========")
  124. os.Remove(dbPath)
  125. db4, _ := DB.Open(dbPath)
  126. db4.SetAutoCommitDelay(0) // 禁用防抖, 只靠脏页阈值
  127. tbl4, _ := DB.UseTable[Record](db4, "test")
  128. // 每行约 72 bytes → 16KB/页 ≈ 228 行/页
  129. // 脏页阈值 2000 页 → 约 456000 行触发一次自动提交
  130. // 插入 100000 行, 观察中间是否触发自动提交
  131. for i := 1; i <= 100000; i++ {
  132. tbl4.Insert(&Record{
  133. Name: fmt.Sprintf("Emp%07d", i),
  134. Age: int64(20 + (i % 50)),
  135. Score: int64(i % 1000),
  136. Dept: fmt.Sprintf("dept_%d", i%10),
  137. })
  138. if i%20000 == 0 {
  139. fi, _ := os.Stat(dbPath)
  140. fmt.Printf(" [%d 行] 文件大小: %.2f MB\n", i, float64(fi.Size())/1024/1024)
  141. }
  142. }
  143. fmt.Println(" 插入 100000 行 (仅靠脏页阈值自动提交)")
  144. // 不手动 Commit, 直接 Close
  145. db4.Close()
  146. fi, _ = os.Stat(dbPath)
  147. fmt.Printf(" Close 后文件大小: %.2f MB\n", float64(fi.Size())/1024/1024)
  148. db4b, _ := DB.Open(dbPath)
  149. tbl4b, _ := DB.UseTable[Record](db4b, "test")
  150. cnt4, _ := tbl4b.Count()
  151. row4, _ := tbl4b.Find(50000)
  152. name4 := ""
  153. if row4 != nil {
  154. name4 = row4.Name
  155. }
  156. db4b.Close()
  157. fmt.Printf(" 重开后 Count: %d, Find(50000).Name: %s\n", cnt4, name4)
  158. // Emp%07d 格式: 50000 → "Emp0050000" (7位数字)
  159. if cnt4 == 100000 && name4 == "Emp0050000" {
  160. fmt.Println(" ✅ 场景 4 通过: 脏页阈值 + Close 兜底")
  161. } else {
  162. fmt.Printf(" ❌ 场景 4 失败: 期望 Count=100000 Name=Emp0050000, 实际 Count=%d Name=%s\n", cnt4, name4)
  163. failed++
  164. }
  165. // ========== 场景 5: 连续 Insert 100 万行, 不手动 Commit ==========
  166. fmt.Println("\n========== 场景 5: 100 万行, 不手动 Commit ==========")
  167. os.Remove(dbPath)
  168. db5, _ := DB.Open(dbPath)
  169. // 使用默认自动提交 (1 秒防抖 + 脏页阈值)
  170. tbl5, _ := DB.UseTable[Record](db5, "test")
  171. t0 := time.Now()
  172. for i := 1; i <= 1_000_000; i++ {
  173. tbl5.Insert(&Record{
  174. Name: fmt.Sprintf("Emp%07d", i),
  175. Age: int64(20 + (i % 50)),
  176. Score: int64(i % 1000),
  177. Dept: fmt.Sprintf("dept_%d", i%10),
  178. })
  179. if i%200000 == 0 {
  180. fi, _ := os.Stat(dbPath)
  181. fmt.Printf(" [%d 行] 文件: %.1f MB, 耗时: %.1fs\n", i, float64(fi.Size())/1024/1024, time.Since(t0).Seconds())
  182. }
  183. }
  184. fmt.Printf(" 插入完成, 耗时: %.2fs\n", time.Since(t0).Seconds())
  185. // 直接 Close, 不手动 Commit
  186. db5.Close()
  187. fi, _ = os.Stat(dbPath)
  188. fmt.Printf(" Close 后文件: %.2f MB\n", float64(fi.Size())/1024/1024)
  189. db5b, _ := DB.Open(dbPath)
  190. tbl5b, _ := DB.UseTable[Record](db5b, "test")
  191. cnt5, _ := tbl5b.Count()
  192. row5a, _ := tbl5b.Find(1)
  193. row5b, _ := tbl5b.Find(1000000)
  194. name5a, name5b := "", ""
  195. if row5a != nil {
  196. name5a = row5a.Name
  197. }
  198. if row5b != nil {
  199. name5b = row5b.Name
  200. }
  201. db5b.Close()
  202. fmt.Printf(" 重开后 Count: %d, Find(1): %s, Find(1000000): %s\n", cnt5, name5a, name5b)
  203. if cnt5 == 1000000 && name5a == "Emp0000001" && name5b == "Emp1000000" {
  204. fmt.Println(" ✅ 场景 5 通过: 100 万行无手动 Commit, 数据完整!")
  205. } else {
  206. fmt.Println(" ❌ 场景 5 失败")
  207. failed++
  208. }
  209. //os.Remove(dbPath)
  210. fmt.Println("\n==============================================")
  211. fmt.Println(" 测试完成!")
  212. fmt.Println("==============================================")
  213. if failed > 0 {
  214. fmt.Printf(" ⚠️ 共 %d 个场景失败\n", failed)
  215. os.Exit(1)
  216. }
  217. }