2021-08-27 22:20:40 +00:00
|
|
|
package cache
|
|
|
|
|
|
|
|
import (
|
2021-09-01 16:10:31 +00:00
|
|
|
"fmt"
|
2022-10-03 14:33:49 +00:00
|
|
|
"strconv"
|
2021-09-01 16:10:52 +00:00
|
|
|
"strings"
|
2021-08-27 22:20:40 +00:00
|
|
|
"time"
|
|
|
|
|
2023-03-07 14:38:08 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
2023-08-23 11:07:52 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
2023-03-07 14:38:08 +00:00
|
|
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
2021-09-01 16:10:31 +00:00
|
|
|
"github.com/bluele/gcache"
|
2022-06-06 08:01:12 +00:00
|
|
|
"go.uber.org/zap"
|
2021-08-27 22:20:40 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
/*
|
2022-04-13 16:56:58 +00:00
|
|
|
This is an implementation of cache which keeps unsorted lists of objects' IDs (all versions)
|
2021-09-01 22:50:01 +00:00
|
|
|
for a specified bucket and a prefix.
|
2021-08-27 22:20:40 +00:00
|
|
|
|
2021-09-01 22:50:01 +00:00
|
|
|
The cache contains gcache whose entries have a key: ObjectsListKey struct and a value: list of ids.
|
2022-04-13 16:56:58 +00:00
|
|
|
After putting a record, it lives for a while (default value is 60 seconds).
|
2021-08-27 22:20:40 +00:00
|
|
|
|
2022-04-13 16:56:58 +00:00
|
|
|
When we receive a request from a user, we try to find the suitable and non-expired cache entry, go through the list
|
2022-12-20 08:38:58 +00:00
|
|
|
and get ObjectInfos from common object cache or with a request to FrostFS.
|
2021-09-01 22:50:01 +00:00
|
|
|
|
2022-04-13 16:56:58 +00:00
|
|
|
When we put an object into a container, we invalidate entries with prefixes that are prefixes of the object's name.
|
2021-08-27 22:20:40 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
type (
|
2021-09-10 06:56:56 +00:00
|
|
|
// ObjectsListCache contains cache for ListObjects and ListObjectVersions.
|
|
|
|
ObjectsListCache struct {
|
2022-06-06 08:01:12 +00:00
|
|
|
cache gcache.Cache
|
|
|
|
logger *zap.Logger
|
2021-09-10 06:56:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ObjectsListKey is a key to find a ObjectsListCache's entry.
|
|
|
|
ObjectsListKey struct {
|
2022-06-28 12:56:41 +00:00
|
|
|
cid cid.ID
|
2022-05-20 08:26:35 +00:00
|
|
|
prefix string
|
|
|
|
latestOnly bool
|
2021-08-27 22:20:40 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2021-09-01 16:10:31 +00:00
|
|
|
// DefaultObjectsListCacheLifetime is a default lifetime of entries in cache of ListObjects.
|
|
|
|
DefaultObjectsListCacheLifetime = time.Second * 60
|
|
|
|
// DefaultObjectsListCacheSize is a default size of cache of ListObjects.
|
|
|
|
DefaultObjectsListCacheSize = 1e5
|
2021-08-27 22:20:40 +00:00
|
|
|
)
|
|
|
|
|
2022-04-13 16:56:58 +00:00
|
|
|
// DefaultObjectsListConfig returns new default cache expiration values.
|
2022-06-06 08:01:12 +00:00
|
|
|
func DefaultObjectsListConfig(logger *zap.Logger) *Config {
|
|
|
|
return &Config{
|
|
|
|
Size: DefaultObjectsListCacheSize,
|
|
|
|
Lifetime: DefaultObjectsListCacheLifetime,
|
|
|
|
Logger: logger,
|
|
|
|
}
|
2021-09-10 06:56:56 +00:00
|
|
|
}
|
2021-08-27 22:20:40 +00:00
|
|
|
|
2022-10-03 14:33:49 +00:00
|
|
|
func (k *ObjectsListKey) String() string {
|
|
|
|
return k.cid.EncodeToString() + k.prefix + strconv.FormatBool(k.latestOnly)
|
|
|
|
}
|
|
|
|
|
2022-04-13 16:56:58 +00:00
|
|
|
// NewObjectsListCache is a constructor which creates an object of ListObjectsCache with the given lifetime of entries.
|
2021-09-10 06:56:56 +00:00
|
|
|
func NewObjectsListCache(config *Config) *ObjectsListCache {
|
|
|
|
gc := gcache.New(config.Size).LRU().Expiration(config.Lifetime).Build()
|
2022-06-06 08:01:12 +00:00
|
|
|
return &ObjectsListCache{cache: gc, logger: config.Logger}
|
2021-08-27 22:20:40 +00:00
|
|
|
}
|
|
|
|
|
2022-05-20 15:02:00 +00:00
|
|
|
// GetVersions returns a list of ObjectInfo.
|
|
|
|
func (l *ObjectsListCache) GetVersions(key ObjectsListKey) []*data.NodeVersion {
|
|
|
|
entry, err := l.cache.Get(key)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
result, ok := entry.([]*data.NodeVersion)
|
|
|
|
if !ok {
|
2023-08-23 11:07:52 +00:00
|
|
|
l.logger.Warn(logs.InvalidCacheEntryType, zap.String("actual", fmt.Sprintf("%T", entry)),
|
2022-10-24 14:44:11 +00:00
|
|
|
zap.String("expected", fmt.Sprintf("%T", result)))
|
2022-05-20 15:02:00 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
// PutVersions puts a list of object versions to cache.
|
|
|
|
func (l *ObjectsListCache) PutVersions(key ObjectsListKey, versions []*data.NodeVersion) error {
|
|
|
|
return l.cache.Set(key, versions)
|
|
|
|
}
|
|
|
|
|
2021-09-01 16:10:52 +00:00
|
|
|
// CleanCacheEntriesContainingObject deletes entries containing specified object.
|
2022-05-25 17:25:43 +00:00
|
|
|
func (l *ObjectsListCache) CleanCacheEntriesContainingObject(objectName string, cnr cid.ID) {
|
2021-09-01 16:10:52 +00:00
|
|
|
keys := l.cache.Keys(true)
|
|
|
|
for _, key := range keys {
|
|
|
|
k, ok := key.(ObjectsListKey)
|
|
|
|
if !ok {
|
2023-08-23 11:07:52 +00:00
|
|
|
l.logger.Warn(logs.InvalidCacheKeyType, zap.String("actual", fmt.Sprintf("%T", key)),
|
2022-06-06 12:03:51 +00:00
|
|
|
zap.String("expected", fmt.Sprintf("%T", k)))
|
2021-09-01 16:10:52 +00:00
|
|
|
continue
|
|
|
|
}
|
2022-06-28 12:56:41 +00:00
|
|
|
if cnr.Equals(k.cid) && strings.HasPrefix(objectName, k.prefix) {
|
2021-09-01 16:10:52 +00:00
|
|
|
l.cache.Remove(k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-20 08:26:35 +00:00
|
|
|
// CreateObjectsListCacheKey returns ObjectsListKey with the given CID, prefix and latestOnly flag.
|
2022-06-27 09:08:26 +00:00
|
|
|
func CreateObjectsListCacheKey(cnr cid.ID, prefix string, latestOnly bool) ObjectsListKey {
|
2021-08-27 22:20:40 +00:00
|
|
|
p := ObjectsListKey{
|
2022-06-28 12:56:41 +00:00
|
|
|
cid: cnr,
|
2022-05-20 08:26:35 +00:00
|
|
|
prefix: prefix,
|
|
|
|
latestOnly: latestOnly,
|
2021-08-27 22:20:40 +00:00
|
|
|
}
|
|
|
|
|
2021-09-01 16:10:31 +00:00
|
|
|
return p
|
2021-08-27 22:20:40 +00:00
|
|
|
}
|