Patchwork [9,of,9] branchmap: enable caching for filtered version too

login
register
mail settings
Submitter Pierre-Yves David
Date Dec. 26, 2012, 8:33 p.m.
Message ID <a1f6f6c2444c9b4186bc.1356553985@yamac.local>
Download mbox | patch
Permalink /patch/305/
State Superseded, archived
Commit b9026ba002f6a0cd7000d22a8713779d8c010687
Headers show

Comments

Pierre-Yves David - Dec. 26, 2012, 8:33 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at ens-lyon.org>
# Date 1356315675 -3600
# Node ID a1f6f6c2444c9b4186bc7d156f6ef01986ad1507
# Parent  4d19904ae62475625f181b4fcd2a1244f9d185f9
branchmap: enable caching for filtered version too

The `_branchcache` attribute is turned into a dictionary. Key are filter name and
value is a `branchcache` object. Unfiltered version is cached as `None` filter.

The attribute is renamed to `_branchcaches` to avoid confusion with the previous
one. Both old and new contents are dictionary even if their contents are
different. I prefer possible extension code to crash right away instead of just
messing the wrong dictionary.

As all different caches work isolated to each other, this code keeps the
previous behavior of using the unfiltered cache  we nothing is filtered.  This
is a cheap way to have cache collaborate and nullify potential impact in the
default case.

Patch

diff --git a/mercurial/branchmap.py b/mercurial/branchmap.py
--- a/mercurial/branchmap.py
+++ b/mercurial/branchmap.py
@@ -55,13 +55,13 @@  def read(repo):
     return partial
 
 
 
 def updatecache(repo):
-    repo = repo.unfiltered()  # Until we get a smarter cache management
     cl = repo.changelog
-    partial = repo._branchcache
+    filtername = repo.filtername
+    partial = repo._branchcaches.get(filtername)
 
     if partial is None or not partial.validfor(repo):
         partial = read(repo)
 
     catip = repo._cacheabletip()
@@ -77,11 +77,11 @@  def updatecache(repo):
     # written to disk since it's not cacheable.
     tiprev = cl.rev(cl.tip())
     if partial.tiprev < tiprev:
         ctxgen = (repo[r] for r in cl.revs(partial.tiprev + 1, tiprev))
         partial.update(repo, ctxgen)
-    repo._branchcache = partial
+    repo._branchcaches[repo.filtername] = partial
 
 class branchcache(dict):
     """A dict like object that hold branches heads cache"""
 
     def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev,
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -227,11 +227,11 @@  class localrepository(object):
         self._applyrequirements(requirements)
         if create:
             self._writerequirements()
 
 
-        self._branchcache = None
+        self._branchcaches = {}
         self.filterpats = {}
         self._datafilters = {}
         self._transref = self._lockref = self._wlockref = None
 
         # A cache for various files under .hg/ that tracks file changes,
@@ -662,18 +662,14 @@  class localrepository(object):
         cl = self.changelog
         return cl.rev(cl.tip())
 
     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()
-            bmap.update(self, (self[r] for r in self))
-            return bmap
-        else:
-            branchmap.updatecache(self)
-            return self._branchcache
+        if self.filtername and not self.changelog.filteredrevs:
+            return self.unfiltered().branchmap()
+        branchmap.updatecache(self)
+        return self._branchcaches[self.filtername]
 
 
     def _branchtip(self, heads):
         '''return the tipmost branch head in heads'''
         tip = heads[-1]
@@ -976,11 +972,11 @@  class localrepository(object):
 
         if '_tagscache' in vars(self):
             # can't use delattr on proxy
             del self.__dict__['_tagscache']
 
-        self.unfiltered()._branchcache = None # in UTF-8
+        self.unfiltered()._branchcaches.clear()
         self.invalidatevolatilesets()
 
     def invalidatevolatilesets(self):
         self.filteredrevcache.clear()
         obsolete.clearobscaches(self)
@@ -1435,11 +1431,11 @@  class localrepository(object):
         # it, Otherwise, since nodes were destroyed, the cache is stale and this
         # 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
+            cache = self._branchcaches[None]
             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
@@ -2494,12 +2490,12 @@  class localrepository(object):
                     rtiprev = max((int(self.changelog.rev(node))
                             for node in rbheads))
                     cache = branchmap.branchcache(rbranchmap,
                                                   self[rtiprev].node(),
                                                   rtiprev)
-                    self._branchcache = cache
-                    cache.write(self)
+                    self._branchcaches[None] = cache
+                    cache.write(self.unfiltered())
             self.invalidate()
             return len(self.heads()) + 1
         finally:
             lock.release()
 
diff --git a/mercurial/statichttprepo.py b/mercurial/statichttprepo.py
--- a/mercurial/statichttprepo.py
+++ b/mercurial/statichttprepo.py
@@ -132,11 +132,11 @@  class statichttprepository(localrepo.loc
 
         self.manifest = manifest.manifest(self.sopener)
         self.changelog = changelog.changelog(self.sopener)
         self._tags = None
         self.nodetagscache = None
-        self._branchcache = None
+        self._branchcaches = {}
         self.encodepats = None
         self.decodepats = None
 
     def _restrictcapabilities(self, caps):
         return caps.difference(["pushkey"])
diff --git a/tests/test-phases.t b/tests/test-phases.t
--- a/tests/test-phases.t
+++ b/tests/test-phases.t
@@ -171,10 +171,25 @@  visible shared between the initial repo 
   adding file changes
   added 1 changesets with 1 changes to 1 files (+1 heads)
 
 :note: The "(+1 heads)" is wrong as we do not had any visible head
 
+check that branch cache with "unserved" filter are properly computed and stored
+
+  $ ls ../push-dest/.hg/cache/branchheads*
+  ../push-dest/.hg/cache/branchheads
+  ../push-dest/.hg/cache/branchheads-unserved
+  $ cat ../push-dest/.hg/cache/branchheads
+  6d6770faffce199f1fddd1cf87f6f026138cf061 6
+  b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e default
+  2713879da13d6eea1ff22b442a5a87cb31a7ce6a default
+  6d6770faffce199f1fddd1cf87f6f026138cf061 default
+  $ cat ../push-dest/.hg/cache/branchheads-unserved
+  cf9fe039dfd67e829edf6522a45de057b5c86519 4
+  b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e default
+  cf9fe039dfd67e829edf6522a45de057b5c86519 default
+
 
 Restore condition prior extra insertion.
   $ hg -q --config extensions.mq= strip .
   $ hg up -q 7
   $ cd ..