-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkeyVal.go
92 lines (82 loc) · 1.96 KB
/
keyVal.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
package main
import (
"container/list"
"sync"
"time"
)
type KeyVal struct {
mu sync.RWMutex
data map[string][]byte
lruList *list.List
keyToElement map[string]*list.Element
memoryLimit int64
currentSize int64
}
type lruItem struct {
key string
value []byte
}
// memoryLimit should be in MB
func NewKeyVal(memoryLimit int64) *KeyVal {
memoryLimit = memoryLimit * 1024 * 1024 //Size in mb
kv := &KeyVal{
data: make(map[string][]byte),
lruList: list.New(),
keyToElement: make(map[string]*list.Element),
memoryLimit: memoryLimit,
currentSize: 0,
}
go kv.startEviction() // Start the background eviction goroutine
return kv
}
func (kv *KeyVal) Set(key, val []byte) error {
kv.mu.Lock()
defer kv.mu.Unlock()
keyStr := string(key)
if existingElem, exists := kv.keyToElement[keyStr]; exists {
existingItem := existingElem.Value.(*lruItem)
kv.currentSize -= int64(len(existingItem.value))
existingItem.value = val
kv.currentSize += int64(len(val))
kv.lruList.MoveToFront(existingElem)
} else {
item := &lruItem{key: keyStr, value: val}
element := kv.lruList.PushFront(item)
kv.keyToElement[keyStr] = element
kv.data[keyStr] = val
kv.currentSize += int64(len(val))
}
kv.evictIfNeeded()
return nil
}
func (kv *KeyVal) Get(key []byte) ([]byte, bool) {
kv.mu.Lock()
defer kv.mu.Unlock()
keyStr := string(key)
if element, exists := kv.keyToElement[keyStr]; exists {
kv.lruList.MoveToFront(element)
return kv.data[keyStr], true
}
return nil, false
}
func (kv *KeyVal) evictIfNeeded() {
for kv.currentSize > kv.memoryLimit {
lastElem := kv.lruList.Back()
if lastElem == nil {
break
}
item := lastElem.Value.(*lruItem)
delete(kv.data, item.key)
kv.lruList.Remove(lastElem)
delete(kv.keyToElement, item.key)
kv.currentSize -= int64(len(item.value))
}
}
func (kv *KeyVal) startEviction() {
for {
time.Sleep(10 * time.Second)
kv.mu.Lock()
kv.evictIfNeeded()
kv.mu.Unlock()
}
}