Initial QSfera import
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
|
||||
olog "github.com/qsfera/server/pkg/log"
|
||||
"github.com/qsfera/server/services/settings/pkg/config"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/store"
|
||||
"github.com/vmihailenco/msgpack/v5"
|
||||
microstore "go-micro.dev/v4/store"
|
||||
)
|
||||
|
||||
// CachedMDC is cache for the metadataclient
|
||||
type CachedMDC struct {
|
||||
cfg *config.Config
|
||||
logger olog.Logger
|
||||
next MetadataClient
|
||||
|
||||
filesCache microstore.Store
|
||||
dirsCache microstore.Store
|
||||
}
|
||||
|
||||
// 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.filesCache.Read(id); err == nil && len(b) == 1 {
|
||||
return b[0].Value, nil
|
||||
}
|
||||
b, err := c.next.SimpleDownload(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = c.filesCache.Write(µstore.Record{
|
||||
Key: id,
|
||||
Value: b,
|
||||
Expiry: c.cfg.Metadata.Cache.TTL,
|
||||
})
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Msg("SimpleDownload: failed to update to files cache")
|
||||
}
|
||||
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.filesCache.Read(id)
|
||||
if err == nil && len(b) == 1 && string(b[0].Value) == string(content) {
|
||||
// no need to bug mdc
|
||||
return nil
|
||||
}
|
||||
|
||||
err = c.next.SimpleUpload(ctx, id, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// invalidate caches
|
||||
if err = c.dirsCache.Delete(path.Dir(id)); err != nil {
|
||||
c.logger.Error().Err(err).Msg("failed to clear dirs cache")
|
||||
}
|
||||
|
||||
err = c.filesCache.Write(µstore.Record{
|
||||
Key: id,
|
||||
Value: content,
|
||||
Expiry: c.cfg.Metadata.Cache.TTL,
|
||||
})
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Msg("SimpleUpload: failed to update to files cache")
|
||||
}
|
||||
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
|
||||
_ = c.removePrefix(c.filesCache, id)
|
||||
_ = c.removePrefix(c.dirsCache, 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.dirsCache.Read(id)
|
||||
if err == nil && len(i) == 1 {
|
||||
var ret []string
|
||||
if err = msgpack.Unmarshal(i[0].Value, &ret); err == nil {
|
||||
return ret, nil
|
||||
}
|
||||
c.logger.Error().Err(err).Msg("failed to unmarshal entry from dirs cache")
|
||||
}
|
||||
|
||||
s, err := c.next.ReadDir(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var value []byte
|
||||
if value, err = msgpack.Marshal(s); err != nil {
|
||||
c.logger.Error().Err(err).Msg("failed to marshal ReadDir result for dirs cache")
|
||||
return s, err
|
||||
}
|
||||
err = c.dirsCache.Write(µstore.Record{
|
||||
Key: id,
|
||||
Value: value,
|
||||
Expiry: c.cfg.Metadata.Cache.TTL,
|
||||
})
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Msg("ReadDir: failed to update dirs cache")
|
||||
}
|
||||
|
||||
return s, err
|
||||
}
|
||||
|
||||
// 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
|
||||
if err = c.dirsCache.Delete(path.Dir(id)); err != nil {
|
||||
c.logger.Error().Err(err).Msg("failed to clear dirs cache")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Init instantiates the caches
|
||||
func (c *CachedMDC) Init(ctx context.Context, id string) error {
|
||||
c.dirsCache = store.Create(
|
||||
store.Store(c.cfg.Metadata.Cache.Store),
|
||||
store.TTL(c.cfg.Metadata.Cache.TTL),
|
||||
microstore.Nodes(c.cfg.Metadata.Cache.Nodes...),
|
||||
microstore.Database(c.cfg.Metadata.Cache.Database),
|
||||
microstore.Table(c.cfg.Metadata.Cache.DirectoryTable),
|
||||
store.DisablePersistence(c.cfg.Metadata.Cache.DisablePersistence),
|
||||
store.Authentication(c.cfg.Metadata.Cache.AuthUsername, c.cfg.Metadata.Cache.AuthPassword),
|
||||
)
|
||||
c.filesCache = store.Create(
|
||||
store.Store(c.cfg.Metadata.Cache.Store),
|
||||
store.TTL(c.cfg.Metadata.Cache.TTL),
|
||||
microstore.Nodes(c.cfg.Metadata.Cache.Nodes...),
|
||||
microstore.Database(c.cfg.Metadata.Cache.Database),
|
||||
microstore.Table(c.cfg.Metadata.Cache.FileTable),
|
||||
store.DisablePersistence(c.cfg.Metadata.Cache.DisablePersistence),
|
||||
store.Authentication(c.cfg.Metadata.Cache.AuthUsername, c.cfg.Metadata.Cache.AuthPassword),
|
||||
)
|
||||
return c.next.Init(ctx, id)
|
||||
}
|
||||
|
||||
func (c *CachedMDC) removePrefix(cache microstore.Store, prefix string) error {
|
||||
c.logger.Debug().Str("prefix", prefix).Msg("removePrefix")
|
||||
keys, err := cache.List(microstore.ListPrefix(prefix))
|
||||
if err != nil {
|
||||
c.logger.Error().Err(err).Msg("failed to list cache entries")
|
||||
}
|
||||
for _, k := range keys {
|
||||
c.logger.Debug().Str("key", k).Msg("removePrefix")
|
||||
if err := cache.Delete(k); err != nil {
|
||||
c.logger.Error().Err(err).Msg("failed to remove prefix from cache")
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user