mercurial/changegroup.py
changeset 38901 23ae0c07a3e1
parent 38900 6e999a2d8fe7
child 38902 4c99c6d1ef95
equal deleted inserted replaced
38900:6e999a2d8fe7 38901:23ae0c07a3e1
   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.
   546         """
   549         """
   547         assert filematcher
   550         assert filematcher
   548         self._filematcher = filematcher
   551         self._filematcher = filematcher
   549 
   552 
   550         self.version = version
   553         self.version = version
       
   554         self._useprevdelta = useprevdelta
   551         self._builddeltaheader = builddeltaheader
   555         self._builddeltaheader = builddeltaheader
   552         self._manifestsend = manifestsend
   556         self._manifestsend = manifestsend
   553         self._sendtreemanifests = sendtreemanifests
   557         self._sendtreemanifests = sendtreemanifests
   554 
   558 
   555         # Set of capabilities we can use to build the bundle.
   559         # Set of capabilities we can use to build the bundle.
   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),