Skip to content

Commit 2a2dff3

Browse files
committed
clean up and bug fix
1 parent cd66151 commit 2a2dff3

File tree

4 files changed

+73
-44
lines changed

4 files changed

+73
-44
lines changed

pkg/storage/helpers.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package storage
2+
3+
import (
4+
"time"
5+
6+
"neurocode.io/cache-offloader/pkg/model"
7+
)
8+
9+
func getSize(value model.Response) float64 {
10+
sizeBytes := len(value.Body)
11+
sizeMB := float64(sizeBytes) / (1024 * 1024)
12+
13+
return sizeMB
14+
}
15+
16+
func getStaleStatus(timeStamp int64, staleDuration int64) uint8 {
17+
if (time.Now().Unix() - timeStamp) >= staleDuration {
18+
return model.StaleValue
19+
} else {
20+
return model.FreshValue
21+
}
22+
}

pkg/storage/memory-lfu.go

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package storage
33
import (
44
"container/list"
55
"context"
6+
"math"
67
"sync"
78
"time"
89

@@ -12,18 +13,18 @@ import (
1213

1314
type LFUCache struct {
1415
mtx sync.RWMutex
15-
min int
16+
min uint
1617
capacityMB float64
1718
sizeMB float64
1819
lookupTimeout time.Duration
19-
lists map[int]*FrequencyList
20+
lists map[uint]*FrequencyList
2021
cache map[string]*list.Element
2122
staleDuration int64
2223
}
2324

2425
type FrequencyList struct {
2526
lruCache *list.List
26-
counter int
27+
counter uint
2728
}
2829

2930
type LfuNode struct {
@@ -43,7 +44,7 @@ func NewLFUCache(maxSizeMB float64, staleInSeconds int64) *LFUCache {
4344
capacityMB: maxSizeMB,
4445
lookupTimeout: lookupTimeout,
4546
sizeMB: 0,
46-
lists: make(map[int]*FrequencyList),
47+
lists: make(map[uint]*FrequencyList),
4748
cache: make(map[string]*list.Element),
4849
staleDuration: staleInSeconds,
4950
}
@@ -53,7 +54,7 @@ func (lfu *LFUCache) Store(ctx context.Context, key string, value *model.Respons
5354
lfu.mtx.Lock()
5455
defer lfu.mtx.Unlock()
5556

56-
bodySizeMB := lfu.getSize(*value)
57+
bodySizeMB := getSize(*value)
5758

5859
if bodySizeMB > lfu.capacityMB {
5960
log.Ctx(ctx).Warn().Msg("The size of the body is bigger than the configured LRU cache maxSize. The body will not be stored.")
@@ -64,7 +65,7 @@ func (lfu *LFUCache) Store(ctx context.Context, key string, value *model.Respons
6465
val, found := lfu.cache[key]
6566

6667
if found {
67-
bodySizeMB -= lfu.getSize(*val.Value.(*LfuNode).value)
68+
bodySizeMB -= getSize(*val.Value.(*LfuNode).value)
6869
node := val.Value.(*LfuNode)
6970
node.value = value
7071
node.timeStamp = time.Now().Unix()
@@ -74,17 +75,7 @@ func (lfu *LFUCache) Store(ctx context.Context, key string, value *model.Respons
7475
lfu.sizeMB += bodySizeMB
7576

7677
for lfu.sizeMB > lfu.capacityMB {
77-
freqList := lfu.lists[lfu.min].lruCache
78-
ejectedNode := freqList.Back()
79-
freqList.Remove(ejectedNode)
80-
81-
if freqList.Len() == 0 {
82-
delete(lfu.lists, lfu.min)
83-
}
84-
85-
delete(lfu.cache, ejectedNode.Value.(*LfuNode).key)
86-
87-
lfu.sizeMB -= lfu.getSize(*ejectedNode.Value.(*LfuNode).value)
78+
lfu.ejectNode()
8879
}
8980

9081
if !found {
@@ -116,11 +107,7 @@ func (lfu *LFUCache) LookUp(ctx context.Context, key string) (*model.Response, e
116107
lfu.update(val)
117108
node := val.Value.(*LfuNode)
118109
response := node.value
119-
if (time.Now().Unix() - node.timeStamp) >= lfu.staleDuration {
120-
response.StaleValue = model.StaleValue
121-
} else {
122-
response.StaleValue = model.FreshValue
123-
}
110+
response.StaleValue = getStaleStatus(node.timeStamp, lfu.staleDuration)
124111

125112
proc <- response
126113

@@ -159,7 +146,7 @@ func (lfu *LFUCache) update(node *list.Element) {
159146
lfu.moveNode(node.Value.(*LfuNode), count+1)
160147
}
161148

162-
func (lfu *LFUCache) moveNode(node *LfuNode, count int) *list.Element {
149+
func (lfu *LFUCache) moveNode(node *LfuNode, count uint) *list.Element {
163150
if _, found := lfu.lists[count]; !found {
164151
lfu.lists[count] = &FrequencyList{
165152
lruCache: list.New(),
@@ -174,9 +161,33 @@ func (lfu *LFUCache) moveNode(node *LfuNode, count int) *list.Element {
174161
return returnedLfuNode
175162
}
176163

177-
func (lfu *LFUCache) getSize(value model.Response) float64 {
178-
sizeBytes := len(value.Body)
179-
sizeMB := float64(sizeBytes) / (1024 * 1024)
164+
func (lfu *LFUCache) ejectNode() {
165+
freqList := lfu.lists[lfu.min].lruCache
166+
ejectedNode := freqList.Back()
167+
freqList.Remove(ejectedNode)
168+
169+
if freqList.Len() == 0 {
170+
delete(lfu.lists, lfu.min)
171+
lfu.min = lfu.findNextMin()
172+
}
173+
174+
delete(lfu.cache, ejectedNode.Value.(*LfuNode).key)
175+
176+
lfu.sizeMB -= getSize(*ejectedNode.Value.(*LfuNode).value)
177+
}
178+
179+
func (lfu *LFUCache) findNextMin() uint {
180+
if _, found := lfu.lists[lfu.min+1]; found {
181+
return lfu.min + 1
182+
}
183+
184+
var newMin uint = math.MaxUint
185+
186+
for k := range lfu.lists {
187+
if k < newMin {
188+
newMin = k
189+
}
190+
}
180191

181-
return sizeMB
192+
return newMin
182193
}

pkg/storage/memory-lfu_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ func TestLFUFunctionality2(t *testing.T) {
140140
assert.Equal(t, 300, resp.Status)
141141
assert.False(t, resp.IsStale())
142142

143+
cache.LookUp(ctx, "3")
144+
cache.LookUp(ctx, "3")
145+
cache.LookUp(ctx, "1")
146+
// both entry 2 and entry 3 should be deleted from cache
143147
err = cache.Store(ctx, "1", &model.Response{
144148
Status: 200,
145149
Body: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9},

pkg/storage/memory-lru.go

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (lru *LRUCache) Store(ctx context.Context, key string, value *model.Respons
4545
lru.mtx.Lock()
4646
defer lru.mtx.Unlock()
4747

48-
bodySizeMB := lru.getSize(*value)
48+
bodySizeMB := getSize(*value)
4949

5050
if bodySizeMB > lru.capacityMB {
5151
log.Ctx(ctx).Warn().Msg("The size of the body is bigger than the configured LRU cache maxSize. The body will not be stored.")
@@ -54,7 +54,7 @@ func (lru *LRUCache) Store(ctx context.Context, key string, value *model.Respons
5454
}
5555

5656
if val, found := lru.cache[key]; found {
57-
bodySizeMB -= lru.getSize(*val.Value.(*LRUNode).value)
57+
bodySizeMB -= getSize(*val.Value.(*LRUNode).value)
5858
node := val.Value.(*LRUNode)
5959
node.value = value
6060
node.timeStamp = time.Now().Unix()
@@ -66,14 +66,9 @@ func (lru *LRUCache) Store(ctx context.Context, key string, value *model.Respons
6666
}
6767

6868
lru.sizeMB += bodySizeMB
69-
var ejectedNode *list.Element
7069

7170
for lru.sizeMB > lru.capacityMB {
72-
ejectedNode = lru.responses.Back()
73-
delete(lru.cache, ejectedNode.Value.(*LRUNode).key)
74-
lru.responses.Remove(ejectedNode)
75-
76-
lru.sizeMB -= lru.getSize(*ejectedNode.Value.(*LRUNode).value)
71+
lru.ejectNode()
7772
}
7873

7974
return nil
@@ -93,11 +88,7 @@ func (lru *LRUCache) LookUp(ctx context.Context, key string) (*model.Response, e
9388
lru.responses.MoveToFront(value)
9489
node := value.Value.(*LRUNode)
9590
response := node.value
96-
if (time.Now().Unix() - node.timeStamp) >= lru.staleDuration {
97-
response.StaleValue = model.StaleValue
98-
} else {
99-
response.StaleValue = model.FreshValue
100-
}
91+
response.StaleValue = getStaleStatus(node.timeStamp, lru.staleDuration)
10192

10293
proc <- response
10394

@@ -119,9 +110,10 @@ func (lru *LRUCache) LookUp(ctx context.Context, key string) (*model.Response, e
119110
}
120111
}
121112

122-
func (lru *LRUCache) getSize(value model.Response) float64 {
123-
sizeBytes := len(value.Body)
124-
sizeMB := float64(sizeBytes) / (1024 * 1024)
113+
func (lru *LRUCache) ejectNode() {
114+
ejectedNode := lru.responses.Back()
115+
delete(lru.cache, ejectedNode.Value.(*LRUNode).key)
116+
lru.responses.Remove(ejectedNode)
125117

126-
return sizeMB
118+
lru.sizeMB -= getSize(*ejectedNode.Value.(*LRUNode).value)
127119
}

0 commit comments

Comments
 (0)