package cache import ( "context" "fmt" "net/url" "strconv" "time" "forge.cadoles.com/arcad/edge/pkg/storage" "forge.cadoles.com/arcad/edge/pkg/storage/driver" "github.com/allegro/bigcache/v3" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) func init() { driver.RegisterBlobStoreFactory("cache", blobStoreFactory) } func blobStoreFactory(dsn *url.URL) (storage.BlobStore, error) { query := dsn.Query() rawDriver := query.Get("driver") if rawDriver == "" { return nil, errors.New("missing required url parameter 'driver'") } query.Del("driver") cacheTTL := time.Minute * 60 rawCacheTTL := query.Get("cacheTTL") if rawCacheTTL != "" { query.Del("cacheTTL") ttl, err := time.ParseDuration(rawCacheTTL) if err != nil { return nil, errors.Wrap(err, "could not parse url parameter 'cacheTTL'") } cacheTTL = ttl } cacheConfig := bigcache.DefaultConfig(cacheTTL) cacheConfig.Logger = &cacheLogger{} rawCacheShards := query.Get("cacheShards") if rawCacheShards != "" { query.Del("cacheShards") cacheShards, err := strconv.ParseInt(rawCacheShards, 10, 32) if err != nil { return nil, errors.Wrap(err, "could not parse url parameter 'cacheShards'") } cacheConfig.Shards = int(cacheShards) } rawMaxCacheSize := query.Get("maxCacheSize") if rawMaxCacheSize != "" { query.Del("maxCacheSize") maxCacheSize, err := strconv.ParseInt(rawMaxCacheSize, 10, 32) if err != nil { return nil, errors.Wrap(err, "could not parse url parameter 'maxCacheSize'") } // See cacheConfig.HardMaxCacheSize documentation var minCacheSize int64 = (2 * (64 + 32) * int64(cacheConfig.Shards)) / 1000 if maxCacheSize < minCacheSize { return nil, errors.Errorf("max cache size can not be set to a value below '%d'", minCacheSize) } cacheConfig.HardMaxCacheSize = int(maxCacheSize) } url := &url.URL{ Scheme: rawDriver, Host: dsn.Host, Path: dsn.Path, RawQuery: query.Encode(), } store, err := driver.NewBlobStore(url.String()) if err != nil { return nil, errors.WithStack(err) } cache, err := bigcache.New(context.Background(), cacheConfig) if err != nil { return nil, errors.WithStack(err) } return NewBlobStore(store, cache), nil } type cacheLogger struct{} func (l *cacheLogger) Printf(format string, v ...interface{}) { logger.Debug(context.Background(), fmt.Sprintf(format, v...)) } var _ bigcache.Logger = &cacheLogger{}