sbt_handler.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. package index
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "sort"
  6. "git.ycl.pub/yl32940/TsDB2/DB/core/index/btree"
  7. "git.ycl.pub/yl32940/TsDB2/DB/core/page"
  8. )
  9. // sbtSecondary — SBT 二级索引处理器基座: BTreeHandler / ComposeChainHandler 共享的
  10. // 全部 IndexHandler 方法与批量写入路径。
  11. //
  12. // 两个二级索引处理器对 IndexHandler 的实现逐字等价 (条目都是 [key(keyLen) +
  13. // PKID(8B BE)], 全部委托 btree.SBT*), 于是收敛到这一份嵌入实现; 各类型只保留
  14. // 自己的索引类型语义与独有方法 (如 BTreeHandler.SearchAll)。
  15. type sbtSecondary struct{}
  16. // 嵌入基座后两个处理器的方法集在编译期锁定: IndexHandler 全数命中,
  17. // BatchInserter 随之命中 —— IndexMetaPage.InsertRows 的批量分发对复合索引同样生效。
  18. var (
  19. _ IndexHandler = (*sbtSecondary)(nil)
  20. _ BatchInserter = (*sbtSecondary)(nil)
  21. )
  22. func (h *sbtSecondary) Insert(handle page.HandleDb, entryPage *uint32, indexKey []byte, pkID uint64, rowData []byte, keyLen int) (uint32, error) {
  23. entry := make([]byte, keyLen+8)
  24. copy(entry[:keyLen], indexKey)
  25. binary.BigEndian.PutUint64(entry[keyLen:], pkID)
  26. rootPID := *entryPage
  27. newRoot, err := btree.SBTInsert(rootPID, entry, handle)
  28. if err != nil {
  29. return 0, err
  30. }
  31. *entryPage = newRoot
  32. return newRoot, nil
  33. }
  34. // InsertBatch 批量写入二级索引条目。
  35. //
  36. // 先把整批条目按复合键 (key, pkID) 排序, 再交给 SBTBulkInsert 做"顺序扫描式"
  37. // 灌叶 —— 排序批量对 B+ 树就是最优写入形态: 相邻条目几乎总落同一张叶, 树被
  38. // 自左向右扫一遍, 每张叶加载/落盘各一次; 而逐条路径是每条从根随机下降 + 整页
  39. // 回写。IndexKey 为 nil 的行不进本索引 (NULL 分量), 直接跳过。
  40. func (h *sbtSecondary) InsertBatch(handle page.HandleDb, entryPage *uint32, rows []BatchRow) error {
  41. // 收集非 nil 键的条目 (定长 [key|pkID], 键长取首个非 nil)
  42. n := 0
  43. keyLen := 0
  44. for i := range rows {
  45. if rows[i].IndexKey != nil {
  46. if n == 0 {
  47. keyLen = len(rows[i].IndexKey)
  48. }
  49. n++
  50. }
  51. }
  52. if n == 0 {
  53. return nil
  54. }
  55. el := keyLen + 8
  56. flat := make([]byte, n*el)
  57. order := make([]int, 0, n)
  58. idx := 0
  59. for i := range rows {
  60. r := &rows[i]
  61. if r.IndexKey == nil {
  62. continue
  63. }
  64. e := flat[idx*el : idx*el+el]
  65. copy(e[:keyLen], r.IndexKey)
  66. binary.BigEndian.PutUint64(e[keyLen:], r.PKID)
  67. order = append(order, idx)
  68. idx++
  69. }
  70. // 定长条目 [key|pkID] 的字节序 == 复合键 (key, pkID) 全序, 直接按字节排序
  71. sort.Slice(order, func(a, b int) bool {
  72. return bytes.Compare(flat[order[a]*el:order[a]*el+el], flat[order[b]*el:order[b]*el+el]) < 0
  73. })
  74. sortedFlat := make([]byte, n*el)
  75. for j, oi := range order {
  76. copy(sortedFlat[j*el:j*el+el], flat[oi*el:oi*el+el])
  77. }
  78. rootPID := *entryPage
  79. newRoot, err := btree.SBTBulkInsert(rootPID, sortedFlat, el, handle)
  80. if err != nil {
  81. return err
  82. }
  83. if newRoot != *entryPage {
  84. *entryPage = newRoot
  85. }
  86. return nil
  87. }
  88. func (h *sbtSecondary) Search(handle page.HandleDb, entryPage uint32, indexKey []byte, keyLen int, resolve RowResolver) ([]byte, bool) {
  89. rootPID := entryPage
  90. if rootPID == 0 {
  91. return nil, false
  92. }
  93. pkID, found := btree.SBTSearch(rootPID, indexKey[:keyLen], handle)
  94. if !found {
  95. return nil, false
  96. }
  97. // 二级索引不存行数据: 回表由索引自己完成 (上层无需知道主键索引是谁)
  98. if resolve != nil {
  99. if row, ok := resolve(pkID); ok {
  100. return row, true
  101. }
  102. return nil, false
  103. }
  104. pkBuf := make([]byte, 8)
  105. binary.BigEndian.PutUint64(pkBuf, pkID)
  106. return pkBuf, true
  107. }
  108. func (h *sbtSecondary) Delete(handle page.HandleDb, entryPage *uint32, indexKey []byte, pkID uint64, keyLen int) error {
  109. rootPID := *entryPage
  110. if rootPID == 0 {
  111. return page.ErrNotFound
  112. }
  113. // 二级索引允许重复 key, 用 (key, pkID) 精确定位本行的条目。
  114. // pkID 未知(为 0)时退回按 key 搜索一个条目。
  115. if pkID == 0 {
  116. pk, found := btree.SBTSearch(rootPID, indexKey[:keyLen], handle)
  117. if !found {
  118. return page.ErrNotFound
  119. }
  120. pkID = pk
  121. }
  122. newRoot, err := btree.SBTDeleteWithPKID(rootPID, indexKey[:keyLen], pkID, handle)
  123. if err != nil {
  124. return err
  125. }
  126. *entryPage = newRoot
  127. return nil
  128. }
  129. func (h *sbtSecondary) Update(handle page.HandleDb, entryPage *uint32, oldKey, newKey, rowData []byte, pkID uint64, keyLen int) error {
  130. // 二级索引条目只存 [key + pkID], 不含行数据:
  131. // 键未变 → 无事可做 (过去"先删再插"会让条目在重复 key 区段里错位, 属于多余动作)
  132. // 键变了 → 按 (oldKey, pkID) 精确删旧条目, 再插新条目
  133. if bytes.Equal(oldKey, newKey) {
  134. return nil
  135. }
  136. if oldKey != nil {
  137. if err := h.Delete(handle, entryPage, oldKey, pkID, len(oldKey)); err != nil && err != page.ErrNotFound {
  138. return err
  139. }
  140. }
  141. _, err := h.Insert(handle, entryPage, newKey, pkID, rowData, len(newKey))
  142. return err
  143. }
  144. // IsRowStore 二级索引不承载行数据
  145. func (h *sbtSecondary) IsRowStore() bool { return false }
  146. // ResolveRow 二级索引无法按 pkID 取行, 由调用方的回表函数负责
  147. func (h *sbtSecondary) ResolveRow(handle page.HandleDb, entryPage uint32, pkID uint64, cache *[]DPRange) ([]byte, bool) {
  148. return nil, false
  149. }
  150. func (h *sbtSecondary) GetDataPageIDs(handle page.HandleDb, entryPage uint32) []uint32 {
  151. // 二级索引没有 DataPage, 返回空
  152. return nil
  153. }
  154. func (h *sbtSecondary) ReadDataPageRows(handle page.HandleDb, dpID uint32) [][]byte {
  155. // 二级索引没有 DataPage
  156. return nil
  157. }
  158. func (h *sbtSecondary) RangeScan(handle page.HandleDb, entryPage uint32,
  159. startKey, endKey []byte, startInclusive, endInclusive bool, reverse bool,
  160. callback func(row []byte) bool) error {
  161. return btree.SBTRangeScan(entryPage, handle, startKey, endKey, startInclusive, endInclusive, reverse, callback)
  162. }