Files
Zijing Zhang f56ac4eabc perf(cache): implement GC feature for simple_cache pkg (#656)
* feat: garbage collection feature

A new `GC()` method has been added to the `Cache` struct,
which performs garbage collection by deleting expired entries from the
cache.
2023-12-17 02:32:47 +08:00

83 lines
1.5 KiB
Go

package simple_cache
import (
"sync"
"sync/atomic"
"time"
)
type Cache struct {
data sync.Map
// when the number of entries reaches gcThold, GC will be triggered
gcThold int
len atomic.Int32
}
func New() *Cache {
return &Cache{
gcThold: 1000,
len: atomic.Int32{},
}
}
func NewWithGCThold(gcThold int) *Cache {
return &Cache{
gcThold: gcThold,
len: atomic.Int32{},
}
}
type cacheEntry struct {
value interface{}
expiration time.Time
}
func (c *Cache) Set(key string, value interface{}, expirationParam ...time.Duration) {
defer c.GC(false)
var expirationTime time.Time
if len(expirationParam) > 0 && expirationParam[0] > 0 {
expirationTime = time.Now().Add(expirationParam[0])
}
entry := cacheEntry{
value: value,
expiration: expirationTime,
}
c.data.Store(key, entry)
c.len.Add(1)
}
func (c *Cache) Get(key string) (interface{}, bool) {
defer c.GC(false)
if val, found := c.data.Load(key); found {
entry := val.(cacheEntry)
if !isExpired(entry) {
return entry.value, true
}
c.data.Delete(key)
}
return nil, false
}
func (c *Cache) Delete(key string) {
c.data.Delete(key)
c.len.Add(-1)
}
func (c* Cache) GC(force bool) {
if int(c.len.Load()) < c.gcThold && !force {
return
}
c.data.Range(func(key, value interface{}) bool {
entry := value.(cacheEntry)
if !isExpired(entry) {
return true
}
c.Delete(key.(string))
return true
})
}
func isExpired(entry cacheEntry) bool {
return !entry.expiration.IsZero() && entry.expiration.Before(time.Now())
}