comparison mercurial/branchmap.py @ 51447:3aba79ce52a9

branchcache: pass the target repository when copying Branchmap are usually copied to be used on a different repoview using a different filter level. Passing the repository around means the repository in `branchcache._repo` will drift from the actual branchmap filter. This is currently "fine" because the repo is only used to retrieve the `nullid` value. However, this is a fairly big trap for any extension or future code using the `_repo` attribute. The replace logic is now using a copy to ensure the right repository view is used to initialized the cached value. We add a couple of assert for make sure this inconsistency does not sneak back.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Mon, 19 Feb 2024 11:43:19 +0100
parents 7f7086a42b2b
children fd30c4301929
comparison
equal deleted inserted replaced
51446:7f7086a42b2b 51447:3aba79ce52a9
58 self._per_filter = {} 58 self._per_filter = {}
59 59
60 def __getitem__(self, repo): 60 def __getitem__(self, repo):
61 self.updatecache(repo) 61 self.updatecache(repo)
62 bcache = self._per_filter[repo.filtername] 62 bcache = self._per_filter[repo.filtername]
63 assert bcache._repo.filtername == repo.filtername, (
64 bcache._repo.filtername,
65 repo.filtername,
66 )
63 return bcache 67 return bcache
64 68
65 def update_disk(self, repo): 69 def update_disk(self, repo):
66 """ensure and up-to-date cache is (or will be) written on disk 70 """ensure and up-to-date cache is (or will be) written on disk
67 71
74 This method exist independently of __getitem__ as it is sometime useful 78 This method exist independently of __getitem__ as it is sometime useful
75 to signal that we have no intend to use the data in memory yet. 79 to signal that we have no intend to use the data in memory yet.
76 """ 80 """
77 self.updatecache(repo) 81 self.updatecache(repo)
78 bcache = self._per_filter[repo.filtername] 82 bcache = self._per_filter[repo.filtername]
83 assert bcache._repo.filtername == repo.filtername, (
84 bcache._repo.filtername,
85 repo.filtername,
86 )
79 bcache.write(repo) 87 bcache.write(repo)
80 88
81 def updatecache(self, repo): 89 def updatecache(self, repo):
82 """Update the cache for the given filtered view on a repository""" 90 """Update the cache for the given filtered view on a repository"""
83 # This can trigger updates for the caches for subsets of the filtered 91 # This can trigger updates for the caches for subsets of the filtered
97 # the cache for a subset, then extend that to add info on missing 105 # the cache for a subset, then extend that to add info on missing
98 # revisions. 106 # revisions.
99 subsetname = subsettable.get(filtername) 107 subsetname = subsettable.get(filtername)
100 if subsetname is not None: 108 if subsetname is not None:
101 subset = repo.filtered(subsetname) 109 subset = repo.filtered(subsetname)
102 bcache = self[subset].copy() 110 bcache = self[subset].copy(repo)
103 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs 111 extrarevs = subset.changelog.filteredrevs - cl.filteredrevs
104 revs.extend(r for r in extrarevs if r <= bcache.tiprev) 112 revs.extend(r for r in extrarevs if r <= bcache.tiprev)
105 else: 113 else:
106 # nothing to fall back on, start empty. 114 # nothing to fall back on, start empty.
107 bcache = branchcache(repo) 115 bcache = branchcache(repo)
146 # Try to stick it as low as possible 154 # Try to stick it as low as possible
147 # filter above served are unlikely to be fetch from a clone 155 # filter above served are unlikely to be fetch from a clone
148 for candidate in (b'base', b'immutable', b'served'): 156 for candidate in (b'base', b'immutable', b'served'):
149 rview = repo.filtered(candidate) 157 rview = repo.filtered(candidate)
150 if cache.validfor(rview): 158 if cache.validfor(rview):
151 self._per_filter[candidate] = cache 159 cache = self._per_filter[candidate] = cache.copy(rview)
152 cache.write(rview) 160 cache.write(rview)
153 return 161 return
154 162
155 def clear(self): 163 def clear(self):
156 self._per_filter.clear() 164 self._per_filter.clear()
413 def iterheads(self): 421 def iterheads(self):
414 """returns all the heads""" 422 """returns all the heads"""
415 self._verifyall() 423 self._verifyall()
416 return self._entries.values() 424 return self._entries.values()
417 425
418 def copy(self): 426 def copy(self, repo):
419 """return an deep copy of the branchcache object""" 427 """return an deep copy of the branchcache object"""
420 return type(self)( 428 return type(self)(
421 self._repo, 429 repo,
422 self._entries, 430 self._entries,
423 self.tipnode, 431 self.tipnode,
424 self.tiprev, 432 self.tiprev,
425 self.filteredhash, 433 self.filteredhash,
426 self._closednodes, 434 self._closednodes,
427 ) 435 )
428 436
429 def write(self, repo): 437 def write(self, repo):
438 assert self._repo.filtername == repo.filtername, (
439 self._repo.filtername,
440 repo.filtername,
441 )
430 tr = repo.currenttransaction() 442 tr = repo.currenttransaction()
431 if not getattr(tr, 'finalized', True): 443 if not getattr(tr, 'finalized', True):
432 # Avoid premature writing. 444 # Avoid premature writing.
433 # 445 #
434 # (The cache warming setup by localrepo will update the file later.) 446 # (The cache warming setup by localrepo will update the file later.)
469 def update(self, repo, revgen): 481 def update(self, repo, revgen):
470 """Given a branchhead cache, self, that may have extra nodes or be 482 """Given a branchhead cache, self, that may have extra nodes or be
471 missing heads, and a generator of nodes that are strictly a superset of 483 missing heads, and a generator of nodes that are strictly a superset of
472 heads missing, this function updates self to be correct. 484 heads missing, this function updates self to be correct.
473 """ 485 """
486 assert self._repo.filtername == repo.filtername, (
487 self._repo.filtername,
488 repo.filtername,
489 )
474 starttime = util.timer() 490 starttime = util.timer()
475 cl = repo.changelog 491 cl = repo.changelog
476 # collect new branch entries 492 # collect new branch entries
477 newbranches = {} 493 newbranches = {}
478 getbranchinfo = repo.revbranchcache().branchinfo 494 getbranchinfo = repo.revbranchcache().branchinfo