branchcache: allow to detect "pure topological case" for branchmap
We don't rum this detection every time we run the branchcache, that would be
costly. However we now do it when running `hg debugupdatecache`.
This will help existing repository to benefit from the fastpath when possible.
--- a/mercurial/branchmap.py Thu Mar 07 04:15:23 2024 +0100
+++ b/mercurial/branchmap.py Thu Mar 07 10:57:16 2024 +0100
@@ -69,7 +69,7 @@
)
return bcache
- def update_disk(self, repo):
+ def update_disk(self, repo, detect_pure_topo=False):
"""ensure and up-to-date cache is (or will be) written on disk
The cache for this repository view is updated if needed and written on
@@ -87,6 +87,8 @@
bcache._filtername,
repo.filtername,
)
+ if detect_pure_topo:
+ bcache._detect_pure_topo(repo)
tr = repo.currenttransaction()
if getattr(tr, 'finalized', True):
bcache.sync_disk(repo)
@@ -488,6 +490,9 @@
def _ensure_populated(self, repo):
"""make sure any lazily loaded values are fully populated"""
+ def _detect_pure_topo(self, repo) -> None:
+ pass
+
def validfor(self, repo):
"""check that cache contents are valid for (a subset of) this repo
@@ -1055,6 +1060,19 @@
self._entries[self._pure_topo_branch] = heads
self._needs_populate = False
+ def _detect_pure_topo(self, repo) -> None:
+ if self._pure_topo_branch is not None:
+ # we are pure topological already
+ return
+ to_node = repo.changelog.node
+ topo_heads = [to_node(r) for r in self._get_topo_heads(repo)]
+ if any(n in self._closednodes for n in topo_heads):
+ return
+ for branch, heads in self._entries.items():
+ if heads == topo_heads:
+ self._pure_topo_branch = branch
+ break
+
class remotebranchcache(_BaseBranchCache):
"""Branchmap info for a remote connection, should not write locally"""
--- a/mercurial/interfaces/repository.py Thu Mar 07 04:15:23 2024 +0100
+++ b/mercurial/interfaces/repository.py Thu Mar 07 10:57:16 2024 +0100
@@ -54,6 +54,8 @@
CACHE_BRANCHMAP_SERVED = b"branchmap-served"
# Warm internal changelog cache (eg: persistent nodemap)
CACHE_CHANGELOG_CACHE = b"changelog-cache"
+# check of a branchmap can use the "pure topo" mode
+CACHE_BRANCHMAP_DETECT_PURE_TOPO = b"branchmap-detect-pure-topo"
# Warm full manifest cache
CACHE_FULL_MANIFEST = b"full-manifest"
# Warm file-node-tags cache
@@ -78,6 +80,7 @@
CACHES_ALL = {
CACHE_BRANCHMAP_SERVED,
CACHE_BRANCHMAP_ALL,
+ CACHE_BRANCHMAP_DETECT_PURE_TOPO,
CACHE_CHANGELOG_CACHE,
CACHE_FILE_NODE_TAGS,
CACHE_FULL_MANIFEST,
--- a/mercurial/localrepo.py Thu Mar 07 04:15:23 2024 +0100
+++ b/mercurial/localrepo.py Thu Mar 07 10:57:16 2024 +0100
@@ -2924,8 +2924,13 @@
if repository.CACHE_BRANCHMAP_SERVED in caches:
if tr is None or tr.changes[b'origrepolen'] < len(self):
self.ui.debug(b'updating the branch cache\n')
- self._branchcaches.update_disk(self.filtered(b'served'))
- self._branchcaches.update_disk(self.filtered(b'served.hidden'))
+ dpt = repository.CACHE_BRANCHMAP_DETECT_PURE_TOPO in caches
+ served = self.filtered(b'served')
+ self._branchcaches.update_disk(served, detect_pure_topo=dpt)
+ served_hidden = self.filtered(b'served.hidden')
+ self._branchcaches.update_disk(
+ served_hidden, detect_pure_topo=dpt
+ )
if repository.CACHE_CHANGELOG_CACHE in caches:
self.changelog.update_caches(transaction=tr)
@@ -2968,9 +2973,11 @@
# even if they haven't explicitly been requested yet (if they've
# never been used by hg, they won't ever have been written, even if
# they're a subset of another kind of cache that *has* been used).
+ dpt = repository.CACHE_BRANCHMAP_DETECT_PURE_TOPO in caches
+
for filt in repoview.filtertable.keys():
filtered = self.filtered(filt)
- self._branchcaches.update_disk(filtered)
+ self._branchcaches.update_disk(filtered, detect_pure_topo=dpt)
# flush all possibly delayed write.
self._branchcaches.write_dirty(self)