Example #1
0
    def testBadTransaction(self):
        # Find transaction headers and blast them.

        L = self.storage.undoLog()
        r = L[3]
        tid = decodebytes(r["id"] + b"\n")
        pos1 = self.storage._txn_find(tid, 0)

        r = L[8]
        tid = decodebytes(r["id"] + b"\n")
        pos2 = self.storage._txn_find(tid, 0)

        self.storage.close()

        # Overwrite the entire header.
        with open(self.path, "a+b") as f:
            f.seek(pos1 - 50)
            f.write(b"\0" * 100)
        output = self.recover()
        self.assertTrue('error' in output, output)
        self.recovered = FileStorage(self.dest)
        self.recovered.close()
        os.remove(self.path)
        os.rename(self.dest, self.path)

        # Overwrite part of the header.
        with open(self.path, "a+b") as f:
            f.seek(pos2 + 10)
            f.write(b"\0" * 100)
        output = self.recover()
        self.assertTrue('error' in output, output)
        self.recovered = FileStorage(self.dest)
        self.recovered.close()
Example #2
0
    def testBadTransaction(self):
        # Find transaction headers and blast them.

        L = self.storage.undoLog()
        r = L[3]
        tid = decodebytes(r["id"] + b"\n")
        pos1 = self.storage._txn_find(tid, 0)

        r = L[8]
        tid = decodebytes(r["id"] + b"\n")
        pos2 = self.storage._txn_find(tid, 0)

        self.storage.close()

        # Overwrite the entire header.
        with open(self.path, "a+b") as f:
            f.seek(pos1 - 50)
            f.write(b"\0" * 100)
        output = self.recover()
        self.assertTrue('error' in output, output)
        self.recovered = FileStorage(self.dest)
        self.recovered.close()
        os.remove(self.path)
        os.rename(self.dest, self.path)

        # Overwrite part of the header.
        with open(self.path, "a+b") as f:
            f.seek(pos2 + 10)
            f.write(b"\0" * 100)
        output = self.recover()
        self.assertTrue('error' in output, output)
        self.recovered = FileStorage(self.dest)
        self.recovered.close()
Example #3
0
    def testUncommittedAtEnd(self):
        # Find a transaction near the end.
        L = self.storage.undoLog()
        r = L[1]
        tid = decodebytes(r["id"] + b"\n")
        pos = self.storage._txn_find(tid, 0)

        # Overwrite its status with 'c'.
        with open(self.path, "r+b") as f:
            f.seek(pos + 16)
            current_status = f.read(1)
            self.assertEqual(current_status, b' ')
            f.seek(pos + 16)
            f.write(b'c')

        # Try to recover.  The original bug was that this never completed --
        # infinite loop in fsrecover.py.  Also, in the ZODB 3.2 line,
        # reference to an undefined global masked the infinite loop.
        self.recover()

        # Verify the destination got truncated.
        self.assertEqual(os.path.getsize(self.dest), pos)

        # Get rid of the temp file holding the truncated bytes.
        os.remove(ZODB.fsrecover._trname)
Example #4
0
    def testUncommittedAtEnd(self):
        # Find a transaction near the end.
        L = self.storage.undoLog()
        r = L[1]
        tid = decodebytes(r["id"] + b"\n")
        pos = self.storage._txn_find(tid, 0)

        # Overwrite its status with 'c'.
        with open(self.path, "r+b") as f:
            f.seek(pos + 16)
            current_status = f.read(1)
            self.assertEqual(current_status, b' ')
            f.seek(pos + 16)
            f.write(b'c')

        # Try to recover.  The original bug was that this never completed --
        # infinite loop in fsrecover.py.  Also, in the ZODB 3.2 line,
        # reference to an undefined global masked the infinite loop.
        self.recover()

        # Verify the destination got truncated.
        self.assertEqual(os.path.getsize(self.dest), pos)

        # Get rid of the temp file holding the truncated bytes.
        os.remove(ZODB.fsrecover._trname)
Example #5
0
    def undo(self, serial_id, transaction):
        undo_serial, keys = self.__storage.undo(serial_id, transaction)
        # serial_id is the transaction id of the txn that we wish to undo.
        # "undo_serial" is the transaction id of txn in which the undo is
        # performed.  "keys" is the list of oids that are involved in the
        # undo transaction.

        # The serial_id is assumed to be given to us base-64 encoded
        # (belying the web UI legacy of the ZODB code :-()
        serial_id = decodebytes(serial_id + b'\n')

        self._lock_acquire()

        try:
            # we get all the blob oids on the filesystem related to the
            # transaction we want to undo.
            for oid in self.fshelper.getOIDsForSerial(serial_id):
                # we want to find the serial id of the previous revision
                # of this blob object.
                load_result = self.loadBefore(oid, serial_id)

                if load_result is None:

                    # There was no previous revision of this blob
                    # object.  The blob was created in the transaction
                    # represented by serial_id.  We copy the blob data
                    # to a new file that references the undo
                    # transaction in case a user wishes to undo this
                    # undo. It would be nice if we had some way to
                    # link to old blobs.
                    orig_fn = self.fshelper.getBlobFilename(oid, serial_id)
                    new_fn = self.fshelper.getBlobFilename(oid, undo_serial)
                else:
                    # A previous revision of this blob existed before the
                    # transaction implied by "serial_id".  We copy the blob
                    # data to a new file that references the undo transaction
                    # in case a user wishes to undo this undo.
                    data, serial_before, serial_after = load_result
                    orig_fn = self.fshelper.getBlobFilename(oid, serial_before)
                    new_fn = self.fshelper.getBlobFilename(oid, undo_serial)
                with open(orig_fn, "rb") as orig:
                    with open(new_fn, "wb") as new:
                        utils.cp(orig, new)
                self.dirty_oids.append((oid, undo_serial))

        finally:
            self._lock_release()
        return undo_serial, keys