Mercurial > hg
comparison mercurial/manifest.py @ 22931:48c0b101a9de
manifest: add fastdelta method to manifestdict
This is another step closer to alternate manifest implementations that
can offer different hashing algorithms.
author | Augie Fackler <raf@durin42.com> |
---|---|
date | Wed, 08 Oct 2014 15:20:14 -0400 |
parents | 1acb81d10eaf |
children | 03602f76deee |
comparison
equal
deleted
inserted
replaced
22930:1acb81d10eaf | 22931:48c0b101a9de |
---|---|
46 | 46 |
47 hex, flags = revlog.hex, self.flags | 47 hex, flags = revlog.hex, self.flags |
48 # if this is changed to support newlines in filenames, | 48 # if this is changed to support newlines in filenames, |
49 # be sure to check the templates/ dir again (especially *-raw.tmpl) | 49 # be sure to check the templates/ dir again (especially *-raw.tmpl) |
50 return ''.join("%s\0%s%s\n" % (f, hex(self[f]), flags(f)) for f in fl) | 50 return ''.join("%s\0%s%s\n" % (f, hex(self[f]), flags(f)) for f in fl) |
51 | |
52 def fastdelta(self, base, changes): | |
53 """Given a base manifest text as an array.array and a list of changes | |
54 relative to that text, compute a delta that can be used by revlog. | |
55 """ | |
56 delta = [] | |
57 dstart = None | |
58 dend = None | |
59 dline = [""] | |
60 start = 0 | |
61 # zero copy representation of base as a buffer | |
62 addbuf = util.buffer(base) | |
63 | |
64 # start with a readonly loop that finds the offset of | |
65 # each line and creates the deltas | |
66 for f, todelete in changes: | |
67 # bs will either be the index of the item or the insert point | |
68 start, end = _msearch(addbuf, f, start) | |
69 if not todelete: | |
70 l = "%s\0%s%s\n" % (f, revlog.hex(self[f]), self.flags(f)) | |
71 else: | |
72 if start == end: | |
73 # item we want to delete was not found, error out | |
74 raise AssertionError( | |
75 _("failed to remove %s from manifest") % f) | |
76 l = "" | |
77 if dstart is not None and dstart <= start and dend >= start: | |
78 if dend < end: | |
79 dend = end | |
80 if l: | |
81 dline.append(l) | |
82 else: | |
83 if dstart is not None: | |
84 delta.append([dstart, dend, "".join(dline)]) | |
85 dstart = start | |
86 dend = end | |
87 dline = [l] | |
88 | |
89 if dstart is not None: | |
90 delta.append([dstart, dend, "".join(dline)]) | |
91 # apply the delta to the base, and get a delta for addrevision | |
92 deltatext, arraytext = _addlistdelta(base, delta) | |
93 return arraytext, deltatext | |
51 | 94 |
52 def _msearch(m, s, lo=0, hi=None): | 95 def _msearch(m, s, lo=0, hi=None): |
53 '''return a tuple (start, end) that says where to find s within m. | 96 '''return a tuple (start, end) that says where to find s within m. |
54 | 97 |
55 If the string is found m[start:end] are the line containing | 98 If the string is found m[start:end] are the line containing |
171 if p1 in self._mancache: | 214 if p1 in self._mancache: |
172 # If our first parent is in the manifest cache, we can | 215 # If our first parent is in the manifest cache, we can |
173 # compute a delta here using properties we know about the | 216 # compute a delta here using properties we know about the |
174 # manifest up-front, which may save time later for the | 217 # manifest up-front, which may save time later for the |
175 # revlog layer. | 218 # revlog layer. |
176 addlist = self._mancache[p1][1] | |
177 | 219 |
178 _checkforbidden(added) | 220 _checkforbidden(added) |
179 # combine the changed lists into one list for sorting | 221 # combine the changed lists into one list for sorting |
180 work = [(x, False) for x in added] | 222 work = [(x, False) for x in added] |
181 work.extend((x, True) for x in removed) | 223 work.extend((x, True) for x in removed) |
182 # this could use heapq.merge() (from Python 2.6+) or equivalent | 224 # this could use heapq.merge() (from Python 2.6+) or equivalent |
183 # since the lists are already sorted | 225 # since the lists are already sorted |
184 work.sort() | 226 work.sort() |
185 | 227 |
186 delta = [] | 228 arraytext, deltatext = map.fastdelta(self._mancache[p1][1], work) |
187 dstart = None | 229 cachedelta = self.rev(p1), deltatext |
188 dend = None | |
189 dline = [""] | |
190 start = 0 | |
191 # zero copy representation of addlist as a buffer | |
192 addbuf = util.buffer(addlist) | |
193 | |
194 # start with a readonly loop that finds the offset of | |
195 # each line and creates the deltas | |
196 for f, todelete in work: | |
197 # bs will either be the index of the item or the insert point | |
198 start, end = _msearch(addbuf, f, start) | |
199 if not todelete: | |
200 l = "%s\0%s%s\n" % (f, revlog.hex(map[f]), map.flags(f)) | |
201 else: | |
202 if start == end: | |
203 # item we want to delete was not found, error out | |
204 raise AssertionError( | |
205 _("failed to remove %s from manifest") % f) | |
206 l = "" | |
207 if dstart is not None and dstart <= start and dend >= start: | |
208 if dend < end: | |
209 dend = end | |
210 if l: | |
211 dline.append(l) | |
212 else: | |
213 if dstart is not None: | |
214 delta.append([dstart, dend, "".join(dline)]) | |
215 dstart = start | |
216 dend = end | |
217 dline = [l] | |
218 | |
219 if dstart is not None: | |
220 delta.append([dstart, dend, "".join(dline)]) | |
221 # apply the delta to the addlist, and get a delta for addrevision | |
222 deltatext, addlist = _addlistdelta(addlist, delta) | |
223 cachedelta = (self.rev(p1), deltatext) | |
224 arraytext = addlist | |
225 text = util.buffer(arraytext) | 230 text = util.buffer(arraytext) |
226 else: | 231 else: |
227 # The first parent manifest isn't already loaded, so we'll | 232 # The first parent manifest isn't already loaded, so we'll |
228 # just encode a fulltext of the manifest and pass that | 233 # just encode a fulltext of the manifest and pass that |
229 # through to the revlog layer, and let it handle the delta | 234 # through to the revlog layer, and let it handle the delta |