[PATCH 04 of 10 V2] branchmap: takes filtered revision in account for cache calculation

Pierre-Yves David pierre-yves.david at ens-lyon.org
Thu Dec 27 18:56:19 CST 2012


# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at ens-lyon.org>
# Date 1356655623 -3600
# Node ID 13d786f9f076697469cbfe87becbac340eff17e0
# Parent  43650a9b9e09a53169ddd7e1535b816e470b3e5b
branchmap: takes filtered revision in account for cache calculation

Tracking tipnode and tiprev is not enough to ensure validaty of the cache as
they do not help distinguish a cache that ignored various revisions below
tiprev.

To detect such difference, we build a hash of all ignored revisions. This hash
is then used when checking the validity of a cache for a repo.

diff --git a/mercurial/branchmap.py b/mercurial/branchmap.py
--- a/mercurial/branchmap.py
+++ b/mercurial/branchmap.py
@@ -5,10 +5,11 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
 from node import bin, hex, nullid, nullrev
 import encoding
+import util
 
 def read(repo):
     try:
         f = repo.opener("cache/branchheads")
         lines = f.read().split('\n')
@@ -67,22 +68,45 @@ def updatecache(repo):
     repo._branchcache = partial
 
 class branchcache(dict):
     """A dict like object that hold branches heads cache"""
 
-    def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev):
+    def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
+                 filteredhash=None):
         super(branchcache, self).__init__(entries)
         self.tipnode = tipnode
         self.tiprev = tiprev
+        self.filteredhash = filteredhash
+
+    def _hashfiltered(self, repo):
+        """build hash of revision filtered in the current cache
+
+        Tracking tipnode and tiprev is not enough to ensure validaty of the
+        cache as they do not help to distinct cache that ignored various
+        revision bellow tiprev.
+
+        To detect such difference, we build a cache of all revision ignored."""
+        cl = repo.changelog
+        if not cl.filteredrevs:
+            return None
+        key = None
+        revs = sorted(r for r in cl.filteredrevs if r <= self.tiprev)
+        if revs:
+            s = util.sha1()
+            for rev in revs:
+                s.update('%s;' % rev)
+            key = s.digest()
+        return key
 
     def validfor(self, repo):
         """Is the cache content valide regarding a repo
 
         - False when cached tipnode are unknown or if we detect a strip.
         - True when cache is up to date or a subset of current repo."""
         try:
-            return self.tipnode == repo.changelog.node(self.tiprev)
+            return ((self.tipnode == repo.changelog.node(self.tiprev))
+                    and (self.filteredhash == self._hashfiltered(repo)))
         except IndexError:
             return False
 
 
     def write(self, repo):
@@ -170,5 +194,6 @@ class branchcache(dict):
             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
+        self.filteredhash = self._hashfiltered(repo)


More information about the Mercurial-devel mailing list