strdatapage.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package strdatapage
  2. import (
  3. "git.ycl.pub/yl32940/TsDB2/DB/core/page"
  4. "bytes"
  5. "encoding/binary"
  6. "errors"
  7. "unsafe"
  8. )
  9. // StrDataPage 字符串索引操作器
  10. // 不再管理独立的 DataPage,直接在 IndexPage 条目中存储 [strKey(N) + PK_ID(8B)]
  11. // Search 返回 PK_ID 的 8 字节编码,Table 层再通过 B+ 树解析实际行数据
  12. type StrDataPage struct{}
  13. const pkIDLen = 8
  14. // countBackOffset Count 字段距离 entries 起始位置的向后偏移
  15. // IndexHeadSize = sizeof(PageHdr) + 14 = 32, Count 在 IndexHead 偏移 24
  16. // countBackOffset = IndexHeadSize - 24 = 8
  17. var countBackOffset = int(unsafe.Sizeof(page.PageHdr{})) + 14 - (int(unsafe.Sizeof(page.PageHdr{})) + 6)
  18. // ======================== IDateEntry 接口实现 ========================
  19. // Insert 在 IndexPage 条目中插入 [strKey(N) + PK_ID(8B)]
  20. // 注意:调用方(insertWithIndex)负责更新 Count 和保存页
  21. func (s *StrDataPage) Insert(handle page.HandleDb, indexEntries []byte, entryLen int, count int, key []byte, pkID uint64, rowData []byte) error {
  22. n := count
  23. keyLen := entryLen - pkIDLen // 实际索引键长度
  24. // 二分查找插入位置(按 strKey 字典序)
  25. pos := n
  26. left, right := 0, n-1
  27. for left <= right {
  28. mid := (left + right) / 2
  29. entryKey := indexEntries[mid*entryLen : mid*entryLen+keyLen]
  30. if bytes.Compare(entryKey, key[:keyLen]) >= 0 {
  31. pos = mid
  32. right = mid - 1
  33. } else {
  34. left = mid + 1
  35. }
  36. }
  37. // 移动后续条目腾出空间
  38. if pos < n {
  39. copy(indexEntries[(pos+1)*entryLen:], indexEntries[pos*entryLen:n*entryLen])
  40. }
  41. // 写入新条目 [strKey(keyLen) + PK_ID(8B)]
  42. entry := indexEntries[pos*entryLen : (pos+1)*entryLen]
  43. copy(entry[:keyLen], key[:keyLen])
  44. binary.BigEndian.PutUint64(entry[keyLen:], pkID)
  45. return nil
  46. }
  47. // Search 二分查找 strKey,返回 PK_ID 的 8 字节编码
  48. func (s *StrDataPage) Search(handle page.HandleDb, indexEntries []byte, entryLen int, key []byte) ([]byte, bool) {
  49. n := len(indexEntries) / entryLen
  50. if n == 0 {
  51. return nil, false
  52. }
  53. keyLen := entryLen - pkIDLen
  54. left, right := 0, n-1
  55. for left <= right {
  56. mid := (left + right) / 2
  57. entryKey := indexEntries[mid*entryLen : mid*entryLen+keyLen]
  58. cmp := bytes.Compare(entryKey, key[:keyLen])
  59. if cmp == 0 {
  60. pkIDBytes := indexEntries[mid*entryLen+keyLen : mid*entryLen+keyLen+pkIDLen]
  61. result := make([]byte, pkIDLen)
  62. copy(result, pkIDBytes)
  63. return result, true
  64. } else if cmp < 0 {
  65. left = mid + 1
  66. } else {
  67. right = mid - 1
  68. }
  69. }
  70. return nil, false
  71. }
  72. // Delete 从 IndexPage 中删除条目(前移后续条目)
  73. func (s *StrDataPage) Delete(handle page.HandleDb, indexEntries []byte, entryLen int, key []byte) error {
  74. n := len(indexEntries) / entryLen
  75. keyLen := entryLen - pkIDLen
  76. // 查找目标条目
  77. pos := -1
  78. left, right := 0, n-1
  79. for left <= right {
  80. mid := (left + right) / 2
  81. entryKey := indexEntries[mid*entryLen : mid*entryLen+keyLen]
  82. cmp := bytes.Compare(entryKey, key[:keyLen])
  83. if cmp == 0 {
  84. pos = mid
  85. break
  86. } else if cmp < 0 {
  87. left = mid + 1
  88. } else {
  89. right = mid - 1
  90. }
  91. }
  92. if pos < 0 {
  93. return errors.New("row not found")
  94. }
  95. // 前移后续条目覆盖被删条目
  96. if pos < n-1 {
  97. copy(indexEntries[pos*entryLen:], indexEntries[(pos+1)*entryLen:n*entryLen])
  98. }
  99. // 清零末尾
  100. zeroes := make([]byte, entryLen)
  101. copy(indexEntries[(n-1)*entryLen:n*entryLen], zeroes)
  102. // 更新 IndexHead.Count(减 1)
  103. // Count 在 entries 起始位置往前 countBackOffset 字节处
  104. countPtr := (*uint32)(unsafe.Add(unsafe.Pointer(&indexEntries[0]), -countBackOffset))
  105. *countPtr--
  106. return nil
  107. }
  108. // Update 字符串索引不支持直接更新
  109. func (s *StrDataPage) Update(handle page.HandleDb, indexEntries []byte, entryLen int, key []byte, pkID uint64, rowData []byte) error {
  110. return errors.New("string index does not support update")
  111. }
  112. // CreateDataPage 字符串索引不需要创建数据页
  113. func (s *StrDataPage) CreateDataPage(handle page.HandleDb, key []byte, pkID uint64, rowData []byte) (uint32, error) {
  114. return 0, errors.New("string index does not create data pages")
  115. }