@@ -0,0 +1,70 @@
|
||||
package filesystem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/valkey-io/valkey-go"
|
||||
)
|
||||
|
||||
const keyStat = "webdav:stat:"
|
||||
|
||||
// CachedClient wraps a FileSystem implementation with Valkey caching.
|
||||
type CachedClient struct {
|
||||
impl FS
|
||||
cache valkey.Client
|
||||
ttl time.Duration
|
||||
hits atomic.Int64
|
||||
misses atomic.Int64
|
||||
readDirHits atomic.Int64
|
||||
readHits atomic.Int64
|
||||
}
|
||||
|
||||
// NewCachedClient creates a new CachedClient.
|
||||
func NewCachedClient(impl FS, client valkey.Client, refreshtime time.Duration) *CachedClient {
|
||||
c := &CachedClient{
|
||||
impl: impl,
|
||||
cache: client,
|
||||
ttl: refreshtime * 5,
|
||||
}
|
||||
|
||||
go func() {
|
||||
t := time.NewTicker(refreshtime)
|
||||
for {
|
||||
<-t.C
|
||||
c.revalidate(context.Background())
|
||||
}
|
||||
}()
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *CachedClient) revalidate(ctx context.Context) {
|
||||
go c.revalidateReadDir(ctx)
|
||||
go c.revalidateRead(ctx)
|
||||
go c.revalidateStat(ctx)
|
||||
}
|
||||
|
||||
func (c *CachedClient) scanAndProcess(ctx context.Context, match string, process func(key string) error) {
|
||||
cursor := uint64(0)
|
||||
for {
|
||||
res, err := c.cache.Do(ctx, c.cache.B().Scan().Cursor(cursor).Match(match).Build()).AsScanEntry()
|
||||
if err != nil {
|
||||
slog.Error("scan failed", "match", match, "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, key := range res.Elements {
|
||||
if err := process(key); err != nil {
|
||||
slog.Debug("process failed", "key", key, "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
cursor = res.Cursor
|
||||
if cursor == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user