| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- package strdatapage
- import (
- "git.ycl.pub/yl32940/TsDB2/DB/core/page"
- "bytes"
- "encoding/binary"
- "errors"
- "unsafe"
- )
- // StrDataPage 字符串索引操作器
- // 不再管理独立的 DataPage,直接在 IndexPage 条目中存储 [strKey(N) + PK_ID(8B)]
- // Search 返回 PK_ID 的 8 字节编码,Table 层再通过 B+ 树解析实际行数据
- type StrDataPage struct{}
- const pkIDLen = 8
- // countBackOffset Count 字段距离 entries 起始位置的向后偏移
- // IndexHeadSize = sizeof(PageHdr) + 14 = 32, Count 在 IndexHead 偏移 24
- // countBackOffset = IndexHeadSize - 24 = 8
- var countBackOffset = int(unsafe.Sizeof(page.PageHdr{})) + 14 - (int(unsafe.Sizeof(page.PageHdr{})) + 6)
- // ======================== IDateEntry 接口实现 ========================
- // Insert 在 IndexPage 条目中插入 [strKey(N) + PK_ID(8B)]
- // 注意:调用方(insertWithIndex)负责更新 Count 和保存页
- func (s *StrDataPage) Insert(handle page.HandleDb, indexEntries []byte, entryLen int, count int, key []byte, pkID uint64, rowData []byte) error {
- n := count
- keyLen := entryLen - pkIDLen // 实际索引键长度
- // 二分查找插入位置(按 strKey 字典序)
- pos := n
- left, right := 0, n-1
- for left <= right {
- mid := (left + right) / 2
- entryKey := indexEntries[mid*entryLen : mid*entryLen+keyLen]
- if bytes.Compare(entryKey, key[:keyLen]) >= 0 {
- pos = mid
- right = mid - 1
- } else {
- left = mid + 1
- }
- }
- // 移动后续条目腾出空间
- if pos < n {
- copy(indexEntries[(pos+1)*entryLen:], indexEntries[pos*entryLen:n*entryLen])
- }
- // 写入新条目 [strKey(keyLen) + PK_ID(8B)]
- entry := indexEntries[pos*entryLen : (pos+1)*entryLen]
- copy(entry[:keyLen], key[:keyLen])
- binary.BigEndian.PutUint64(entry[keyLen:], pkID)
- return nil
- }
- // Search 二分查找 strKey,返回 PK_ID 的 8 字节编码
- func (s *StrDataPage) Search(handle page.HandleDb, indexEntries []byte, entryLen int, key []byte) ([]byte, bool) {
- n := len(indexEntries) / entryLen
- if n == 0 {
- return nil, false
- }
- keyLen := entryLen - pkIDLen
- left, right := 0, n-1
- for left <= right {
- mid := (left + right) / 2
- entryKey := indexEntries[mid*entryLen : mid*entryLen+keyLen]
- cmp := bytes.Compare(entryKey, key[:keyLen])
- if cmp == 0 {
- pkIDBytes := indexEntries[mid*entryLen+keyLen : mid*entryLen+keyLen+pkIDLen]
- result := make([]byte, pkIDLen)
- copy(result, pkIDBytes)
- return result, true
- } else if cmp < 0 {
- left = mid + 1
- } else {
- right = mid - 1
- }
- }
- return nil, false
- }
- // Delete 从 IndexPage 中删除条目(前移后续条目)
- func (s *StrDataPage) Delete(handle page.HandleDb, indexEntries []byte, entryLen int, key []byte) error {
- n := len(indexEntries) / entryLen
- keyLen := entryLen - pkIDLen
- // 查找目标条目
- pos := -1
- left, right := 0, n-1
- for left <= right {
- mid := (left + right) / 2
- entryKey := indexEntries[mid*entryLen : mid*entryLen+keyLen]
- cmp := bytes.Compare(entryKey, key[:keyLen])
- if cmp == 0 {
- pos = mid
- break
- } else if cmp < 0 {
- left = mid + 1
- } else {
- right = mid - 1
- }
- }
- if pos < 0 {
- return errors.New("row not found")
- }
- // 前移后续条目覆盖被删条目
- if pos < n-1 {
- copy(indexEntries[pos*entryLen:], indexEntries[(pos+1)*entryLen:n*entryLen])
- }
- // 清零末尾
- zeroes := make([]byte, entryLen)
- copy(indexEntries[(n-1)*entryLen:n*entryLen], zeroes)
- // 更新 IndexHead.Count(减 1)
- // Count 在 entries 起始位置往前 countBackOffset 字节处
- countPtr := (*uint32)(unsafe.Add(unsafe.Pointer(&indexEntries[0]), -countBackOffset))
- *countPtr--
- return nil
- }
- // Update 字符串索引不支持直接更新
- func (s *StrDataPage) Update(handle page.HandleDb, indexEntries []byte, entryLen int, key []byte, pkID uint64, rowData []byte) error {
- return errors.New("string index does not support update")
- }
- // CreateDataPage 字符串索引不需要创建数据页
- func (s *StrDataPage) CreateDataPage(handle page.HandleDb, key []byte, pkID uint64, rowData []byte) (uint32, error) {
- return 0, errors.New("string index does not create data pages")
- }
|