[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