Skip to content

Commit 94bca3a

Browse files
authored
Merge pull request #11 from lxzan/dev
Fix Update TTL
2 parents 517ec93 + 66a3e96 commit 94bca3a

File tree

3 files changed

+165
-29
lines changed

3 files changed

+165
-29
lines changed

cache.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,8 @@ func (c *MemoryCache) SetWithCallback(key string, value any, exp time.Duration,
168168
v, ok := c.fetch(b, key)
169169
if ok {
170170
v.Value = value
171-
v.ExpireAt = expireAt
172171
v.cb = cb
173-
b.Heap.Down(v.index, b.Heap.Len())
172+
b.Heap.UpdateTTL(v, expireAt)
174173
return true
175174
}
176175

@@ -205,8 +204,7 @@ func (c *MemoryCache) GetWithTTL(key string, exp time.Duration) (v any, exist bo
205204
return nil, false
206205
}
207206

208-
result.ExpireAt = c.getExp(exp)
209-
b.Heap.Down(result.index, b.Heap.Len())
207+
b.Heap.UpdateTTL(result, c.getExp(exp))
210208
return result.Value, true
211209
}
212210

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: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ type heap struct {
1212

1313
func (c *heap) Less(i, j int) bool { return c.Data[i].ExpireAt < c.Data[j].ExpireAt }
1414

15+
func (c *heap) UpdateTTL(ele *Element, exp int64) {
16+
var down = exp > ele.ExpireAt
17+
ele.ExpireAt = exp
18+
if down {
19+
c.Down(ele.index, c.Len())
20+
} else {
21+
c.Up(ele.index)
22+
}
23+
}
24+
1525
func (c *heap) min(i, j int) int {
1626
if c.Data[i].ExpireAt < c.Data[j].ExpireAt {
1727
return i
@@ -59,10 +69,22 @@ func (c *heap) Pop() (ele *Element) {
5969
}
6070

6171
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)
72+
var n = c.Len()
73+
switch n {
74+
case 1:
75+
c.Data = c.Data[:0]
76+
default:
77+
var down = c.Less(i, n-1)
78+
c.Swap(i, n-1)
79+
c.Data = c.Data[:n-1]
80+
if i < n-1 {
81+
if down {
82+
c.Down(i, n-1)
83+
} else {
84+
c.Up(i)
85+
}
86+
}
87+
}
6688
}
6789

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

0 commit comments

Comments
 (0)