cache clean implemented
This commit is contained in:
Vendored
+115
@@ -0,0 +1,115 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
)
|
||||
|
||||
type fileEntry struct {
|
||||
path string
|
||||
size int64
|
||||
atime time.Time
|
||||
}
|
||||
|
||||
func (c *Cache) Clean() error {
|
||||
// age always triggers eviction
|
||||
// if cache is still over max size after age eviction
|
||||
// evict until size is sizeThreshold % of max size
|
||||
sizeThreshold := c.cfg.MaxCacheSize * 3 / 4
|
||||
|
||||
cacheSize, cachedFiles, err := c.getCachedFiles()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// remove any pkgs over max age, update cache size while doing
|
||||
evictBefore := time.Now().Add(-c.cfg.MaxCacheAge)
|
||||
i := 0
|
||||
rsize := int64(0)
|
||||
for _, f := range cachedFiles {
|
||||
if !f.atime.Before(evictBefore) {
|
||||
break
|
||||
}
|
||||
if err := c.cr.Remove(f.path); err != nil {
|
||||
slog.Error("failed to remove file: %v", "file", f.path, "err", err)
|
||||
continue
|
||||
}
|
||||
cacheSize -= f.size
|
||||
rsize += f.size
|
||||
i++
|
||||
}
|
||||
cachedFiles = cachedFiles[i:]
|
||||
slog.Info("evicted aged out pkgs", "num", i, "size", humanize.Bytes(uint64(rsize)))
|
||||
|
||||
// if cache size < max size we're done
|
||||
if cacheSize < c.cfg.MaxCacheSize {
|
||||
return nil
|
||||
}
|
||||
|
||||
// remove oldest files until cache size < threshold
|
||||
i = 0
|
||||
rsize = 0
|
||||
for i < len(cachedFiles) && cacheSize > sizeThreshold {
|
||||
f := cachedFiles[i]
|
||||
if err := c.cr.Remove(f.path); err != nil {
|
||||
slog.Error("failed to remove file: %v", "file", f.path, "err", err)
|
||||
continue
|
||||
}
|
||||
cacheSize -= f.size
|
||||
rsize += f.size
|
||||
i++
|
||||
}
|
||||
slog.Info("evicted aged out pkgs", "num", i, "size", humanize.Bytes(uint64(rsize)))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cache) getCachedFiles() (int64, []fileEntry, error) {
|
||||
// returns total cache size and sorted slice, oldest first,
|
||||
// of all fileEntry where name is the relative path
|
||||
// from the cacheroot
|
||||
cacheSize := int64(0)
|
||||
cachedFiles := []fileEntry{}
|
||||
for _, repo := range c.cfg.mirroredRepos {
|
||||
relPath := filepath.Join(repo, "os/x86_64")
|
||||
f, err := c.cr.Open(relPath)
|
||||
files, err := f.ReadDir(-1)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
for _, f := range files {
|
||||
fInfo, err := f.Info()
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
if strings.HasSuffix(f.Name(), ".gz") || strings.HasSuffix(f.Name(), ".db") {
|
||||
continue
|
||||
}
|
||||
name := filepath.Join(repo, repoArch, f.Name())
|
||||
size := fInfo.Size()
|
||||
stat_t := fInfo.Sys().(*syscall.Stat_t)
|
||||
atime := time.Unix(stat_t.Atim.Sec, stat_t.Atim.Nsec)
|
||||
entry := fileEntry{
|
||||
path: name,
|
||||
size: size,
|
||||
atime: atime,
|
||||
}
|
||||
cachedFiles = append(cachedFiles, entry)
|
||||
cacheSize += size
|
||||
|
||||
}
|
||||
}
|
||||
slices.SortFunc(cachedFiles, func(a, b fileEntry) int {
|
||||
return a.atime.Compare(b.atime)
|
||||
})
|
||||
return cacheSize, cachedFiles, nil
|
||||
}
|
||||
Reference in New Issue
Block a user