[#253] Add access box cache

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2021-09-08 10:08:56 +03:00 committed by Kirillov Denis
parent 7ad81c4d09
commit 951eb6fda8
7 changed files with 144 additions and 68 deletions

View file

@ -81,9 +81,9 @@ func (p prs) Seek(_ int64, _ int) (int64, error) {
var _ io.ReadSeeker = prs(0)
// New creates an instance of AuthCenter.
func New(conns pool.Pool, key *keys.PrivateKey) Center {
func New(conns pool.Pool, key *keys.PrivateKey, config *tokens.CacheConfig) Center {
return &center{
cli: tokens.New(conns, key),
cli: tokens.New(conns, key, config),
reg: &regexpSubmatcher{re: authorizationFieldRegexp},
postReg: &regexpSubmatcher{re: postPolicyCredentialRegexp},
}

View file

@ -226,7 +226,7 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
}
address, err := tokens.
New(a.pool, secrets.EphemeralKey).
New(a.pool, secrets.EphemeralKey, tokens.DefaultCacheConfig()).
Put(ctx, cid, oid, box, lifetime.Exp, options.GatesPublicKeys...)
if err != nil {
return fmt.Errorf("failed to put bearer token: %w", err)
@ -268,7 +268,7 @@ func (a *Agent) IssueSecret(ctx context.Context, w io.Writer, options *IssueSecr
// ObtainSecret receives an existing secret access key from NeoFS and
// writes to io.Writer the secret access key.
func (a *Agent) ObtainSecret(ctx context.Context, w io.Writer, options *ObtainSecretOptions) error {
bearerCreds := tokens.New(a.pool, options.GatePrivateKey)
bearerCreds := tokens.New(a.pool, options.GatePrivateKey, tokens.DefaultCacheConfig())
address := object.NewAddress()
if err := address.Parse(options.SecretAddress); err != nil {
return fmt.Errorf("failed to parse secret address: %w", err)

View file

@ -6,6 +6,7 @@ import (
"math"
"net"
"net/http"
"time"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-s3-gw/api"
@ -13,6 +14,7 @@ import (
"github.com/nspcc-dev/neofs-s3-gw/api/cache"
"github.com/nspcc-dev/neofs-s3-gw/api/handler"
"github.com/nspcc-dev/neofs-s3-gw/api/layer"
"github.com/nspcc-dev/neofs-s3-gw/creds/tokens"
"github.com/nspcc-dev/neofs-s3-gw/internal/wallet"
"github.com/nspcc-dev/neofs-sdk-go/policy"
"github.com/nspcc-dev/neofs-sdk-go/pool"
@ -116,7 +118,7 @@ func newApp(ctx context.Context, l *zap.Logger, v *viper.Viper) *App {
obj = layer.NewLayer(l, conns, cacheCfg)
// prepare auth center
ctr = auth.New(conns, key)
ctr = auth.New(conns, key, getAccessBoxCacheConfig(v, l))
handlerOptions := getHandlerOptions(v, l)
@ -222,53 +224,54 @@ func getCacheOptions(v *viper.Viper, l *zap.Logger) *layer.CacheConfig {
Lifetime: cache.DefaultObjectsCacheLifetime,
}
if v.IsSet(cfgObjectsCacheLifetime) {
lifetime := v.GetDuration(cfgObjectsCacheLifetime)
if lifetime <= 0 {
l.Error("invalid cache lifetime, using default value (in seconds)",
zap.Duration("value in config", lifetime),
zap.Duration("default", cacheCfg.Lifetime))
} else {
cacheCfg.Lifetime = lifetime
}
}
cacheCfg.Lifetime = getLifetime(v, l, cfgObjectsCacheLifetime, cacheCfg.Lifetime)
cacheCfg.Size = getSize(v, l, cfgObjectsCacheSize, cacheCfg.Size)
if v.IsSet(cfgCacheSize) {
size := v.GetInt(cfgCacheSize)
if size <= 0 {
l.Error("invalid cache size, using default value",
zap.Int("value in config", size),
zap.Int("default", cacheCfg.Size))
} else {
cacheCfg.Size = size
}
}
if v.IsSet(cfgListObjectsCacheLifetime) {
lifetime := v.GetDuration(cfgListObjectsCacheLifetime)
if lifetime <= 0 {
l.Error("invalid list objects cache lifetime, using default value (in seconds)",
zap.Duration("value in config", lifetime),
zap.Duration("default", cacheCfg.ListObjectsLifetime))
} else {
cacheCfg.ListObjectsLifetime = lifetime
}
}
if v.IsSet(cfgListObjectsCacheSize) {
size := v.GetInt(cfgListObjectsCacheSize)
if size <= 0 {
l.Error("invalid cache size, using default value",
zap.Int("value in config", size),
zap.Int("default", cacheCfg.ListObjectsSize))
} else {
cacheCfg.Size = size
}
}
cacheCfg.ListObjectsLifetime = getLifetime(v, l, cfgListObjectsCacheLifetime, cacheCfg.ListObjectsLifetime)
cacheCfg.ListObjectsSize = getSize(v, l, cfgListObjectsCacheSize, cacheCfg.ListObjectsSize)
return &cacheCfg
}
func getLifetime(v *viper.Viper, l *zap.Logger, cfgEntry string, defaultValue time.Duration) time.Duration {
if v.IsSet(cfgEntry) {
lifetime := v.GetDuration(cfgEntry)
if lifetime <= 0 {
l.Error("invalid lifetime, using default value (in seconds)",
zap.String("parameter", cfgEntry),
zap.Duration("value in config", lifetime),
zap.Duration("default", defaultValue))
} else {
return lifetime
}
}
return defaultValue
}
func getSize(v *viper.Viper, l *zap.Logger, cfgEntry string, defaultValue int) int {
if v.IsSet(cfgEntry) {
size := v.GetInt(cfgEntry)
if size <= 0 {
l.Error("invalid cache size, using default value",
zap.String("parameter", cfgEntry),
zap.Int("value in config", size),
zap.Int("default", defaultValue))
} else {
return size
}
}
return defaultValue
}
func getAccessBoxCacheConfig(v *viper.Viper, l *zap.Logger) *tokens.CacheConfig {
cacheCfg := tokens.DefaultCacheConfig()
cacheCfg.Lifetime = getLifetime(v, l, cfgAccessBoxCacheLifetime, cacheCfg.Lifetime)
cacheCfg.Size = getSize(v, l, cfgAccessBoxCacheSize, cacheCfg.Size)
return cacheCfg
}
func getHandlerOptions(v *viper.Viper, l *zap.Logger) *handler.Config {
var (
cfg handler.Config

View file

@ -55,10 +55,12 @@ const ( // Settings.
cfgRebalanceTimer = "rebalance_timer"
// Caching.
cfgObjectsCacheLifetime = "cache.lifetime"
cfgCacheSize = "cache.size"
cfgListObjectsCacheLifetime = "cache.list_objects_lifetime"
cfgListObjectsCacheSize = "cache.list_objects_size"
cfgObjectsCacheLifetime = "cache.objects.lifetime"
cfgObjectsCacheSize = "cache.objects.size"
cfgListObjectsCacheLifetime = "cache.list.lifetime"
cfgListObjectsCacheSize = "cache.list.size"
cfgAccessBoxCacheLifetime = "cache.accessbox.lifetime"
cfgAccessBoxCacheSize = "cache.accessbox.size"
// Policy.
cfgDefaultPolicy = "default_policy"

View file

@ -0,0 +1,59 @@
package tokens
import (
"time"
"github.com/bluele/gcache"
"github.com/nspcc-dev/neofs-api-go/pkg/object"
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
)
const (
// DefaultCacheSize is a default maximum number of entries in cache.
DefaultCacheSize = 100
// DefaultCacheLifetime is a default lifetime of entries in cache.
DefaultCacheLifetime = 10 * time.Minute
)
// CacheConfig stores expiration params for cache.
type CacheConfig struct {
Size int
Lifetime time.Duration
}
// DefaultCacheConfig return new default cache expiration values.
func DefaultCacheConfig() *CacheConfig {
return &CacheConfig{Size: DefaultCacheSize, Lifetime: DefaultCacheLifetime}
}
// AccessBoxCache stores access box by its address.
type AccessBoxCache struct {
cache gcache.Cache
}
// NewAccessBoxCache creates an object of BucketCache.
func NewAccessBoxCache(config *CacheConfig) *AccessBoxCache {
gc := gcache.New(config.Size).LRU().Expiration(config.Lifetime).Build()
return &AccessBoxCache{cache: gc}
}
// Get returns cached object.
func (o *AccessBoxCache) Get(address *object.Address) *accessbox.Box {
entry, err := o.cache.Get(address.String())
if err != nil {
return nil
}
result, ok := entry.(*accessbox.Box)
if !ok {
return nil
}
return result
}
// Put stores an object to cache.
func (o *AccessBoxCache) Put(address *object.Address, box *accessbox.Box) error {
return o.cache.Set(address.String(), box)
}

View file

@ -25,8 +25,9 @@ type (
}
cred struct {
key *keys.PrivateKey
pool pool.Pool
key *keys.PrivateKey
pool pool.Pool
cache *AccessBoxCache
}
)
@ -46,8 +47,8 @@ var bufferPool = sync.Pool{
var _ = New
// New creates new Credentials instance using given cli and key.
func New(conns pool.Pool, key *keys.PrivateKey) Credentials {
return &cred{pool: conns, key: key}
func New(conns pool.Pool, key *keys.PrivateKey, config *CacheConfig) Credentials {
return &cred{pool: conns, key: key, cache: NewAccessBoxCache(config)}
}
func (c *cred) acquireBuffer() *bytes.Buffer {
@ -59,22 +60,27 @@ func (c *cred) releaseBuffer(buf *bytes.Buffer) {
bufferPool.Put(buf)
}
func (c *cred) GetTokens(ctx context.Context, address *object.Address) (*accessbox.GateData, error) {
box, err := c.getAccessBox(ctx, address)
if err != nil {
return nil, err
}
return box.GetTokens(c.key)
}
func (c *cred) GetBox(ctx context.Context, address *object.Address) (*accessbox.Box, error) {
cachedBox := c.cache.Get(address)
if cachedBox != nil {
return cachedBox, nil
}
box, err := c.getAccessBox(ctx, address)
if err != nil {
return nil, err
}
return box.GetBox(c.key)
cachedBox, err = box.GetBox(c.key)
if err != nil {
return nil, err
}
if err = c.cache.Put(address, cachedBox); err != nil {
return nil, err
}
return cachedBox, nil
}
func (c *cred) getAccessBox(ctx context.Context, address *object.Address) (*accessbox.AccessBox, error) {

View file

@ -108,8 +108,14 @@ If the value is not set at all it will be set as `REP 3`.
Parameters for caches in s3-gw can be specified in a .yaml config file. E.g.:
```
cache:
lifetime: 300s
size: 150
list_objects_lifetime: 1m
objects:
lifetime: 300s
size: 150
list:
lifetime: 1m
size: 100
accessbox:
lifetime: 5m
size: 10
```
If invalid values are set, the gateway will use default values instead.