# HG changeset patch # User Augie Fackler # Date 1412796014 14400 # Node ID 48c0b101a9de1fdbd638daa858da845cd05a6be7 # Parent 1acb81d10eaf811cbdbcf3006375352b4b877118 manifest: add fastdelta method to manifestdict This is another step closer to alternate manifest implementations that can offer different hashing algorithms. diff -r 1acb81d10eaf -r 48c0b101a9de mercurial/manifest.py --- a/mercurial/manifest.py Wed Oct 08 15:21:59 2014 -0400 +++ b/mercurial/manifest.py Wed Oct 08 15:20:14 2014 -0400 @@ -49,6 +49,49 @@ # be sure to check the templates/ dir again (especially *-raw.tmpl) return ''.join("%s\0%s%s\n" % (f, hex(self[f]), flags(f)) for f in fl) + def fastdelta(self, base, changes): + """Given a base manifest text as an array.array and a list of changes + relative to that text, compute a delta that can be used by revlog. + """ + delta = [] + dstart = None + dend = None + dline = [""] + start = 0 + # zero copy representation of base as a buffer + addbuf = util.buffer(base) + + # start with a readonly loop that finds the offset of + # each line and creates the deltas + for f, todelete in changes: + # bs will either be the index of the item or the insert point + start, end = _msearch(addbuf, f, start) + if not todelete: + l = "%s\0%s%s\n" % (f, revlog.hex(self[f]), self.flags(f)) + else: + if start == end: + # item we want to delete was not found, error out + raise AssertionError( + _("failed to remove %s from manifest") % f) + l = "" + if dstart is not None and dstart <= start and dend >= start: + if dend < end: + dend = end + if l: + dline.append(l) + else: + if dstart is not None: + delta.append([dstart, dend, "".join(dline)]) + dstart = start + dend = end + dline = [l] + + if dstart is not None: + delta.append([dstart, dend, "".join(dline)]) + # apply the delta to the base, and get a delta for addrevision + deltatext, arraytext = _addlistdelta(base, delta) + return arraytext, deltatext + def _msearch(m, s, lo=0, hi=None): '''return a tuple (start, end) that says where to find s within m. @@ -173,7 +216,6 @@ # compute a delta here using properties we know about the # manifest up-front, which may save time later for the # revlog layer. - addlist = self._mancache[p1][1] _checkforbidden(added) # combine the changed lists into one list for sorting @@ -183,45 +225,8 @@ # since the lists are already sorted work.sort() - delta = [] - dstart = None - dend = None - dline = [""] - start = 0 - # zero copy representation of addlist as a buffer - addbuf = util.buffer(addlist) - - # start with a readonly loop that finds the offset of - # each line and creates the deltas - for f, todelete in work: - # bs will either be the index of the item or the insert point - start, end = _msearch(addbuf, f, start) - if not todelete: - l = "%s\0%s%s\n" % (f, revlog.hex(map[f]), map.flags(f)) - else: - if start == end: - # item we want to delete was not found, error out - raise AssertionError( - _("failed to remove %s from manifest") % f) - l = "" - if dstart is not None and dstart <= start and dend >= start: - if dend < end: - dend = end - if l: - dline.append(l) - else: - if dstart is not None: - delta.append([dstart, dend, "".join(dline)]) - dstart = start - dend = end - dline = [l] - - if dstart is not None: - delta.append([dstart, dend, "".join(dline)]) - # apply the delta to the addlist, and get a delta for addrevision - deltatext, addlist = _addlistdelta(addlist, delta) - cachedelta = (self.rev(p1), deltatext) - arraytext = addlist + arraytext, deltatext = map.fastdelta(self._mancache[p1][1], work) + cachedelta = self.rev(p1), deltatext text = util.buffer(arraytext) else: # The first parent manifest isn't already loaded, so we'll