Cache Warmer now waits for Cache to be available

This commit is contained in:
Deluan 2020-10-31 00:35:20 -04:00
parent 145a5708ca
commit 58d6b0a84f
7 changed files with 42 additions and 20 deletions

View File

@ -52,7 +52,7 @@ func createScanner() scanner.Scanner {
dataStore := persistence.New()
artworkCache := core.GetImageCache()
artwork := core.NewArtwork(dataStore, artworkCache)
cacheWarmer := core.NewCacheWarmer(artwork)
cacheWarmer := core.NewCacheWarmer(artwork, artworkCache)
scannerScanner := scanner.New(dataStore, cacheWarmer)
return scannerScanner
}
@ -61,6 +61,7 @@ func createScanner() scanner.Scanner {
var allProviders = wire.NewSet(core.Set, subsonic.New, app.New, persistence.New)
// Scanner must be a Singleton
var (
onceScanner sync.Once
scannerInstance scanner.Scanner

View File

@ -10,6 +10,7 @@ import (
"github.com/deluan/navidrome/server/app"
"github.com/deluan/navidrome/server/subsonic"
"github.com/google/wire"
"sync"
)
var allProviders = wire.NewSet(

View File

@ -37,7 +37,7 @@ var _ = Describe("Artwork", func() {
conf.Server.DataFolder, _ = ioutil.TempDir("", "file_caches")
conf.Server.ImageCacheSize = "100MB"
cache := GetImageCache()
Eventually(func() bool { return cache.Ready() }).Should(BeTrue())
Eventually(func() bool { return cache.Ready(context.TODO()) }).Should(BeTrue())
artwork = NewArtwork(ds, cache)
})

View File

@ -23,7 +23,8 @@ type ReadFunc func(ctx context.Context, item Item) (io.Reader, error)
type FileCache interface {
Get(ctx context.Context, item Item) (*CachedStream, error)
Ready() bool
Ready(ctx context.Context) bool
Available(ctx context.Context) bool
}
func NewFileCache(name, cacheSize, cacheFolder string, maxItems int, getReader ReadFunc) *fileCache {
@ -67,13 +68,13 @@ type fileCache struct {
mutex *sync.RWMutex
}
func (fc *fileCache) Ready() bool {
func (fc *fileCache) Ready(ctx context.Context) bool {
fc.mutex.RLock()
defer fc.mutex.RUnlock()
return fc.ready
}
func (fc *fileCache) available(ctx context.Context) bool {
func (fc *fileCache) Available(ctx context.Context) bool {
fc.mutex.RLock()
defer fc.mutex.RUnlock()
@ -85,7 +86,7 @@ func (fc *fileCache) available(ctx context.Context) bool {
}
func (fc *fileCache) Get(ctx context.Context, arg Item) (*CachedStream, error) {
if !fc.available(ctx) {
if !fc.Available(ctx) {
reader, err := fc.getReader(ctx, arg)
if err != nil {
return nil, err

View File

@ -16,7 +16,7 @@ import (
// Call NewFileCache and wait for it to be ready
func callNewFileCache(name, cacheSize, cacheFolder string, maxItems int, getReader ReadFunc) *fileCache {
fc := NewFileCache(name, cacheSize, cacheFolder, maxItems, getReader)
Eventually(func() bool { return fc.Ready() }).Should(BeTrue())
Eventually(func() bool { return fc.Ready(context.TODO()) }).Should(BeTrue())
return fc
}

View File

@ -3,6 +3,7 @@ package core
import (
"context"
"io/ioutil"
"time"
"github.com/deluan/navidrome/conf"
"github.com/deluan/navidrome/core/pool"
@ -14,10 +15,11 @@ type CacheWarmer interface {
Flush(ctx context.Context)
}
func NewCacheWarmer(artwork Artwork) CacheWarmer {
func NewCacheWarmer(artwork Artwork, artworkCache ArtworkCache) CacheWarmer {
w := &warmer{
artwork: artwork,
albums: map[string]struct{}{},
artwork: artwork,
artworkCache: artworkCache,
albums: map[string]struct{}{},
}
p, err := pool.NewPool("artwork", 3, &artworkItem{}, w.execute)
if err != nil {
@ -30,9 +32,10 @@ func NewCacheWarmer(artwork Artwork) CacheWarmer {
}
type warmer struct {
pool *pool.Pool
artwork Artwork
albums map[string]struct{}
pool *pool.Pool
artwork Artwork
artworkCache ArtworkCache
albums map[string]struct{}
}
func (w *warmer) AddAlbum(ctx context.Context, albumID string) {
@ -42,15 +45,31 @@ func (w *warmer) AddAlbum(ctx context.Context, albumID string) {
w.albums[albumID] = struct{}{}
}
func (w *warmer) Flush(ctx context.Context) {
if conf.Server.DevPreCacheAlbumArtwork {
if w.pool == nil || len(w.albums) == 0 {
func (w *warmer) waitForCacheReady(ctx context.Context) {
tick := time.NewTicker(time.Second)
defer tick.Stop()
for {
<-tick.C
if w.artworkCache.Ready(ctx) {
return
}
log.Info(ctx, "Pre-caching album artworks", "numAlbums", len(w.albums))
for id := range w.albums {
w.pool.Submit(artworkItem{albumID: id})
}
}
func (w *warmer) Flush(ctx context.Context) {
w.waitForCacheReady(ctx)
if w.artworkCache.Available(ctx) {
if conf.Server.DevPreCacheAlbumArtwork {
if w.pool == nil || len(w.albums) == 0 {
return
}
log.Info(ctx, "Pre-caching album artworks", "numAlbums", len(w.albums))
for id := range w.albums {
w.pool.Submit(artworkItem{albumID: id})
}
}
} else {
log.Warn(ctx, "Pre-cache warmer is not available as ImageCache is DISABLED")
}
w.albums = map[string]struct{}{}
}

View File

@ -29,7 +29,7 @@ var _ = Describe("MediaStreamer", func() {
{ID: "123", Path: "tests/fixtures/test.mp3", Suffix: "mp3", BitRate: 128, Duration: 257.0},
})
testCache := GetTranscodingCache()
Eventually(func() bool { return testCache.Ready() }).Should(BeTrue())
Eventually(func() bool { return testCache.Ready(context.TODO()) }).Should(BeTrue())
streamer = NewMediaStreamer(ds, ffmpeg, testCache)
})