github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/service/application_metadata_cache.go (about) 1 package service 2 3 import ( 4 "context" 5 "reflect" 6 "time" 7 8 "github.com/pyroscope-io/pyroscope/pkg/model/appmetadata" 9 ) 10 11 type ApplicationMetadataWriter interface { 12 CreateOrUpdate(ctx context.Context, application appmetadata.ApplicationMetadata) error 13 } 14 15 type ApplicationMetadataCacheService struct { 16 appSvc ApplicationMetadataWriter 17 cache *cache 18 } 19 20 type ApplicationMetadataCacheServiceConfig struct { 21 Size int 22 TTL time.Duration 23 } 24 25 func NewApplicationMetadataCacheService(config ApplicationMetadataCacheServiceConfig, appSvc ApplicationMetadataWriter) *ApplicationMetadataCacheService { 26 if config.Size <= 0 { 27 config.Size = 1000 28 } 29 30 if config.TTL <= 0 { 31 config.TTL = 5 * time.Minute 32 } 33 34 cache := newCache(config.Size, config.TTL) 35 return &ApplicationMetadataCacheService{appSvc: appSvc, cache: cache} 36 } 37 38 // CreateOrUpdate delegates to the underlying service in the following cases: 39 // * item is not in the cache 40 // * data is different from what's in the cache 41 // Otherwise it does nothing 42 func (svc *ApplicationMetadataCacheService) CreateOrUpdate(ctx context.Context, application appmetadata.ApplicationMetadata) error { 43 if cachedApp, ok := svc.cache.get(application.FQName); ok { 44 if !svc.isTheSame(application, cachedApp.(appmetadata.ApplicationMetadata)) { 45 return svc.writeToBoth(ctx, application) 46 } 47 return nil 48 } 49 50 // Not in cache 51 // Could be due to TTL 52 // Or could it be that's a new app 53 return svc.writeToBoth(ctx, application) 54 } 55 56 // writeToBoth writes to both the cache and the underlying service 57 func (svc *ApplicationMetadataCacheService) writeToBoth(ctx context.Context, application appmetadata.ApplicationMetadata) error { 58 if err := svc.appSvc.CreateOrUpdate(ctx, application); err != nil { 59 return err 60 } 61 svc.cache.put(application.FQName, application) 62 return nil 63 } 64 65 // isTheSame check if 2 applications have the same data 66 // TODO(eh-am): update to a more robust comparison function 67 // See https://pkg.go.dev/reflect#DeepEqual for its drawbacks 68 func (*ApplicationMetadataCacheService) isTheSame(app1 appmetadata.ApplicationMetadata, app2 appmetadata.ApplicationMetadata) bool { 69 return reflect.DeepEqual(app1, app2) 70 }