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"
)