comparison mercurial/branchmap.py @ 51516:ec640dc9cebd

branchcache: use an explicit class for the v2 version This prepare the introduction of an experimental v3 format version. In the process, we move the description of the format in that new class.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Tue, 27 Feb 2024 14:04:29 +0100
parents 0239ebdd0740
children fe8347b984f3
comparison
equal deleted inserted replaced
51515:c7e81615b5c4 51516:ec640dc9cebd
98 cl = repo.changelog 98 cl = repo.changelog
99 filtername = repo.filtername 99 filtername = repo.filtername
100 bcache = self._per_filter.get(filtername) 100 bcache = self._per_filter.get(filtername)
101 if bcache is None or not bcache.validfor(repo): 101 if bcache is None or not bcache.validfor(repo):
102 # cache object missing or cache object stale? Read from disk 102 # cache object missing or cache object stale? Read from disk
103 bcache = branchcache.fromfile(repo) 103 bcache = branch_cache_from_file(repo)
104 104
105 revs = [] 105 revs = []
106 if bcache is None: 106 if bcache is None:
107 # no (fresh) cache available anymore, perhaps we can re-use 107 # no (fresh) cache available anymore, perhaps we can re-use
108 # the cache for a subset, then extend that to add info on missing 108 # the cache for a subset, then extend that to add info on missing
114 bcache = self._per_filter[subset.filtername].inherit_for(repo) 114 bcache = self._per_filter[subset.filtername].inherit_for(repo)
115 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs 115 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
116 revs.extend(r for r in extrarevs if r <= bcache.tiprev) 116 revs.extend(r for r in extrarevs if r <= bcache.tiprev)
117 else: 117 else:
118 # nothing to fall back on, start empty. 118 # nothing to fall back on, start empty.
119 bcache = branchcache(repo) 119 bcache = new_branch_cache(repo)
120 120
121 revs.extend(cl.revs(start=bcache.tiprev + 1)) 121 revs.extend(cl.revs(start=bcache.tiprev + 1))
122 if revs: 122 if revs:
123 bcache.update(repo, revs) 123 bcache.update(repo, revs)
124 124
145 if c: 145 if c:
146 closed.add(h) 146 closed.add(h)
147 147
148 if rbheads: 148 if rbheads:
149 rtiprev = max((int(clrev(node)) for node in rbheads)) 149 rtiprev = max((int(clrev(node)) for node in rbheads))
150 cache = branchcache( 150 cache = new_branch_cache(
151 repo, 151 repo,
152 remotebranchmap, 152 remotebranchmap,
153 repo[rtiprev].node(), 153 repo[rtiprev].node(),
154 rtiprev, 154 rtiprev,
155 closednodes=closed, 155 closednodes=closed,
197 class _BaseBranchCache: 197 class _BaseBranchCache:
198 """A dict like object that hold branches heads cache. 198 """A dict like object that hold branches heads cache.
199 199
200 This cache is used to avoid costly computations to determine all the 200 This cache is used to avoid costly computations to determine all the
201 branch heads of a repo. 201 branch heads of a repo.
202
203 The cache is serialized on disk in the following format:
204
205 <tip hex node> <tip rev number> [optional filtered repo hex hash]
206 <branch head hex node> <open/closed state> <branch name>
207 <branch head hex node> <open/closed state> <branch name>
208 ...
209
210 The first line is used to check if the cache is still valid. If the
211 branch cache is for a filtered repo view, an optional third hash is
212 included that hashes the hashes of all filtered and obsolete revisions.
213
214 The open/closed state is represented by a single letter 'o' or 'c'.
215 This field can be used to avoid changelog reads when determining if a
216 branch head closes a branch or not.
217 """ 202 """
218 203
219 def __init__( 204 def __init__(
220 self, 205 self,
221 repo: "localrepo.localrepository", 206 repo: "localrepo.localrepository",
418 STATE_CLEAN = 1 403 STATE_CLEAN = 1
419 STATE_INHERITED = 2 404 STATE_INHERITED = 2
420 STATE_DIRTY = 3 405 STATE_DIRTY = 3
421 406
422 407
423 class branchcache(_BaseBranchCache): 408 class _LocalBranchCache(_BaseBranchCache):
424 """Branchmap info for a local repo or repoview""" 409 """base class of branch-map info for a local repo or repoview"""
425 410
426 _base_filename = b"branch2" 411 _base_filename = None
427 412
428 def __init__( 413 def __init__(
429 self, 414 self,
430 repo: "localrepo.localrepository", 415 repo: "localrepo.localrepository",
431 entries: Union[ 416 entries: Union[
558 543
559 @classmethod 544 @classmethod
560 def _filename(cls, repo): 545 def _filename(cls, repo):
561 """name of a branchcache file for a given repo or repoview""" 546 """name of a branchcache file for a given repo or repoview"""
562 filename = cls._base_filename 547 filename = cls._base_filename
548 assert filename is not None
563 if repo.filtername: 549 if repo.filtername:
564 filename = b'%s-%s' % (filename, repo.filtername) 550 filename = b'%s-%s' % (filename, repo.filtername)
565 return filename 551 return filename
566 552
567 def inherit_for(self, repo): 553 def inherit_for(self, repo):
739 # 725 #
740 # (The cache warming setup by localrepo will update the file later.) 726 # (The cache warming setup by localrepo will update the file later.)
741 self.write(repo) 727 self.write(repo)
742 728
743 729
730 def branch_cache_from_file(repo) -> Optional[_LocalBranchCache]:
731 """Build a branch cache from on-disk data if possible"""
732 return BranchCacheV2.fromfile(repo)
733
734
735 def new_branch_cache(repo, *args, **kwargs):
736 """Build a new branch cache from argument"""
737 return BranchCacheV2(repo, *args, **kwargs)
738
739
740 class BranchCacheV2(_LocalBranchCache):
741 """a branch cache using version 2 of the format on disk
742
743 The cache is serialized on disk in the following format:
744
745 <tip hex node> <tip rev number> [optional filtered repo hex hash]
746 <branch head hex node> <open/closed state> <branch name>
747 <branch head hex node> <open/closed state> <branch name>
748 ...
749
750 The first line is used to check if the cache is still valid. If the
751 branch cache is for a filtered repo view, an optional third hash is
752 included that hashes the hashes of all filtered and obsolete revisions.
753
754 The open/closed state is represented by a single letter 'o' or 'c'.
755 This field can be used to avoid changelog reads when determining if a
756 branch head closes a branch or not.
757 """
758
759 _base_filename = b"branch2"
760
761
744 class remotebranchcache(_BaseBranchCache): 762 class remotebranchcache(_BaseBranchCache):
745 """Branchmap info for a remote connection, should not write locally""" 763 """Branchmap info for a remote connection, should not write locally"""
746 764
747 def __init__( 765 def __init__(
748 self, 766 self,