From 809d8eca139712f6c833cea813674a1cb1154ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 3 Dec 2024 11:50:46 +0800 Subject: [PATCH] freelru: fix PurgeExpired --- contrab/freelru/lru.go | 15 +++++++-------- contrab/freelru/lru_test.go | 28 +++++++++++++++++++--------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/contrab/freelru/lru.go b/contrab/freelru/lru.go index 56422255..55e89371 100644 --- a/contrab/freelru/lru.go +++ b/contrab/freelru/lru.go @@ -687,20 +687,19 @@ func (lru *LRU[K, V]) Purge() { // PurgeExpired purges all expired items from the LRU. // The evict function is called for each expired item. func (lru *LRU[K, V]) PurgeExpired() { + n := now() +loop: l := lru.len if l == 0 { return } - n := now() - pos := lru.head + pos := lru.elements[lru.head].next for i := uint32(0); i < l; i++ { - next := lru.elements[pos].next - if lru.elements[pos].expire != 0 { - if lru.elements[pos].expire <= n { - lru.removeAt(pos) - } + if lru.elements[pos].expire != 0 && lru.elements[pos].expire <= n { + lru.removeAt(pos) + goto loop } - pos = next + pos = lru.elements[pos].next } } diff --git a/contrab/freelru/lru_test.go b/contrab/freelru/lru_test.go index 0b548b5f..d3ea64a3 100644 --- a/contrab/freelru/lru_test.go +++ b/contrab/freelru/lru_test.go @@ -1,6 +1,9 @@ package freelru_test import ( + "github.com/sagernet/sing/common" + F "github.com/sagernet/sing/common/format" + "math/rand/v2" "testing" "time" @@ -75,16 +78,23 @@ func TestUpdateLifetime2(t *testing.T) { require.False(t, ok) } -func TestPeekWithLifetime(t *testing.T) { +func TestPurgeExpired(t *testing.T) { t.Parallel() - lru, err := freelru.New[string, string](1024, maphash.NewHasher[string]().Hash32) + lru, err := freelru.New[string, *string](1024, maphash.NewHasher[string]().Hash32) require.NoError(t, err) lru.SetLifetime(time.Second) - lru.AddWithLifetime("hello", "world", 10*time.Second) - lru.Add("hello1", "") - lru.Add("hello2", "") - lru.Add("hello3", "") - time.Sleep(2 * time.Second) - lru.PurgeExpired() - require.Equal(t, 1, lru.Len()) + lru.SetOnEvict(func(s string, s2 *string) { + if s2 == nil { + t.Fail() + } + }) + for i := 0; i < 100; i++ { + lru.AddWithLifetime("hello_"+F.ToString(i), common.Ptr("world_"+F.ToString(i)), time.Duration(rand.Int32N(3000))*time.Millisecond) + } + for i := 0; i < 5; i++ { + time.Sleep(time.Second) + lru.GetAndRefreshOrAdd("hellox"+F.ToString(i), func() (*string, bool) { + return common.Ptr("worldx"), true + }) + } }