Commit d01f9b40 authored by Jim Fulton's avatar Jim Fulton

Fixed bug that could cause infinate loop when odd objects

got registered. (Deja vu all over again. ;)

Changed to commit objects in registration order and to allow
additional objects to get registered while commiting. (The
later was wanted by PJE.)

Added a comment in commit to explain the "invariant".

Fixed bug that caused objects to get multiply aborted.  Now always
clear object registry on commit and abort. This seems like a good
idea anyway. (We were relying on free_transaction to have the
same effect. This faild miserably in single-threaded apps and
in certain error conditions.

Added a teeny optimization in get_transaction().
parent f4be63cc
...@@ -84,8 +84,8 @@ ...@@ -84,8 +84,8 @@
############################################################################## ##############################################################################
"""Transaction management """Transaction management
$Id: Transaction.py,v 1.21 2000/05/28 02:22:53 chrism Exp $""" $Id: Transaction.py,v 1.22 2000/05/30 19:03:27 jim Exp $"""
__version__='$Revision: 1.21 $'[11:-2] __version__='$Revision: 1.22 $'[11:-2]
import time, sys, struct, POSException import time, sys, struct, POSException
from struct import pack from struct import pack
...@@ -166,9 +166,8 @@ class Transaction: ...@@ -166,9 +166,8 @@ class Transaction:
finally: finally:
tb=None tb=None
if subtransaction: del self._objects[:] # Clear registered
del self._objects[:] # make sure it's empty (shouldn't need) if not subtransaction and freeme:
elif freeme:
if self._id is not None: free_transaction() if self._id is not None: free_transaction()
else: self._init() else: self._init()
...@@ -197,7 +196,7 @@ class Transaction: ...@@ -197,7 +196,7 @@ class Transaction:
if objects: if objects:
# Do an implicit sub-transaction commit: # Do an implicit sub-transaction commit:
self.commit(1) self.commit(1)
objects=() objects=[]
subjars=subj.values() subjars=subj.values()
self._sub=None self._sub=None
...@@ -221,9 +220,24 @@ class Transaction: ...@@ -221,9 +220,24 @@ class Transaction:
""") """)
try: try:
# It's important that:
#
# - Every object in self._objects is either committed
# or aborted.
#
# - For each object that is committed
# we call tpc_begin on it's jar at least once
#
# - For every jar for which we've called tpc_begin on,
# we either call tpc_abort or tpc_finish. It is OK
# to call these multiple times, as the storage is
# required to ignore these calls if tpc_begin has not
# been called.
ncommitted=0
try: try:
while objects: for o in objects:
o=objects.pop()
j=getattr(o, '_p_jar', o) j=getattr(o, '_p_jar', o)
if j is None: continue if j is None: continue
i=id(j) i=id(j)
...@@ -235,6 +249,7 @@ class Transaction: ...@@ -235,6 +249,7 @@ class Transaction:
else: else:
j.tpc_begin(self) j.tpc_begin(self)
j.commit(o,self) j.commit(o,self)
ncommitted=ncommitted+1
# Commit work done in subtransactions # Commit work done in subtransactions
while subjars: while subjars:
...@@ -258,7 +273,7 @@ class Transaction: ...@@ -258,7 +273,7 @@ class Transaction:
# have to clean up. # have to clean up.
# First, we have to abort any uncommitted objects. # First, we have to abort any uncommitted objects.
for o in objects: for o in objects[ncommitted:]:
try: try:
j=getattr(o, '_p_jar', o) j=getattr(o, '_p_jar', o)
if j is not None: j.abort(o, self) if j is not None: j.abort(o, self)
...@@ -297,9 +312,8 @@ class Transaction: ...@@ -297,9 +312,8 @@ class Transaction:
finally: finally:
tb=None tb=None
if subtransaction: del objects[:] # clear registered
del self._objects[:] # make sure it's empty (shouldn't need) if not subtransaction and self._id is not None: free_transaction()
elif self._id is not None: free_transaction()
def register(self,object): def register(self,object):
'Register the given object for transaction control.' 'Register the given object for transaction control.'
...@@ -334,10 +348,10 @@ except: ...@@ -334,10 +348,10 @@ except:
else: else:
_t={} _t={}
def get_transaction(_id=thread.get_ident, _t=_t): def get_transaction(_id=thread.get_ident, _t=_t, get=_t.get, None=None):
id=_id() id=_id()
try: t=_t[id] t=get(id, None)
except KeyError: _t[id]=t=Transaction(id) if t is None: _t[id]=t=Transaction(id)
return t return t
def free_transaction(_id=thread.get_ident, _t=_t): def free_transaction(_id=thread.get_ident, _t=_t):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment