edge/pkg/storage/driver/cache/blob_store.go

99 lines
2.6 KiB
Go

package cache
import (
"context"
"forge.cadoles.com/arcad/edge/pkg/storage"
"github.com/allegro/bigcache/v3"
"github.com/hashicorp/golang-lru/v2/expirable"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type BlobStore struct {
store storage.BlobStore
contentCache *bigcache.BigCache
bucketCache *expirable.LRU[string, storage.BlobBucket]
blobInfoCache *expirable.LRU[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.Remove(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, ok := s.bucketCache.Get(name)
if ok {
logger.Debug(ctx, "found bucket in cache", logger.F("name", name))
return &BlobBucket{
bucket: bucket,
contentCache: s.contentCache,
blobInfoCache: s.blobInfoCache,
bucketCache: s.bucketCache,
}, nil
}
bucket, err := s.store.OpenBucket(ctx, name)
if err != nil {
return nil, errors.WithStack(err)
}
s.bucketCache.Add(name, bucket)
return &BlobBucket{
bucket: bucket,
contentCache: s.contentCache,
blobInfoCache: s.blobInfoCache,
bucketCache: s.bucketCache,
}, nil
}
func NewBlobStore(store storage.BlobStore, funcs ...OptionFunc) (*BlobStore, error) {
options := NewOptions(funcs...)
contentCache, err := bigcache.New(context.Background(), options.BigCache)
if err != nil {
return nil, errors.WithStack(err)
}
onBlobBucketEvict := func(key string, bucket storage.BlobBucket) {
ctx := context.Background()
logger.Debug(ctx, "evicting blob bucket from cache", logger.F("cacheKey", key))
if err := bucket.Close(); err != nil {
logger.Error(ctx, "could not close bucket", logger.E(errors.WithStack(err)))
}
}
bucketCache := expirable.NewLRU[string, storage.BlobBucket](options.BucketCacheSize, onBlobBucketEvict, options.CacheTTL)
blobInfoCache := expirable.NewLRU[string, storage.BlobInfo](options.BlobInfoCacheSize, nil, options.CacheTTL)
return &BlobStore{
store: store,
contentCache: contentCache,
bucketCache: bucketCache,
blobInfoCache: blobInfoCache,
}, nil
}
var _ storage.BlobStore = &BlobStore{}