Skip to content

Commit

Permalink
Fix clear lru cache
Browse files Browse the repository at this point in the history
  • Loading branch information
nekohasekai committed Nov 18, 2024
1 parent ad36d3b commit 8c0bf1c
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 2 deletions.
10 changes: 8 additions & 2 deletions common/cache/lrucache.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,15 @@ func (c *LruCache[K, V]) Delete(key K) {
func (c *LruCache[K, V]) Clear() {
c.mu.Lock()
defer c.mu.Unlock()
for element := c.lru.Front(); element != nil; element = element.Next() {
c.deleteElement(element)

if c.onEvict != nil {
for le := c.lru.Front(); le != nil; le = le.Next() {
c.onEvict(le.Value.key, le.Value.value)
}
}

c.lru.Init()
c.cache = make(map[K]*list.Element[*entry[K, V]])
}

func (c *LruCache[K, V]) maybeDeleteOldest() {
Expand Down
113 changes: 113 additions & 0 deletions common/cache/lrucache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package cache_test

import (
"testing"
"time"

"github.com/sagernet/sing/common/cache"

"github.com/stretchr/testify/require"
)

func TestLRUCache(t *testing.T) {
t.Run("basic operations", func(t *testing.T) {
t.Parallel()
c := cache.New[string, int]()

c.Store("key1", 1)
value, exists := c.Load("key1")
require.True(t, exists)
require.Equal(t, 1, value)

value, exists = c.Load("missing")
require.False(t, exists)
require.Zero(t, value)

c.Delete("key1")
_, exists = c.Load("key1")
require.False(t, exists)
})

t.Run("max size", func(t *testing.T) {
t.Parallel()
c := cache.New[string, int](cache.WithSize[string, int](2))

c.Store("key1", 1)
c.Store("key2", 2)
c.Store("key3", 3)

_, exists := c.Load("key1")
require.False(t, exists)

value, exists := c.Load("key2")
require.True(t, exists)
require.Equal(t, 2, value)
})

t.Run("expiration", func(t *testing.T) {
t.Parallel()
c := cache.New[string, int](cache.WithAge[string, int](1))

c.Store("key1", 1)

value, exists := c.Load("key1")
require.True(t, exists)
require.Equal(t, 1, value)

time.Sleep(time.Second * 2)

value, exists = c.Load("key1")
require.False(t, exists)
require.Zero(t, value)
})

t.Run("clear", func(t *testing.T) {
t.Parallel()
evicted := make(map[string]int)
c := cache.New[string, int](
cache.WithEvict[string, int](func(key string, value int) {
evicted[key] = value
}),
)

c.Store("key1", 1)
c.Store("key2", 2)

c.Clear()

require.Equal(t, map[string]int{"key1": 1, "key2": 2}, evicted)
_, exists := c.Load("key1")
require.False(t, exists)
})

t.Run("load or store", func(t *testing.T) {
t.Parallel()
c := cache.New[string, int]()

value, loaded := c.LoadOrStore("key1", func() int { return 1 })
require.False(t, loaded)
require.Equal(t, 1, value)

value, loaded = c.LoadOrStore("key1", func() int { return 2 })
require.True(t, loaded)
require.Equal(t, 1, value)
})

t.Run("update age on get", func(t *testing.T) {
t.Parallel()
c := cache.New[string, int](
cache.WithAge[string, int](5),
cache.WithUpdateAgeOnGet[string, int](),
)

c.Store("key1", 1)

time.Sleep(time.Second * 3)
_, exists := c.Load("key1")
require.True(t, exists)

time.Sleep(time.Second * 3)
_, exists = c.Load("key1")
require.True(t, exists)
})
}

0 comments on commit 8c0bf1c

Please sign in to comment.