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 {
mu sync.RWMutex
log logr.Logger
NoCache http.Handler
src string
dst string
mdf *os.File
jenc *json.Encoder
dc *DirCache
q *Quota
md MetadataMap
pm map[string]func()
cancel func()
mu sync.RWMutex
log logr.Logger
NoCache http.Handler
src string
dst string
statCancel func()
flushCancel func()
mdf *os.File
jenc *json.Encoder
dc *DirCache
sc *StatCache
q *Quota
md MetadataMap
pm map[string]func()
}
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 {
return
}
statCtx, statCancel := context.WithCancel(context.Background())
flushCtx, flushCancel := context.WithCancel(context.Background())
fs = &FS{
log: log,
NoCache: http.FileServer(http.Dir(src)),
src: src,
dst: dst,
mdf: mdf,
dc: NewDirCache(),
md: make(MetadataMap),
pm: make(map[string]func()),
jenc: json.NewEncoder(mdf),
log: log,
NoCache: http.FileServer(http.Dir(src)),
src: src,
dst: dst,
mdf: mdf,
statCancel: statCancel,
flushCancel: flushCancel,
dc: NewDirCache(),
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"))
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.q.Init()
ctx, cancel := context.WithCancel(context.Background())
fs.cancel = cancel
go fs.flusher(ctx)
go fs.flusher(flushCtx)
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) {
sp, dp := fs.paths(name)
fi, err = fs.sc.Get(name)
if err == nil {
return
}
fi, err = os.Stat(sp)
if err == nil {
fs.sc.Set(name, fi)
return
}
fi, err = os.Stat(dp)
@ -347,7 +357,8 @@ func (fs *FS) flushMetadata() {
}
func (fs *FS) Close() {
fs.cancel()
fs.flushCancel()
fs.statCancel()
for _, cancel := range fs.pm {
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}
}