100 lines
2.1 KiB
Go
100 lines
2.1 KiB
Go
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
|
|
}
|