frostfs-s3-gw/api/layer/object_cache.go
Angira Kekteeva 8a69c7cca0 [#179] api: Add cache for ListObjectsV1/V2
Refactored cache for ListObjects:
made cache common for all versions,
simplified: remove dependendence on token/startafter
add mitable cachelifetime.

Refactored listobjects

Signed-off-by: Angira Kekteeva <kira@nspcc.ru>
2021-08-09 13:52:11 +03:00

92 lines
2.1 KiB
Go

package layer
import (
"context"
"sync"
"time"
cid "github.com/nspcc-dev/neofs-api-go/pkg/container/id"
)
/*
This is an implementation of a cache for ListObjectsV2/V1 which we can return to users when we receive a ListObjects
request.
The cache is a map which has a key: cacheOptions struct and a value: list of objects. After putting a record we
start a timer (via time.AfterFunc) that removes the record after defaultCacheLifetime value.
When we get a request from the user we just try to find the suitable and non-expired cache and then we return
the list of objects. Otherwise we send the request to NeoFS.
*/
// ObjectsListCache provides interface for cache of ListObjectsV2 in a layer struct.
type (
ObjectsListCache interface {
Get(key cacheOptions) []*ObjectInfo
Put(key cacheOptions, objects []*ObjectInfo)
}
)
const defaultCacheLifetime = time.Second * 60
type (
listObjectsCache struct {
cacheLifetime time.Duration
caches map[cacheOptions]cache
mtx sync.RWMutex
}
cache struct {
list []*ObjectInfo
}
cacheOptions struct {
key string
delimiter string
prefix string
}
)
func newListObjectsCache(lifetime time.Duration) *listObjectsCache {
return &listObjectsCache{
caches: make(map[cacheOptions]cache),
cacheLifetime: lifetime,
}
}
func (l *listObjectsCache) Get(key cacheOptions) []*ObjectInfo {
l.mtx.RLock()
defer l.mtx.RUnlock()
if val, ok := l.caches[key]; ok {
return val.list
}
return nil
}
func (l *listObjectsCache) Put(key cacheOptions, objects []*ObjectInfo) {
if len(objects) == 0 {
return
}
var c cache
l.mtx.Lock()
defer l.mtx.Unlock()
c.list = objects
l.caches[key] = c
time.AfterFunc(l.cacheLifetime, func() {
l.mtx.Lock()
delete(l.caches, key)
l.mtx.Unlock()
})
}
func createKey(ctx context.Context, cid *cid.ID, prefix, delimiter string) (cacheOptions, error) {
box, err := GetBoxData(ctx)
if err != nil {
return cacheOptions{}, err
}
p := cacheOptions{
key: box.Gate.AccessKey + cid.String(),
delimiter: delimiter,
prefix: prefix,
}
return p, nil
}