[PATCH 09 of 10 V2] branchmap: make update a method

Pierre-Yves David pierre-yves.david at ens-lyon.org
Sun Dec 23 19:53:41 CST 2012


# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at ens-lyon.org>
# Date 1356192495 -3600
# Node ID f0eeb9b3444aaf4934a03cff079337377bec7737
# Parent  1b05ffce47bdaff256a48fabc65bffb63fca9ba5
branchmap: make update a method

diff --git a/mercurial/branchmap.py b/mercurial/branchmap.py
--- a/mercurial/branchmap.py
+++ b/mercurial/branchmap.py
@@ -40,91 +40,10 @@ def read(repo):
         if repo.ui.debugflag:
             repo.ui.warn(str(inst), '\n')
         partial = branchcache()
     return partial
 
-def update(repo, partial, ctxgen):
-    """Given a branchhead cache, partial, that may have extra nodes or be
-    missing heads, and a generator of nodes that are at least a superset of
-    heads missing, this function updates partial to be correct.
-    """
-    cl = repo.changelog
-    # collect new branch entries
-    newbranches = {}
-    for c in ctxgen:
-        newbranches.setdefault(c.branch(), []).append(c.node())
-    # if older branchheads are reachable from new ones, they aren't
-    # really branchheads. Note checking parents is insufficient:
-    # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
-    for branch, newnodes in newbranches.iteritems():
-        bheads = partial.setdefault(branch, [])
-        # Remove candidate heads that no longer are in the repo (e.g., as
-        # the result of a strip that just happened).  Avoid using 'node in
-        # self' here because that dives down into branchcache code somewhat
-        # recursively.
-        bheadrevs = [cl.rev(node) for node in bheads
-                     if cl.hasnode(node)]
-        newheadrevs = [cl.rev(node) for node in newnodes
-                       if cl.hasnode(node)]
-        ctxisnew = bheadrevs and min(newheadrevs) > max(bheadrevs)
-        # Remove duplicates - nodes that are in newheadrevs and are already
-        # in bheadrevs.  This can happen if you strip a node whose parent
-        # was already a head (because they're on different branches).
-        bheadrevs = sorted(set(bheadrevs).union(newheadrevs))
-
-        # Starting from tip means fewer passes over reachable.  If we know
-        # the new candidates are not ancestors of existing heads, we don't
-        # have to examine ancestors of existing heads
-        if ctxisnew:
-            iterrevs = sorted(newheadrevs)
-        else:
-            iterrevs = list(bheadrevs)
-
-        # This loop prunes out two kinds of heads - heads that are
-        # superseded by a head in newheadrevs, and newheadrevs that are not
-        # heads because an existing head is their descendant.
-        while iterrevs:
-            latest = iterrevs.pop()
-            if latest not in bheadrevs:
-                continue
-            ancestors = set(cl.ancestors([latest],
-                                                     bheadrevs[0]))
-            if ancestors:
-                bheadrevs = [b for b in bheadrevs if b not in ancestors]
-        partial[branch] = [cl.node(rev) for rev in bheadrevs]
-        tiprev = max(bheadrevs)
-        if tiprev > partial.tiprev:
-            partial.tipnode = cl.node(tiprev)
-            partial.tiprev = tiprev
-
-
-    # There may be branches that cease to exist when the last commit in the
-    # branch was stripped.  This code filters them out.  Note that the
-    # branch that ceased to exist may not be in newbranches because
-    # newbranches is the set of candidate heads, which when you strip the
-    # last commit in a branch will be the parent branch.
-    droppednodes = []
-    for branch in partial.keys():
-        nodes = [head for head in partial[branch]
-                 if cl.hasnode(head)]
-        if not nodes:
-            droppednodes.extend(nodes)
-            del partial[branch]
-    try:
-        node = cl.node(partial.tiprev)
-    except IndexError:
-        node = None
-    if ((partial.tipnode != node)
-        or (partial.tipnode in droppednodes)):
-        # cache key are not valid anymore
-        partial.tipnode = nullid
-        partial.tiprev = nullrev
-        for heads in partial.values():
-            tiprev = max(cl.rev(node) for node in heads)
-            if tiprev > partial.tiprev:
-                partial.tipnode = cl.node(tiprev)
-                partial.tiprev = tiprev
 
 
 def updatecache(repo):
     repo = repo.unfiltered()  # Until we get a smarter cache management
     cl = repo.changelog
@@ -140,19 +59,19 @@ def updatecache(repo):
     # if partial.tiprev == catip: cache is already up to date
     # if partial.tiprev >  catip: we have uncachable element in `partial` can't
     #                             write on disk
     if partial.tiprev < catip:
         ctxgen = (repo[r] for r in cl.revs(partial.tiprev + 1, catip))
-        update(repo, partial, ctxgen)
+        partial.update(repo, ctxgen)
         partial.write(repo)
     # If cacheable tip were lower than actual tip, we need to update the
     # cache up to tip. This update (from cacheable to actual tip) is not
     # written to disk since it's not cacheable.
     tiprev = len(repo) - 1
     if partial.tiprev < tiprev:
         ctxgen = (repo[r] for r in cl.revs(partial.tiprev + 1, tiprev))
-        update(repo, partial, ctxgen)
+        partial.update(repo, ctxgen)
     repo._branchcache = partial
 
 class branchcache(dict):
     """A dict like object that hold branches heads cache"""
 
@@ -169,5 +88,86 @@ class branchcache(dict):
                 for node in nodes:
                     f.write("%s %s\n" % (hex(node), encoding.fromlocal(label)))
             f.close()
         except (IOError, OSError):
             pass
+
+    def update(self, repo, ctxgen):
+        """Given a branchhead cache, self, that may have extra nodes or be
+        missing heads, and a generator of nodes that are at least a superset of
+        heads missing, this function updates self to be correct.
+        """
+        cl = repo.changelog
+        # collect new branch entries
+        newbranches = {}
+        for c in ctxgen:
+            newbranches.setdefault(c.branch(), []).append(c.node())
+        # if older branchheads are reachable from new ones, they aren't
+        # really branchheads. Note checking parents is insufficient:
+        # 1 (branch a) -> 2 (branch b) -> 3 (branch a)
+        for branch, newnodes in newbranches.iteritems():
+            bheads = self.setdefault(branch, [])
+            # Remove candidate heads that no longer are in the repo (e.g., as
+            # the result of a strip that just happened).  Avoid using 'node in
+            # self' here because that dives down into branchcache code somewhat
+            # recursively.
+            bheadrevs = [cl.rev(node) for node in bheads
+                         if cl.hasnode(node)]
+            newheadrevs = [cl.rev(node) for node in newnodes
+                           if cl.hasnode(node)]
+            ctxisnew = bheadrevs and min(newheadrevs) > max(bheadrevs)
+            # Remove duplicates - nodes that are in newheadrevs and are already
+            # in bheadrevs.  This can happen if you strip a node whose parent
+            # was already a head (because they're on different branches).
+            bheadrevs = sorted(set(bheadrevs).union(newheadrevs))
+
+            # Starting from tip means fewer passes over reachable.  If we know
+            # the new candidates are not ancestors of existing heads, we don't
+            # have to examine ancestors of existing heads
+            if ctxisnew:
+                iterrevs = sorted(newheadrevs)
+            else:
+                iterrevs = list(bheadrevs)
+
+            # This loop prunes out two kinds of heads - heads that are
+            # superseded by a head in newheadrevs, and newheadrevs that are not
+            # heads because an existing head is their descendant.
+            while iterrevs:
+                latest = iterrevs.pop()
+                if latest not in bheadrevs:
+                    continue
+                ancestors = set(cl.ancestors([latest],
+                                                         bheadrevs[0]))
+                if ancestors:
+                    bheadrevs = [b for b in bheadrevs if b not in ancestors]
+            self[branch] = [cl.node(rev) for rev in bheadrevs]
+            tiprev = max(bheadrevs)
+            if tiprev > self.tiprev:
+                self.tipnode = cl.node(tiprev)
+                self.tiprev = tiprev
+
+        # There may be branches that cease to exist when the last commit in the
+        # branch was stripped.  This code filters them out.  Note that the
+        # branch that ceased to exist may not be in newbranches because
+        # newbranches is the set of candidate heads, which when you strip the
+        # last commit in a branch will be the parent branch.
+        droppednodes = []
+        for branch in self.keys():
+            nodes = [head for head in self[branch]
+                     if cl.hasnode(head)]
+            if not nodes:
+                droppednodes.extend(nodes)
+                del self[branch]
+        try:
+            node = cl.node(self.tiprev)
+        except IndexError:
+            node = None
+        if ((self.tipnode != node)
+            or (self.tipnode in droppednodes)):
+            # cache key are not valid anymore
+            self.tipnode = nullid
+            self.tiprev = nullrev
+            for heads in self.values():
+                tiprev = max(cl.rev(node) for node in heads)
+                if tiprev > self.tiprev:
+                    self.tipnode = cl.node(tiprev)
+                    self.tiprev = tiprev
diff --git a/mercurial/discovery.py b/mercurial/discovery.py
--- a/mercurial/discovery.py
+++ b/mercurial/discovery.py
@@ -194,11 +194,11 @@ def _headssummary(repo, remote, outgoing
     # D. Update newmap with outgoing changes.
     # This will possibly add new heads and remove existing ones.
     newmap = branchmap.branchcache((branch, heads[1])
                                  for branch, heads in headssum.iteritems()
                                  if heads[0] is not None)
-    branchmap.update(repo, newmap, missingctx)
+    newmap.update(repo, missingctx)
     for branch, newheads in newmap.iteritems():
         headssum[branch][1][:] = newheads
     return headssum
 
 def _oldheadssummary(repo, remoteheads, outgoing, inc=False):
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -664,11 +664,11 @@ class localrepository(object):
     def branchmap(self):
         '''returns a dictionary {branch: [branchheads]}'''
         if self.changelog.filteredrevs:
             # some changeset are excluded we can't use the cache
             bmap = branchmap.branchcache()
-            branchmap.update(self, bmap, (self[r] for r in self))
+            bmap.update(self, (self[r] for r in self))
             return bmap
         else:
             branchmap.updatecache(self)
             return self._branchcache
 
@@ -1435,11 +1435,11 @@ class localrepository(object):
         # will be caught the next time it is read.
         if newheadnodes:
             ctxgen = (self[node] for node in newheadnodes
                       if self.changelog.hasnode(node))
             cache = self._branchcache
-            branchmap.update(self, cache, ctxgen)
+            cache.update(self, ctxgen)
             cache.write(self)
 
         # Ensure the persistent tag cache is updated.  Doing it now
         # means that the tag cache only has to worry about destroyed
         # heads immediately after a strip/rollback.  That in turn


More information about the Mercurial-devel mailing list