mercurial/branchmap.py
changeset 51536 718f28ea3af4
parent 51535 03247e37ccf7
child 51537 4a8bb136ee77
equal deleted inserted replaced
51535:03247e37ccf7 51536:718f28ea3af4
    60         self._per_filter = {}
    60         self._per_filter = {}
    61 
    61 
    62     def __getitem__(self, repo):
    62     def __getitem__(self, repo):
    63         self.updatecache(repo)
    63         self.updatecache(repo)
    64         bcache = self._per_filter[repo.filtername]
    64         bcache = self._per_filter[repo.filtername]
       
    65         bcache._ensure_populated(repo)
    65         assert bcache._filtername == repo.filtername, (
    66         assert bcache._filtername == repo.filtername, (
    66             bcache._filtername,
    67             bcache._filtername,
    67             repo.filtername,
    68             repo.filtername,
    68         )
    69         )
    69         return bcache
    70         return bcache
   482             self._hasnode = repo.changelog.hasnode
   483             self._hasnode = repo.changelog.hasnode
   483 
   484 
   484     def _compute_key_hashes(self, repo) -> Tuple[bytes]:
   485     def _compute_key_hashes(self, repo) -> Tuple[bytes]:
   485         raise NotImplementedError
   486         raise NotImplementedError
   486 
   487 
       
   488     def _ensure_populated(self, repo):
       
   489         """make sure any lazily loaded values are fully populated"""
       
   490 
   487     def validfor(self, repo):
   491     def validfor(self, repo):
   488         """check that cache contents are valid for (a subset of) this repo
   492         """check that cache contents are valid for (a subset of) this repo
   489 
   493 
   490         - False when the order of changesets changed or if we detect a strip.
   494         - False when the order of changesets changed or if we detect a strip.
   491         - True when cache is up-to-date for the current repo or its subset."""
   495         - True when cache is up-to-date for the current repo or its subset."""
   859     """
   863     """
   860 
   864 
   861     _base_filename = b"branch3"
   865     _base_filename = b"branch3"
   862     _default_key_hashes = (None, None)
   866     _default_key_hashes = (None, None)
   863 
   867 
   864     def _get_topo_heads(self, repo) -> List[int]:
   868     def __init__(self, *args, pure_topo_branch=None, **kwargs):
       
   869         super().__init__(*args, **kwargs)
       
   870         self._pure_topo_branch = pure_topo_branch
       
   871         self._needs_populate = self._pure_topo_branch is not None
       
   872 
       
   873     def inherit_for(self, repo):
       
   874         new = super().inherit_for(repo)
       
   875         new._pure_topo_branch = self._pure_topo_branch
       
   876         new._needs_populate = self._needs_populate
       
   877         return new
       
   878 
       
   879     def _get_topo_heads(self, repo):
   865         """returns the topological head of a repoview content up to self.tiprev"""
   880         """returns the topological head of a repoview content up to self.tiprev"""
   866         cl = repo.changelog
   881         cl = repo.changelog
   867         if self.tiprev == nullrev:
   882         if self.tiprev == nullrev:
   868             return []
   883             return []
   869         elif self.tiprev == cl.tiprev():
   884         elif self.tiprev == cl.tiprev():
   881         if self.key_hashes:
   896         if self.key_hashes:
   882             if self.key_hashes[0] is not None:
   897             if self.key_hashes[0] is not None:
   883                 cache_keys[b"filtered-hash"] = hex(self.key_hashes[0])
   898                 cache_keys[b"filtered-hash"] = hex(self.key_hashes[0])
   884             if self.key_hashes[1] is not None:
   899             if self.key_hashes[1] is not None:
   885                 cache_keys[b"obsolete-hash"] = hex(self.key_hashes[1])
   900                 cache_keys[b"obsolete-hash"] = hex(self.key_hashes[1])
       
   901         if self._pure_topo_branch is not None:
       
   902             cache_keys[b"topo-mode"] = b"pure"
   886         pieces = (b"%s=%s" % i for i in sorted(cache_keys.items()))
   903         pieces = (b"%s=%s" % i for i in sorted(cache_keys.items()))
   887         fp.write(b" ".join(pieces) + b'\n')
   904         fp.write(b" ".join(pieces) + b'\n')
       
   905         if self._pure_topo_branch is not None:
       
   906             label = encoding.fromlocal(self._pure_topo_branch)
       
   907             fp.write(label + b'\n')
   888 
   908 
   889     def _write_heads(self, repo, fp) -> int:
   909     def _write_heads(self, repo, fp) -> int:
   890         """write list of heads to a file
   910         """write list of heads to a file
   891 
   911 
   892         Return the number of heads written."""
   912         Return the number of heads written."""
   893         nodecount = 0
   913         nodecount = 0
   894         topo_heads = set(self._get_topo_heads(repo))
   914         topo_heads = None
       
   915         if self._pure_topo_branch is None:
       
   916             topo_heads = set(self._get_topo_heads(repo))
   895         to_rev = repo.changelog.index.rev
   917         to_rev = repo.changelog.index.rev
   896         for label, nodes in sorted(self._entries.items()):
   918         for label, nodes in sorted(self._entries.items()):
       
   919             if label == self._pure_topo_branch:
       
   920                 # not need to write anything the header took care of that
       
   921                 continue
   897             label = encoding.fromlocal(label)
   922             label = encoding.fromlocal(label)
   898             for node in nodes:
   923             for node in nodes:
   899                 rev = to_rev(node)
   924                 if topo_heads is not None:
   900                 if rev in topo_heads:
   925                     rev = to_rev(node)
   901                     continue
   926                     if rev in topo_heads:
       
   927                         continue
   902                 if node in self._closednodes:
   928                 if node in self._closednodes:
   903                     state = b'c'
   929                     state = b'c'
   904                 else:
   930                 else:
   905                     state = b'o'
   931                     state = b'o'
   906                 nodecount += 1
   932                 nodecount += 1
   914         cache_keys = dict(p.split(b'=', 1) for p in pieces)
   940         cache_keys = dict(p.split(b'=', 1) for p in pieces)
   915 
   941 
   916         args = {}
   942         args = {}
   917         filtered_hash = None
   943         filtered_hash = None
   918         obsolete_hash = None
   944         obsolete_hash = None
       
   945         has_pure_topo_heads = False
   919         for k, v in cache_keys.items():
   946         for k, v in cache_keys.items():
   920             if k == b"tip-rev":
   947             if k == b"tip-rev":
   921                 args["tiprev"] = int(v)
   948                 args["tiprev"] = int(v)
   922             elif k == b"tip-node":
   949             elif k == b"tip-node":
   923                 args["tipnode"] = bin(v)
   950                 args["tipnode"] = bin(v)
   924             elif k == b"filtered-hash":
   951             elif k == b"filtered-hash":
   925                 filtered_hash = bin(v)
   952                 filtered_hash = bin(v)
   926             elif k == b"obsolete-hash":
   953             elif k == b"obsolete-hash":
   927                 obsolete_hash = bin(v)
   954                 obsolete_hash = bin(v)
       
   955             elif k == b"topo-mode":
       
   956                 if v == b"pure":
       
   957                     has_pure_topo_heads = True
       
   958                 else:
       
   959                     msg = b"unknown topo-mode: %r" % v
       
   960                     raise ValueError(msg)
   928             else:
   961             else:
   929                 msg = b"unknown cache key: %r" % k
   962                 msg = b"unknown cache key: %r" % k
   930                 raise ValueError(msg)
   963                 raise ValueError(msg)
   931         args["key_hashes"] = (filtered_hash, obsolete_hash)
   964         args["key_hashes"] = (filtered_hash, obsolete_hash)
       
   965         if has_pure_topo_heads:
       
   966             pure_line = next(lineiter).rstrip(b'\n')
       
   967             args["pure_topo_branch"] = encoding.tolocal(pure_line)
   932         return args
   968         return args
   933 
   969 
   934     def _load_heads(self, repo, lineiter):
   970     def _load_heads(self, repo, lineiter):
   935         """fully loads the branchcache by reading from the file using the line
   971         """fully loads the branchcache by reading from the file using the line
   936         iterator passed"""
   972         iterator passed"""
   937         super()._load_heads(repo, lineiter)
   973         super()._load_heads(repo, lineiter)
       
   974         if self._pure_topo_branch is not None:
       
   975             # no need to read the repository heads, we know their value already.
       
   976             return
   938         cl = repo.changelog
   977         cl = repo.changelog
   939         getbranchinfo = repo.revbranchcache().branchinfo
   978         getbranchinfo = repo.revbranchcache().branchinfo
   940         obsrevs = obsolete.getrevs(repo, b'obsolete')
   979         obsrevs = obsolete.getrevs(repo, b'obsolete')
   941         to_node = cl.node
   980         to_node = cl.node
   942         touched_branch = set()
   981         touched_branch = set()
   957         """return the cache key hashes that match this repoview state"""
   996         """return the cache key hashes that match this repoview state"""
   958         return scmutil.filtered_and_obsolete_hash(
   997         return scmutil.filtered_and_obsolete_hash(
   959             repo,
   998             repo,
   960             self.tiprev,
   999             self.tiprev,
   961         )
  1000         )
       
  1001 
       
  1002     def _process_new(
       
  1003         self,
       
  1004         repo,
       
  1005         newbranches,
       
  1006         new_closed,
       
  1007         obs_ignored,
       
  1008         max_rev,
       
  1009     ) -> None:
       
  1010         if (
       
  1011             # note: the check about `obs_ignored` is too strict as the
       
  1012             # obsolete revision could be non-topological, but lets keep
       
  1013             # things simple for now
       
  1014             #
       
  1015             # The same apply to `new_closed` if the closed changeset are
       
  1016             # not a head, we don't care that it is closed, but lets keep
       
  1017             # things simple here too.
       
  1018             not (obs_ignored or new_closed)
       
  1019             and (
       
  1020                 not newbranches
       
  1021                 or (
       
  1022                     len(newbranches) == 1
       
  1023                     and (
       
  1024                         self.tiprev == nullrev
       
  1025                         or self._pure_topo_branch in newbranches
       
  1026                     )
       
  1027                 )
       
  1028             )
       
  1029         ):
       
  1030             if newbranches:
       
  1031                 assert len(newbranches) == 1
       
  1032                 self._pure_topo_branch = list(newbranches.keys())[0]
       
  1033                 self._needs_populate = True
       
  1034                 self._entries.pop(self._pure_topo_branch, None)
       
  1035             return
       
  1036 
       
  1037         self._ensure_populated(repo)
       
  1038         self._pure_topo_branch = None
       
  1039         super()._process_new(
       
  1040             repo,
       
  1041             newbranches,
       
  1042             new_closed,
       
  1043             obs_ignored,
       
  1044             max_rev,
       
  1045         )
       
  1046 
       
  1047     def _ensure_populated(self, repo):
       
  1048         """make sure any lazily loaded values are fully populated"""
       
  1049         if self._needs_populate:
       
  1050             assert self._pure_topo_branch is not None
       
  1051             cl = repo.changelog
       
  1052             to_node = cl.node
       
  1053             topo_heads = self._get_topo_heads(repo)
       
  1054             heads = [to_node(r) for r in topo_heads]
       
  1055             self._entries[self._pure_topo_branch] = heads
       
  1056             self._needs_populate = False
   962 
  1057 
   963 
  1058 
   964 class remotebranchcache(_BaseBranchCache):
  1059 class remotebranchcache(_BaseBranchCache):
   965     """Branchmap info for a remote connection, should not write locally"""
  1060     """Branchmap info for a remote connection, should not write locally"""
   966 
  1061