[Zope-dev] External transaction integration bug?

John D. Heintz jheintz@isogen.com
Thu, 19 Apr 2001 09:09:42 -0500


This is a multi-part message in MIME format.
--------------080309070504070407050907
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

I can't directly address the concerns you've raised, but for my project 
I have rewritten TM.py to work better within the begin/vote/finish/abort 
protocol framework.  I've also added more documentation.

John

Randall F. Kern wrote:

> I may just be missing something obvious here, but it seems like there is
> a hole in ZODB.Transaction.Transaction.commit and Shared.DC.ZRDB.TM.TM,
> that can cause external transactions (those that use the TM mixin class,
> like psycopg) to be abandoned (never get committed or rolled back).
> 
> Let's say somewhere around line 300 in Transaction.py (the call to
> j.commit(o, self)) we get an exception.  Furthermore, let's say the TM
> derived database object has already been committed (the only effect of
> which is to move the DB into the jars mapping, since TM.tpc_begin() and
> TM.commit() both do nothing).
> 
> The exception dumps us down to about line 353, where we call
> _p_jar.abort() on all the uncommitted objects (note: it's important that
> the database connection isn't in this list, because TM.abort() will
> rollback the transaction.  the way we keep the db out of this list is by
> having it appear in objects _before_ the object that failed the commit).
> 
> Next we reach line ~366, where we should "unwind TPC for the jars that
> began it".  What this means is calling tpc_abort() on each jar from the
> objects that were already committed (which includes the database).
> However, TM.tpc_abort() does nothing, leaving the external database
> transaction open.
> 
> Does this make sense?
> 
> If this makes sense (i.e. seems bad :), does catching tpc_abort() in TM
> and calling TM.abort() seem like a valid fix?
> 
> Thanks,
> -Randy
> 
> _______________________________________________
> Zope-Dev maillist  -  Zope-Dev@zope.org
> http://lists.zope.org/mailman/listinfo/zope-dev
> **  No cross posts or HTML encoding!  **
> (Related lists - 
>  http://lists.zope.org/mailman/listinfo/zope-announce
>  http://lists.zope.org/mailman/listinfo/zope )
> 
> 
> 



--------------080309070504070407050907
Content-Type: text/plain;
 name="TM.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="TM.py"

##############################################################################
# 
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
# 
# Copyright (c) Digital Creations.  All rights reserved.
# 
# This license has been certified as Open Source(tm).
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# 
# 1. Redistributions in source code must retain the above copyright
#    notice, this list of conditions, and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions, and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
# 
# 3. Digital Creations requests that attribution be given to Zope
#    in any manner possible. Zope includes a "Powered by Zope"
#    button that is installed by default. While it is not a license
#    violation to remove this button, it is requested that the
#    attribution remain. A significant investment has been put
#    into Zope, and this effort will continue if the Zope community
#    continues to grow. This is one way to assure that growth.
# 
# 4. All advertising materials and documentation mentioning
#    features derived from or use of this software must display
#    the following acknowledgement:
# 
#      "This product includes software developed by Digital Creations
#      for use in the Z Object Publishing Environment
#      (http://www.zope.org/)."
# 
#    In the event that the product being advertised includes an
#    intact Zope distribution (with copyright and license included)
#    then this clause is waived.
# 
# 5. Names associated with Zope or Digital Creations must not be used to
#    endorse or promote products derived from this software without
#    prior written permission from Digital Creations.
# 
# 6. Modified redistributions of any form whatsoever must retain
#    the following acknowledgment:
# 
#      "This product includes software developed by Digital Creations
#      for use in the Z Object Publishing Environment
#      (http://www.zope.org/)."
# 
#    Intact (re-)distributions of any official Zope release do not
#    require an external acknowledgement.
# 
# 7. Modifications are encouraged but must be packaged separately as
#    patches to official Zope releases.  Distributions that do not
#    clearly separate the patches from the original work must be clearly
#    labeled as unofficial distributions.  Modifications which do not
#    carry the name Zope may be packaged in any form, as long as they
#    conform to all of the clauses above.
# 
# 
# Disclaimer
# 
#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#   SUCH DAMAGE.
# 
# 
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations.  Specific
# attributions are listed in the accompanying credits file.
# 
##############################################################################
"""Provide support for linking an external transaction manager with Zope's
"""


class TM:
    """Mix-in class that provides transaction management support

    A sub class should call self._register() whenever it performs
    any transaction-dependent operations (e.g. sql statements).

    The sub class will need to override:
      _begin if necessary
      _vote to raise an except if necessary
      _finish to finallize work,
      _abort to roll-back work
    """

    def _begin(self):
        """Hook method to begin external transaction.
        This may be called multiple times,"""
        pass

    def _vote(self):
        """Hook method to vote on success of transaction commit.
        This will only be called once,"""
        pass

    def _finish(self):
        """Hook method to complete transaction work.
        This may be called multiple times."""
        pass

    def _abort(self):
        """Hook method to undo transaction work.
        This may be called multiple times."""
        pass

    _registered=None

    class Surrogate:
        "A ZODB persistent look-alike."
        def __init__(self, connection):
            self._p_jar=connection

    def _register(self):
        """This method will register a surrogate persistent
        object with the transaction.  This surrogate will include
        me in the tpc_* two-phase commit process."""

        if not self._registered:
            try:
                get_transaction().register(TM.Surrogate(self))
                self._registered=1
            except:
                import traceback
                traceback.print_exc()
                pass

    def commit(self, *ignored):
        "We don't need to actually do an storing."
        pass

    def tpc_begin(self, *ignored):
        "Connection method to begin a commit."
        self._begin()

    def tpc_vote(self, *ignored):
        "Connection method to vote on commit success."
        self._vote()
        
    def tpc_finish(self, *ignored):
        """Connection method to signal commit success.
        This should *never* fail"""
        try: self._finish()
        finally: self._registered=0

    def abort(self, *ignored):
        """Connnection method to signal commit failure.
        This should *never* fail"""
        try: self._abort()
        finally: self._registered=0

--------------080309070504070407050907--