示例#1
0
    def buildPackIndex(self):
        pos = 4
        # We make the initial assumption that the database has been
        # packed before and set unpacked to True only after seeing the
        # first record with a status == " ".  If we get to the packtime
        # and unpacked is still False, we need to watch for a redundant
        # pack.
        unpacked = False
        while pos < self.eof:
            th = self._read_txn_header(pos)
            if th.tid > self.packtime:
                break
            self.checkTxn(th, pos)
            if th.status != "p":
                unpacked = True

            tpos = pos
            end = pos + th.tlen
            pos += th.headerlen()

            while pos < end:
                dh = self._read_data_header(pos)
                self.checkData(th, tpos, dh, pos)
                if dh.plen or dh.back:
                    self.oid2curpos[dh.oid] = pos
                else:
                    if dh.oid in self.oid2curpos:
                        del self.oid2curpos[dh.oid]
                pos += dh.recordlen()

            tlen = self._read_num(pos)
            if tlen != th.tlen:
                self.fail(
                    pos, "redundant transaction length does not "
                    "match initial transaction length: %d != %d", tlen,
                    th.tlen)
            pos += 8

        self.packpos = pos

        if unpacked:
            return
        # check for a redundant pack.  If the first record following
        # the newly computed packpos has status 'p', then it was
        # packed earlier and the current pack is redudant.
        try:
            th = self._read_txn_header(pos)
        except CorruptedDataError as err:
            if err.buf != b"":
                raise
        if th.status == 'p':
            # Delayed import to cope with circular imports.
            # TODO:  put exceptions in a separate module.
            from ZODB.FileStorage.FileStorage import RedundantPackWarning
            raise RedundantPackWarning(
                "The database has already been packed to a later time"
                " or no changes have been made since the last pack")
示例#2
0
class GC(FileStorageFormatter):
    def __init__(self, file, eof, packtime, gc, referencesf):
        self._file = file
        self._name = file.name
        self.eof = eof
        self.packtime = packtime
        self.gc = gc
        # packpos: position of first txn header after pack time
        self.packpos = None

        # {oid -> current data record position}:
        self.oid2curpos = ZODB.fsIndex.fsIndex()

        # The set of reachable revisions of each object.
        #
        # This set as managed using two data structures.  The first is
        # an fsIndex mapping oids to one data record pos.  Since only
        # a few objects will have more than one revision, we use this
        # efficient data structure to handle the common case.  The
        # second is a dictionary mapping objects to lists of
        # positions; it is used to handle the same number of objects
        # for which we must keep multiple revisions.
        self.reachable = ZODB.fsIndex.fsIndex()
        self.reach_ex = {}

        # keep ltid for consistency checks during initial scan
        self.ltid = z64

        self.referencesf = referencesf

    def isReachable(self, oid, pos):
        """Return 1 if revision of `oid` at `pos` is reachable."""

        rpos = self.reachable.get(oid)
        if rpos is None:
            return 0
        if rpos == pos:
            return 1
        return pos in self.reach_ex.get(oid, [])

    def findReachable(self):
        self.buildPackIndex()
        if self.gc:
            self.findReachableAtPacktime([z64])
            self.findReachableFromFuture()
            # These mappings are no longer needed and may consume a lot of
            # space.
            del self.oid2curpos
        else:
            self.reachable = self.oid2curpos

    def buildPackIndex(self):
        pos = 4L
        # We make the initial assumption that the database has been
        # packed before and set unpacked to True only after seeing the
        # first record with a status == " ".  If we get to the packtime
        # and unpacked is still False, we need to watch for a redundant
        # pack.
        unpacked = False
        while pos < self.eof:
            th = self._read_txn_header(pos)
            if th.tid > self.packtime:
                break
            self.checkTxn(th, pos)
            if th.status != "p":
                unpacked = True

            tpos = pos
            end = pos + th.tlen
            pos += th.headerlen()

            while pos < end:
                dh = self._read_data_header(pos)
                self.checkData(th, tpos, dh, pos)
                if dh.plen or dh.back:
                    self.oid2curpos[dh.oid] = pos
                else:
                    if dh.oid in self.oid2curpos:
                        del self.oid2curpos[dh.oid]
                pos += dh.recordlen()

            tlen = self._read_num(pos)
            if tlen != th.tlen:
                self.fail(
                    pos, "redundant transaction length does not "
                    "match initial transaction length: %d != %d", tlen,
                    th.tlen)
            pos += 8

        self.packpos = pos

        if unpacked:
            return
        # check for a redundant pack.  If the first record following
        # the newly computed packpos has status 'p', then it was
        # packed earlier and the current pack is redudant.
        try:
            th = self._read_txn_header(pos)
        except CorruptedDataError, err:
            if err.buf != "":
                raise
        if th.status == 'p':
            # Delayed import to cope with circular imports.
            # TODO:  put exceptions in a separate module.
            from ZODB.FileStorage.FileStorage import RedundantPackWarning
            raise RedundantPackWarning(
                "The database has already been packed to a later time"
                " or no changes have been made since the last pack")