diff --git a/api/cache/network_info.go b/api/cache/network_info.go new file mode 100644 index 00000000..92f1a999 --- /dev/null +++ b/api/cache/network_info.go @@ -0,0 +1,65 @@ +package cache + +import ( + "fmt" + "time" + + "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" + "github.com/bluele/gcache" + "go.uber.org/zap" +) + +type ( + // NetworkInfoCache provides cache for network info. + NetworkInfoCache struct { + cache gcache.Cache + logger *zap.Logger + } + + // NetworkInfoCacheConfig stores expiration params for cache. + NetworkInfoCacheConfig struct { + Lifetime time.Duration + Logger *zap.Logger + } +) + +const ( + DefaultNetworkInfoCacheLifetime = 1 * time.Minute + networkInfoCacheSize = 1 + networkInfoKey = "network_info" +) + +// DefaultNetworkInfoConfig returns new default cache expiration values. +func DefaultNetworkInfoConfig(logger *zap.Logger) *NetworkInfoCacheConfig { + return &NetworkInfoCacheConfig{ + Lifetime: DefaultNetworkInfoCacheLifetime, + Logger: logger, + } +} + +// NewNetworkInfoCache creates an object of NetworkInfoCache. +func NewNetworkInfoCache(config *NetworkInfoCacheConfig) *NetworkInfoCache { + gc := gcache.New(networkInfoCacheSize).LRU().Expiration(config.Lifetime).Build() + return &NetworkInfoCache{cache: gc, logger: config.Logger} +} + +func (c *NetworkInfoCache) Get() *netmap.NetworkInfo { + entry, err := c.cache.Get(networkInfoKey) + if err != nil { + return nil + } + + result, ok := entry.(netmap.NetworkInfo) + if !ok { + c.logger.Warn(logs.InvalidCacheEntryType, zap.String("actual", fmt.Sprintf("%T", entry)), + zap.String("expected", fmt.Sprintf("%T", result))) + return nil + } + + return &result +} + +func (c *NetworkInfoCache) Put(info netmap.NetworkInfo) error { + return c.cache.Set(networkInfoKey, info) +} diff --git a/api/handler/handlers_test.go b/api/handler/handlers_test.go index b7ef210d..42550db9 100644 --- a/api/handler/handlers_test.go +++ b/api/handler/handlers_test.go @@ -243,6 +243,7 @@ func getMinCacheConfig(logger *zap.Logger) *layer.CachesConfig { Buckets: minCacheCfg, System: minCacheCfg, AccessControl: minCacheCfg, + NetworkInfo: &cache.NetworkInfoCacheConfig{Lifetime: minCacheCfg.Lifetime}, } } diff --git a/api/layer/cache.go b/api/layer/cache.go index ca9a5920..c3ceb7cd 100644 --- a/api/layer/cache.go +++ b/api/layer/cache.go @@ -5,6 +5,7 @@ import ( "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" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" "go.uber.org/zap" @@ -19,6 +20,7 @@ type Cache struct { bucketCache *cache.BucketCache systemCache *cache.SystemCache accessCache *cache.AccessControlCache + networkInfoCache *cache.NetworkInfoCache } // CachesConfig contains params for caches. @@ -31,6 +33,7 @@ type CachesConfig struct { Buckets *cache.Config System *cache.Config AccessControl *cache.Config + NetworkInfo *cache.NetworkInfoCacheConfig } // DefaultCachesConfigs returns filled configs. @@ -44,6 +47,7 @@ func DefaultCachesConfigs(logger *zap.Logger) *CachesConfig { Buckets: cache.DefaultBucketConfig(logger), System: cache.DefaultSystemConfig(logger), AccessControl: cache.DefaultAccessControlConfig(logger), + NetworkInfo: cache.DefaultNetworkInfoConfig(logger), } } @@ -57,6 +61,7 @@ func NewCache(cfg *CachesConfig) *Cache { bucketCache: cache.NewBucketCache(cfg.Buckets), systemCache: cache.NewSystemCache(cfg.System), accessCache: cache.NewAccessControlCache(cfg.AccessControl), + networkInfoCache: cache.NewNetworkInfoCache(cfg.NetworkInfo), } } @@ -283,3 +288,13 @@ func (c *Cache) PutLifecycleConfiguration(owner user.ID, bkt *data.BucketInfo, c func (c *Cache) DeleteLifecycleConfiguration(bktInfo *data.BucketInfo) { c.systemCache.Delete(bktInfo.LifecycleConfigurationObjectName()) } + +func (c *Cache) GetNetworkInfo() *netmap.NetworkInfo { + return c.networkInfoCache.Get() +} + +func (c *Cache) PutNetworkInfo(info netmap.NetworkInfo) { + if err := c.networkInfoCache.Put(info); err != nil { + c.logger.Warn(logs.CouldntCacheNetworkInfo, zap.Error(err)) + } +} diff --git a/api/layer/layer.go b/api/layer/layer.go index 57f804d5..236b9734 100644 --- a/api/layer/layer.go +++ b/api/layer/layer.go @@ -855,10 +855,17 @@ func (n *Layer) DeleteBucket(ctx context.Context, p *DeleteBucketParams) error { } func (n *Layer) GetNetworkInfo(ctx context.Context) (netmap.NetworkInfo, error) { + cachedInfo := n.cache.GetNetworkInfo() + if cachedInfo != nil { + return *cachedInfo, nil + } + networkInfo, err := n.frostFS.NetworkInfo(ctx) if err != nil { - return networkInfo, fmt.Errorf("get network info: %w", err) + return netmap.NetworkInfo{}, fmt.Errorf("get network info: %w", err) } + n.cache.PutNetworkInfo(networkInfo) + return networkInfo, nil } diff --git a/api/layer/multipart_upload.go b/api/layer/multipart_upload.go index c99173d0..ce3f5525 100644 --- a/api/layer/multipart_upload.go +++ b/api/layer/multipart_upload.go @@ -150,9 +150,9 @@ func (n *Layer) CreateMultipartUpload(ctx context.Context, p *CreateMultipartPar metaSize += len(p.Data.TagSet) } - networkInfo, err := n.frostFS.NetworkInfo(ctx) + networkInfo, err := n.GetNetworkInfo(ctx) if err != nil { - return fmt.Errorf("get network info: %w", err) + return err } info := &data.MultipartInfo{ diff --git a/cmd/s3-gw/app.go b/cmd/s3-gw/app.go index 7b69e384..96ad889e 100644 --- a/cmd/s3-gw/app.go +++ b/cmd/s3-gw/app.go @@ -941,6 +941,8 @@ func getCacheOptions(v *viper.Viper, l *zap.Logger) *layer.CachesConfig { cacheCfg.AccessControl.Lifetime = fetchCacheLifetime(v, l, cfgAccessControlCacheLifetime, cacheCfg.AccessControl.Lifetime) cacheCfg.AccessControl.Size = fetchCacheSize(v, l, cfgAccessControlCacheSize, cacheCfg.AccessControl.Size) + cacheCfg.NetworkInfo.Lifetime = fetchCacheLifetime(v, l, cfgNetworkInfoCacheLifetime, cacheCfg.NetworkInfo.Lifetime) + return cacheCfg } diff --git a/cmd/s3-gw/app_settings.go b/cmd/s3-gw/app_settings.go index 8dfe312a..e8bd0318 100644 --- a/cmd/s3-gw/app_settings.go +++ b/cmd/s3-gw/app_settings.go @@ -130,6 +130,7 @@ const ( // Settings. cfgMorphPolicyCacheSize = "cache.morph_policy.size" cfgFrostfsIDCacheLifetime = "cache.frostfsid.lifetime" cfgFrostfsIDCacheSize = "cache.frostfsid.size" + cfgNetworkInfoCacheLifetime = "cache.network_info.lifetime" cfgAccessBoxCacheRemovingCheckInterval = "cache.accessbox.removing_check_interval" diff --git a/config/config.env b/config/config.env index 6e8a88e1..53ac8f14 100644 --- a/config/config.env +++ b/config/config.env @@ -122,6 +122,8 @@ S3_GW_CACHE_MORPH_POLICY_SIZE=10000 # Cache which stores frostfsid subject info S3_GW_CACHE_FROSTFSID_LIFETIME=1m S3_GW_CACHE_FROSTFSID_SIZE=10000 +# Cache which stores network info +S3_GW_CACHE_NETWORK_INFO_LIFETIME=1m # Default policy of placing containers in FrostFS # If a user sends a request `CreateBucket` and doesn't define policy for placing of a container in FrostFS, the S3 Gateway diff --git a/config/config.yaml b/config/config.yaml index bccb6b4e..2a4e65e6 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -147,6 +147,9 @@ cache: frostfsid: lifetime: 1m size: 10000 + # Cache which stores network info + network_info: + lifetime: 1m # Parameters of FrostFS container placement policy placement_policy: diff --git a/docs/configuration.md b/docs/configuration.md index d8bd2088..13754e97 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -438,6 +438,8 @@ cache: frostfsid: lifetime: 1m size: 10000 + network_info: + lifetime: 1m ``` | Parameter | Type | Default value | Description | @@ -452,6 +454,7 @@ cache: | `accesscontrol` | [Cache config](#cache-subsection) | `lifetime: 1m`
`size: 100000` | Cache which stores owner to cache operation mapping. | | `morph_policy` | [Cache config](#cache-subsection) | `lifetime: 1m`
`size: 10000` | Cache which stores list of policy chains. | | `frostfsid` | [Cache config](#cache-subsection) | `lifetime: 1m`
`size: 10000` | Cache which stores FrostfsID subject info. | +| `network_info` | [Cache config](#cache-subsection) | `lifetime: 1m` | Cache which stores network info. | #### `cache` subsection diff --git a/internal/logs/logs.go b/internal/logs/logs.go index 24abb0fe..cbcbfbbd 100644 --- a/internal/logs/logs.go +++ b/internal/logs/logs.go @@ -169,4 +169,5 @@ const ( WarnValueVHSEnabledFlagWrongType = "the value of the VHS enable flag for the namespace is of the wrong type, config value skipped" WarnDomainContainsInvalidPlaceholder = "the domain contains an invalid placeholder, domain skipped" FailedToRemoveOldPartNode = "failed to remove old part node" + CouldntCacheNetworkInfo = "couldn't cache network info" )