Skip to content

Commit 9ae04f0

Browse files
committed
Fix Set/GetWithTTL/Delete
1 parent 517ec93 commit 9ae04f0

File tree

3 files changed

+167
-28
lines changed

3 files changed

+167
-28
lines changed

cache.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,15 @@ func (c *MemoryCache) SetWithCallback(key string, value any, exp time.Duration,
167167
var expireAt = c.getExp(exp)
168168
v, ok := c.fetch(b, key)
169169
if ok {
170+
var down = expireAt > v.ExpireAt
170171
v.Value = value
171172
v.ExpireAt = expireAt
172173
v.cb = cb
173-
b.Heap.Down(v.index, b.Heap.Len())
174+
if down {
175+
b.Heap.Down(v.index, b.Heap.Len())
176+
} else {
177+
b.Heap.Up(v.index)
178+
}
174179
return true
175180
}
176181

@@ -205,8 +210,14 @@ func (c *MemoryCache) GetWithTTL(key string, exp time.Duration) (v any, exist bo
205210
return nil, false
206211
}
207212

208-
result.ExpireAt = c.getExp(exp)
209-
b.Heap.Down(result.index, b.Heap.Len())
213+
var expireAt = c.getExp(exp)
214+
var down = expireAt > result.ExpireAt
215+
result.ExpireAt = expireAt
216+
if down {
217+
b.Heap.Down(result.index, b.Heap.Len())
218+
} else {
219+
b.Heap.Up(result.index)
220+
}
210221
return result.Value, true
211222
}
212223

cache_test.go

Lines changed: 137 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package memorycache
22

33
import (
44
"math/rand"
5+
"sort"
6+
"strconv"
57
"sync"
68
"testing"
79
"time"
@@ -140,6 +142,40 @@ func TestMemoryCache_Set(t *testing.T) {
140142
mc.Set("feng", 1, 2*time.Hour)
141143
assert.ElementsMatch(t, mc.Keys(""), []string{"ming", "feng"})
142144
})
145+
146+
t.Run("update ttl", func(t *testing.T) {
147+
var mc = New(WithBucketNum(1))
148+
var count = 1000
149+
for i := 0; i < 10*count; i++ {
150+
key := strconv.Itoa(utils.Numeric.Intn(count))
151+
exp := time.Duration(utils.Numeric.Intn(count)+10) * time.Second
152+
mc.Set(key, 1, exp)
153+
}
154+
155+
var list1 []int
156+
var list2 []int
157+
for _, b := range mc.storage {
158+
b.Lock()
159+
for _, item := range b.Heap.Data {
160+
list1 = append(list1, int(item.ExpireAt))
161+
}
162+
b.Unlock()
163+
}
164+
sort.Ints(list1)
165+
166+
for _, b := range mc.storage {
167+
b.Lock()
168+
for b.Heap.Len() > 0 {
169+
list2 = append(list2, int(b.Heap.Pop().ExpireAt))
170+
}
171+
b.Unlock()
172+
}
173+
174+
assert.Equal(t, len(list1), len(list2))
175+
for i, v := range list2 {
176+
assert.Equal(t, list1[i], v)
177+
}
178+
})
143179
}
144180

145181
func TestMemoryCache_Get(t *testing.T) {
@@ -199,30 +235,72 @@ func TestMemoryCache_Get(t *testing.T) {
199235
}
200236

201237
func TestMemoryCache_GetWithTTL(t *testing.T) {
202-
var list []string
203-
var count = 10000
204-
var mc = New(WithInterval(100*time.Millisecond, 100*time.Millisecond))
205-
for i := 0; i < count; i++ {
206-
key := string(utils.AlphabetNumeric.Generate(8))
207-
exp := rand.Intn(1000) + 200
208-
list = append(list, key)
209-
mc.Set(key, 1, time.Duration(exp)*time.Millisecond)
210-
}
211-
var keys = mc.Keys("")
212-
for _, key := range keys {
213-
mc.GetWithTTL(key, 2*time.Second)
214-
}
238+
t.Run("", func(t *testing.T) {
239+
var list []string
240+
var count = 10000
241+
var mc = New(WithInterval(100*time.Millisecond, 100*time.Millisecond))
242+
for i := 0; i < count; i++ {
243+
key := string(utils.AlphabetNumeric.Generate(8))
244+
exp := rand.Intn(1000) + 200
245+
list = append(list, key)
246+
mc.Set(key, 1, time.Duration(exp)*time.Millisecond)
247+
}
248+
var keys = mc.Keys("")
249+
for _, key := range keys {
250+
mc.GetWithTTL(key, 2*time.Second)
251+
}
215252

216-
time.Sleep(1100 * time.Millisecond)
253+
time.Sleep(1100 * time.Millisecond)
217254

218-
for _, item := range list {
219-
_, ok := mc.Get(item)
220-
assert.True(t, ok)
221-
}
255+
for _, item := range list {
256+
_, ok := mc.Get(item)
257+
assert.True(t, ok)
258+
}
222259

223-
mc.Delete(list[0])
224-
_, ok := mc.GetWithTTL(list[0], -1)
225-
assert.False(t, ok)
260+
mc.Delete(list[0])
261+
_, ok := mc.GetWithTTL(list[0], -1)
262+
assert.False(t, ok)
263+
})
264+
265+
t.Run("update ttl", func(t *testing.T) {
266+
var mc = New(WithBucketNum(1))
267+
var count = 1000
268+
for i := 0; i < count; i++ {
269+
key := strconv.Itoa(utils.Numeric.Intn(count))
270+
exp := time.Duration(utils.Numeric.Intn(count)+10) * time.Second
271+
mc.Set(key, 1, exp)
272+
}
273+
274+
for i := 0; i < count; i++ {
275+
key := strconv.Itoa(utils.Numeric.Intn(count))
276+
exp := time.Duration(utils.Numeric.Intn(count)+10) * time.Second
277+
mc.GetWithTTL(key, exp)
278+
}
279+
280+
var list1 []int
281+
var list2 []int
282+
for _, b := range mc.storage {
283+
b.Lock()
284+
for _, item := range b.Heap.Data {
285+
list1 = append(list1, int(item.ExpireAt))
286+
}
287+
b.Unlock()
288+
}
289+
sort.Ints(list1)
290+
291+
for _, b := range mc.storage {
292+
b.Lock()
293+
for b.Heap.Len() > 0 {
294+
list2 = append(list2, int(b.Heap.Pop().ExpireAt))
295+
}
296+
b.Unlock()
297+
}
298+
299+
assert.Equal(t, len(list1), len(list2))
300+
for i, v := range list2 {
301+
assert.Equal(t, list1[i], v)
302+
}
303+
})
226304
}
227305

228306
func TestMemoryCache_Delete(t *testing.T) {
@@ -276,6 +354,44 @@ func TestMemoryCache_Delete(t *testing.T) {
276354
go mc.Delete("ting")
277355
wg.Wait()
278356
})
357+
358+
t.Run("batch delete", func(t *testing.T) {
359+
var mc = New(WithBucketNum(1))
360+
var count = 1000
361+
for i := 0; i < count; i++ {
362+
key := strconv.Itoa(utils.Numeric.Intn(count))
363+
exp := time.Duration(utils.Numeric.Intn(count)+10) * time.Second
364+
mc.Set(key, 1, exp)
365+
}
366+
for i := 0; i < count/2; i++ {
367+
key := strconv.Itoa(utils.Numeric.Intn(count))
368+
mc.Delete(key)
369+
}
370+
371+
var list1 []int
372+
var list2 []int
373+
for _, b := range mc.storage {
374+
b.Lock()
375+
for _, item := range b.Heap.Data {
376+
list1 = append(list1, int(item.ExpireAt))
377+
}
378+
b.Unlock()
379+
}
380+
sort.Ints(list1)
381+
382+
for _, b := range mc.storage {
383+
b.Lock()
384+
for b.Heap.Len() > 0 {
385+
list2 = append(list2, int(b.Heap.Pop().ExpireAt))
386+
}
387+
b.Unlock()
388+
}
389+
390+
assert.Equal(t, len(list1), len(list2))
391+
for i, v := range list2 {
392+
assert.Equal(t, list1[i], v)
393+
}
394+
})
279395
}
280396

281397
func TestMaxCap(t *testing.T) {

heap.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,22 @@ func (c *heap) Pop() (ele *Element) {
5959
}
6060

6161
func (c *heap) Delete(i int) {
62-
n := c.Len()
63-
c.Swap(i, n-1)
64-
c.Data = c.Data[:n-1]
65-
c.Down(i, n-1)
62+
var n = c.Len()
63+
switch n {
64+
case 1:
65+
c.Data = c.Data[:0]
66+
default:
67+
var down = c.Data[n-1].ExpireAt > c.Data[i].ExpireAt
68+
c.Swap(i, n-1)
69+
c.Data = c.Data[:n-1]
70+
if i < n-1 {
71+
if down {
72+
c.Down(i, n-1)
73+
} else {
74+
c.Up(i)
75+
}
76+
}
77+
}
6678
}
6779

6880
func (c *heap) Down(i, n int) {

0 commit comments

Comments
 (0)