-
Notifications
You must be signed in to change notification settings - Fork 1
/
skiplist.go
212 lines (179 loc) · 5.7 KB
/
skiplist.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
package main
import (
"encoding/binary"
"math/rand"
)
/*maxHeight se zadaje u kodu - nije u eksternom config -u
height je trenutna visina skip liste
size je ukupan broj elemenata u skip listi
head je prvi element skip liste*/
type SkipList struct {
maxHeight int
height int
size int
head *SkipListNode
}
/*next je slice pokazivaca na sledeci element u skip listi - za svaki nivo na koji se propagira*/
type SkipListNode struct {
Input []byte //zapisi u skiplisti su isti kao kod WAL-a!!!
next []*SkipListNode
}
/*Funkcija kreira novu praznu skiplistu
Interni dogovor - max visina skip liste je 32 - podrzava 2^32 vrednosti*/
func NewSkipList() *SkipList {
in := make([]byte,30)
binary.LittleEndian.PutUint64(in[13:21],1)
in[29] = 0
return &SkipList{
maxHeight: 32,
height: 0,
size: 0,
head: &SkipListNode{
Input: in,
next: make([]*SkipListNode,32),
},
}
}
/*Funkcija koja baca kockicu i odredjuje na koliko nivoa se propagira kljuc - vraca indeks maksimalnog nivoa na kome se element moze naci
Prima pokazivac na trenutnu skip listu*/
func (s *SkipList) roll() int {
level := 0 // alwasy start from level 0
// We roll until we don't get 1 from rand function and we did not
// outgrow maxHeight. BUT rand can give us 0, and if that is the case
// than we will just increase level, and wait for 1 from rand!
for ; rand.Int31n(2) == 1 && level < s.maxHeight; level++ {
if level > s.height {
// When we get 1 from rand function and we did not
// outgrow maxHeight, that number becomes new height
s.height = level
return level
}
}
return level
}
/*Funkcija nalazi element sa zadatim kljucem u skip listi
Vraca SkipListNode sa zadatim kljucem
Vodi racuna o postavljenom tombstone - u!*/
func (s *SkipList) GetElement(key string) *SkipListNode{
current_node := s.head
for i := s.height; i >= 0; i-- {
//pomeramo se udesno sve dok ne dodjemo do kraja trenutnog nivoa
for ; current_node.next[i] != nil; current_node = current_node.next[i] {
next_node := current_node.next[i]
key_size := binary.LittleEndian.Uint64(current_node.Input[13:21])
tombstone := int(current_node.Input[12])
//Pronasli smo kljuc I NIJE OBRISAN
if string(current_node.Input[29:29 + key_size]) == key && tombstone == 0{
//println(i)
return current_node
}
//Sledeci je trazeni
next_key_size := binary.LittleEndian.Uint64(next_node.Input[13:21])
next_tombstone := int(next_node.Input[12])
//Sledeci cvor je trazeni - ubrzava algoritam za jednu iteraciju
if string(next_node.Input[29:29 + next_key_size]) == key && next_tombstone == 0 {
//println(i)
return next_node
}
//Idemo dole
if string(next_node.Input[29:29 + next_key_size]) > key{
break
}
}
}
return nil
}
/*Funkcija dodaje element u skip listu
Prima niz bajtova u formatu kao i WAL*/
//Vraca status izvrsenja - true = uspesno, false = neuspesno
func (s *SkipList) AddElement(input []byte) bool {
key_size := binary.LittleEndian.Uint64(input[13:21])
key := string(input[29:29 + key_size])
found := s.GetElement(key)
//Element nije prethodno upisan u strukturu
if found == nil {
max_level := s.roll()
//println(key + " se propagira do " + strconv.Itoa(max_level) + ". nivoa.")
new_node := &SkipListNode{
Input : input,
next : make([]*SkipListNode,max_level + 1),
}
current := s.head
/*Pocinjemo od najnizeg nivoa i penjemo se na poslednji nivo na kome treba da se nadje element*/
for i := s.height; i >= 0; i-- {
//Pomeramo se za jedno mesto udesno dok ne nadjemo poziciju
for ; current.next[i] != nil; current = current.next[i] {
next := current.next[i]
next_key_size := binary.LittleEndian.Uint64(next.Input[13:21])
if string(next.Input[29:29 + next_key_size]) > key { break }
}
if i > max_level {
continue
}
new_node.next[i] = current.next[i]
current.next[i] = new_node
}
s.size += 1
return true
} else {
//Menjamo vrednost pod postojecim kljucem
found.Input = input
return false
}
return false
}
/*Funkcija brise element iz skip liste - postavlja tombstone podatka na 1
Vraca status izvrsenja*/
func (s *SkipList) DeleteElement(key string) bool{
value := s.GetElement(key)
if value != nil{
value.Input[12] = 1 //tombstone postavljen
return true
} else{
//println("Kljuc se ne nalazi u skiplisti!")
return false
}
}
/*Funkcija vraca sve elemente skip liste
Oni se svi nalaze na nultom nivou*/
func (s *SkipList) GetAll() [][]byte {
current_node := s.head
if current_node.next == nil { //prazna skip lista
return make([][]byte,0)
} else{
matrix := make([][]byte,0)
for current_node = s.head.next[0]; current_node != nil; current_node = current_node.next[0] {
matrix = append(matrix, current_node.Input)
}
return matrix
}
}
/*Pomocna funkcija za iscrtavanje skip liste po nivoima*/
func (s *SkipList) printSkipList(){
current_node := s.head
for i := s.height; i >= 0; i-- {
if s.head.next[i] == nil {
continue
}
for current_node = s.head.next[i]; current_node != nil; current_node = current_node.next[i] {
key_size := binary.LittleEndian.Uint64(current_node.Input[13:21])
value_size := binary.LittleEndian.Uint64((current_node.Input[21:29]))
tombstone := int (current_node.Input[12])
if tombstone == 0 {
print("(" + string(current_node.Input[29:29+key_size]) + "," + string(current_node.Input[29+key_size:29+key_size+value_size]) + ") ")
}
}
println()
}
}
//staro testiranje
/*func main(){
skip_list := newSkipList()
skip_list.addElement("10",[]byte("idk1"))
skip_list.addElement("8",[]byte("idk2"))
skip_list.addElement("16",[]byte("idk3"))
skip_list.addElement("9",[]byte("idk4"))
skip_list.addElement("10",[]byte("idk5"))
skip_list.printSkipList()
skip_list.getElement("16")
}*/