From faa2a978c02c586e75565796588087364a98880e Mon Sep 17 00:00:00 2001 From: Deluan <deluan@deluan.com> Date: Fri, 28 Feb 2020 14:16:15 -0500 Subject: [PATCH] refactor: use only one DB instance for the whole application --- db/db.go | 24 +++++--- persistence/persistence.go | 87 ++++++++++++++------------- persistence/persistence_suite_test.go | 4 +- tests/navidrome-test.toml | 2 +- 4 files changed, 61 insertions(+), 56 deletions(-) diff --git a/db/db.go b/db/db.go index 1e93445a1..8463e4167 100644 --- a/db/db.go +++ b/db/db.go @@ -13,32 +13,36 @@ import ( ) var ( - once sync.Once Driver = "sqlite3" Path string ) -func Init() { +var ( + once sync.Once + db *sql.DB +) + +func Db() *sql.DB { once.Do(func() { + var err error Path = conf.Server.DbPath if Path == ":memory:" { Path = "file::memory:?cache=shared" conf.Server.DbPath = Path } log.Debug("Opening DataBase", "dbPath", Path, "driver", Driver) + db, err = sql.Open(Driver, Path) + if err != nil { + panic(err) + } }) + return db } func EnsureLatestVersion() { - Init() - db, err := sql.Open(Driver, Path) - defer db.Close() - if err != nil { - log.Error("Failed to open DB", err) - os.Exit(1) - } + db := Db() - err = goose.SetDialect(Driver) + err := goose.SetDialect(Driver) if err != nil { log.Error("Invalid DB driver", "driver", Driver, err) os.Exit(1) diff --git a/persistence/persistence.go b/persistence/persistence.go index fc2ee1714..f2de43669 100644 --- a/persistence/persistence.go +++ b/persistence/persistence.go @@ -20,65 +20,62 @@ type SQLStore struct { } func New() model.DataStore { - once.Do(func() { - err := orm.RegisterDataBase("default", db.Driver, db.Path) - if err != nil { - panic(err) - } - }) return &SQLStore{} } -func (db *SQLStore) Album(ctx context.Context) model.AlbumRepository { - return NewAlbumRepository(ctx, db.getOrmer()) +func (s *SQLStore) Album(ctx context.Context) model.AlbumRepository { + return NewAlbumRepository(ctx, s.getOrmer()) } -func (db *SQLStore) Artist(ctx context.Context) model.ArtistRepository { - return NewArtistRepository(ctx, db.getOrmer()) +func (s *SQLStore) Artist(ctx context.Context) model.ArtistRepository { + return NewArtistRepository(ctx, s.getOrmer()) } -func (db *SQLStore) MediaFile(ctx context.Context) model.MediaFileRepository { - return NewMediaFileRepository(ctx, db.getOrmer()) +func (s *SQLStore) MediaFile(ctx context.Context) model.MediaFileRepository { + return NewMediaFileRepository(ctx, s.getOrmer()) } -func (db *SQLStore) MediaFolder(ctx context.Context) model.MediaFolderRepository { - return NewMediaFolderRepository(ctx, db.getOrmer()) +func (s *SQLStore) MediaFolder(ctx context.Context) model.MediaFolderRepository { + return NewMediaFolderRepository(ctx, s.getOrmer()) } -func (db *SQLStore) Genre(ctx context.Context) model.GenreRepository { - return NewGenreRepository(ctx, db.getOrmer()) +func (s *SQLStore) Genre(ctx context.Context) model.GenreRepository { + return NewGenreRepository(ctx, s.getOrmer()) } -func (db *SQLStore) Playlist(ctx context.Context) model.PlaylistRepository { - return NewPlaylistRepository(ctx, db.getOrmer()) +func (s *SQLStore) Playlist(ctx context.Context) model.PlaylistRepository { + return NewPlaylistRepository(ctx, s.getOrmer()) } -func (db *SQLStore) Property(ctx context.Context) model.PropertyRepository { - return NewPropertyRepository(ctx, db.getOrmer()) +func (s *SQLStore) Property(ctx context.Context) model.PropertyRepository { + return NewPropertyRepository(ctx, s.getOrmer()) } -func (db *SQLStore) User(ctx context.Context) model.UserRepository { - return NewUserRepository(ctx, db.getOrmer()) +func (s *SQLStore) User(ctx context.Context) model.UserRepository { + return NewUserRepository(ctx, s.getOrmer()) } -func (db *SQLStore) Resource(ctx context.Context, m interface{}) model.ResourceRepository { +func (s *SQLStore) Resource(ctx context.Context, m interface{}) model.ResourceRepository { switch m.(type) { case model.User: - return db.User(ctx).(model.ResourceRepository) + return s.User(ctx).(model.ResourceRepository) case model.Artist: - return db.Artist(ctx).(model.ResourceRepository) + return s.Artist(ctx).(model.ResourceRepository) case model.Album: - return db.Album(ctx).(model.ResourceRepository) + return s.Album(ctx).(model.ResourceRepository) case model.MediaFile: - return db.MediaFile(ctx).(model.ResourceRepository) + return s.MediaFile(ctx).(model.ResourceRepository) } log.Error("Resource no implemented", "model", reflect.TypeOf(m).Name()) return nil } -func (db *SQLStore) WithTx(block func(tx model.DataStore) error) error { - o := orm.NewOrm() - err := o.Begin() +func (s *SQLStore) WithTx(block func(tx model.DataStore) error) error { + o, err := orm.NewOrmWithDB(db.Driver, "default", db.Db()) + if err != nil { + return err + } + err = o.Begin() if err != nil { return err } @@ -101,41 +98,45 @@ func (db *SQLStore) WithTx(block func(tx model.DataStore) error) error { return nil } -func (db *SQLStore) GC(ctx context.Context) error { - err := db.Album(ctx).PurgeEmpty() +func (s *SQLStore) GC(ctx context.Context) error { + err := s.Album(ctx).PurgeEmpty() if err != nil { return err } - err = db.Artist(ctx).PurgeEmpty() + err = s.Artist(ctx).PurgeEmpty() if err != nil { return err } - err = db.MediaFile(ctx).(*mediaFileRepository).cleanSearchIndex() + err = s.MediaFile(ctx).(*mediaFileRepository).cleanSearchIndex() if err != nil { return err } - err = db.Album(ctx).(*albumRepository).cleanSearchIndex() + err = s.Album(ctx).(*albumRepository).cleanSearchIndex() if err != nil { return err } - err = db.Artist(ctx).(*artistRepository).cleanSearchIndex() + err = s.Artist(ctx).(*artistRepository).cleanSearchIndex() if err != nil { return err } - err = db.MediaFile(ctx).(*mediaFileRepository).cleanAnnotations() + err = s.MediaFile(ctx).(*mediaFileRepository).cleanAnnotations() if err != nil { return err } - err = db.Album(ctx).(*albumRepository).cleanAnnotations() + err = s.Album(ctx).(*albumRepository).cleanAnnotations() if err != nil { return err } - return db.Artist(ctx).(*artistRepository).cleanAnnotations() + return s.Artist(ctx).(*artistRepository).cleanAnnotations() } -func (db *SQLStore) getOrmer() orm.Ormer { - if db.orm == nil { - return orm.NewOrm() +func (s *SQLStore) getOrmer() orm.Ormer { + if s.orm == nil { + o, err := orm.NewOrmWithDB(db.Driver, "default", db.Db()) + if err != nil { + log.Error("Error obtaining new orm instance", err) + } + return o } - return db.orm + return s.orm } diff --git a/persistence/persistence_suite_test.go b/persistence/persistence_suite_test.go index a4a216fb8..fd1d379f0 100644 --- a/persistence/persistence_suite_test.go +++ b/persistence/persistence_suite_test.go @@ -21,8 +21,8 @@ func TestPersistence(t *testing.T) { //os.Remove("./test-123.db") //conf.Server.Path = "./test-123.db" - conf.Server.DbPath = ":memory:" - db.Init() + conf.Server.DbPath = "file::memory:?cache=shared" + orm.RegisterDataBase("default", db.Driver, conf.Server.DbPath) New() db.EnsureLatestVersion() log.SetLevel(log.LevelCritical) diff --git a/tests/navidrome-test.toml b/tests/navidrome-test.toml index 1a12949d1..7b80a4fff 100644 --- a/tests/navidrome-test.toml +++ b/tests/navidrome-test.toml @@ -1,6 +1,6 @@ DevDisableAuthentication = false User = "deluan" Password = "wordpass" -DbPath = ":memory:" +DbPath = "file::memory:?cache=shared" MusicFolder = "./tests/itunes-library.xml" DownsampleCommand = "ffmpeg -i %s -b:a %bk mp3 -"