-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.go
152 lines (136 loc) · 3.1 KB
/
index.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package simpledb
import (
)
const (
BucketLen = 1024
indexName = "idx.pix"
)
type index struct {
*MmapFile
//buckets []*bucket
freeBucketOffs []int64
numBucket int64 // count of buckets already used, including the free buckets
}
func (idx *index) bucketIndex(hash uint32) uint32 {
return hash & (BucketLen-1)
}
func bucketOffset(bidx uint32) int64 {
return int64(bucketSize) * int64(bidx)
}
func (idx *index) createOverflowBucket() (*bucketHandle, error) {
// Todo: if may corrected as for
if bucketSize*(idx.numBucket+1) > idx.MmapFile.FileSize() {
newFileSize := idx.MmapFile.FileSize()*2
err := idx.MmapFile.Grow(newFileSize)
if err!=nil {
return nil, err
}
}
bh := &bucketHandle{
MmapFile: idx.MmapFile,
offset:bucketSize*idx.numBucket,
bucket: &bucket{},
}
if err := bh.read(); err != nil {
return nil, err
}
idx.numBucket++
return bh, nil
}
func (idx *index) fillBucket(off int64) (*bucketHandle, error) {
bh := &bucketHandle{
MmapFile: idx.MmapFile,
offset: off,
bucket: &bucket{},
}
err := bh.read()
if err != nil {
return nil, err
}
return bh, nil
}
func (idx *index) get(hash uint32) (*slot, error) {
bidx := idx.bucketIndex(hash)
off := bucketOffset(bidx)
bh, err := idx.fillBucket(off)
if err != nil {
return nil, err
}
buc := bh.bucket
if slot, _ := buc.iterateSlots(hash); slot != nil {
return slot, nil
}
// search in the next bucket
off = buc.next
for ; off!=0; off = buc.next {
bh, err = idx.fillBucket(off)
if err != nil {
return nil, err
}
buc = bh.bucket
if slot, _ := buc.iterateSlots(hash); slot != nil {
return slot, nil
}
}
return nil, nil
}
func (idx *index) put (sl *slot) error {
bidx := idx.bucketIndex(sl.hash)
off := bucketOffset(bidx)
bh, err := idx.fillBucket(off)
if err != nil {
return err
}
buc := bh.bucket
pos := slotsCountPerBucket
var slot *slot
// replace the existing slot if existed
if slot, pos = buc.iterateSlots(sl.hash); slot!=nil {
buc.slots[pos] = *sl
return bh.write()
}
off = buc.next
for ; off!=0; off = buc.next {
bh, err = idx.fillBucket(off)
if err != nil {
return err
}
buc = bh.bucket
if slot, pos = buc.iterateSlots(sl.hash); slot != nil {
buc.slots[pos] = *sl
return bh.write()
}
}
// add a new slot
if pos == slotsCountPerBucket { // The current bucket is full
var newBucket *bucket
var newBucketOff int64
var newBucketHandle *bucketHandle
if len(idx.freeBucketOffs) >0 { // fetch a new bucket from the free buckets
newBucketOff = idx.freeBucketOffs[0]
idx.freeBucketOffs = idx.freeBucketOffs[1:]
newBucketHandle, err = idx.fillBucket(newBucketOff)
if err != nil {
return err
}
newBucket = newBucketHandle.bucket
} else { // extend the buckets
newBucketHandle, err = idx.createOverflowBucket()
if err != nil {
return err
}
newBucket = newBucketHandle.bucket
newBucketOff = newBucketHandle.offset
}
buc.next = newBucketOff
// write the previous bucket
if err := bh.write(); err != nil {
return err
}
newBucket.insert(sl, 0)
bh = newBucketHandle
} else {
buc.insert(sl, pos)
}
return bh.write()
}