[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).
This commit is contained in:
Fabio Erculiani
2013-12-07 12:27:55 +01:00
parent 3545f2b619
commit c356d615f3
2 changed files with 70 additions and 21 deletions

View File

@@ -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)

View File

@@ -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(