* 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.
83 lines
1.5 KiB
Go
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())
|
|
}
|