Pārlūkot izejas kodu

feat: batch insertion

Fela Maslen 5 gadi atpakaļ
vecāks
revīzija
d54a05729f

+ 3 - 1
music-player/pkg/read/audio.go

@@ -23,6 +23,9 @@ func ReadFile(basePath string, scannedFile *File) (song *Song, err error) {
   }
 
   durationTime, durationOk := duration.GetSongDuration(file, tags)
+  if !durationOk {
+    durationTime = 0
+  }
 
   trackNumber, _ := tags.Track()
 
@@ -32,7 +35,6 @@ func ReadFile(basePath string, scannedFile *File) (song *Song, err error) {
     Artist: tags.Artist(),
     Album: tags.Album(),
     Duration: durationTime,
-    DurationOk: durationOk,
     BasePath: basePath,
     RelativePath: scannedFile.RelativePath,
     ModifiedDate: scannedFile.ModifiedDate,

+ 0 - 1
music-player/pkg/read/audio_test.go

@@ -31,7 +31,6 @@ var _ = Describe("reading audio files", func() {
 	Artist: "Kevin MacLeod",
 	Album: "YouTube Audio Library",
 	Duration: 74,
-	DurationOk: true,
 	BasePath: basePath,
 	RelativePath: "file_example_OOG_1MG.ogg",
 	ModifiedDate: 102118,

+ 2 - 2
music-player/pkg/read/files.go

@@ -116,7 +116,6 @@ func batchFilterFiles(
 
   var processBatch = func() {
     if batchSize == 0 {
-      l.Verbose("[FILTER] Finished filtering files\n")
       return
     }
 
@@ -158,7 +157,7 @@ func batchFilterFiles(
       var file File
       newOrUpdatedFiles.StructScan(&file)
 
-      l.Debug("[FILTER] %s\n", file.RelativePath)
+      l.Verbose("[NEW] %s\n", file.RelativePath)
 
       *filteredOutput <- &file
     }
@@ -172,6 +171,7 @@ func batchFilterFiles(
     case file, more := <- *allFiles:
       if !more {
         processBatch()
+        l.Verbose("[FILTER] Finished filtering %d files\n", numFiltered)
         return
       }
 

+ 0 - 2
music-player/pkg/read/test_file_info.go

@@ -8,7 +8,6 @@ var TestSong = Song{
   Artist: "Kevin MacLeod",
   Album: "YouTube Audio Library",
   Duration: 74,
-  DurationOk: true,
   BasePath: TestDirectory,
   RelativePath: "file_example_OOG_1MG.ogg",
 }
@@ -19,7 +18,6 @@ var TestSongNested = Song{
   Artist: "Howard Shelley",
   Album: "Clementi: The Complete Piano Sonatas, Vol. 4",
   Duration: 166,
-  DurationOk: true,
   BasePath: TestDirectory,
   RelativePath: "nested/14 Clementi Piano Sonata in D major, Op 25 No 6 - Movement 2 Un poco andante.ogg",
 }

+ 0 - 1
music-player/pkg/read/types.go

@@ -6,7 +6,6 @@ type Song struct {
   Artist string 	`db:"artist"`
   Album string 		`db:"album"`
   Duration int 		`db:"duration"`
-  DurationOk bool
   BasePath string 	`db:"base_path"`
   RelativePath string 	`db:"relative_path"`
   ModifiedDate int64 	`db:"modified_date"` 

+ 94 - 45
music-player/pkg/repository/scan.go

@@ -1,72 +1,121 @@
 package repository
 
 import (
-	"fmt"
-
 	"github.com/felamaslen/go-music-player/pkg/config"
 	"github.com/felamaslen/go-music-player/pkg/database"
 	"github.com/felamaslen/go-music-player/pkg/logger"
 	"github.com/felamaslen/go-music-player/pkg/read"
+	"github.com/lib/pq"
 )
 
+const BATCH_SIZE = 100
+const LOG_EVERY = 100;
+
 func InsertMusicIntoDatabase(songs chan *read.Song) {
   var l = logger.CreateLogger(config.GetConfig().LogLevel)
 
   db := database.GetConnection()
 
+  var batch [BATCH_SIZE]*read.Song
+  var batchSize = 0
+  var numAdded = 0
+
+  var processBatch = func() {
+    if batchSize == 0 {
+      return
+    }
+
+    l.Debug("[INSERT] Processing batch\n")
+
+    var trackNumbers pq.Int64Array
+    var titles pq.StringArray
+    var artists pq.StringArray
+    var albums pq.StringArray
+    var durations pq.Int64Array
+
+    var modifiedDates pq.Int64Array
+
+    var basePaths pq.StringArray
+    var relativePaths pq.StringArray
+
+    for i := 0; i < batchSize; i++ {
+      trackNumbers = append(trackNumbers, int64(batch[i].TrackNumber))
+      titles = append(titles, batch[i].Title)
+      artists = append(artists, batch[i].Artist)
+      albums = append(albums, batch[i].Album)
+      durations = append(durations, int64(batch[i].Duration))
+
+      modifiedDates = append(modifiedDates, batch[i].ModifiedDate)
+
+      basePaths = append(basePaths, batch[i].BasePath)
+      relativePaths = append(relativePaths, batch[i].RelativePath)
+    }
+
+    db.MustExec(
+      `
+      insert into songs (
+        track_number
+        ,title
+        ,artist
+        ,album
+        ,duration
+        ,modified_date
+        ,base_path
+        ,relative_path
+      )
+      select * from unnest(
+        $1::integer[]
+        ,$2::varchar[]
+        ,$3::varchar[]
+        ,$4::varchar[]
+        ,$5::integer[]
+        ,$6::bigint[]
+        ,$7::varchar[]
+        ,$8::varchar[]
+      )
+      on conflict (base_path, relative_path) do update
+      set
+        track_number = excluded.track_number
+        ,title = excluded.title
+        ,artist = excluded.artist
+        ,album = excluded.album
+        ,duration = excluded.duration
+        ,modified_date = excluded.modified_date
+      `,
+      trackNumbers,
+      titles,
+      artists,
+      albums,
+      durations,
+      modifiedDates,
+      basePaths,
+      relativePaths,
+    )
+
+    l.Debug("[INSERT] Processed batch\n")
+
+    batchSize = 0
+  }
+
   for {
     select {
     case song, more := <- songs:
       if !more {
-        l.Verbose("Finished inserting songs\n")
+        processBatch()
+        l.Verbose("[INSERT] Finished inserting %d songs\n", numAdded)
         return
       }
 
-      l.Debug("Adding song: %v\n", song)
+      batch[batchSize] = song
+      batchSize++
 
-      duration := "NULL"
-      if song.DurationOk {
-        duration = fmt.Sprintf("%d", song.Duration)
+      numAdded++
+      if numAdded % LOG_EVERY == 0 {
+        l.Verbose("[INSERT] Inserted %d\n", numAdded)
       }
 
-      query, err := db.Query(
-        `
-        insert into songs (
-          title
-          ,track_number
-          ,artist
-          ,album
-          ,duration
-          ,base_path
-          ,relative_path
-          ,modified_date
-        )
-        values ($1, $2::integer, $3, $4, $5::integer, $6, $7, $8::integer)
-        on conflict (base_path, relative_path) do update
-        set
-          title = excluded.title
-          ,track_number = excluded.track_number
-          ,artist = excluded.artist
-          ,album = excluded.album
-          ,duration = excluded.duration
-          ,modified_date = excluded.modified_date
-        `,
-        song.Title,
-        song.TrackNumber,
-        song.Artist,
-        song.Album,
-        duration,
-        song.BasePath,
-        song.RelativePath,
-        song.ModifiedDate,
-      )
-
-      query.Close()
-
-      if err == nil {
-        l.Info("Added %s\n", song.RelativePath)
-      } else {
-        l.Error("Error inserting record: %s\n", err)
+      if batchSize >= BATCH_SIZE {
+        processBatch()
       }
     }
   }

+ 0 - 2
music-player/pkg/repository/scan_test.go

@@ -31,7 +31,6 @@ var _ = Describe("scanning repository", func() {
 	  Artist: "The Beatles",
 	  Album: "",
 	  Duration: 431,
-	  DurationOk: true,
 	  BasePath: "/path/to",
 	  RelativePath: "file.ogg",
 	  ModifiedDate: 8876,
@@ -43,7 +42,6 @@ var _ = Describe("scanning repository", func() {
 	  Artist: "David Bowie",
 	  Album: "The Rise and Fall of Ziggy Stardust and the Spiders from Mars",
 	  Duration: 256,
-	  DurationOk: true,
 	  BasePath: "/different/path",
 	  RelativePath: "otherFile.ogg",
 	  ModifiedDate: 11883,