// Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause package webdavfs import ( "io/fs" "path/filepath" "sync" "time" "github.com/jellydator/ttlcache/v3" ) // statCache provides a cache for file directory and file metadata. Especially // when used from the command-line, mapped WebDAV drives can generate // repetitive requests for the same file metadata. This cache helps reduce the // number of round-trips to the WebDAV server for such requests. type statCache struct { // mu guards the below values. mu sync.Mutex cache *ttlcache.Cache[string, fs.FileInfo] } func newStatCache(ttl time.Duration) *statCache { cache := ttlcache.New( ttlcache.WithTTL[string, fs.FileInfo](ttl), ) go cache.Start() return &statCache{cache: cache} } func (c *statCache) getOrFetch(name string, fetch func(string) (fs.FileInfo, error)) (fs.FileInfo, error) { c.mu.Lock() item := c.cache.Get(name) c.mu.Unlock() if item != nil { return item.Value(), nil } fi, err := fetch(name) if err == nil { c.mu.Lock() c.cache.Set(name, fi, ttlcache.DefaultTTL) c.mu.Unlock() } return fi, err } func (c *statCache) set(parentPath string, infos []fs.FileInfo) { c.mu.Lock() defer c.mu.Unlock() for _, info := range infos { path := filepath.Join(parentPath, filepath.Base(info.Name())) c.cache.Set(path, info, ttlcache.DefaultTTL) } } func (c *statCache) invalidate() { c.mu.Lock() defer c.mu.Unlock() c.cache.DeleteAll() } func (c *statCache) stop() { c.cache.Stop() }