diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index c71b426f00cbca17ca0b2597e222e3e2a57ea58d..e8feb4ce5309bfa92feec72c4624190a3c1e1c79 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -1,88 +1,7 @@ package cache -import ( - "fmt" - "time" - - "git.perx.ru/perxis/perxis-go/pkg/service" - lru "github.com/hashicorp/golang-lru/v2" - "go.uber.org/zap" -) - -const ( - defaultCacheSize = 1000 - defaultTTL = 30 * time.Second -) - -type Cache struct { - cache *lru.Cache[interface{}, interface{}] - ttl time.Duration - logger *zap.Logger -} - -type item struct { - value interface{} - expiredAt time.Time -} - -func NewCache(size int, ttl time.Duration, opts ...interface{}) *Cache { - if size == 0 { - size = defaultCacheSize - } - if ttl == 0 { - ttl = defaultTTL - } - c, err := lru.New[interface{}, interface{}](size) - if err != nil { - panic(err) - } - ch := &Cache{ - cache: c, - ttl: ttl, - logger: zap.NewNop(), - } - - for _, o := range opts { - switch p := o.(type) { - case *zap.Logger: - ch.logger = p - } - } - - ch.logger = ch.logger.Named("Cache") - - return ch -} - -func (c *Cache) Set(key, value interface{}) (err error) { - c.cache.Add(key, &item{value: value, expiredAt: time.Now().Add(c.ttl)}) - c.logger.Debug("Set", zap.String("key", fmt.Sprintf("%v", key)), zap.String("ptr", fmt.Sprintf("%p", value))) - return nil -} - -func (c *Cache) Get(key interface{}) (value interface{}, err error) { - val, ok := c.cache.Get(key) - if ok { - v := val.(*item) - if v.expiredAt.Before(time.Now()) { - _ = c.Remove(key) - c.logger.Debug("Expired", zap.String("key", fmt.Sprintf("%v", key)), zap.String("ptr", fmt.Sprintf("%p", v.value))) - return nil, service.ErrNotFound - } - c.logger.Debug("Hit", zap.String("key", fmt.Sprintf("%v", key)), zap.String("ptr", fmt.Sprintf("%p", v.value))) - return v.value, nil - } - c.logger.Debug("Miss", zap.String("key", fmt.Sprintf("%v", key))) - return nil, service.ErrNotFound -} - -func (c *Cache) Remove(key interface{}) (err error) { - present := c.cache.Remove(key) - c.logger.Debug("Remove", zap.String("key", fmt.Sprintf("%v", key))) - - if !present { - err = service.ErrNotFound - } - - return +type Cache interface { + Set(key, value any) error + Get(key any) (any, error) + Remove(key any) error } diff --git a/pkg/cache/memory_cache.go b/pkg/cache/memory_cache.go new file mode 100644 index 0000000000000000000000000000000000000000..12b9b55812bbfb11646f828a4a3e643027687c4b --- /dev/null +++ b/pkg/cache/memory_cache.go @@ -0,0 +1,90 @@ +package cache + +import ( + "fmt" + "time" + + "git.perx.ru/perxis/perxis-go/pkg/service" + lru "github.com/hashicorp/golang-lru/v2" + "go.uber.org/zap" +) + +const ( + defaultCacheSize = 1000 + defaultTTL = 30 * time.Second +) + +var _ Cache = &MemoryCache{} + +type MemoryCache struct { + cache *lru.Cache[interface{}, interface{}] + ttl time.Duration + logger *zap.Logger +} + +type item struct { + value interface{} + expiredAt time.Time +} + +func NewMemoryCache(size int, ttl time.Duration, opts ...interface{}) *MemoryCache { + if size == 0 { + size = defaultCacheSize + } + if ttl == 0 { + ttl = defaultTTL + } + c, err := lru.New[interface{}, interface{}](size) + if err != nil { + panic(err) + } + ch := &MemoryCache{ + cache: c, + ttl: ttl, + logger: zap.NewNop(), + } + + for _, o := range opts { + switch p := o.(type) { + case *zap.Logger: + ch.logger = p + } + } + + ch.logger = ch.logger.Named("Cache") + + return ch +} + +func (c *MemoryCache) Set(key, value interface{}) (err error) { + c.cache.Add(key, &item{value: value, expiredAt: time.Now().Add(c.ttl)}) + c.logger.Debug("Set", zap.String("key", fmt.Sprintf("%v", key)), zap.String("ptr", fmt.Sprintf("%p", value))) + return nil +} + +func (c *MemoryCache) Get(key interface{}) (value interface{}, err error) { + val, ok := c.cache.Get(key) + if ok { + v := val.(*item) + if v.expiredAt.Before(time.Now()) { + _ = c.Remove(key) + c.logger.Debug("Expired", zap.String("key", fmt.Sprintf("%v", key)), zap.String("ptr", fmt.Sprintf("%p", v.value))) + return nil, service.ErrNotFound + } + c.logger.Debug("Hit", zap.String("key", fmt.Sprintf("%v", key)), zap.String("ptr", fmt.Sprintf("%p", v.value))) + return v.value, nil + } + c.logger.Debug("Miss", zap.String("key", fmt.Sprintf("%v", key))) + return nil, service.ErrNotFound +} + +func (c *MemoryCache) Remove(key interface{}) (err error) { + present := c.cache.Remove(key) + c.logger.Debug("Remove", zap.String("key", fmt.Sprintf("%v", key))) + + if !present { + err = service.ErrNotFound + } + + return +}