Fix mutexes in the cacher
This commit is contained in:
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
FROM docker.io/alpine AS builder
|
||||||
|
|
||||||
|
LABEL maintainer="vladimir@hodakov.me"
|
||||||
|
|
||||||
|
COPY . /src
|
||||||
|
|
||||||
|
RUN apk add --no-cache go
|
||||||
|
|
||||||
|
RUN cd /src && go build ./cmd/faketunes
|
||||||
|
|
||||||
|
FROM docker.io/alpine
|
||||||
|
|
||||||
|
RUN apk add --no-cache fuse3 ffmpeg
|
||||||
|
|
||||||
|
COPY --from=builder /src/faketunes /bin/faketunes
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/bin/faketunes" ]
|
||||||
@@ -20,17 +20,18 @@ type Cacher struct {
|
|||||||
transcoder domains.Transcoder
|
transcoder domains.Transcoder
|
||||||
|
|
||||||
cacheDir string
|
cacheDir string
|
||||||
cacheMutex sync.RWMutex
|
|
||||||
currentSize int64
|
currentSize int64
|
||||||
maxSize int64
|
maxSize int64
|
||||||
items map[string]*models.CacheItem
|
items map[string]*models.CacheItem
|
||||||
|
itemsMutex sync.RWMutex
|
||||||
stat map[string]*models.CacherStat
|
stat map[string]*models.CacherStat
|
||||||
|
statMutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(app *application.App) *Cacher {
|
func New(app *application.App) *Cacher {
|
||||||
return &Cacher{
|
return &Cacher{
|
||||||
app: app,
|
app: app,
|
||||||
cacheDir: app.Config().Paths.Destination + "./.cache",
|
cacheDir: app.Config().Paths.Destination + "/.cache",
|
||||||
maxSize: app.Config().FakeTunes.CacheSize * 1024 * 1024,
|
maxSize: app.Config().FakeTunes.CacheSize * 1024 * 1024,
|
||||||
items: make(map[string]*models.CacheItem, 0),
|
items: make(map[string]*models.CacheItem, 0),
|
||||||
stat: make(map[string]*models.CacherStat, 0),
|
stat: make(map[string]*models.CacherStat, 0),
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ func (c *Cacher) GetFileDTO(sourcePath string) (*dto.CacheItem, error) {
|
|||||||
return nil, fmt.Errorf("%w: %w (%w)", ErrCacher, ErrFailedToGetSourceFile, err)
|
return nil, fmt.Errorf("%w: %w (%w)", ErrCacher, ErrFailedToGetSourceFile, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.app.Logger().WithField("item", item).Debug("Retrieved cache item")
|
||||||
|
|
||||||
return models.CacheItemModelToDTO(item), nil
|
return models.CacheItemModelToDTO(item), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,8 +34,8 @@ func (c *Cacher) getFile(sourcePath string) (*models.CacheItem, error) {
|
|||||||
cacheKey := fmt.Sprintf("%x", hash)
|
cacheKey := fmt.Sprintf("%x", hash)
|
||||||
cacheFilePath := filepath.Join(c.cacheDir, cacheKey+".m4a")
|
cacheFilePath := filepath.Join(c.cacheDir, cacheKey+".m4a")
|
||||||
|
|
||||||
c.cacheMutex.Lock()
|
c.itemsMutex.Lock()
|
||||||
defer c.cacheMutex.Unlock()
|
defer c.itemsMutex.Unlock()
|
||||||
|
|
||||||
// Check if file information exists in cache
|
// Check if file information exists in cache
|
||||||
if item, ok := c.items[cacheKey]; ok {
|
if item, ok := c.items[cacheKey]; ok {
|
||||||
@@ -92,7 +94,7 @@ func (c *Cacher) getFile(sourcePath string) (*models.CacheItem, error) {
|
|||||||
|
|
||||||
c.updateCachedStat(sourcePath, size)
|
c.updateCachedStat(sourcePath, size)
|
||||||
// TODO: run cleanup on inotify events.
|
// TODO: run cleanup on inotify events.
|
||||||
c.cleanup()
|
// c.cleanup()
|
||||||
|
|
||||||
return item, nil
|
return item, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ import (
|
|||||||
|
|
||||||
// getStat returns file size without triggering conversion (for ls/stat)
|
// getStat returns file size without triggering conversion (for ls/stat)
|
||||||
func (c *Cacher) GetStat(sourcePath string) (int64, error) {
|
func (c *Cacher) GetStat(sourcePath string) (int64, error) {
|
||||||
|
c.statMutex.RLock()
|
||||||
|
defer c.statMutex.RUnlock()
|
||||||
|
|
||||||
// First check cache
|
// First check cache
|
||||||
if size, ok := c.getCachedStat(sourcePath); ok {
|
if size, ok := c.getCachedStat(sourcePath); ok {
|
||||||
return size, nil
|
return size, nil
|
||||||
@@ -43,8 +46,8 @@ func (c *Cacher) GetStat(sourcePath string) (int64, error) {
|
|||||||
|
|
||||||
// updateCachedStat updates the stat cache
|
// updateCachedStat updates the stat cache
|
||||||
func (c *Cacher) updateCachedStat(sourcePath string, size int64) {
|
func (c *Cacher) updateCachedStat(sourcePath string, size int64) {
|
||||||
c.cacheMutex.Lock()
|
c.statMutex.Lock()
|
||||||
defer c.cacheMutex.Unlock()
|
defer c.statMutex.Unlock()
|
||||||
|
|
||||||
c.stat[sourcePath] = &models.CacherStat{
|
c.stat[sourcePath] = &models.CacherStat{
|
||||||
Size: size,
|
Size: size,
|
||||||
@@ -54,8 +57,8 @@ func (c *Cacher) updateCachedStat(sourcePath string, size int64) {
|
|||||||
|
|
||||||
// getCachedStat returns cached file stats
|
// getCachedStat returns cached file stats
|
||||||
func (c *Cacher) getCachedStat(sourcePath string) (int64, bool) {
|
func (c *Cacher) getCachedStat(sourcePath string) (int64, bool) {
|
||||||
c.cacheMutex.RLock()
|
c.statMutex.RLock()
|
||||||
defer c.cacheMutex.RUnlock()
|
defer c.statMutex.RUnlock()
|
||||||
|
|
||||||
if stat, ok := c.stat[sourcePath]; ok {
|
if stat, ok := c.stat[sourcePath]; ok {
|
||||||
return stat.Size, true
|
return stat.Size, true
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package filesystem
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -123,11 +122,14 @@ func (f *MusicFile) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, f
|
|||||||
|
|
||||||
entry, err := f.f.cacher.GetFileDTO(f.sourcePath)
|
entry, err := f.f.cacher.GetFileDTO(f.sourcePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to convert %s to ALAC: %v", filepath.Base(f.sourcePath), err)
|
f.f.app.Logger().WithError(err).WithField("source file", f.sourcePath).
|
||||||
|
WithError(err).Error("Failed to convert file to cache")
|
||||||
|
|
||||||
return nil, 0, syscall.EIO
|
return nil, 0, syscall.EIO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.f.app.Logger().WithField("path", entry.Path).Debug("Opening cached file")
|
||||||
|
|
||||||
file, err := os.Open(entry.Path)
|
file, err := os.Open(entry.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, syscall.EIO
|
return nil, 0, syscall.EIO
|
||||||
|
|||||||
Reference in New Issue
Block a user