Skip to content

Commit cbc9ead

Browse files
committed
Refactor
1 parent 9a85504 commit cbc9ead

14 files changed

Lines changed: 243 additions & 141 deletions

File tree

secretary/btree.go

Lines changed: 118 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,17 @@ import (
1313
func (s *Secretary) NewBTree(
1414
collectionName string,
1515
order uint8,
16-
batchNumLevel uint8,
16+
numLevel uint8,
1717
batchBaseSize uint32,
18-
batchIncrement uint8,
19-
batchLength uint8,
18+
increment uint8,
2019
compactionBatchSize uint32,
2120
) (*BTree, error) {
2221
if order < MIN_ORDER || order > MAX_ORDER {
2322
return nil, ErrorInvalidOrder
2423
}
2524

26-
if batchIncrement < 110 || batchIncrement > 200 {
27-
return nil, ErrorInvalidBatchIncrement
25+
if increment < 110 || increment > 200 {
26+
return nil, ErrorInvalidIncrement
2827
}
2928

3029
nodeSize := uint32(order)*(KEY_SIZE+KEY_OFFSET_SIZE) + 3*POINTER_SIZE + 1
@@ -43,11 +42,10 @@ func (s *Secretary) NewBTree(
4342

4443
root: &Node{},
4544

46-
Order: order,
47-
BatchNumLevel: batchNumLevel,
48-
BatchBaseSize: batchBaseSize,
49-
BatchIncrement: batchIncrement,
50-
BatchLength: batchLength,
45+
Order: order,
46+
NumLevel: numLevel,
47+
BatchBaseSize: batchBaseSize,
48+
Increment: increment,
5149

5250
nodeSize: uint32(nodeSize),
5351

@@ -62,7 +60,7 @@ func (s *Secretary) NewBTree(
6260
}
6361
tree.nodePager = nodePager
6462

65-
recordPagers := make([]*RecordPager, batchNumLevel)
63+
recordPagers := make([]*RecordPager, numLevel)
6664
for i := range recordPagers {
6765
pager, err := tree.NewRecordPager("record", uint8(i))
6866
if err != nil {
@@ -99,36 +97,79 @@ func (tree *BTree) SaveHeader() error {
9997
headerBytes = append([]byte(SECRETARY), headerBytes...)
10098

10199
if len(headerBytes) < SECRETARY_HEADER_LENGTH {
102-
// header = append(header, make([]byte, rootHeaderSize-len(header))...)
103100
headerBytes = append(headerBytes, utils.MakeByteArray(SECRETARY_HEADER_LENGTH-len(headerBytes), '-')...)
104101
}
105102

106103
return tree.nodePager.WriteAt(headerBytes, 0)
107104
}
108105

109-
func (tree *BTree) readRoot() error {
110-
rootBytes, err := tree.nodePager.ReadAt(SECRETARY_HEADER_LENGTH, int32(tree.nodeSize))
106+
func (tree *BTree) ReadNodeAtIndex(index uint64) (*Node, error) {
107+
offset := SECRETARY_HEADER_LENGTH + index*uint64(tree.nodeSize)
108+
109+
rootBytes, err := tree.nodePager.ReadAt(int64(offset), int32(tree.nodeSize))
111110
if err != nil {
112-
return err
111+
return nil, err
113112
}
114113

115-
var root Node
116-
err = binstruct.Deserialize(rootBytes, &root)
114+
var node Node
115+
err = binstruct.Deserialize(rootBytes, &node)
116+
if err != nil {
117+
return nil, err
118+
}
119+
120+
return &node, nil
121+
}
122+
123+
func (tree *BTree) readRoot() error {
124+
node, err := tree.ReadNodeAtIndex(0)
117125
if err != nil {
118126
return err
119127
}
128+
tree.root = node
129+
return nil
130+
}
120131

121-
tree.root = &root
132+
func (tree *BTree) SaveNode(node *Node) error {
133+
if node.Index == 0 {
134+
stat, err := tree.nodePager.file.Stat()
135+
if err != nil {
136+
return err
137+
}
138+
lastFileIndex := uint64(stat.Size()) - uint64(SECRETARY_HEADER_LENGTH)/uint64(tree.nodeSize)
139+
if lastFileIndex != tree.NumNodeSeq {
140+
return fmt.Errorf("NumNodes dont match %d != %d", lastFileIndex, tree.NumNodeSeq)
141+
}
142+
tree.SaveNodeAtIndex(node, lastFileIndex)
143+
} else {
144+
tree.SaveNodeAtIndex(node, uint64(node.Index))
145+
}
122146
return nil
123147
}
124148

125-
func (tree *BTree) saveRoot() error {
126-
rootHeader, err := binstruct.Serialize(tree.root)
149+
func (tree *BTree) SaveNodeAtIndex(node *Node, index uint64) error {
150+
node.Index = index
151+
if node.parent != nil {
152+
node.ParentIndex = node.parent.Index
153+
}
154+
if node.next != nil {
155+
node.NextIndex = node.next.Index
156+
}
157+
if node.prev != nil {
158+
node.PrevIndex = node.prev.Index
159+
}
160+
161+
rootHeader, err := binstruct.Serialize(node)
127162
if err != nil {
128163
return err
129164
}
130165

131-
return tree.nodePager.WriteAt(rootHeader, SECRETARY_HEADER_LENGTH)
166+
offset := SECRETARY_HEADER_LENGTH + index*uint64(tree.nodeSize)
167+
168+
return tree.nodePager.WriteAt(rootHeader, int64(offset))
169+
}
170+
171+
func (tree *BTree) saveRoot() error {
172+
return tree.SaveNodeAtIndex(tree.root, 0)
132173
}
133174

134175
func (s *Secretary) NewBTreeReadHeader(collectionName string) (*BTree, error) {
@@ -138,7 +179,6 @@ func (s *Secretary) NewBTreeReadHeader(collectionName string) (*BTree, error) {
138179
0,
139180
125,
140181
0,
141-
0,
142182
)
143183
if err != nil {
144184
return nil, err
@@ -174,6 +214,20 @@ func (tree *BTree) Height() int {
174214
return height
175215
}
176216

217+
func (tree *BTree) Level(node *Node) int {
218+
if node == nil || tree.root == nil {
219+
return -1 // Return -1 for invalid nodes
220+
}
221+
222+
level := 0
223+
for node != nil && node != tree.root {
224+
level++
225+
node = node.parent
226+
}
227+
228+
return level
229+
}
230+
177231
func (tree *BTree) GetFirstNodePerHeight() []*Node {
178232
var firstNodePerHeight []*Node
179233

@@ -188,3 +242,45 @@ func (tree *BTree) GetFirstNodePerHeight() []*Node {
188242

189243
return firstNodePerHeight
190244
}
245+
246+
func (tree *BTree) BFSCompactBatchTraversal() []*Node {
247+
var compactBatch []*Node
248+
249+
firstNodePerHeight := tree.GetFirstNodePerHeight()
250+
251+
if tree.root == nil {
252+
return compactBatch
253+
}
254+
if tree.nextCompactionNode == nil {
255+
tree.nextCompactionNode = tree.root
256+
}
257+
258+
for i := 0; i < int(tree.CompactionBatchSize); i++ {
259+
260+
// Ensure nextCompactionNode is not nil
261+
if tree.nextCompactionNode == nil {
262+
// utils.Log("tree.nextCompactionNode == nil")
263+
break
264+
}
265+
266+
compactBatch = append(compactBatch, tree.nextCompactionNode)
267+
268+
if tree.nextCompactionNode.next != nil {
269+
tree.nextCompactionNode = tree.nextCompactionNode.next
270+
} else {
271+
// Ensure nextCompactionNode is not nil before calling Level()
272+
level := tree.Level(tree.nextCompactionNode)
273+
274+
// utils.Log("level", level, "lenfirst", len(firstNodePerHeight), level > 0 && (level+1) < len(firstNodePerHeight))
275+
276+
if level >= 0 && (level+1) < len(firstNodePerHeight) {
277+
firstNode := firstNodePerHeight[level+1]
278+
tree.nextCompactionNode = firstNode
279+
} else {
280+
break
281+
}
282+
}
283+
}
284+
285+
return compactBatch
286+
}

secretary/btree_test.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ func TestBtreeInvalid(t *testing.T) {
4646
32,
4747
1024,
4848
125,
49-
10,
5049
1000,
5150
)
5251
_, invalidIncrementErr := s.NewBTree(
@@ -55,7 +54,6 @@ func TestBtreeInvalid(t *testing.T) {
5554
32,
5655
1024,
5756
225,
58-
10,
5957
1000,
6058
)
6159
_, invalidOrderErr := s.NewBTree(
@@ -64,7 +62,6 @@ func TestBtreeInvalid(t *testing.T) {
6462
32,
6563
1024,
6664
225,
67-
10,
6865
1000,
6966
)
7067
if invalidNameErr == nil || invalidIncrementErr == nil || invalidOrderErr == nil {

secretary/datalocation.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,13 @@ import (
44
"github.com/codeharik/secretary/utils/binstruct"
55
)
66

7-
func (datalocation DataLocation) toRecordLocation() RecordLocation {
7+
func ToRecordLocation(datalocation uint64) RecordLocation {
88
return RecordLocation{
99
batchLevel: uint8((uint64(datalocation) & RECORD_BATCH_LEVEL_AND) >> 56),
1010
offset: uint64(datalocation) & RECORD_BATCH_OFFSET_AND,
1111
}
1212
}
1313

14-
func (datalocation DataLocation) toNodeLocation() NodeLocation {
15-
return NodeLocation{
16-
index: uint16((uint64(datalocation) & NODE_INDEX_AND) >> 48),
17-
batchOffset: uint64(datalocation) & NODE_BATCH_OFFSET_AND,
18-
}
19-
}
20-
2114
func (nodes *Node) ToBytes() ([]byte, error) {
2215
return binstruct.Serialize(nodes)
2316
}

secretary/errors.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ var (
3131
ErrorRecordsNotSorted = errors.New("Records not sorted")
3232

3333
ErrorInvalidOrder = fmt.Errorf("Order must be between %d and %d", MIN_ORDER, MAX_ORDER)
34-
ErrorInvalidBatchIncrement = errors.New("Batch Increment must be between 110 and 200")
34+
ErrorInvalidIncrement = errors.New("Increment must be between 110 and 200")
3535
ErrorInvalidCollectionName = errors.New("Collection name is not valid, should be a-z 0-9 and with >4 & <30 characters")
3636

3737
// File I/O

secretary/example/main.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ func main() {
2121
32,
2222
1024,
2323
125,
24-
10,
2524
1000,
2625
)
2726

@@ -31,7 +30,6 @@ func main() {
3130
32,
3231
1024*1024,
3332
125,
34-
10,
3533
1000,
3634
)
3735
if userErr != nil || imagesErr != nil {

secretary/node_test.go

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ func dummyTree(t *testing.T, collectionName string, order uint8) (*Secretary, *B
1919
32,
2020
1024,
2121
125,
22-
10,
23-
1000,
22+
20,
2423
)
2524
if serr != nil || err != nil {
2625
t.Fatal(err)
@@ -32,12 +31,12 @@ func TestSaveRoot(t *testing.T) {
3231
_, tree := dummyTree(t, "TestSaveRoot", 10)
3332

3433
root := Node{
35-
ParentOffset: 101,
36-
NextOffset: 102,
37-
PrevOffset: 103,
34+
ParentIndex: 101,
35+
NextIndex: 102,
36+
PrevIndex: 103,
3837

39-
Keys: [][]byte{{10, 21, 32, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
40-
KeyOffsets: []DataLocation{2, 3, 4, 5, 6},
38+
Keys: [][]byte{{10, 21, 32, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
39+
KeyLocation: []uint64{2, 3, 4, 5, 6},
4140
}
4241
tree.root = &root
4342

@@ -529,14 +528,55 @@ func TestSplitInternal(t *testing.T) {
529528
t.Fatal(err)
530529
}
531530

532-
nodes := tree.GetFirstNodePerHeight()
533-
expected := []uint64{21, 7, 2, 0}
534-
if len(nodes) != len(expected) {
535-
t.Fatalf("Expected %d nodes, got %d", len(expected), len(nodes))
531+
{
532+
nodes := tree.GetFirstNodePerHeight()
533+
expected := []uint64{21, 7, 2, 0}
534+
if len(nodes) != len(expected) {
535+
t.Fatalf("Expected %d nodes, got %d", len(expected), len(nodes))
536+
}
537+
for i, node := range nodes {
538+
if node.NodeID != expected[i] {
539+
t.Errorf("At height %d, expected NodeID %d, got %d", i, expected[i], node.NodeID)
540+
}
541+
}
536542
}
537-
for i, node := range nodes {
538-
if node.NodeID != expected[i] {
539-
t.Errorf("At height %d, expected NodeID %d, got %d", i, expected[i], node.NodeID)
543+
544+
{ // Perform batch traversal
545+
compactBatch := tree.BFSCompactBatchTraversal()
546+
expected := []uint64{21, 7, 20, 34, 47, 2, 6, 11, 15, 19, 25, 29, 50, 33, 38, 42, 46, 0, 1, 3}
547+
if len(compactBatch) != len(expected) {
548+
t.Fatalf("Expected %d nodes, got %d", len(expected), len(compactBatch))
549+
}
550+
for i, node := range compactBatch {
551+
if node.NodeID != expected[i] {
552+
t.Errorf("At index %d, expected NodeID %d, got %d", i, expected[i], node.NodeID)
553+
}
554+
}
555+
556+
compactBatch = tree.BFSCompactBatchTraversal()
557+
expected = []uint64{4, 5, 8, 9, 10, 12, 13, 14, 16, 17, 18, 22, 23, 24, 26, 27, 28, 48, 49, 30}
558+
559+
if len(compactBatch) != len(expected) {
560+
t.Fatalf("Expected %d nodes, got %d", len(expected), len(compactBatch))
561+
}
562+
for i, node := range compactBatch {
563+
if node.NodeID != expected[i] {
564+
t.Errorf("At index %d, expected NodeID %d, got %d", i, expected[i], node.NodeID)
565+
}
566+
}
567+
568+
compactBatch = tree.BFSCompactBatchTraversal()
569+
expected = []uint64{31, 32, 35, 36, 37, 39, 40, 41, 43, 44, 45}
570+
571+
// utils.Log(utils.Map(compactBatch, func(s *Node) uint64 { return s.NodeID }))
572+
573+
if len(compactBatch) != len(expected) {
574+
t.Fatalf("Expected %d nodes, got %d", len(expected), len(compactBatch))
575+
}
576+
for i, node := range compactBatch {
577+
if node.NodeID != expected[i] {
578+
t.Errorf("At index %d, expected NodeID %d, got %d", i, expected[i], node.NodeID)
579+
}
540580
}
541581
}
542582
}

0 commit comments

Comments
 (0)