added stat cache

This commit is contained in:
ston1th 2022-03-20 10:19:03 +01:00
commit 675bc4d125
2 changed files with 100 additions and 25 deletions

View file

@ -22,18 +22,20 @@ import (
) )
type FS struct { type FS struct {
mu sync.RWMutex mu sync.RWMutex
log logr.Logger log logr.Logger
NoCache http.Handler NoCache http.Handler
src string src string
dst string dst string
mdf *os.File statCancel func()
jenc *json.Encoder flushCancel func()
dc *DirCache mdf *os.File
q *Quota jenc *json.Encoder
md MetadataMap dc *DirCache
pm map[string]func() sc *StatCache
cancel func() q *Quota
md MetadataMap
pm map[string]func()
} }
func NewFS(max int64, src, dst, metadata string, log logr.Logger) (fs *FS, err error) { func NewFS(max int64, src, dst, metadata string, log logr.Logger) (fs *FS, err error) {
@ -53,16 +55,21 @@ func NewFS(max int64, src, dst, metadata string, log logr.Logger) (fs *FS, err e
if err != nil { if err != nil {
return return
} }
statCtx, statCancel := context.WithCancel(context.Background())
flushCtx, flushCancel := context.WithCancel(context.Background())
fs = &FS{ fs = &FS{
log: log, log: log,
NoCache: http.FileServer(http.Dir(src)), NoCache: http.FileServer(http.Dir(src)),
src: src, src: src,
dst: dst, dst: dst,
mdf: mdf, mdf: mdf,
dc: NewDirCache(), statCancel: statCancel,
md: make(MetadataMap), flushCancel: flushCancel,
pm: make(map[string]func()), dc: NewDirCache(),
jenc: json.NewEncoder(mdf), sc: NewStatCache(statCtx),
md: make(MetadataMap),
pm: make(map[string]func()),
jenc: json.NewEncoder(mdf),
} }
fs.q, err = NewQuota(max, fs, fs.log.WithName("quota")) fs.q, err = NewQuota(max, fs, fs.log.WithName("quota"))
if err != nil { if err != nil {
@ -74,9 +81,7 @@ func NewFS(max int64, src, dst, metadata string, log logr.Logger) (fs *FS, err e
} }
fs.initMetadata() fs.initMetadata()
fs.q.Init() fs.q.Init()
ctx, cancel := context.WithCancel(context.Background()) go fs.flusher(flushCtx)
fs.cancel = cancel
go fs.flusher(ctx)
return fs, err return fs, err
} }
@ -110,8 +115,13 @@ func (fs *FS) Stat(name string) (fi stdfs.FileInfo, err error) {
func (fs *FS) StatWithOffline(name string) (fi stdfs.FileInfo, offline bool, err error) { func (fs *FS) StatWithOffline(name string) (fi stdfs.FileInfo, offline bool, err error) {
sp, dp := fs.paths(name) sp, dp := fs.paths(name)
fi, err = fs.sc.Get(name)
if err == nil {
return
}
fi, err = os.Stat(sp) fi, err = os.Stat(sp)
if err == nil { if err == nil {
fs.sc.Set(name, fi)
return return
} }
fi, err = os.Stat(dp) fi, err = os.Stat(dp)
@ -347,7 +357,8 @@ func (fs *FS) flushMetadata() {
} }
func (fs *FS) Close() { func (fs *FS) Close() {
fs.cancel() fs.flushCancel()
fs.statCancel()
for _, cancel := range fs.pm { for _, cancel := range fs.pm {
cancel() cancel()
} }

64
pkg/fs/stat.go Normal file
View file

@ -0,0 +1,64 @@
// 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}
}