mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-02-26 15:39:18 -06:00
124
settings/pkg/store/metadata/cache.go
Normal file
124
settings/pkg/store/metadata/cache.go
Normal file
@@ -0,0 +1,124 @@
|
||||
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
|
||||
err = c.dirs.Remove(path.Dir(id))
|
||||
err = 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 {
|
||||
err := c.next.Delete(ctx, id)
|
||||
if 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
|
||||
}
|
||||
@@ -58,8 +58,13 @@ func (s *Store) Init() {
|
||||
s.l.Lock()
|
||||
defer s.l.Unlock()
|
||||
|
||||
if s.mdc != nil {
|
||||
return
|
||||
}
|
||||
|
||||
//s.init.Do(func() {
|
||||
if err := s.initMetadataClient(NewMetadataClient(s.cfg.Metadata)); err != nil {
|
||||
mdc := &CachedMDC{next: NewMetadataClient(s.cfg.Metadata)}
|
||||
if err := s.initMetadataClient(mdc); err != nil {
|
||||
s.Logger.Error().Err(err).Msg("error initializing metadata client")
|
||||
}
|
||||
//})
|
||||
|
||||
Reference in New Issue
Block a user