github.com/bazelbuild/remote-apis-sdks@v0.0.0-20240425170053-8a36686a6350/go/pkg/filemetadata/cache.go (about) 1 package filemetadata 2 3 import ( 4 "path/filepath" 5 "sync/atomic" 6 7 "github.com/bazelbuild/remote-apis-sdks/go/pkg/cache" 8 ) 9 10 var globalCache cache.SingleFlight 11 12 // ResetGlobalCache clears the cache globally. 13 // Applies to all Cache instances created by NewSingleFlightCache. 14 func ResetGlobalCache() { 15 globalCache.Reset() 16 } 17 18 // Cache is a store for file digests that supports invalidation. 19 type fmCache struct { 20 Backend *cache.SingleFlight 21 cacheHits uint64 22 cacheMisses uint64 23 } 24 25 // NewSingleFlightCache returns a singleton-backed in-memory cache, with no validation. 26 func NewSingleFlightCache() Cache { 27 return &fmCache{Backend: &globalCache} 28 } 29 30 // Get retrieves the metadata of the file with the given filename, whether from cache or by 31 // computing the digest. 32 func (c *fmCache) Get(filename string) *Metadata { 33 abs, err := filepath.Abs(filename) 34 if err != nil { 35 return &Metadata{Err: err} 36 } 37 md, ch, err := c.loadMetadata(abs) 38 if err != nil { 39 return &Metadata{Err: err} 40 } 41 c.updateMetrics(ch) 42 return md 43 } 44 45 // Delete deletes an entry from cache. 46 func (c *fmCache) Delete(filename string) error { 47 abs, err := filepath.Abs(filename) 48 if err != nil { 49 return err 50 } 51 c.Backend.Delete(abs) 52 return nil 53 } 54 55 // Update updates the cache entry for the filename with the given value. 56 func (c *fmCache) Update(filename string, cacheEntry *Metadata) error { 57 abs, err := filepath.Abs(filename) 58 if err != nil { 59 return err 60 } 61 c.Backend.Store(abs, cacheEntry) 62 return nil 63 } 64 65 // GetCacheHits returns the number of cache hits. 66 func (c *fmCache) GetCacheHits() uint64 { 67 return atomic.LoadUint64(&c.cacheHits) 68 } 69 70 // GetCacheMisses returns the number of cache misses. 71 func (c *fmCache) GetCacheMisses() uint64 { 72 return atomic.LoadUint64(&c.cacheMisses) 73 } 74 75 func (c *fmCache) loadMetadata(filename string) (*Metadata, bool, error) { 76 cacheHit := true 77 val, err := c.Backend.LoadOrStore(filename, func() (interface{}, error) { 78 cacheHit = false 79 return Compute(filename), nil 80 }) 81 if err != nil { 82 return nil, false, err 83 } 84 return val.(*Metadata), cacheHit, nil 85 } 86 87 func (c *fmCache) updateMetrics(cacheHit bool) { 88 if cacheHit { 89 atomic.AddUint64(&c.cacheHits, 1) 90 } else { 91 atomic.AddUint64(&c.cacheMisses, 1) 92 } 93 }