[entropy.client] avoid calling close() on cached repositories and make the cache explode, improve constraints on repository objects

This commit is contained in:
Fabio Erculiani
2011-03-05 00:04:59 +01:00
parent cdb8ee7e8b
commit 96d8deb0d2
3 changed files with 51 additions and 10 deletions
@@ -757,8 +757,9 @@ class Client(Singleton, TextInterface, LoadersMixin, CacheMixin, CalculatorsMixi
"""
self.__instance_destroyed = True
if hasattr(self, '_installed_repository'):
if self._installed_repository != None:
self._installed_repository.close()
if self._installed_repository is not None:
self._installed_repository.close(
_token = etpConst['clientdbid'])
if hasattr(self, 'logger'):
self.logger.close()
if hasattr(self, '_settings') and \
+37 -3
View File
@@ -79,8 +79,38 @@ class ClientEntropyRepositoryPlugin(EntropyRepositoryPlugin):
return 0
class CachedRepository(EntropyRepository):
"""
This kind of repository cannot have close() called directly, without
a valid token passed. This is because the class object is cached somewhere
and calling close() would turn into a software bug.
"""
def setCloseToken(self, token):
"""
Set a token that can be used to validate close() calls. Calling
close() on these repos is prohibited and considered a software bug.
Only Entropy Client should be able to close them.
"""
self._close_token = token
class InstalledPackagesRepository(EntropyRepository):
def close(self, _token = None):
"""
Reimplemented from EntropyRepository
"""
close_token = getattr(self, "_close_token", None)
if close_token is not None:
if (_token is None) or (_token != close_token):
raise PermissionDenied(
"cannot close this repository directly. Software bug!")
return EntropyRepository.close(self)
def __del__(self):
"""
Cannot honor the constraint in this case, sorry!
"""
return EntropyRepository.close(self)
class InstalledPackagesRepository(CachedRepository):
"""
This class represents the installed packages repository and is a direct
subclass of EntropyRepository.
@@ -2387,7 +2417,7 @@ class MaskableRepository(EntropyRepositoryBase):
return -1, myr
class AvailablePackagesRepository(EntropyRepository, MaskableRepository):
class AvailablePackagesRepository(CachedRepository, MaskableRepository):
"""
This class represents the available packages repository and is a direct
subclass of EntropyRepository. It implements the update() method in order
@@ -2467,10 +2497,14 @@ class AvailablePackagesRepository(EntropyRepository, MaskableRepository):
EntropyRepository.clearCache(self)
class GenericRepository(EntropyRepository, MaskableRepository):
class GenericRepository(CachedRepository, MaskableRepository):
"""
This class represents a generic packages repository and is a direct
subclass of EntropyRepository.
Even GenericRepository is a CachedRepository because its object could
get cached by 3rd party. Actually, we require this because our installed
packages repository could end up being a GenericRepository, when running
in fail-safe mode.
"""
def handlePackage(self, pkg_data, forcedRevision = -1,
+11 -5
View File
@@ -62,9 +62,12 @@ class RepositoryMixin:
def ensure_closed_repo(repoid):
key = self.__get_repository_cache_key(repoid)
for cache_obj in (self._repodb_cache, self._memory_db_instances):
obj = cache_obj.pop(key, None)
if obj is None:
continue
try:
cache_obj.pop(key).close()
except (KeyError, AttributeError, OperationalError):
obj.close(_token = repoid)
except OperationalError:
pass
t2 = _("Please update your repositories now in order to remove this message!")
@@ -149,6 +152,7 @@ class RepositoryMixin:
def close_repositories(self, mask_clear = True):
for item in sorted(self._repodb_cache.keys()):
repository_id, root = item
# in-memory repositories cannot be closed
# otherwise everything will be lost, to
# effectively close these repos you
@@ -156,7 +160,7 @@ class RepositoryMixin:
if item in self._memory_db_instances:
continue
try:
self._repodb_cache.pop(item).close()
self._repodb_cache.pop(item).close(_token = repository_id)
except OperationalError as err: # wtf!
sys.stderr.write("!!! Cannot close Entropy repos: %s\n" % (
err,))
@@ -265,6 +269,7 @@ class RepositoryMixin:
xcache = xcache,
indexing = indexing
)
conn.setCloseToken(repoid)
self._add_plugin_to_client_repository(conn)
if (repoid not in self._treeupdates_repos) and \
@@ -788,6 +793,7 @@ class RepositoryMixin:
name = etpConst['clientdbid'],
xcache = self.xcache, indexing = self.indexing
)
conn.setCloseToken(etpConst['clientdbid'])
self._add_plugin_to_client_repository(conn)
# TODO: remove this in future, drop useless data from clientdb
except (DatabaseError,):
@@ -800,7 +806,7 @@ class RepositoryMixin:
conn.validate()
except SystemDatabaseError:
try:
conn.close()
conn.close(_token = etpConst['clientdbid'])
except (RepositoryPluginError, OSError, IOError):
pass
entropy.tools.print_traceback(f = self.logger)
@@ -810,7 +816,7 @@ class RepositoryMixin:
return conn
def reopen_installed_repository(self):
self._installed_repository.close()
self._installed_repository.close(_token = etpConst['clientdbid'])
self._open_installed_repository()
# make sure settings are in sync
self._settings.clear()