2021-12-03 03:15:48 +00:00
|
|
|
package cache
|
|
|
|
|
2024-02-05 18:16:35 +00:00
|
|
|
import (
|
2024-03-15 19:35:39 +00:00
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
2024-02-05 18:16:35 +00:00
|
|
|
"time"
|
2021-12-03 03:15:48 +00:00
|
|
|
|
2024-02-05 18:16:35 +00:00
|
|
|
"github.com/OrlovEvgeny/go-mcache"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Cache struct {
|
|
|
|
mcache *mcache.CacheDriver
|
2024-03-15 19:35:39 +00:00
|
|
|
memoryLimit int
|
2024-02-05 18:16:35 +00:00
|
|
|
lastCheck time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewInMemoryCache returns a new mcache that can grow infinitely.
|
2024-02-15 16:08:29 +00:00
|
|
|
func NewInMemoryCache() ICache {
|
2021-12-03 03:15:48 +00:00
|
|
|
return mcache.New()
|
|
|
|
}
|
2024-02-05 18:16:35 +00:00
|
|
|
|
|
|
|
// NewInMemoryCache returns a new mcache with a memory limit.
|
|
|
|
// If the limit is exceeded, the cache will be cleared.
|
2024-03-15 19:35:39 +00:00
|
|
|
func NewInMemoryCacheWithLimit(memoryLimit int) ICache {
|
2024-02-05 18:16:35 +00:00
|
|
|
return &Cache{
|
|
|
|
mcache: mcache.New(),
|
|
|
|
memoryLimit: memoryLimit,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Cache) Set(key string, value interface{}, ttl time.Duration) error {
|
|
|
|
now := time.Now()
|
|
|
|
|
2024-03-15 19:35:39 +00:00
|
|
|
// we don't want to do it too often
|
2024-02-05 18:16:35 +00:00
|
|
|
if now.Sub(c.lastCheck) > (time.Second * 3) {
|
|
|
|
if c.memoryLimitOvershot() {
|
2024-03-15 19:35:39 +00:00
|
|
|
log.Info().Msg("[cache] memory limit exceeded, clearing cache")
|
2024-02-05 18:16:35 +00:00
|
|
|
c.mcache.Truncate()
|
|
|
|
}
|
|
|
|
c.lastCheck = now
|
|
|
|
}
|
|
|
|
|
|
|
|
return c.mcache.Set(key, value, ttl)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Cache) Get(key string) (interface{}, bool) {
|
|
|
|
return c.mcache.Get(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Cache) Remove(key string) {
|
|
|
|
c.mcache.Remove(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Cache) memoryLimitOvershot() bool {
|
2024-03-15 19:35:39 +00:00
|
|
|
mem := getCurrentMemory()
|
2024-02-05 18:16:35 +00:00
|
|
|
|
2024-03-15 19:35:39 +00:00
|
|
|
log.Debug().Int("kB", mem).Msg("[cache] current memory usage")
|
2024-02-05 18:16:35 +00:00
|
|
|
|
2024-03-15 19:35:39 +00:00
|
|
|
return mem > c.memoryLimit
|
|
|
|
}
|
|
|
|
|
|
|
|
// getCurrentMemory returns the current memory in KB
|
|
|
|
func getCurrentMemory() int {
|
|
|
|
b, err := os.ReadFile("/proc/self/statm")
|
|
|
|
if err != nil {
|
|
|
|
log.Error().Err(err).Msg("[cache] could not read /proc/self/statm")
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
str := string(b)
|
|
|
|
arr := strings.Split(str, " ")
|
|
|
|
|
|
|
|
// convert to pages
|
|
|
|
res, err := strconv.Atoi(arr[1])
|
|
|
|
if err != nil {
|
|
|
|
log.Error().Err(err).Msg("[cache] could not convert string to int")
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert to KB
|
|
|
|
return (res * os.Getpagesize()) / 1024
|
2024-02-05 18:16:35 +00:00
|
|
|
}
|