From: Marcel van der Veldt Date: Mon, 3 Apr 2023 15:53:29 +0000 (+0200) Subject: fix db lock issue X-Git-Url: https://git.kitaultman.com/?a=commitdiff_plain;h=d90e284a9815878598faac185f5a5505573a005d;p=music-assistant-server.git fix db lock issue --- diff --git a/music_assistant/server/controllers/media/albums.py b/music_assistant/server/controllers/media/albums.py index 0633778a..de863b75 100644 --- a/music_assistant/server/controllers/media/albums.py +++ b/music_assistant/server/controllers/media/albums.py @@ -190,34 +190,34 @@ class AlbumsController(MediaControllerBase[Album]): """Add a new record to the database.""" assert item.provider_mappings, "Item is missing provider mapping(s)" assert item.artists, f"Album {item.name} is missing artists" - async with self._db_add_lock: - cur_item = None - # always try to grab existing item by musicbrainz_id - if item.musicbrainz_id: - match = {"musicbrainz_id": item.musicbrainz_id} - cur_item = await self.mass.music.database.get_row(self.db_table, match) - # try barcode/upc - if not cur_item and item.barcode: - for barcode in item.barcode: - if search_result := await self.mass.music.database.search( - self.db_table, barcode, "barcode" - ): - cur_item = Album.from_db_row(search_result[0]) - break - if not cur_item: - # fallback to search and match - for row in await self.mass.music.database.search(self.db_table, item.name): - row_album = Album.from_db_row(row) - if compare_album(row_album, item): - cur_item = row_album - break - if cur_item: - # update existing - return await self._update_db_item(cur_item.item_id, item) + cur_item = None + # always try to grab existing item by musicbrainz_id + if item.musicbrainz_id: + match = {"musicbrainz_id": item.musicbrainz_id} + cur_item = await self.mass.music.database.get_row(self.db_table, match) + # try barcode/upc + if not cur_item and item.barcode: + for barcode in item.barcode: + if search_result := await self.mass.music.database.search( + self.db_table, barcode, "barcode" + ): + cur_item = Album.from_db_row(search_result[0]) + break + if not cur_item: + # fallback to search and match + for row in await self.mass.music.database.search(self.db_table, item.name): + row_album = Album.from_db_row(row) + if compare_album(row_album, item): + cur_item = row_album + break + if cur_item: + # update existing + return await self._update_db_item(cur_item.item_id, item) - # insert new item - album_artists = await self._get_artist_mappings(item, cur_item) - sort_artist = album_artists[0].sort_name if album_artists else "" + # insert new item + album_artists = await self._get_artist_mappings(item, cur_item) + sort_artist = album_artists[0].sort_name if album_artists else "" + async with self._db_add_lock: new_item = await self.mass.music.database.insert( self.db_table, { @@ -229,11 +229,11 @@ class AlbumsController(MediaControllerBase[Album]): }, ) item_id = new_item["item_id"] - # update/set provider_mappings table - await self._set_provider_mappings(item_id, item.provider_mappings) - self.logger.debug("added %s to database", item.name) - # return created object - return await self.get_db_item(item_id) + # update/set provider_mappings table + await self._set_provider_mappings(item_id, item.provider_mappings) + self.logger.debug("added %s to database", item.name) + # return created object + return await self.get_db_item(item_id) async def _update_db_item( self, item_id: int, item: Album | ItemMapping, overwrite: bool = False diff --git a/music_assistant/server/controllers/media/artists.py b/music_assistant/server/controllers/media/artists.py index b4eb0be8..5d98e803 100644 --- a/music_assistant/server/controllers/media/artists.py +++ b/music_assistant/server/controllers/media/artists.py @@ -283,41 +283,41 @@ class ArtistsController(MediaControllerBase[Artist]): if item.musicbrainz_id == VARIOUS_ARTISTS_ID: item.name = VARIOUS_ARTISTS - async with self._db_add_lock: - # always try to grab existing item by musicbrainz_id - cur_item = None - if musicbrainz_id := getattr(item, "musicbrainz_id", None): - match = {"musicbrainz_id": musicbrainz_id} - cur_item = await self.mass.music.database.get_row(self.db_table, match) - if not cur_item: - # fallback to exact name match - # NOTE: we match an artist by name which could theoretically lead to collisions - # but the chance is so small it is not worth the additional overhead of grabbing - # the musicbrainz id upfront - match = {"sort_name": item.sort_name} - for row in await self.mass.music.database.get_rows(self.db_table, match): - row_artist = Artist.from_db_row(row) - if row_artist.sort_name == item.sort_name: - cur_item = row_artist - break - if cur_item: - # update existing - return await self._update_db_item(cur_item.item_id, item) + # always try to grab existing item by musicbrainz_id + cur_item = None + if musicbrainz_id := getattr(item, "musicbrainz_id", None): + match = {"musicbrainz_id": musicbrainz_id} + cur_item = await self.mass.music.database.get_row(self.db_table, match) + if not cur_item: + # fallback to exact name match + # NOTE: we match an artist by name which could theoretically lead to collisions + # but the chance is so small it is not worth the additional overhead of grabbing + # the musicbrainz id upfront + match = {"sort_name": item.sort_name} + for row in await self.mass.music.database.get_rows(self.db_table, match): + row_artist = Artist.from_db_row(row) + if row_artist.sort_name == item.sort_name: + cur_item = row_artist + break + if cur_item: + # update existing + return await self._update_db_item(cur_item.item_id, item) - # insert item - item.timestamp_added = int(utc_timestamp()) - item.timestamp_modified = int(utc_timestamp()) - # edge case: item is an ItemMapping, - # try to construct (a half baken) Artist object from it - if isinstance(item, ItemMapping): - item = Artist.from_dict(item.to_dict()) + # insert item + item.timestamp_added = int(utc_timestamp()) + item.timestamp_modified = int(utc_timestamp()) + # edge case: item is an ItemMapping, + # try to construct (a half baken) Artist object from it + if isinstance(item, ItemMapping): + item = Artist.from_dict(item.to_dict()) + async with self._db_add_lock: new_item = await self.mass.music.database.insert(self.db_table, item.to_db_row()) item_id = new_item["item_id"] - # update/set provider_mappings table - await self._set_provider_mappings(item_id, item.provider_mappings) - self.logger.debug("added %s to database", item.name) - # return created object - return await self.get_db_item(item_id) + # update/set provider_mappings table + await self._set_provider_mappings(item_id, item.provider_mappings) + self.logger.debug("added %s to database", item.name) + # return created object + return await self.get_db_item(item_id) async def _update_db_item( self, item_id: int, item: Artist | ItemMapping, overwrite: bool = False diff --git a/music_assistant/server/controllers/media/playlists.py b/music_assistant/server/controllers/media/playlists.py index 789aec25..8cb38f6f 100644 --- a/music_assistant/server/controllers/media/playlists.py +++ b/music_assistant/server/controllers/media/playlists.py @@ -193,21 +193,21 @@ class PlaylistController(MediaControllerBase[Playlist]): async def _add_db_item(self, item: Playlist) -> Playlist: """Add a new record to the database.""" assert item.provider_mappings, "Item is missing provider mapping(s)" + match = {"name": item.name, "owner": item.owner} + if cur_item := await self.mass.music.database.get_row(self.db_table, match): + # update existing + return await self._update_db_item(cur_item["item_id"], item) + # insert new item + item.timestamp_added = int(utc_timestamp()) + item.timestamp_modified = int(utc_timestamp()) async with self._db_add_lock: - match = {"name": item.name, "owner": item.owner} - if cur_item := await self.mass.music.database.get_row(self.db_table, match): - # update existing - return await self._update_db_item(cur_item["item_id"], item) - # insert new item - item.timestamp_added = int(utc_timestamp()) - item.timestamp_modified = int(utc_timestamp()) new_item = await self.mass.music.database.insert(self.db_table, item.to_db_row()) item_id = new_item["item_id"] - # update/set provider_mappings table - await self._set_provider_mappings(item_id, item.provider_mappings) - self.logger.debug("added %s to database", item.name) - # return created object - return await self.get_db_item(item_id) + # update/set provider_mappings table + await self._set_provider_mappings(item_id, item.provider_mappings) + self.logger.debug("added %s to database", item.name) + # return created object + return await self.get_db_item(item_id) async def _update_db_item( self, item_id: int, item: Playlist, overwrite: bool = True diff --git a/music_assistant/server/controllers/media/radio.py b/music_assistant/server/controllers/media/radio.py index 8a27bdba..2dbb946d 100644 --- a/music_assistant/server/controllers/media/radio.py +++ b/music_assistant/server/controllers/media/radio.py @@ -79,21 +79,21 @@ class RadioController(MediaControllerBase[Radio]): async def _add_db_item(self, item: Radio) -> Radio: """Add a new item record to the database.""" assert item.provider_mappings, "Item is missing provider mapping(s)" + match = {"name": item.name} + if cur_item := await self.mass.music.database.get_row(self.db_table, match): + # update existing + return await self._update_db_item(cur_item["item_id"], item) + # insert new item + item.timestamp_added = int(utc_timestamp()) + item.timestamp_modified = int(utc_timestamp()) async with self._db_add_lock: - match = {"name": item.name} - if cur_item := await self.mass.music.database.get_row(self.db_table, match): - # update existing - return await self._update_db_item(cur_item["item_id"], item) - # insert new item - item.timestamp_added = int(utc_timestamp()) - item.timestamp_modified = int(utc_timestamp()) new_item = await self.mass.music.database.insert(self.db_table, item.to_db_row()) item_id = new_item["item_id"] - # update/set provider_mappings table - await self._set_provider_mappings(item_id, item.provider_mappings) - self.logger.debug("added %s to database", item.name) - # return created object - return await self.get_db_item(item_id) + # update/set provider_mappings table + await self._set_provider_mappings(item_id, item.provider_mappings) + self.logger.debug("added %s to database", item.name) + # return created object + return await self.get_db_item(item_id) async def _update_db_item(self, item_id: int, item: Radio, overwrite: bool = True) -> Radio: """Update Radio record in the database.""" diff --git a/music_assistant/server/controllers/media/tracks.py b/music_assistant/server/controllers/media/tracks.py index 0889d512..3f4e6364 100644 --- a/music_assistant/server/controllers/media/tracks.py +++ b/music_assistant/server/controllers/media/tracks.py @@ -271,36 +271,34 @@ class TracksController(MediaControllerBase[Track]): assert isinstance(item, Track), "Not a full Track object" assert item.artists, "Track is missing artist(s)" assert item.provider_mappings, "Track is missing provider mapping(s)" - async with self._db_add_lock: - cur_item = None + cur_item = None - # always try to grab existing item by external_id - if item.musicbrainz_id: - match = {"musicbrainz_id": item.musicbrainz_id} - cur_item = await self.mass.music.database.get_row(self.db_table, match) - for isrc in item.isrc: - if search_result := await self.mass.music.database.search( - self.db_table, isrc, "isrc" - ): - cur_item = Track.from_db_row(search_result[0]) + # always try to grab existing item by external_id + if item.musicbrainz_id: + match = {"musicbrainz_id": item.musicbrainz_id} + cur_item = await self.mass.music.database.get_row(self.db_table, match) + for isrc in item.isrc: + if search_result := await self.mass.music.database.search(self.db_table, isrc, "isrc"): + cur_item = Track.from_db_row(search_result[0]) + break + if not cur_item: + # fallback to matching + match = {"sort_name": item.sort_name} + for row in await self.mass.music.database.get_rows(self.db_table, match): + row_track = Track.from_db_row(row) + if compare_track(row_track, item): + cur_item = row_track break - if not cur_item: - # fallback to matching - match = {"sort_name": item.sort_name} - for row in await self.mass.music.database.get_rows(self.db_table, match): - row_track = Track.from_db_row(row) - if compare_track(row_track, item): - cur_item = row_track - break - if cur_item: - # update existing - return await self._update_db_item(cur_item.item_id, item) + if cur_item: + # update existing + return await self._update_db_item(cur_item.item_id, item) - # no existing match found: insert new item - track_artists = await self._get_artist_mappings(item) - track_albums = await self._get_track_albums(item) - sort_artist = track_artists[0].sort_name if track_artists else "" - sort_album = track_albums[0].sort_name if track_albums else "" + # no existing match found: insert new item + track_artists = await self._get_artist_mappings(item) + track_albums = await self._get_track_albums(item) + sort_artist = track_artists[0].sort_name if track_artists else "" + sort_album = track_albums[0].sort_name if track_albums else "" + async with self._db_add_lock: new_item = await self.mass.music.database.insert( self.db_table, { @@ -314,11 +312,11 @@ class TracksController(MediaControllerBase[Track]): }, ) item_id = new_item["item_id"] - # update/set provider_mappings table - await self._set_provider_mappings(item_id, item.provider_mappings) - # return created object - self.logger.debug("added %s to database: %s", item.name, item_id) - return await self.get_db_item(item_id) + # update/set provider_mappings table + await self._set_provider_mappings(item_id, item.provider_mappings) + # return created object + self.logger.debug("added %s to database: %s", item.name, item_id) + return await self.get_db_item(item_id) async def _update_db_item( self, item_id: int, item: Track | ItemMapping, overwrite: bool = False