github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/filecache/file_cache.go (about) 1 package filecache 2 3 import ( 4 "encoding/hex" 5 "errors" 6 "io" 7 "os" 8 "path" 9 "path/filepath" 10 ) 11 12 // New returns a new Cache implemented by fileCache. 13 func New(dir string) Cache { 14 return newFileCache(dir) 15 } 16 17 func newFileCache(dir string) *fileCache { 18 return &fileCache{dirPath: dir} 19 } 20 21 // fileCache persists compiled functions into dirPath. 22 // 23 // Note: this can be expanded to do binary signing/verification, set TTL on each entry, etc. 24 type fileCache struct { 25 dirPath string 26 } 27 28 func (fc *fileCache) path(key Key) string { 29 return path.Join(fc.dirPath, hex.EncodeToString(key[:])) 30 } 31 32 func (fc *fileCache) Get(key Key) (content io.ReadCloser, ok bool, err error) { 33 f, err := os.Open(fc.path(key)) 34 if errors.Is(err, os.ErrNotExist) { 35 return nil, false, nil 36 } else if err != nil { 37 return nil, false, err 38 } else { 39 return f, true, nil 40 } 41 } 42 43 func (fc *fileCache) Add(key Key, content io.Reader) (err error) { 44 path := fc.path(key) 45 dirPath, fileName := filepath.Split(path) 46 47 file, err := os.CreateTemp(dirPath, fileName+".*.tmp") 48 if err != nil { 49 return 50 } 51 defer func() { 52 file.Close() 53 if err != nil { 54 _ = os.Remove(file.Name()) 55 } 56 }() 57 if _, err = io.Copy(file, content); err != nil { 58 return 59 } 60 if err = file.Sync(); err != nil { 61 return 62 } 63 if err = file.Close(); err != nil { 64 return 65 } 66 err = os.Rename(file.Name(), path) 67 return 68 } 69 70 func (fc *fileCache) Delete(key Key) (err error) { 71 err = os.Remove(fc.path(key)) 72 if errors.Is(err, os.ErrNotExist) { 73 err = nil 74 } 75 return 76 }