64 lines
1.1 KiB
Go
64 lines
1.1 KiB
Go
// 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}
|
|
}
|