Mercurial > hg
comparison mercurial/branchmap.py @ 51529:4141d12de073
branchcache: store filtered hash and obsolete hash independently for V3
This will avoid the bug covered in tests/test-branches-obsolete.t when we stop
storing all heads explicitly in V3.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Wed, 06 Mar 2024 11:39:44 +0100 |
parents | fa9e3976a5a0 |
children | f85f23f1479b |
comparison
equal
deleted
inserted
replaced
51528:88b0e07dd2cd | 51529:4141d12de073 |
---|---|
811 The first line is used to check if the cache is still valid. It is a series | 811 The first line is used to check if the cache is still valid. It is a series |
812 of key value pair. The following key are recognized: | 812 of key value pair. The following key are recognized: |
813 | 813 |
814 - tip-rev: the rev-num of the tip-most revision seen by this cache | 814 - tip-rev: the rev-num of the tip-most revision seen by this cache |
815 - tip-node: the node-id of the tip-most revision sen by this cache | 815 - tip-node: the node-id of the tip-most revision sen by this cache |
816 - filtered-hash: the hash of all filtered and obsolete revisions (before | 816 - filtered-hash: the hash of all filtered revisions (before tip-rev) |
817 ignored by this cache. | |
818 - obsolete-hash: the hash of all non-filtered obsolete revisions (before | |
817 tip-rev) ignored by this cache. | 819 tip-rev) ignored by this cache. |
818 | 820 |
819 The tip-rev is used to know how far behind the value in the file are | 821 The tip-rev is used to know how far behind the value in the file are |
820 compared to the current repository state. | 822 compared to the current repository state. |
821 | 823 |
822 The tip-node and filtered-hash are used to detect if this cache can be used | 824 The tip-node, filtered-hash and obsolete-hash are used to detect if this |
823 for this repository state at all. | 825 cache can be used for this repository state at all. |
824 | 826 |
825 The open/closed state is represented by a single letter 'o' or 'c'. | 827 The open/closed state is represented by a single letter 'o' or 'c'. |
826 This field can be used to avoid changelog reads when determining if a | 828 This field can be used to avoid changelog reads when determining if a |
827 branch head closes a branch or not. | 829 branch head closes a branch or not. |
828 """ | 830 """ |
829 | 831 |
830 _base_filename = b"branch3" | 832 _base_filename = b"branch3" |
833 _default_key_hashes = (None, None) | |
831 | 834 |
832 def _write_header(self, fp) -> None: | 835 def _write_header(self, fp) -> None: |
833 cache_keys = { | 836 cache_keys = { |
834 b"tip-node": hex(self.tipnode), | 837 b"tip-node": hex(self.tipnode), |
835 b"tip-rev": b'%d' % self.tiprev, | 838 b"tip-rev": b'%d' % self.tiprev, |
836 } | 839 } |
837 if self.key_hashes: | 840 if self.key_hashes: |
838 cache_keys[b"filtered-hash"] = hex(self.key_hashes[0]) | 841 if self.key_hashes[0] is not None: |
842 cache_keys[b"filtered-hash"] = hex(self.key_hashes[0]) | |
843 if self.key_hashes[1] is not None: | |
844 cache_keys[b"obsolete-hash"] = hex(self.key_hashes[1]) | |
839 pieces = (b"%s=%s" % i for i in sorted(cache_keys.items())) | 845 pieces = (b"%s=%s" % i for i in sorted(cache_keys.items())) |
840 fp.write(b" ".join(pieces) + b'\n') | 846 fp.write(b" ".join(pieces) + b'\n') |
841 | 847 |
842 @classmethod | 848 @classmethod |
843 def _load_header(cls, repo, lineiter): | 849 def _load_header(cls, repo, lineiter): |
844 header_line = next(lineiter) | 850 header_line = next(lineiter) |
845 pieces = header_line.rstrip(b'\n').split(b" ") | 851 pieces = header_line.rstrip(b'\n').split(b" ") |
846 cache_keys = dict(p.split(b'=', 1) for p in pieces) | 852 cache_keys = dict(p.split(b'=', 1) for p in pieces) |
847 | 853 |
848 args = {} | 854 args = {} |
855 filtered_hash = None | |
856 obsolete_hash = None | |
849 for k, v in cache_keys.items(): | 857 for k, v in cache_keys.items(): |
850 if k == b"tip-rev": | 858 if k == b"tip-rev": |
851 args["tiprev"] = int(v) | 859 args["tiprev"] = int(v) |
852 elif k == b"tip-node": | 860 elif k == b"tip-node": |
853 args["tipnode"] = bin(v) | 861 args["tipnode"] = bin(v) |
854 elif k == b"filtered-hash": | 862 elif k == b"filtered-hash": |
855 args["key_hashes"] = (bin(v),) | 863 filtered_hash = bin(v) |
864 elif k == b"obsolete-hash": | |
865 obsolete_hash = bin(v) | |
856 else: | 866 else: |
857 msg = b"unknown cache key: %r" % k | 867 msg = b"unknown cache key: %r" % k |
858 raise ValueError(msg) | 868 raise ValueError(msg) |
869 args["key_hashes"] = (filtered_hash, obsolete_hash) | |
859 return args | 870 return args |
860 | 871 |
861 def _compute_key_hashes(self, repo) -> Tuple[bytes]: | 872 def _compute_key_hashes(self, repo) -> Tuple[bytes]: |
862 """return the cache key hashes that match this repoview state""" | 873 """return the cache key hashes that match this repoview state""" |
863 filtered_hash = scmutil.combined_filtered_and_obsolete_hash( | 874 return scmutil.filtered_and_obsolete_hash( |
864 repo, | 875 repo, |
865 self.tiprev, | 876 self.tiprev, |
866 needobsolete=True, | |
867 ) | 877 ) |
868 if filtered_hash is None: | |
869 return cast(Tuple[bytes], ()) | |
870 else: | |
871 return (filtered_hash,) | |
872 | 878 |
873 | 879 |
874 class remotebranchcache(_BaseBranchCache): | 880 class remotebranchcache(_BaseBranchCache): |
875 """Branchmap info for a remote connection, should not write locally""" | 881 """Branchmap info for a remote connection, should not write locally""" |
876 | 882 |