| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- 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 = "integrity_test.db"
- func main() {
- os.Remove(dbPath)
- fmt.Println("==============================================")
- fmt.Println(" TsDB2 完整性测试 (100万行)")
- fmt.Println("==============================================")
- fmt.Println()
- // ---- Phase 1: 打开数据库 ----
- fmt.Println("========== Phase 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)
- }
- printMemDisk("初始状态")
- // ---- Phase 2: 批量插入 100 万行 ----
- fmt.Println("\n========== Phase 2: 批量插入 ==========")
- N := 1_000_000
- t0 := time.Now()
- for i := 1; i <= N; i++ {
- err := tbl.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 err != nil {
- panic(fmt.Sprintf("insert row %d: %v", i, err))
- }
- if i%100_000 == 0 {
- printMemDisk(fmt.Sprintf("插入 %d 行", i))
- }
- }
- insertTime := time.Since(t0)
- fmt.Printf(" 插入 %d 行耗时: %.2fs (%.0f rows/s)\n", N, insertTime.Seconds(), float64(N)/insertTime.Seconds())
- // ---- Phase 3: Commit ----
- fmt.Println("\n========== Phase 3: Commit ==========")
- t1 := time.Now()
- if err := db.Commit(); err != nil {
- panic(err)
- }
- commitTime := time.Since(t1)
- printMemDisk("Commit 后")
- fmt.Printf(" Commit 耗时: %.2fs\n", commitTime.Seconds())
- // ---- Phase 4: 主键精确查找 ----
- fmt.Println("\n========== Phase 4: 主键精确查找 ==========")
- findTests := []uint64{1, 100, 1000, 10000, 100000, 500000, 999999, 1000000}
- findOK := 0
- findFail := 0
- t2 := time.Now()
- for _, id := range findTests {
- row, err := tbl.Find(id)
- if err != nil {
- fmt.Printf(" Find(%d): FAIL (%v)\n", id, err)
- findFail++
- } else {
- expected := fmt.Sprintf("Emp%07d", id)
- if row.Name != expected {
- fmt.Printf(" Find(%d): DATA ERROR (Name=%s, expected %s)\n", id, row.Name, expected)
- findFail++
- } else {
- findOK++
- }
- }
- }
- findTime := time.Since(t2)
- fmt.Printf(" 查找 %d 个样本: %d 成功, %d 失败, 耗时 %.3fs\n", len(findTests), findOK, findFail, findTime.Seconds())
- // ---- Phase 5: 全量扫描验证 ----
- fmt.Println("\n========== Phase 5: 全量扫描验证 ==========")
- t3 := time.Now()
- count := 0
- nameErrors := 0
- ageErrors := 0
- err = tbl.Select(func(rec *Record) bool {
- count++
- expectedName := fmt.Sprintf("Emp%07d", rec.ID)
- if rec.Name != expectedName {
- nameErrors++
- }
- expectedAge := int64(20 + (rec.ID % 50))
- if rec.Age != expectedAge {
- ageErrors++
- }
- return true
- })
- selectTime := time.Since(t3)
- if err != nil {
- fmt.Printf(" Select error: %v\n", err)
- }
- fmt.Printf(" 扫描行数: %d\n", count)
- fmt.Printf(" Name 错误: %d\n", nameErrors)
- fmt.Printf(" Age 错误: %d\n", ageErrors)
- fmt.Printf(" 全量扫描耗时: %.2fs (%.0f rows/s)\n", selectTime.Seconds(), float64(count)/selectTime.Seconds())
- // ---- Phase 6: 条件查询 ----
- fmt.Println("\n========== Phase 6: 条件查询 ==========")
- // Age = 25 (约 20000 行)
- t4 := time.Now()
- ageRows, err := tbl.Where("Age", "=", int64(25)).Find()
- ageQueryTime := time.Since(t4)
- if err != nil {
- fmt.Printf(" WHERE Age=25: ERROR (%v)\n", err)
- } else {
- fmt.Printf(" WHERE Age=25: %d 行, 耗时 %.3fs\n", len(ageRows), ageQueryTime.Seconds())
- }
- // Score = 500 (约 1000 行)
- t5 := time.Now()
- scoreRows, err := tbl.Where("Score", "=", int64(500)).Find()
- scoreQueryTime := time.Since(t5)
- if err != nil {
- fmt.Printf(" WHERE Score=500: ERROR (%v)\n", err)
- } else {
- fmt.Printf(" WHERE Score=500: %d 行, 耗时 %.3fs\n", len(scoreRows), scoreQueryTime.Seconds())
- }
- // ---- Phase 7: 更新验证 ----
- fmt.Println("\n========== Phase 7: 更新验证 ==========")
- t6 := time.Now()
- err = tbl.Update(&Record{
- BaseModel: DB.BaseModel{ID: 500},
- Dept: "UPDATED",
- })
- if err != nil {
- fmt.Printf(" Update id=500: FAIL (%v)\n", err)
- } else {
- row, err := tbl.Find(500)
- if err != nil {
- fmt.Printf(" Update 后 Find(500): FAIL (%v)\n", err)
- } else if row.Dept == "UPDATED" {
- fmt.Printf(" Update id=500: OK (Dept=UPDATED)\n")
- } else {
- fmt.Printf(" Update id=500: DATA ERROR (Dept=%s)\n", row.Dept)
- }
- }
- db.Commit()
- fmt.Printf(" 更新+Commit 耗时: %.3fs\n", time.Since(t6).Seconds())
- // ---- Phase 8: 删除验证 ----
- fmt.Println("\n========== Phase 8: 删除验证 ==========")
- t7 := time.Now()
- err = tbl.Delete(999)
- if err != nil {
- fmt.Printf(" Delete id=999: FAIL (%v)\n", err)
- } else {
- _, err := tbl.Find(999)
- if err != nil {
- fmt.Printf(" Delete id=999: OK (已找不到)\n")
- } else {
- fmt.Printf(" Delete id=999: FAIL (仍然能找到)\n")
- }
- }
- db.Commit()
- fmt.Printf(" 删除+Commit 耗时: %.3fs\n", time.Since(t7).Seconds())
- // 验证 Count
- cnt, _ := tbl.Count()
- fmt.Printf(" 删除后 Count: %d (应为 %d)\n", cnt, N-1)
- // ---- Phase 9: 关闭重开验证 ----
- fmt.Println("\n========== Phase 9: 关闭重开验证 ==========")
- db.Close()
- printMemDisk("Close 后")
- db2, err := DB.Open(dbPath)
- if err != nil {
- panic(err)
- }
- tbl2, err := DB.UseTable[Record](db2, "test")
- if err != nil {
- panic(err)
- }
- cnt2, _ := tbl2.Count()
- fmt.Printf(" 重开后 Count: %d\n", cnt2)
- // 重开后查找
- row, err := tbl2.Find(1)
- if err != nil {
- fmt.Printf(" 重开后 Find(1): FAIL (%v)\n", err)
- } else {
- fmt.Printf(" 重开后 Find(1): OK (Name=%s)\n", row.Name)
- }
- row, err = tbl2.Find(1000000)
- if err != nil {
- fmt.Printf(" 重开后 Find(1000000): FAIL (%v)\n", err)
- } else {
- fmt.Printf(" 重开后 Find(1000000): OK (Name=%s)\n", row.Name)
- }
- db2.Close()
- // ---- Phase 10: 最终统计 ----
- fmt.Println("\n========== Phase 10: 最终统计 ==========")
- fi, _ := os.Stat(dbPath)
- sizeMB := float64(fi.Size()) / 1024 / 1024
- fmt.Printf(" 数据库文件大小: %.2f MB\n", sizeMB)
- fmt.Printf(" 每行平均占用: %.0f bytes\n", float64(fi.Size())/float64(N))
- fmt.Printf(" 理论最小行大小: ~72 bytes (32+8+8+16+8)\n")
- fmt.Printf(" 空间放大系数: %.1fx\n", float64(fi.Size())/float64(N)/72.0)
- var m runtime.MemStats
- runtime.ReadMemStats(&m)
- fmt.Printf(" Go 堆内存: %.1f MB\n", float64(m.Alloc)/1024/1024)
- fmt.Printf(" 总分配内存: %.1f MB\n", float64(m.TotalAlloc)/1024/1024)
- fmt.Println("\n==============================================")
- if findFail == 0 && nameErrors == 0 && ageErrors == 0 && cnt2 == int64(N-1) {
- fmt.Println(" ✅ 完整性测试全部通过!")
- } else {
- fmt.Printf(" ❌ 有失败项: Find=%d, Name=%d, Age=%d, Count=%d\n",
- findFail, nameErrors, ageErrors, int(int64(N-1)-cnt2))
- os.Exit(1) // 让 make test / CI 能感知失败
- }
- fmt.Println("==============================================")
- }
- func printMemDisk(label string) {
- fi, _ := os.Stat(dbPath)
- sizeMB := float64(fi.Size()) / 1024 / 1024
- var m runtime.MemStats
- runtime.ReadMemStats(&m)
- heapMB := float64(m.Alloc) / 1024 / 1024
- fmt.Printf(" [%s] 磁盘: %8.2f MB | Go堆: %6.1f MB | Sys: %6.1f MB | Goroutines: %d\n",
- label, sizeMB, heapMB, float64(m.Sys)/1024/1024, runtime.NumGoroutine())
- }
|