119 lines
3.1 KiB
Go
119 lines
3.1 KiB
Go
package cache
|
|
|
|
import (
|
|
"context"
|
|
|
|
"forge.cadoles.com/arcad/edge/pkg/storage"
|
|
"forge.cadoles.com/arcad/edge/pkg/storage/driver/cache/lfu"
|
|
"github.com/pkg/errors"
|
|
"gitlab.com/wpetit/goweb/logger"
|
|
)
|
|
|
|
type BlobStore struct {
|
|
store storage.BlobStore
|
|
blobCache *lfu.Cache[string, []byte]
|
|
bucketCache *lfu.Cache[string, storage.BlobBucket]
|
|
blobInfoCache *lfu.Cache[string, storage.BlobInfo]
|
|
}
|
|
|
|
// DeleteBucket implements storage.BlobStore.
|
|
func (s *BlobStore) DeleteBucket(ctx context.Context, name string) error {
|
|
if err := s.store.DeleteBucket(ctx, name); err != nil {
|
|
return errors.WithStack(err)
|
|
}
|
|
|
|
s.bucketCache.Delete(name)
|
|
|
|
return nil
|
|
}
|
|
|
|
// ListBuckets implements storage.BlobStore.
|
|
func (s *BlobStore) ListBuckets(ctx context.Context) ([]string, error) {
|
|
buckets, err := s.store.ListBuckets(ctx)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
return buckets, nil
|
|
}
|
|
|
|
// OpenBucket implements storage.BlobStore.
|
|
func (s *BlobStore) OpenBucket(ctx context.Context, name string) (storage.BlobBucket, error) {
|
|
bucket, err := s.bucketCache.Get(name)
|
|
if err == nil {
|
|
logger.Debug(ctx, "found bucket in cache", logger.F("name", name))
|
|
|
|
return &BlobBucket{
|
|
bucket: bucket,
|
|
blobCache: s.blobCache,
|
|
blobInfoCache: s.blobInfoCache,
|
|
bucketCache: s.bucketCache,
|
|
}, nil
|
|
}
|
|
|
|
if err != nil && !errors.Is(err, lfu.ErrNotFound) {
|
|
logger.Error(ctx, "could not retrieve bucket from cache",
|
|
logger.F("cacheKey", name),
|
|
logger.CapturedE(errors.WithStack(err)),
|
|
)
|
|
}
|
|
|
|
bucket, err = s.store.OpenBucket(ctx, name)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
if err := s.bucketCache.Set(name, bucket); err != nil {
|
|
logger.Error(ctx, "could not set bucket in cache",
|
|
logger.F("cacheKey", name),
|
|
logger.CapturedE(errors.WithStack(err)),
|
|
)
|
|
}
|
|
|
|
return &BlobBucket{
|
|
bucket: bucket,
|
|
blobCache: s.blobCache,
|
|
blobInfoCache: s.blobInfoCache,
|
|
bucketCache: s.bucketCache,
|
|
}, nil
|
|
}
|
|
|
|
func NewBlobStore(store storage.BlobStore, funcs ...OptionFunc) (*BlobStore, error) {
|
|
options := NewOptions(funcs...)
|
|
|
|
blobCache := lfu.NewCache[string, []byte](
|
|
options.BlobCacheStore,
|
|
lfu.WithTTL[string, []byte](options.CacheTTL),
|
|
lfu.WithCapacity[string, []byte](options.BlobCacheSize),
|
|
lfu.WithGetValueSize[string, []byte](func(value []byte) (int, error) {
|
|
return len(value), nil
|
|
}),
|
|
)
|
|
|
|
blobBucketCache := lfu.NewCache[string, storage.BlobBucket](
|
|
options.BlobBucketCacheStore,
|
|
lfu.WithCapacity[string, storage.BlobBucket](options.BlobBucketCacheSize),
|
|
lfu.WithGetValueSize[string, storage.BlobBucket](func(value storage.BlobBucket) (int, error) {
|
|
return 1, nil
|
|
}),
|
|
)
|
|
|
|
blobInfoCache := lfu.NewCache[string, storage.BlobInfo](
|
|
options.BlobInfoCacheStore,
|
|
lfu.WithTTL[string, storage.BlobInfo](options.CacheTTL),
|
|
lfu.WithCapacity[string, storage.BlobInfo](options.BlobInfoCacheSize),
|
|
lfu.WithGetValueSize[string, storage.BlobInfo](func(value storage.BlobInfo) (int, error) {
|
|
return 1, nil
|
|
}),
|
|
)
|
|
|
|
return &BlobStore{
|
|
store: store,
|
|
blobCache: blobCache,
|
|
bucketCache: blobBucketCache,
|
|
blobInfoCache: blobInfoCache,
|
|
}, nil
|
|
}
|
|
|
|
var _ storage.BlobStore = &BlobStore{}
|