diff options
Diffstat (limited to 'pym/portage/cache/metadata_overlay.py')
-rw-r--r-- | pym/portage/cache/metadata_overlay.py | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/pym/portage/cache/metadata_overlay.py b/pym/portage/cache/metadata_overlay.py new file mode 100644 index 000000000..d82ba96f8 --- /dev/null +++ b/pym/portage/cache/metadata_overlay.py @@ -0,0 +1,105 @@ +# Copyright 1999-2006 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +import time +if not hasattr(__builtins__, "set"): + from sets import Set as set +from cache import template +from cache.cache_errors import CacheCorruption +from cache.flat_hash import database as db_rw +from cache.metadata import database as db_ro + +class database(template.database): + + serialize_eclasses = False + + def __init__(self, location, label, auxdbkeys, db_rw=db_rw, db_ro=db_ro, + *args, **config): + super_config = config.copy() + super_config.pop("gid", None) + super(database, self).__init__(location, label, auxdbkeys, + *args, **super_config) + self.db_rw = db_rw(location, label, auxdbkeys, **config) + self.commit = self.db_rw.commit + self.autocommits = self.db_rw.autocommits + if isinstance(db_ro, type): + ro_config = config.copy() + ro_config["readonly"] = True + self.db_ro = db_ro(label, "metadata/cache", auxdbkeys, **ro_config) + else: + self.db_ro = db_ro + + def __getitem__(self, cpv): + """funnel whiteout validation through here, since value needs to be fetched""" + try: + value = self.db_rw[cpv] + except KeyError: + return self.db_ro[cpv] # raises a KeyError when necessary + except CacheCorruption: + del self.db_rw[cpv] + return self.db_ro[cpv] # raises a KeyError when necessary + if self._is_whiteout(value): + if self._is_whiteout_valid(cpv, value): + raise KeyError(cpv) + else: + del self.db_rw[cpv] + return self.db_ro[cpv] # raises a KeyError when necessary + else: + return value + + def _setitem(self, name, values): + value_ro = self.db_ro.get(name, None) + if value_ro is not None and \ + self._are_values_identical(value_ro, values): + # we have matching values in the underlying db_ro + # so it is unnecessary to store data in db_rw + try: + del self.db_rw[name] # delete unwanted whiteout when necessary + except KeyError: + pass + return + self.db_rw[name] = values + + def _delitem(self, cpv): + value = self[cpv] # validates whiteout and/or raises a KeyError when necessary + if self.db_ro.has_key(cpv): + self.db_rw[cpv] = self._create_whiteout(value) + else: + del self.db_rw[cpv] + + def __contains__(self, cpv): + try: + self[cpv] # validates whiteout when necessary + except KeyError: + return False + return True + + def iterkeys(self): + s = set() + for cpv in self.db_rw.iterkeys(): + if self.has_key(cpv): # validates whiteout when necessary + yield cpv + # set includes whiteouts so they won't be yielded later + s.add(cpv) + for cpv in self.db_ro.iterkeys(): + if cpv not in s: + yield cpv + + def _is_whiteout(self, value): + return value["EAPI"] == "whiteout" + + def _create_whiteout(self, value): + return {"EAPI":"whiteout","_eclasses_":value["_eclasses_"],"_mtime_":value["_mtime_"]} + + def _is_whiteout_valid(self, name, value_rw): + try: + value_ro = self.db_ro[name] + return self._are_values_identical(value_rw,value_ro) + except KeyError: + return False + + def _are_values_identical(self, value1, value2): + if long(value1["_mtime_"]) != long(value2["_mtime_"]): + return False + return value1["_eclasses_"] == value2["_eclasses_"] |