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 } func DeSerializePage(data []byte) (*Page, error) { head, err := DeSerializePageHead(data[0:BlockFileHeaderSize]) if err != nil { return nil, err } if head.CellCount == 0 { return &Page{ PageHead: head, Cells: []*Cell{}, data: data, }, nil } cells := make([]*Cell, head.CellCount) // find cell offset array start 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") } currentFreeOffset := head.FirstFreeOffset for i := 0; i < head.CellCount; i++ { cellOffset := binary.LittleEndian.Uint32(data[cellPOffset+i*4 : cellPOffset+i*4+4]) nextOffSet := binary.LittleEndian.Uint32(data[cellOffset : cellOffset+4]) cellSize := nextOffSet - cellOffset cells[i] = &Cell{ IsFree: false, NextFreeOffset: 0, ActualSize: int(cellSize), Start: Offset(cellOffset), } if cellOffset == uint32(currentFreeOffset) { cells[i].IsFree = true cells[i].NextFreeOffset = Offset(binary.LittleEndian.Uint32(data[cellOffset+4 : cellOffset+8])) currentFreeOffset = cells[i].NextFreeOffset } } return &Page{ PageHead: head, Cells: cells, data: data, }, nil }