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

@ -27,13 +27,15 @@ type FS struct {
NoCache http.Handler NoCache http.Handler
src string src string
dst string dst string
statCancel func()
flushCancel func()
mdf *os.File mdf *os.File
jenc *json.Encoder jenc *json.Encoder
dc *DirCache dc *DirCache
sc *StatCache
q *Quota q *Quota
md MetadataMap md MetadataMap
pm map[string]func() pm map[string]func()
cancel 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,13 +55,18 @@ 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,
statCancel: statCancel,
flushCancel: flushCancel,
dc: NewDirCache(), dc: NewDirCache(),
sc: NewStatCache(statCtx),
md: make(MetadataMap), md: make(MetadataMap),
pm: make(map[string]func()), pm: make(map[string]func()),
jenc: json.NewEncoder(mdf), jenc: json.NewEncoder(mdf),
@ -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}
}