D6711: branchheads: store wdir-dependent caches in wcache (issue6181)

spectral (Kyle Lippincott) phabricator at mercurial-scm.org
Fri Aug 2 21:27:10 EDT 2019

spectral created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

  Previously, all branch2-* caches were stored in .hg/cache, which is shared
  across repos when using `hg share`. This can cause cache thrashing when the
  repos are accessed concurrently, since some of the caches depend on wdir state
  (which is NOT shared across the repos).
  There's already a cache directory for caches that depend on wdir state, wcache,
  so let's just put the caches there.
  This change does not clean up any existing caches in .hg/cache that are now
  moved to the new location, and it does not re-use the caches from that location
  when constructing them in the wcache directory. Upgrades to versions of
  Mercurial that have this commit will need to regenerate their branchheads once, and
  this may be an expensive operation.
  The format of these cache files is not changing - forwards/backwards
  compatibility remains; if a newer repo (with these in wcache) is accessed by an
  older hg, the older hg will either see the files that remain in .hg/cache, and
  update them there, or will not see the files at all and will fall back to a
  slower path (and then likely cache them in .hg/cache). If it's then accessed by
  a newer hg, the work done by the older hg is ignored, and the wcache copies are
  brought up to date.

  rHG Mercurial




diff --git a/tests/test-branchmap-cache.t b/tests/test-branchmap-cache.t
new file mode 100644
--- /dev/null
+++ b/tests/test-branchmap-cache.t
@@ -0,0 +1,38 @@
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > share=
+  > [experimental]
+  > evolution=createmarkers
+  > EOF
+  $ hg init -q orig
+  $ cd orig
+  $ echo hi > foo
+  $ hg ci -qAm initial_rev0
+  $ echo "hi again" >> foo
+  $ hg ci -qAm "hi again rev1"
+  $ hg commit -q --amend -m "obsoleted 1, this is rev2"
+  $ cd ..
+  $ hg share -q orig other
+  $ cd other
+  $ hg co -qr 1 --hidden
+  updated to hidden changeset a3571a6d8234
+  (hidden revision 'a3571a6d8234' was rewritten as: 0444ce380f11)
+  $ cd ..
+Forcefully update the caches in each repo once; we're not using --debug since we
+know that these are going to update some/all of the caches, we don't need to
+know which.
+  $ hg -R orig debugupdatecache
+  $ hg -R other debugupdatecache
+The branchheads caches should not change just because we're accessing from a
+different repo each time. If they were stale, we'd get another line in the
+output per filtername that's stale.
+  $ hg -R orig debugupdatecache --debug
+  updating the branch cache
+  $ hg -R other debugupdatecache --debug
+  updating the branch cache
+  $ hg -R orig debugupdatecache --debug
+  updating the branch cache
+  $ hg -R other debugupdatecache --debug
+  updating the branch cache
diff --git a/mercurial/utils/repoviewutil.py b/mercurial/utils/repoviewutil.py
--- a/mercurial/utils/repoviewutil.py
+++ b/mercurial/utils/repoviewutil.py
@@ -20,3 +20,8 @@
                'served.hidden': 'served',
                'served': 'immutable',
                'immutable': 'base'}
+# List of views that are potentially dependent upon wdir state (such as the
+# current parents of the working directory) and need to be kept in wcache
+# instead of cache.
+wdirdependent = frozenset(['served', 'visible', 'visible-hidden'])
diff --git a/mercurial/branchmap.py b/mercurial/branchmap.py
--- a/mercurial/branchmap.py
+++ b/mercurial/branchmap.py
@@ -221,7 +221,7 @@
     def fromfile(cls, repo):
         f = None
-            f = repo.cachevfs(cls._filename(repo))
+            f = cls._opencachefile(repo)
             lineiter = iter(f)
             cachekey = next(lineiter).rstrip('\n').split(" ", 2)
             last, lrev = cachekey[:2]
@@ -271,12 +271,15 @@
-    def _filename(repo):
+    def _opencachefile(repo, *args, **kwargs):
         """name of a branchcache file for a given repo or repoview"""
         filename = "branch2"
+        vfs = repo.cachevfs
         if repo.filtername:
             filename = '%s-%s' % (filename, repo.filtername)
-        return filename
+            if repo.filtername in repoviewutil.wdirdependent:
+                vfs = repo.wcachevfs
+        return vfs(filename, *args, **kwargs)
     def validfor(self, repo):
         """Is the cache content valid regarding a repo
@@ -335,7 +338,7 @@
     def write(self, repo):
-            f = repo.cachevfs(self._filename(repo), "w", atomictemp=True)
+            f = self._opencachefile(repo, "w", atomictemp=True)
             cachekey = [hex(self.tipnode), '%d' % self.tiprev]
             if self.filteredhash is not None:

To: spectral, #hg-reviewers
Cc: mercurial-devel

More information about the Mercurial-devel mailing list