Skip to content

Commit 5daf95c

Browse files
committed
fix(scanner): reduce sqlite lock contention during scans
closes #678
1 parent 0f98064 commit 5daf95c

File tree

2 files changed

+27
-17
lines changed

2 files changed

+27
-17
lines changed

db/db.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,15 @@ func (db *DB) TransactionChunked(data []int64, cb func(*DB, []int64) error) erro
127127
}
128128
// https://sqlite.org/limits.html
129129
const size = 999
130-
return db.Transaction(func(tx *DB) error {
131-
for i := 0; i < len(data); i += size {
132-
end := min(i+size, len(data))
133-
if err := cb(tx, data[i:end]); err != nil {
134-
return err
135-
}
130+
for i := 0; i < len(data); i += size {
131+
end := min(i+size, len(data))
132+
if err := db.Transaction(func(tx *DB) error {
133+
return cb(tx, data[i:end])
134+
}); err != nil {
135+
return err
136136
}
137-
return nil
138-
})
137+
}
138+
return nil
139139
}
140140

141141
type SettingKey string

scanner/scanner.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -372,20 +372,30 @@ func (s *Scanner) scanDir(st *State, absPath string) error {
372372
return nil
373373
}
374374

375+
// read tags outside the transaction to avoid holding db locks during disk i/o
376+
type trackTagData struct {
377+
trackUpdate
378+
trprops tags.Properties
379+
trags tags.Tags
380+
}
381+
tagData := make([]trackTagData, 0, len(trackUpdates))
382+
for _, t := range trackUpdates {
383+
trprops, trags, err := s.tagReader.Read(t.absPath)
384+
if err != nil {
385+
return fmt.Errorf("read %q: %w: %w", t.basename, err, ErrReadingTags)
386+
}
387+
tagData = append(tagData, trackTagData{trackUpdate: t, trprops: trprops, trags: trags})
388+
}
389+
375390
return s.db.Transaction(func(tx *db.DB) error {
376391
var discTitles = map[int]string{}
377-
for _, t := range trackUpdates {
378-
trprops, trags, err := s.tagReader.Read(t.absPath)
379-
if err != nil {
380-
return fmt.Errorf("read %q: %w: %w", t.basename, err, ErrReadingTags)
381-
}
382-
383-
if err := s.populateTrackAndArtists(tx, st, t.i, &album, t.track, t.timeSpec, trprops, trags, t.basename, t.absPath); err != nil {
392+
for _, t := range tagData {
393+
if err := s.populateTrackAndArtists(tx, st, t.i, &album, t.track, t.timeSpec, t.trprops, t.trags, t.basename, t.absPath); err != nil {
384394
return fmt.Errorf("populate track %q: %w", t.basename, err)
385395
}
386396

387-
discNum := cmp.Or(tags.ParseInt(normtag.Get(trags, normtag.DiscNumber)), 1)
388-
discSubtitle := normtag.Get(trags, "DISCSUBTITLE")
397+
discNum := cmp.Or(tags.ParseInt(normtag.Get(t.trags, normtag.DiscNumber)), 1)
398+
discSubtitle := normtag.Get(t.trags, "DISCSUBTITLE")
389399

390400
if _, exists := discTitles[discNum]; !exists && discSubtitle != "" {
391401
discTitles[discNum] = discSubtitle

0 commit comments

Comments
 (0)