@@ -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