############################################################################## # # Copyright (c) 2003 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. # ############################################################################## __metaclass__ = type from threading import Lock from transaction.interfaces import * from zope.interface import implements try: from sets import Set except ImportError: class Set(dict): def add(self, k): self[k] = 1 def remove(self, k): del self[k] class Status: ACTIVE = "Active" PREPARING = "Preparing" PREPARED = "Prepared" FAILED = "Failed" COMMITTED = "Committed" ABORTING = "Aborting" ABORTED = "Aborted" SUSPENDED = "Suspended" class Transaction: implements(ITransaction) def __init__(self, manager=None, parent=None): self._manager = manager self._parent = parent self._status = Status.ACTIVE self._suspend = None self._resources = Set() self._lock = Lock() 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 if self._status != Status.ACTIVE: raise IllegalStateError("commit", self._status) self._manager.commit(self) def abort(self): """Rollback to initial state.""" assert self._manager is not None if self._status == Status.ABORTED: return if self._status not in (Status.ACTIVE, Status.PREPARED, Status.FAILED): raise IllegalStateError("abort", self._status) self._manager.abort(self) def savepoint(self): """Save current progress and return a savepoint.""" assert self._manager is not None if self._status != Status.ACTIVE: raise IllegalStateError("create savepoint", self._status) 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 IllegalStateError("join", self._status) self._manager.logger.debug("%s join %s" % (self, resource)) self._resources.add(resource) def status(self): """Return the status of the transaction.""" return self._status def suspend(self): self._lock.acquire() try: if self._status == Status.SUSPENDED: raise IllegalStateError("suspend", self._status) self._manager.suspend(self) self._suspend = self._status self._status = Status.SUSPENDED finally: self._lock.release() def resume(self): self._lock.acquire() try: if self._status != Status.SUSPENDED: raise TransactionError("Can only resume suspended transaction") self._manager.resume(self) self._status = self._suspend self._suspend = None finally: self._lock.release()