From 14032a524bc88ae383b0372e2980ca94350961b0 Mon Sep 17 00:00:00 2001 From: Deluan Date: Wed, 28 Dec 2022 13:03:41 -0500 Subject: [PATCH] Reduce retention in CacheWarmer --- core/artwork/cache_warmer.go | 56 +++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/core/artwork/cache_warmer.go b/core/artwork/cache_warmer.go index a3ef8d8af..0ad337470 100644 --- a/core/artwork/cache_warmer.go +++ b/core/artwork/cache_warmer.go @@ -4,10 +4,13 @@ import ( "context" "fmt" "io" + "sync" + "time" "github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" + "github.com/navidrome/navidrome/model/request" "github.com/navidrome/navidrome/utils/pl" ) @@ -22,24 +25,63 @@ func NewCacheWarmer(artwork Artwork) CacheWarmer { } a := &cacheWarmer{ - artwork: artwork, - input: make(chan string), + artwork: artwork, + wakeSignal: make(chan struct{}, 1), } - go a.run(context.TODO()) + + // Create a context with a fake admin user, to be able to pre-cache Playlist CoverArts + ctx := request.WithUser(context.TODO(), model.User{IsAdmin: true}) + go a.run(ctx) return a } type cacheWarmer struct { - artwork Artwork - input chan string + artwork Artwork + buffer []string + mutex sync.Mutex + wakeSignal chan struct{} } func (a *cacheWarmer) PreCache(artID model.ArtworkID) { - a.input <- artID.String() + a.mutex.Lock() + defer a.mutex.Unlock() + a.buffer = append(a.buffer, artID.String()) + a.sendWakeSignal() +} + +func (a *cacheWarmer) sendWakeSignal() { + // Don't block if the previous signal was not read yet + select { + case a.wakeSignal <- struct{}{}: + default: + } } func (a *cacheWarmer) run(ctx context.Context) { - errs := pl.Sink(ctx, 2, a.input, a.doCacheImage) + for { + time.AfterFunc(5*time.Second, func() { + a.sendWakeSignal() + }) + <-a.wakeSignal + + a.mutex.Lock() + var batch []string + if len(a.buffer) > 0 { + batch = a.buffer + a.buffer = nil + } + a.mutex.Unlock() + + if len(batch) > 0 { + a.processBatch(ctx, batch) + } + } +} + +func (a *cacheWarmer) processBatch(ctx context.Context, batch []string) { + log.Trace(ctx, "PreCaching a new batch of artwork", "batchSize", len(batch)) + input := pl.FromSlice(ctx, batch) + errs := pl.Sink(ctx, 2, input, a.doCacheImage) for err := range errs { log.Warn(ctx, "Error warming cache", err) }