# HG changeset patch # User mpm@selenic.com # Date 1117469034 28800 # Node ID 5d8553352d2ee495b48e76cc9285173ac7e5ecaf # Parent d7e859cf2f1b29ca22acc0d97df63b161ef17f24 Changes to network protocol -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Changes to network protocol Stream changes at the delta level rather than at whole delta groups this breaks the protocol - we now send a zero byte delta to indicate the end of a group rather than sending the entire group length up front Fix filename length asymmetry while we're breaking things Fix hidden O(n^2) bug in calculating changegroup list.append(e) is O(n), list + [element] is not Decompress chunks on read in revlog.group() Improve status messages report bytes transferred report nothing to do Deal with /dev/null path brokenness Remove untriggered patch assertion manifest hash: 3eedcfe878561f9eb4adedb04f6be618fb8ae8d8 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.0 (GNU/Linux) iD8DBQFCmzlqywK+sNU5EO8RAn0KAJ4z4toWSSGjLoZO6FKWLx/3QbZufACglQgd S48bumc++DnuY1iPSNWKGAI= =lCjx -----END PGP SIGNATURE----- diff -r d7e859cf2f1b -r 5d8553352d2e hg --- a/hg Sun May 29 09:24:51 2005 -0800 +++ b/hg Mon May 30 08:03:54 2005 -0800 @@ -417,7 +417,6 @@ if args[0] in paths: args[0] = paths[args[0]] other = hg.repository(ui, args[0]) - ui.status("requesting changegroup\n") cg = repo.getchangegroup(other) repo.addchangegroup(cg) else: diff -r d7e859cf2f1b -r 5d8553352d2e mercurial/hg.py --- a/mercurial/hg.py Sun May 29 09:24:51 2005 -0800 +++ b/mercurial/hg.py Mon May 30 08:03:54 2005 -0800 @@ -291,6 +291,7 @@ return os.path.join(self.path, f) def file(self, f): + if f[0] == '/': f = f[1:] return filelog(self.opener, f) def transaction(self): @@ -530,6 +531,8 @@ fetch = [] seen = {} seenbranch = {} + + self.ui.status("searching for changes\n") tip = remote.branches([])[0] self.ui.debug("remote tip branch is %s:%s\n" % (short(tip[0]), short(tip[1]))) @@ -542,7 +545,7 @@ unknown = [tip] if tip[0] in m: - self.ui.note("nothing to do!\n") + self.ui.status("nothing to do!\n") return None while unknown: @@ -627,14 +630,13 @@ # the changegroup is changesets + manifests + all file revs revs = [ self.changelog.rev(n) for n in nodes ] - yield self.changelog.group(linkmap) - yield self.manifest.group(linkmap) - + for y in self.changelog.group(linkmap): yield y + for y in self.manifest.group(linkmap): yield y for f in changed: + yield struct.pack(">l", len(f) + 4) + f g = self.file(f).group(linkmap) - if not g: raise "couldn't find change to %s" % f - l = struct.pack(">l", len(f)) - yield "".join([l, f, g]) + for y in g: + yield y def addchangegroup(self, generator): changesets = files = revisions = 0 @@ -656,11 +658,18 @@ if not generator: return source = genread(generator) - def getchunk(add = 0): + def getchunk(): d = source.read(4) if not d: return "" l = struct.unpack(">l", d)[0] - return source.read(l - 4 + add) + if l <= 4: return "" + return source.read(l - 4) + + def getgroup(): + while 1: + c = getchunk() + if not c: break + yield c tr = self.transaction() simple = True @@ -671,21 +680,17 @@ def report(x): self.ui.debug("add changeset %s\n" % short(x)) return self.changelog.count() - - csg = getchunk() + co = self.changelog.tip() - cn = self.changelog.addgroup(csg, report, tr) + cn = self.changelog.addgroup(getgroup(), report, tr) - revisions = self.changelog.rev(cn) - self.changelog.rev(co) - changesets = revisions + changesets = self.changelog.rev(cn) - self.changelog.rev(co) self.ui.status("adding manifests\n") # pull off the manifest group - mfg = getchunk() mm = self.manifest.tip() - mo = self.manifest.addgroup(mfg, lambda x: self.changelog.rev(x), tr) - - revisions += self.manifest.rev(mo) - self.manifest.rev(mm) + mo = self.manifest.addgroup(getgroup(), + lambda x: self.changelog.rev(x), tr) # do we need a resolve? if self.changelog.ancestor(co, cn) != co: @@ -749,13 +754,12 @@ # process the files self.ui.status("adding files\n") while 1: - f = getchunk(4) + f = getchunk() if not f: break - fg = getchunk() self.ui.debug("adding %s revisions\n" % f) fl = self.file(f) o = fl.tip() - n = fl.addgroup(fg, lambda x: self.changelog.rev(x), tr) + n = fl.addgroup(getgroup(), lambda x: self.changelog.rev(x), tr) revisions += fl.rev(n) - fl.rev(o) files += 1 if f in need: @@ -774,9 +778,9 @@ # For simple merges, we don't need to resolve manifests or changesets if simple: self.ui.debug("simple merge, skipping resolve\n") - self.ui.status(("added %d changesets, %d files," + + self.ui.status(("modified %d files, added %d changesets" + " and %d new revisions\n") - % (changesets, files, revisions)) + % (files, changesets, revisions)) tr.close() return @@ -865,12 +869,15 @@ n = " ".join(map(hex, nodes)) zd = zlib.decompressobj() f = self.do_cmd("changegroup", roots=n) + bytes = 0 while 1: d = f.read(4096) + bytes += len(d) if not d: yield zd.flush() break yield zd.decompress(d) + self.ui.note("%d bytes of data transfered\n" % bytes) def repository(ui, path=None, create=0): if path and path[:7] == "http://": diff -r d7e859cf2f1b -r 5d8553352d2e mercurial/revlog.py --- a/mercurial/revlog.py Sun May 29 09:24:51 2005 -0800 +++ b/mercurial/revlog.py Mon May 30 08:03:54 2005 -0800 @@ -244,8 +244,6 @@ end = self.end(t) prev = self.revision(self.tip()) d = self.diff(prev, text) - if self.patches(prev, [d]) != text: - raise AssertionError("diff failed") data = compress(d) dist = end - start + len(data) @@ -330,7 +328,9 @@ needed[i] = 1 # if we don't have any revisions touched by these changesets, bail - if not revs: return struct.pack(">l", 0) + if not revs: + yield struct.pack(">l", 0) + return # add the parent of the first rev p = self.parents(self.node(revs[0]))[0] @@ -352,25 +352,25 @@ needed = needed.keys() needed.sort() spans = [] + oo = -1 + ol = 0 for n in needed: if n < 0: continue o = self.start(n) l = self.length(n) - spans.append((o, l, [(n, l)])) - - # merge spans - merge = [spans.pop(0)] - while spans: - e = spans.pop(0) - f = merge[-1] - if e[0] == f[0] + f[1]: - merge[-1] = (f[0], f[1] + e[1], f[2] + e[2]) + if oo + ol == o: # can we merge with the previous? + nl = spans[-1][2] + nl.append((n, l)) + ol += l + spans[-1] = (oo, ol, nl) else: - merge.append(e) + oo = o + ol = l + spans.append((oo, ol, [(n, l)])) # read spans in, divide up chunks chunks = {} - for span in merge: + for span in spans: # we reopen the file for each span to make http happy for now f = self.opener(self.datafile) f.seek(span[0]) @@ -379,12 +379,12 @@ # divide up the span pos = 0 for r, l in span[2]: - chunks[r] = data[pos: pos + l] + chunks[r] = decompress(data[pos: pos + l]) pos += l # helper to reconstruct intermediate versions def construct(text, base, rev): - bins = [decompress(chunks[r]) for r in xrange(base + 1, rev + 1)] + bins = [chunks[r] for r in xrange(base + 1, rev + 1)] return mdiff.patches(text, bins) # build deltas @@ -392,11 +392,12 @@ for d in xrange(0, len(revs) - 1): a, b = revs[d], revs[d + 1] n = self.node(b) - + + # do we need to construct a new delta? if a + 1 != b or self.base(b) == b: if a >= 0: base = self.base(a) - ta = decompress(chunks[self.base(a)]) + ta = chunks[self.base(a)] ta = construct(ta, base, a) else: ta = "" @@ -406,36 +407,30 @@ base = a tb = ta else: - tb = decompress(chunks[self.base(b)]) + tb = chunks[self.base(b)] tb = construct(tb, base, b) d = self.diff(ta, tb) else: - d = decompress(chunks[b]) + d = chunks[b] p = self.parents(n) meta = n + p[0] + p[1] + linkmap[self.linkrev(n)] l = struct.pack(">l", len(meta) + len(d) + 4) - deltas.append(l + meta + d) + yield l + yield meta + yield d - l = struct.pack(">l", sum(map(len, deltas)) + 4) - deltas.insert(0, l) - return "".join(deltas) - - def addgroup(self, data, linkmapper, transaction): + yield struct.pack(">l", 0) + + def addgroup(self, revs, linkmapper, transaction): # given a set of deltas, add them to the revision log. the # first delta is against its parent, which should be in our # log, the rest are against the previous delta. - if not data: return self.tip() - - # retrieve the parent revision of the delta chain - chain = data[24:44] - if not chain in self.nodemap: - raise "unknown base %s" % short(chain[:4]) - # track the base of the current delta log r = self.count() t = r - 1 + node = nullid base = prev = -1 start = end = 0 @@ -452,15 +447,19 @@ ifh = self.opener(self.indexfile, "a") # loop through our set of deltas - pos = 0 - while pos < len(data): - l, node, p1, p2, cs = struct.unpack(">l20s20s20s20s", - data[pos:pos+84]) + chain = None + for chunk in revs: + node, p1, p2, cs = struct.unpack("20s20s20s20s", chunk[:80]) link = linkmapper(cs) if node in self.nodemap: raise "already have %s" % hex(node[:4]) - delta = data[pos + 84:pos + l] - pos += l + delta = chunk[80:] + + if not chain: + # retrieve the parent revision of the delta chain + chain = p1 + if not chain in self.nodemap: + raise "unknown base %s" % short(chain[:4]) # full versions are inserted when the needed deltas become # comparable to the uncompressed text or when the previous