From d9405b45e9048f2ef8089551a8b750fd368164d0 Mon Sep 17 00:00:00 2001 From: qizhiwang Date: Thu, 6 May 2021 22:00:51 +0800 Subject: [PATCH 1/3] [Update] add expire check interval --- arc.go | 25 ++++++++++++++++++++++ cache.go | 8 +++++++ examples/expireinterval/expire_interval.go | 21 ++++++++++++++++++ lfu.go | 25 ++++++++++++++++++++++ lru.go | 25 ++++++++++++++++++++++ simple.go | 25 ++++++++++++++++++++++ 6 files changed, 129 insertions(+) create mode 100644 examples/expireinterval/expire_interval.go diff --git a/arc.go b/arc.go index e2015e9..8fdd0a0 100644 --- a/arc.go +++ b/arc.go @@ -32,6 +32,31 @@ func (c *ARC) init() { c.t2 = newARCList() c.b1 = newARCList() c.b2 = newARCList() + + if c.expireCheckInterval != nil && *c.expireCheckInterval != 0 { + go func() { + for range time.Tick(*c.expireCheckInterval) { + for key := range c.items { + now := time.Now() + c.checkAndDeleteExpire(key, &now) + } + } + }() + } +} + +func (c *ARC) checkAndDeleteExpire(key interface{}, now *time.Time) { + c.mu.Lock() + defer c.mu.Unlock() + + item, ok := c.items[key] + if !ok { + return + } + + if item.IsExpired(now) { + c.remove(key) + } } func (c *ARC) replace(key interface{}) { diff --git a/cache.go b/cache.go index e13e6f1..05638db 100644 --- a/cache.go +++ b/cache.go @@ -42,6 +42,7 @@ type baseCache struct { deserializeFunc DeserializeFunc serializeFunc SerializeFunc expiration *time.Duration + expireCheckInterval *time.Duration mu sync.RWMutex loadGroup Group *stats @@ -66,6 +67,7 @@ type CacheBuilder struct { purgeVisitorFunc PurgeVisitorFunc addedFunc AddedFunc expiration *time.Duration + expireCheckInterval *time.Duration deserializeFunc DeserializeFunc serializeFunc SerializeFunc } @@ -152,6 +154,11 @@ func (cb *CacheBuilder) Expiration(expiration time.Duration) *CacheBuilder { return cb } +func (cb *CacheBuilder) ExpireCheckInterval(expireCheckInterval time.Duration) *CacheBuilder { + cb.expireCheckInterval = &expireCheckInterval + return cb +} + func (cb *CacheBuilder) Build() Cache { if cb.size <= 0 && cb.tp != TYPE_SIMPLE { panic("gcache: Cache size <= 0") @@ -185,6 +192,7 @@ func buildCache(c *baseCache, cb *CacheBuilder) { c.serializeFunc = cb.serializeFunc c.evictedFunc = cb.evictedFunc c.purgeVisitorFunc = cb.purgeVisitorFunc + c.expireCheckInterval = cb.expireCheckInterval c.stats = &stats{} } diff --git a/examples/expireinterval/expire_interval.go b/examples/expireinterval/expire_interval.go new file mode 100644 index 0000000..3c1195c --- /dev/null +++ b/examples/expireinterval/expire_interval.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "github.com/bluele/gcache" + "time" +) + +func main () { + gc := gcache.New(10). + LRU(). + EvictedFunc(func(key, value interface{}) { + fmt.Printf("key: [%v] evicted\n", key) + }). + ExpireCheckInterval(300 * time.Millisecond). + Build() + + _ = gc.SetWithExpire(1, 1, time.Second) + + time.Sleep(time.Second * 2) +} diff --git a/lfu.go b/lfu.go index 9a4e3df..4f2bbf9 100644 --- a/lfu.go +++ b/lfu.go @@ -43,6 +43,31 @@ func (c *LFUCache) init() { freq: 0, items: make(map[*lfuItem]struct{}), }) + + if c.expireCheckInterval != nil && *c.expireCheckInterval != 0 { + go func() { + for range time.Tick(*c.expireCheckInterval) { + for key := range c.items { + now := time.Now() + c.checkAndDeleteExpire(key, &now) + } + } + }() + } +} + +func (c *LFUCache) checkAndDeleteExpire(key interface{}, now *time.Time) { + c.mu.Lock() + defer c.mu.Unlock() + + item, ok := c.items[key] + if !ok { + return + } + + if item.IsExpired(now) { + c.remove(key) + } } // Set a new key-value pair diff --git a/lru.go b/lru.go index a85d660..d94ea2b 100644 --- a/lru.go +++ b/lru.go @@ -24,6 +24,31 @@ func newLRUCache(cb *CacheBuilder) *LRUCache { func (c *LRUCache) init() { c.evictList = list.New() c.items = make(map[interface{}]*list.Element, c.size+1) + + if c.expireCheckInterval != nil && *c.expireCheckInterval != 0 { + go func() { + for range time.Tick(*c.expireCheckInterval) { + for key := range c.items { + now := time.Now() + c.checkAndDeleteExpire(key, &now) + } + } + }() + } +} + +func (c *LRUCache) checkAndDeleteExpire(key interface{}, now *time.Time) { + c.mu.Lock() + defer c.mu.Unlock() + + item, ok := c.items[key] + if !ok { + return + } + + if item.Value.(*lruItem).IsExpired(now) { + c.remove(key) + } } func (c *LRUCache) set(key, value interface{}) (interface{}, error) { diff --git a/simple.go b/simple.go index 7310af1..e1e38ab 100644 --- a/simple.go +++ b/simple.go @@ -25,6 +25,31 @@ func (c *SimpleCache) init() { } else { c.items = make(map[interface{}]*simpleItem, c.size) } + + if c.expireCheckInterval != nil && *c.expireCheckInterval != 0 { + go func() { + for range time.Tick(*c.expireCheckInterval) { + for key := range c.items { + now := time.Now() + c.checkAndDeleteExpire(key, &now) + } + } + }() + } +} + +func (c *SimpleCache) checkAndDeleteExpire(key interface{}, now *time.Time) { + c.mu.Lock() + defer c.mu.Unlock() + + item, ok := c.items[key] + if !ok { + return + } + + if item.IsExpired(now) { + c.remove(key) + } } // Set a new key-value pair From 2543a1aab907c0c575d689f4884a38375bcf9dc2 Mon Sep 17 00:00:00 2001 From: qizhiwang Date: Thu, 6 May 2021 22:12:00 +0800 Subject: [PATCH 2/3] [Update] add expire check interval doc in README.md --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index b8f124b..06c7c84 100644 --- a/README.md +++ b/README.md @@ -312,6 +312,28 @@ added key: 1 added key: 2 ``` +## Interval +### Expire check interval +```go +func main () { + gc := gcache.New(10). + LRU(). + EvictedFunc(func(key, value interface{}) { + fmt.Printf("key: [%v] evicted\n", key) + }). + ExpireCheckInterval(300 * time.Millisecond). + Build() + + _ = gc.SetWithExpire(1, 1, time.Second) + + time.Sleep(time.Second * 2) +} +``` + +``` +key: [1] evicted +``` + # Author **Jun Kimura** From 75299298bdd43f832e6391fb92936e7f21e7800f Mon Sep 17 00:00:00 2001 From: qizhiwang Date: Thu, 6 May 2021 22:18:07 +0800 Subject: [PATCH 3/3] [Format] format code --- cache.go | 46 +++++++++++----------- examples/autoloading/autoloading_cache.go | 4 +- examples/expireinterval/expire_interval.go | 2 +- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/cache.go b/cache.go index 05638db..90bd1eb 100644 --- a/cache.go +++ b/cache.go @@ -33,18 +33,18 @@ type Cache interface { } type baseCache struct { - clock Clock - size int - loaderExpireFunc LoaderExpireFunc - evictedFunc EvictedFunc - purgeVisitorFunc PurgeVisitorFunc - addedFunc AddedFunc - deserializeFunc DeserializeFunc - serializeFunc SerializeFunc - expiration *time.Duration - expireCheckInterval *time.Duration - mu sync.RWMutex - loadGroup Group + clock Clock + size int + loaderExpireFunc LoaderExpireFunc + evictedFunc EvictedFunc + purgeVisitorFunc PurgeVisitorFunc + addedFunc AddedFunc + deserializeFunc DeserializeFunc + serializeFunc SerializeFunc + expiration *time.Duration + expireCheckInterval *time.Duration + mu sync.RWMutex + loadGroup Group *stats } @@ -59,17 +59,17 @@ type ( ) type CacheBuilder struct { - clock Clock - tp string - size int - loaderExpireFunc LoaderExpireFunc - evictedFunc EvictedFunc - purgeVisitorFunc PurgeVisitorFunc - addedFunc AddedFunc - expiration *time.Duration - expireCheckInterval *time.Duration - deserializeFunc DeserializeFunc - serializeFunc SerializeFunc + clock Clock + tp string + size int + loaderExpireFunc LoaderExpireFunc + evictedFunc EvictedFunc + purgeVisitorFunc PurgeVisitorFunc + addedFunc AddedFunc + expiration *time.Duration + expireCheckInterval *time.Duration + deserializeFunc DeserializeFunc + serializeFunc SerializeFunc } func New(size int) *CacheBuilder { diff --git a/examples/autoloading/autoloading_cache.go b/examples/autoloading/autoloading_cache.go index 5200b46..7bb3d16 100644 --- a/examples/autoloading/autoloading_cache.go +++ b/examples/autoloading/autoloading_cache.go @@ -9,8 +9,8 @@ func main() { gc := gcache.New(10). LFU(). LoaderFunc(func(key interface{}) (interface{}, error) { - return fmt.Sprintf("%v-value", key), nil - }). + return fmt.Sprintf("%v-value", key), nil + }). Build() v, err := gc.Get("key") diff --git a/examples/expireinterval/expire_interval.go b/examples/expireinterval/expire_interval.go index 3c1195c..94d080e 100644 --- a/examples/expireinterval/expire_interval.go +++ b/examples/expireinterval/expire_interval.go @@ -6,7 +6,7 @@ import ( "time" ) -func main () { +func main() { gc := gcache.New(10). LRU(). EvictedFunc(func(key, value interface{}) {