From 9803bba7360404b2b203d1cef3bc5d61973c4279 Mon Sep 17 00:00:00 2001 From: Matthew Kim <38759997+friendlymatthew@users.noreply.github.com> Date: Mon, 24 Jun 2024 11:47:47 -0400 Subject: [PATCH] code movement --- pkg/bptree/bptree.go | 42 ++++++++-------- pkg/bptree/bptree_test.go | 86 ++++++++++++++++----------------- pkg/bptree/node.go | 39 ++------------- pkg/bptree/node_test.go | 8 +-- pkg/handlers/csv.go | 2 +- pkg/handlers/csv_test.go | 10 ++-- pkg/handlers/equality_test.go | 8 +-- pkg/handlers/jsonl.go | 12 ++--- pkg/handlers/jsonl_test.go | 22 ++++----- pkg/mocks/btree.go | 12 ++--- pkg/mocks/node.go | 4 +- pkg/pointer/referenced_value.go | 38 +++++++++++++++ 12 files changed, 144 insertions(+), 139 deletions(-) create mode 100644 pkg/pointer/referenced_value.go diff --git a/pkg/bptree/bptree.go b/pkg/bptree/bptree.go index d0bf5282..9e9fd9c5 100644 --- a/pkg/bptree/bptree.go +++ b/pkg/bptree/bptree.go @@ -42,12 +42,12 @@ type TraversalRecord struct { type TraversalIterator struct { tree *BPTree - key ReferencedValue + key pointer.ReferencedValue records []TraversalRecord err error } -func (p *TraversalIterator) Key() ReferencedValue { +func (p *TraversalIterator) Key() pointer.ReferencedValue { return p.records[0].node.Keys[p.records[0].index] } @@ -133,22 +133,22 @@ func (p *TraversalIterator) Err() error { return p.err } -func (t *BPTree) Iter(key ReferencedValue) (*TraversalIterator, error) { +func (t *BPTree) Iter(key pointer.ReferencedValue) (*TraversalIterator, error) { return &TraversalIterator{tree: t, key: key}, nil } -func (t *BPTree) Find(key ReferencedValue) (ReferencedValue, pointer.MemoryPointer, error) { +func (t *BPTree) Find(key pointer.ReferencedValue) (pointer.ReferencedValue, pointer.MemoryPointer, error) { p, err := t.Iter(key) if err != nil { - return ReferencedValue{}, pointer.MemoryPointer{}, err + return pointer.ReferencedValue{}, pointer.MemoryPointer{}, err } if !p.Next() { - return ReferencedValue{}, pointer.MemoryPointer{}, p.Err() + return pointer.ReferencedValue{}, pointer.MemoryPointer{}, p.Err() } return p.Key(), p.Pointer(), nil } -func (t *BPTree) Contains(key ReferencedValue) (bool, error) { +func (t *BPTree) Contains(key pointer.ReferencedValue) (bool, error) { k, _, err := t.Find(key) if err != nil { return false, err @@ -172,16 +172,16 @@ func (t *BPTree) readNode(ptr pointer.MemoryPointer) (*BPTreeNode, error) { return node, nil } -func (t *BPTree) first() (ReferencedValue, error) { +func (t *BPTree) first() (pointer.ReferencedValue, error) { rootNode, _, err := t.root() if err != nil { - return ReferencedValue{}, err + return pointer.ReferencedValue{}, err } currNode, err := t.readNode(rootNode.Pointer(0)) if err != nil { - return ReferencedValue{}, err + return pointer.ReferencedValue{}, err } for !currNode.Leaf() { @@ -189,23 +189,23 @@ func (t *BPTree) first() (ReferencedValue, error) { currNode, err = t.readNode(childPointer) if err != nil { - return ReferencedValue{}, err + return pointer.ReferencedValue{}, err } } return currNode.Keys[0], nil } -func (t *BPTree) last() (ReferencedValue, error) { +func (t *BPTree) last() (pointer.ReferencedValue, error) { rootNode, _, err := t.root() if err != nil { - return ReferencedValue{}, err + return pointer.ReferencedValue{}, err } currNode, err := t.readNode(rootNode.Pointer(rootNode.NumPointers() - 1)) if err != nil { - return ReferencedValue{}, err + return pointer.ReferencedValue{}, err } for !currNode.Leaf() { @@ -213,7 +213,7 @@ func (t *BPTree) last() (ReferencedValue, error) { currNode, err = t.readNode(childPointer) if err != nil { - return ReferencedValue{}, err + return pointer.ReferencedValue{}, err } } @@ -222,9 +222,9 @@ func (t *BPTree) last() (ReferencedValue, error) { // traverse returns the path from root to leaf in reverse order (leaf first) // the last element is always the node passed in -func (t *BPTree) traverse(key ReferencedValue, node *BPTreeNode, ptr pointer.MemoryPointer) ([]TraversalRecord, error) { +func (t *BPTree) traverse(key pointer.ReferencedValue, node *BPTreeNode, ptr pointer.MemoryPointer) ([]TraversalRecord, error) { // binary search node.Keys to find the first key greater than key - index, found := slices.BinarySearchFunc(node.Keys, key, CompareReferencedValues) + index, found := slices.BinarySearchFunc(node.Keys, key, pointer.CompareReferencedValues) if node.Leaf() { return []TraversalRecord{{node: node, index: index, ptr: ptr}}, nil @@ -249,7 +249,7 @@ func (t *BPTree) traverse(key ReferencedValue, node *BPTreeNode, ptr pointer.Mem return append(path, TraversalRecord{node: node, index: index, ptr: ptr}), nil } -func (t *BPTree) Insert(key ReferencedValue, value pointer.MemoryPointer) error { +func (t *BPTree) Insert(key pointer.ReferencedValue, value pointer.MemoryPointer) error { if t.Width != uint16(0) { if uint16(len(key.Value)) != t.Width-1 { @@ -264,7 +264,7 @@ func (t *BPTree) Insert(key ReferencedValue, value pointer.MemoryPointer) error if root == nil { // special case, create the root as the first node node := &BPTreeNode{Data: t.Data, DataParser: t.DataParser, Width: t.Width} - node.Keys = []ReferencedValue{key} + node.Keys = []pointer.ReferencedValue{key} node.LeafPointers = []pointer.MemoryPointer{value} buf, err := node.MarshalBinary() if err != nil { @@ -284,7 +284,7 @@ func (t *BPTree) Insert(key ReferencedValue, value pointer.MemoryPointer) error // insert the key into the leaf n := path[0].node - j, found := slices.BinarySearchFunc(n.Keys, key, CompareReferencedValues) + j, found := slices.BinarySearchFunc(n.Keys, key, pointer.CompareReferencedValues) if found { return fmt.Errorf("key already exists. Data pointer: %v", key.DataPointer) @@ -361,7 +361,7 @@ func (t *BPTree) Insert(key ReferencedValue, value pointer.MemoryPointer) error } else { // the root split, so create a new root p := &BPTreeNode{Data: t.Data, DataParser: t.DataParser, Width: t.Width} - p.Keys = []ReferencedValue{midKey} + p.Keys = []pointer.ReferencedValue{midKey} p.InternalPointers = []uint64{ noffset, uint64(moffset), } diff --git a/pkg/bptree/bptree_test.go b/pkg/bptree/bptree_test.go index ea54244f..ac63aee1 100644 --- a/pkg/bptree/bptree_test.go +++ b/pkg/bptree/bptree_test.go @@ -63,7 +63,7 @@ func TestBPTree(t *testing.T) { } tree := &BPTree{PageFile: p, MetaPage: newTestMetaPage(t, p)} // find a key that doesn't exist - k, _, err := tree.Find(ReferencedValue{Value: []byte("hello")}) + k, _, err := tree.Find(pointer.ReferencedValue{Value: []byte("hello")}) if err != nil { t.Fatal(err) } @@ -79,10 +79,10 @@ func TestBPTree(t *testing.T) { t.Fatal(err) } tree := &BPTree{PageFile: p, MetaPage: newTestMetaPage(t, p), Width: uint16(6)} - if err := tree.Insert(ReferencedValue{Value: []byte("hello")}, pointer.MemoryPointer{Offset: 1, Length: 5}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte("hello")}, pointer.MemoryPointer{Offset: 1, Length: 5}); err != nil { t.Fatal(err) } - k, v, err := tree.Find(ReferencedValue{Value: []byte("hello")}) + k, v, err := tree.Find(pointer.ReferencedValue{Value: []byte("hello")}) if err != nil { t.Fatal(err) } @@ -101,13 +101,13 @@ func TestBPTree(t *testing.T) { t.Fatal(err) } tree := &BPTree{PageFile: p, MetaPage: newTestMetaPage(t, p), Width: uint16(6)} - if err := tree.Insert(ReferencedValue{Value: []byte("hello")}, pointer.MemoryPointer{Offset: 1}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte("hello")}, pointer.MemoryPointer{Offset: 1}); err != nil { t.Fatal(err) } - if err := tree.Insert(ReferencedValue{Value: []byte("world")}, pointer.MemoryPointer{Offset: 2}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte("world")}, pointer.MemoryPointer{Offset: 2}); err != nil { t.Fatal(err) } - k1, v1, err := tree.Find(ReferencedValue{Value: []byte("hello")}) + k1, v1, err := tree.Find(pointer.ReferencedValue{Value: []byte("hello")}) if err != nil { t.Fatal(err) } @@ -117,7 +117,7 @@ func TestBPTree(t *testing.T) { if v1.Offset != 1 { t.Fatalf("expected value 1, got %d", v1) } - k2, v2, err := tree.Find(ReferencedValue{Value: []byte("world")}) + k2, v2, err := tree.Find(pointer.ReferencedValue{Value: []byte("world")}) if err != nil { t.Fatal(err) } @@ -137,20 +137,20 @@ func TestBPTree(t *testing.T) { } mp := newTestMetaPage(t, p) tree := &BPTree{PageFile: p, MetaPage: mp, Width: uint16(6)} - if err := tree.Insert(ReferencedValue{Value: []byte("hello")}, pointer.MemoryPointer{Offset: 1, Length: 5}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte("hello")}, pointer.MemoryPointer{Offset: 1, Length: 5}); err != nil { t.Fatal(err) } - if err := tree.Insert(ReferencedValue{Value: []byte("world")}, pointer.MemoryPointer{Offset: 2, Length: 5}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte("world")}, pointer.MemoryPointer{Offset: 2, Length: 5}); err != nil { t.Fatal(err) } - if err := tree.Insert(ReferencedValue{Value: []byte("moooo")}, pointer.MemoryPointer{Offset: 3, Length: 5}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte("moooo")}, pointer.MemoryPointer{Offset: 3, Length: 5}); err != nil { t.Fatal(err) } - if err := tree.Insert(ReferencedValue{Value: []byte("cooow")}, pointer.MemoryPointer{Offset: 4, Length: 5}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte("cooow")}, pointer.MemoryPointer{Offset: 4, Length: 5}); err != nil { t.Fatal(err) } - k1, v1, err := tree.Find(ReferencedValue{Value: []byte("hello")}) + k1, v1, err := tree.Find(pointer.ReferencedValue{Value: []byte("hello")}) if err != nil { t.Fatal(err) } @@ -160,7 +160,7 @@ func TestBPTree(t *testing.T) { if v1.Offset != 1 { t.Fatalf("expected value 1, got %d", v1) } - k2, v2, err := tree.Find(ReferencedValue{Value: []byte("world")}) + k2, v2, err := tree.Find(pointer.ReferencedValue{Value: []byte("world")}) if err != nil { t.Fatal(err) } @@ -170,7 +170,7 @@ func TestBPTree(t *testing.T) { if v2.Offset != 2 { t.Fatalf("expected value 2, got %d", v2) } - k3, v3, err := tree.Find(ReferencedValue{Value: []byte("moooo")}) + k3, v3, err := tree.Find(pointer.ReferencedValue{Value: []byte("moooo")}) if err != nil { t.Fatal(err) } @@ -180,7 +180,7 @@ func TestBPTree(t *testing.T) { if v3.Offset != 3 { t.Fatalf("expected value 3, got %d", v3) } - k4, v4, err := tree.Find(ReferencedValue{Value: []byte("cooow")}) + k4, v4, err := tree.Find(pointer.ReferencedValue{Value: []byte("cooow")}) if err != nil { t.Fatal(err) } @@ -200,19 +200,19 @@ func TestBPTree(t *testing.T) { } tree := &BPTree{PageFile: p, MetaPage: newTestMetaPage(t, p), Width: uint16(2)} - if err := tree.Insert(ReferencedValue{Value: []byte{0x05}}, pointer.MemoryPointer{Offset: 5}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte{0x05}}, pointer.MemoryPointer{Offset: 5}); err != nil { t.Fatal(err) } - if err := tree.Insert(ReferencedValue{Value: []byte{0x10}}, pointer.MemoryPointer{Offset: 10}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte{0x10}}, pointer.MemoryPointer{Offset: 10}); err != nil { t.Fatal(err) } - if err := tree.Insert(ReferencedValue{Value: []byte{0x15}}, pointer.MemoryPointer{Offset: 15}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte{0x15}}, pointer.MemoryPointer{Offset: 15}); err != nil { t.Fatal(err) } - if err := tree.Insert(ReferencedValue{Value: []byte{0x20}}, pointer.MemoryPointer{Offset: 20}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte{0x20}}, pointer.MemoryPointer{Offset: 20}); err != nil { t.Fatal(err) } - if err := tree.Insert(ReferencedValue{Value: []byte{0x25}}, pointer.MemoryPointer{Offset: 25}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte{0x25}}, pointer.MemoryPointer{Offset: 25}); err != nil { t.Fatal(err) } }) @@ -225,15 +225,15 @@ func TestBPTree(t *testing.T) { } tree := &BPTree{PageFile: p, MetaPage: newTestMetaPage(t, p), Width: uint16(2)} - if err := tree.Insert(ReferencedValue{Value: []byte{byte(1)}}, pointer.MemoryPointer{Offset: 5}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte{byte(1)}}, pointer.MemoryPointer{Offset: 5}); err != nil { t.Fatal(err) } - if err := tree.Insert(ReferencedValue{Value: []byte{byte(2)}}, pointer.MemoryPointer{Offset: 10}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte{byte(2)}}, pointer.MemoryPointer{Offset: 10}); err != nil { t.Fatal(err) } for _, byteVal := range []byte{1, 2} { - res, err := tree.Contains(ReferencedValue{Value: []byte{byteVal}}) + res, err := tree.Contains(pointer.ReferencedValue{Value: []byte{byteVal}}) if err != nil { t.Fatal(err) } @@ -243,7 +243,7 @@ func TestBPTree(t *testing.T) { } } - res, err := tree.Contains(ReferencedValue{Value: []byte{byte(3)}}) + res, err := tree.Contains(pointer.ReferencedValue{Value: []byte{byte(3)}}) if err != nil { t.Fatal(err) } @@ -266,7 +266,7 @@ func TestBPTree_SequentialInsertionTest(t *testing.T) { for i := 0; i < 256; i++ { buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, uint64(i)) - if err := tree.Insert(ReferencedValue{Value: buf}, pointer.MemoryPointer{Offset: uint64(i), Length: uint32(len(buf))}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: buf}, pointer.MemoryPointer{Offset: uint64(i), Length: uint32(len(buf))}); err != nil { t.Fatal(err) } } @@ -274,7 +274,7 @@ func TestBPTree_SequentialInsertionTest(t *testing.T) { for i := 0; i < 256; i++ { buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, uint64(i)) - k, v, err := tree.Find(ReferencedValue{Value: buf}) + k, v, err := tree.Find(pointer.ReferencedValue{Value: buf}) if err != nil { t.Fatal(err) } @@ -307,7 +307,7 @@ func TestBPTree_RandomTests(t *testing.T) { if _, err := r.Read(buf); err != nil { t.Fatal(err) } - if err := tree.Insert(ReferencedValue{Value: buf}, pointer.MemoryPointer{Offset: uint64(i)}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: buf}, pointer.MemoryPointer{Offset: uint64(i)}); err != nil { t.Fatal(err) } } @@ -317,7 +317,7 @@ func TestBPTree_RandomTests(t *testing.T) { if _, err := s.Read(buf); err != nil { t.Fatal(err) } - k, v, err := tree.Find(ReferencedValue{Value: buf}) + k, v, err := tree.Find(pointer.ReferencedValue{Value: buf}) if err != nil { t.Fatal(err) } @@ -338,7 +338,7 @@ func TestBPTree_RandomTests(t *testing.T) { } tree := &BPTree{PageFile: p, MetaPage: newTestMetaPage(t, p), Data: make([]byte, 65536*4+8), DataParser: &StubDataParser{}} for i := 0; i < 65536*4; i++ { - if err := tree.Insert(ReferencedValue{ + if err := tree.Insert(pointer.ReferencedValue{ Value: []byte{1, 2, 3, 4, 5, 6, 7, 8}, // DataPointer is used as a disambiguator. DataPointer: pointer.MemoryPointer{Offset: uint64(i), Length: 8}, @@ -377,7 +377,7 @@ func TestBPTree_Iteration(t *testing.T) { metaPage := newTestMetaPage(t, p) tree := &BPTree{PageFile: p, MetaPage: metaPage, Data: make([]byte, 16384*4+8), DataParser: &StubDataParser{}} for i := 0; i < 16384*4; i++ { - if err := tree.Insert(ReferencedValue{ + if err := tree.Insert(pointer.ReferencedValue{ Value: []byte{1, 2, 3, 4, 5, 6, 7, 8}, // DataPointer is used as a disambiguator. DataPointer: pointer.MemoryPointer{Offset: uint64(i), Length: 8}, @@ -387,7 +387,7 @@ func TestBPTree_Iteration(t *testing.T) { } t.Run("forward iteration", func(t *testing.T) { - iter, err := tree.Iter(ReferencedValue{Value: []byte{1, 2, 3, 4, 5, 6, 7, 8}}) + iter, err := tree.Iter(pointer.ReferencedValue{Value: []byte{1, 2, 3, 4, 5, 6, 7, 8}}) if err != nil { t.Fatal(err) } @@ -414,7 +414,7 @@ func TestBPTree_Iteration(t *testing.T) { }) t.Run("reverse iteration", func(t *testing.T) { - iter, err := tree.Iter(ReferencedValue{Value: []byte{1, 2, 3, 4, 5, 6, 7, 8}, DataPointer: pointer.MemoryPointer{Offset: math.MaxUint64}}) + iter, err := tree.Iter(pointer.ReferencedValue{Value: []byte{1, 2, 3, 4, 5, 6, 7, 8}, DataPointer: pointer.MemoryPointer{Offset: math.MaxUint64}}) if err != nil { t.Fatal(err) } @@ -450,7 +450,7 @@ func TestBPTree_Iteration_SinglePage(t *testing.T) { metaPage := newTestMetaPage(t, p) tree := &BPTree{PageFile: p, MetaPage: metaPage, Data: make([]byte, 64+8), DataParser: &StubDataParser{}} for i := 0; i < 64; i++ { - if err := tree.Insert(ReferencedValue{ + if err := tree.Insert(pointer.ReferencedValue{ Value: []byte{1, 2, 3, 4, 5, 6, 7, 8}, // DataPointer is used as a disambiguator. DataPointer: pointer.MemoryPointer{Offset: uint64(i), Length: 8}, @@ -460,7 +460,7 @@ func TestBPTree_Iteration_SinglePage(t *testing.T) { } t.Run("forward iteration", func(t *testing.T) { - iter, err := tree.Iter(ReferencedValue{Value: []byte{1, 2, 3, 4, 5, 6, 7, 8}}) + iter, err := tree.Iter(pointer.ReferencedValue{Value: []byte{1, 2, 3, 4, 5, 6, 7, 8}}) if err != nil { t.Fatal(err) } @@ -487,7 +487,7 @@ func TestBPTree_Iteration_SinglePage(t *testing.T) { }) t.Run("reverse iteration", func(t *testing.T) { - iter, err := tree.Iter(ReferencedValue{Value: []byte{1, 2, 3, 4, 5, 6, 7, 8}, DataPointer: pointer.MemoryPointer{Offset: math.MaxUint64}}) + iter, err := tree.Iter(pointer.ReferencedValue{Value: []byte{1, 2, 3, 4, 5, 6, 7, 8}, DataPointer: pointer.MemoryPointer{Offset: math.MaxUint64}}) if err != nil { t.Fatal(err) } @@ -529,7 +529,7 @@ func TestBPTree_Iteration_FirstLast(t *testing.T) { buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, math.Float64bits(i)) - if err := tree.Insert(ReferencedValue{Value: buf}, pointer.MemoryPointer{Offset: uint64(i * 100), Length: uint32(len(buf))}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: buf}, pointer.MemoryPointer{Offset: uint64(i * 100), Length: uint32(len(buf))}); err != nil { t.Fatal(err) } @@ -619,7 +619,7 @@ func TestBPTree_IncorrectWidth(t *testing.T) { } floatTree := &BPTree{PageFile: p, MetaPage: newTestMetaPage(t, p), Width: uint16(9)} - if err := floatTree.Insert(ReferencedValue{Value: []byte{1}, DataPointer: pointer.MemoryPointer{Offset: uint64(0)}}, pointer.MemoryPointer{Offset: uint64(0), Length: uint32(39)}); err == nil { + if err := floatTree.Insert(pointer.ReferencedValue{Value: []byte{1}, DataPointer: pointer.MemoryPointer{Offset: uint64(0)}}, pointer.MemoryPointer{Offset: uint64(0), Length: uint32(39)}); err == nil { t.Fatalf("should error %v", err) } }) @@ -632,7 +632,7 @@ func TestBPTree_IncorrectWidth(t *testing.T) { } nilTree := &BPTree{PageFile: p, MetaPage: newTestMetaPage(t, p), Width: uint16(1)} - if err := nilTree.Insert(ReferencedValue{Value: []byte{1}, DataPointer: pointer.MemoryPointer{Offset: uint64(0)}}, pointer.MemoryPointer{Offset: uint64(0), Length: uint32(39)}); err == nil { + if err := nilTree.Insert(pointer.ReferencedValue{Value: []byte{1}, DataPointer: pointer.MemoryPointer{Offset: uint64(0)}}, pointer.MemoryPointer{Offset: uint64(0), Length: uint32(39)}); err == nil { t.Fatalf("should error %v", err) } }) @@ -652,7 +652,7 @@ func TestBPTree_Iteration_Overcount(t *testing.T) { buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, math.Float64bits(23)) - if err := tree.Insert(ReferencedValue{Value: buf, DataPointer: pointer.MemoryPointer{Offset: uint64(i)}}, pointer.MemoryPointer{Offset: uint64(i), Length: uint32(len(buf))}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: buf, DataPointer: pointer.MemoryPointer{Offset: uint64(i)}}, pointer.MemoryPointer{Offset: uint64(i), Length: uint32(len(buf))}); err != nil { t.Fatal(err) } } @@ -661,7 +661,7 @@ func TestBPTree_Iteration_Overcount(t *testing.T) { buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, math.Float64bits(23)) - valueRef := ReferencedValue{ + valueRef := pointer.ReferencedValue{ Value: buf, } @@ -706,7 +706,7 @@ func TestBPTree_Iteration_EmptyTree(t *testing.T) { buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, math.Float64bits(23)) - valueRef := ReferencedValue{ + valueRef := pointer.ReferencedValue{ Value: buf, } @@ -741,14 +741,14 @@ func TestBPTree_Iteration_StartsAfterTree(t *testing.T) { for i := 0; i < count; i++ { buf := []byte{0x01} - if err := tree.Insert(ReferencedValue{Value: buf, DataPointer: pointer.MemoryPointer{Offset: uint64(i)}}, pointer.MemoryPointer{Offset: uint64(i), Length: uint32(len(buf))}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: buf, DataPointer: pointer.MemoryPointer{Offset: uint64(i)}}, pointer.MemoryPointer{Offset: uint64(i), Length: uint32(len(buf))}); err != nil { t.Fatal(err) } } t.Run("finds nothing", func(t *testing.T) { buf := []byte{0x02} - valueRef := ReferencedValue{ + valueRef := pointer.ReferencedValue{ Value: buf, } diff --git a/pkg/bptree/node.go b/pkg/bptree/node.go index 8bd02fe6..db8c0ae8 100644 --- a/pkg/bptree/node.go +++ b/pkg/bptree/node.go @@ -1,7 +1,6 @@ package bptree import ( - "bytes" "encoding/binary" "fmt" "github.com/kevmo314/appendable/pkg/encoding" @@ -9,38 +8,6 @@ import ( "io" ) -type ReferencedValue struct { - // it is generally optional to set the DataPointer. if it is not set, the - // value is taken to be unreferenced and is stored directly in the node. - // if it is set, the value is used for comparison but the value is stored - // as a reference to the DataPointer. - // - // caveat: DataPointer is used as a disambiguator for the value. the b+ tree - // implementation does not support duplicate keys and uses the DataPointer - // to disambiguate between keys that compare as equal. - DataPointer pointer.MemoryPointer - Value []byte -} - -func (rv ReferencedValue) String() string { - return fmt.Sprintf("ReferencedValue@%s{%s}", rv.DataPointer, rv.Value) -} - -func CompareReferencedValues(a, b ReferencedValue) int { - if cmp := bytes.Compare(a.Value, b.Value); cmp != 0 { - return cmp - } else if a.DataPointer.Offset < b.DataPointer.Offset { - return -1 - } else if a.DataPointer.Offset > b.DataPointer.Offset { - return 1 - } else if a.DataPointer.Length < b.DataPointer.Length { - return -1 - } else if a.DataPointer.Length > b.DataPointer.Length { - return 1 - } - return 0 -} - type DataParser interface { Parse([]byte) []byte } @@ -52,7 +19,7 @@ type BPTreeNode struct { // if the node is a leaf, the last pointer is the offset of the next leaf LeafPointers []pointer.MemoryPointer InternalPointers []uint64 - Keys []ReferencedValue + Keys []pointer.ReferencedValue // the expected width for the BPTree's type Width uint16 @@ -153,10 +120,10 @@ func (n *BPTreeNode) UnmarshalBinary(buf []byte) error { leaf := size < 0 if leaf { n.LeafPointers = make([]pointer.MemoryPointer, -size) - n.Keys = make([]ReferencedValue, -size) + n.Keys = make([]pointer.ReferencedValue, -size) } else { n.InternalPointers = make([]uint64, size+1) - n.Keys = make([]ReferencedValue, size) + n.Keys = make([]pointer.ReferencedValue, size) } if size == 0 { panic("empty node") diff --git a/pkg/bptree/node_test.go b/pkg/bptree/node_test.go index 411a45fa..8028362f 100644 --- a/pkg/bptree/node_test.go +++ b/pkg/bptree/node_test.go @@ -15,7 +15,7 @@ func TestBPTreeNode_ReadWriteLeaf(t *testing.T) { {Offset: 3, Length: 3}, {Offset: 6, Length: 3}, }, - Keys: []ReferencedValue{ + Keys: []pointer.ReferencedValue{ {Value: []byte{0, 1, 2}}, {Value: []byte{1, 2, 3}}, {Value: []byte{3, 4, 5}}, @@ -46,7 +46,7 @@ func TestBPTreeNode_ReadWriteIntermediate(t *testing.T) { // Create a test BPTreeNode node1 := &BPTreeNode{ InternalPointers: []uint64{0, 1, 2, 3}, - Keys: []ReferencedValue{ + Keys: []pointer.ReferencedValue{ {Value: []byte{0, 1}}, {Value: []byte{1, 2}}, {Value: []byte{3, 4}}, @@ -74,7 +74,7 @@ func TestBPTreeNode_ReadWriteIntermediate(t *testing.T) { } func TestBPTreeNode_CompareReferencedValues(t *testing.T) { - rv := []ReferencedValue{ + rv := []pointer.ReferencedValue{ { Value: []byte{0}, }, @@ -91,7 +91,7 @@ func TestBPTreeNode_CompareReferencedValues(t *testing.T) { } for i := 0; i < len(rv); i++ { for j := 0; j < len(rv); j++ { - cmp := CompareReferencedValues(rv[i], rv[j]) + cmp := pointer.CompareReferencedValues(rv[i], rv[j]) if i < j && cmp >= 0 { t.Fatalf("expected %d < %d", i, j) } diff --git a/pkg/handlers/csv.go b/pkg/handlers/csv.go index a4623f64..8e0b1c27 100644 --- a/pkg/handlers/csv.go +++ b/pkg/handlers/csv.go @@ -184,7 +184,7 @@ func (c CSVHandler) handleCSVLine(f *appendable.IndexFile, df []byte, dec *csv.R Length: fieldLength, } - if err := page.BPTree(&bptree.BPTree{Data: df, DataParser: CSVHandler{}, Width: uint16(0)}).Insert(bptree.ReferencedValue{Value: c.Parse([]byte(fieldValue)), DataPointer: mp}, data); err != nil { + if err := page.BPTree(&bptree.BPTree{Data: df, DataParser: CSVHandler{}, Width: uint16(0)}).Insert(pointer.ReferencedValue{Value: c.Parse([]byte(fieldValue)), DataPointer: mp}, data); err != nil { return fmt.Errorf("failed to insert into b+tree: %w", err) } diff --git a/pkg/handlers/csv_test.go b/pkg/handlers/csv_test.go index 8122e7ef..6d61b449 100644 --- a/pkg/handlers/csv_test.go +++ b/pkg/handlers/csv_test.go @@ -92,7 +92,7 @@ func TestCSV(t *testing.T) { t.Errorf("got len(i.Indexes) = %d, want 1", len(collected)) } - rv1, mp1, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: CSVHandler{}}).Find(bptree.ReferencedValue{Value: []byte("test1")}) + rv1, mp1, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: CSVHandler{}}).Find(pointer.ReferencedValue{Value: []byte("test1")}) if err != nil { t.Fatal(err) } @@ -109,7 +109,7 @@ func TestCSV(t *testing.T) { t.Errorf("got i.Indexes[0].Btree().Find(\"test1\") = %+v, want {%d, %d}", mp1, len("test\n"), len("test1")) } - rv2, mp2, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: CSVHandler{}}).Find(bptree.ReferencedValue{Value: []byte("test2")}) + rv2, mp2, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: CSVHandler{}}).Find(pointer.ReferencedValue{Value: []byte("test2")}) if err != nil { t.Fatal(err) } @@ -162,7 +162,7 @@ func TestCSV(t *testing.T) { t.Errorf("got len(i.Indexes) = %d, want 1", len(collected)) } - rv1, mp1, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: CSVHandler{}}).Find(bptree.ReferencedValue{Value: []byte("test1")}) + rv1, mp1, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: CSVHandler{}}).Find(pointer.ReferencedValue{Value: []byte("test1")}) if err != nil { t.Fatal(err) } @@ -192,7 +192,7 @@ func TestCSV(t *testing.T) { v2 := make([]byte, 8) binary.BigEndian.PutUint64(v2, math.Float64bits(123)) - rv2, mp2, err := collected[1].BPTree(&bptree.BPTree{Data: r2, DataParser: CSVHandler{}}).Find(bptree.ReferencedValue{Value: v2}) + rv2, mp2, err := collected[1].BPTree(&bptree.BPTree{Data: r2, DataParser: CSVHandler{}}).Find(pointer.ReferencedValue{Value: v2}) if err != nil { t.Fatal(err) } @@ -295,7 +295,7 @@ func TestCSV(t *testing.T) { v2 := make([]byte, 8) binary.BigEndian.PutUint64(v2, math.Float64bits(1234)) - iter, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}}).Iter(bptree.ReferencedValue{Value: v2}) + iter, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}}).Iter(pointer.ReferencedValue{Value: v2}) if err != nil { t.Fatal(err) } diff --git a/pkg/handlers/equality_test.go b/pkg/handlers/equality_test.go index c3cd14d1..ad4d81d1 100644 --- a/pkg/handlers/equality_test.go +++ b/pkg/handlers/equality_test.go @@ -190,7 +190,7 @@ func compareMetaPages(i1, i2 []*linkedpage.LinkedPage, jr, cr []byte) (bool, str if i == 0 { for _, val := range h1 { - rv1, mp1, err := collected1.BPTree(&bptree.BPTree{Data: jr, DataParser: JSONLHandler{}}).Find(bptree.ReferencedValue{Value: []byte(val)}) + rv1, mp1, err := collected1.BPTree(&bptree.BPTree{Data: jr, DataParser: JSONLHandler{}}).Find(pointer.ReferencedValue{Value: []byte(val)}) if err != nil { return false, fmt.Sprintf("failed to find bptree for jsonl reader %v", val) @@ -199,7 +199,7 @@ func compareMetaPages(i1, i2 []*linkedpage.LinkedPage, jr, cr []byte) (bool, str return false, fmt.Sprintf("failed to find %v for reader", val) } - rv2, mp2, err := collected2.BPTree(&bptree.BPTree{Data: cr, DataParser: CSVHandler{}}).Find(bptree.ReferencedValue{Value: []byte(val)}) + rv2, mp2, err := collected2.BPTree(&bptree.BPTree{Data: cr, DataParser: CSVHandler{}}).Find(pointer.ReferencedValue{Value: []byte(val)}) if err != nil { return false, fmt.Sprintf("failed to find bptree for jsonl reader %v", val) @@ -219,7 +219,7 @@ func compareMetaPages(i1, i2 []*linkedpage.LinkedPage, jr, cr []byte) (bool, str v2 := make([]byte, 8) binary.BigEndian.PutUint64(v2, math.Float64bits(val)) - rv1, mp1, err := collected1.BPTree(&bptree.BPTree{Data: jr, DataParser: JSONLHandler{}}).Find(bptree.ReferencedValue{Value: v2}) + rv1, mp1, err := collected1.BPTree(&bptree.BPTree{Data: jr, DataParser: JSONLHandler{}}).Find(pointer.ReferencedValue{Value: v2}) if err != nil { return false, fmt.Sprintf("failed to find bptree for jsonl reader %v", val) @@ -228,7 +228,7 @@ func compareMetaPages(i1, i2 []*linkedpage.LinkedPage, jr, cr []byte) (bool, str return false, fmt.Sprintf("failed to find %v for josnl reader", val) } - rv2, mp2, err := collected2.BPTree(&bptree.BPTree{Data: cr, DataParser: CSVHandler{}}).Find(bptree.ReferencedValue{Value: v2}) + rv2, mp2, err := collected2.BPTree(&bptree.BPTree{Data: cr, DataParser: CSVHandler{}}).Find(pointer.ReferencedValue{Value: v2}) if err != nil { return false, fmt.Sprintf("failed to find bptree for jsonl reader %v", val) diff --git a/pkg/handlers/jsonl.go b/pkg/handlers/jsonl.go index 1152d5d5..56875f91 100644 --- a/pkg/handlers/jsonl.go +++ b/pkg/handlers/jsonl.go @@ -174,7 +174,7 @@ func (j JSONLHandler) handleJSONLObject(f *appendable.IndexFile, r []byte, dec * } valueBytes := []byte(valueStr) - if err := page.BPTree(&bptree.BPTree{Data: r, DataParser: j, Width: width}).Insert(bptree.ReferencedValue{ + if err := page.BPTree(&bptree.BPTree{Data: r, DataParser: j, Width: width}).Insert(pointer.ReferencedValue{ DataPointer: mp, Value: valueBytes, }, data); err != nil { @@ -192,7 +192,7 @@ func (j JSONLHandler) handleJSONLObject(f *appendable.IndexFile, r []byte, dec * for _, tri := range trigrams { valueBytes := []byte(tri.Word) - if err := page.BPTree(&bptree.BPTree{Data: r, DataParser: j, Width: width}).Insert(bptree.ReferencedValue{ + if err := page.BPTree(&bptree.BPTree{Data: r, DataParser: j, Width: width}).Insert(pointer.ReferencedValue{ DataPointer: pointer.MemoryPointer{ Offset: mp.Offset + tri.Offset, Length: uint32(len(valueStr)), // this is a degenerate case - for ngrams, we store the entire length of the valueStr. This is to help us with the ranking heuristic. @@ -207,7 +207,7 @@ func (j JSONLHandler) handleJSONLObject(f *appendable.IndexFile, r []byte, dec * case appendable.FieldTypeNull: // nil values are a bit of a degenerate case, we are essentially using the bptree // as a set. we store the value as an empty byte slice. - if err := page.BPTree(&bptree.BPTree{Data: r, DataParser: j, Width: width}).Insert(bptree.ReferencedValue{ + if err := page.BPTree(&bptree.BPTree{Data: r, DataParser: j, Width: width}).Insert(pointer.ReferencedValue{ Value: []byte{}, DataPointer: mp, }, data); err != nil { @@ -226,7 +226,7 @@ func (j JSONLHandler) handleJSONLObject(f *appendable.IndexFile, r []byte, dec * binary.BigEndian.PutUint64(buf, math.Float64bits(value)) } - if err := page.BPTree(&bptree.BPTree{Data: r, DataParser: j, Width: width}).Insert(bptree.ReferencedValue{ + if err := page.BPTree(&bptree.BPTree{Data: r, DataParser: j, Width: width}).Insert(pointer.ReferencedValue{ DataPointer: mp, Value: buf, }, @@ -242,14 +242,14 @@ func (j JSONLHandler) handleJSONLObject(f *appendable.IndexFile, r []byte, dec * return fmt.Errorf("expected bool type") } if valueBool { - if err := page.BPTree(&bptree.BPTree{Data: r, DataParser: j, Width: width}).Insert(bptree.ReferencedValue{ + if err := page.BPTree(&bptree.BPTree{Data: r, DataParser: j, Width: width}).Insert(pointer.ReferencedValue{ DataPointer: mp, Value: []byte{1}, }, data); err != nil { return fmt.Errorf("failed to insert into b+tree: %w", err) } } else { - if err := page.BPTree(&bptree.BPTree{Data: r, DataParser: j, Width: width}).Insert(bptree.ReferencedValue{ + if err := page.BPTree(&bptree.BPTree{Data: r, DataParser: j, Width: width}).Insert(pointer.ReferencedValue{ DataPointer: mp, Value: []byte{0}, }, data); err != nil { diff --git a/pkg/handlers/jsonl_test.go b/pkg/handlers/jsonl_test.go index 556b8a1c..f657abe5 100644 --- a/pkg/handlers/jsonl_test.go +++ b/pkg/handlers/jsonl_test.go @@ -78,7 +78,7 @@ func TestJSONL(t *testing.T) { t.Errorf("got len(i.Indexes) = %d, want 4", len(collected)) } - rv1, mp1, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(0)}).Find(bptree.ReferencedValue{Value: []byte("test1")}) + rv1, mp1, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(0)}).Find(pointer.ReferencedValue{Value: []byte("test1")}) if err != nil { t.Fatal(err) } @@ -94,7 +94,7 @@ func TestJSONL(t *testing.T) { t.Errorf("got i.Indexes[0].Btree().Find(\"test1\") = %+v, want {0, %d}", mp1, len("{\"test\":\"test1\"}")) } - rv2, mp2, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(0)}).Find(bptree.ReferencedValue{Value: []byte("test3")}) + rv2, mp2, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(0)}).Find(pointer.ReferencedValue{Value: []byte("test3")}) if err != nil { t.Fatal(err) } @@ -161,7 +161,7 @@ func TestJSONL(t *testing.T) { } } - rv1, mp1, err := strIndexes[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(0)}).Find(bptree.ReferencedValue{Value: []byte("test1")}) + rv1, mp1, err := strIndexes[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(0)}).Find(pointer.ReferencedValue{Value: []byte("test1")}) if err != nil { t.Fatal(err) } @@ -190,7 +190,7 @@ func TestJSONL(t *testing.T) { } bp2 := strIndexes[1].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(0)}) - rv2, mp2, err := bp2.Find(bptree.ReferencedValue{Value: []byte("test3")}) + rv2, mp2, err := bp2.Find(pointer.ReferencedValue{Value: []byte("test3")}) if err != nil { t.Fatal(err) } @@ -247,7 +247,7 @@ func TestJSONL(t *testing.T) { t.Errorf("got len(i.Indexes) = %d, want 2", len(collected)) } - rv1, mp1, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(0)}).Find(bptree.ReferencedValue{Value: []byte("test1")}) + rv1, mp1, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(0)}).Find(pointer.ReferencedValue{Value: []byte("test1")}) if err != nil { t.Fatal(err) } @@ -277,7 +277,7 @@ func TestJSONL(t *testing.T) { v2 := make([]byte, 8) binary.BigEndian.PutUint64(v2, math.Float64bits(123)) - rv2, mp2, err := collected[1].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(9)}).Find(bptree.ReferencedValue{Value: v2}) + rv2, mp2, err := collected[1].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(9)}).Find(pointer.ReferencedValue{Value: v2}) if err != nil { t.Fatal(err) } @@ -584,7 +584,7 @@ func TestJSONL(t *testing.T) { } } - rv1, mp1, err := vanillaIndexes[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(0)}).Find(bptree.ReferencedValue{Value: []byte("test1")}) + rv1, mp1, err := vanillaIndexes[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(0)}).Find(pointer.ReferencedValue{Value: []byte("test1")}) if err != nil { t.Fatal(err) } @@ -612,7 +612,7 @@ func TestJSONL(t *testing.T) { t.Errorf("got i.Indexes[0].FieldType = %#v, want FieldTypeString", md1.FieldType) } - rv2, mp2, err := vanillaIndexes[1].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(1)}).Find(bptree.ReferencedValue{}) + rv2, mp2, err := vanillaIndexes[1].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(1)}).Find(pointer.ReferencedValue{}) if err != nil { t.Fatal(err) } @@ -719,7 +719,7 @@ func TestJSONL(t *testing.T) { v2 := make([]byte, 8) binary.BigEndian.PutUint64(v2, math.Float64bits(1234)) - iter, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(9)}).Iter(bptree.ReferencedValue{Value: v2}) + iter, err := collected[0].BPTree(&bptree.BPTree{Data: r2, DataParser: JSONLHandler{}, Width: uint16(9)}).Iter(pointer.ReferencedValue{Value: v2}) if err != nil { t.Fatal(err) } @@ -791,7 +791,7 @@ func TestJSONL(t *testing.T) { tris := ngram.BuildNgram("howdy", 3) for _, tri := range tris { - rv1, mp1, err := bp.Find(bptree.ReferencedValue{Value: []byte(tri.Word)}) + rv1, mp1, err := bp.Find(pointer.ReferencedValue{Value: []byte(tri.Word)}) if err != nil { t.Fatal(err) } @@ -860,7 +860,7 @@ func TestJSONL(t *testing.T) { trigramTable := make(map[uint64]int) for _, tri := range tris { - iter, err := tree.Iter(bptree.ReferencedValue{Value: []byte(tri.Word)}) + iter, err := tree.Iter(pointer.ReferencedValue{Value: []byte(tri.Word)}) if err != nil { t.Fatal(err) diff --git a/pkg/mocks/btree.go b/pkg/mocks/btree.go index c6f1b2c7..0966abb3 100644 --- a/pkg/mocks/btree.go +++ b/pkg/mocks/btree.go @@ -23,16 +23,16 @@ func generateBasicBtree() { } tree := &bptree.BPTree{PageFile: p, MetaPage: mp, Width: uint16(6)} - if err := tree.Insert(bptree.ReferencedValue{Value: []byte("hello")}, pointer.MemoryPointer{Offset: 1, Length: 5}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte("hello")}, pointer.MemoryPointer{Offset: 1, Length: 5}); err != nil { log.Fatalf("%v", err) } - if err := tree.Insert(bptree.ReferencedValue{Value: []byte("world")}, pointer.MemoryPointer{Offset: 2, Length: 5}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte("world")}, pointer.MemoryPointer{Offset: 2, Length: 5}); err != nil { log.Fatalf("%v", err) } - if err := tree.Insert(bptree.ReferencedValue{Value: []byte("moooo")}, pointer.MemoryPointer{Offset: 3, Length: 5}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte("moooo")}, pointer.MemoryPointer{Offset: 3, Length: 5}); err != nil { log.Fatalf("%v", err) } - if err := tree.Insert(bptree.ReferencedValue{Value: []byte("cooow")}, pointer.MemoryPointer{Offset: 4, Length: 5}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: []byte("cooow")}, pointer.MemoryPointer{Offset: 4, Length: 5}); err != nil { log.Fatalf("%v", err) } @@ -62,7 +62,7 @@ func generateBtreeIterator() { } tree := &bptree.BPTree{PageFile: p, MetaPage: mp, Data: make([]byte, 16384*4+8), DataParser: &StubDataParser{}, Width: uint16(0)} for i := 0; i < 16384*4; i++ { - if err := tree.Insert(bptree.ReferencedValue{ + if err := tree.Insert(pointer.ReferencedValue{ Value: []byte{1, 2, 3, 4, 5, 6, 7, 8}, // DataPointer is used as a disambiguator. DataPointer: pointer.MemoryPointer{Offset: uint64(i), Length: 8}, @@ -93,7 +93,7 @@ func generate1023Btree() { buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, math.Float64bits(23)) - if err := tree.Insert(bptree.ReferencedValue{Value: buf, DataPointer: pointer.MemoryPointer{Offset: uint64(i)}}, pointer.MemoryPointer{Offset: uint64(i), Length: uint32(len(buf))}); err != nil { + if err := tree.Insert(pointer.ReferencedValue{Value: buf, DataPointer: pointer.MemoryPointer{Offset: uint64(i)}}, pointer.MemoryPointer{Offset: uint64(i), Length: uint32(len(buf))}); err != nil { log.Fatal(err) } } diff --git a/pkg/mocks/node.go b/pkg/mocks/node.go index 030ad541..fe160d77 100644 --- a/pkg/mocks/node.go +++ b/pkg/mocks/node.go @@ -25,7 +25,7 @@ func generateLeafNode() { {Offset: 3, Length: 3}, {Offset: 6, Length: 3}, }, - Keys: []bptree.ReferencedValue{ + Keys: []pointer.ReferencedValue{ {Value: []byte{0, 1, 2}}, {Value: []byte{1, 2, 3}}, {Value: []byte{3, 4, 5}}, @@ -45,7 +45,7 @@ func generateInternalNode() { // Create a test BPTreeNode node1 := &bptree.BPTreeNode{ InternalPointers: []uint64{0, 1, 2, 3}, - Keys: []bptree.ReferencedValue{ + Keys: []pointer.ReferencedValue{ {Value: []byte{0, 1}}, {Value: []byte{1, 2}}, {Value: []byte{3, 4}}, diff --git a/pkg/pointer/referenced_value.go b/pkg/pointer/referenced_value.go new file mode 100644 index 00000000..6ff83b0d --- /dev/null +++ b/pkg/pointer/referenced_value.go @@ -0,0 +1,38 @@ +package pointer + +import ( + "bytes" + "fmt" +) + +type ReferencedValue struct { + // it is generally optional to set the DataPointer. if it is not set, the + // value is taken to be unreferenced and is stored directly in the node. + // if it is set, the value is used for comparison but the value is stored + // as a reference to the DataPointer. + // + // caveat: DataPointer is used as a disambiguator for the value. the b+ tree + // implementation does not support duplicate keys and uses the DataPointer + // to disambiguate between keys that compare as equal. + DataPointer MemoryPointer + Value []byte +} + +func (rv ReferencedValue) String() string { + return fmt.Sprintf("ReferencedValue@%s{%s}", rv.DataPointer, rv.Value) +} + +func CompareReferencedValues(a, b ReferencedValue) int { + if cmp := bytes.Compare(a.Value, b.Value); cmp != 0 { + return cmp + } else if a.DataPointer.Offset < b.DataPointer.Offset { + return -1 + } else if a.DataPointer.Offset > b.DataPointer.Offset { + return 1 + } else if a.DataPointer.Length < b.DataPointer.Length { + return -1 + } else if a.DataPointer.Length > b.DataPointer.Length { + return 1 + } + return 0 +}