package strdatapage import ( "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 字节处 countAddr := uintptr(unsafe.Pointer(&indexEntries[0])) - uintptr(countBackOffset) countPtr := (*uint32)(unsafe.Pointer(countAddr)) *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, rowData []byte) (uint32, error) { return 0, errors.New("string index does not create data pages") }