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 { ...@@ -89,11 +89,21 @@ func readLink(fs fuse.FileSystem, name string) *linkResponse {
func NewCachingFileSystem(fs fuse.FileSystem, ttlNs int64) *CachingFileSystem { func NewCachingFileSystem(fs fuse.FileSystem, ttlNs int64) *CachingFileSystem {
c := new(CachingFileSystem) c := new(CachingFileSystem)
c.FileSystem = fs c.FileSystem = fs
c.attributes = NewTimedCache(func(n string) interface{} { return getAttr(fs, n) }, ttlNs) c.attributes = NewTimedCache(func(n string) (interface{}, bool) {
c.dirs = NewTimedCache(func(n string) interface{} { return readDir(fs, n) }, ttlNs) a := getAttr(fs, n)
c.links = NewTimedCache(func(n string) interface{} { return readLink(fs, n) }, ttlNs) return a, a.Ok()
c.xattr = NewTimedCache(func(n string) interface{} { }, ttlNs)
return getXAttr(fs, n) 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) }, ttlNs)
return c return c
} }
......
...@@ -19,8 +19,9 @@ type cacheEntry struct { ...@@ -19,8 +19,9 @@ type cacheEntry struct {
// thread-safe. Calls of fetch() do no happen inside a critical // thread-safe. Calls of fetch() do no happen inside a critical
// section, so when multiple concurrent Get()s happen for the same // section, so when multiple concurrent Get()s happen for the same
// key, multiple fetch() calls may be issued for the same key. // key, multiple fetch() calls may be issued for the same key.
type TimedCacheFetcher func(name string) (value interface{}, cacheable bool)
type TimedCache struct { type TimedCache struct {
fetch func(name string) interface{} fetch TimedCacheFetcher
// ttlNs is a duration of the cache. // ttlNs is a duration of the cache.
ttlNs int64 ttlNs int64
...@@ -35,7 +36,7 @@ const layerCacheTimeoutNs = 1e9 ...@@ -35,7 +36,7 @@ const layerCacheTimeoutNs = 1e9
// Creates a new cache with the given TTL. If TTL <= 0, the caching is // Creates a new cache with the given TTL. If TTL <= 0, the caching is
// indefinite. // indefinite.
func NewTimedCache(fetcher func(name string) interface{}, ttlNs int64) *TimedCache { func NewTimedCache(fetcher TimedCacheFetcher, ttlNs int64) *TimedCache {
l := new(TimedCache) l := new(TimedCache)
l.ttlNs = ttlNs l.ttlNs = ttlNs
l.fetch = fetcher l.fetch = fetcher
...@@ -73,8 +74,10 @@ func (me *TimedCache) DropEntry(name string) { ...@@ -73,8 +74,10 @@ func (me *TimedCache) DropEntry(name string) {
} }
func (me *TimedCache) GetFresh(name string) interface{} { func (me *TimedCache) GetFresh(name string) interface{} {
data := me.fetch(name) data, ok := me.fetch(name)
me.Set(name, data) if ok {
me.Set(name, data)
}
return data return data
} }
......
...@@ -10,12 +10,33 @@ import ( ...@@ -10,12 +10,33 @@ import (
var _ = fmt.Print var _ = fmt.Print
var _ = log.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) { func TestTimedCache(t *testing.T) {
fetchCount := 0 fetchCount := 0
fetch := func(n string) interface{} { fetch := func(n string) (interface{}, bool) {
fetchCount++ fetchCount++
i := int(n[0]) i := int(n[0])
return &i return &i, true
} }
var ttl int64 var ttl int64
......
...@@ -97,7 +97,7 @@ func NewUnionFs(fileSystems []fuse.FileSystem, options UnionFsOptions) *UnionFs ...@@ -97,7 +97,7 @@ func NewUnionFs(fileSystems []fuse.FileSystem, options UnionFsOptions) *UnionFs
g.deletionCache = NewDirCache(writable, options.DeletionDirName, int64(options.DeletionCacheTTLSecs*1e9)) g.deletionCache = NewDirCache(writable, options.DeletionDirName, int64(options.DeletionCacheTTLSecs*1e9))
g.branchCache = NewTimedCache( 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)) int64(options.BranchCacheTTLSecs*1e9))
g.branchCache.RecurringPurge() g.branchCache.RecurringPurge()
return g 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