pages-server/server/cache/memory.go

85 lines
1.7 KiB
Go

package cache
import (
"os"
"strconv"
"strings"
"time"
"github.com/OrlovEvgeny/go-mcache"
"github.com/rs/zerolog/log"
)
type Cache struct {
mcache *mcache.CacheDriver
memoryLimit int
lastCheck time.Time
}
// NewInMemoryCache returns a new mcache that can grow infinitely.
func NewInMemoryCache() ICache {
return mcache.New()
}
// NewInMemoryCache returns a new mcache with a memory limit.
// If the limit is exceeded, the cache will be cleared.
func NewInMemoryCacheWithLimit(memoryLimit int) ICache {
return &Cache{
mcache: mcache.New(),
memoryLimit: memoryLimit,
}
}
func (c *Cache) Set(key string, value interface{}, ttl time.Duration) error {
now := time.Now()
// we don't want to do it too often
if now.Sub(c.lastCheck) > (time.Second * 3) {
if c.memoryLimitOvershot() {
log.Info().Msg("[cache] memory limit exceeded, clearing cache")
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 {
mem := getCurrentMemory()
log.Debug().Int("kB", mem).Msg("[cache] current memory usage")
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
}