query_scan_mutation_test.go 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. package core
  2. import (
  3. "testing"
  4. "git.ycl.pub/yl32940/TsDB2/DB/core/types"
  5. )
  6. // TestScanWithDeleteDuringBatchResolve 扫描回调里逐行删除 (demo/stress_test 第 12 步
  7. // 的回归): 二级索引扫描物化 pkID 后走批量回表, 回调里的删除会改写主键 B+ 树
  8. // (叶合并/NextPage 重接)。批量回表必须"分批物化、批后回调" —— 绝不能让用户回调
  9. // 踩坏正在推进的叶链游标 (旧实现因此 index out of range)。
  10. func TestScanWithDeleteDuringBatchResolve(t *testing.T) {
  11. db := fixOpenDB(t)
  12. tbl := qopNewTable(t, db, "t")
  13. qopSeed(t, tbl, 1000)
  14. if err := db.Commit(); err != nil {
  15. t.Fatalf("commit: %v", err)
  16. }
  17. deleted := 0
  18. err := tbl.Query().Where(Ge("age", int64(0), 0)).ScanWithPKID(func(pkID uint64, _ []types.FieldValue) bool {
  19. if err := tbl.DeleteRow("pk", qopPKKey(pkID)); err != nil {
  20. t.Fatalf("删除 %d: %v", pkID, err)
  21. }
  22. deleted++
  23. return true
  24. })
  25. if err != nil {
  26. t.Fatalf("scan+delete: %v", err)
  27. }
  28. if deleted != 1000 {
  29. t.Fatalf("应删 1000 行, 实删 %d", deleted)
  30. }
  31. cnt, err := tbl.Query().Count()
  32. if err != nil || cnt != 0 {
  33. t.Fatalf("删尽后 count=%d err=%v, 想要 0", cnt, err)
  34. }
  35. }
  36. // TestScanWithUpdateDuringBatchResolve 扫描回调里逐行更新 (改索引列):
  37. // 更新会改写二级索引与行数据, 正在分批回表的游标必须不受影响, 且每行都被回调到。
  38. func TestScanWithUpdateDuringBatchResolve(t *testing.T) {
  39. db := fixOpenDB(t)
  40. tbl := qopNewTable(t, db, "t")
  41. qopSeed(t, tbl, 500)
  42. if err := db.Commit(); err != nil {
  43. t.Fatalf("commit: %v", err)
  44. }
  45. updated := 0
  46. err := tbl.Query().Where(In("age", []interface{}{int64(7), int64(8), int64(9)}, 0)).
  47. ScanWithPKID(func(pkID uint64, _ []types.FieldValue) bool {
  48. if err := tbl.UpdateRowByPK(pkID, []types.FieldValue{
  49. {FieldName: []byte("age"), Value: int64(99)},
  50. {FieldName: []byte("score"), Value: int64(1)},
  51. }); err != nil {
  52. t.Fatalf("更新 %d: %v", pkID, err)
  53. }
  54. updated++
  55. return true
  56. })
  57. if err != nil {
  58. t.Fatalf("scan+update: %v", err)
  59. }
  60. // age ∈ {7,8,9} 且 id<=500: 每值 10 个 → 30 行
  61. if updated != 30 {
  62. t.Fatalf("应更新 30 行, 实更新 %d", updated)
  63. }
  64. cnt, err := tbl.Query().Where(Eq("age", int64(99), 0)).Count()
  65. if err != nil || cnt != 30 {
  66. t.Fatalf("更新后 age=99 的 count=%d err=%v, 想要 30", cnt, err)
  67. }
  68. }