feat: cache revalidation
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
package filesystem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (c *CachedClient) Stat(path string) (info os.FileInfo, err error) {
|
||||
key := keyStat + path
|
||||
ctx := context.Background()
|
||||
|
||||
// Try cache
|
||||
val, err := c.client.Do(ctx, c.client.B().Get().Key(key).Build()).ToString()
|
||||
if err == nil && val != "" {
|
||||
var f File
|
||||
if err := json.Unmarshal([]byte(val), &f); err == nil {
|
||||
c.hits.Add(1)
|
||||
slog.Debug("cache hit", "key", key)
|
||||
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Cache miss
|
||||
c.misses.Add(1)
|
||||
slog.Debug("cache miss", "key", key)
|
||||
fileInfo, err := c.impl.Stat(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Serialize and cache
|
||||
// Type assert to ensure we capture ContentType and Path
|
||||
info = ParseToFile(fileInfo)
|
||||
|
||||
bytes, err := json.Marshal(info)
|
||||
if err == nil {
|
||||
c.client.Do(ctx, c.client.B().Set().Key(key).Value(string(bytes)).Ex(c.ttl).Build())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *CachedClient) revalidateStat(ctx context.Context) {
|
||||
startTime := time.Now()
|
||||
c.scanAndProcess(ctx, keyStat+"*", func(key string) error {
|
||||
path := strings.TrimPrefix(key, keyStat)
|
||||
info, err := c.impl.Stat(path)
|
||||
if err != nil {
|
||||
c.client.Do(ctx, c.client.B().Del().Key(key).Build())
|
||||
return err
|
||||
}
|
||||
|
||||
// Serialize and cache
|
||||
f := ParseToFile(info)
|
||||
bytes, err := json.Marshal(f)
|
||||
if err == nil {
|
||||
c.client.Do(ctx, c.client.B().Set().Key(key).Value(string(bytes)).Ex(c.ttl).Build())
|
||||
}
|
||||
return nil
|
||||
})
|
||||
slog.Debug("revalidation of Stat complete", "duration", time.Since(startTime))
|
||||
}
|
||||
Reference in New Issue
Block a user