diff --git a/src/calibre/db/cache.py b/src/calibre/db/cache.py index d18bffa986..144d19b119 100644 --- a/src/calibre/db/cache.py +++ b/src/calibre/db/cache.py @@ -2379,27 +2379,31 @@ class Cache: def __del__(self): self.close() - @write_api + @api def close(self): - if hasattr(self, 'close_called'): - return - self.close_called = True - self.shutting_down = True - self.event_dispatcher.close() - if self.fts_queue_thread is not None: - self.fts_job_queue.put(None) - from calibre.customize.ui import available_library_closed_plugins - for plugin in available_library_closed_plugins(): - try: - plugin.run(self) - except Exception: - import traceback - traceback.print_exc() + with self.write_lock: + if hasattr(self, 'close_called'): + return + self.close_called = True + self.shutting_down = True + self.event_dispatcher.close() + if self.fts_queue_thread is not None: + self.fts_job_queue.put(None) + from calibre.customize.ui import available_library_closed_plugins + for plugin in available_library_closed_plugins(): + try: + plugin.run(self) + except Exception: + import traceback + traceback.print_exc() + # the fts supervisor thread could be in the middle of committing a + # result to the db, so holding a lock here will cause a deadlock self.backend.shutdown_fts() if self.fts_queue_thread is not None: self.fts_queue_thread.join() self.fts_queue_thread = None - self.backend.close() + with self.write_lock: + self.backend.close() @property def is_closed(self): diff --git a/src/calibre/db/fts/pool.py b/src/calibre/db/fts/pool.py index 768d82a2ce..675dd7addd 100644 --- a/src/calibre/db/fts/pool.py +++ b/src/calibre/db/fts/pool.py @@ -129,6 +129,7 @@ class Pool: self.workers = [] self.initialized = Event() self.dbref = dbref + self.keep_going = True def initialize(self): if not self.initialized.is_set(): @@ -202,10 +203,13 @@ class Pool: def shutdown(self): if self.initialized.is_set(): - self.supervise_queue.put(quit) + self.keep_going = False + for i in range(2): + self.supervise_queue.put(quit) for w in self.workers: w.keep_going = False - self.jobs_queue.put(quit) + for i in range(2*len(self.workers)): + self.jobs_queue.put(quit) self.supervisor_thread.join() for w in self.workers: w.join() @@ -219,7 +223,7 @@ class Pool: db.queue_next_fts_job() def supervise(self): - while True: + while self.keep_going: x = self.supervise_queue.get() try: if x is check_for_work: