mercurial/manifest.py
changeset 22931 48c0b101a9de
parent 22930 1acb81d10eaf
child 22942 03602f76deee
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