btree_handler.go 5.8 KB

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