# HG changeset patch # User Pierre-Yves David # Date 1710043800 -3600 # Node ID 82c1a388e86a21601645e920ce98aef1ecd6c1c7 # Parent 2e8a88e5809fe4f8cabc6a1f616b342a136b74e6 branchcache: explicitly track inheritence "state" We move from a binary "dirty" flag to a three value "state": "clean", "inherited", "dirty". The "inherited" means that the branch cache is not only "clean", but it is a duplicate of its parent filter. If a branch cache is "inherited", we can non only skip writing its value on disk, but it is a good idea to delete any stale value on disk, as those will just waste time (and possibly induce bug) in the future. We only do this in the update related to transaction or explicit cache update (e.g `hg debugupdatecache`). Deleting the file when we simply detected a stall cache during a read only operation seems more dangerous. We rename `copy` to `inherit_for` to clarify we associate a stronger semantic to the operation. diff -r 2e8a88e5809f -r 82c1a388e86a contrib/perf.py --- a/contrib/perf.py Sun Mar 10 04:53:17 2024 +0100 +++ b/contrib/perf.py Sun Mar 10 05:10:00 2024 +0100 @@ -4303,8 +4303,16 @@ baserepo = repo.filtered(b'__perf_branchmap_update_base') targetrepo = repo.filtered(b'__perf_branchmap_update_target') + bcache = repo.branchmap() + copy_method = 'copy' + copy_base_kwargs = copy_base_kwargs = {} - if 'repo' in getargspec(repo.branchmap().copy).args: + if hasattr(bcache, 'copy'): + if 'repo' in getargspec(bcache.copy).args: + copy_base_kwargs = {"repo": baserepo} + copy_target_kwargs = {"repo": targetrepo} + else: + copy_method = 'inherit_for' copy_base_kwargs = {"repo": baserepo} copy_target_kwargs = {"repo": targetrepo} @@ -4316,7 +4324,7 @@ if candidatebm.validfor(baserepo): filtered = repoview.filterrevs(repo, candidatefilter) missing = [r for r in allbaserevs if r in filtered] - base = candidatebm.copy(**copy_base_kwargs) + base = getattr(candidatebm, copy_method)(**copy_base_kwargs) base.update(baserepo, missing) break candidatefilter = subsettable.get(candidatefilter) @@ -4326,7 +4334,7 @@ base.update(baserepo, allbaserevs) def setup(): - x[0] = base.copy(**copy_target_kwargs) + x[0] = getattr(base, copy_method)(**copy_target_kwargs) if clearcaches: unfi._revbranchcache = None clearchangelog(repo) diff -r 2e8a88e5809f -r 82c1a388e86a mercurial/branchmap.py --- a/mercurial/branchmap.py Sun Mar 10 04:53:17 2024 +0100 +++ b/mercurial/branchmap.py Sun Mar 10 05:10:00 2024 +0100 @@ -85,8 +85,7 @@ bcache._filtername, repo.filtername, ) - if bcache._dirty: - bcache.write(repo) + bcache.sync_disk(repo) def updatecache(self, repo): """Update the cache for the given filtered view on a repository""" @@ -109,7 +108,7 @@ subsetname = subsettable.get(filtername) if subsetname is not None: subset = repo.filtered(subsetname) - bcache = self[subset].copy(repo) + bcache = self[subset].inherit_for(repo) extrarevs = subset.changelog.filteredrevs - cl.filteredrevs revs.extend(r for r in extrarevs if r <= bcache.tiprev) else: @@ -160,7 +159,7 @@ if cache.validfor(rview): cache._filtername = candidate self._per_filter[candidate] = cache - cache._dirty = True + cache._state = STATE_DIRTY cache.write(rview) return @@ -173,12 +172,11 @@ cache = self._per_filter.get(filtername) if cache is None: continue - if cache._dirty: - if filtername is None: - repo = unfi - else: - repo = unfi.filtered(filtername) - cache.write(repo) + if filtername is None: + repo = unfi + else: + repo = unfi.filtered(filtername) + cache.sync_disk(repo) def _unknownnode(node): @@ -414,6 +412,11 @@ return max_rev +STATE_CLEAN = 1 +STATE_INHERITED = 2 +STATE_DIRTY = 3 + + class branchcache(_BaseBranchCache): """Branchmap info for a local repo or repoview""" @@ -431,6 +434,7 @@ closednodes: Optional[Set[bytes]] = None, hasnode: Optional[Callable[[bytes], bool]] = None, verify_node: bool = False, + inherited: bool = False, ) -> None: """hasnode is a function which can be used to verify whether changelog has a given node or not. If it's not provided, we assume that every node @@ -442,7 +446,9 @@ self.tipnode = tipnode self.tiprev = tiprev self.filteredhash = filteredhash - self._dirty = False + self._state = STATE_CLEAN + if inherited: + self._state = STATE_INHERITED super().__init__(repo=repo, entries=entries, closed_nodes=closednodes) # closednodes is a set of nodes that close their branch. If the branch @@ -555,7 +561,7 @@ filename = b'%s-%s' % (filename, repo.filtername) return filename - def copy(self, repo): + def inherit_for(self, repo): """return a deep copy of the branchcache object""" assert repo.filtername != self._filtername other = type(self)( @@ -569,16 +575,33 @@ filteredhash=self.filteredhash, closednodes=set(self._closednodes), verify_node=self._verify_node, + inherited=True, ) # also copy information about the current verification state other._verifiedbranches = set(self._verifiedbranches) return other + def sync_disk(self, repo): + """synchronise the on disk file with the cache state + + If new value specific to this filter level need to be written, the file + will be updated, if the state of the branchcache is inherited from a + subset, any stalled on disk file will be deleted. + + That method does nothing if there is nothing to do. + """ + if self._state == STATE_DIRTY: + self.write(repo) + elif self._state == STATE_INHERITED: + filename = self._filename(repo) + repo.cachevfs.tryunlink(filename) + def write(self, repo): assert self._filtername == repo.filtername, ( self._filtername, repo.filtername, ) + assert self._state == STATE_DIRTY, self._state tr = repo.currenttransaction() if not getattr(tr, 'finalized', True): # Avoid premature writing. @@ -597,7 +620,7 @@ len(self._entries), nodecount, ) - self._dirty = False + self._state = STATE_CLEAN except (IOError, OSError, error.Abort) as inst: # Abort may be raised by read only opener, so log and continue repo.ui.debug( @@ -707,7 +730,7 @@ self.filteredhash = scmutil.filteredhash( repo, self.tiprev, needobsolete=True ) - self._dirty = True + self._state = STATE_DIRTY self.write(repo) diff -r 2e8a88e5809f -r 82c1a388e86a tests/test-acl.t --- a/tests/test-acl.t Sun Mar 10 04:53:17 2024 +0100 +++ b/tests/test-acl.t Sun Mar 10 05:10:00 2024 +0100 @@ -167,7 +167,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -187,7 +186,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -237,7 +235,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -257,7 +254,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -317,7 +313,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -337,7 +332,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -388,7 +382,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -408,7 +401,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -463,7 +455,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -483,7 +474,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -535,7 +525,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -555,7 +544,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -612,7 +600,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -632,7 +619,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -686,7 +672,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -706,7 +691,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -761,7 +745,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 1 changesets found list of changesets: @@ -783,7 +766,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -849,7 +831,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 1 changesets found list of changesets: @@ -871,7 +852,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -938,7 +918,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -958,7 +937,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -1024,7 +1002,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -1044,7 +1021,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -1108,7 +1084,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -1128,7 +1103,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -1186,7 +1160,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -1206,7 +1179,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -1275,7 +1247,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -1295,7 +1266,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -1365,7 +1335,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -1385,7 +1354,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -1452,7 +1420,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -1472,7 +1439,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -1535,7 +1501,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -1555,7 +1520,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 @@ -1622,7 +1586,6 @@ listing keys for "phases" checking for updated bookmarks listing keys for "bookmarks" - invalid branch cache (served): tip differs listing keys for "bookmarks" 3 changesets found list of changesets: @@ -1642,7 +1605,6 @@ bundle2-input-part: total payload size * (glob) bundle2-input-part: "check:updated-heads" supported bundle2-input-part: total payload size * (glob) - invalid branch cache (served): tip differs bundle2-input-part: "changegroup" (params: 1 mandatory) supported adding changesets add changeset ef1ea85a6374 diff -r 2e8a88e5809f -r 82c1a388e86a tests/test-blackbox.t --- a/tests/test-blackbox.t Sun Mar 10 04:53:17 2024 +0100 +++ b/tests/test-blackbox.t Sun Mar 10 05:10:00 2024 +0100 @@ -188,13 +188,11 @@ $ hg strip tip 0 files updated, 0 files merged, 1 files removed, 0 files unresolved saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob) - $ hg blackbox -l 6 + $ hg blackbox -l 4 1970-01-01 00:00:00.000 bob @73f6ee326b27d820b0472f1a825e3a50f3dc489b (5000)> strip tip 1970-01-01 00:00:00.000 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/73f6ee326b27-7612e004-backup.hg - 1970-01-01 00:00:00.000 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated branch cache (base) in * seconds (glob) - 1970-01-01 00:00:00.000 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote branch cache (base) with 1 labels and 2 nodes 1970-01-01 00:00:00.000 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> strip tip exited 0 after * seconds (glob) - 1970-01-01 00:00:00.000 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6 + 1970-01-01 00:00:00.000 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 4 extension and python hooks - use the eol extension for a pythonhook diff -r 2e8a88e5809f -r 82c1a388e86a tests/test-strip-branch-cache.t --- a/tests/test-strip-branch-cache.t Sun Mar 10 04:53:17 2024 +0100 +++ b/tests/test-strip-branch-cache.t Sun Mar 10 05:10:00 2024 +0100 @@ -43,11 +43,9 @@ $ ls -1 .hg/cache/branch?* .hg/cache/branch2-base - .hg/cache/branch2-served - $ cat .hg/cache/branch?-served - 222ae9789a75703f9836e44de7db179cbfd420ee 2 - a3498d6e39376d2456425dd8c692367bdbf00fa2 o default - 222ae9789a75703f9836e44de7db179cbfd420ee o default + $ cat .hg/cache/branch?-base + 7ab0a3bd758a58b9f79557ce708533e627776cce 0 + 7ab0a3bd758a58b9f79557ce708533e627776cce o default We do a new commit and we get a new valid branchmap for the served version