492 if len(d) < n: |
496 if len(d) < n: |
493 d += readexactly(self._fh, n - len(d)) |
497 d += readexactly(self._fh, n - len(d)) |
494 return d |
498 return d |
495 return readexactly(self._fh, n) |
499 return readexactly(self._fh, n) |
496 |
500 |
|
501 @attr.s(slots=True, frozen=True) |
|
502 class revisiondelta(object): |
|
503 """Describes a delta entry in a changegroup. |
|
504 |
|
505 Captured data is sufficient to serialize the delta into multiple |
|
506 formats. |
|
507 """ |
|
508 # 20 byte node of this revision. |
|
509 node = attr.ib() |
|
510 # 20 byte nodes of parent revisions. |
|
511 p1node = attr.ib() |
|
512 p2node = attr.ib() |
|
513 # 20 byte node of node this delta is against. |
|
514 basenode = attr.ib() |
|
515 # 20 byte node of changeset revision this delta is associated with. |
|
516 linknode = attr.ib() |
|
517 # 2 bytes of flags to apply to revision data. |
|
518 flags = attr.ib() |
|
519 # Iterable of chunks holding raw delta data. |
|
520 deltachunks = attr.ib() |
497 |
521 |
498 class cg1packer(object): |
522 class cg1packer(object): |
499 deltaheader = _CHANGEGROUPV1_DELTA_HEADER |
523 deltaheader = _CHANGEGROUPV1_DELTA_HEADER |
500 version = '01' |
524 version = '01' |
501 def __init__(self, repo, filematcher, bundlecaps=None): |
525 def __init__(self, repo, filematcher, bundlecaps=None): |
897 raise error.ProgrammingError('cg1 should not be used in this case') |
921 raise error.ProgrammingError('cg1 should not be used in this case') |
898 return prev |
922 return prev |
899 |
923 |
900 def revchunk(self, store, rev, prev, linknode): |
924 def revchunk(self, store, rev, prev, linknode): |
901 if util.safehasattr(self, 'full_nodes'): |
925 if util.safehasattr(self, 'full_nodes'): |
902 fn = self._revchunknarrow |
926 fn = self._revisiondeltanarrow |
903 else: |
927 else: |
904 fn = self._revchunknormal |
928 fn = self._revisiondeltanormal |
905 |
929 |
906 return fn(store, rev, prev, linknode) |
930 delta = fn(store, rev, prev, linknode) |
907 |
931 if not delta: |
908 def _revchunknormal(self, store, rev, prev, linknode): |
932 return |
|
933 |
|
934 meta = self.builddeltaheader(delta.node, delta.p1node, delta.p2node, |
|
935 delta.basenode, delta.linknode, |
|
936 delta.flags) |
|
937 l = len(meta) + sum(len(x) for x in delta.deltachunks) |
|
938 |
|
939 yield chunkheader(l) |
|
940 yield meta |
|
941 for x in delta.deltachunks: |
|
942 yield x |
|
943 |
|
944 def _revisiondeltanormal(self, store, rev, prev, linknode): |
909 node = store.node(rev) |
945 node = store.node(rev) |
910 p1, p2 = store.parentrevs(rev) |
946 p1, p2 = store.parentrevs(rev) |
911 base = self.deltaparent(store, rev, p1, p2, prev) |
947 base = self.deltaparent(store, rev, p1, p2, prev) |
912 |
948 |
913 prefix = '' |
949 prefix = '' |
925 delta = store.revision(node, raw=True) |
961 delta = store.revision(node, raw=True) |
926 prefix = mdiff.trivialdiffheader(len(delta)) |
962 prefix = mdiff.trivialdiffheader(len(delta)) |
927 else: |
963 else: |
928 delta = store.revdiff(base, rev) |
964 delta = store.revdiff(base, rev) |
929 p1n, p2n = store.parents(node) |
965 p1n, p2n = store.parents(node) |
930 basenode = store.node(base) |
966 |
931 flags = store.flags(rev) |
967 return revisiondelta( |
932 meta = self.builddeltaheader(node, p1n, p2n, basenode, linknode, flags) |
968 node=node, |
933 meta += prefix |
969 p1node=p1n, |
934 l = len(meta) + len(delta) |
970 p2node=p2n, |
935 yield chunkheader(l) |
971 basenode=store.node(base), |
936 yield meta |
972 linknode=linknode, |
937 yield delta |
973 flags=store.flags(rev), |
938 |
974 deltachunks=(prefix, delta), |
939 def _revchunknarrow(self, store, rev, prev, linknode): |
975 ) |
|
976 |
|
977 def _revisiondeltanarrow(self, store, rev, prev, linknode): |
940 # build up some mapping information that's useful later. See |
978 # build up some mapping information that's useful later. See |
941 # the local() nested function below. |
979 # the local() nested function below. |
942 if not self.changelog_done: |
980 if not self.changelog_done: |
943 self.clnode_to_rev[linknode] = rev |
981 self.clnode_to_rev[linknode] = rev |
944 linkrev = rev |
982 linkrev = rev |
948 self.clrev_to_localrev[linkrev] = rev |
986 self.clrev_to_localrev[linkrev] = rev |
949 |
987 |
950 # This is a node to send in full, because the changeset it |
988 # This is a node to send in full, because the changeset it |
951 # corresponds to was a full changeset. |
989 # corresponds to was a full changeset. |
952 if linknode in self.full_nodes: |
990 if linknode in self.full_nodes: |
953 for x in self._revchunknormal(store, rev, prev, linknode): |
991 return self._revisiondeltanormal(store, rev, prev, linknode) |
954 yield x |
|
955 return |
|
956 |
992 |
957 # At this point, a node can either be one we should skip or an |
993 # At this point, a node can either be one we should skip or an |
958 # ellipsis. If it's not an ellipsis, bail immediately. |
994 # ellipsis. If it's not an ellipsis, bail immediately. |
959 if linkrev not in self.precomputed_ellipsis: |
995 if linkrev not in self.precomputed_ellipsis: |
960 return |
996 return |
1041 |
1077 |
1042 n = store.node(rev) |
1078 n = store.node(rev) |
1043 p1n, p2n = store.node(p1), store.node(p2) |
1079 p1n, p2n = store.node(p1), store.node(p2) |
1044 flags = store.flags(rev) |
1080 flags = store.flags(rev) |
1045 flags |= revlog.REVIDX_ELLIPSIS |
1081 flags |= revlog.REVIDX_ELLIPSIS |
1046 meta = self.builddeltaheader( |
1082 |
1047 n, p1n, p2n, nullid, linknode, flags) |
|
1048 # TODO: try and actually send deltas for ellipsis data blocks |
1083 # TODO: try and actually send deltas for ellipsis data blocks |
1049 data = store.revision(n) |
1084 data = store.revision(n) |
1050 diffheader = mdiff.trivialdiffheader(len(data)) |
1085 diffheader = mdiff.trivialdiffheader(len(data)) |
1051 l = len(meta) + len(diffheader) + len(data) |
1086 |
1052 yield ''.join((chunkheader(l), |
1087 return revisiondelta( |
1053 meta, |
1088 node=n, |
1054 diffheader, |
1089 p1node=p1n, |
1055 data)) |
1090 p2node=p2n, |
|
1091 basenode=nullid, |
|
1092 linknode=linknode, |
|
1093 flags=flags, |
|
1094 deltachunks=(diffheader, data), |
|
1095 ) |
1056 |
1096 |
1057 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags): |
1097 def builddeltaheader(self, node, p1n, p2n, basenode, linknode, flags): |
1058 # do nothing with basenode, it is implicitly the previous one in HG10 |
1098 # do nothing with basenode, it is implicitly the previous one in HG10 |
1059 # do nothing with flags, it is implicitly 0 for cg1 and cg2 |
1099 # do nothing with flags, it is implicitly 0 for cg1 and cg2 |
1060 return struct.pack(self.deltaheader, node, p1n, p2n, linknode) |
1100 return struct.pack(self.deltaheader, node, p1n, p2n, linknode) |