layout_assert.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. package main
  2. import (
  3. "TsDB2/DB/core"
  4. "TsDB2/DB/core/types"
  5. "TsDB2/DB/core/util"
  6. "unsafe"
  7. )
  8. // 编译期断言: 把 analyzer 里硬编码的盘上布局 (META_SZ / TINFO_SZ / TI_* / IM_*)
  9. // 与 DB/core 中的真实结构体逐个钉在一起。
  10. //
  11. // 为什么需要这个文件:
  12. //
  13. // analyzer 在自己的模块里手写偏移直接读盘。过去这件事只能靠 DB/core 的注释约束
  14. // (「改布局时记得同步 analyzer/main.go 的 TI_*」) —— 而漏改的后果不是报错, 而是
  15. // **静默读错**: 把索引名数组的高位字节当成 IndexType、把别的字段当成 EntryPage,
  16. // 页面照常渲染但数据全错, 极难发现。
  17. //
  18. // analyzer 的 go.mod 已有 `replace TsDB2 => ../`, 可以直接引用真实结构体, 于是把这层
  19. // 依赖交给编译器: 任何一边改了布局, 这里当场编译失败。
  20. //
  21. // 断言写法:
  22. // - [a - b]struct{} 与 [b - a]struct{} 同时成立 ⇔ a == b (差值为负时数组长度非法);
  23. // - _ [N]byte = [unsafe.Offsetof(...)]byte{} ⇔ 偏移恰好等于 N (长度不等则类型不符)。
  24. var (
  25. // 结构体整体尺寸
  26. _ [int(unsafe.Sizeof(core.IndexMeta{})) - META_SZ]struct{}
  27. _ [META_SZ - int(unsafe.Sizeof(core.IndexMeta{}))]struct{}
  28. _ [int(unsafe.Sizeof(core.TableInfo{})) - TINFO_SZ]struct{}
  29. _ [TINFO_SZ - int(unsafe.Sizeof(core.TableInfo{}))]struct{}
  30. // TableInfo 字段偏移
  31. _ [TI_FLAG]byte = [unsafe.Offsetof(core.TableInfo{}.Flag)]byte{}
  32. _ [TI_HPCNT]byte = [unsafe.Offsetof(core.TableInfo{}.HeapPageCount)]byte{}
  33. _ [TI_ROWS]byte = [unsafe.Offsetof(core.TableInfo{}.TotalRows)]byte{}
  34. _ [TI_FHEAP]byte = [unsafe.Offsetof(core.TableInfo{}.FirstHeap)]byte{}
  35. _ [TI_FDATA]byte = [unsafe.Offsetof(core.TableInfo{}.FirstData)]byte{}
  36. _ [TI_ROWSZ]byte = [unsafe.Offsetof(core.TableInfo{}.RowSize)]byte{}
  37. _ [TI_ALLOC]byte = [unsafe.Offsetof(core.TableInfo{}.FieldAllocateSize)]byte{}
  38. _ [TI_FIDX]byte = [unsafe.Offsetof(core.TableInfo{}.FirstIndexID)]byte{}
  39. _ [TI_EXTPG]byte = [unsafe.Offsetof(core.TableInfo{}.ExtPage)]byte{}
  40. _ [TI_EXTOFF]byte = [unsafe.Offsetof(core.TableInfo{}.ExtOff)]byte{}
  41. // IndexMeta 字段偏移 (这些会随 IndexNameSize 整体平移)
  42. _ [IM_NAMSZ]byte = [unsafe.Sizeof(core.IndexMeta{}.IndexName)]byte{}
  43. _ [IM_TYPE]byte = [unsafe.Offsetof(core.IndexMeta{}.IndexType)]byte{}
  44. _ [IM_FCNT]byte = [unsafe.Offsetof(core.IndexMeta{}.FieldCnt)]byte{}
  45. _ [IM_FLDS]byte = [unsafe.Offsetof(core.IndexMeta{}.FieldIDs)]byte{}
  46. _ [IM_EP]byte = [unsafe.Offsetof(core.IndexMeta{}.EntryPage)]byte{}
  47. _ [IM_FLAG]byte = [unsafe.Offsetof(core.IndexMeta{}.Flag)]byte{}
  48. // 位掩码同样是"读盘约定": analyzer 里手写的位必须与 core 的常量一致。
  49. // 读错位的后果和读错偏移一样安静 —— 列 / 索引照样渲染出来, 只是"可空"
  50. // 读成了"非空"、"唯一"读成了"普通"。
  51. _ [FLAG_DELETED - int(types.FlagDeleted)]struct{}
  52. _ [int(types.FlagDeleted) - FLAG_DELETED]struct{}
  53. _ [FLAG_NULLABLE - int(types.FlagNullable)]struct{}
  54. _ [int(types.FlagNullable) - FLAG_NULLABLE]struct{}
  55. _ [FLAG_UNIQUE - int(types.FlagUnique)]struct{}
  56. _ [int(types.FlagUnique) - FLAG_UNIQUE]struct{}
  57. _ [FLAG_SCALE - int(types.FlagScaleMask)]struct{}
  58. _ [int(types.FlagScaleMask) - FLAG_SCALE]struct{}
  59. _ [IM_FLAG_UNIQUE - int(core.IndexFlagUnique)]struct{}
  60. _ [int(core.IndexFlagUnique) - IM_FLAG_UNIQUE]struct{}
  61. )
  62. // init 兜底: core 没有给"这一位是删除位"单列常量 (那一位的语义由 util.IsHighBitSet
  63. // 表达), 所以它只能用运行时断言。只跑一次, 不在热路径上。
  64. func init() {
  65. if !util.IsHighBitSet(IM_FLAG_DELETED) {
  66. panic("IM_FLAG_DELETED 与 core/util.IsHighBitSet 的判定不一致: 删除位读错会让已删的索引照常渲染")
  67. }
  68. }