// Copyright (C) 2022 Marius Schellenberger package fs import ( "context" "os" "sync" "time" ) const statExpiry = time.Minute * 5 type statCacheEntry struct { mtime time.Time fi os.FileInfo } type StatCache struct { mu sync.RWMutex ctx context.Context m map[string]*statCacheEntry } func NewStatCache(ctx context.Context) *StatCache { sc := &StatCache{ctx: ctx, m: make(map[string]*statCacheEntry)} go sc.cleanup() return sc } func (sc *StatCache) cleanup() { t := time.NewTicker(statExpiry) defer t.Stop() for { select { case <-sc.ctx.Done(): return case <-t.C: } sc.mu.Lock() now := time.Now() for k, sce := range sc.m { if now.After(sce.mtime) { delete(sc.m, k) } } sc.mu.Unlock() } } func (sc *StatCache) Get(name string) (os.FileInfo, error) { sc.mu.RLock() defer sc.mu.RUnlock() if sce, ok := sc.m[name]; ok { return sce.fi, nil } return nil, NoCacheEntry } func (sc *StatCache) Set(name string, fi os.FileInfo) { sc.mu.Lock() defer sc.mu.Unlock() sc.m[name] = &statCacheEntry{time.Now().Add(statExpiry), fi} }