mercurial/changegroup.py
changeset 39018 4a202bccafcf
parent 39017 6d726d1b08cb
child 39019 227ebd88ce5e
equal deleted inserted replaced
39017:6d726d1b08cb 39018:4a202bccafcf
   586         if self._repo.ui.verbose and not self._repo.ui.debugflag:
   586         if self._repo.ui.verbose and not self._repo.ui.debugflag:
   587             self._verbosenote = self._repo.ui.note
   587             self._verbosenote = self._repo.ui.note
   588         else:
   588         else:
   589             self._verbosenote = lambda s: None
   589             self._verbosenote = lambda s: None
   590 
   590 
   591         # TODO the functionality keyed off of this should probably be
       
   592         # controlled via arguments to group() that influence behavior.
       
   593         self._changelogdone = False
       
   594 
       
   595         # Maps CL revs to per-revlog revisions. Cleared in close() at
   591         # Maps CL revs to per-revlog revisions. Cleared in close() at
   596         # the end of each group.
   592         # the end of each group.
   597         self._clrevtolocalrev = {}
   593         self._clrevtolocalrev = {}
   598         self._nextclrevtolocalrev = {}
   594         self._nextclrevtolocalrev = {}
   599 
   595 
   612 
   608 
   613     def _fileheader(self, fname):
   609     def _fileheader(self, fname):
   614         return chunkheader(len(fname)) + fname
   610         return chunkheader(len(fname)) + fname
   615 
   611 
   616     # Extracted both for clarity and for overriding in extensions.
   612     # Extracted both for clarity and for overriding in extensions.
   617     def _sortgroup(self, store, nodelist, lookup):
   613     def _sortgroup(self, store, ischangelog, nodelist, lookup):
   618         """Sort nodes for change group and turn them into revnums."""
   614         """Sort nodes for change group and turn them into revnums."""
   619         # Ellipses serving mode.
   615         # Ellipses serving mode.
   620         #
   616         #
   621         # In a perfect world, we'd generate better ellipsis-ified graphs
   617         # In a perfect world, we'd generate better ellipsis-ified graphs
   622         # for non-changelog revlogs. In practice, we haven't started doing
   618         # for non-changelog revlogs. In practice, we haven't started doing
   630         # The one invariant we *know* holds is that the new (potentially
   626         # The one invariant we *know* holds is that the new (potentially
   631         # bogus) DAG shape will be valid if we order the nodes in the
   627         # bogus) DAG shape will be valid if we order the nodes in the
   632         # order that they're introduced in dramatis personae by the
   628         # order that they're introduced in dramatis personae by the
   633         # changelog, so what we do is we sort the non-changelog histories
   629         # changelog, so what we do is we sort the non-changelog histories
   634         # by the order in which they are used by the changelog.
   630         # by the order in which they are used by the changelog.
   635         if self._ellipses and self._changelogdone:
   631         if self._ellipses and not ischangelog:
   636             key = lambda n: self._clnodetorev[lookup(n)]
   632             key = lambda n: self._clnodetorev[lookup(n)]
   637             return [store.rev(n) for n in sorted(nodelist, key=key)]
   633             return [store.rev(n) for n in sorted(nodelist, key=key)]
   638 
   634 
   639         # for generaldelta revlogs, we linearize the revs; this will both be
   635         # for generaldelta revlogs, we linearize the revs; this will both be
   640         # much quicker and generate a much smaller bundle
   636         # much quicker and generate a much smaller bundle
   642             dag = dagutil.revlogdag(store)
   638             dag = dagutil.revlogdag(store)
   643             return dag.linearize(set(store.rev(n) for n in nodelist))
   639             return dag.linearize(set(store.rev(n) for n in nodelist))
   644         else:
   640         else:
   645             return sorted([store.rev(n) for n in nodelist])
   641             return sorted([store.rev(n) for n in nodelist])
   646 
   642 
   647     def group(self, nodelist, store, lookup, units=None):
   643     def group(self, nodelist, store, ischangelog, lookup, units=None):
   648         """Calculate a delta group, yielding a sequence of changegroup chunks
   644         """Calculate a delta group, yielding a sequence of changegroup chunks
   649         (strings).
   645         (strings).
   650 
   646 
   651         Given a list of changeset revs, return a set of deltas and
   647         Given a list of changeset revs, return a set of deltas and
   652         metadata corresponding to nodes. The first delta is
   648         metadata corresponding to nodes. The first delta is
   661         # if we don't have any revisions touched by these changesets, bail
   657         # if we don't have any revisions touched by these changesets, bail
   662         if len(nodelist) == 0:
   658         if len(nodelist) == 0:
   663             yield self._close()
   659             yield self._close()
   664             return
   660             return
   665 
   661 
   666         revs = self._sortgroup(store, nodelist, lookup)
   662         revs = self._sortgroup(store, ischangelog, nodelist, lookup)
   667 
   663 
   668         # add the parent of the first rev
   664         # add the parent of the first rev
   669         p = store.parentrevs(revs[0])[0]
   665         p = store.parentrevs(revs[0])[0]
   670         revs.insert(0, p)
   666         revs.insert(0, p)
   671 
   667 
   677         for r in pycompat.xrange(len(revs) - 1):
   673         for r in pycompat.xrange(len(revs) - 1):
   678             if progress:
   674             if progress:
   679                 progress.update(r + 1)
   675                 progress.update(r + 1)
   680             prev, curr = revs[r], revs[r + 1]
   676             prev, curr = revs[r], revs[r + 1]
   681             linknode = lookup(store.node(curr))
   677             linknode = lookup(store.node(curr))
   682             for c in self._revchunk(store, curr, prev, linknode):
   678             for c in self._revchunk(store, ischangelog, curr, prev, linknode):
   683                 yield c
   679                 yield c
   684 
   680 
   685         if progress:
   681         if progress:
   686             progress.complete()
   682             progress.complete()
   687         yield self._close()
   683         yield self._close()
   707             assert self.version == b'03'
   703             assert self.version == b'03'
   708             yield self._fileheader(dir)
   704             yield self._fileheader(dir)
   709 
   705 
   710         # TODO violates storage abstractions by assuming revlogs.
   706         # TODO violates storage abstractions by assuming revlogs.
   711         dirlog = self._repo.manifestlog._revlog.dirlog(dir)
   707         dirlog = self._repo.manifestlog._revlog.dirlog(dir)
   712         for chunk in self.group(mfnodes, dirlog, lookuplinknode,
   708         for chunk in self.group(mfnodes, dirlog, False, lookuplinknode,
   713                                 units=_('manifests')):
   709                                 units=_('manifests')):
   714             yield chunk
   710             yield chunk
   715 
   711 
   716     def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
   712     def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
   717         """Yield a sequence of changegroup byte chunks."""
   713         """Yield a sequence of changegroup byte chunks."""
   726         for chunk in chunks:
   722         for chunk in chunks:
   727             size += len(chunk)
   723             size += len(chunk)
   728             yield chunk
   724             yield chunk
   729 
   725 
   730         self._verbosenote(_('%8.i (changelog)\n') % size)
   726         self._verbosenote(_('%8.i (changelog)\n') % size)
   731 
       
   732         self._changelogdone = True
       
   733 
   727 
   734         clrevorder = clstate['clrevorder']
   728         clrevorder = clstate['clrevorder']
   735         mfs = clstate['mfs']
   729         mfs = clstate['mfs']
   736         changedfiles = clstate['changedfiles']
   730         changedfiles = clstate['changedfiles']
   737 
   731 
   859             'clrevorder': clrevorder,
   853             'clrevorder': clrevorder,
   860             'mfs': mfs,
   854             'mfs': mfs,
   861             'changedfiles': changedfiles,
   855             'changedfiles': changedfiles,
   862         }
   856         }
   863 
   857 
   864         gen = self.group(nodes, cl, lookupcl, units=_('changesets'))
   858         gen = self.group(nodes, cl, True, lookupcl, units=_('changesets'))
   865 
   859 
   866         return state, gen
   860         return state, gen
   867 
   861 
   868     def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev, mfs,
   862     def generatemanifests(self, commonrevs, clrevorder, fastpathlinkrev, mfs,
   869                           fnodes, source):
   863                           fnodes, source):
   988             if filenodes:
   982             if filenodes:
   989                 progress.update(i + 1, item=fname)
   983                 progress.update(i + 1, item=fname)
   990                 h = self._fileheader(fname)
   984                 h = self._fileheader(fname)
   991                 size = len(h)
   985                 size = len(h)
   992                 yield h
   986                 yield h
   993                 for chunk in self.group(filenodes, filerevlog, lookupfilelog):
   987                 for chunk in self.group(filenodes, filerevlog, False,
       
   988                                         lookupfilelog):
   994                     size += len(chunk)
   989                     size += len(chunk)
   995                     yield chunk
   990                     yield chunk
   996                 self._verbosenote(_('%8.i  %s\n') % (size, fname))
   991                 self._verbosenote(_('%8.i  %s\n') % (size, fname))
   997         progress.complete()
   992         progress.complete()
   998 
   993 
   999     def _revchunk(self, store, rev, prev, linknode):
   994     def _revchunk(self, store, ischangelog, rev, prev, linknode):
  1000         if self._ellipses:
   995         if self._ellipses:
  1001             fn = self._revisiondeltanarrow
   996             fn = self._revisiondeltanarrow
  1002         else:
   997         else:
  1003             fn = self._revisiondeltanormal
   998             fn = self._revisiondeltanormal
  1004 
   999 
  1005         delta = fn(store, rev, prev, linknode)
  1000         delta = fn(store, ischangelog, rev, prev, linknode)
  1006         if not delta:
  1001         if not delta:
  1007             return
  1002             return
  1008 
  1003 
  1009         meta = self._builddeltaheader(delta)
  1004         meta = self._builddeltaheader(delta)
  1010         l = len(meta) + sum(len(x) for x in delta.deltachunks)
  1005         l = len(meta) + sum(len(x) for x in delta.deltachunks)
  1012         yield chunkheader(l)
  1007         yield chunkheader(l)
  1013         yield meta
  1008         yield meta
  1014         for x in delta.deltachunks:
  1009         for x in delta.deltachunks:
  1015             yield x
  1010             yield x
  1016 
  1011 
  1017     def _revisiondeltanormal(self, store, rev, prev, linknode):
  1012     def _revisiondeltanormal(self, store, ischangelog, rev, prev, linknode):
  1018         node = store.node(rev)
  1013         node = store.node(rev)
  1019         p1, p2 = store.parentrevs(rev)
  1014         p1, p2 = store.parentrevs(rev)
  1020         base = self._deltaparentfn(store, rev, p1, p2, prev)
  1015         base = self._deltaparentfn(store, rev, p1, p2, prev)
  1021 
  1016 
  1022         prefix = ''
  1017         prefix = ''
  1045             linknode=linknode,
  1040             linknode=linknode,
  1046             flags=store.flags(rev),
  1041             flags=store.flags(rev),
  1047             deltachunks=(prefix, delta),
  1042             deltachunks=(prefix, delta),
  1048         )
  1043         )
  1049 
  1044 
  1050     def _revisiondeltanarrow(self, store, rev, prev, linknode):
  1045     def _revisiondeltanarrow(self, store, ischangelog, rev, prev, linknode):
  1051         # build up some mapping information that's useful later. See
  1046         # build up some mapping information that's useful later. See
  1052         # the local() nested function below.
  1047         # the local() nested function below.
  1053         if not self._changelogdone:
  1048         if ischangelog:
  1054             self._clnodetorev[linknode] = rev
  1049             self._clnodetorev[linknode] = rev
  1055             linkrev = rev
  1050             linkrev = rev
  1056             self._clrevtolocalrev[linkrev] = rev
  1051             self._clrevtolocalrev[linkrev] = rev
  1057         else:
  1052         else:
  1058             linkrev = self._clnodetorev[linknode]
  1053             linkrev = self._clnodetorev[linknode]
  1059             self._clrevtolocalrev[linkrev] = rev
  1054             self._clrevtolocalrev[linkrev] = rev
  1060 
  1055 
  1061         # This is a node to send in full, because the changeset it
  1056         # This is a node to send in full, because the changeset it
  1062         # corresponds to was a full changeset.
  1057         # corresponds to was a full changeset.
  1063         if linknode in self._fullnodes:
  1058         if linknode in self._fullnodes:
  1064             return self._revisiondeltanormal(store, rev, prev, linknode)
  1059             return self._revisiondeltanormal(store, ischangelog, rev, prev,
       
  1060                                              linknode)
  1065 
  1061 
  1066         # At this point, a node can either be one we should skip or an
  1062         # At this point, a node can either be one we should skip or an
  1067         # ellipsis. If it's not an ellipsis, bail immediately.
  1063         # ellipsis. If it's not an ellipsis, bail immediately.
  1068         if linkrev not in self._precomputedellipsis:
  1064         if linkrev not in self._precomputedellipsis:
  1069             return
  1065             return
  1080             mappings as needed.
  1076             mappings as needed.
  1081             """
  1077             """
  1082             if clrev == nullrev:
  1078             if clrev == nullrev:
  1083                 return nullrev
  1079                 return nullrev
  1084 
  1080 
  1085             if not self._changelogdone:
  1081             if ischangelog:
  1086                 # If we're doing the changelog, it's possible that we
  1082                 # If we're doing the changelog, it's possible that we
  1087                 # have a parent that is already on the client, and we
  1083                 # have a parent that is already on the client, and we
  1088                 # need to store some extra mapping information so that
  1084                 # need to store some extra mapping information so that
  1089                 # our contained ellipsis nodes will be able to resolve
  1085                 # our contained ellipsis nodes will be able to resolve
  1090                 # their parents.
  1086                 # their parents.