pk_dup_shortcut_test.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. package core
  2. // 显式主键查重短路的回归测试。
  3. //
  4. // 背景 (bench_ts profile): InsertRowWithID 对显式 pkID 逐行回表查重, 时序行存储
  5. // 按 pkID 取行是 O(段数+页内行扫), 顺序写入时占写入 CPU 36%。修复: pkID 大于等于
  6. // "历史发号上界" (nextPK, 只增不减) 时必然不存在, 跳过查重。这里钉住两件事:
  7. // 1. 短路生效 (大于上界的号免查, 写入提速);
  8. // 2. 短路不误伤 —— 已存在的号 (无论 < 还是触达过上界后又被显式复用) 仍报重复。
  9. import (
  10. "errors"
  11. "testing"
  12. "git.ycl.pub/yl32940/TsDB2/DB/core/page"
  13. "git.ycl.pub/yl32940/TsDB2/DB/core/types"
  14. )
  15. func dupCheckTable(t *testing.T, db *DB, name string) *Table {
  16. t.Helper()
  17. tbl, err := db.CreateTable(name, []types.FieldInfo{
  18. {FieldType: types.FieldType_Uint64, FieldName: []byte("id")},
  19. {FieldType: types.FieldType_Uint64, FieldName: []byte("v")},
  20. })
  21. if err != nil {
  22. t.Fatalf("建表: %v", err)
  23. }
  24. if _, err := tbl.CreateIndex("pk", page.IndexTypePrimary, []byte{0}); err != nil {
  25. t.Fatalf("建索引: %v", err)
  26. }
  27. return tbl
  28. }
  29. func TestExplicitPKDuplicateStillDetected(t *testing.T) {
  30. db := fixOpenDB(t)
  31. tbl := dupCheckTable(t, db, "t")
  32. // 顺序显式写入 1..100 (全部命中短路, 但不能因此漏检后面的重复)
  33. for i := uint64(1); i <= 100; i++ {
  34. if _, err := tbl.InsertRowWithID(i, []types.FieldValue{
  35. {FieldName: []byte("id"), Value: i},
  36. {FieldName: []byte("v"), Value: i},
  37. }); err != nil {
  38. t.Fatalf("insert %d: %v", i, err)
  39. }
  40. }
  41. if err := db.Commit(); err != nil {
  42. t.Fatalf("commit: %v", err)
  43. }
  44. // 已存在的号 (< nextPK) 仍必须报重复
  45. for _, id := range []uint64{1, 50, 100} {
  46. if _, err := tbl.InsertRowWithID(id, []types.FieldValue{
  47. {FieldName: []byte("id"), Value: id},
  48. {FieldName: []byte("v"), Value: id},
  49. }); !errors.Is(err, ErrDuplicatePK) {
  50. t.Fatalf("重复插入 id=%d 必须报 ErrDuplicatePK, 实际: %v", id, err)
  51. }
  52. }
  53. // 从未发放过的号 (>= nextPK) 正常写入; 二次插入同一号 (此时已 < nextPK) 报重复
  54. if _, err := tbl.InsertRowWithID(101, []types.FieldValue{
  55. {FieldName: []byte("id"), Value: uint64(101)},
  56. {FieldName: []byte("v"), Value: uint64(101)},
  57. }); err != nil {
  58. t.Fatalf("insert 101: %v", err)
  59. }
  60. if _, err := tbl.InsertRowWithID(101, []types.FieldValue{
  61. {FieldName: []byte("id"), Value: uint64(101)},
  62. {FieldName: []byte("v"), Value: uint64(101)},
  63. }); !errors.Is(err, ErrDuplicatePK) {
  64. t.Fatalf("第二次插入 id=101 必须报 ErrDuplicatePK, 实际: %v", err)
  65. }
  66. // 批量路径同规则: 批内显式重复 + 与既有行撞车都要拦住
  67. if _, err := tbl.InsertRowsWithIDs([]uint64{200, 200}, [][]types.FieldValue{
  68. {{FieldName: []byte("id"), Value: uint64(200)}, {FieldName: []byte("v"), Value: uint64(200)}},
  69. {{FieldName: []byte("id"), Value: uint64(200)}, {FieldName: []byte("v"), Value: uint64(200)}},
  70. }); !errors.Is(err, ErrDuplicatePK) {
  71. t.Fatalf("批内重复必须报 ErrDuplicatePK, 实际: %v", err)
  72. }
  73. if _, err := tbl.InsertRowsWithIDs([]uint64{50}, [][]types.FieldValue{
  74. {{FieldName: []byte("id"), Value: uint64(50)}, {FieldName: []byte("v"), Value: uint64(50)}},
  75. }); !errors.Is(err, ErrDuplicatePK) {
  76. t.Fatalf("批量撞既有行必须报 ErrDuplicatePK, 实际: %v", err)
  77. }
  78. }