package gobplustree import ( "encoding/binary" "errors" ) type PageType int8 type Offset uint32 const ( PageTypeLeaf PageType = iota PageTypeInternal ) const ( CellHeaderSize = 17 ) type PageHead struct { PageId int64 Type PageType CellCount int FirstFreeOffset Offset } type Cell struct { IsFree bool NextFreeOffset Offset ActualSize int Start Offset } type Page struct { *PageHead Cells []*Cell data []byte } func DeSerializePageHead(data []byte) (*PageHead, error) { PageId := binary.LittleEndian.Uint64(data[0:8]) Type := PageType(data[8]) CellCount := int(data[9]) FirstFreeOffset := Offset(data[10]) return &PageHead{ PageId: int64(PageId), Type: Type, CellCount: CellCount, FirstFreeOffset: FirstFreeOffset, }, nil } // DeSerializePage 从字节数据中反序列化Page结构 // data: 包含页面数据的字节切片 // 返回值: 解析出的Page指针和可能的错误 func DeSerializePage(data []byte) (*Page, error) { head, err := DeSerializePageHead(data[0:BlockFileHeaderSize]) if err != nil { return nil, err } // 如果没有cell,直接返回空的cells数组 if head.CellCount == 0 { return &Page{ PageHead: head, Cells: []*Cell{}, data: data, }, nil } cells := make([]*Cell, head.CellCount) // 查找cell偏移数组的起始位置 cellPOffset := 0 for i := 17; i < BlockFilePageSize; i++ { t := binary.LittleEndian.Uint32(data[i : i+4]) if t != 0 { cellPOffset = i break } } if cellPOffset == 0 { return nil, errors.New("invalid page") } previousCellOffset := 0 currentFreeOffset := head.FirstFreeOffset // 遍历所有cell,解析每个cell的信息 for i := 0; i < head.CellCount; i++ { cellOffset := binary.LittleEndian.Uint32(data[cellPOffset+i*4 : cellPOffset+i*4+4]) cellSize := 0 // cell if from end to start if i == 0 { cellSize = BlockFilePageSize - int(cellOffset) } else { cellSize = int(cellOffset) - int(previousCellOffset) } cells[i] = &Cell{ IsFree: false, NextFreeOffset: 0, ActualSize: int(cellSize), Start: Offset(cellOffset), } // 检查当前cell是否为空闲cell if cellOffset == uint32(currentFreeOffset) { cells[i].IsFree = true cells[i].NextFreeOffset = Offset(binary.LittleEndian.Uint32(data[cellOffset+4 : cellOffset+8])) currentFreeOffset = cells[i].NextFreeOffset } previousCellOffset = int(cellOffset) } return &Page{ PageHead: head, Cells: cells, data: data, }, nil } func (p *Page) Serialize() []byte { // 写入PageHead binary.LittleEndian.PutUint64(p.data[0:8], uint64(p.PageId)) p.data[8] = byte(p.Type) p.data[9] = byte(p.CellCount) p.data[10] = byte(p.FirstFreeOffset) // 写入Cell偏移数组 lastCellOffset := p.Cells[p.CellCount-1].Start cellOffsets := make([]byte, p.CellCount*4) for i, cell := range p.Cells { binary.LittleEndian.PutUint32(cellOffsets[i*4:i*4+4], uint32(cell.Start)) } copy(p.data[int(lastCellOffset)-len(cellOffsets):lastCellOffset], cellOffsets) return p.data } func (p *Page) GetCell(index int) *Cell { return p.Cells[index] } func (p *Page) GetCellData(cell *Cell) []byte { return p.data[cell.Start : cell.Start+Offset(cell.ActualSize)] } func (p *Page) WriteNewCell(data []byte) (*Cell, error) { }