compose_handler.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. package index
  2. import (
  3. "TsDB2/DB/core/index/composepage"
  4. "TsDB2/DB/core/page"
  5. "TsDB2/DB/core/util"
  6. "bytes"
  7. "encoding/binary"
  8. "unsafe"
  9. )
  10. func init() {
  11. Compose.RegisterHandler(page.IndexTypeCompose, &ComposeChainHandler{})
  12. }
  13. // ======================== IEntry: 复合索引条目 ========================
  14. // ComposeEntry 通用复合索引结构体
  15. // Keys: 存储 N 个索引键 (uint64)
  16. // PKID: 主键ID(8字节),通过 B+ 树解析数据位置
  17. type ComposeEntry struct {
  18. Keys []uint64 // 任意多个索引键(1个、2个、3..都支持)
  19. PKID uint64 // 主键ID (8字节)
  20. }
  21. func (e *ComposeEntry) DataEntry() IDateEntry {
  22. return &composepage.ComposeEntryPage{}
  23. }
  24. // EntryLength 自动计算长度:8*键数量 + 8 (PK_ID)
  25. func (e *ComposeEntry) EntryLength() uint16 {
  26. return uint16(len(e.Keys)*8 + 8)
  27. }
  28. // Compare 通用复合索引比较逻辑:自动按顺序比较所有键(不含末尾 PK_ID)
  29. func (e *ComposeEntry) Compare(midEntry []byte, key []byte) int {
  30. entryLen := int(e.EntryLength())
  31. keyCount := (entryLen - 8) / 8
  32. for i := 0; i < keyCount; i++ {
  33. offset := i * 8
  34. f1 := binary.BigEndian.Uint64(midEntry[offset : offset+8])
  35. f2 := binary.BigEndian.Uint64(key[offset : offset+8])
  36. cmp := util.CompareUint64(f1, f2)
  37. if cmp != 0 {
  38. return cmp
  39. }
  40. }
  41. return 0
  42. }
  43. // Serialize 自动序列化 N 个键 + PK_ID
  44. func (e *ComposeEntry) Serialize(ie IEntry) []byte {
  45. ent, ok := ie.(*ComposeEntry)
  46. if !ok {
  47. return nil
  48. }
  49. keyCount := len(ent.Keys)
  50. buf := make([]byte, keyCount*8+8)
  51. for i, k := range ent.Keys {
  52. binary.BigEndian.PutUint64(buf[i*8:(i+1)*8], k)
  53. }
  54. binary.BigEndian.PutUint64(buf[keyCount*8:], ent.PKID)
  55. return buf
  56. }
  57. // Deserialize 自动反序列化 N 个键 + PK_ID
  58. func (e *ComposeEntry) Deserialize(buf []byte) IEntry {
  59. keyCount := (len(buf) - 8) / 8
  60. keys := make([]uint64, 0, keyCount)
  61. for i := 0; i < keyCount; i++ {
  62. keys = append(keys, binary.BigEndian.Uint64(buf[i*8:(i+1)*8]))
  63. }
  64. return &ComposeEntry{
  65. Keys: keys,
  66. PKID: binary.BigEndian.Uint64(buf[keyCount*8:]),
  67. }
  68. }
  69. // Insert 插入索引
  70. func (e *ComposeEntry) Insert(entries *[]byte, data []byte) error {
  71. *entries = append(*entries, data...)
  72. return nil
  73. }
  74. // Search 二分查找(通用 N 字段复合索引)
  75. func (e *ComposeEntry) Search(entries []byte, key []byte) (uint32, bool) {
  76. entryLen := int(e.EntryLength())
  77. pos, found := util.BinarySearch(entries, entryLen, key, e.Compare)
  78. if !found {
  79. return 0, false
  80. }
  81. return pos, true
  82. }
  83. // ======================== IndexHandler: 复合二级索引处理器 ========================
  84. // ComposeChainHandler — 复合二级索引 (page.IndexTypeCompose)
  85. // 扁平索引页链, 条目 [composeKey(N*8B) + PKID(8B)]
  86. type ComposeChainHandler struct{}
  87. func (h *ComposeChainHandler) Insert(handle page.HandleDb, entryPage *uint32, indexKey []byte, pkID uint64, rowData []byte, keyLen int) (uint32, error) {
  88. dataEntry := h.getDataEntry()
  89. curPageID := *entryPage
  90. lastIdxPageID := uint32(0)
  91. for curPageID != 0 {
  92. buf := make([]byte, page.IndexPageSize)
  93. if err := handle.ReadPage(curPageID, buf); err != nil {
  94. return 0, err
  95. }
  96. hdr := (*page.IndexHead)(unsafe.Pointer(&buf[0]))
  97. pageEntryLen := int(hdr.EntryLen)
  98. count := int(hdr.Count)
  99. idxPageHasRoom := hdr.Hdr.UseSize+uint32(pageEntryLen) <= page.IndexPageSize
  100. if !idxPageHasRoom {
  101. lastIdxPageID = curPageID
  102. curPageID = hdr.Hdr.NextPage
  103. continue
  104. }
  105. entries := buf[page.IndexHeadSize : page.IndexHeadSize+(count+1)*pageEntryLen]
  106. err := dataEntry.Insert(handle, entries, pageEntryLen, count, indexKey, pkID, rowData)
  107. if err == nil {
  108. hdr.Count++
  109. hdr.Hdr.UseSize += uint32(pageEntryLen)
  110. if err := handle.SavePage(curPageID, buf); err != nil {
  111. return 0, err
  112. }
  113. return *entryPage, nil
  114. }
  115. lastIdxPageID = curPageID
  116. curPageID = hdr.Hdr.NextPage
  117. }
  118. entryLen := keyLen + 8
  119. newEntry := make([]byte, entryLen)
  120. copy(newEntry[:keyLen], indexKey)
  121. binary.BigEndian.PutUint64(newEntry[keyLen:], pkID)
  122. return *entryPage, writeToNewIndexPage(handle, entryPage, newEntry, lastIdxPageID)
  123. }
  124. func (h *ComposeChainHandler) Search(handle page.HandleDb, entryPage uint32, indexKey []byte, keyLen int, resolve RowResolver) ([]byte, bool) {
  125. dataEntry := h.getDataEntry()
  126. curPageID := entryPage
  127. for curPageID != 0 {
  128. buf := make([]byte, page.IndexPageSize)
  129. if err := handle.ReadPage(curPageID, buf); err != nil {
  130. break
  131. }
  132. hdr := (*page.IndexHead)(unsafe.Pointer(&buf[0]))
  133. entries := buf[page.IndexHeadSize : page.IndexHeadSize+int(hdr.Count)*int(hdr.EntryLen)]
  134. entryLen := int(hdr.EntryLen)
  135. pkBuf, found := dataEntry.Search(handle, entries, entryLen, indexKey)
  136. if found {
  137. // 二级索引不存行数据: 内部回表取整行
  138. if resolve != nil && len(pkBuf) == 8 {
  139. if row, ok := resolve(binary.BigEndian.Uint64(pkBuf)); ok {
  140. return row, true
  141. }
  142. return nil, false
  143. }
  144. return pkBuf, true
  145. }
  146. curPageID = hdr.Hdr.NextPage
  147. }
  148. return nil, false
  149. }
  150. // Delete 按 (key, pkID) 精确删除复合索引条目。
  151. // 链页里的条目是 [composeKey(N*8B) + pkID(8B)] 的扁平数组, 直接原地摘除即可。
  152. func (h *ComposeChainHandler) Delete(handle page.HandleDb, entryPage *uint32, indexKey []byte, pkID uint64, keyLen int) error {
  153. curPageID := *entryPage
  154. for curPageID != 0 {
  155. buf := make([]byte, page.IndexPageSize)
  156. if err := handle.ReadPage(curPageID, buf); err != nil {
  157. return err
  158. }
  159. hdr := (*page.IndexHead)(unsafe.Pointer(&buf[0]))
  160. entryLen := int(hdr.EntryLen)
  161. count := int(hdr.Count)
  162. if entryLen > 8 && count > 0 {
  163. base := page.IndexHeadSize
  164. keyPart := entryLen - 8
  165. for i := 0; i < count; i++ {
  166. off := base + i*entryLen
  167. if off+entryLen > len(buf) {
  168. break
  169. }
  170. if composeCmp(buf[off:off+keyPart], indexKey) != 0 {
  171. continue
  172. }
  173. if pkID != 0 && binary.BigEndian.Uint64(buf[off+keyPart:off+entryLen]) != pkID {
  174. continue
  175. }
  176. copy(buf[off:base+count*entryLen], buf[off+entryLen:base+count*entryLen])
  177. copy(buf[base+(count-1)*entryLen:base+count*entryLen], make([]byte, entryLen))
  178. hdr.Count--
  179. hdr.Hdr.UseSize -= uint32(entryLen)
  180. if err := handle.SavePage(curPageID, buf); err != nil {
  181. return err
  182. }
  183. return nil
  184. }
  185. }
  186. curPageID = hdr.Hdr.NextPage
  187. }
  188. return page.ErrNotFound
  189. }
  190. func (h *ComposeChainHandler) Update(handle page.HandleDb, entryPage *uint32, oldKey, newKey, rowData []byte, pkID uint64, keyLen int) error {
  191. // 二级索引条目只存 [key + pkID]: 键未变则无事可做, 键变了则删旧插新
  192. if bytes.Equal(oldKey, newKey) {
  193. return nil
  194. }
  195. if oldKey != nil {
  196. if err := h.Delete(handle, entryPage, oldKey, pkID, len(oldKey)); err != nil && err != page.ErrNotFound {
  197. return err
  198. }
  199. }
  200. _, err := h.Insert(handle, entryPage, newKey, pkID, rowData, len(newKey))
  201. return err
  202. }
  203. // IsRowStore 复合二级索引不承载行数据
  204. func (h *ComposeChainHandler) IsRowStore() bool { return false }
  205. // ResolveRow 复合二级索引无法按 pkID 取行, 由调用方的回表函数负责
  206. func (h *ComposeChainHandler) ResolveRow(handle page.HandleDb, entryPage uint32, pkID uint64, cache *[]DPRange) ([]byte, bool) {
  207. return nil, false
  208. }
  209. func (h *ComposeChainHandler) GetDataPageIDs(handle page.HandleDb, entryPage uint32) []uint32 {
  210. return nil
  211. }
  212. func (h *ComposeChainHandler) ReadDataPageRows(handle page.HandleDb, dpID uint32) [][]byte {
  213. return nil
  214. }
  215. // RangeScan 复合二级索引范围扫描
  216. // 条目格式: [key(keyLen) + pkID(8B BE)]
  217. // 回调收到 8B BigEndian pkID
  218. func (h *ComposeChainHandler) RangeScan(handle page.HandleDb, entryPage uint32,
  219. startKey, endKey []byte, startInclusive, endInclusive bool, reverse bool,
  220. callback func(row []byte) bool) error {
  221. if entryPage == 0 {
  222. return nil
  223. }
  224. type pageData struct {
  225. entries []byte
  226. el int
  227. count int
  228. }
  229. var pages []pageData
  230. curPageID := entryPage
  231. for curPageID != 0 {
  232. buf := make([]byte, page.IndexPageSize)
  233. if err := handle.ReadPage(curPageID, buf); err != nil {
  234. break
  235. }
  236. hdr := (*page.IndexHead)(unsafe.Pointer(&buf[0]))
  237. el := int(hdr.EntryLen)
  238. count := int(hdr.Count)
  239. entries := make([]byte, count*el)
  240. copy(entries, buf[page.IndexHeadSize:page.IndexHeadSize+count*el])
  241. pages = append(pages, pageData{entries: entries, el: el, count: count})
  242. curPageID = hdr.Hdr.NextPage
  243. }
  244. if !reverse {
  245. for p := 0; p < len(pages); p++ {
  246. pg := &pages[p]
  247. for i := 0; i < pg.count; i++ {
  248. entry := pg.entries[i*pg.el : (i+1)*pg.el]
  249. key := entry[:pg.el-8]
  250. if endKey != nil {
  251. cmp := composeCmp(key, endKey)
  252. if cmp > 0 || (cmp == 0 && !endInclusive) {
  253. return nil
  254. }
  255. }
  256. if startKey != nil {
  257. cmp := composeCmp(key, startKey)
  258. if cmp < 0 || (cmp == 0 && !startInclusive) {
  259. continue
  260. }
  261. }
  262. pkID := entry[pg.el-8:]
  263. if !callback(pkID) {
  264. return nil
  265. }
  266. }
  267. }
  268. } else {
  269. for p := len(pages) - 1; p >= 0; p-- {
  270. pg := &pages[p]
  271. for i := pg.count - 1; i >= 0; i-- {
  272. entry := pg.entries[i*pg.el : (i+1)*pg.el]
  273. key := entry[:pg.el-8]
  274. if startKey != nil {
  275. cmp := composeCmp(key, startKey)
  276. if cmp < 0 || (cmp == 0 && !startInclusive) {
  277. return nil
  278. }
  279. }
  280. if endKey != nil {
  281. cmp := composeCmp(key, endKey)
  282. if cmp > 0 || (cmp == 0 && !endInclusive) {
  283. continue
  284. }
  285. }
  286. pkID := entry[pg.el-8:]
  287. if !callback(pkID) {
  288. return nil
  289. }
  290. }
  291. }
  292. }
  293. return nil
  294. }
  295. // composeCmp 字节切片比较
  296. func composeCmp(a, b []byte) int {
  297. ml := len(a)
  298. if len(b) < ml {
  299. ml = len(b)
  300. }
  301. for i := 0; i < ml; i++ {
  302. if a[i] < b[i] {
  303. return -1
  304. }
  305. if a[i] > b[i] {
  306. return 1
  307. }
  308. }
  309. if len(a) < len(b) {
  310. return -1
  311. }
  312. if len(a) > len(b) {
  313. return 1
  314. }
  315. return 0
  316. }
  317. func (h *ComposeChainHandler) deleteEntry(handle page.HandleDb, entryPage *uint32, indexKey []byte) error {
  318. dataEntry := h.getDataEntry()
  319. curPageID := *entryPage
  320. for curPageID != 0 {
  321. buf := make([]byte, page.IndexPageSize)
  322. if err := handle.ReadPage(curPageID, buf); err != nil {
  323. return err
  324. }
  325. hdr := (*page.IndexHead)(unsafe.Pointer(&buf[0]))
  326. entries := buf[page.IndexHeadSize : page.IndexHeadSize+int(hdr.Count)*int(hdr.EntryLen)]
  327. entryLen := int(hdr.EntryLen)
  328. err := dataEntry.Delete(handle, entries, entryLen, indexKey)
  329. if err == nil {
  330. hdr.Hdr.UseSize -= uint32(entryLen)
  331. if err := handle.SavePage(curPageID, buf); err != nil {
  332. return err
  333. }
  334. return nil
  335. }
  336. curPageID = hdr.Hdr.NextPage
  337. }
  338. return page.ErrNotFound
  339. }
  340. func (h *ComposeChainHandler) getDataEntry() IDateEntry {
  341. handler, _ := Compose.GetEntryHandler(page.IndexTypeCompose)
  342. return handler.DataEntry()
  343. }
  344. // CollectPageIDs 实现 index.PageCollector: 顺着 NextPage 走完整条扁平页链。
  345. // seen 兜底防环 (链被写坏时 NextPage 可能绕回自身, 否则这里会死循环)。
  346. func (h *ComposeChainHandler) CollectPageIDs(handle page.HandleDb, entryPage uint32) []uint32 {
  347. var out []uint32
  348. seen := make(map[uint32]bool)
  349. for cur := entryPage; cur != 0 && !seen[cur]; {
  350. seen[cur] = true
  351. out = append(out, cur)
  352. buf := make([]byte, page.IndexPageSize)
  353. if err := handle.ReadPage(cur, buf); err != nil {
  354. // 读不到就到此为止: 继续按 buf 里的残留指针走会收集到无关的页号
  355. break
  356. }
  357. cur = (*page.IndexHead)(unsafe.Pointer(&buf[0])).Hdr.NextPage
  358. }
  359. return out
  360. }