| package common |
| |
| import "unsafe" |
| |
| // Inode represents an internal node inside of a node. |
| // It can be used to point to elements in a page or point |
| // to an element which hasn't been added to a page yet. |
| type Inode struct { |
| flags uint32 |
| pgid Pgid |
| key []byte |
| value []byte |
| } |
| |
| type Inodes []Inode |
| |
| func (in *Inode) Flags() uint32 { |
| return in.flags |
| } |
| |
| func (in *Inode) SetFlags(flags uint32) { |
| in.flags = flags |
| } |
| |
| func (in *Inode) Pgid() Pgid { |
| return in.pgid |
| } |
| |
| func (in *Inode) SetPgid(id Pgid) { |
| in.pgid = id |
| } |
| |
| func (in *Inode) Key() []byte { |
| return in.key |
| } |
| |
| func (in *Inode) SetKey(key []byte) { |
| in.key = key |
| } |
| |
| func (in *Inode) Value() []byte { |
| return in.value |
| } |
| |
| func (in *Inode) SetValue(value []byte) { |
| in.value = value |
| } |
| |
| func ReadInodeFromPage(p *Page) Inodes { |
| inodes := make(Inodes, int(p.Count())) |
| isLeaf := p.IsLeafPage() |
| for i := 0; i < int(p.Count()); i++ { |
| inode := &inodes[i] |
| if isLeaf { |
| elem := p.LeafPageElement(uint16(i)) |
| inode.SetFlags(elem.Flags()) |
| inode.SetKey(elem.Key()) |
| inode.SetValue(elem.Value()) |
| } else { |
| elem := p.BranchPageElement(uint16(i)) |
| inode.SetPgid(elem.Pgid()) |
| inode.SetKey(elem.Key()) |
| } |
| Assert(len(inode.Key()) > 0, "read: zero-length inode key") |
| } |
| |
| return inodes |
| } |
| |
| func WriteInodeToPage(inodes Inodes, p *Page) uint32 { |
| // Loop over each item and write it to the page. |
| // off tracks the offset into p of the start of the next data. |
| off := unsafe.Sizeof(*p) + p.PageElementSize()*uintptr(len(inodes)) |
| isLeaf := p.IsLeafPage() |
| for i, item := range inodes { |
| Assert(len(item.Key()) > 0, "write: zero-length inode key") |
| |
| // Create a slice to write into of needed size and advance |
| // byte pointer for next iteration. |
| sz := len(item.Key()) + len(item.Value()) |
| b := UnsafeByteSlice(unsafe.Pointer(p), off, 0, sz) |
| off += uintptr(sz) |
| |
| // Write the page element. |
| if isLeaf { |
| elem := p.LeafPageElement(uint16(i)) |
| elem.SetPos(uint32(uintptr(unsafe.Pointer(&b[0])) - uintptr(unsafe.Pointer(elem)))) |
| elem.SetFlags(item.Flags()) |
| elem.SetKsize(uint32(len(item.Key()))) |
| elem.SetVsize(uint32(len(item.Value()))) |
| } else { |
| elem := p.BranchPageElement(uint16(i)) |
| elem.SetPos(uint32(uintptr(unsafe.Pointer(&b[0])) - uintptr(unsafe.Pointer(elem)))) |
| elem.SetKsize(uint32(len(item.Key()))) |
| elem.SetPgid(item.Pgid()) |
| Assert(elem.Pgid() != p.Id(), "write: circular dependency occurred") |
| } |
| |
| // Write data for the element to the end of the page. |
| l := copy(b, item.Key()) |
| copy(b[l:], item.Value()) |
| } |
| |
| return uint32(off) |
| } |
| |
| func UsedSpaceInPage(inodes Inodes, p *Page) uint32 { |
| off := unsafe.Sizeof(*p) + p.PageElementSize()*uintptr(len(inodes)) |
| for _, item := range inodes { |
| sz := len(item.Key()) + len(item.Value()) |
| off += uintptr(sz) |
| } |
| |
| return uint32(off) |
| } |