add caching

Signed-off-by: jkoberg <jkoberg@owncloud.com>
This commit is contained in:
jkoberg
2022-03-05 12:57:57 +01:00
parent fc5a67c45e
commit 1d98e4827e
2 changed files with 130 additions and 1 deletions

View 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
}

View File

@@ -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")
}
//})