fix: use transaction for MBID updates to prevent SQLite deadlock

updateMBIDs was calling l.db.ExecContext (main connection) while
inside a transaction that held the write lock. With SQLite's
SetMaxOpenConns(1), this deadlocked — the UPDATE waited for the
transaction to release the lock, but the transaction waited for
the UPDATE to complete.

Fix: pass *sql.Tx through processMetadata to updateMBIDs and use
tx.ExecContext instead. All MBID writes now happen within the same
transaction as the entity upserts.
This commit is contained in:
2026-03-26 09:52:38 -04:00
parent 8f6a4c6a8e
commit ad6104132d
+9 -7
View File
@@ -973,7 +973,7 @@ func (l *Library) saveAudioFile(
// Process metadata and create related records.
recordingID, err := l.processMetadata(
q, cache, metrics, result, thumbChan,
q, tx, cache, metrics, result, thumbChan,
)
if err != nil {
return fmt.Errorf("could not process metadata: %w", err)
@@ -1067,7 +1067,7 @@ func (l *Library) updateAudioFileMetadata(
// Process metadata and create related records.
recordingID, err := l.processMetadata(
q, cache, metrics, result, thumbChan,
q, tx, cache, metrics, result, thumbChan,
)
if err != nil {
return fmt.Errorf("could not process metadata: %w", err)
@@ -1148,6 +1148,7 @@ func (l *Library) updateAudioFileMetadata(
// asynchronously.
func (l *Library) processMetadata(
q *sqlcgen.Queries,
tx *sql.Tx,
cache *entityCache,
metrics *ScanMetrics,
result importResult,
@@ -1236,9 +1237,9 @@ func (l *Library) processMetadata(
// 7. Update MusicBrainz IDs (if present in tags).
if releaseGroupID.Valid {
l.updateMBIDs(cache, tags, artistName, releaseGroupID.Int64, recording.ID)
l.updateMBIDs(tx, cache, tags, artistName, releaseGroupID.Int64, recording.ID)
} else {
l.updateMBIDs(cache, tags, artistName, 0, recording.ID)
l.updateMBIDs(tx, cache, tags, artistName, 0, recording.ID)
}
return recording.ID, nil
@@ -1249,6 +1250,7 @@ func (l *Library) processMetadata(
// queries predate the mbid columns. Skips silently if tags have
// no MBIDs.
func (l *Library) updateMBIDs(
tx *sql.Tx,
cache *entityCache,
tags *metadata.TrackMetadata,
artistName string,
@@ -1263,7 +1265,7 @@ func (l *Library) updateMBIDs(
if artistMBID != "" {
if artist, ok := cache.artists[artistName]; ok {
_, _ = l.db.ExecContext(
_, _ = tx.ExecContext(l.ctx,
"UPDATE artists SET mbid = ? WHERE id = ? AND (mbid IS NULL OR mbid = '')",
artistMBID, artist.ID,
)
@@ -1272,7 +1274,7 @@ func (l *Library) updateMBIDs(
// Release group MBID.
if tags.ReleaseGroupMBID != "" && releaseGroupID > 0 {
_, _ = l.db.ExecContext(
_, _ = tx.ExecContext(l.ctx,
"UPDATE release_groups SET mbid = ? WHERE id = ? AND (mbid IS NULL OR mbid = '')",
tags.ReleaseGroupMBID, releaseGroupID,
)
@@ -1280,7 +1282,7 @@ func (l *Library) updateMBIDs(
// Recording MBID.
if tags.RecordingMBID != "" && recordingID > 0 {
_, _ = l.db.ExecContext(
_, _ = tx.ExecContext(l.ctx,
"UPDATE recordings SET mbid = ? WHERE id = ? AND (mbid IS NULL OR mbid = '')",
tags.RecordingMBID, recordingID,
)