changeset 56:ad2ea1185f04

Add getchangegroup code to efficiently calculate and request a changegroup
author mpm@selenic.com
date Wed, 11 May 2005 15:06:41 -0800
parents 2add70d51441
children 115106376f45
files hg mercurial/hg.py
diffstat 2 files changed, 101 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/hg	Wed May 11 14:38:26 2005 -0800
+++ b/hg	Wed May 11 15:06:41 2005 -0800
@@ -187,7 +187,7 @@
     diff(None, prev, node)
 
 elif cmd == "debugchangegroup":
-    newer = repo.newer(repo.changelog.lookup(args[0]))
+    newer = repo.newer(map(repo.changelog.lookup, args))
     cg = repo.changegroup(newer)
     sys.stdout.write(cg)
 
@@ -195,6 +195,16 @@
     data = sys.stdin.read()
     repo.addchangegroup(data)
 
+elif cmd == "debuggetchangegroup":
+    if args:
+        other = hg.repository(ui, args[0])
+	print "building changegroup"
+        cg = repo.getchangegroup(other)
+	print "applying changegroup"
+	repo.addchangegroup(cg)
+    else:
+        print "missing source repository"
+
 elif cmd == "addremove":
     (c, a, d) = repo.diffdir(repo.root, repo.current)
     repo.add(a)
--- a/mercurial/hg.py	Wed May 11 14:38:26 2005 -0800
+++ b/mercurial/hg.py	Wed May 11 15:06:41 2005 -0800
@@ -560,14 +560,97 @@
         for f in list:
             dl.write(f + "\n")
 
-    def newer(self, node):
-        nodes = []
-        for i in xrange(self.changelog.rev(node) + 1, self.changelog.count()):
-            nodes.append(self.changelog.node(i))
+    def branches(self, nodes):
+        if not nodes: nodes = [self.changelog.tip()]
+        b = []
+        for n in nodes:
+            t = n
+            while n:
+                p = self.changelog.parents(n)
+                if p[1] != nullid or p[0] == nullid:
+                    b.append((t, n, p[0], p[1]))
+                    break
+                n = p[0]
+        return b
+
+    def between(self, pairs):
+        r = []
+
+        for top, bottom in pairs:
+            n, l, i = top, [], 0
+            f = 1
+
+            while n != bottom:
+                p = self.changelog.parents(n)[0]
+                if i == f:
+                    l.append(n) 
+                    f = f * 2
+                n = p
+                i += 1
+
+            r.append(l)
+
+        return r
+
+    def newer(self, nodes):
+        m = {}
+        nl = []
+        cl = self.changelog
+        t = l = cl.count()
+        for n in nodes:
+            l = min(l, cl.rev(n))
+            for p in cl.parents(n):
+                m[p] = 1
 
-        return nodes
+        for i in xrange(l, t):
+            n = cl.node(i)
+            for p in cl.parents(n):
+                if p in m and n not in m:
+                    m[n] = 1
+                    nl.append(n)
+
+        return nl
+
+    def getchangegroup(self, remote):
+        tip = remote.branches([])
+        cl = self.changelog
+        unknown = tip
+        search = []
+        fetch = []
 
-    def changegroup(self, nodes):
+        if tip[0] == self.changelog.tip():
+            return ""
+            
+        while unknown:
+            n = unknown.pop(0)
+            if n == nullid: break
+            if n[1] and cl.nodemap.has_key(n[1]): # do we know the base?
+                search.append(n) # schedule branch range for scanning
+            else:
+                for b in remote.branches([n[2], n[3]]):
+                    if cl.nodemap.has_key(b[0]):
+                        fetch.append(n[1]) # earliest unknown
+                    else:
+                        unknown.append(b)
+  
+        while search:
+            n = search.pop(0)
+            l = remote.between([(n[0], n[1])])[0]
+            p = n[0]
+            f = 1
+            for i in l + [n[1]]:
+                if self.changelog.nodemap.has_key(i):
+                    if f == 1:
+                        fetch.append(p)
+                    else:
+                        search.append((p, i))
+                p, f = i, f * 2
+
+        return remote.changegroup(fetch)
+    
+    def changegroup(self, basenodes):
+        nodes = self.newer(basenodes)
+
         # construct the link map
         linkmap = {}
         for n in nodes:
@@ -597,10 +680,9 @@
             l = struct.pack(">l", len(f))
             cg += [l, f, g]
 
-        return compress("".join(cg))
+        return "".join(cg)
 
     def addchangegroup(self, data):
-        data = decompress(data)
         def getlen(data, pos):
             return struct.unpack(">l", data[pos:pos + 4])[0]