mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-30 17:48:52 -05:00
171 lines
4.8 KiB
Go
171 lines
4.8 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"path"
|
|
|
|
olog "github.com/opencloud-eu/opencloud/pkg/log"
|
|
"github.com/opencloud-eu/opencloud/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
|
|
}
|