[Zope3-checkins] CVS: Zope3/src/transaction - __init__.py:1.2 interfaces.py:1.2 manager.py:1.2 txn.py:1.2
Jim Fulton
jim@zope.com
Wed, 25 Dec 2002 09:13:44 -0500
Update of /cvs-repository/Zope3/src/transaction
In directory cvs.zope.org:/tmp/cvs-serv15352/src/transaction
Added Files:
__init__.py interfaces.py manager.py txn.py
Log Message:
Grand renaming:
- Renamed most files (especially python modules) to lower case.
- Moved views and interfaces into separate hierarchies within each
project, where each top-level directory under the zope package
is a separate project.
- Moved everything to src from lib/python.
lib/python will eventually go away. I need access to the cvs
repository to make this happen, however.
There are probably some bits that are broken. All tests pass
and zope runs, but I haven't tried everything. There are a number
of cleanups I'll work on tomorrow.
=== Zope3/src/transaction/__init__.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:44 2002
+++ Zope3/src/transaction/__init__.py Wed Dec 25 09:12:14 2002
@@ -0,0 +1,21 @@
+##############################################################################
+#
+# 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 transaction.manager import ThreadedTransactionManager
+
+_manager = ThreadedTransactionManager()
+get_transaction = _manager.new
+
+def set_factory(factory):
+ _manager.txn_factory = factory
=== Zope3/src/transaction/interfaces.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:44 2002
+++ Zope3/src/transaction/interfaces.py Wed Dec 25 09:12:14 2002
@@ -0,0 +1,77 @@
+##############################################################################
+#
+# 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 zope.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."""
=== Zope3/src/transaction/manager.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:44 2002
+++ Zope3/src/transaction/manager.py Wed Dec 25 09:12:14 2002
@@ -0,0 +1,99 @@
+import logging
+
+from transaction.interfaces import IRollback
+from transaction.txn 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]
=== Zope3/src/transaction/txn.py 1.1 => 1.2 ===
--- /dev/null Wed Dec 25 09:13:44 2002
+++ Zope3/src/transaction/txn.py Wed Dec 25 09:12:14 2002
@@ -0,0 +1,71 @@
+# 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 transaction.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