Skip to content

Commit 0d6f179

Browse files
committed
Avoid scanning same album concurrently
1 parent 4f2c4ba commit 0d6f179

File tree

3 files changed

+50
-10
lines changed

3 files changed

+50
-10
lines changed

server/cmdargs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ type CmdArgs struct {
2525
}
2626

2727
func parseCollectionOptions(collectionOption string, defaultIndex int) (collection *Collection, err error) {
28-
collection = new(Collection)
28+
collection = NewCollection()
2929
collection.Index = defaultIndex
3030
collection.Hide = false
3131
collection.ReadOnly = false

server/collection.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

3033
type 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
4756
func 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+
}

server/pseudo.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"os"
88
"path/filepath"
99
"strings"
10-
"sync"
1110

1211
"golang.org/x/exp/slices"
1312
)
@@ -54,16 +53,11 @@ func (photo *Photo) CopyForPseudoAlbum() *Photo {
5453
}
5554
}
5655

57-
var mux sync.Mutex
58-
5956
func readPseudoAlbum(collection *Collection, album *Album) ([]PseudoAlbumEntry, error) {
6057
if !album.IsPseudo {
6158
return nil, errors.New("the destination must be a pseudo album")
6259
}
6360

64-
mux.Lock()
65-
defer mux.Unlock()
66-
6761
filename := filepath.Join(collection.PhotosPath, album.Name+PSEUDO_ALBUM_EXT)
6862
file, err := os.Open(filename)
6963
if err != nil {
@@ -98,9 +92,6 @@ func writePseudoAlbum(collection *Collection, album *Album, entries ...PseudoAlb
9892
return errors.New("the destination must be a pseudo album")
9993
}
10094

101-
mux.Lock()
102-
defer mux.Unlock()
103-
10495
filename := filepath.Join(collection.PhotosPath, album.Name+PSEUDO_ALBUM_EXT)
10596
file, err := os.OpenFile(filename, os.O_TRUNC|os.O_WRONLY, 0644)
10697
if err != nil {
@@ -168,6 +159,10 @@ func GetPseudoAlbums(collections map[string]*Collection) []PseudoAlbum {
168159
}
169160

170161
func (album *Album) EditPseudoAlbum(collection *Collection, query PseudoAlbumSaveQuery, isAdd bool) error {
162+
// Lock album to avoid concurrent edits
163+
collection.LockAlbum(album.Name)
164+
defer collection.UnlockAlbum(album.Name)
165+
171166
// Read entries from target album
172167
entries, err := readPseudoAlbum(collection, album)
173168
if err != nil {

0 commit comments

Comments
 (0)