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{}