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

Cleanup CachingFileSystem.

parent 49362c2e
...@@ -2,118 +2,96 @@ package unionfs ...@@ -2,118 +2,96 @@ package unionfs
import ( import (
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
"sync"
) )
type attrResponse struct { type attrResponse struct {
attr *fuse.Attr *fuse.Attr
code fuse.Status fuse.Status
} }
type dirResponse struct { type dirResponse struct {
entries []fuse.DirEntry entries []fuse.DirEntry
code fuse.Status fuse.Status
} }
type linkResponse struct { type linkResponse struct {
linkContent string linkContent string
code fuse.Status fuse.Status
} }
// Caches readdir and getattr() // Caches readdir and getattr()
type CachingFileSystem struct { type CachingFileSystem struct {
fuse.FileSystem fuse.FileSystem
attributesLock sync.RWMutex attributes *TimedCache
attributes map[string]attrResponse dirs *TimedCache
links *TimedCache
dirsLock sync.RWMutex
dirs map[string]dirResponse
linksLock sync.RWMutex
links map[string]linkResponse
}
func NewCachingFileSystem(pfs fuse.FileSystem) *CachingFileSystem {
c := new(CachingFileSystem)
c.FileSystem = pfs
c.attributes = make(map[string]attrResponse)
c.dirs = make(map[string]dirResponse)
c.links = make(map[string]linkResponse)
return c
} }
func (me *CachingFileSystem) GetAttr(name string) (*fuse.Attr, fuse.Status) { func readDir(fs fuse.FileSystem, name string) *dirResponse {
me.attributesLock.RLock() origStream, code := fs.OpenDir(name)
v, ok := me.attributes[name]
me.attributesLock.RUnlock()
if ok { r := &dirResponse{nil, code}
return v.attr, v.code if code != fuse.OK {
return r
} }
var r attrResponse for {
r.attr, r.code = me.FileSystem.GetAttr(name) d, ok := <-origStream
if !ok {
// TODO - could do async. break
me.attributesLock.Lock() }
me.attributes[name] = r r.entries = append(r.entries, d)
me.attributesLock.Unlock() }
return r.attr, r.code return r
} }
func (me *CachingFileSystem) Readlink(name string) (string, fuse.Status) { func getAttr(fs fuse.FileSystem, name string) *attrResponse {
me.linksLock.RLock() a, code := fs.GetAttr(name)
v, ok := me.links[name] return &attrResponse{
me.linksLock.RUnlock() Attr: a,
Status: code,
}
}
if ok { func readLink(fs fuse.FileSystem, name string) *linkResponse {
return v.linkContent, v.code a, code := fs.Readlink(name)
return &linkResponse{
linkContent: a,
Status: code,
} }
}
v.linkContent, v.code = me.FileSystem.Readlink(name) 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)
return c
}
// TODO - could do async. func (me *CachingFileSystem) GetAttr(name string) (*fuse.Attr, fuse.Status) {
me.linksLock.Lock() r := me.attributes.Get(name).(attrResponse)
me.links[name] = v return r.Attr, r.Status
me.linksLock.Unlock() }
return v.linkContent, v.code func (me *CachingFileSystem) Readlink(name string) (string, fuse.Status) {
r := me.attributes.Get(name).(linkResponse)
return r.linkContent, r.Status
} }
func (me *CachingFileSystem) OpenDir(name string) (stream chan fuse.DirEntry, status fuse.Status) { func (me *CachingFileSystem) OpenDir(name string) (stream chan fuse.DirEntry, status fuse.Status) {
me.dirsLock.RLock() r := me.dirs.Get(name).(dirResponse)
v, ok := me.dirs[name] if r.Status == fuse.OK {
me.dirsLock.RUnlock() stream = make(chan fuse.DirEntry, len(r.entries))
for _, d := range r.entries {
if !ok {
origStream, code := me.FileSystem.OpenDir(name)
if code != fuse.OK {
return nil, code
}
v.code = code
for {
d := <-origStream
if d.Name == "" {
break
}
v.entries = append(v.entries, d)
}
me.dirsLock.Lock()
me.dirs[name] = v
me.dirsLock.Unlock()
}
stream = make(chan fuse.DirEntry)
go func() {
for _, d := range v.entries {
stream <- d stream <- d
} }
stream <- fuse.DirEntry{} close(stream)
}() return stream, r.Status
}
return stream, v.code return nil, r.Status
} }
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