Add a lock to allow plugins to sync access to the Kobo db

This commit is contained in:
Kovid Goyal 2025-03-11 11:32:57 +05:30
parent 7aa9d1d7fc
commit 05bc7e966e
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -4,12 +4,17 @@
import os import os
import shutil import shutil
from contextlib import closing, suppress from contextlib import closing, suppress
from threading import RLock
import apsw import apsw
from calibre.prints import debug_print from calibre.prints import debug_print
from calibre.ptempfile import PersistentTemporaryFile, TemporaryDirectory from calibre.ptempfile import PersistentTemporaryFile, TemporaryDirectory
# Any plugins not running in the device thread must acquire this lock before
# trying to access the Kobo database.
kobo_db_lock = RLock()
def row_factory(cursor: apsw.Cursor, row): def row_factory(cursor: apsw.Cursor, row):
return {k[0]: row[i] for i, k in enumerate(cursor.getdescription())} return {k[0]: row[i] for i, k in enumerate(cursor.getdescription())}
@ -68,14 +73,18 @@ class Database:
raise raise
def __enter__(self) -> apsw.Connection: def __enter__(self) -> apsw.Connection:
kobo_db_lock.acquire()
self.conn = apsw.Connection(self.dbpath) self.conn = apsw.Connection(self.dbpath)
if self.use_row_factory: if self.use_row_factory:
self.conn.setrowtrace(row_factory) self.conn.setrowtrace(row_factory)
return self.conn.__enter__() return self.conn.__enter__()
def __exit__(self, exc_type, exc_value, tb) -> bool | None: def __exit__(self, exc_type, exc_value, tb) -> bool | None:
with closing(self.conn): try:
suppress_exception = self.conn.__exit__(exc_type, exc_value, tb) with closing(self.conn):
if self.needs_copy and (suppress_exception or (exc_type is None and exc_value is None and tb is None)): suppress_exception = self.conn.__exit__(exc_type, exc_value, tb)
copy_db(self.conn, self.path_on_device) if self.needs_copy and (suppress_exception or (exc_type is None and exc_value is None and tb is None)):
copy_db(self.conn, self.path_on_device)
finally:
kobo_db_lock.release()
return suppress_exception return suppress_exception