mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-24 13:58:12 -05:00
124 lines
2.8 KiB
Go
124 lines
2.8 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"path"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/ReneKroon/ttlcache/v2"
|
|
)
|
|
|
|
var (
|
|
cachettl = 0
|
|
// these need to be global instances for now as the `Service` (and therefore the `Store`) are instantiated twice (for grpc and http)
|
|
// therefore caches need to cover both instances
|
|
dircache = initCache(cachettl)
|
|
filescache = initCache(cachettl)
|
|
)
|
|
|
|
// CachedMDC is cache for the metadataclient
|
|
type CachedMDC struct {
|
|
next MetadataClient
|
|
|
|
files *ttlcache.Cache
|
|
dirs *ttlcache.Cache
|
|
}
|
|
|
|
// SimpleDownload caches the answer from SimpleDownload or returns the cached one
|
|
func (c *CachedMDC) SimpleDownload(ctx context.Context, id string) ([]byte, error) {
|
|
if b, err := c.files.Get(id); err == nil {
|
|
return b.([]byte), nil
|
|
}
|
|
b, err := c.next.SimpleDownload(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_ = c.files.Set(id, b)
|
|
return b, nil
|
|
}
|
|
|
|
// SimpleUpload caches the answer from SimpleUpload and invalidates the cache
|
|
func (c *CachedMDC) SimpleUpload(ctx context.Context, id string, content []byte) error {
|
|
b, err := c.files.Get(id)
|
|
if err == nil && string(b.([]byte)) == string(content) {
|
|
// no need to bug mdc
|
|
return nil
|
|
}
|
|
|
|
err = c.next.SimpleUpload(ctx, id, content)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// invalidate caches
|
|
_ = c.dirs.Remove(path.Dir(id))
|
|
_ = c.files.Set(id, content)
|
|
return nil
|
|
}
|
|
|
|
// Delete invalidates the cache when operation was successful
|
|
func (c *CachedMDC) Delete(ctx context.Context, id string) error {
|
|
if err := c.next.Delete(ctx, id); err != nil {
|
|
return err
|
|
}
|
|
|
|
// invalidate caches
|
|
_ = removePrefix(c.files, id)
|
|
_ = removePrefix(c.dirs, id)
|
|
return nil
|
|
}
|
|
|
|
// ReadDir caches the response from ReadDir or returnes the cached one
|
|
func (c *CachedMDC) ReadDir(ctx context.Context, id string) ([]string, error) {
|
|
i, err := c.dirs.Get(id)
|
|
if err == nil {
|
|
return i.([]string), nil
|
|
}
|
|
|
|
s, err := c.next.ReadDir(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return s, c.dirs.Set(id, s)
|
|
}
|
|
|
|
// MakeDirIfNotExist invalidates the cache
|
|
func (c *CachedMDC) MakeDirIfNotExist(ctx context.Context, id string) error {
|
|
err := c.next.MakeDirIfNotExist(ctx, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// invalidate caches
|
|
_ = c.dirs.Remove(path.Dir(id))
|
|
return nil
|
|
}
|
|
|
|
// Init instantiates the caches
|
|
func (c *CachedMDC) Init(ctx context.Context, id string) error {
|
|
c.dirs = dircache
|
|
c.files = filescache
|
|
return c.next.Init(ctx, id)
|
|
}
|
|
|
|
func initCache(ttlSeconds int) *ttlcache.Cache {
|
|
cache := ttlcache.NewCache()
|
|
_ = cache.SetTTL(time.Duration(ttlSeconds) * time.Second)
|
|
cache.SkipTTLExtensionOnHit(true)
|
|
return cache
|
|
}
|
|
|
|
func removePrefix(cache *ttlcache.Cache, prefix string) error {
|
|
for _, k := range cache.GetKeys() {
|
|
if strings.HasPrefix(k, prefix) {
|
|
if err := cache.Remove(k); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|