[Zodb-checkins] CVS: ZODB4/Transaction - Manager.py:1.1 Transaction.py:1.1 __init__.py:1.1 interfaces.py:1.1

Jim Fulton jim@zope.com
Wed, 25 Dec 2002 09:37:37 -0500


Update of /cvs-repository/ZODB4/Transaction
In directory cvs.zope.org:/tmp/cvs-serv27110/Transaction

Added Files:
	Manager.py Transaction.py __init__.py interfaces.py 
Log Message:
Copied Transaction package from Zope 3 tree.

We're going to delete these files from the Zope 3 tree because they
have been renamed.



=== Added File ZODB4/Transaction/Manager.py ===
import logging

from interfaces import IRollback
from Transaction import Transaction, Status

# XXX need to change asserts of transaction status into explicit checks
# that raise some exception

# XXX need lots of error checking

class TransactionManager(object):

    txn_factory = Transaction

    def __init__(self):
        self.logger = logging.getLogger("txn")

    def new(self):
        txn = self.txn_factory(self)
        self.logger.debug("%s: begin", txn)
        return txn

    def commit(self, txn):
        assert txn._status is Status.ACTIVE
        txn._status = Status.PREPARING
        prepare_ok = True
        self.logger.debug("%s: prepare", txn)
        try:
            for r in txn._resources:
                if prepare_ok and not r.prepare(txn):
                    prepare_ok = False
        except:
            txn._status = Status.FAILED
            raise
        txn._status = Status.PREPARED
        # XXX An error below is intolerable.  What state to use?
        if prepare_ok:
            self._commit(txn)
        else:
            self.abort(txn)

    def _commit(self, txn):
        self.logger.debug("%s: commit", txn)
        # finish the two-phase commit
        for r in txn._resources:
            r.commit(txn)
        txn._status = Status.COMMITTED

    def abort(self, txn):
        self.logger.debug("%s: abort", txn)
        assert txn._status in (Status.ACTIVE, Status.PREPARED, Status.FAILED)
        txn._status = Status.PREPARING
        for r in txn._resources:
            r.abort(txn)
        txn._status = Status.ABORTED

    def savepoint(self, txn):
        self.logger.debug("%s: savepoint", txn)
        return Rollback([r.savepoint(txn) for r in txn._resources])

class Rollback(object):

    __implements__ = IRollback

    def __init__(self, resources):
        self._resources = resources

    def rollback(self):
        for r in self._resources:
            r.rollback()

# make the transaction manager visible to client code
import thread

class ThreadedTransactionManager(TransactionManager):

    def __init__(self):
        TransactionManager.__init__(self)
        self._pool = {}

    def new(self):
        tid = thread.get_ident()
        txn = self._pool.get(tid)
        if txn is None:
            txn = super(ThreadedTransactionManager, self).new()
            self._pool[tid] = txn
        return txn

    def _commit(self, txn):
        tid = thread.get_ident()
        assert self._pool[tid] is txn
        super(ThreadedTransactionManager, self)._commit(txn)
        del self._pool[tid]

    def abort(self, txn):
        tid = thread.get_ident()
        assert self._pool[tid] is txn
        super(ThreadedTransactionManager, self).abort(txn)
        del self._pool[tid]


=== Added File ZODB4/Transaction/Transaction.py ===
# XXX The fact that this module has the same name as the package makes
# explicit imports impossible elsewhere.  Pick a new name?

__metaclass__ = type

from interfaces import ITransaction, TransactionError

class Set(dict):

    def add(self, k):
        self[k] = 1

class Status:

    ACTIVE = "Active"
    PREPARING = "Preparing"
    PREPARED = "Prepared"
    FAILED = "Failed"
    COMMITTED = "Committed"
    ABORTING = "Aborting"
    ABORTED = "Aborted"

class Transaction:

    __implements__ = ITransaction

    def __init__(self, manager=None, parent=None):
        self._manager = manager
        self._parent = parent
        self._status = Status.ACTIVE
        self._resources = Set()

    def __repr__(self):
        return "<%s %X %s>" % (self.__class__.__name__, id(self), self._status)

    def begin(self, parent=None):
        """Begin a transaction.

        If parent is not None, it is the parent transaction for this one.
        """
        assert self._manager is not None
        if parent is not None:
            t = Transaction(self._manager, self)
            return t

    def commit(self):
        """Commit a transaction."""
        assert self._manager is not None
        self._manager.commit(self)

    def abort(self):
        """Rollback to initial state."""
        assert self._manager is not None
        self._manager.abort(self)

    def savepoint(self):
        """Save current progress and return a savepoint."""
        assert self._manager is not None
        return self._manager.savepoint(self)

    def join(self, resource):
        """resource is participating in the transaction."""
        assert self._manager is not None
        if self._status != Status.ACTIVE:
            raise TransactionError("Can't join transaction. Status=%s" %
                                   self._status)
        self._resources.add(resource)

    def status(self):
        """Return the status of the transaction."""
        return self._status


=== Added File ZODB4/Transaction/__init__.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################

from Manager import ThreadedTransactionManager

_manager = ThreadedTransactionManager()
get_transaction = _manager.new

def set_factory(factory):
    _manager.txn_factory = factory


=== Added File ZODB4/Transaction/interfaces.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
from Interface import Interface

class TransactionError(StandardError):
    """An error occured due to normal transaction processing."""

class ConflictError(TransactionError):
    """Two transactions tried to modify the same object at once

    This transaction should be resubmitted.
    """

class RollbackError(TransactionError):
    """An error occurred rolling back a savepoint."""

class IDataManager(Interface):
    """Data management interface for storing objects transactionally

    This is currently implemented by ZODB database connections.
    """

    def prepare(transaction):
        """Begin two-phase commit of a transaction.

        DataManager should return True or False.
        """
        
    def abort(transaction):
        """Abort changes made by transaction."""
    
    def commit(transaction):
        """Commit changes made by transaction."""

    def savepoint(transaction):
        """Do tentative commit of changes to this point.

        Should return an object implementing IRollback
        """
        
class IRollback(Interface):
    
    def rollback():
        """Rollback changes since savepoint."""

class ITransaction(Interface):
    """Transaction objects

    Application code typically gets these by calling
    get_transaction().
    """

    def abort():
        """Abort the current transaction."""

    def begin():
        """Begin a transaction."""

    def commit():
        """Commit a transaction."""

    def join(resource):
        """Join a resource manager to the current transaction."""

    def status():
        """Return status of the current transaction."""