Commit 6596e915 authored by Jim Fulton's avatar Jim Fulton

Added subtransaction support.

parent 5de492bf
...@@ -84,13 +84,13 @@ ...@@ -84,13 +84,13 @@
############################################################################## ##############################################################################
"""Transaction management """Transaction management
$Id: Transaction.py,v 1.7 1999/05/18 15:55:10 jim Exp $""" $Id: Transaction.py,v 1.8 1999/06/29 18:28:38 jim Exp $"""
__version__='$Revision: 1.7 $'[11:-2] __version__='$Revision: 1.8 $'[11:-2]
import time, sys, struct import time, sys, struct
from struct import pack from struct import pack
from string import split, strip, join from string import split, strip, join
from zLOG import LOG, ERROR
from POSException import ConflictError from POSException import ConflictError
class Transaction: class Transaction:
...@@ -99,6 +99,7 @@ class Transaction: ...@@ -99,6 +99,7 @@ class Transaction:
description='' description=''
_connections=None _connections=None
_extension=None _extension=None
_sub=None # This is a subtrasaction flag
def __init__(self, id=None): def __init__(self, id=None):
self._id=id self._id=id
...@@ -114,6 +115,7 @@ class Transaction: ...@@ -114,6 +115,7 @@ class Transaction:
del self._connections del self._connections
def sub(self): def sub(self):
# Create a manually managed subtransaction for internal use
r=self.__class__() r=self.__class__()
r.user=self.user r.user=self.user
r.description=self.description r.description=self.description
...@@ -122,13 +124,23 @@ class Transaction: ...@@ -122,13 +124,23 @@ class Transaction:
def __str__(self): return "%.3f\t%s" % (self._id, self.user) def __str__(self): return "%.3f\t%s" % (self._id, self.user)
def abort(self, freeme=1): def abort(self, sub=0, freeme=1):
'''Abort the transaction. '''Abort the transaction.
This is called from the application. This means that we haven\'t This is called from the application. This means that we haven\'t
entered two-phase commit yet, so no tpc_ messages are sent. entered two-phase commit yet, so no tpc_ messages are sent.
''' '''
t=v=tb=None t=v=tb=None
subj=self._sub
subjars=()
if not sub:
if subj is not None:
# Abort of top-level transaction after commiting
# subtransactions.
subjars=subj.values()
self._sub=None
try: try:
# Abort the objects # Abort the objects
for o in self._objects: for o in self._objects:
...@@ -139,41 +151,78 @@ class Transaction: ...@@ -139,41 +151,78 @@ class Transaction:
if t is None: if t is None:
t,v,tb=sys.exc_info() t,v,tb=sys.exc_info()
# Ugh, we need to abort work done in sub-transactions.
while subjars:
j=subjars.pop()
j.abort_sub(self) # This should never fail
if t is not None: raise t,v,tb if t is not None: raise t,v,tb
finally: finally:
tb=None tb=None
if self._id is not None and freeme: free_transaction() if sub:
del self._objects[:] # make sure it's empty (shouldn't need)
elif freeme:
if self._id is not None: free_transaction()
else: self._init()
def begin(self, info=None): def begin(self, sub=None, info=None):
'''Begin a new transaction. '''Begin a new transaction.
This aborts any transaction in progres. This aborts any transaction in progres.
''' '''
if self._objects: self.abort(0) if self._objects: self.abort(sub, 0)
self._init()
if info: if info:
info=split(info,'\t') info=split(info,'\t')
self.user=strip(info[0]) self.user=strip(info[0])
self.description=strip(join(info[1:],'\t')) self.description=strip(join(info[1:],'\t'))
def commit(self): def commit(self, sub=None):
'Finalize the transaction' 'Finalize the transaction'
t=v=tb=None
jars={}
objects=self._objects objects=self._objects
jars={}
subj=self._sub
subjars=()
if sub:
if subj is None: self._sub=subj={}
else:
if subj is not None:
if objects:
# Do an implicit sub-transaction commit:
self.commit(1)
objects=()
subjars=subj.values()
self._sub=None
t=v=tb=None
try: try:
try: try:
while objects: while objects:
o=objects[-1] o=objects[-1]
j=getattr(o, '_p_jar', o) j=getattr(o, '_p_jar', o)
#if j is None:
# print 'waaa'
# print o, o._p_oid
# raise 'what the hell'
i=id(j) i=id(j)
if not jars.has_key(i): if not jars.has_key(i):
jars[i]=j jars[i]=j
j.tpc_begin(self) if sub: subj[i]=j
j.tpc_begin(self, sub)
j.commit(o,self) j.commit(o,self)
del objects[-1] del objects[-1]
# Commit work done in subtransactions
while subjars:
j=subjars.pop()
i=id(j)
if not jars.has_key(i):
jars[i]=j
j.commit_sub(self)
except: except:
t,v,tb=sys.exc_info() t,v,tb=sys.exc_info()
...@@ -192,6 +241,11 @@ class Transaction: ...@@ -192,6 +241,11 @@ class Transaction:
try: j.tpc_abort(self) # This should never fail try: j.tpc_abort(self) # This should never fail
except: pass except: pass
# Ugh, we need to abort work done in sub-transactions.
while subjars:
j=subjars.pop()
j.abort_sub(self) # This should never fail
raise t,v,tb raise t,v,tb
for j in jars.values(): for j in jars.values():
...@@ -205,7 +259,9 @@ class Transaction: ...@@ -205,7 +259,9 @@ class Transaction:
finally: finally:
tb=None tb=None
if self._id is not None: free_transaction() if sub:
del self._objects[:] # make sure it's empty (shouldn't need)
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.'
......
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