Fix to correctly wipe Kodi databases

This commit is contained in:
croneter 2019-11-15 08:24:21 +01:00
parent 19a964ccb2
commit e52b67c3a9
5 changed files with 35 additions and 32 deletions

View file

@ -52,21 +52,25 @@ def catch_operationalerrors(method):
return wrapper
def _initial_db_connection_setup(conn):
def _initial_db_connection_setup(conn, wal_mode):
"""
Set-up DB e.g. for WAL journal mode, if that hasn't already been done
before. Also start a transaction
"""
conn.execute('PRAGMA journal_mode=WAL;')
conn.execute('PRAGMA cache_size = -8000;')
conn.execute('PRAGMA synchronous=NORMAL;')
if wal_mode:
conn.execute('PRAGMA journal_mode=WAL;')
conn.execute('PRAGMA cache_size = -8000;')
conn.execute('PRAGMA synchronous=NORMAL;')
conn.execute('BEGIN')
def connect(media_type=None):
def connect(media_type=None, wal_mode=True):
"""
Open a connection to the Kodi database.
media_type: 'video' (standard if not passed), 'plex', 'music', 'texture'
Pass wal_mode=False if you want the standard (and slower) sqlite
journal_mode, e.g. when wiping entire tables. Useful if you do NOT want
concurrent access to DB for both PKC and Kodi
"""
if media_type == "plex":
db_path = v.DB_PLEX_PATH
@ -80,7 +84,7 @@ def connect(media_type=None):
attempts = DB_WRITE_ATTEMPTS
while True:
try:
_initial_db_connection_setup(conn)
_initial_db_connection_setup(conn, wal_mode)
except sqlite3.OperationalError as err:
if 'database is locked' not in err:
# Not an error we want to catch, so reraise it

View file

@ -61,7 +61,10 @@ def setup_kodi_default_entries():
def reset_cached_images():
LOG.info('Resetting cached artwork')
# Remove all existing textures first
LOG.debug('Resetting the Kodi texture DB')
with KodiTextureDB(wal_mode=False) as kodidb:
kodidb.wipe()
LOG.debug('Deleting all cached image files')
path = path_ops.translate_path('special://thumbnails/')
if path_ops.exists(path):
path_ops.rmtree(path, ignore_errors=True)
@ -72,10 +75,10 @@ def reset_cached_images():
new_path = path_ops.translate_path('special://thumbnails/%s' % path)
try:
path_ops.makedirs(path_ops.encode_path(new_path))
except OSError:
pass
with KodiTextureDB() as kodidb:
kodidb.reset_cached_images()
except OSError as err:
LOG.warn('Could not create thumbnail directory %s: %s',
new_path, err)
LOG.info('Done resetting cached artwork')
def wipe_dbs(music=True):
@ -83,16 +86,18 @@ def wipe_dbs(music=True):
Completely resets the Kodi databases 'video', 'texture' and 'music' (if
music sync is enabled)
DO NOT use context menu as we need to connect without WAL mode - if Kodi
is still accessing the DB
We need to connect without sqlite WAL mode as Kodi might still be accessing
the dbs and we need to prevent that
"""
LOG.warn('Wiping Kodi databases!')
kinds = [KodiVideoDB, KodiTextureDB]
LOG.info('Wiping Kodi video database')
with KodiVideoDB(wal_mode=False) as kodidb:
kodidb.wipe()
if music:
kinds.insert(1, KodiMusicDB)
for kind in kinds:
with kind() as kodidb:
LOG.info('Wiping Kodi music database')
with KodiMusicDB(wal_mode=False) as kodidb:
kodidb.wipe()
reset_cached_images()
setup_kodi_default_entries()
# Delete SQLITE wal files
import xbmc

View file

@ -14,9 +14,12 @@ class KodiDBBase(object):
"""
Kodi database methods used for all types of items
"""
def __init__(self, texture_db=False, kodiconn=None, artconn=None, lock=True):
def __init__(self, texture_db=False, kodiconn=None, artconn=None,
lock=True, wal_mode=True):
"""
Allows direct use with a cursor instead of context mgr
Pass wal_mode=False if you want the standard sqlite journal_mode, e.g.
when wiping entire tables
"""
self._texture_db = texture_db
self.lock = lock
@ -24,13 +27,15 @@ class KodiDBBase(object):
self.cursor = self.kodiconn.cursor() if self.kodiconn else None
self.artconn = artconn
self.artcursor = self.artconn.cursor() if self.artconn else None
self.wal_mode = wal_mode
def __enter__(self):
if self.lock:
KODIDB_LOCK.acquire()
self.kodiconn = db.connect(self.db_kind)
self.kodiconn = db.connect(self.db_kind, self.wal_mode)
self.cursor = self.kodiconn.cursor()
self.artconn = db.connect('texture') if self._texture_db else None
self.artconn = db.connect('texture', self.wal_mode) if self._texture_db \
else None
self.artcursor = self.artconn.cursor() if self._texture_db else None
return self

View file

@ -3,7 +3,6 @@
from __future__ import absolute_import, division, unicode_literals
from . import common
from .. import db
class KodiTextureDB(common.KodiDBBase):
@ -16,11 +15,3 @@ class KodiTextureDB(common.KodiDBBase):
self.artcursor.execute('SELECT url FROM texture WHERE url = ? LIMIT 1',
(url, ))
return self.artcursor.fetchone() is None
@db.catch_operationalerrors
def reset_cached_images(self):
for row in self.cursor.execute('SELECT tbl_name '
'FROM sqlite_master WHERE type=?',
('table', )):
if row[0] != 'version':
self.cursor.execute("DELETE FROM %s" % row[0])

View file

@ -573,12 +573,10 @@ def wipe_database(reboot=True):
# Plex DB completely empty yet. Wipe existing Kodi music only if we
# expect to sync Plex music
music = settings('enableMusic') == 'true'
LOG.info("Resetting all cached artwork.")
kodi_db.wipe_dbs(music)
plex_db.wipe()
LOG.info("Resetting all cached artwork.")
# Remove all cached artwork
kodi_db.reset_cached_images()
# reset the install run flag
settings('SyncInstallRunDone', value="false")
settings('sections_asked_for_machine_identifier', value='')