| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- package composepage
- import (
- "TsDB2/DB/core/page"
- "encoding/binary"
- "errors"
- "unsafe"
- )
- // ComposeEntryPage 复合索引操作器
- // 不再管理独立的 DataPage,直接在 IndexPage 条目中存储 [composeKey(N*8B) + PK_ID(8B)]
- // Search 返回 PK_ID 的 8 字节编码,Table 层再通过 B+ 树解析实际行数据
- type ComposeEntryPage struct{}
- const pkIDLen = 8
- // countBackOffset Count 字段距离 entries 起始位置的偏移
- var countBackOffset = int(unsafe.Sizeof(page.PageHdr{})) + 14 - (int(unsafe.Sizeof(page.PageHdr{})) + 6)
- // ======================== IDateEntry 接口实现 ========================
- // Insert 在 IndexPage 条目中插入 [composeKey + PK_ID(8B)]
- func (c *ComposeEntryPage) Insert(handle page.HandleDb, indexEntries []byte, entryLen int, count int, key []byte, pkID uint64, rowData []byte) error {
- keyPartLen := entryLen - pkIDLen
- n := count
- // 二分查找插入位置(按复合 key 排序)
- pos := n
- left, right := 0, n-1
- for left <= right {
- mid := (left + right) / 2
- entryKey := indexEntries[mid*entryLen : mid*entryLen+keyPartLen]
- if compareComposeKey(entryKey, key[:keyPartLen]) >= 0 {
- pos = mid
- right = mid - 1
- } else {
- left = mid + 1
- }
- }
- // 移动后续条目腾出空间
- if pos < n {
- copy(indexEntries[(pos+1)*entryLen:], indexEntries[pos*entryLen:n*entryLen])
- }
- // 写入新条目 [composeKey + PK_ID(8B)]
- entry := indexEntries[pos*entryLen : (pos+1)*entryLen]
- copy(entry[:keyPartLen], key[:keyPartLen])
- binary.BigEndian.PutUint64(entry[keyPartLen:], pkID)
- return nil
- }
- // Search 二分查找复合 key,返回 PK_ID 的 8 字节编码
- func (c *ComposeEntryPage) Search(handle page.HandleDb, indexEntries []byte, entryLen int, key []byte) ([]byte, bool) {
- keyPartLen := entryLen - pkIDLen
- n := len(indexEntries) / entryLen
- if n == 0 {
- return nil, false
- }
- left, right := 0, n-1
- for left <= right {
- mid := (left + right) / 2
- entryKey := indexEntries[mid*entryLen : mid*entryLen+keyPartLen]
- cmp := compareComposeKey(entryKey, key[:keyPartLen])
- if cmp == 0 {
- pkIDBytes := indexEntries[mid*entryLen+keyPartLen : mid*entryLen+keyPartLen+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 (c *ComposeEntryPage) Delete(handle page.HandleDb, indexEntries []byte, entryLen int, key []byte) error {
- keyPartLen := entryLen - pkIDLen
- n := len(indexEntries) / entryLen
- pos := -1
- left, right := 0, n-1
- for left <= right {
- mid := (left + right) / 2
- entryKey := indexEntries[mid*entryLen : mid*entryLen+keyPartLen]
- cmp := compareComposeKey(entryKey, key[:keyPartLen])
- 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)
- // 更新 Count
- countPtr := (*uint32)(unsafe.Add(unsafe.Pointer(&indexEntries[0]), -countBackOffset))
- *countPtr--
- return nil
- }
- // Update 复合索引不支持直接更新
- func (c *ComposeEntryPage) Update(handle page.HandleDb, indexEntries []byte, entryLen int, key []byte, pkID uint64, rowData []byte) error {
- return errors.New("compose index does not support update")
- }
- // CreateDataPage 复合索引不需要创建数据页
- func (c *ComposeEntryPage) CreateDataPage(handle page.HandleDb, key []byte, pkID uint64, rowData []byte) (uint32, error) {
- return 0, errors.New("compose index does not create data pages")
- }
- // ======================== 工具函数 ========================
- // compareComposeKey 比较两个复合 key(每个字段 8 字节 BigEndian)
- func compareComposeKey(a, b []byte) int {
- keyCount := len(a) / 8
- for i := 0; i < keyCount; i++ {
- va := binary.BigEndian.Uint64(a[i*8:])
- vb := binary.BigEndian.Uint64(b[i*8:])
- if va < vb {
- return -1
- }
- if va > vb {
- return 1
- }
- }
- return 0
- }
|