In order to avoid having BlockerDB instantiate a new FakeVartree for each
authorZac Medico <zmedico@gentoo.org>
Sun, 13 Jul 2008 05:29:35 +0000 (05:29 -0000)
committerZac Medico <zmedico@gentoo.org>
Sun, 13 Jul 2008 05:29:35 +0000 (05:29 -0000)
merge, add a FakeVartree.sync() method and so that the same FakeVartree
can be reused. Package counters and timestamps are used to validate package
instances during each sync() call.

svn path=/main/trunk/; revision=11033

pym/_emerge/__init__.py

index 4f5042567048c3b9932c7b2046105903be40718c..ac2d63b28a72793213207c8f347a2547f7f44087 100644 (file)
@@ -1014,6 +1014,7 @@ class FakeVartree(portage.vartree):
        global updates are necessary (updates are performed when necessary if there
        is not a matching ebuild in the tree)."""
        def __init__(self, root_config, pkg_cache=None, acquire_lock=1):
+               self._root_config = root_config
                if pkg_cache is None:
                        pkg_cache = {}
                real_vartree = root_config.trees["vartree"]
@@ -1116,6 +1117,80 @@ class FakeVartree(portage.vartree):
                                pkg, self.dbapi, self._global_updates)
                return self._aux_get(pkg, wants)
 
+       def sync(self, acquire_lock=1):
+               """
+               Call this method to synchronize state with the real vardb
+               after one or more packages may have been installed or
+               uninstalled.
+               """
+               vdb_path = os.path.join(self.root, portage.VDB_PATH)
+               try:
+                       # At least the parent needs to exist for the lock file.
+                       portage.util.ensure_dirs(vdb_path)
+               except portage.exception.PortageException:
+                       pass
+               vdb_lock = None
+               try:
+                       if acquire_lock and os.access(vdb_path, os.W_OK):
+                               vdb_lock = portage.locks.lockdir(vdb_path)
+                       self._sync()
+               finally:
+                       if vdb_lock:
+                               portage.locks.unlockdir(vdb_lock)
+
+       def _sync(self):
+
+               real_vardb = self._root_config.trees["vartree"].dbapi
+               current_cpv_set = frozenset(real_vardb.cpv_all())
+               pkg_vardb = self.dbapi
+               aux_get_history = self._aux_get_history
+
+               # Remove any packages that have been uninstalled.
+               for pkg in list(pkg_vardb):
+                       if pkg.cpv not in current_cpv_set:
+                               pkg_vardb.cpv_remove(pkg)
+                               aux_get_history.discard(pkg.cpv)
+
+               # Validate counters and timestamps.
+               slot_counters = {}
+               root = self.root
+               validation_keys = ["COUNTER", "_mtime_"]
+               for cpv in current_cpv_set:
+
+                       pkg_hash_key = ("installed", root, cpv, "nomerge")
+                       pkg = pkg_vardb.get(pkg_hash_key)
+                       if pkg is not None:
+                               counter, mtime = real_vardb.aux_get(cpv, validation_keys)
+
+                               if counter != pkg.metadata["COUNTER"] or \
+                                       mtime != pkg.mtime:
+                                       pkg_vardb.cpv_remove(pkg)
+                                       aux_get_history.discard(pkg.cpv)
+                                       pkg = None
+
+                       if pkg is None:
+                               pkg = self._pkg(cpv)
+
+                       other_counter = slot_counters.get(pkg.slot_atom)
+                       if other_counter is not None:
+                               if other_counter > pkg.counter:
+                                       continue
+
+                       slot_counters[pkg.slot_atom] = pkg.counter
+                       pkg_vardb.cpv_inject(pkg)
+
+               real_vardb.flush_cache()
+
+       def _pkg(self, cpv):
+               root_config = self._root_config
+               real_vardb = root_config.trees["vartree"].dbapi
+               pkg = Package(cpv=cpv, installed=True,
+                       metadata=izip(Package.metadata_keys,
+                               real_vardb.aux_get(cpv, Package.metadata_keys)),
+                       root_config=root_config,
+                       type_name="installed")
+               return pkg
+
 def grab_global_updates(portdir):
        from portage.update import grab_updates, parse_updates
        updpath = os.path.join(portdir, "profiles", "updates")
@@ -3494,20 +3569,31 @@ class BlockerDB(object):
                self._root_config = root_config
                self._vartree = root_config.trees["vartree"]
                self._portdb = root_config.trees["porttree"].dbapi
-                       
-               self._dep_check_trees = { self._vartree.root : {
-                       "porttree"    :  self._vartree,
-                       "vartree"     :  self._vartree,
-               }}
+
+               self._dep_check_trees = None
+               self._fake_vartree = None
+
+       def _get_fake_vartree(self, acquire_lock=0):
+               fake_vartree = self._fake_vartree
+               if fake_vartree is None:
+                       fake_vartree = FakeVartree(self._root_config,
+                               acquire_lock=acquire_lock)
+                       self._fake_vartree = fake_vartree
+                       self._dep_check_trees = { self._vartree.root : {
+                               "porttree"    :  fake_vartree,
+                               "vartree"     :  fake_vartree,
+                       }}
+               else:
+                       fake_vartree.sync(acquire_lock=acquire_lock)
+               return fake_vartree
 
        def findInstalledBlockers(self, new_pkg, acquire_lock=0):
                blocker_cache = BlockerCache(self._vartree.root, self._vartree.dbapi)
                dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
-               dep_check_trees = self._dep_check_trees
                settings = self._vartree.settings
                stale_cache = set(blocker_cache)
-               fake_vartree = \
-                       FakeVartree(self._root_config, acquire_lock=acquire_lock)
+               fake_vartree = self._get_fake_vartree(acquire_lock=acquire_lock)
+               dep_check_trees = self._dep_check_trees
                vardb = fake_vartree.dbapi
                installed_pkgs = list(vardb)
 
@@ -3665,6 +3751,19 @@ class PackageVirtualDbapi(portage.dbapi):
                        return True
                return False
 
+       def get(self, item, default=None):
+               cpv = getattr(item, "cpv", None)
+               if cpv is None:
+                       if len(item) != 4:
+                               return default
+                       type_name, root, cpv, operation = item
+
+               existing = self._cpv_map.get(cpv)
+               if existing is not None and \
+                       existing == item:
+                       return existing
+               return default
+
        def match_pkgs(self, atom):
                return [self._cpv_map[cpv] for cpv in self.match(atom)]
 
@@ -8213,10 +8312,12 @@ class Scheduler(PollScheduler):
                        self.edebug = 1
                self.pkgsettings = {}
                self._config_pool = {}
+               self._blocker_db = {}
                for root in trees:
                        self.pkgsettings[root] = portage.config(
                                clone=trees[root]["vartree"].settings)
                        self._config_pool[root] = []
+                       self._blocker_db[root] = BlockerDB(trees[root]["root_config"])
                self.curval = 0
                self._logger = self._emerge_log_class(
                        xterm_titles=("notitles" not in settings.features))
@@ -8378,7 +8479,7 @@ class Scheduler(PollScheduler):
                import gc
                gc.collect()
 
-               blocker_db = BlockerDB(self.trees[new_pkg.root]["root_config"])
+               blocker_db = self._blocker_db[new_pkg.root]
 
                blocker_dblinks = []
                for blocking_pkg in blocker_db.findInstalledBlockers(