116 lines
2.7 KiB
Go
116 lines
2.7 KiB
Go
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)
|
|
}
|