-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcache_memory.go
101 lines (84 loc) · 2.15 KB
/
cache_memory.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
package kimg
import (
"container/list"
"errors"
"sync"
)
type kimgMemoryCache struct {
mtx sync.Mutex
list *list.List
table map[string]*list.Element
size int64
capacity int64
}
type cacheEntry struct {
key string
data []byte
size int64
}
// NewKimgMemoryCache create a memory cache instance.
func NewKimgMemoryCache(config *KimgConfig) (KimgCache, error) {
return &kimgMemoryCache{
list: list.New(),
table: make(map[string]*list.Element),
capacity: config.Cache.Memory.Capacity,
}, nil
}
func (cache *kimgMemoryCache) Set(key string, data []byte) error {
cache.mtx.Lock()
defer cache.mtx.Unlock()
if ele := cache.table[key]; ele != nil {
cache.updateInplace(ele, data)
} else {
cache.addNew(key, data)
}
return nil
}
func (cache *kimgMemoryCache) Get(key string) ([]byte, error) {
cache.mtx.Lock()
defer cache.mtx.Unlock()
ele, ok := cache.table[key]
if ele == nil || !ok {
return nil, errors.New("memory cache miss")
}
cache.moveToFront(ele)
return ele.Value.(*cacheEntry).data, nil
}
func (cache *kimgMemoryCache) Del(key string) error {
cache.mtx.Lock()
defer cache.mtx.Unlock()
ele, ok := cache.table[key]
if ele == nil || !ok {
return errors.New("memory cache miss")
}
cache.list.Remove(ele)
delete(cache.table, key)
cache.size -= ele.Value.(*cacheEntry).size
return nil
}
func (cache *kimgMemoryCache) updateInplace(ele *list.Element, data []byte) {
cache.size += int64(len(data)) - ele.Value.(*cacheEntry).size
ele.Value.(*cacheEntry).data = data
ele.Value.(*cacheEntry).size = int64(len(data))
cache.moveToFront(ele)
cache.checkCapacity()
}
func (cache *kimgMemoryCache) moveToFront(ele *list.Element) {
cache.list.MoveToFront(ele)
}
func (cache *kimgMemoryCache) addNew(key string, data []byte) {
entry := &cacheEntry{key, data, int64(len(data))}
ele := cache.list.PushFront(entry)
cache.table[key] = ele
cache.size += entry.size
cache.checkCapacity()
}
func (cache *kimgMemoryCache) checkCapacity() {
for cache.size > cache.capacity {
ele := cache.list.Back()
entry := ele.Value.(*cacheEntry)
cache.list.Remove(ele)
delete(cache.table, entry.key)
cache.size -= entry.size
}
}