[#713] Fix cache access

User can access only keys that he puts into caches

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
support/v0.25
Denis Kirillov 2022-10-03 17:33:49 +03:00 committed by Alex Vanin
parent c6098e53f6
commit 3d31c2ab4a
14 changed files with 365 additions and 196 deletions

69
api/cache/access_control.go vendored 100644
View File

@ -0,0 +1,69 @@
package cache
import (
"fmt"
"time"
"github.com/bluele/gcache"
"github.com/nspcc-dev/neofs-sdk-go/user"
"go.uber.org/zap"
)
// AccessControlCache provides lru cache for objects.
type AccessControlCache struct {
cache gcache.Cache
logger *zap.Logger
}
const (
// DefaultAccessControlCacheLifetime is a default lifetime of entries in access' cache.
DefaultAccessControlCacheLifetime = 1 * time.Minute
// DefaultAccessControlCacheSize is a default maximum number of entries in access' cache.
DefaultAccessControlCacheSize = 1e5
)
// DefaultAccessControlConfig returns new default cache expiration values.
func DefaultAccessControlConfig(logger *zap.Logger) *Config {
return &Config{
Size: DefaultAccessControlCacheSize,
Lifetime: DefaultAccessControlCacheLifetime,
Logger: logger,
}
}
// NewAccessControlCache creates an object of AccessControlCache.
func NewAccessControlCache(config *Config) *AccessControlCache {
gc := gcache.New(config.Size).LRU().Expiration(config.Lifetime).Build()
return &AccessControlCache{cache: gc, logger: config.Logger}
}
// Get returns true if such key exists.
func (o *AccessControlCache) Get(owner user.ID, key string) bool {
entry, err := o.cache.Get(cacheKey(owner, key))
if err != nil {
return false
}
result, ok := entry.(bool)
if !ok {
o.logger.Warn("invalid cache entry type", zap.String("actual", fmt.Sprintf("%T", entry)),
zap.String("expected", fmt.Sprintf("%T", result)))
return false
}
return result
}
// Put puts an item to cache.
func (o *AccessControlCache) Put(owner user.ID, key string) error {
return o.cache.Set(cacheKey(owner, key), true)
}
// Delete deletes an object from cache.
func (o *AccessControlCache) Delete(owner user.ID, key string) bool {
return o.cache.Remove(cacheKey(owner, key))
}
func cacheKey(owner user.ID, key string) string {
return owner.EncodeToString() + key
}

View File

@ -2,6 +2,7 @@ package cache
import (
"fmt"
"strconv"
"strings"
"time"
@ -56,6 +57,10 @@ func DefaultObjectsListConfig(logger *zap.Logger) *Config {
}
}
func (k *ObjectsListKey) String() string {
return k.cid.EncodeToString() + k.prefix + strconv.FormatBool(k.latestOnly)
}
// NewObjectsListCache is a constructor which creates an object of ListObjectsCache with the given lifetime of entries.
func NewObjectsListCache(config *Config) *ObjectsListCache {
gc := gcache.New(config.Size).LRU().Expiration(config.Lifetime).Build()

205
api/layer/cache.go 100644
View File

@ -0,0 +1,205 @@
package layer
import (
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
"github.com/nspcc-dev/neofs-s3-gw/api/data"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/user"
"go.uber.org/zap"
)
type Cache struct {
logger *zap.Logger
listsCache *cache.ObjectsListCache
objCache *cache.ObjectsCache
namesCache *cache.ObjectsNameCache
bucketCache *cache.BucketCache
systemCache *cache.SystemCache
accessCache *cache.AccessControlCache
}
// CachesConfig contains params for caches.
type CachesConfig struct {
Logger *zap.Logger
Objects *cache.Config
ObjectsList *cache.Config
Names *cache.Config
Buckets *cache.Config
System *cache.Config
AccessControl *cache.Config
}
// DefaultCachesConfigs returns filled configs.
func DefaultCachesConfigs(logger *zap.Logger) *CachesConfig {
return &CachesConfig{
Logger: logger,
Objects: cache.DefaultObjectsConfig(logger),
ObjectsList: cache.DefaultObjectsListConfig(logger),
Names: cache.DefaultObjectsNameConfig(logger),
Buckets: cache.DefaultBucketConfig(logger),
System: cache.DefaultSystemConfig(logger),
AccessControl: cache.DefaultAccessControlConfig(logger),
}
}
func NewCache(cfg *CachesConfig) *Cache {
return &Cache{
logger: cfg.Logger,
listsCache: cache.NewObjectsListCache(cfg.ObjectsList),
objCache: cache.New(cfg.Objects),
namesCache: cache.NewObjectsNameCache(cfg.Names),
bucketCache: cache.NewBucketCache(cfg.Buckets),
systemCache: cache.NewSystemCache(cfg.System),
accessCache: cache.NewAccessControlCache(cfg.AccessControl),
}
}
func (c *Cache) GetBucket(name string) *data.BucketInfo {
return c.bucketCache.Get(name)
}
func (c *Cache) PutBucket(bktInfo *data.BucketInfo) {
if err := c.bucketCache.Put(bktInfo); err != nil {
c.logger.Warn("couldn't put bucket info into cache",
zap.String("bucket name", bktInfo.Name),
zap.Stringer("bucket cid", bktInfo.CID),
zap.Error(err))
}
}
func (c *Cache) DeleteBucket(name string) {
c.bucketCache.Delete(name)
}
func (c *Cache) CleanListCacheEntriesContainingObject(objectName string, cnrID cid.ID) {
c.listsCache.CleanCacheEntriesContainingObject(objectName, cnrID)
}
func (c *Cache) DeleteObjectName(cnrID cid.ID, bktName, objName string) {
c.namesCache.Delete(bktName + "/" + objName)
c.listsCache.CleanCacheEntriesContainingObject(objName, cnrID)
}
func (c *Cache) DeleteObject(addr oid.Address) {
c.objCache.Delete(addr)
}
func (c *Cache) GetObject(owner user.ID, addr oid.Address) *data.ExtendedObjectInfo {
if !c.accessCache.Get(owner, addr.String()) {
return nil
}
return c.objCache.GetObject(addr)
}
func (c *Cache) GetLastObject(owner user.ID, bktName, objName string) *data.ExtendedObjectInfo {
addr := c.namesCache.Get(bktName + "/" + objName)
if addr == nil {
return nil
}
return c.GetObject(owner, *addr)
}
func (c *Cache) PutObject(owner user.ID, extObjInfo *data.ExtendedObjectInfo) {
if err := c.objCache.PutObject(extObjInfo); err != nil {
c.logger.Warn("couldn't add object to cache", zap.Error(err),
zap.String("object_name", extObjInfo.ObjectInfo.Name), zap.String("bucket_name", extObjInfo.ObjectInfo.Bucket),
zap.String("cid", extObjInfo.ObjectInfo.CID.EncodeToString()), zap.String("oid", extObjInfo.ObjectInfo.ID.EncodeToString()))
}
if err := c.accessCache.Put(owner, extObjInfo.ObjectInfo.Address().EncodeToString()); err != nil {
c.logger.Warn("couldn't cache access control operation", zap.Error(err))
}
}
func (c *Cache) PutObjectWithName(owner user.ID, extObjInfo *data.ExtendedObjectInfo) {
c.PutObject(owner, extObjInfo)
if err := c.namesCache.Put(extObjInfo.ObjectInfo.NiceName(), extObjInfo.ObjectInfo.Address()); err != nil {
c.logger.Warn("couldn't put obj address to name cache",
zap.String("obj nice name", extObjInfo.ObjectInfo.NiceName()),
zap.Error(err))
}
}
func (c *Cache) GetList(owner user.ID, key cache.ObjectsListKey) []*data.NodeVersion {
if !c.accessCache.Get(owner, key.String()) {
return nil
}
return c.listsCache.GetVersions(key)
}
func (c *Cache) PutList(owner user.ID, key cache.ObjectsListKey, list []*data.NodeVersion) {
if err := c.listsCache.PutVersions(key, list); err != nil {
c.logger.Warn("couldn't cache list of objects", zap.Error(err))
}
if err := c.accessCache.Put(owner, key.String()); err != nil {
c.logger.Warn("couldn't cache access control operation", zap.Error(err))
}
}
func (c *Cache) GetTagging(key string) map[string]string {
return c.systemCache.GetTagging(key)
}
func (c *Cache) PutTagging(key string, tags map[string]string) {
if err := c.systemCache.PutTagging(key, tags); err != nil {
c.logger.Error("couldn't cache tags", zap.Error(err))
}
}
func (c *Cache) DeleteTagging(key string) {
c.systemCache.Delete(key)
}
func (c *Cache) GetLockInfo(key string) *data.LockInfo {
return c.systemCache.GetLockInfo(key)
}
func (c *Cache) PutLockInfo(key string, lockInfo *data.LockInfo) {
if err := c.systemCache.PutLockInfo(key, lockInfo); err != nil {
c.logger.Error("couldn't cache lock info", zap.Error(err))
}
}
func (c *Cache) GetSettings(bktInfo *data.BucketInfo) *data.BucketSettings {
key := bktInfo.Name + bktInfo.SettingsObjectName()
return c.systemCache.GetSettings(key)
}
func (c *Cache) PutSettings(bktInfo *data.BucketInfo, settings *data.BucketSettings) {
key := bktInfo.Name + bktInfo.SettingsObjectName()
if err := c.systemCache.PutSettings(key, settings); err != nil {
c.logger.Warn("couldn't cache bucket settings", zap.String("bucket", bktInfo.Name), zap.Error(err))
}
}
func (c *Cache) GetCORS(bkt *data.BucketInfo) *data.CORSConfiguration {
return c.systemCache.GetCORS(bkt.Name + bkt.CORSObjectName())
}
func (c *Cache) PutCORS(bkt *data.BucketInfo, settings *data.CORSConfiguration) {
if err := c.systemCache.PutCORS(bkt.Name+bkt.CORSObjectName(), settings); err != nil {
c.logger.Warn("couldn't cache cors", zap.String("bucket", bkt.Name), zap.Error(err))
}
}
func (c *Cache) DeleteCORS(bktInfo *data.BucketInfo) {
c.systemCache.Delete(bktInfo.Name + bktInfo.CORSObjectName())
}
func (c *Cache) GetNotificationConfiguration(bktInfo *data.BucketInfo) *data.NotificationConfiguration {
key := bktInfo.Name + bktInfo.NotificationConfigurationObjectName()
return c.systemCache.GetNotificationConfiguration(key)
}
func (c *Cache) PutNotificationConfiguration(bktInfo *data.BucketInfo, configuration *data.NotificationConfiguration) {
key := bktInfo.Name + bktInfo.NotificationConfigurationObjectName()
if err := c.systemCache.PutNotificationConfiguration(key, configuration); err != nil {
c.logger.Warn("couldn't cache notification configuration", zap.String("bucket", bktInfo.Name), zap.Error(err))
}
}

View File

@ -6,7 +6,6 @@ import (
"github.com/nspcc-dev/neofs-s3-gw/api/data"
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
"go.uber.org/zap"
)
func (n *layer) GetObjectTaggingAndLock(ctx context.Context, objVersion *ObjectVersion, nodeVersion *data.NodeVersion) (map[string]string, *data.LockInfo, error) {
@ -15,8 +14,8 @@ func (n *layer) GetObjectTaggingAndLock(ctx context.Context, objVersion *ObjectV
tags map[string]string
)
tags = n.systemCache.GetTagging(objectTaggingCacheKey(objVersion))
lockInfo := n.systemCache.GetLockInfo(lockObjectKey(objVersion))
tags = n.cache.GetTagging(objectTaggingCacheKey(objVersion))
lockInfo := n.cache.GetLockInfo(lockObjectKey(objVersion))
if tags != nil && lockInfo != nil {
return tags, lockInfo, nil
@ -37,13 +36,8 @@ func (n *layer) GetObjectTaggingAndLock(ctx context.Context, objVersion *ObjectV
return nil, nil, err
}
if err = n.systemCache.PutTagging(objectTaggingCacheKey(objVersion), tags); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
if err = n.systemCache.PutLockInfo(lockObjectKey(objVersion), lockInfo); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
n.cache.PutTagging(objectTaggingCacheKey(objVersion), tags)
n.cache.PutLockInfo(lockObjectKey(objVersion), lockInfo)
return tags, lockInfo, nil
}

View File

@ -70,10 +70,7 @@ func (n *layer) containerInfo(ctx context.Context, idCnr cid.ID) (*data.BucketIn
}
}
if err = n.bucketCache.Put(info); err != nil {
log.Warn("could not put bucket info into cache",
zap.String("bucket_name", info.Name), zap.Error(err))
}
n.cache.PutBucket(info)
return info, nil
}
@ -152,12 +149,7 @@ func (n *layer) createContainer(ctx context.Context, p *CreateBucketParams) (*da
return nil, fmt.Errorf("set container eacl: %w", err)
}
if err = n.bucketCache.Put(bktInfo); err != nil {
n.log.Warn("couldn't put bucket info into cache",
zap.String("bucket name", bktInfo.Name),
zap.Stringer("bucket cid", bktInfo.CID),
zap.Error(err))
}
n.cache.PutBucket(bktInfo)
return bktInfo, nil
}

View File

@ -64,15 +64,13 @@ func (n *layer) PutBucketCORS(ctx context.Context, p *PutCORSParams) error {
}
}
if err = n.systemCache.PutCORS(systemObjectKey(p.BktInfo, prm.Filepath), cors); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
n.cache.PutCORS(p.BktInfo, cors)
return nil
}
func (n *layer) GetBucketCORS(ctx context.Context, bktInfo *data.BucketInfo) (*data.CORSConfiguration, error) {
cors, err := n.getCORS(ctx, bktInfo, bktInfo.CORSObjectName())
cors, err := n.getCORS(ctx, bktInfo)
if err != nil {
if errorsStd.Is(err, ErrNodeNotFound) {
return nil, errors.GetAPIError(errors.ErrNoSuchCORSConfiguration)
@ -95,7 +93,7 @@ func (n *layer) DeleteBucketCORS(ctx context.Context, bktInfo *data.BucketInfo)
}
}
n.systemCache.Delete(systemObjectKey(bktInfo, bktInfo.CORSObjectName()))
n.cache.DeleteCORS(bktInfo)
return nil
}

View File

@ -14,7 +14,6 @@ import (
"github.com/nats-io/nats.go"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-s3-gw/api"
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
"github.com/nspcc-dev/neofs-s3-gw/api/data"
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
"github.com/nspcc-dev/neofs-s3-gw/api/layer/encryption"
@ -51,11 +50,7 @@ type (
anonKey AnonymousKey
resolver BucketResolver
ncontroller EventListener
listsCache *cache.ObjectsListCache
objCache *cache.ObjectsCache
namesCache *cache.ObjectsNameCache
bucketCache *cache.BucketCache
systemCache *cache.SystemCache
cache *Cache
treeService TreeService
}
@ -72,15 +67,6 @@ type (
Key *keys.PrivateKey
}
// CachesConfig contains params for caches.
CachesConfig struct {
Objects *cache.Config
ObjectsList *cache.Config
Names *cache.Config
Buckets *cache.Config
System *cache.Config
}
// GetObjectParams stores object get request parameters.
GetObjectParams struct {
Range *RangeParams
@ -280,17 +266,6 @@ func (f MsgHandlerFunc) HandleMessage(ctx context.Context, msg *nats.Msg) error
return f(ctx, msg)
}
// DefaultCachesConfigs returns filled configs.
func DefaultCachesConfigs(logger *zap.Logger) *CachesConfig {
return &CachesConfig{
Objects: cache.DefaultObjectsConfig(logger),
ObjectsList: cache.DefaultObjectsListConfig(logger),
Names: cache.DefaultObjectsNameConfig(logger),
Buckets: cache.DefaultBucketConfig(logger),
System: cache.DefaultSystemConfig(logger),
}
}
// NewLayer creates an instance of a layer. It checks credentials
// and establishes gRPC connection with the node.
func NewLayer(log *zap.Logger, neoFS NeoFS, config *Config) Client {
@ -299,11 +274,7 @@ func NewLayer(log *zap.Logger, neoFS NeoFS, config *Config) Client {
log: log,
anonKey: config.AnonKey,
resolver: config.Resolver,
listsCache: cache.NewObjectsListCache(config.Caches.ObjectsList),
objCache: cache.New(config.Caches.Objects),
namesCache: cache.NewObjectsNameCache(config.Caches.Names),
bucketCache: cache.NewBucketCache(config.Caches.Buckets),
systemCache: cache.NewSystemCache(config.Caches.System),
cache: NewCache(config.Caches),
treeService: config.TreeService,
}
}
@ -365,7 +336,7 @@ func (n *layer) GetBucketInfo(ctx context.Context, name string) (*data.BucketInf
return nil, fmt.Errorf("unescape bucket name: %w", err)
}
if bktInfo := n.bucketCache.Get(name); bktInfo != nil {
if bktInfo := n.cache.GetBucket(name); bktInfo != nil {
return bktInfo, nil
}
@ -561,7 +532,7 @@ func (n *layer) deleteObject(ctx context.Context, bkt *data.BucketInfo, settings
}
obj.Error = n.treeService.RemoveVersion(ctx, bkt, nodeVersion.ID)
n.listsCache.CleanCacheEntriesContainingObject(obj.Name, bkt.CID)
n.cache.CleanListCacheEntriesContainingObject(obj.Name, bkt.CID)
return obj
}
@ -604,8 +575,7 @@ func (n *layer) deleteObject(ctx context.Context, bkt *data.BucketInfo, settings
return obj
}
n.namesCache.Delete(bkt.Name + "/" + obj.Name)
n.listsCache.CleanCacheEntriesContainingObject(obj.Name, bkt.CID)
n.cache.DeleteObjectName(bkt.CID, bkt.Name, obj.Name)
return obj
}
@ -681,6 +651,6 @@ func (n *layer) DeleteBucket(ctx context.Context, p *DeleteBucketParams) error {
return errors.GetAPIError(errors.ErrBucketNotEmpty)
}
n.bucketCache.Delete(p.BktInfo.Name)
n.cache.DeleteBucket(p.BktInfo.Name)
return n.neoFS.DeleteContainer(ctx, p.BktInfo.CID, p.SessionToken)
}

View File

@ -461,7 +461,7 @@ func (n *layer) CompleteMultipartUpload(ctx context.Context, p *CompleteMultipar
zap.Error(err))
}
addr.SetObject(partInfo.OID)
n.objCache.Delete(addr)
n.cache.DeleteObject(addr)
}
return uploadData, obj, n.treeService.DeleteMultipartUpload(ctx, p.Info.Bkt, multipartInfo.ID)

View File

@ -25,13 +25,11 @@ func (n *layer) PutBucketNotificationConfiguration(ctx context.Context, p *PutBu
return fmt.Errorf("marshal notify configuration: %w", err)
}
sysName := p.BktInfo.NotificationConfigurationObjectName()
prm := PrmObjectCreate{
Container: p.BktInfo.CID,
Creator: p.BktInfo.Owner,
Payload: bytes.NewReader(confXML),
Filepath: sysName,
Filepath: p.BktInfo.NotificationConfigurationObjectName(),
CopiesNumber: p.CopiesNumber,
}
@ -55,17 +53,13 @@ func (n *layer) PutBucketNotificationConfiguration(ctx context.Context, p *PutBu
}
}
if err = n.systemCache.PutNotificationConfiguration(systemObjectKey(p.BktInfo, sysName), p.Configuration); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
n.cache.PutNotificationConfiguration(p.BktInfo, p.Configuration)
return nil
}
func (n *layer) GetBucketNotificationConfiguration(ctx context.Context, bktInfo *data.BucketInfo) (*data.NotificationConfiguration, error) {
systemCacheKey := systemObjectKey(bktInfo, bktInfo.NotificationConfigurationObjectName())
if conf := n.systemCache.GetNotificationConfiguration(systemCacheKey); conf != nil {
if conf := n.cache.GetNotificationConfiguration(bktInfo); conf != nil {
return conf, nil
}
@ -88,11 +82,7 @@ func (n *layer) GetBucketNotificationConfiguration(ctx context.Context, bktInfo
}
}
if err = n.systemCache.PutNotificationConfiguration(systemCacheKey, conf); err != nil {
n.log.Warn("couldn't put system meta to objects cache",
zap.Stringer("bucket id", bktInfo.CID),
zap.Error(err))
}
n.cache.PutNotificationConfiguration(bktInfo, conf)
return conf, nil
}

View File

@ -185,7 +185,7 @@ func ParseCompletedPartHeader(hdr string) (*Part, error) {
// PutObject stores object into NeoFS, took payload from io.Reader.
func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.ObjectInfo, error) {
own := n.Owner(ctx)
owner := n.Owner(ctx)
bktSettings, err := n.GetBucketSettings(ctx, p.BktInfo)
if err != nil {
@ -230,7 +230,7 @@ func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Object
prm := PrmObjectCreate{
Container: p.BktInfo.CID,
Creator: own,
Creator: owner,
PayloadSize: uint64(p.Size),
Filepath: p.Object,
Payload: r,
@ -271,13 +271,13 @@ func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Object
}
}
n.listsCache.CleanCacheEntriesContainingObject(p.Object, p.BktInfo.CID)
n.cache.CleanListCacheEntriesContainingObject(p.Object, p.BktInfo.CID)
objInfo := &data.ObjectInfo{
ID: id,
CID: p.BktInfo.CID,
Owner: own,
Owner: owner,
Bucket: p.BktInfo.Name,
Name: p.Object,
Size: p.Size,
@ -292,25 +292,15 @@ func (n *layer) PutObject(ctx context.Context, p *PutObjectParams) (*data.Object
NodeVersion: newVersion,
}
if err = n.objCache.PutObject(extendedObjInfo); err != nil {
n.log.Warn("couldn't add object to cache", zap.Error(err),
zap.String("object_name", p.Object), zap.String("bucket_name", p.BktInfo.Name),
zap.String("cid", objInfo.CID.EncodeToString()), zap.String("oid", objInfo.ID.EncodeToString()))
}
if err = n.namesCache.Put(objInfo.NiceName(), objInfo.Address()); err != nil {
n.log.Warn("couldn't put obj address to name cache",
zap.String("obj nice name", objInfo.NiceName()),
zap.Error(err))
}
n.cache.PutObjectWithName(owner, extendedObjInfo)
return objInfo, nil
}
func (n *layer) headLastVersionIfNotDeleted(ctx context.Context, bkt *data.BucketInfo, objectName string) (*data.ExtendedObjectInfo, error) {
if addr := n.namesCache.Get(bkt.Name + "/" + objectName); addr != nil {
if extObjInfo := n.objCache.GetObject(*addr); extObjInfo != nil {
return extObjInfo, nil
}
owner := n.Owner(ctx)
if extObjInfo := n.cache.GetLastObject(owner, bkt.Name, objectName); extObjInfo != nil {
return extObjInfo, nil
}
node, err := n.treeService.GetLatestVersion(ctx, bkt, objectName)
@ -336,17 +326,7 @@ func (n *layer) headLastVersionIfNotDeleted(ctx context.Context, bkt *data.Bucke
NodeVersion: node,
}
if err = n.objCache.PutObject(extObjInfo); err != nil {
n.log.Warn("couldn't put object info to cache",
zap.Stringer("object id", node.OID),
zap.Stringer("bucket id", bkt.CID),
zap.Error(err))
}
if err = n.namesCache.Put(objInfo.NiceName(), objInfo.Address()); err != nil {
n.log.Warn("couldn't put obj address to head cache",
zap.String("obj nice name", objInfo.NiceName()),
zap.Error(err))
}
n.cache.PutObjectWithName(owner, extObjInfo)
return extObjInfo, nil
}
@ -379,7 +359,8 @@ func (n *layer) headVersion(ctx context.Context, bkt *data.BucketInfo, p *HeadOb
}
}
if extObjInfo := n.objCache.GetObject(newAddress(bkt.CID, foundVersion.OID)); extObjInfo != nil {
owner := n.Owner(ctx)
if extObjInfo := n.cache.GetObject(owner, newAddress(bkt.CID, foundVersion.OID)); extObjInfo != nil {
return extObjInfo, nil
}
@ -397,14 +378,7 @@ func (n *layer) headVersion(ctx context.Context, bkt *data.BucketInfo, p *HeadOb
NodeVersion: foundVersion,
}
if err = n.objCache.PutObject(extObjInfo); err != nil {
n.log.Warn("couldn't put obj to object cache",
zap.String("bucket name", objInfo.Bucket),
zap.Stringer("bucket cid", objInfo.CID),
zap.String("object name", objInfo.Name),
zap.Stringer("object id", objInfo.ID),
zap.Error(err))
}
n.cache.PutObject(owner, extObjInfo)
return extObjInfo, nil
}
@ -418,7 +392,7 @@ func (n *layer) objectDelete(ctx context.Context, bktInfo *data.BucketInfo, idOb
n.prepareAuthParameters(ctx, &prm.PrmAuth, bktInfo.Owner)
n.objCache.Delete(newAddress(bktInfo.CID, idObj))
n.cache.DeleteObject(newAddress(bktInfo.CID, idObj))
return n.neoFS.DeleteObject(ctx, prm)
}
@ -503,17 +477,16 @@ func (n *layer) getLatestObjectsVersions(ctx context.Context, p allObjectParams)
return nil, nil, nil
}
owner := n.Owner(ctx)
cacheKey := cache.CreateObjectsListCacheKey(p.Bucket.CID, p.Prefix, true)
nodeVersions := n.listsCache.GetVersions(cacheKey)
nodeVersions := n.cache.GetList(owner, cacheKey)
if nodeVersions == nil {
nodeVersions, err = n.treeService.GetLatestVersionsByPrefix(ctx, p.Bucket, p.Prefix)
if err != nil {
return nil, nil, err
}
if err = n.listsCache.PutVersions(cacheKey, nodeVersions); err != nil {
n.log.Error("couldn't cache list of objects", zap.Error(err))
}
n.cache.PutList(owner, cacheKey, nodeVersions)
}
if len(nodeVersions) == 0 {
@ -643,17 +616,17 @@ func getPartialObjectInfo(bktInfo *data.BucketInfo, node *data.NodeVersion) *dat
func (n *layer) bucketNodeVersions(ctx context.Context, bkt *data.BucketInfo, prefix string) ([]*data.NodeVersion, error) {
var err error
owner := n.Owner(ctx)
cacheKey := cache.CreateObjectsListCacheKey(bkt.CID, prefix, false)
nodeVersions := n.listsCache.GetVersions(cacheKey)
nodeVersions := n.cache.GetList(owner, cacheKey)
if nodeVersions == nil {
nodeVersions, err = n.treeService.GetAllVersionsByPrefix(ctx, bkt, prefix)
if err != nil {
return nil, fmt.Errorf("get all versions from tree service: %w", err)
}
if err = n.listsCache.PutVersions(cacheKey, nodeVersions); err != nil {
n.log.Error("couldn't cache list of objects", zap.Error(err))
}
n.cache.PutList(owner, cacheKey, nodeVersions)
}
return nodeVersions, nil
@ -763,9 +736,9 @@ func (n *layer) objectInfoFromObjectsCacheOrNeoFS(ctx context.Context, bktInfo *
return oiDir
}
extObjInfo := n.objCache.GetObject(newAddress(bktInfo.CID, node.OID))
if extObjInfo != nil {
return extObjInfo.ObjectInfo
owner := n.Owner(ctx)
if extInfo := n.cache.GetObject(owner, newAddress(bktInfo.CID, node.OID)); extInfo != nil {
return extInfo.ObjectInfo
}
meta, err := n.objectHead(ctx, bktInfo, node.OID)
@ -775,9 +748,7 @@ func (n *layer) objectInfoFromObjectsCacheOrNeoFS(ctx context.Context, bktInfo *
}
oi = objectInfoFromMeta(bktInfo, meta)
if err = n.objCache.PutObject(&data.ExtendedObjectInfo{ObjectInfo: oi, NodeVersion: node}); err != nil {
n.log.Warn("couldn't cache an object", zap.Error(err))
}
n.cache.PutObject(owner, &data.ExtendedObjectInfo{ObjectInfo: oi, NodeVersion: node})
return oi
}

View File

@ -12,7 +12,6 @@ import (
"github.com/nspcc-dev/neofs-s3-gw/api/data"
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"go.uber.org/zap"
)
const (
@ -34,7 +33,7 @@ func (n *layer) PutLockInfo(ctx context.Context, p *PutLockInfoParams) (err erro
// if not, then receive node version from tree service
if versionNode == nil {
// check cache if node version is stored inside extendedObjectVersion
versionNode = n.getNodeVersionFromCache(p.ObjVersion)
versionNode = n.getNodeVersionFromCache(n.Owner(ctx), p.ObjVersion)
if versionNode == nil {
// else get node version from tree service
versionNode, err = n.getNodeVersion(ctx, p.ObjVersion)
@ -101,9 +100,7 @@ func (n *layer) PutLockInfo(ctx context.Context, p *PutLockInfoParams) (err erro
return fmt.Errorf("couldn't put lock into tree: %w", err)
}
if err = n.systemCache.PutLockInfo(lockObjectKey(p.ObjVersion), lockInfo); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
n.cache.PutLockInfo(lockObjectKey(p.ObjVersion), lockInfo)
return nil
}
@ -127,7 +124,7 @@ func (n *layer) putLockObject(ctx context.Context, bktInfo *data.BucketInfo, obj
}
func (n *layer) GetLockInfo(ctx context.Context, objVersion *ObjectVersion) (*data.LockInfo, error) {
if lockInfo := n.systemCache.GetLockInfo(lockObjectKey(objVersion)); lockInfo != nil {
if lockInfo := n.cache.GetLockInfo(lockObjectKey(objVersion)); lockInfo != nil {
return lockInfo, nil
}
@ -144,17 +141,16 @@ func (n *layer) GetLockInfo(ctx context.Context, objVersion *ObjectVersion) (*da
lockInfo = &data.LockInfo{}
}
if err = n.systemCache.PutLockInfo(lockObjectKey(objVersion), lockInfo); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
n.cache.PutLockInfo(lockObjectKey(objVersion), lockInfo)
return lockInfo, nil
}
func (n *layer) getCORS(ctx context.Context, bkt *data.BucketInfo, sysName string) (*data.CORSConfiguration, error) {
if cors := n.systemCache.GetCORS(systemObjectKey(bkt, sysName)); cors != nil {
func (n *layer) getCORS(ctx context.Context, bkt *data.BucketInfo) (*data.CORSConfiguration, error) {
if cors := n.cache.GetCORS(bkt); cors != nil {
return cors, nil
}
objID, err := n.treeService.GetBucketCORS(ctx, bkt)
objIDNotFound := errorsStd.Is(err, ErrNodeNotFound)
if err != nil && !objIDNotFound {
@ -176,30 +172,18 @@ func (n *layer) getCORS(ctx context.Context, bkt *data.BucketInfo, sysName strin
return nil, fmt.Errorf("unmarshal cors: %w", err)
}
if err = n.systemCache.PutCORS(systemObjectKey(bkt, sysName), cors); err != nil {
objID, _ := obj.ID()
n.log.Warn("couldn't put system meta to objects cache",
zap.Stringer("object id", &objID),
zap.String("bucket id", bkt.CID.EncodeToString()),
zap.Error(err))
}
n.cache.PutCORS(bkt, cors)
return cors, nil
}
// systemObjectKey is a key to use in SystemCache.
func systemObjectKey(bktInfo *data.BucketInfo, obj string) string {
return bktInfo.Name + obj
}
func lockObjectKey(objVersion *ObjectVersion) string {
// todo reconsider forming name since versionID can be "null" or ""
return ".lock." + objVersion.BktInfo.CID.EncodeToString() + "." + objVersion.ObjectName + "." + objVersion.VersionID
}
func (n *layer) GetBucketSettings(ctx context.Context, bktInfo *data.BucketInfo) (*data.BucketSettings, error) {
systemKey := systemObjectKey(bktInfo, bktInfo.SettingsObjectName())
if settings := n.systemCache.GetSettings(systemKey); settings != nil {
if settings := n.cache.GetSettings(bktInfo); settings != nil {
return settings, nil
}
@ -211,11 +195,7 @@ func (n *layer) GetBucketSettings(ctx context.Context, bktInfo *data.BucketInfo)
settings = &data.BucketSettings{Versioning: data.VersioningUnversioned}
}
if err = n.systemCache.PutSettings(systemKey, settings); err != nil {
n.log.Warn("couldn't put system meta to objects cache",
zap.String("bucket id", bktInfo.CID.EncodeToString()),
zap.Error(err))
}
n.cache.PutSettings(bktInfo, settings)
return settings, nil
}
@ -225,10 +205,7 @@ func (n *layer) PutBucketSettings(ctx context.Context, p *PutSettingsParams) err
return fmt.Errorf("failed to get settings node: %w", err)
}
systemKey := systemObjectKey(p.BktInfo, p.BktInfo.SettingsObjectName())
if err := n.systemCache.PutSettings(systemKey, p.Settings); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
n.cache.PutSettings(p.BktInfo, p.Settings)
return nil
}

View File

@ -8,7 +8,7 @@ import (
"github.com/nspcc-dev/neofs-s3-gw/api/errors"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"go.uber.org/zap"
"github.com/nspcc-dev/neofs-sdk-go/user"
)
func (n *layer) GetObjectTagging(ctx context.Context, p *ObjectVersion) (string, map[string]string, error) {
@ -18,7 +18,7 @@ func (n *layer) GetObjectTagging(ctx context.Context, p *ObjectVersion) (string,
)
if len(p.VersionID) != 0 && p.VersionID != data.UnversionedObjectVersionID {
tags = n.systemCache.GetTagging(objectTaggingCacheKey(p))
tags = n.cache.GetTagging(objectTaggingCacheKey(p))
if tags != nil {
return p.VersionID, tags, nil
}
@ -30,7 +30,7 @@ func (n *layer) GetObjectTagging(ctx context.Context, p *ObjectVersion) (string,
}
p.VersionID = version.OID.EncodeToString()
tags = n.systemCache.GetTagging(objectTaggingCacheKey(p))
tags = n.cache.GetTagging(objectTaggingCacheKey(p))
if tags != nil {
return p.VersionID, tags, nil
}
@ -43,9 +43,7 @@ func (n *layer) GetObjectTagging(ctx context.Context, p *ObjectVersion) (string,
return "", nil, err
}
if err = n.systemCache.PutTagging(objectTaggingCacheKey(p), tags); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
n.cache.PutTagging(objectTaggingCacheKey(p), tags)
return p.VersionID, tags, nil
}
@ -65,9 +63,7 @@ func (n *layer) PutObjectTagging(ctx context.Context, p *ObjectVersion, tagSet m
return nil, err
}
if err = n.systemCache.PutTagging(objectTaggingCacheKey(p), tagSet); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
n.cache.PutTagging(objectTaggingCacheKey(p), tagSet)
return version, nil
}
@ -88,7 +84,7 @@ func (n *layer) DeleteObjectTagging(ctx context.Context, p *ObjectVersion) (*dat
p.VersionID = version.OID.EncodeToString()
n.systemCache.Delete(objectTaggingCacheKey(p))
n.cache.DeleteTagging(objectTaggingCacheKey(p))
return version, nil
}
@ -99,7 +95,7 @@ func (n *layer) GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo)
tags map[string]string
)
tags = n.systemCache.GetTagging(bucketTaggingCacheKey(bktInfo.CID))
tags = n.cache.GetTagging(bucketTaggingCacheKey(bktInfo.CID))
if tags != nil {
return tags, nil
}
@ -108,9 +104,7 @@ func (n *layer) GetBucketTagging(ctx context.Context, bktInfo *data.BucketInfo)
return nil, err
}
if err := n.systemCache.PutTagging(bucketTaggingCacheKey(bktInfo.CID), tags); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
n.cache.PutTagging(bucketTaggingCacheKey(bktInfo.CID), tags)
return tags, nil
}
@ -119,15 +113,14 @@ func (n *layer) PutBucketTagging(ctx context.Context, bktInfo *data.BucketInfo,
if err := n.treeService.PutBucketTagging(ctx, bktInfo, tagSet); err != nil {
return err
}
if err := n.systemCache.PutTagging(bucketTaggingCacheKey(bktInfo.CID), tagSet); err != nil {
n.log.Error("couldn't cache system object", zap.Error(err))
}
n.cache.PutTagging(bucketTaggingCacheKey(bktInfo.CID), tagSet)
return nil
}
func (n *layer) DeleteBucketTagging(ctx context.Context, bktInfo *data.BucketInfo) error {
n.systemCache.Delete(bucketTaggingCacheKey(bktInfo.CID))
n.cache.DeleteTagging(bucketTaggingCacheKey(bktInfo.CID))
return n.treeService.DeleteBucketTagging(ctx, bktInfo)
}
@ -171,7 +164,7 @@ func (n *layer) getNodeVersion(ctx context.Context, objVersion *ObjectVersion) (
return version, err
}
func (n *layer) getNodeVersionFromCache(o *ObjectVersion) *data.NodeVersion {
func (n *layer) getNodeVersionFromCache(owner user.ID, o *ObjectVersion) *data.NodeVersion {
if len(o.VersionID) == 0 || o.VersionID == data.UnversionedObjectVersionID {
return nil
}
@ -185,7 +178,7 @@ func (n *layer) getNodeVersionFromCache(o *ObjectVersion) *data.NodeVersion {
addr.SetContainer(o.BktInfo.CID)
addr.SetObject(objID)
extObjectInfo := n.objCache.GetObject(addr)
extObjectInfo := n.cache.GetObject(owner, addr)
if extObjectInfo == nil {
return nil
}

View File

@ -547,9 +547,12 @@ func getCacheOptions(v *viper.Viper, l *zap.Logger) *layer.CachesConfig {
cacheCfg.Names.Lifetime = getLifetime(v, l, cfgNamesCacheLifetime, cacheCfg.Names.Lifetime)
cacheCfg.Names.Size = getSize(v, l, cfgNamesCacheSize, cacheCfg.Names.Size)
cacheCfg.System.Lifetime = getLifetime(v, l, cfgSystemLifetimeSize, cacheCfg.System.Lifetime)
cacheCfg.System.Lifetime = getLifetime(v, l, cfgSystemCacheLifetime, cacheCfg.System.Lifetime)
cacheCfg.System.Size = getSize(v, l, cfgSystemCacheSize, cacheCfg.System.Size)
cacheCfg.AccessControl.Lifetime = getLifetime(v, l, cfgAccessControlCacheLifetime, cacheCfg.AccessControl.Lifetime)
cacheCfg.AccessControl.Size = getSize(v, l, cfgAccessControlCacheSize, cacheCfg.AccessControl.Size)
return cacheCfg
}

View File

@ -52,18 +52,20 @@ const ( // Settings.
cfgPoolErrorThreshold = "pool_error_threshold"
// Caching.
cfgObjectsCacheLifetime = "cache.objects.lifetime"
cfgObjectsCacheSize = "cache.objects.size"
cfgListObjectsCacheLifetime = "cache.list.lifetime"
cfgListObjectsCacheSize = "cache.list.size"
cfgBucketsCacheLifetime = "cache.buckets.lifetime"
cfgBucketsCacheSize = "cache.buckets.size"
cfgNamesCacheLifetime = "cache.names.lifetime"
cfgNamesCacheSize = "cache.names.size"
cfgSystemLifetimeSize = "cache.system.lifetime"
cfgSystemCacheSize = "cache.system.size"
cfgAccessBoxCacheLifetime = "cache.accessbox.lifetime"
cfgAccessBoxCacheSize = "cache.accessbox.size"
cfgObjectsCacheLifetime = "cache.objects.lifetime"
cfgObjectsCacheSize = "cache.objects.size"
cfgListObjectsCacheLifetime = "cache.list.lifetime"
cfgListObjectsCacheSize = "cache.list.size"
cfgBucketsCacheLifetime = "cache.buckets.lifetime"
cfgBucketsCacheSize = "cache.buckets.size"
cfgNamesCacheLifetime = "cache.names.lifetime"
cfgNamesCacheSize = "cache.names.size"
cfgSystemCacheLifetime = "cache.system.lifetime"
cfgSystemCacheSize = "cache.system.size"
cfgAccessBoxCacheLifetime = "cache.accessbox.lifetime"
cfgAccessBoxCacheSize = "cache.accessbox.size"
cfgAccessControlCacheLifetime = "cache.accesscontrol.lifetime"
cfgAccessControlCacheSize = "cache.accesscontrol.size"
// NATS.
cfgEnableNATS = "nats.enabled"