Example #1
0
    def add(self, map, transaction, link, p1, p2, added, removed):
        if p1 in self._mancache:
            # If our first parent is in the manifest cache, we can
            # compute a delta here using properties we know about the
            # manifest up-front, which may save time later for the
            # revlog layer.

            _checkforbidden(added)
            # combine the changed lists into one list for sorting
            work = [(x, False) for x in added]
            work.extend((x, True) for x in removed)
            # this could use heapq.merge() (from Python 2.6+) or equivalent
            # since the lists are already sorted
            work.sort()

            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
            # just encode a fulltext of the manifest and pass that
            # through to the revlog layer, and let it handle the delta
            # process.
            text = map.text()
            arraytext = array.array('c', text)
            cachedelta = None

        n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
        self._mancache[n] = (map, arraytext)

        return n
Example #2
0
    def add(self, m, transaction, link, p1, p2, added, removed):
        if (p1 in self._mancache and not self._treeinmem
                and not self._usemanifestv2):
            # If our first parent is in the manifest cache, we can
            # compute a delta here using properties we know about the
            # manifest up-front, which may save time later for the
            # revlog layer.

            _checkforbidden(added)
            # combine the changed lists into one sorted iterator
            work = heapq.merge([(x, False) for x in added],
                               [(x, True) for x in removed])

            arraytext, deltatext = m.fastdelta(self._mancache[p1][1], work)
            cachedelta = self.rev(p1), deltatext
            text = util.buffer(arraytext)
            n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
        else:
            # The first parent manifest isn't already loaded, so we'll
            # just encode a fulltext of the manifest and pass that
            # through to the revlog layer, and let it handle the delta
            # process.
            if self._treeondisk:
                m1 = self.read(p1)
                m2 = self.read(p2)
                n = self._addtree(m, transaction, link, m1, m2)
                arraytext = None
            else:
                text = m.text(self._usemanifestv2)
                n = self.addrevision(text, transaction, link, p1, p2)
                arraytext = array.array('c', text)

        self._mancache[n] = (m, arraytext)

        return n
Example #3
0
    def _getchunk(self, offset, length):
        o, d = self._chunkcache
        l = len(d)

        # is it in the cache?
        cachestart = offset - o
        cacheend = cachestart + length
        if cachestart >= 0 and cacheend <= l:
            if cachestart == 0 and cacheend == l:
                return d  # avoid a copy
            return util.buffer(d, cachestart, cacheend - cachestart)

        return self._loadchunk(offset, length)
Example #4
0
    def _getchunk(self, offset, length):
        o, d = self._chunkcache
        l = len(d)

        # is it in the cache?
        cachestart = offset - o
        cacheend = cachestart + length
        if cachestart >= 0 and cacheend <= l:
            if cachestart == 0 and cacheend == l:
                return d # avoid a copy
            return util.buffer(d, cachestart, cacheend - cachestart)

        return self._loadchunk(offset, length)
Example #5
0
    def _loadchunk(self, offset, length):
        if self._inline:
            df = self.opener(self.indexfile)
        else:
            df = self.opener(self.datafile)

        readahead = max(65536, length)
        df.seek(offset)
        d = df.read(readahead)
        df.close()
        self._addchunk(offset, d)
        if readahead > length:
            return util.buffer(d, 0, length)
        return d
Example #6
0
    def _loadchunk(self, offset, length):
        if self._inline:
            df = self.opener(self.indexfile)
        else:
            df = self.opener(self.datafile)

        readahead = max(65536, length)
        df.seek(offset)
        d = df.read(readahead)
        df.close()
        self._addchunk(offset, d)
        if readahead > length:
            return util.buffer(d, 0, length)
        return d
Example #7
0
    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:
                h, fl = self._lm[f]
                l = "%s\0%s%s\n" % (f, revlog.hex(h), fl)
            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
Example #8
0
    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:
                h, fl = self._lm[f]
                l = "%s\0%s%s\n" % (f, revlog.hex(h), fl)
            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
Example #9
0
    def _loadchunk(self, offset, length):
        if self._inline:
            df = self.opener(self.indexfile)
        else:
            df = self.opener(self.datafile)

        # Cache data both forward and backward around the requested
        # data, in a fixed size window. This helps speed up operations
        # involving reading the revlog backwards.
        cachesize = self._chunkcachesize
        realoffset = offset & ~(cachesize - 1)
        reallength = (((offset + length + cachesize) & ~(cachesize - 1)) -
                      realoffset)
        df.seek(realoffset)
        d = df.read(reallength)
        df.close()
        self._addchunk(realoffset, d)
        if offset != realoffset or reallength != length:
            return util.buffer(d, offset - realoffset, length)
        return d
Example #10
0
    def _loadchunk(self, offset, length):
        if self._inline:
            df = self.opener(self.indexfile)
        else:
            df = self.opener(self.datafile)

        # Cache data both forward and backward around the requested
        # data, in a fixed size window. This helps speed up operations
        # involving reading the revlog backwards.
        cachesize = self._chunkcachesize
        realoffset = offset & ~(cachesize - 1)
        reallength = (((offset + length + cachesize) & ~(cachesize - 1))
                      - realoffset)
        df.seek(realoffset)
        d = df.read(reallength)
        df.close()
        self._addchunk(realoffset, d)
        if offset != realoffset or reallength != length:
            return util.buffer(d, offset - realoffset, length)
        return d
    def add(self, map, transaction, link, p1=None, p2=None, changed=None):
        # apply the changes collected during the bisect loop to our addlist
        # return a delta suitable for addrevision
        def addlistdelta(addlist, x):
            # start from the bottom up
            # so changes to the offsets don't mess things up.
            for start, end, content in reversed(x):
                if content:
                    addlist[start:end] = array.array('c', content)
                else:
                    del addlist[start:end]
            return "".join(
                struct.pack(">lll", start, end, len(content)) + content
                for start, end, content in x)

        def checkforbidden(l):
            for f in l:
                if '\n' in f or '\r' in f:
                    raise error.RevlogError(
                        _("'\\n' and '\\r' disallowed in filenames: %r") % f)

        # if we're using the cache, make sure it is valid and
        # parented by the same node we're diffing against
        if not (changed and self._mancache and p1 and self._mancache[0] == p1):
            files = sorted(map)
            checkforbidden(files)

            # if this is changed to support newlines in filenames,
            # be sure to check the templates/ dir again (especially *-raw.tmpl)
            hex, flags = revlog.hex, map.flags
            text = ''.join("%s\0%s%s\n" % (f, hex(map[f]), flags(f))
                           for f in files)
            arraytext = array.array('c', text)
            cachedelta = None
        else:
            added, removed = changed
            addlist = self._mancache[2]

            checkforbidden(added)
            # combine the changed lists into one list for sorting
            work = [(x, False) for x in added]
            work.extend((x, True) for x in removed)
            # this could use heapq.merge() (from python2.6+) or equivalent
            # 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 = self._search(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
            cachedelta = (self.rev(p1), addlistdelta(addlist, delta))
            arraytext = addlist
            text = util.buffer(arraytext)

        n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
        self._mancache = (n, map, arraytext)

        return n
Example #12
0
def patch(a, bin):
    if len(a) == 0:
        # skip over trivial delta header
        return util.buffer(bin, 12)
    return mpatch.patches(a, [bin])
Example #13
0
    def add(self, map, transaction, link, p1=None, p2=None,
            changed=None):
        # apply the changes collected during the bisect loop to our addlist
        # return a delta suitable for addrevision
        def addlistdelta(addlist, x):
            # start from the bottom up
            # so changes to the offsets don't mess things up.
            for start, end, content in reversed(x):
                if content:
                    addlist[start:end] = array.array('c', content)
                else:
                    del addlist[start:end]
            return "".join(struct.pack(">lll", start, end, len(content)) + content
                           for start, end, content in x)

        def checkforbidden(l):
            for f in l:
                if '\n' in f or '\r' in f:
                    raise error.RevlogError(
                        _("'\\n' and '\\r' disallowed in filenames: %r") % f)

        # if we're using the cache, make sure it is valid and
        # parented by the same node we're diffing against
        if not (changed and self._mancache and p1 and self._mancache[0] == p1):
            files = sorted(map)
            checkforbidden(files)

            # if this is changed to support newlines in filenames,
            # be sure to check the templates/ dir again (especially *-raw.tmpl)
            hex, flags = revlog.hex, map.flags
            text = ''.join("%s\0%s%s\n" % (f, hex(map[f]), flags(f))
                           for f in files)
            arraytext = array.array('c', text)
            cachedelta = None
        else:
            added, removed = changed
            addlist = self._mancache[2]

            checkforbidden(added)
            # combine the changed lists into one list for sorting
            work = [(x, False) for x in added]
            work.extend((x, True) for x in removed)
            # this could use heapq.merge() (from python2.6+) or equivalent
            # 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 = self._search(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
            cachedelta = (self.rev(p1), addlistdelta(addlist, delta))
            arraytext = addlist
            text = util.buffer(arraytext)

        n = self.addrevision(text, transaction, link, p1, p2, cachedelta)
        self._mancache = (n, map, arraytext)

        return n