From b7c7652ad2fa6908406fa5da21bc8577e8458103 Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys <hanwen@google.com> Date: Fri, 29 Apr 2011 11:17:30 -0300 Subject: [PATCH] Cleanup CachingFileSystem. --- unionfs/cachingfs.go | 134 ++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 78 deletions(-) diff --git a/unionfs/cachingfs.go b/unionfs/cachingfs.go index e2b4716..f685a17 100644 --- a/unionfs/cachingfs.go +++ b/unionfs/cachingfs.go @@ -2,118 +2,96 @@ package unionfs import ( "github.com/hanwen/go-fuse/fuse" - "sync" ) type attrResponse struct { - attr *fuse.Attr - code fuse.Status + *fuse.Attr + fuse.Status } type dirResponse struct { entries []fuse.DirEntry - code fuse.Status + fuse.Status } type linkResponse struct { linkContent string - code fuse.Status + fuse.Status } // Caches readdir and getattr() type CachingFileSystem struct { fuse.FileSystem - attributesLock sync.RWMutex - attributes map[string]attrResponse - - dirsLock sync.RWMutex - dirs map[string]dirResponse - - linksLock sync.RWMutex - links map[string]linkResponse + attributes *TimedCache + dirs *TimedCache + links *TimedCache } -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) { - me.attributesLock.RLock() - v, ok := me.attributes[name] - me.attributesLock.RUnlock() +func readDir(fs fuse.FileSystem, name string) *dirResponse { + origStream, code := fs.OpenDir(name) - if ok { - return v.attr, v.code + r := &dirResponse{nil, code} + if code != fuse.OK { + return r } - var r attrResponse - r.attr, r.code = me.FileSystem.GetAttr(name) - - // TODO - could do async. - me.attributesLock.Lock() - me.attributes[name] = r - me.attributesLock.Unlock() + for { + d, ok := <-origStream + if !ok { + break + } + r.entries = append(r.entries, d) + } - return r.attr, r.code + return r } -func (me *CachingFileSystem) Readlink(name string) (string, fuse.Status) { - me.linksLock.RLock() - v, ok := me.links[name] - me.linksLock.RUnlock() +func getAttr(fs fuse.FileSystem, name string) *attrResponse { + a, code := fs.GetAttr(name) + return &attrResponse{ + Attr: a, + Status: code, + } +} - if ok { - return v.linkContent, v.code +func readLink(fs fuse.FileSystem, name string) *linkResponse { + 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. - me.linksLock.Lock() - me.links[name] = v - me.linksLock.Unlock() +func (me *CachingFileSystem) GetAttr(name string) (*fuse.Attr, fuse.Status) { + r := me.attributes.Get(name).(attrResponse) + return r.Attr, r.Status +} - 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) { - me.dirsLock.RLock() - v, ok := me.dirs[name] - me.dirsLock.RUnlock() - - 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 { + r := me.dirs.Get(name).(dirResponse) + if r.Status == fuse.OK { + stream = make(chan fuse.DirEntry, len(r.entries)) + for _, d := range r.entries { stream <- d } - stream <- fuse.DirEntry{} - }() + close(stream) + return stream, r.Status + } - return stream, v.code + return nil, r.Status } -- 2.30.9