Commit e36affb8 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

Only cache successful results indefinitely in CachingFileSystem.

parent eb06cb23
......@@ -89,11 +89,21 @@ func readLink(fs fuse.FileSystem, name string) *linkResponse {
func NewCachingFileSystem(fs fuse.FileSystem, ttlNs int64) *CachingFileSystem {
c := new(CachingFileSystem)
c.FileSystem = fs
c.attributes = NewTimedCache(func(n string) interface{} { return getAttr(fs, n) }, ttlNs)
c.dirs = NewTimedCache(func(n string) interface{} { return readDir(fs, n) }, ttlNs)
c.links = NewTimedCache(func(n string) interface{} { return readLink(fs, n) }, ttlNs)
c.xattr = NewTimedCache(func(n string) interface{} {
return getXAttr(fs, n)
c.attributes = NewTimedCache(func(n string) (interface{}, bool) {
a := getAttr(fs, n)
return a, a.Ok()
}, ttlNs)
c.dirs = NewTimedCache(func(n string) (interface{}, bool) {
d := readDir(fs, n)
return d, d.Ok()
}, ttlNs)
c.links = NewTimedCache(func(n string) (interface{}, bool) {
l := readLink(fs, n)
return l, l.Ok()
}, ttlNs)
c.xattr = NewTimedCache(func(n string) (interface{}, bool) {
l := getXAttr(fs, n)
return l, l.Ok()
}, ttlNs)
return c
}
......
......@@ -19,8 +19,9 @@ type cacheEntry struct {
// thread-safe. Calls of fetch() do no happen inside a critical
// section, so when multiple concurrent Get()s happen for the same
// key, multiple fetch() calls may be issued for the same key.
type TimedCacheFetcher func(name string) (value interface{}, cacheable bool)
type TimedCache struct {
fetch func(name string) interface{}
fetch TimedCacheFetcher
// ttlNs is a duration of the cache.
ttlNs int64
......@@ -35,7 +36,7 @@ const layerCacheTimeoutNs = 1e9
// Creates a new cache with the given TTL. If TTL <= 0, the caching is
// indefinite.
func NewTimedCache(fetcher func(name string) interface{}, ttlNs int64) *TimedCache {
func NewTimedCache(fetcher TimedCacheFetcher, ttlNs int64) *TimedCache {
l := new(TimedCache)
l.ttlNs = ttlNs
l.fetch = fetcher
......@@ -73,8 +74,10 @@ func (me *TimedCache) DropEntry(name string) {
}
func (me *TimedCache) GetFresh(name string) interface{} {
data := me.fetch(name)
data, ok := me.fetch(name)
if ok {
me.Set(name, data)
}
return data
}
......
......@@ -10,12 +10,33 @@ import (
var _ = fmt.Print
var _ = log.Print
func TestTimedCacheUncacheable(t *testing.T) {
fetchCount := 0
fetch := func(n string) (interface{}, bool) {
fetchCount++
i := int(n[0])
return &i, false
}
cache := NewTimedCache(fetch, 0)
v := cache.Get("n").(*int)
w := cache.Get("n").(*int)
if *v != int('n') || *w != *v {
t.Errorf("value mismatch: got %d, %d want %d", *v, *w, int('n'))
}
if fetchCount != 2 {
t.Fatalf("Should have fetched twice: %d", fetchCount)
}
}
func TestTimedCache(t *testing.T) {
fetchCount := 0
fetch := func(n string) interface{} {
fetch := func(n string) (interface{}, bool) {
fetchCount++
i := int(n[0])
return &i
return &i, true
}
var ttl int64
......
......@@ -97,7 +97,7 @@ func NewUnionFs(fileSystems []fuse.FileSystem, options UnionFsOptions) *UnionFs
g.deletionCache = NewDirCache(writable, options.DeletionDirName, int64(options.DeletionCacheTTLSecs*1e9))
g.branchCache = NewTimedCache(
func(n string) interface{} { return g.getBranchAttrNoCache(n) },
func(n string) (interface{}, bool) { return g.getBranchAttrNoCache(n), true },
int64(options.BranchCacheTTLSecs*1e9))
g.branchCache.RecurringPurge()
return g
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment