519 # Iterable of chunks holding raw delta data. |
519 # Iterable of chunks holding raw delta data. |
520 deltachunks = attr.ib() |
520 deltachunks = attr.ib() |
521 |
521 |
522 class cg1packer(object): |
522 class cg1packer(object): |
523 def __init__(self, repo, filematcher, version, allowreorder, |
523 def __init__(self, repo, filematcher, version, allowreorder, |
524 builddeltaheader, manifestsend, sendtreemanifests, |
524 useprevdelta, builddeltaheader, manifestsend, |
525 bundlecaps=None): |
525 sendtreemanifests, bundlecaps=None): |
526 """Given a source repo, construct a bundler. |
526 """Given a source repo, construct a bundler. |
527 |
527 |
528 filematcher is a matcher that matches on files to include in the |
528 filematcher is a matcher that matches on files to include in the |
529 changegroup. Used to facilitate sparse changegroups. |
529 changegroup. Used to facilitate sparse changegroups. |
530 |
530 |
531 allowreorder controls whether reordering of revisions is allowed. |
531 allowreorder controls whether reordering of revisions is allowed. |
532 This value is used when ``bundle.reorder`` is ``auto`` or isn't |
532 This value is used when ``bundle.reorder`` is ``auto`` or isn't |
533 set. |
533 set. |
|
534 |
|
535 useprevdelta controls whether revisions should always delta against |
|
536 the previous revision in the changegroup. |
534 |
537 |
535 builddeltaheader is a callable that constructs the header for a group |
538 builddeltaheader is a callable that constructs the header for a group |
536 delta. |
539 delta. |
537 |
540 |
538 manifestsend is a chunk to send after manifests have been fully emitted. |
541 manifestsend is a chunk to send after manifests have been fully emitted. |
948 yield chunk |
952 yield chunk |
949 self._verbosenote(_('%8.i %s\n') % (size, fname)) |
953 self._verbosenote(_('%8.i %s\n') % (size, fname)) |
950 progress.complete() |
954 progress.complete() |
951 |
955 |
952 def deltaparent(self, store, rev, p1, p2, prev): |
956 def deltaparent(self, store, rev, p1, p2, prev): |
953 if not store.candelta(prev, rev): |
957 if self._useprevdelta: |
954 raise error.ProgrammingError('cg1 should not be used in this case') |
958 if not store.candelta(prev, rev): |
955 return prev |
959 raise error.ProgrammingError( |
|
960 'cg1 should not be used in this case') |
|
961 return prev |
|
962 |
|
963 # Narrow ellipses mode. |
|
964 if util.safehasattr(self, 'full_nodes'): |
|
965 # TODO: send better deltas when in narrow mode. |
|
966 # |
|
967 # changegroup.group() loops over revisions to send, |
|
968 # including revisions we'll skip. What this means is that |
|
969 # `prev` will be a potentially useless delta base for all |
|
970 # ellipsis nodes, as the client likely won't have it. In |
|
971 # the future we should do bookkeeping about which nodes |
|
972 # have been sent to the client, and try to be |
|
973 # significantly smarter about delta bases. This is |
|
974 # slightly tricky because this same code has to work for |
|
975 # all revlogs, and we don't have the linkrev/linknode here. |
|
976 return p1 |
|
977 |
|
978 dp = store.deltaparent(rev) |
|
979 if dp == nullrev and store.storedeltachains: |
|
980 # Avoid sending full revisions when delta parent is null. Pick prev |
|
981 # in that case. It's tempting to pick p1 in this case, as p1 will |
|
982 # be smaller in the common case. However, computing a delta against |
|
983 # p1 may require resolving the raw text of p1, which could be |
|
984 # expensive. The revlog caches should have prev cached, meaning |
|
985 # less CPU for changegroup generation. There is likely room to add |
|
986 # a flag and/or config option to control this behavior. |
|
987 base = prev |
|
988 elif dp == nullrev: |
|
989 # revlog is configured to use full snapshot for a reason, |
|
990 # stick to full snapshot. |
|
991 base = nullrev |
|
992 elif dp not in (p1, p2, prev): |
|
993 # Pick prev when we can't be sure remote has the base revision. |
|
994 return prev |
|
995 else: |
|
996 base = dp |
|
997 |
|
998 if base != nullrev and not store.candelta(base, rev): |
|
999 base = nullrev |
|
1000 |
|
1001 return base |
956 |
1002 |
957 def revchunk(self, store, rev, prev, linknode): |
1003 def revchunk(self, store, rev, prev, linknode): |
958 if util.safehasattr(self, 'full_nodes'): |
1004 if util.safehasattr(self, 'full_nodes'): |
959 fn = self._revisiondeltanarrow |
1005 fn = self._revisiondeltanarrow |
960 else: |
1006 else: |
1123 linknode=linknode, |
1169 linknode=linknode, |
1124 flags=flags, |
1170 flags=flags, |
1125 deltachunks=(diffheader, data), |
1171 deltachunks=(diffheader, data), |
1126 ) |
1172 ) |
1127 |
1173 |
1128 class cg2packer(cg1packer): |
|
1129 def deltaparent(self, store, rev, p1, p2, prev): |
|
1130 # Narrow ellipses mode. |
|
1131 if util.safehasattr(self, 'full_nodes'): |
|
1132 # TODO: send better deltas when in narrow mode. |
|
1133 # |
|
1134 # changegroup.group() loops over revisions to send, |
|
1135 # including revisions we'll skip. What this means is that |
|
1136 # `prev` will be a potentially useless delta base for all |
|
1137 # ellipsis nodes, as the client likely won't have it. In |
|
1138 # the future we should do bookkeeping about which nodes |
|
1139 # have been sent to the client, and try to be |
|
1140 # significantly smarter about delta bases. This is |
|
1141 # slightly tricky because this same code has to work for |
|
1142 # all revlogs, and we don't have the linkrev/linknode here. |
|
1143 return p1 |
|
1144 |
|
1145 dp = store.deltaparent(rev) |
|
1146 if dp == nullrev and store.storedeltachains: |
|
1147 # Avoid sending full revisions when delta parent is null. Pick prev |
|
1148 # in that case. It's tempting to pick p1 in this case, as p1 will |
|
1149 # be smaller in the common case. However, computing a delta against |
|
1150 # p1 may require resolving the raw text of p1, which could be |
|
1151 # expensive. The revlog caches should have prev cached, meaning |
|
1152 # less CPU for changegroup generation. There is likely room to add |
|
1153 # a flag and/or config option to control this behavior. |
|
1154 base = prev |
|
1155 elif dp == nullrev: |
|
1156 # revlog is configured to use full snapshot for a reason, |
|
1157 # stick to full snapshot. |
|
1158 base = nullrev |
|
1159 elif dp not in (p1, p2, prev): |
|
1160 # Pick prev when we can't be sure remote has the base revision. |
|
1161 return prev |
|
1162 else: |
|
1163 base = dp |
|
1164 if base != nullrev and not store.candelta(base, rev): |
|
1165 base = nullrev |
|
1166 return base |
|
1167 |
|
1168 def _makecg1packer(repo, filematcher, bundlecaps): |
1174 def _makecg1packer(repo, filematcher, bundlecaps): |
1169 builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack( |
1175 builddeltaheader = lambda d: _CHANGEGROUPV1_DELTA_HEADER.pack( |
1170 d.node, d.p1node, d.p2node, d.linknode) |
1176 d.node, d.p1node, d.p2node, d.linknode) |
1171 |
1177 |
1172 return cg1packer(repo, filematcher, b'01', allowreorder=None, |
1178 return cg1packer(repo, filematcher, b'01', |
|
1179 useprevdelta=True, |
|
1180 allowreorder=None, |
1173 builddeltaheader=builddeltaheader, |
1181 builddeltaheader=builddeltaheader, |
1174 manifestsend=b'', sendtreemanifests=False, |
1182 manifestsend=b'', sendtreemanifests=False, |
1175 bundlecaps=bundlecaps) |
1183 bundlecaps=bundlecaps) |
1176 |
1184 |
1177 def _makecg2packer(repo, filematcher, bundlecaps): |
1185 def _makecg2packer(repo, filematcher, bundlecaps): |
1179 d.node, d.p1node, d.p2node, d.basenode, d.linknode) |
1187 d.node, d.p1node, d.p2node, d.basenode, d.linknode) |
1180 |
1188 |
1181 # Since generaldelta is directly supported by cg2, reordering |
1189 # Since generaldelta is directly supported by cg2, reordering |
1182 # generally doesn't help, so we disable it by default (treating |
1190 # generally doesn't help, so we disable it by default (treating |
1183 # bundle.reorder=auto just like bundle.reorder=False). |
1191 # bundle.reorder=auto just like bundle.reorder=False). |
1184 return cg2packer(repo, filematcher, b'02', allowreorder=False, |
1192 return cg1packer(repo, filematcher, b'02', |
|
1193 useprevdelta=False, |
|
1194 allowreorder=False, |
1185 builddeltaheader=builddeltaheader, |
1195 builddeltaheader=builddeltaheader, |
1186 manifestsend=b'', sendtreemanifests=False, |
1196 manifestsend=b'', sendtreemanifests=False, |
1187 bundlecaps=bundlecaps) |
1197 bundlecaps=bundlecaps) |
1188 |
1198 |
1189 def _makecg3packer(repo, filematcher, bundlecaps): |
1199 def _makecg3packer(repo, filematcher, bundlecaps): |
1190 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack( |
1200 builddeltaheader = lambda d: _CHANGEGROUPV3_DELTA_HEADER.pack( |
1191 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags) |
1201 d.node, d.p1node, d.p2node, d.basenode, d.linknode, d.flags) |
1192 |
1202 |
1193 return cg2packer(repo, filematcher, b'03', allowreorder=False, |
1203 return cg1packer(repo, filematcher, b'03', |
|
1204 useprevdelta=False, |
|
1205 allowreorder=False, |
1194 builddeltaheader=builddeltaheader, |
1206 builddeltaheader=builddeltaheader, |
1195 manifestsend=closechunk(), sendtreemanifests=True, |
1207 manifestsend=closechunk(), sendtreemanifests=True, |
1196 bundlecaps=bundlecaps) |
1208 bundlecaps=bundlecaps) |
1197 |
1209 |
1198 _packermap = {'01': (_makecg1packer, cg1unpacker), |
1210 _packermap = {'01': (_makecg1packer, cg1unpacker), |