From 15d561e54fd43b4985e30adbef5b018f34c64576 Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Wed, 15 Mar 2023 08:44:19 +0800 Subject: [PATCH] move inode operations(read/write) into package internal/common Signed-off-by: Benjamin Wang --- internal/common/inode.go | 60 ++++++++++++++++++++++++++++++++++++++++ internal/common/page.go | 7 +++++ node.go | 50 ++------------------------------- 3 files changed, 69 insertions(+), 48 deletions(-) diff --git a/internal/common/inode.go b/internal/common/inode.go index f8711cf15..9f99937e7 100644 --- a/internal/common/inode.go +++ b/internal/common/inode.go @@ -1,5 +1,7 @@ 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. @@ -43,3 +45,61 @@ func (in *Inode) Value() []byte { 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) +} diff --git a/internal/common/page.go b/internal/common/page.go index cd8abf831..504feb8f3 100644 --- a/internal/common/page.go +++ b/internal/common/page.go @@ -162,6 +162,13 @@ func (p *Page) hexdump(n int) { fmt.Fprintf(os.Stderr, "%x\n", buf) } +func (p *Page) PageElementSize() uintptr { + if p.IsLeafPage() { + return LeafPageElementSize + } + return BranchPageElementSize +} + func (p *Page) Id() Pgid { return p.id } diff --git a/node.go b/node.go index 5f3518faf..05504c0c6 100644 --- a/node.go +++ b/node.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "sort" - "unsafe" "go.etcd.io/bbolt/internal/common" ) @@ -163,22 +162,7 @@ func (n *node) del(key []byte) { func (n *node) read(p *common.Page) { n.pgid = p.Id() n.isLeaf = p.IsLeafPage() - n.inodes = make(common.Inodes, int(p.Count())) - - for i := 0; i < int(p.Count()); i++ { - inode := &n.inodes[i] - if n.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()) - } - common.Assert(len(inode.Key()) > 0, "read: zero-length inode key") - } + n.inodes = common.ReadInodeFromPage(p) // Save first key, so we can find the node in the parent when we spill. if len(n.inodes) > 0 { @@ -212,37 +196,7 @@ func (n *node) write(p *common.Page) { return } - // 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) + n.pageElementSize()*uintptr(len(n.inodes)) - for i, item := range n.inodes { - common.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 := common.UnsafeByteSlice(unsafe.Pointer(p), off, 0, sz) - off += uintptr(sz) - - // Write the page element. - if n.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()) - common.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()) - } + common.WriteInodeToPage(n.inodes, p) // DEBUG ONLY: n.dump() }