@@ -10,6 +10,7 @@ import (
1010 "os"
1111 "path/filepath"
1212 "strings"
13+ "sync"
1314
1415 "github.com/dustin/go-humanize"
1516 "github.com/shirou/gopsutil/disk"
@@ -25,6 +26,8 @@ type Collection struct {
2526 ReadOnly bool
2627 RenameOnReplace bool
2728 cache Cache
29+ muxAlbumMap sync.Mutex
30+ muxsAlbums map [string ]* sync.Mutex
2831}
2932
3033type CollectionInfo struct {
@@ -43,6 +46,12 @@ type AddAlbumQuery struct {
4346 Type string `json:"type"`
4447}
4548
49+ func NewCollection () * Collection {
50+ return & Collection {
51+ muxsAlbums : make (map [string ]* sync.Mutex ),
52+ }
53+ }
54+
4655// List all collections
4756func GetCollections (collections map [string ]* Collection ) []CollectionInfo {
4857 list := make ([]CollectionInfo , len (collections ))
@@ -151,7 +160,22 @@ func (c *Collection) GetAlbumWithPhotos(albumName string, forceUpdate bool, runn
151160 if err == nil { // Is cached
152161 return cachedAlbum , nil
153162 }
163+
164+ // If we try to get the cached album whilst another scan is in progress, it will fail.
165+ // So we try again but locking until the running scan is completed.
166+ // That way we do not need to lock getting albums from the cache in the first attempt.
167+ c .LockAlbum (albumName )
168+ cachedAlbum , err = c .cache .GetAlbum (albumName )
169+ c .UnlockAlbum (albumName )
170+ if err == nil { // Is cached
171+ return cachedAlbum , nil
172+ }
154173 }
174+
175+ // Lock album to avoid concurrent scans
176+ c .LockAlbum (albumName )
177+ defer c .UnlockAlbum (albumName )
178+
155179 // If not in cache, read from disk
156180 album , err := c .GetAlbum (albumName )
157181 if err != nil {
@@ -215,3 +239,24 @@ func (collection *Collection) StorageUsage() (CollectionStorage, error) {
215239 Percentage : int (math .Round (percentage )),
216240 }, nil
217241}
242+
243+ func (c * Collection ) LockAlbum (id string ) {
244+ c .muxAlbumMap .Lock ()
245+ mux , ok := c .muxsAlbums [id ]
246+ if ! ok {
247+ mux = new (sync.Mutex )
248+ c .muxsAlbums [id ] = mux
249+ }
250+ c .muxAlbumMap .Unlock ()
251+ mux .Lock ()
252+ }
253+
254+ func (c * Collection ) UnlockAlbum (id string ) {
255+ c .muxAlbumMap .Lock ()
256+ mux , ok := c .muxsAlbums [id ]
257+ if ok {
258+ mux .Unlock ()
259+ //delete(c.muxsAlbums, id)
260+ }
261+ c .muxAlbumMap .Unlock ()
262+ }
0 commit comments