mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-27 03:55:36 +00:00
50fb8b9123
Instead of modeling remote WebDAV servers as actual webdav.FS instances, we now just proxy traffic to them. This not only simplifies the code, but it also allows WebDAV locking to work correctly by making sure locks are handled by the servers that need to (i.e. the ones actually serving the files). Updates tailscale/corp#16827 Signed-off-by: Percy Wegmann <percy@tailscale.com>
93 lines
1.9 KiB
Go
93 lines
1.9 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package compositedav
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/jellydator/ttlcache/v3"
|
|
)
|
|
|
|
// StatCache provides a cache for directory listings 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.
|
|
// This is similar to the DirectoryCacheLifetime setting of Windows' built-in
|
|
// SMB client, see
|
|
// https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-7/ff686200(v=ws.10)
|
|
type StatCache struct {
|
|
TTL time.Duration
|
|
|
|
// mu guards the below values.
|
|
mu sync.Mutex
|
|
cachesByDepthAndPath map[int]*ttlcache.Cache[string, []byte]
|
|
}
|
|
|
|
func (c *StatCache) get(name string, depth int) []byte {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
if c.cachesByDepthAndPath == nil {
|
|
return nil
|
|
}
|
|
cache := c.cachesByDepthAndPath[depth]
|
|
if cache == nil {
|
|
return nil
|
|
}
|
|
item := cache.Get(name)
|
|
if item == nil {
|
|
return nil
|
|
}
|
|
return item.Value()
|
|
}
|
|
|
|
func (c *StatCache) set(name string, depth int, value []byte) {
|
|
if c == nil {
|
|
return
|
|
}
|
|
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
if c.cachesByDepthAndPath == nil {
|
|
c.cachesByDepthAndPath = make(map[int]*ttlcache.Cache[string, []byte])
|
|
}
|
|
cache := c.cachesByDepthAndPath[depth]
|
|
if cache == nil {
|
|
cache = ttlcache.New(
|
|
ttlcache.WithTTL[string, []byte](c.TTL),
|
|
)
|
|
go cache.Start()
|
|
c.cachesByDepthAndPath[depth] = cache
|
|
}
|
|
cache.Set(name, value, ttlcache.DefaultTTL)
|
|
}
|
|
|
|
func (c *StatCache) invalidate() {
|
|
if c == nil {
|
|
return
|
|
}
|
|
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
for _, cache := range c.cachesByDepthAndPath {
|
|
cache.DeleteAll()
|
|
}
|
|
}
|
|
|
|
func (c *StatCache) stop() {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
for _, cache := range c.cachesByDepthAndPath {
|
|
cache.Stop()
|
|
}
|
|
}
|