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 |
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", |
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, |