nixgates / plugin.video.seren

Repository for Seren Development
306 stars 95 forks source link

[BUG] sqlite3.OperationalError: database is locked #870

Open henryjfry opened 1 year ago

henryjfry commented 1 year ago

Describe the bug

Seren 3.0.0 cleanOrphanedMetadata throws "database is locked" error when it runs in the regular maintenance schedule and thereafter the "traktsync.db" appears to be permanently locked.

To Reproduce This appears to happen very frequently after sync but im not aware exactly what is being synced at any given time so I dont know if its a timing issue or the db connection is just not getting closed. But I can reproduce it by restarting my device.

Expected behavior A db query should write to the db and immediately close the connection.

Log file here: https://pastebin.com/5tUgJmW6

Kodi Version (please complete the following information):

Additional context I attempeted to force connection closures in "/home/osmc/.kodi/addons/plugin.video.seren/resources/lib/database/init.py" Which did appear to work for the most part but the transactions in "smart_transaction" seemed to never drop the connection causing the db file to be permanently locked?

But the log file is from stock Seren 3.0.0

nixgates commented 1 year ago

Hmm, we were under the assumption we did fix all these occurances in testing. Apparently ones slipped through, we are working on this and a fix should be available in the next update!

runkpocker commented 8 months ago

Was this fixed in 3.0? I havent been able to use Seren reliably for some time due to traktsync.db locking issues.

henryjfry commented 8 months ago

No it wasn't fixed, I think it was actually worse in V3 than in v2 due to other changes.

Depending on how you use seren if you don't sign into trakt with seren then it doesn't cause the error? But that might not be a solution as I'm not sure how it builds the automatic playlist to play consecutive episodes of a show without trakt.

I have continued using seten 2.11 (or whatever the latest version before seren 3 was) and in the router I have disabled the auto maintenance activities associate with trakt.

Doing that seren will occasionally cause everything to stop while it catches series information from trakt when you go to play something. But aside from that it'll scrape and play nice without serious freakouts.

So I suggest you just do that in router.py

henryjfry commented 6 months ago

Ok so i think I may have found a solution for this problem with Seren 3.0.0 which I have been testing the last couple of days.

So the fixes are pretty small:

In "database/init.py" change the timeout to 60 seconds:

/plugin.video.seren/resources/lib/database/init.py

class SQLiteConnection(_connection):
    def __init__(self, path):
        super().__init__()
        self.path = path
        self._create_db_path()

    def _create_connection(self):
        retries = 0
        exception = None
        while retries != 50 and not g.abort_requested():
            try:
                connection = sqlite3.connect(  # pylint: disable=no-member
                    self.path,
                    timeout=60,
                    detect_types=sqlite3.PARSE_DECLTYPES,  # pylint: disable=no-member
                    isolation_level=None,
                    check_same_thread=False,
                )
                self._set_connection_settings(connection)
                return connection
            except Exception as error:
                self._retry_handler(error)
                exception = error
            retries += 1
        # If we reach here we have exceeded our retries so just raise the last exception
        g.log(f"Unable to connect to database '{self.path}' {exception=}", "error")
        raise exception

And in "modules/globals.py" change the variable timezone_string to retrieve the setting using kodi rather than the settings cache.

/home/osmc/.kodi/addons/plugin.video.seren/resources/lib/modules/globals.py

    def _init_local_timezone(self):
        try:
            #timezone_string = self.get_setting("general.localtimezone")
            timezone_string = self.ADDON.getSetting("general.localtimezone")
            if timezone_string:
                self.LOCAL_TIMEZONE = pytz.timezone(timezone_string)
        except pytz.UnknownTimeZoneError:
            self.log(f"Invalid local timezone '{timezone_string}' in settings.xml", "debug")
        except Exception as e:
            self.log(f"Error using local timezone '{timezone_string}' in settings.xml: {e}", "warning")
        finally:
            if not self.LOCAL_TIMEZONE or self.LOCAL_TIMEZONE == self.UTC_TIMEZONE:
                self.init_local_timezone()
henryjfry commented 6 months ago

So i believe the issue is that the maintenance activities which run frequently will occasionally hit the locked DB and the timeout apparently makes this less likely if its given longer to respond? Found that with some googling and it seems to work.

The other thing with the timezone string. I was finding that the "cleanOrphanedMetadata" which would before have potentially crashed kodi was completing but "updateLocalTimezone" was seemingly then crashing kodi.

The nature of the crash is such that it doesnt even generate logs and in my experience those are timing issues in kodi like when you try to refer to a window variable at just the wrong millisecond.

Anyway I started looking at the "updateLocalTimezone" and saw it was referencing the settings cache and figured it neednt do that for that particular function and just getting the setting directly using a kodi method appears to fix the crashing.

Edit: nope it's back crashing at clear orphaned metadata. I might investigate further try and track it down.