Skip to content

Commit

Permalink
feat: add meta page abstraction (#21)
Browse files Browse the repository at this point in the history
Closes #16
  • Loading branch information
kevmo314 authored Jan 2, 2024
1 parent 02a56c9 commit 9455e8d
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 35 deletions.
46 changes: 18 additions & 28 deletions pkg/btree/bptree.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,27 @@ import (
"slices"
)

// MetaPage is an abstract interface over the root page of a btree
// This allows the caller to control the memory location of the meta
// pointer
type MetaPage interface {
Root() (MemoryPointer, error)
SetRoot(MemoryPointer) error
}

type ReadWriteSeekTruncater interface {
io.ReadWriteSeeker
Truncate(size int64) error
}

type BPTree struct {
tree ReadWriteSeekTruncater
meta MetaPage

maxPageSize int
}

func NewBPTree(tree ReadWriteSeekTruncater, maxPageSize int) (*BPTree, error) {
func NewBPTree(tree ReadWriteSeekTruncater, meta MetaPage, maxPageSize int) (*BPTree, error) {
// read the root from the meta page
var root uint64
if err := binary.Read(tree, binary.BigEndian, &root); err != nil {
Expand All @@ -35,21 +44,12 @@ func NewBPTree(tree ReadWriteSeekTruncater, maxPageSize int) (*BPTree, error) {
return nil, err
}
}
return &BPTree{tree: tree, maxPageSize: maxPageSize}, nil
return &BPTree{tree: tree, meta: meta, maxPageSize: maxPageSize}, nil
}

func (t *BPTree) root() (*BPTreeNode, MemoryPointer, error) {
mp := MemoryPointer{}
if _, err := t.tree.Seek(0, io.SeekStart); err != nil {
return nil, mp, err
}
if err := binary.Read(t.tree, binary.BigEndian, &mp.Offset); err != nil {
return nil, mp, err
}
if err := binary.Read(t.tree, binary.BigEndian, &mp.Length); err != nil {
return nil, mp, err
}
if mp.Offset == 0 || mp.Length == 0 {
mp, err := t.meta.Root()
if err != nil || mp.Offset == 0 || mp.Length == 0 {
return nil, mp, nil
}
root, err := t.readNode(mp)
Expand All @@ -59,16 +59,6 @@ func (t *BPTree) root() (*BPTreeNode, MemoryPointer, error) {
return root, mp, nil
}

func (t *BPTree) writeRoot(mp MemoryPointer) error {
if _, err := t.tree.Seek(0, io.SeekStart); err != nil {
return err
}
if err := binary.Write(t.tree, binary.BigEndian, mp.Offset); err != nil {
return err
}
return binary.Write(t.tree, binary.BigEndian, mp.Length)
}

func (t *BPTree) Find(key []byte) (MemoryPointer, bool, error) {
root, _, err := t.root()
if err != nil {
Expand Down Expand Up @@ -153,7 +143,7 @@ func (t *BPTree) Insert(key []byte, value MemoryPointer) error {
if err != nil {
return err
}
return t.writeRoot(MemoryPointer{Offset: uint64(offset), Length: uint32(length)})
return t.meta.SetRoot(MemoryPointer{Offset: uint64(offset), Length: uint32(length)})
}
path, err := t.traverse(key, root)
if err != nil {
Expand Down Expand Up @@ -249,7 +239,7 @@ func (t *BPTree) Insert(key []byte, value MemoryPointer) error {
if err != nil {
return err
}
return t.writeRoot(MemoryPointer{Offset: uint64(poffset), Length: uint32(psize)})
return t.meta.SetRoot(MemoryPointer{Offset: uint64(poffset), Length: uint32(psize)})
}
} else {
// write this node to disk and update the parent
Expand All @@ -268,7 +258,7 @@ func (t *BPTree) Insert(key []byte, value MemoryPointer) error {
p.node.Pointers[p.index] = MemoryPointer{Offset: uint64(offset), Length: uint32(length)}
} else {
// update the root
return t.writeRoot(MemoryPointer{Offset: uint64(offset), Length: uint32(length)})
return t.meta.SetRoot(MemoryPointer{Offset: uint64(offset), Length: uint32(length)})
}
}
}
Expand Down Expand Up @@ -359,7 +349,7 @@ type Entry struct {
// parents = nextParents
// if len(parents) == 1 {
// // this is the root
// return t.writeRoot(parents[0].pointer)
// return t.meta.SetRoot(parents[0].pointer)
// }
// }
// }
Expand Down Expand Up @@ -468,7 +458,7 @@ func (t *BPTree) compact() error {
}

// update the meta pointer
return t.writeRoot(referenceMap[rootOffset.Offset])
return t.meta.SetRoot(referenceMap[rootOffset.Offset])
}

func (t *BPTree) String() string {
Expand Down
27 changes: 20 additions & 7 deletions pkg/btree/bptree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,23 @@ import (
"testing"
)

type testMetaPage struct {
root MemoryPointer
}

func (m *testMetaPage) SetRoot(mp MemoryPointer) error {
m.root = mp
return nil
}

func (m *testMetaPage) Root() (MemoryPointer, error) {
return m.root, nil
}

func TestBPTree(t *testing.T) {
t.Run("empty tree", func(t *testing.T) {
b := newSeekableBuffer()
tree, err := NewBPTree(b, 4096)
tree, err := NewBPTree(b, &testMetaPage{}, 4096)
if err != nil {
t.Fatal(err)
}
Expand All @@ -25,7 +38,7 @@ func TestBPTree(t *testing.T) {

t.Run("insert creates a root", func(t *testing.T) {
b := newSeekableBuffer()
tree, err := NewBPTree(b, 4096)
tree, err := NewBPTree(b, &testMetaPage{}, 4096)
if err != nil {
t.Fatal(err)
}
Expand All @@ -46,7 +59,7 @@ func TestBPTree(t *testing.T) {

t.Run("insert into root", func(t *testing.T) {
b := newSeekableBuffer()
tree, err := NewBPTree(b, 4096)
tree, err := NewBPTree(b, &testMetaPage{}, 4096)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -80,7 +93,7 @@ func TestBPTree(t *testing.T) {

t.Run("compacting after second root insertion removes old root", func(t *testing.T) {
b := newSeekableBuffer()
tree, err := NewBPTree(b, 4096)
tree, err := NewBPTree(b, &testMetaPage{}, 4096)
if err != nil {
t.Fatal(err)
}
Expand All @@ -107,7 +120,7 @@ func TestBPTree(t *testing.T) {

t.Run("split root", func(t *testing.T) {
b := newSeekableBuffer()
tree, err := NewBPTree(b, 4096)
tree, err := NewBPTree(b, &testMetaPage{}, 4096)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -170,7 +183,7 @@ func TestBPTree(t *testing.T) {

t.Run("split intermediate", func(t *testing.T) {
b := newSeekableBuffer()
tree, err := NewBPTree(b, 2)
tree, err := NewBPTree(b, &testMetaPage{}, 2)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -203,7 +216,7 @@ func TestBPTree(t *testing.T) {

t.Run("insertion test", func(t *testing.T) {
b := newSeekableBuffer()
tree, err := NewBPTree(b, 512)
tree, err := NewBPTree(b, &testMetaPage{}, 512)
if err != nil {
t.Fatal(err)
}
Expand Down

0 comments on commit 9455e8d

Please sign in to comment.