package cache import ( "fmt" "time" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" "github.com/bluele/gcache" "go.uber.org/zap" ) // BucketCache contains cache with objects and the lifetime of cache entries. type BucketCache struct { cache gcache.Cache cidCache gcache.Cache logger *zap.Logger } const ( // DefaultBucketCacheSize is a default maximum number of entries in cache. DefaultBucketCacheSize = 1e3 // DefaultBucketCacheLifetime is a default lifetime of entries in cache. DefaultBucketCacheLifetime = time.Minute ) // DefaultBucketConfig returns new default cache expiration values. func DefaultBucketConfig(logger *zap.Logger) *Config { return &Config{ Size: DefaultBucketCacheSize, Lifetime: DefaultBucketCacheLifetime, Logger: logger, } } // NewBucketCache creates an object of BucketCache. func NewBucketCache(config *Config, cidCache bool) *BucketCache { cache := &BucketCache{ cache: gcache.New(config.Size).LRU().Expiration(config.Lifetime).Build(), logger: config.Logger, } if cidCache { cache.cidCache = gcache.New(config.Size).LRU().Expiration(config.Lifetime).Build() } return cache } // Get returns a cached object. func (o *BucketCache) Get(ns, bktName string) *data.BucketInfo { return o.get(formKey(ns, bktName)) } func (o *BucketCache) GetByCID(cnrID cid.ID) *data.BucketInfo { if o.cidCache == nil { return nil } entry, err := o.cidCache.Get(cnrID) if err != nil { return nil } key, ok := entry.(string) if !ok { o.logger.Warn(logs.InvalidCacheEntryType, zap.String("actual", fmt.Sprintf("%T", entry)), zap.String("expected", fmt.Sprintf("%T", key))) return nil } return o.get(key) } func (o *BucketCache) get(key string) *data.BucketInfo { entry, err := o.cache.Get(key) if err != nil { return nil } result, ok := entry.(*data.BucketInfo) if !ok { o.logger.Warn(logs.InvalidCacheEntryType, zap.String("actual", fmt.Sprintf("%T", entry)), zap.String("expected", fmt.Sprintf("%T", result))) return nil } return result } // Put puts an object to cache. func (o *BucketCache) Put(bkt *data.BucketInfo) error { if o.cidCache != nil { if err := o.cidCache.Set(bkt.CID, formKey(bkt.Zone, bkt.Name)); err != nil { return err } } return o.cache.Set(formKey(bkt.Zone, bkt.Name), bkt) } // Delete deletes an object from cache. func (o *BucketCache) Delete(bkt *data.BucketInfo) bool { if o.cidCache != nil { o.cidCache.Remove(bkt.CID) } return o.cache.Remove(formKey(bkt.Zone, bkt.Name)) } func formKey(zone, name string) string { return name + "." + zone }