forked from TrueCloudLab/frostfs-s3-gw
[#253] Add access box cache
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
7ad81c4d09
commit
951eb6fda8
7 changed files with 144 additions and 68 deletions
|
@ -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 ¢er{
|
||||
cli: tokens.New(conns, key),
|
||||
cli: tokens.New(conns, key, config),
|
||||
reg: ®expSubmatcher{re: authorizationFieldRegexp},
|
||||
postReg: ®expSubmatcher{re: postPolicyCredentialRegexp},
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
59
creds/tokens/accessbox_cache.go
Normal file
59
creds/tokens/accessbox_cache.go
Normal 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)
|
||||
}
|
|
@ -27,6 +27,7 @@ type (
|
|||
cred struct {
|
||||
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) {
|
||||
|
|
|
@ -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:
|
||||
objects:
|
||||
lifetime: 300s
|
||||
size: 150
|
||||
list_objects_lifetime: 1m
|
||||
list:
|
||||
lifetime: 1m
|
||||
size: 100
|
||||
accessbox:
|
||||
lifetime: 5m
|
||||
size: 10
|
||||
```
|
||||
If invalid values are set, the gateway will use default values instead.
|
||||
|
|
Loading…
Reference in a new issue