From 05ed2747260954b35d01d421ebac4de575f87db9 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 16 Dec 2010 13:55:10 -0700 Subject: [PATCH] Disable the cover cache. This means that if you are running calibre on an underpowered machine, you might notice some slow down in the cover browser. On the other hand, calibre's memory consumption will be reduced. --- src/calibre/gui2/library/models.py | 46 +----------- src/calibre/gui2/ui.py | 3 - src/calibre/library/caches.py | 115 +---------------------------- 3 files changed, 6 insertions(+), 158 deletions(-) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 37d7d56ce1..e0d5c64961 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -12,7 +12,7 @@ from operator import attrgetter from PyQt4.Qt import QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage, \ QModelIndex, QVariant, QDate -from calibre.gui2 import NONE, config, UNDEFINED_QDATE, FunctionDispatcher +from calibre.gui2 import NONE, config, UNDEFINED_QDATE from calibre.utils.pyparsing import ParseException from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors from calibre.ptempfile import PersistentTemporaryFile @@ -22,7 +22,7 @@ from calibre.utils.icu import sort_key, strcmp as icu_strcmp from calibre.ebooks.metadata.meta import set_metadata as _set_metadata from calibre.utils.search_query_parser import SearchQueryParser from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \ - REGEXP_MATCH, CoverCache, MetadataBackup + REGEXP_MATCH, MetadataBackup from calibre.library.cli import parse_series_string from calibre import strftime, isbytestring, prepare_string_for_xml from calibre.constants import filesystem_encoding, DEBUG @@ -89,7 +89,6 @@ class BooksModel(QAbstractTableModel): # {{{ self.headers = {} self.alignment_map = {} self.buffer_size = buffer - self.cover_cache = None self.metadata_backup = None self.bool_yes_icon = QIcon(I('ok.png')) self.bool_no_icon = QIcon(I('list_remove.png')) @@ -113,10 +112,6 @@ class BooksModel(QAbstractTableModel): # {{{ def is_custom_column(self, cc_label): return cc_label in self.custom_columns - def clear_caches(self): - if self.cover_cache: - self.cover_cache.clear_cache() - def read_config(self): self.use_roman_numbers = config['use_roman_numerals_for_series_number'] @@ -154,18 +149,8 @@ class BooksModel(QAbstractTableModel): # {{{ self.build_data_convertors() self.reset() self.database_changed.emit(db) - if self.cover_cache is not None: - self.cover_cache.stop() - # Would like to to a join here, but the thread might be waiting to - # do something on the GUI thread. Deadlock. - self.cover_cache = CoverCache(db, FunctionDispatcher(self.db.cover)) - self.cover_cache.start() self.stop_metadata_backup() self.start_metadata_backup() - def refresh_cover(event, ids): - if event == 'cover' and self.cover_cache is not None: - self.cover_cache.refresh(ids) - db.add_listener(refresh_cover) def start_metadata_backup(self): self.metadata_backup = MetadataBackup(self.db) @@ -225,7 +210,6 @@ class BooksModel(QAbstractTableModel): # {{{ def books_deleted(self): self.count_changed() - self.clear_caches() self.reset() def delete_books(self, indices): @@ -254,7 +238,6 @@ class BooksModel(QAbstractTableModel): # {{{ return self.last_search = text if reset: - self.clear_caches() self.reset() if self.last_search: # Do not issue search done for the null search. It is used to clear @@ -269,7 +252,6 @@ class BooksModel(QAbstractTableModel): # {{{ label = self.column_map[col] self.db.sort(label, ascending) if reset: - self.clear_caches() self.reset() self.sorted_on = (label, order) self.sort_history.insert(0, self.sorted_on) @@ -357,26 +339,10 @@ class BooksModel(QAbstractTableModel): # {{{ data[name] = val return data - def set_cache(self, idx): - l, r = 0, self.count()-1 - if self.cover_cache is not None: - l = max(l, idx-self.buffer_size) - r = min(r, idx+self.buffer_size) - k = min(r-idx, idx-l) - ids = [idx] - for i in range(1, k): - ids.extend([idx-i, idx+i]) - ids = ids + [i for i in range(l, r, 1) if i not in ids] - try: - ids = [self.db.id(i) for i in ids] - except IndexError: - return - self.cover_cache.set_cache(ids) def current_changed(self, current, previous, emit_signal=True): if current.isValid(): idx = current.row() - self.set_cache(idx) data = self.get_book_display_info(idx) if emit_signal: self.new_bookdisplay_data.emit(data) @@ -533,13 +499,7 @@ class BooksModel(QAbstractTableModel): # {{{ def cover(self, row_number): data = None try: - id = self.db.id(row_number) - if self.cover_cache is not None: - img = self.cover_cache.cover(id) - if not img.isNull(): - return img - if not data: - data = self.db.cover(row_number) + data = self.db.cover(row_number) except IndexError: # Happens if database has not yet been refreshed pass diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index c3e0bcb0da..219a76bceb 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -583,9 +583,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ while self.spare_servers: self.spare_servers.pop().close() self.device_manager.keep_going = False - cc = self.library_view.model().cover_cache - if cc is not None: - cc.stop() mb = self.library_view.model().metadata_backup if mb is not None: mb.stop() diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py index a99c9df125..ff3aa0bf67 100644 --- a/src/calibre/library/caches.py +++ b/src/calibre/library/caches.py @@ -9,10 +9,8 @@ __docformat__ = 'restructuredtext en' import re, itertools, time, traceback from itertools import repeat from datetime import timedelta -from threading import Thread, RLock -from Queue import Queue, Empty - -from PyQt4.Qt import QImage, Qt +from threading import Thread +from Queue import Empty from calibre.utils.config import tweaks from calibre.utils.date import parse_date, now, UNDEFINED_DATE @@ -20,7 +18,7 @@ from calibre.utils.search_query_parser import SearchQueryParser from calibre.utils.pyparsing import ParseException from calibre.ebooks.metadata import title_sort from calibre.ebooks.metadata.opf2 import metadata_to_opf -from calibre import fit_image, prints +from calibre import prints class MetadataBackup(Thread): # {{{ ''' @@ -118,113 +116,6 @@ class MetadataBackup(Thread): # {{{ # }}} -class CoverCache(Thread): # {{{ - - def __init__(self, db, cover_func): - Thread.__init__(self) - self.daemon = True - self.db = db - self.cover_func = cover_func - self.load_queue = Queue() - self.keep_running = True - self.cache = {} - self.lock = RLock() - self.allowed_ids = frozenset([]) - self.null_image = QImage() - - def stop(self): - self.keep_running = False - - def _image_for_id(self, id_): - img = self.cover_func(id_, index_is_id=True, as_image=True) - if img is None: - img = QImage() - if not img.isNull(): - scaled, nwidth, nheight = fit_image(img.width(), - img.height(), 600, 800) - if scaled: - img = img.scaled(nwidth, nheight, Qt.KeepAspectRatio, - Qt.SmoothTransformation) - - return img - - def run(self): - while self.keep_running: - try: - # The GUI puts the same ID into the queue many times. The code - # below emptys the queue, building a set of unique values. When - # the queue is empty, do the work - ids = set() - id_ = self.load_queue.get(True, 2) - ids.add(id_) - try: - while True: - # Give the gui some time to put values into the queue - id_ = self.load_queue.get(True, 0.5) - ids.add(id_) - except Empty: - pass - except: - # Happens during shutdown - break - except Empty: - continue - except: - #Happens during interpreter shutdown - break - if not self.keep_running: - break - for id_ in ids: - time.sleep(0.050) # Limit 20/second to not overwhelm the GUI - if not self.keep_running: - return - with self.lock: - if id_ not in self.allowed_ids: - continue - try: - img = self._image_for_id(id_) - except: - try: - traceback.print_exc() - except: - # happens during shutdown - break - continue - try: - with self.lock: - self.cache[id_] = img - except: - # Happens during interpreter shutdown - break - - def set_cache(self, ids): - with self.lock: - self.allowed_ids = frozenset(ids) - already_loaded = set([]) - for id in self.cache.keys(): - if id in ids: - already_loaded.add(id) - else: - self.cache.pop(id) - for id_ in set(ids) - already_loaded: - self.load_queue.put(id_) - - def cover(self, id_): - with self.lock: - return self.cache.get(id_, self.null_image) - - def clear_cache(self): - with self.lock: - self.cache = {} - - def refresh(self, ids): - with self.lock: - for id_ in ids: - cover = self.cache.pop(id_, None) - if cover is not None: - self.load_queue.put(id_) -# }}} - ### Global utility function for get_match here and in gui2/library.py CONTAINS_MATCH = 0 EQUALS_MATCH = 1