From c356d615f357d736aa8905c00928fd3c79236645 Mon Sep 17 00:00:00 2001 From: Fabio Erculiani Date: Sat, 7 Dec 2013 12:27:55 +0100 Subject: [PATCH] [Rigo] use direct access to the installed packages repository, avoid locking Locking is too expensive, and using memory cached data may result in huge inconsistencies due to stale data. Direct mode allows to skip memory cache and read data directly from the database storage. However, entropy.db.sqlite queries using memory caches did not perform very well when cache is cold. But this has been solved by directed() already (a different query is run if memory cache is disabled). --- rigo/rigo/models/application.py | 63 ++++++++++++++++--- rigo/rigo/ui/gtk3/controllers/applications.py | 28 +++++---- 2 files changed, 70 insertions(+), 21 deletions(-) diff --git a/rigo/rigo/models/application.py b/rigo/rigo/models/application.py index dc7ccc53c..0d629bf44 100644 --- a/rigo/rigo/models/application.py +++ b/rigo/rigo/models/application.py @@ -45,6 +45,7 @@ from rigo.enums import Icons from rigo.utils import build_application_store_url, escape_markup, \ prepare_markup + class ReviewStats(object): NO_RATING = 0 @@ -929,6 +930,25 @@ class ApplicationMetadata(object): _ICON_DISCARD_SIGNALS.append(discard_signal) +def direct(method): + """ + Enable direct access to the EntropyRepository instance + skipping memory cache in case of Installed Packages repository. + This avoids having to acquire a shared or exclusive lock at + the price of reading stale data. + """ + def wrapped(self, *args, **kwargs): + repo = self._entropy.open_repository(self._repo_id) + inst_repo = self._entropy.installed_repository() + if repo is inst_repo: + with inst_repo.direct(): + return method(self, *args, **kwargs) + else: + return method(self, *args, **kwargs) + + return wrapped + + # this is a very lean class as its used in the main listview # and there are a lot of application objects in memory class Application(object): @@ -973,6 +993,7 @@ class Application(object): self._vanished_callback = vanished_callback @property + @direct def name(self): """Show user visible name""" with self._entropy.rwsem().reader(): @@ -1018,6 +1039,7 @@ class Application(object): with self._entropy.rwsem().reader(): return self._is_installed_app() + @direct def _is_installed_app(self): """ Return whether this Application object describes an @@ -1027,6 +1049,7 @@ class Application(object): inst_repo = self._entropy.installed_repository() return repo is inst_repo + @direct def _get_installed(self): """ Application.get_installed() method body. @@ -1060,6 +1083,7 @@ class Application(object): (package_id, inst_repo.repository_id()), redraw_callback=self._redraw_callback) + @direct def _source_repository_id(self, repo): """ Return the actual repository name (if possible) if @@ -1076,6 +1100,7 @@ class Application(object): repository_id = _repository_id return repository_id + @direct def get_installed(self): """ Return the Application object of the installed @@ -1085,6 +1110,7 @@ class Application(object): with self._entropy.rwsem().reader(): return self._get_installed() + @direct def is_updatable(self): """ Return if Application can be updated. @@ -1110,6 +1136,7 @@ class Application(object): else: return True + @direct def _get_removal_queue(self): """ Return Application removal queue. @@ -1120,6 +1147,7 @@ class Application(object): except DependenciesNotRemovable: return None + @direct def get_removal_queue(self): """ Return a list of Applications that would be removed. @@ -1138,6 +1166,7 @@ class Application(object): remove.append(app) return remove + @direct def is_removable(self): """ Return if Application can be removed or it's part of @@ -1159,6 +1188,7 @@ class Application(object): except DependenciesNotRemovable: return False + @direct def _get_install_queue(self): """ Return Application install and removal queues. @@ -1173,18 +1203,18 @@ class Application(object): if masked: return None - with inst_repo.shared(): - try: - install_queue, removal_queue = \ - self._entropy.get_install_queue( - [pkg_match], False, False) - except DependenciesNotFound: - raise - except DependenciesCollision: - raise + try: + install_queue, removal_queue = \ + self._entropy.get_install_queue( + [pkg_match], False, False) + except DependenciesNotFound: + raise + except DependenciesCollision: + raise return install_queue, removal_queue + @direct def get_install_conflicts(self): """ Return a list of Application objects belonging to @@ -1214,6 +1244,7 @@ class Application(object): except DependenciesCollision: return None + @direct def get_install_queue(self): """ Return a tuple composed by a list of Applications that @@ -1258,6 +1289,7 @@ class Application(object): "get_install_queue: DependenciesCollision: %s" % (err,)) return None + @direct def accept_licenses(self, install_queue): """ Return a mapping representing the licenses to accept, @@ -1276,6 +1308,7 @@ class Application(object): obj.append(pkg_map[pkg_match]) return license_map + @direct def is_installable(self): """ Return if Application can be installed or it's masked @@ -1300,6 +1333,7 @@ class Application(object): return True + @direct def is_available(self): """ Return if Application is actually available in repos, @@ -1311,6 +1345,7 @@ class Application(object): repo = self._entropy.open_repository(self._repo_id) return repo.isPackageIdAvailable(self._pkg_id) + @direct def get_markup(self): """ Get Application markup text. @@ -1342,6 +1377,7 @@ class Application(object): escape_markup(description)) return text + @direct def search(self, keyword): """ Match keyword against Application name. Return True if @@ -1352,6 +1388,7 @@ class Application(object): return True return keyword.lower() in name.lower() + @direct def get_extended_markup(self): """ Get Application markup text (extended version). @@ -1426,6 +1463,7 @@ class Application(object): ) return text + @direct def get_info_markup(self): """ Get Application info markup text. @@ -1538,6 +1576,7 @@ class Application(object): ) return text + @direct def get_review_stats(self, _still_visible_cb=None, cached=False): """ Return ReviewStats object containing user review @@ -1575,6 +1614,7 @@ class Application(object): stat.downloads_total = down return stat + @direct def get_icon(self, _still_visible_cb=None, cached=False): """ Return Application Icon image Entropy Document object. @@ -1610,6 +1650,7 @@ class Application(object): return icon, cache_hit + @direct def download_comments(self, callback, offset=0): """ Return Application Comments Entropy Document object. @@ -1636,6 +1677,7 @@ class Application(object): "Application{%s}.download_comments called" % ( self._pkg_match,)) + @direct def download_images(self, callback, offset=0): """ Return Application Images Entropy Document object. @@ -1695,7 +1737,7 @@ class Application(object): return -1 return progress - # get a AppDetails object for this Applications + @direct def get_details(self): """ Return a new AppDetails object for this application @@ -1704,6 +1746,7 @@ class Application(object): self._service, self._pkg_match, self, redraw_callback=self._redraw_callback) + @direct def __str__(self): with self._entropy.rwsem().reader(): repo = self._entropy.open_repository(self._repo_id) diff --git a/rigo/rigo/ui/gtk3/controllers/applications.py b/rigo/rigo/ui/gtk3/controllers/applications.py index 6c5fa7710..4526b63b5 100644 --- a/rigo/rigo/ui/gtk3/controllers/applications.py +++ b/rigo/rigo/ui/gtk3/controllers/applications.py @@ -181,16 +181,20 @@ class ApplicationsViewController(GObject.Object): if search_cmd == ApplicationsViewController.SHOW_INSTALLED_KEY: use_fallback = False sort = True + inst_repo = self._entropy.installed_repository() - if not search_args: - for pkg_id in inst_repo.listAllPackageIds( - order_by="atom"): - matches.append((pkg_id, inst_repo.repository_id())) - else: - for search_arg in search_args: - for pkg_id in inst_repo.searchPackages( - search_arg.lower(), just_id=True): + with inst_repo.direct(): + if not search_args: + for pkg_id in inst_repo.listAllPackageIds( + order_by="atom"): matches.append((pkg_id, inst_repo.repository_id())) + else: + for search_arg in search_args: + for pkg_id in inst_repo.searchPackages( + search_arg.lower(), just_id=True): + matches.append( + (pkg_id, inst_repo.repository_id())) + elif search_cmd == \ ApplicationsViewController.SHOW_CATEGORY_KEY and \ search_args: @@ -316,7 +320,8 @@ class ApplicationsViewController(GObject.Object): with self._entropy.rwsem().reader(): inst_repo = self._entropy.installed_repository() pkg_repo = inst_repo.repository_id() - pkg_id, rc = inst_repo.atomMatch(dependency) + with inst_repo.direct(): + pkg_id, rc = inst_repo.atomMatch(dependency) if pkg_id == -1: const_debug_write( @@ -395,8 +400,9 @@ class ApplicationsViewController(GObject.Object): "%s" % (text,)) with self._entropy.rwsem().reader(): inst_repo = self._entropy.installed_repository() - pkg_ids = inst_repo.searchPackages(text, just_id=True) - manual_pkg_ids, rc = inst_repo.atomMatch(text, multiMatch=True) + with inst_repo.direct(): + pkg_ids = inst_repo.searchPackages(text, just_id=True) + manual_pkg_ids, rc = inst_repo.atomMatch(text, multiMatch=True) def _notify(): self._service._unsupported_applications_signal(