[Zodb-checkins] SVN: ZODB/trunk/src/ Mostly clarifications of the complicated state transactions

Tim Peters tim.one at comcast.net
Mon Jun 28 18:52:38 EDT 2004


Log message for revision 25994:
Mostly clarifications of the complicated state transactions
are in now (partly ZODB 3, partly ZODB 4, partly transitional).
More is needed.
Added new collaborations.txt, which spells out some dynamics
of the system in a compact way.  This is in a format Jim used
for Zope 3, essentially a flat-text and less-formal representation
of UML sequence diagrams.



-=-
Modified: ZODB/trunk/src/ZODB/Connection.py
===================================================================
--- ZODB/trunk/src/ZODB/Connection.py	2004-06-26 19:15:34 UTC (rev 25993)
+++ ZODB/trunk/src/ZODB/Connection.py	2004-06-28 22:52:38 UTC (rev 25994)
@@ -452,9 +452,10 @@
         self._cache = cache = PickleCache(self, cache_size)
 
     def abort(self, transaction):
-        """Abort the object in the transaction.
+        """Abort modifications to registered objects.
 
-        This just deactivates the thing.
+        This tells the cache to invalidate changed objects.  _p_jar
+        and _p_oid are deleted from new objects.
         """
 
         for obj in self._registered_objects:
@@ -632,6 +633,7 @@
                 self._cache[oid] = obj
             except:
                 # Dang, I bet it's wrapped:
+                # XXX Deprecate, then remove, this.
                 if hasattr(obj, 'aq_base'):
                     self._cache[oid] = obj.aq_base
                 else:

Added: ZODB/trunk/src/ZODB/collaborations.txt
===================================================================
--- ZODB/trunk/src/ZODB/collaborations.txt	2004-06-26 19:15:34 UTC (rev 25993)
+++ ZODB/trunk/src/ZODB/collaborations.txt	2004-06-28 22:52:38 UTC (rev 25994)
@@ -0,0 +1,91 @@
+Participants
+    DB:  ZODB.DB.DB
+    C:  ZODB.Connection.Connection
+    S:  ZODB.FileStorage.FileStorage
+    T:  transaction.interfaces.ITransaction
+    TM:  transaction.interfaces.ITransactionManager
+    o1, o2, ...:  pre-existing persistent objects
+
+Scenario
+    """Simple fetch, modify, commit."""
+
+    DB.open()
+        create C
+        TM.registerSynch(C)
+    TM.begin()
+        create T
+    C.get(1) # fetches o1
+    C.get(2) # fetches o2
+    C.get(3) # fetches o3
+    o1.modify() # anything that modifies o1
+        C.register(o1)
+            T.join(C)
+    o2.modify()
+        C.register(o2)
+            # T.join(C) does not happen again
+    o1.modify()
+        # C.register(o1) doesn't happen again, because o1 was already
+        # in the changed state.
+    T.commit()
+        C.beforeCompletion(T)
+        C.tpc_begin(T, False)
+            S.tpc_begin(T)
+        C.commit(T)
+            S.store(1, ..., T)
+            S.store(2, ..., T)
+            # o3 is not stored, because it wasn't modified
+        C.tpc_vote(T)
+            S.tpc_vote(T)
+        C.tpc_finish(T)
+            S.tpc_finish(T, f) # f is a callback function, which arranges
+                               # to call DB.invalidate (next)
+                DB.invalidate(tid, {1: 1, 2: 1}, C)
+                    C2.invalidate(tid, {1: 1, 2: 1}) # for all connections
+                                                     # C2 to DB, where C2
+                                                     # is not C
+        TM.free(T)
+        C.afterCompletion(T)
+            C._flush_invalidations()
+            # Processes invalidations that may have come in from other
+            # transactions.
+
+
+Participants
+    DB:  ZODB.DB.DB
+    C:  ZODB.Connection.Connection
+    S:  ZODB.FileStorage.FileStorage
+    T:  transaction.interfaces.ITransaction
+    TM:  transaction.interfaces.ITransactionManager
+    o1, o2, ...:  pre-existing persistent objects
+
+Scenario
+    """Simple fetch, modify, abort."""
+
+    DB.open()
+        create C
+        TM.registerSynch(C)
+    TM.begin()
+        create T
+    C.get(1) # fetches o1
+    C.get(2) # fetches o2
+    C.get(3) # fetches o3
+    o1.modify() # anything that modifies o1
+        C.register(o1)
+            T.join(C)
+    o2.modify()
+        C.register(o2)
+            # T.join(C) does not happen again
+    o1.modify()
+        # C.register(o1) doesn't happen again, because o1 was already
+        # in the changed state.
+    T.abort()
+        C.beforeCompletion(T)
+        C.abort(T)
+            C._cache.invalidate(1)  # toss changes to o1
+            C._cache.invalidate(2)  # toss changes to o2
+            # o3 wasn't modified, and its cache entry isn't invalidated.
+        TM.free(T)
+        C.afterCompletion(T)
+            C._flush_invalidations()
+            # Processes invalidations that may have come in from other
+            # transactions.


Property changes on: ZODB/trunk/src/ZODB/collaborations.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: ZODB/trunk/src/ZODB/interfaces.py
===================================================================
--- ZODB/trunk/src/ZODB/interfaces.py	2004-06-26 19:15:34 UTC (rev 25993)
+++ ZODB/trunk/src/ZODB/interfaces.py	2004-06-28 22:52:38 UTC (rev 25994)
@@ -17,205 +17,7 @@
 """
 
 import zope.interface
-from zope.interface import Attribute
 
-class IDataManager(zope.interface.Interface):
-    """Objects that manage transactional storage.
-
-    These object's may manage data for other objects, or they may manage
-    non-object storages, such as relational databases.
-    """
-
-    def abort_sub(transaction):
-        """Discard all subtransaction data.
-
-        See subtransaction.txt
-
-        This is called when top-level transactions are aborted.
-
-        No further subtransactions can be started once abort_sub()
-        has been called; this is only used when the transaction is
-        being aborted.
-
-        abort_sub also implies the abort of a 2-phase commit.
-
-        This should never fail.
-        """
-
-    def commit_sub(transaction):
-        """Commit all changes made in subtransactions and begin 2-phase commit
-
-        Data are saved *as if* they are part of the current transaction.
-        That is, they will not be persistent unless the current transaction
-        is committed.
-
-        This is called when the current top-level transaction is committed.
-
-        No further subtransactions can be started once commit_sub()
-        has been called; this is only used when the transaction is
-        being committed.
-
-        This call also implied the beginning of 2-phase commit.
-        """
-
-    # Two-phase commit protocol.  These methods are called by the
-    # ITransaction object associated with the transaction being
-    # committed.
-
-    def tpc_begin(transaction, subtransaction=False):
-        """Begin commit of a transaction, starting the two-phase commit.
-
-        transaction is the ITransaction instance associated with the
-        transaction being committed.
-
-        subtransaction is a Boolean flag indicating whether the
-        two-phase commit is being invoked for a subtransaction.
-
-        Important note: Subtransactions are modelled in the sense that
-        when you commit a subtransaction, subsequent commits should be
-        for subtransactions as well.  That is, there must be a
-        commit_sub() call between a tpc_begin() call with the
-        subtransaction flag set to true and a tpc_begin() with the
-        flag set to false.
-
-        """
-
-
-    def tpc_abort(transaction):
-        """Abort a transaction.
-
-        This is always called after a tpc_begin call.
-
-        transaction is the ITransaction instance associated with the
-        transaction being committed.
-
-        This should never fail.
-        """
-
-    def tpc_finish(transaction):
-        """Indicate confirmation that the transaction is done.
-
-        transaction is the ITransaction instance associated with the
-        transaction being committed.
-
-        This should never fail. If this raises an exception, the
-        database is not expected to maintain consistency; it's a
-        serious error.
-
-        """
-
-    def tpc_vote(transaction):
-        """Verify that a data manager can commit the transaction
-
-        This is the last chance for a data manager to vote 'no'.  A
-        data manager votes 'no' by raising an exception.
-
-        transaction is the ITransaction instance associated with the
-        transaction being committed.
-        """
-
-    def commit(object, transaction):
-        """CCCommit changes to an object
-
-        Save the object as part of the data to be made persistent if
-        the transaction commits.
-        """
-
-    def abort(object, transaction):
-        """Abort changes to an object
-
-        Only changes made since the last transaction or
-        sub-transaction boundary are discarded.
-
-        This method may be called either:
-
-        o Outside of two-phase commit, or
-
-        o In the first phase of two-phase commit
-
-        """
-
-
-class ITransaction(zope.interface.Interface):
-    """Object representing a running transaction.
-
-    Objects with this interface may represent different transactions
-    during their lifetime (.begin() can be called to start a new
-    transaction using the same instance).
-    """
-
-    user = Attribute(
-        "user",
-        "The name of the user on whose behalf the transaction is being\n"
-        "performed.  The format of the user name is defined by the\n"
-        "application.")
-    # XXX required to be a string?
-
-    description = Attribute(
-        "description",
-        "Textual description of the transaction.")
-
-    def begin(info=None, subtransaction=None):
-        """Begin a new transaction.
-
-        If the transaction is in progress, it is aborted and a new
-        transaction is started using the same transaction object.
-        """
-
-    def commit(subtransaction=None):
-        """Finalize the transaction.
-
-        This executes the two-phase commit algorithm for all
-        IDataManager objects associated with the transaction.
-        """
-
-    def abort(subtransaction=0, freeme=1):
-        """Abort the transaction.
-
-        This is called from the application.  This can only be called
-        before the two-phase commit protocol has been started.
-        """
-
-    def join(datamanager):
-        """Add a datamanager to the transaction.
-
-        The datamanager must implement the
-        transactions.interfaces.IDataManager interface, and be
-        adaptable to ZODB.interfaces.IDataManager.
-        """
-
-    def register(object):
-        """Register the given object for transaction control."""
-
-    def note(text):
-        """Add text to the transaction description.
-
-        If a description has already been set, text is added to the
-        end of the description following two newline characters.
-        Surrounding whitespace is stripped from text.
-        """
-        # XXX does impl do the right thing with ''?  Not clear what
-        # the "right thing" is.
-
-    def setUser(user_name, path="/"):
-        """Set the user name.
-
-        path should be provided if needed to further qualify the
-        identified user.
-        """
-
-    def setExtendedInfo(name, value):
-        """Add extension data to the transaction.
-
-        name is the name of the extension property to set; value must
-        be a picklable value.
-
-        Storage implementations may limit the amount of extension data
-        which can be stored.
-        """
-        # XXX is this this allowed to cause an exception here, during
-        # the two-phase commit, or can it toss data silently?
-
 class IConnection(zope.interface.Interface):
     """ZODB connection.
 

Modified: ZODB/trunk/src/transaction/interfaces.py
===================================================================
--- ZODB/trunk/src/transaction/interfaces.py	2004-06-26 19:15:34 UTC (rev 25993)
+++ ZODB/trunk/src/transaction/interfaces.py	2004-06-28 22:52:38 UTC (rev 25994)
@@ -16,20 +16,138 @@
 $Id$
 """
 
-from zope.interface import Interface
+import zope.interface
 
-class IDataManager(Interface):
-    """Data management interface for storing objects transactionally
+class IDataManagerOriginal(zope.interface.Interface):
+    """Objects that manage transactional storage.
 
-    This is currently implemented by ZODB database connections.
+    These objects may manage data for other objects, or they may manage
+    non-object storages, such as relational databases.
 
-    XXX This exists to document ZODB4 behavior, to help create some
-    backward-compatability support for Zope 3.  New classes shouldn't
-    implement this. They should implement ZODB.interfaces.IDataManager
-    for now. Our hope is that there will eventually be an interface
-    like this or that this interface will evolve and become the
-    standard interface. There are some issues to be resolved first, like:
+    IDataManagerOriginal is the interface currently provided by ZODB
+    database connections, but the intent is to move to the newer
+    IDataManager.
+    """
 
+    def abort_sub(transaction):
+        """Discard all subtransaction data.
+
+        See subtransaction.txt
+
+        This is called when top-level transactions are aborted.
+
+        No further subtransactions can be started once abort_sub()
+        has been called; this is only used when the transaction is
+        being aborted.
+
+        abort_sub also implies the abort of a 2-phase commit.
+
+        This should never fail.
+        """
+
+    def commit_sub(transaction):
+        """Commit all changes made in subtransactions and begin 2-phase commit
+
+        Data are saved *as if* they are part of the current transaction.
+        That is, they will not be persistent unless the current transaction
+        is committed.
+
+        This is called when the current top-level transaction is committed.
+
+        No further subtransactions can be started once commit_sub()
+        has been called; this is only used when the transaction is
+        being committed.
+
+        This call also implied the beginning of 2-phase commit.
+        """
+
+    # Two-phase commit protocol.  These methods are called by the
+    # ITransaction object associated with the transaction being
+    # committed.
+
+    def tpc_begin(transaction, subtransaction=False):
+        """Begin commit of a transaction, starting the two-phase commit.
+
+        transaction is the ITransaction instance associated with the
+        transaction being committed.
+
+        subtransaction is a Boolean flag indicating whether the
+        two-phase commit is being invoked for a subtransaction.
+
+        Important note: Subtransactions are modelled in the sense that
+        when you commit a subtransaction, subsequent commits should be
+        for subtransactions as well.  That is, there must be a
+        commit_sub() call between a tpc_begin() call with the
+        subtransaction flag set to true and a tpc_begin() with the
+        flag set to false.
+
+        """
+
+
+    def tpc_abort(transaction):
+        """Abort a transaction.
+
+        This is always called after a tpc_begin call.
+
+        transaction is the ITransaction instance associated with the
+        transaction being committed.
+
+        This should never fail.
+        """
+
+    def tpc_finish(transaction):
+        """Indicate confirmation that the transaction is done.
+
+        transaction is the ITransaction instance associated with the
+        transaction being committed.
+
+        This should never fail. If this raises an exception, the
+        database is not expected to maintain consistency; it's a
+        serious error.
+
+        """
+
+    def tpc_vote(transaction):
+        """Verify that a data manager can commit the transaction
+
+        This is the last chance for a data manager to vote 'no'.  A
+        data manager votes 'no' by raising an exception.
+
+        transaction is the ITransaction instance associated with the
+        transaction being committed.
+        """
+
+    def commit(object, transaction):
+        """CCCommit changes to an object
+
+        Save the object as part of the data to be made persistent if
+        the transaction commits.
+        """
+
+    def abort(object, transaction):
+        """Abort changes to an object
+
+        Only changes made since the last transaction or
+        sub-transaction boundary are discarded.
+
+        This method may be called either:
+
+        o Outside of two-phase commit, or
+
+        o In the first phase of two-phase commit
+
+        """
+
+class IDataManager(zope.interface.Interface):
+    """Data management interface for storing objects transactionally.
+
+    ZODB database connections currently provides the older
+    IDataManagerOriginal interface, but the intent is to move to this newer
+    IDataManager interface.
+
+    Our hope is that this interface will evolve and become the standard
+    interface.  There are some issues to be resolved first, like:
+
     - Probably want separate abort methods for use in and out of
       two-phase commit.
 
@@ -99,9 +217,88 @@
 
         """
 
+class ITransaction(zope.interface.Interface):
+    """Object representing a running transaction.
 
-class IRollback(Interface):
+    Objects with this interface may represent different transactions
+    during their lifetime (.begin() can be called to start a new
+    transaction using the same instance).
+    """
 
+    user = zope.interface.Attribute(
+        "user",
+        "The name of the user on whose behalf the transaction is being\n"
+        "performed.  The format of the user name is defined by the\n"
+        "application.")
+    # XXX required to be a string?
+
+    description = zope.interface.Attribute(
+        "description",
+        "Textual description of the transaction.")
+
+    def begin(info=None, subtransaction=None):
+        """Begin a new transaction.
+
+        If the transaction is in progress, it is aborted and a new
+        transaction is started using the same transaction object.
+        """
+
+    def commit(subtransaction=None):
+        """Finalize the transaction.
+
+        This executes the two-phase commit algorithm for all
+        IDataManager objects associated with the transaction.
+        """
+
+    def abort(subtransaction=0, freeme=1):
+        """Abort the transaction.
+
+        This is called from the application.  This can only be called
+        before the two-phase commit protocol has been started.
+        """
+
+    def join(datamanager):
+        """Add a datamanager to the transaction.
+
+        The datamanager must implement the
+        transactions.interfaces.IDataManager interface, and be
+        adaptable to ZODB.interfaces.IDataManager.
+        """
+
+    def register(object):
+        """Register the given object for transaction control."""
+
+    def note(text):
+        """Add text to the transaction description.
+
+        If a description has already been set, text is added to the
+        end of the description following two newline characters.
+        Surrounding whitespace is stripped from text.
+        """
+        # XXX does impl do the right thing with ''?  Not clear what
+        # the "right thing" is.
+
+    def setUser(user_name, path="/"):
+        """Set the user name.
+
+        path should be provided if needed to further qualify the
+        identified user.
+        """
+
+    def setExtendedInfo(name, value):
+        """Add extension data to the transaction.
+
+        name is the name of the extension property to set; value must
+        be a picklable value.
+
+        Storage implementations may limit the amount of extension data
+        which can be stored.
+        """
+        # XXX is this this allowed to cause an exception here, during
+        # the two-phase commit, or can it toss data silently?
+
+class IRollback(zope.interface.Interface):
+
     def rollback():
         """Rollback changes since savepoint.
 



More information about the Zodb-checkins mailing list