bundle-ng: simplify lookup and state handling
authorBenoit Boissinot <benoit.boissinot@ens-lyon.org>
Fri, 10 May 2013 23:14:54 +0200
changeset 19207 a67e1380dfbd
parent 19206 6308896b1d4a
child 19208 0b564cf359a7
bundle-ng: simplify lookup and state handling Use simpler callbacks to collect linkrev nodes.
mercurial/changegroup.py
--- a/mercurial/changegroup.py	Fri May 10 22:57:54 2013 +0200
+++ b/mercurial/changegroup.py	Fri May 10 23:14:54 2013 +0200
@@ -244,14 +244,13 @@
             reorder = util.parsebool(reorder)
         self._repo = repo
         self._reorder = reorder
-        self.count = [0, 0]
     def close(self):
         return closechunk()
 
     def fileheader(self, fname):
         return chunkheader(len(fname)) + fname
 
-    def group(self, nodelist, revlog, reorder=None):
+    def group(self, nodelist, revlog, lookup, reorder=None):
         """Calculate a delta group, yielding a sequence of changegroup chunks
         (strings).
 
@@ -284,7 +283,8 @@
         # build deltas
         for r in xrange(len(revs) - 1):
             prev, curr = revs[r], revs[r + 1]
-            for c in self.revchunk(revlog, curr, prev):
+            linknode = lookup(revlog.node(curr))
+            for c in self.revchunk(revlog, curr, prev, linknode):
                 yield c
 
         yield self.close()
@@ -296,7 +296,10 @@
         mf = self._manifest
         reorder = self._reorder
         progress = repo.ui.progress
-        count = self.count
+        # Keep track of progress, this is a list since it is modified by revlog
+        # callbacks. First item is the number of items done, second is the
+        # total number to be processed.
+        count = [0, 0]
         _bundling = _('bundling')
         _changesets = _('changesets')
         _manifests = _('manifests')
@@ -305,7 +308,6 @@
         mfs = {} # needed manifests
         fnodes = {} # needed file nodes
         changedfiles = set()
-        fstate = ['', {}]
 
         # filter any nodes that claim to be part of the known set
         def prune(revlog, missing):
@@ -313,35 +315,38 @@
             return [n for n in missing
                     if rl(rr(n)) not in commonrevs]
 
-        def lookup(revlog, x):
-            if revlog == cl:
-                c = cl.read(x)
-                changedfiles.update(c[3])
-                mfs.setdefault(c[0], x)
-                count[0] += 1
-                progress(_bundling, count[0],
-                         unit=_changesets, total=count[1])
-                return x
-            elif revlog == mf:
-                clnode = mfs[x]
-                if not fastpathlinkrev:
-                    mdata = mf.readfast(x)
-                    for f, n in mdata.iteritems():
-                        if f in changedfiles:
-                            fnodes[f].setdefault(n, clnode)
-                count[0] += 1
-                progress(_bundling, count[0],
-                         unit=_manifests, total=count[1])
-                return clnode
-            else:
-                progress(_bundling, count[0], item=fstate[0],
-                         unit=_files, total=count[1])
-                return fstate[1][x]
+        # Callback for the changelog, used to collect changed files and manifest
+        # nodes.
+        # Returns the linkrev node (identity in the changelog case).
+        def lookupcl(x):
+            c = cl.read(x)
+            changedfiles.update(c[3])
+            # record the first changeset introducing this manifest version
+            mfs.setdefault(c[0], x)
+            count[0] += 1
+            progress(_bundling, count[0],
+                     unit=_changesets, total=count[1])
+            return x
 
-        self._lookup = lookup
+        # Callback for the manifest, used to collect linkrevs for filelog
+        # revisions.
+        # Returns the linkrev node (collected in lookupcl).
+        def lookupmf(x):
+            clnode = mfs[x]
+            if not fastpathlinkrev:
+                mdata = mf.readfast(x)
+                for f, n in mdata.iteritems():
+                    if f in changedfiles:
+                        # record the first changeset introducing this filelog
+                        # version
+                        fnodes[f].setdefault(n, clnode)
+            count[0] += 1
+            progress(_bundling, count[0],
+                     unit=_manifests, total=count[1])
+            return clnode
 
         count[:] = [0, len(clnodes)]
-        for chunk in self.group(clnodes, cl, reorder=reorder):
+        for chunk in self.group(clnodes, cl, lookupcl, reorder=reorder):
             yield chunk
         progress(_bundling, None)
 
@@ -349,7 +354,7 @@
             fnodes[f] = {}
         count[:] = [0, len(mfs)]
         mfnodes = prune(mf, mfs)
-        for chunk in self.group(mfnodes, mf, reorder=reorder):
+        for chunk in self.group(mfnodes, mf, lookupmf, reorder=reorder):
             yield chunk
         progress(_bundling, None)
 
@@ -369,13 +374,21 @@
                         if linkrev not in commonrevs:
                             yield filerevlog.node(r), cl.node(linkrev)
                 fnodes[fname] = dict(genfilenodes())
-            fstate[0] = fname
-            fstate[1] = fnodes.pop(fname, {})
-            filenodes = prune(filerevlog, fstate[1])
+
+            linkrevnodes = fnodes.pop(fname, {})
+            # Lookup for filenodes, we collected the linkrev nodes above in the
+            # fastpath case and with lookupmf in the slowpath case.
+            def lookupfilelog(x):
+                progress(_bundling, count[0], item=fname,
+                         unit=_files, total=count[1])
+                return linkrevnodes[x]
+
+            filenodes = prune(filerevlog, linkrevnodes)
             if filenodes:
                 count[0] += 1
                 yield self.fileheader(fname)
-                for chunk in self.group(filenodes, filerevlog, reorder):
+                for chunk in self.group(filenodes, filerevlog, lookupfilelog,
+                                        reorder):
                     yield chunk
         yield self.close()
         progress(_bundling, None)
@@ -383,7 +396,7 @@
         if clnodes:
             repo.hook('outgoing', node=hex(clnodes[0]), source=source)
 
-    def revchunk(self, revlog, rev, prev):
+    def revchunk(self, revlog, rev, prev, linknode):
         node = revlog.node(rev)
         p1, p2 = revlog.parentrevs(rev)
         base = prev
@@ -394,7 +407,6 @@
             prefix = mdiff.trivialdiffheader(len(delta))
         else:
             delta = revlog.revdiff(base, rev)
-        linknode = self._lookup(revlog, node)
         p1n, p2n = revlog.parents(node)
         basenode = revlog.node(base)
         meta = self.builddeltaheader(node, p1n, p2n, basenode, linknode)