main.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. package main
  2. import (
  3. "git.ycl.pub/yl32940/TsDB2/DB/core"
  4. "git.ycl.pub/yl32940/TsDB2/DB/core/page"
  5. "git.ycl.pub/yl32940/TsDB2/DB/core/types"
  6. "encoding/binary"
  7. "fmt"
  8. "os"
  9. )
  10. const dbPath = "wal_rowlevel_test.db"
  11. func main() {
  12. // 支持命令行参数控制测试阶段
  13. phase := "all"
  14. if len(os.Args) > 1 {
  15. phase = os.Args[1]
  16. }
  17. switch phase {
  18. case "setup":
  19. runSetup()
  20. case "verify":
  21. runVerify()
  22. case "txn_setup":
  23. runTxnSetup()
  24. case "txn_verify":
  25. runTxnVerify()
  26. case "rollback_test":
  27. runRollbackTest()
  28. default:
  29. runSetup()
  30. runVerify()
  31. fmt.Println()
  32. runTxnSetup()
  33. runTxnVerify()
  34. fmt.Println()
  35. runRollbackTest()
  36. }
  37. }
  38. // =============================================================================
  39. // 测试 1: 普通 CRUD 通过 WAL 保存数据 (显式 Commit)
  40. // =============================================================================
  41. func runSetup() {
  42. fmt.Println("===== 测试 1: 普通 CRUD + WAL Commit =====")
  43. os.Remove(dbPath)
  44. db, err := core.Open(dbPath)
  45. if err != nil {
  46. fmt.Println("Open DB error:", err)
  47. return
  48. }
  49. // 禁用防抖自动提交, 仅靠手动 Commit
  50. db.SetAutoCommitDelay(0)
  51. table, err := db.CreateTable("Users", []types.FieldInfo{
  52. {FieldType: types.FieldType_Uint64, FieldName: []byte("ID")},
  53. {FieldType: types.FieldType_String, Flag: types.WidthCodeFor(32), FieldName: []byte("Name")},
  54. {FieldType: types.FieldType_Uint16, FieldName: []byte("Age")},
  55. })
  56. if err != nil {
  57. fmt.Println("CreateTable error:", err)
  58. return
  59. }
  60. _, err = table.CreateIndex("pk_id", page.IndexTypePrimary, []byte{0})
  61. if err != nil {
  62. fmt.Println("CreateIndex error:", err)
  63. return
  64. }
  65. // 插入 10 行
  66. fmt.Println("\n--- 插入 10 行 ---")
  67. for i := uint64(1); i <= 10; i++ {
  68. nameBytes := make([]byte, 32)
  69. copy(nameBytes, fmt.Sprintf("User_%d", i))
  70. _, err := table.InsertRow([]types.FieldValue{
  71. {FieldName: []byte("ID"), Value: i},
  72. {FieldName: []byte("Name"), Value: nameBytes},
  73. {FieldName: []byte("Age"), Value: int16(20 + i)},
  74. })
  75. if err != nil {
  76. fmt.Printf("Insert(%d) error: %v\n", i, err)
  77. }
  78. }
  79. fmt.Printf("插入完成, TotalRows=%d\n", table.TotalRows())
  80. // 更新 2 行
  81. fmt.Println("\n--- 更新 ID=3, ID=5 ---")
  82. updateName := make([]byte, 32)
  83. copy(updateName, "User_3_Updated")
  84. key3 := make([]byte, 8)
  85. binary.BigEndian.PutUint64(key3, 3)
  86. err = table.UpdateRow("pk_id", key3, []types.FieldValue{
  87. {FieldName: []byte("ID"), Value: uint64(3)},
  88. {FieldName: []byte("Name"), Value: updateName},
  89. {FieldName: []byte("Age"), Value: int16(99)},
  90. })
  91. if err != nil {
  92. fmt.Println("Update(3) error:", err)
  93. } else {
  94. fmt.Println("Update(3) OK")
  95. }
  96. updateName5 := make([]byte, 32)
  97. copy(updateName5, "User_5_Updated")
  98. key5 := make([]byte, 8)
  99. binary.BigEndian.PutUint64(key5, 5)
  100. err = table.UpdateRow("pk_id", key5, []types.FieldValue{
  101. {FieldName: []byte("ID"), Value: uint64(5)},
  102. {FieldName: []byte("Name"), Value: updateName5},
  103. {FieldName: []byte("Age"), Value: int16(88)},
  104. })
  105. if err != nil {
  106. fmt.Println("Update(5) error:", err)
  107. } else {
  108. fmt.Println("Update(5) OK")
  109. }
  110. // 删除 2 行
  111. fmt.Println("\n--- 删除 ID=7, ID=9 ---")
  112. key7 := make([]byte, 8)
  113. binary.BigEndian.PutUint64(key7, 7)
  114. if err := table.DeleteRow("pk_id", key7); err != nil {
  115. fmt.Println("Delete(7) error:", err)
  116. } else {
  117. fmt.Println("Delete(7) OK")
  118. }
  119. key9 := make([]byte, 8)
  120. binary.BigEndian.PutUint64(key9, 9)
  121. if err := table.DeleteRow("pk_id", key9); err != nil {
  122. fmt.Println("Delete(9) error:", err)
  123. } else {
  124. fmt.Println("Delete(9) OK")
  125. }
  126. fmt.Printf("\n操作后 TotalRows=%d\n", table.TotalRows())
  127. // 显式 Commit (走 WAL)
  128. fmt.Println("\n--- 显式 Commit (WAL) ---")
  129. if err := db.Commit(); err != nil {
  130. fmt.Println("Commit error:", err)
  131. } else {
  132. fmt.Println("Commit OK")
  133. }
  134. // 验证当前可查询
  135. fmt.Println("\n--- 验证查询 ---")
  136. verifyQuery(table, "ID=3", 3)
  137. verifyQuery(table, "ID=5", 5)
  138. verifyQueryNotExist(table, "ID=7", 7)
  139. verifyQueryNotExist(table, "ID=9", 9)
  140. db.Close()
  141. fmt.Println("\n数据库已关闭 (不模拟崩溃, 正常关闭)")
  142. }
  143. // runVerify 重新打开数据库验证数据持久化
  144. func runVerify() {
  145. fmt.Println("\n===== 测试 1 验证: 重新打开数据库 =====")
  146. db, err := core.Open(dbPath)
  147. if err != nil {
  148. fmt.Println("Open DB error:", err)
  149. return
  150. }
  151. defer db.Close()
  152. table, ok := db.FindTable("Users")
  153. if !ok {
  154. fmt.Println("Table 'Users' not found!")
  155. return
  156. }
  157. fmt.Printf("TotalRows=%d (期望: 8)\n", table.TotalRows())
  158. // 验证所有行
  159. fmt.Println("\n--- 验证查询 ---")
  160. verifyQuery(table, "ID=1", 1)
  161. verifyQuery(table, "ID=3", 3) // 已更新
  162. verifyQuery(table, "ID=5", 5) // 已更新
  163. verifyQueryNotExist(table, "ID=7", 7) // 已删除
  164. verifyQueryNotExist(table, "ID=9", 9) // 已删除
  165. verifyQuery(table, "ID=10", 10)
  166. fmt.Println("\n✅ 测试 1 通过: 普通 CRUD + WAL Commit 数据持久化成功")
  167. }
  168. // =============================================================================
  169. // 测试 2: 事务 CRUD + WAL
  170. // =============================================================================
  171. func runTxnSetup() {
  172. fmt.Println("===== 测试 2: 事务 CRUD + WAL =====")
  173. os.Remove(dbPath)
  174. db, err := core.Open(dbPath)
  175. if err != nil {
  176. fmt.Println("Open DB error:", err)
  177. return
  178. }
  179. db.SetAutoCommitDelay(0)
  180. table, err := db.CreateTable("TxnUsers", []types.FieldInfo{
  181. {FieldType: types.FieldType_Uint64, FieldName: []byte("ID")},
  182. {FieldType: types.FieldType_String, Flag: types.WidthCodeFor(32), FieldName: []byte("Name")},
  183. {FieldType: types.FieldType_Uint16, FieldName: []byte("Age")},
  184. })
  185. if err != nil {
  186. fmt.Println("CreateTable error:", err)
  187. return
  188. }
  189. _, err = table.CreateIndex("pk_id", page.IndexTypePrimary, []byte{0})
  190. if err != nil {
  191. fmt.Println("CreateIndex error:", err)
  192. return
  193. }
  194. // 先插入 5 行 (非事务)
  195. fmt.Println("\n--- 非事务插入 5 行 ---")
  196. for i := uint64(1); i <= 5; i++ {
  197. nameBytes := make([]byte, 32)
  198. copy(nameBytes, fmt.Sprintf("Base_%d", i))
  199. table.InsertRow([]types.FieldValue{
  200. {FieldName: []byte("ID"), Value: i},
  201. {FieldName: []byte("Name"), Value: nameBytes},
  202. {FieldName: []byte("Age"), Value: int16(20 + i)},
  203. })
  204. }
  205. db.Commit() // 提交基础数据
  206. fmt.Printf("基础数据 TotalRows=%d\n", table.TotalRows())
  207. // 开启事务
  208. fmt.Println("\n--- 开启事务 ---")
  209. txn := db.BeginTransaction()
  210. // 事务内插入 5 行
  211. fmt.Println("--- 事务内插入 5 行 (ID=6~10) ---")
  212. for i := uint64(6); i <= 10; i++ {
  213. nameBytes := make([]byte, 32)
  214. copy(nameBytes, fmt.Sprintf("Txn_%d", i))
  215. _, err := table.InsertRow([]types.FieldValue{
  216. {FieldName: []byte("ID"), Value: i},
  217. {FieldName: []byte("Name"), Value: nameBytes},
  218. {FieldName: []byte("Age"), Value: int16(30 + i)},
  219. })
  220. if err != nil {
  221. fmt.Printf("Txn Insert(%d) error: %v\n", i, err)
  222. }
  223. }
  224. // 事务内更新 1 行
  225. fmt.Println("--- 事务内更新 ID=2 ---")
  226. txnName := make([]byte, 32)
  227. copy(txnName, "Base_2_TxnUpdated")
  228. key2 := make([]byte, 8)
  229. binary.BigEndian.PutUint64(key2, 2)
  230. table.UpdateRow("pk_id", key2, []types.FieldValue{
  231. {FieldName: []byte("ID"), Value: uint64(2)},
  232. {FieldName: []byte("Name"), Value: txnName},
  233. {FieldName: []byte("Age"), Value: int16(77)},
  234. })
  235. // 事务内删除 1 行
  236. fmt.Println("--- 事务内删除 ID=4 ---")
  237. key4 := make([]byte, 8)
  238. binary.BigEndian.PutUint64(key4, 4)
  239. table.DeleteRow("pk_id", key4)
  240. fmt.Printf("\n事务内操作后 TotalRows=%d (期望: 9, 5+5-1)\n", table.TotalRows())
  241. // 提交事务
  242. fmt.Println("\n--- 事务 Commit ---")
  243. if err := txn.Commit(); err != nil {
  244. fmt.Println("Txn Commit error:", err)
  245. return
  246. }
  247. fmt.Println("事务 Commit OK")
  248. db.Close()
  249. fmt.Println("数据库已关闭")
  250. }
  251. func runTxnVerify() {
  252. fmt.Println("\n===== 测试 2 验证: 重新打开数据库 =====")
  253. db, err := core.Open(dbPath)
  254. if err != nil {
  255. fmt.Println("Open DB error:", err)
  256. return
  257. }
  258. defer db.Close()
  259. table, ok := db.FindTable("TxnUsers")
  260. if !ok {
  261. fmt.Println("Table 'TxnUsers' not found!")
  262. return
  263. }
  264. fmt.Printf("TotalRows=%d (期望: 9)\n", table.TotalRows())
  265. // 验证基础数据
  266. verifyQuery(table, "ID=1", 1)
  267. verifyQuery(table, "ID=2", 2) // 事务内更新
  268. verifyQueryNotExist(table, "ID=4", 4) // 事务内删除
  269. // 验证事务内插入
  270. verifyQuery(table, "ID=6", 6)
  271. verifyQuery(table, "ID=10", 10)
  272. fmt.Println("\n✅ 测试 2 通过: 事务 CRUD + WAL 数据持久化成功")
  273. }
  274. // =============================================================================
  275. // 测试 3: 事务 Rollback
  276. // =============================================================================
  277. func runRollbackTest() {
  278. fmt.Println("\n===== 测试 3: 事务 Rollback =====")
  279. os.Remove(dbPath)
  280. db, err := core.Open(dbPath)
  281. if err != nil {
  282. fmt.Println("Open DB error:", err)
  283. return
  284. }
  285. db.SetAutoCommitDelay(0)
  286. table, err := db.CreateTable("RollbackTest", []types.FieldInfo{
  287. {FieldType: types.FieldType_Uint64, FieldName: []byte("ID")},
  288. {FieldType: types.FieldType_String, Flag: types.WidthCodeFor(32), FieldName: []byte("Name")},
  289. })
  290. if err != nil {
  291. fmt.Println("CreateTable error:", err)
  292. return
  293. }
  294. _, err = table.CreateIndex("pk_id", page.IndexTypePrimary, []byte{0})
  295. if err != nil {
  296. fmt.Println("CreateIndex error:", err)
  297. return
  298. }
  299. // 插入基础数据
  300. fmt.Println("--- 插入 5 行基础数据 ---")
  301. for i := uint64(1); i <= 5; i++ {
  302. nameBytes := make([]byte, 32)
  303. copy(nameBytes, fmt.Sprintf("Base_%d", i))
  304. table.InsertRow([]types.FieldValue{
  305. {FieldName: []byte("ID"), Value: i},
  306. {FieldName: []byte("Name"), Value: nameBytes},
  307. })
  308. }
  309. db.Commit()
  310. fmt.Printf("基础数据 TotalRows=%d\n", table.TotalRows())
  311. // 开启事务
  312. fmt.Println("\n--- 开启事务, 插入 5 行 (ID=6~10) ---")
  313. txn := db.BeginTransaction()
  314. for i := uint64(6); i <= 10; i++ {
  315. nameBytes := make([]byte, 32)
  316. copy(nameBytes, fmt.Sprintf("Txn_%d", i))
  317. table.InsertRow([]types.FieldValue{
  318. {FieldName: []byte("ID"), Value: i},
  319. {FieldName: []byte("Name"), Value: nameBytes},
  320. })
  321. }
  322. fmt.Printf("事务内 TotalRows=%d (期望: 10)\n", table.TotalRows())
  323. // 回滚
  324. fmt.Println("\n--- 事务 Rollback ---")
  325. if err := txn.Rollback(); err != nil {
  326. fmt.Println("Rollback error:", err)
  327. return
  328. }
  329. fmt.Println("Rollback OK")
  330. fmt.Printf("回滚后 TotalRows=%d (期望: 5)\n", table.TotalRows())
  331. // 验证回滚效果
  332. verifyQuery(table, "ID=1", 1)
  333. verifyQueryNotExist(table, "ID=6", 6)
  334. verifyQueryNotExist(table, "ID=10", 10)
  335. db.Close()
  336. // 重新打开验证持久化
  337. fmt.Println("\n--- 重新打开数据库验证 ---")
  338. db2, err := core.Open(dbPath)
  339. if err != nil {
  340. fmt.Println("Open DB error:", err)
  341. return
  342. }
  343. defer db2.Close()
  344. table2, ok := db2.FindTable("RollbackTest")
  345. if !ok {
  346. fmt.Println("Table not found!")
  347. return
  348. }
  349. fmt.Printf("重开后 TotalRows=%d (期望: 5)\n", table2.TotalRows())
  350. verifyQuery(table2, "ID=1", 1)
  351. verifyQueryNotExist(table2, "ID=6", 6)
  352. fmt.Println("\n✅ 测试 3 通过: 事务 Rollback 正确")
  353. }
  354. // =============================================================================
  355. // 辅助函数
  356. // =============================================================================
  357. func verifyQuery(table *core.Table, label string, id uint64) {
  358. key := make([]byte, 8)
  359. binary.BigEndian.PutUint64(key, id)
  360. row, err := table.SearchByIndex("pk_id", key)
  361. if err != nil {
  362. fmt.Printf(" ❌ %s: 查询失败: %v\n", label, err)
  363. return
  364. }
  365. fmt.Printf(" ✅ %s: 找到 -> ", label)
  366. for _, fv := range row {
  367. fmt.Printf("%s=%v ", string(fv.FieldName), formatValue(fv.Value))
  368. }
  369. fmt.Println()
  370. }
  371. func verifyQueryNotExist(table *core.Table, label string, id uint64) {
  372. key := make([]byte, 8)
  373. binary.BigEndian.PutUint64(key, id)
  374. _, err := table.SearchByIndex("pk_id", key)
  375. if err != nil {
  376. fmt.Printf(" ✅ %s: 正确不存在\n", label)
  377. return
  378. }
  379. fmt.Printf(" ❌ %s: 应该不存在但找到了!\n", label)
  380. }
  381. func formatValue(v interface{}) string {
  382. switch val := v.(type) {
  383. case []byte:
  384. // 去除尾部零字节
  385. end := len(val)
  386. for end > 0 && val[end-1] == 0 {
  387. end--
  388. }
  389. return string(val[:end])
  390. default:
  391. return fmt.Sprintf("%v", val)
  392. }
  393. }