From 50686ae19161261f38bab53b0a288660bb48e7a3 Mon Sep 17 00:00:00 2001 From: croneter Date: Tue, 25 Dec 2018 19:12:49 +0100 Subject: [PATCH] Fix database is locked - Fixes #580 --- resources/lib/library_sync/fanart.py | 51 ++++++++++++++++------------ resources/lib/plex_db/common.py | 18 +++++++--- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/resources/lib/library_sync/fanart.py b/resources/lib/library_sync/fanart.py index e32b33ef..77af7634 100644 --- a/resources/lib/library_sync/fanart.py +++ b/resources/lib/library_sync/fanart.py @@ -15,6 +15,7 @@ LOG = getLogger('PLEX.sync.fanart') SUPPORTED_TYPES = (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW) SYNC_FANART = utils.settings('FanartTV') == 'true' PREFER_KODI_COLLECTION_ART = utils.settings('PreferKodiCollectionArt') == 'false' +BATCH_SIZE = 500 def suspends(): @@ -45,29 +46,37 @@ class FanartThread(backgroundthread.KillableThread): def _run_internal(self): LOG.info('Starting FanartThread') finished = False - while True: - with PlexDB() as plexdb: - func = plexdb.every_plex_id if self.refresh else plexdb.missing_fanart - for typus in SUPPORTED_TYPES: - for plex_id in func(typus): - if self.isCanceled() or self.isSuspended(): - break + try: + for typus in SUPPORTED_TYPES: + offset = 0 + while True: + with PlexDB() as plexdb: + # Keep DB connection open only for a short period of time! + if self.refresh: + batch = list(plexdb.every_plex_id(typus, + offset, + BATCH_SIZE)) + else: + batch = list(plexdb.missing_fanart(typus, + offset, + BATCH_SIZE)) + for plex_id in batch: + # Do the actual, time-consuming processing + if self.isCanceled(): + return + if self.isSuspended(): + if self.isCanceled(): + return + app.APP.monitor.waitForAbort(1) process_fanart(plex_id, typus, self.refresh) - if self.isCanceled() or self.isSuspended(): + if len(batch) < BATCH_SIZE: break - else: - # Done processing! - finished = True - break - # Need to have these outside our DB context to close the connection - if self.isCanceled(): - return - if self.isSuspended(): - if self.isCanceled(): - return - app.APP.monitor.waitForAbort(1) - LOG.info('FanartThread finished') - self.callback(finished) + offset += BATCH_SIZE + else: + finished = True + finally: + LOG.info('FanartThread finished: %s', finished) + self.callback(finished) class FanartTask(common.libsync_mixin, backgroundthread.Task): diff --git a/resources/lib/plex_db/common.py b/resources/lib/plex_db/common.py index 4e9e50c0..981db266 100644 --- a/resources/lib/plex_db/common.py +++ b/resources/lib/plex_db/common.py @@ -121,20 +121,28 @@ class PlexDBBase(object): """ self.cursor.execute('DELETE FROM %s WHERE plex_id = ?' % plex_type, (plex_id, )) - def every_plex_id(self, plex_type): + def every_plex_id(self, plex_type, offset, limit): """ Returns an iterator for plex_type for every single plex_id + Will start with records at DB position offset [int] and return limit + [int] number of items """ return (x[0] for x in - self.cursor.execute('SELECT plex_id from %s' % plex_type)) + self.cursor.execute('SELECT plex_id FROM %s LIMIT %s OFFSET %s' + % (plex_type, limit, offset))) - def missing_fanart(self, plex_type): + def missing_fanart(self, plex_type, offset, limit): """ Returns an iterator for plex_type for all plex_id, where fanart_synced has not yet been set to 1 + Will start with records at DB position offset [int] and return limit + [int] number of items """ - return (x[0] for x in - self.cursor.execute('SELECT plex_id from %s WHERE fanart_synced = 0' % plex_type)) + query = ''' + SELECT plex_id FROM %s WHERE fanart_synced = 0 + LIMIT %s OFFSET %s + ''' % (plex_type, limit, offset) + return (x[0] for x in self.cursor.execute(query)) def set_fanart_synced(self, plex_id, plex_type): """